diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 28f77c3..51c1111 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -24,7 +24,7 @@ jobs: run: | npm view npm get version of @babel/plugin-proposal-private-property-in-object version command sudo apt-get update - sudo apt install gcc-10 g++-10 + sudo apt install gcc-12 g++-12 sudo apt-get install liblilv-dev libboost-dev libjack-jackd2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev catch sudo apt install libasound2-dev sudo apt install libwebsocketpp-dev authbind diff --git a/.vscode/launch.json b/.vscode/launch.json index 894e5c8..dcf6e77 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -4,6 +4,7 @@ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ + @@ -35,6 +36,37 @@ } ] }, + { + "name": "(gdb) pipedal_nm_p2pd", + "type": "cppdbg", + "request": "launch", + // Resolved by CMake Tools: + "program": "${command:cmake.launchTargetPath}", + "args": [ + "--loglevel", + "trace", + "--systemd-console" + ], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [ + { + // add the directory where our target was built to the PATHs + // it gets resolved by CMake Tools: + "name": "PATH", + "value": "$PATH:${command:cmake.launchTargetDirectory}" + } + ], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + }, { "name": "(gdb) pipedald", @@ -79,7 +111,8 @@ //"[Dev]" -- all dev-machine tests. //"[json_variants]" // subtest of your choice, or none to run all of the tests. //"[inverting_mutex_test]" - "[utf8_to_utf32]" + // "[utf8_to_utf32]" + "[wifi_channels_test]" ], "stopAtEntry": false, @@ -188,9 +221,12 @@ ///"args": [ "[lv2host_leak]" ], "args": [ - "../../../debian/copyrights-base", + "--projectCopyright", + "debian/copyright", "--output", - "../../../debian/copyrights" + "/tmp/copyrights.txt", + "liblilv-0-0", "lv2-dev", "libsdbus-c++-dev", "librsvg2-2", "libpango-1.0-0", "libx11-6", "libxrandr2" + ], "stopAtEntry": false, "cwd": "${workspaceFolder}", @@ -229,10 +265,11 @@ // Resolved by CMake Tools: "program": "${command:cmake.launchTargetPath}", "args": [ - "--get-current-port" + "--nosudo", // run without sudo (which will fail because of perms, but allow us to debug deeper into install code.) + //"--get-current-port" // "--uninstall" - //"--enable-p2p" , "--nopkexec" - //,"CA", "PiPedalTest","12345678","1" + //"--enable-p2p" , "CA", "PiPedalTest","12345678","14" + "--list-p2p-channels" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/.vscode/settings.json b/.vscode/settings.json index 15f1448..eb5ed79 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -92,7 +92,11 @@ "util": "cpp", "charconv": "cpp", "valarray": "cpp", - "hash_map": "cpp" + "hash_map": "cpp", + "nm-device-wifi-p2p.h": "c", + "strstream": "cpp", + "p2p_i.h": "c", + "p2p.h": "c" }, "cSpell.words": [ "Guitarix", diff --git a/CMakeLists.txt b/CMakeLists.txt index 4e29fa1..851ef76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,10 +1,10 @@ cmake_minimum_required(VERSION 3.16.0) project(pipedal - VERSION 1.1.31 + VERSION 1.2.33 DESCRIPTION "PiPedal Guitar Effect Pedal For Raspberry Pi" HOMEPAGE_URL "https://rerdavies.github.io/pipedal" ) -set (DISPLAY_VERSION "v1.1.31") +set (DISPLAY_VERSION "v1.2.31beta1") set (CMAKE_INSTALL_PREFIX "/usr/") @@ -16,13 +16,21 @@ enable_testing() add_subdirectory("submodules/pipedal_p2pd") +add_subdirectory("PiPedalCommon") + add_subdirectory("react") add_subdirectory("src") -install (TARGETS pipedal_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/bin +add_subdirectory("NetworkManagerP2P") + + +install (TARGETS pipedal_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin ) - + +install (TARGETS pipedal_nm_p2pd DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin +) + # select LV2 source directory for the current build architecture message(STATUS "CMAKE_SYSTEM_PROCESSOR: ${CMAKE_SYSTEM_PROCESSOR}") @@ -67,27 +75,27 @@ install (DIRECTORY ${LV2_SOURCE_DIRECTORY} install(CODE [[ file(GET_RUNTIME_DEPENDENCIES - EXECUTABLES ${CMAKE_INSTALL_PREFIX}/bin/pipedald ${CMAKE_INSTALL_PREFIX}/bin/pipedalconfig + EXECUTABLES + ${CMAKE_INSTALL_PREFIX}/sbin/pipedaladmind + ${CMAKE_INSTALL_PREFIX}/sbin/pipedald + ${CMAKE_INSTALL_PREFIX}/sbin/pipedal_nm_p2pd + ${CMAKE_INSTALL_PREFIX}/sbin/pipedal_p2pd + ${CMAKE_INSTALL_PREFIX}/bin/pipedalconfig ) ]] ) -# Should be done by install.sh instead of here so that we can build the package without root permissions. -# install( -# CODE "execute_process(COMMAND ${CMAKE_INSTALL_PREFIX}/bin/pipedalconfig --install)" -# ) - set(CPACK_GENERATOR "DEB") set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Robin Davies") # required set(CPACK_PACKAGE_VENDOR "Robin Davies") set(CPACK_PACKAGE_DESCRIPTION "IoT guitar effect pedal for Raspberry Pi, with phone-friendly web interface.") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IoT guitar effect for Raspberry Pi") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "IoT guitar effect pedal for Raspberry Pi") set(CPACK_DEBIAN_PACKAGE_SECTION sound) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_CONTROL_STRICT_PERMISSION TRUE) -#set(CPACK_DEBIAN_PACKAGE_DEPENDS "jackd2, hostapd, dnsmasq" ) -set(CPACK_DEBIAN_PACKAGE_DEPENDS "lv2-dev, hostapd, dnsmasq, authbind" ) +#set(CPACK_DEBIAN_PACKAGE_DEPENDS "jackd2, hostapd, dhcpcd, dnsmasq" ) +set(CPACK_DEBIAN_PACKAGE_DEPENDS "lv2-dev, hostapd, dhcpcd,dnsmasq, authbind" ) #set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "arm64") set(CPACK_PACKAGING_INSTALL_PREFIX /usr) set(CPACK_PROJECT_NAME ${PROJECT_NAME}) diff --git a/NetworkManagerP2P/CMakeLists.txt b/NetworkManagerP2P/CMakeLists.txt new file mode 100644 index 0000000..5cfe6da --- /dev/null +++ b/NetworkManagerP2P/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory("src") diff --git a/NetworkManagerP2P/README.md b/NetworkManagerP2P/README.md new file mode 100644 index 0000000..84edad2 --- /dev/null +++ b/NetworkManagerP2P/README.md @@ -0,0 +1,25 @@ +The pipedal_nm_p2pd service manages PiPedal P2P connections on Debian bookworm or later distros. + +Debian Bookworm switchs the entire network stack from the deprecated dhcpcd/NetworkManager +stack to the current NetworkManager stack. Unfortunately, NetworkManager does not +provide support for P2P Wi-fi direct. + +NetworkManager P2P support is abysmal, providing no support whatsoever +for P2P GOs. Furthermore, a bug in NetworkManager prevents anyone else from providing a P2P GO +solution through wpas_supplicant. Specifically, NetworkManager call RemoveInterface on any P2P +group that it didn't start itself, even if p2p-dev-wlan-0 is marked as unmanaged. + +The solution: Configure NetworkManager to mark wlan0 as an unmanaged interface. This allows +the pipedal_nm_p2pd service to manage p2p sessions via wpa_supplicant without interference from +NetworkManager. Unfortunately, that means that PiPedal can't run wi-fi connections anymore when +running Wifi p2p connections. If the NetworkManager project provides sensible support +for p2p in future, we will look at it again. + +This project uses DBus interfaces, which is a significant improvement on the use of +wpa_cli sockets in the old pipedal_p2pd module. + +Dependent packages: + + + sudo apt install libsdbus-c++-dev + sudo apt install libsdbus-c++-bin diff --git a/NetworkManagerP2P/src/CMakeLists.txt b/NetworkManagerP2P/src/CMakeLists.txt new file mode 100644 index 0000000..b69baa9 --- /dev/null +++ b/NetworkManagerP2P/src/CMakeLists.txt @@ -0,0 +1,57 @@ +cmake_minimum_required(VERSION 3.19.0) + + +# specify the C++ standard +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True)# apt get lbsdbus-c++-dev + +find_package(sdbus-c++ REQUIRED) + +include(FindPkgConfig) + +pkg_check_modules(SYSTEMD "systemd") +if(!SYSTEMD_FOUND) + message(ERROR "libsystemd-dev package not installed.") +else() + message(STATUS "SYSTEMD_LIBRARIES: ${SYSTEMD_LIBRARIES}") + message(STATUS "SYSTEMD_INCLUDE_DIRS: ${SYSTEMD_INCLUDE_DIRS}") +endif() + + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + +if (CMAKE_BUILD_TYPE MATCHES Debug) + message(STATUS "Debug build") + + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG" ) +endif() + + +message(STATUS "NMPIPEDAL CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") + + +# Use the sdbus-c++ target in SDBusCpp namespace +add_executable(pipedal_nm_p2pd + Install.cpp Install.hpp + NMP2pSettings.cpp NMP2pSettings.hpp + SignalHandler.cpp SignalHandler.hpp + WpaInterfaces.hpp WpaInterfaces.cpp + NetworkManagerInterfaces.hpp NetworkManagerInterfaces.cpp + NMManager.hpp + NMManager.cpp + P2PManager.hpp P2PManager.cpp + DBusEvent.hpp DBusEvent.cpp + DBusDispatcher.hpp DBusDispatcher.cpp + DBusLog.hpp DBusLog.cpp + DBusVariantHelper.hpp DBusVariantHelper.cpp + ss.hpp + dbus/hpp/org.freedesktop.NetworkManager.hpp + main.cpp + CommandLineParser.hpp + Sudo.hpp Sudo.cpp + ) +target_link_libraries(pipedal_nm_p2pd PRIVATE PiPedalCommon SDBusCpp::sdbus-c++ systemd ) + +target_compile_definitions(pipedal_nm_p2pd PRIVATE USE_NETWORK_MANAGER) + + diff --git a/NetworkManagerP2P/src/CommandLineParser.hpp b/NetworkManagerP2P/src/CommandLineParser.hpp new file mode 100644 index 0000000..90eb303 --- /dev/null +++ b/NetworkManagerP2P/src/CommandLineParser.hpp @@ -0,0 +1,235 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once +#include +#include +#include +#include + +class CommandLineException : public std::runtime_error +{ +public: + using base = std::runtime_error; + CommandLineException(const std::string &error) + : base(error) + { + } +}; +class CommandLineParser +{ +private: + class OptionBase + { + std::string option; + + public: + OptionBase(const std::string &option_) + : option(option_) + { + } + virtual ~OptionBase() + { + } + + protected: + const std::string &GetName() const { return option; } + + public: + bool Matches(const std::string &text) const + { + return option == text; + } + virtual int Execute(int argcRemaining, const char **argvRemaining) = 0; + }; + std::vector options; + + class BooleanOption : public OptionBase + { + + bool *pOutput; + bool value; + + public: + BooleanOption(const std::string &name, bool *pOutput, bool value) + : OptionBase(name), + pOutput(pOutput), + value(value) + { + } + virtual int Execute(int argcRemaining, const char **argvRemaining) + { + *pOutput = value; + return 0; + } + }; + + template + class Option : public OptionBase + { + + T *pOutput; + + public: + Option(const std::string &name, T *pOutput) + : OptionBase(name), + pOutput(pOutput) + { + } + virtual int Execute(int argcRemaining, const char **argvRemaining) + { + if (argcRemaining == 0) + { + throw CommandLineException("Expecting a parameter for option " + GetName()); + } + std::stringstream s(argvRemaining[0]); + try + { + s >> *pOutput; + if (s.fail() || !s.eof()) + { + throw std::exception(); + } + } + catch (const std::exception &e) + { + throw CommandLineException("Argument for option " + GetName() + " is not in the correct format."); + } + return 1; // consumed one argument. + } + }; + + class StringOption : public OptionBase + { + + std::string name; + std::string *pOutput; + + public: + StringOption(const std::string &name, std::string *pOutput) + : OptionBase(name), + pOutput(pOutput) + { + } + virtual int Execute(int argcRemaining, const char **argvRemaining) + { + if (argcRemaining == 0 || argvRemaining[0][0] == '-') + { + throw CommandLineException("Expecting a parameter for option " + GetName()); + } + *pOutput = argvRemaining[0]; + return 1; + } + }; + + int ProcessOption(const std::string &text, int argsRemaining, char *argv[]) + { + for (auto option : options) + { + if (option->Matches(text)) + { + return option->Execute(argsRemaining, (const char**)argv); + } + } + std::stringstream s; + s << "Invalid option: " << text; + throw CommandLineException(s.str()); + } + + std::vector args; + +public: + ~CommandLineParser() + { + for (auto item : options) + { + delete item; + } + } + + void AddOption(const std::string &shortOption, const std::string &longOption, bool *pResult) + { + if (shortOption.length() != 0) + { + auto option = "-" + longOption; + options.push_back(new BooleanOption(option, pResult, true)); + options.push_back(new BooleanOption(option + "+", pResult, true)); + options.push_back(new BooleanOption(option + "-", pResult, false)); + } + if (longOption.length() != 0) + { + auto option = "--" + longOption; + options.push_back(new BooleanOption(option, pResult, true)); + options.push_back(new BooleanOption(option + "+", pResult, true)); + options.push_back(new BooleanOption(option + "-", pResult, false)); + } + } + + void AddOption(const std::string &option, bool *pResult) + { + options.push_back(new BooleanOption(option, pResult, true)); + options.push_back(new BooleanOption(option + "+", pResult, true)); + options.push_back(new BooleanOption(option + "-", pResult, false)); + } + + void AddOption(const std::string &shortOption, const std::string &longOption, std::string *pResult) + { + options.push_back(new StringOption("-" + shortOption, pResult)); + options.push_back(new StringOption("--" + longOption, pResult)); + } + + void AddOption(const std::string &option, std::string *pResult) + { + options.push_back(new StringOption(option, pResult)); + } + + template + void AddOption(const std::string &shortOption, const std::string &longOption, T *pResult) + { + if (shortOption.length() != 0) + options.push_back(new Option("-" + shortOption, pResult)); + if (longOption.length() != 0) + options.push_back(new Option("--" + longOption, pResult)); + } + + template + void AddOption(const std::string &option, T *pResult) + { + options.push_back(new Option(option, pResult)); + } + bool Parse(int argc, char **argv) + { + for (int i = 1; i < argc; ++i) + { + const char *arg = argv[i]; + if (arg[0] == '-') + { + int argsConsumed = ProcessOption(arg, argc - i - 1, argv + i + 1); + i += argsConsumed; + } + else + { + args.push_back(std::string(arg)); + } + } + return true; + } + + const std::vector &Arguments() { return args; } +}; diff --git a/NetworkManagerP2P/src/DBusDispatcher.cpp b/NetworkManagerP2P/src/DBusDispatcher.cpp new file mode 100644 index 0000000..f653267 --- /dev/null +++ b/NetworkManagerP2P/src/DBusDispatcher.cpp @@ -0,0 +1,273 @@ +#include "DBusDispatcher.hpp" +#include "DBusLog.hpp" +#include +#include +#include +#include "ss.hpp" +#include +#include + +DBusDispatcher::DBusDispatcher(bool systemBus) +{ + // SignalStop requires this to be true. + + if (systemBus) + { + busConnection = sdbus::createSystemBusConnection(); + } + else + { + busConnection = sdbus::createSessionBusConnection(); + } +} +DBusDispatcher::~DBusDispatcher() +{ + Stop(); + busConnection = nullptr; +} + +DBusDispatcher::PostHandle DBusDispatcher::Post(DBusDispatcher::PostCallback &&fn) +{ + auto nextHandle = NextHandle(); + { + std::lock_guard lock{postMutex}; + this->postedEvents.push_back(CallbackEntry{std::move(fn), clock::time_point::min(), nextHandle}); + } + WakeThread(); + return nextHandle; +} + +bool DBusDispatcher::CancelPost(DBusDispatcher::PostHandle handle) +{ + { + std::lock_guard lock{postMutex}; + for (auto i = postedEvents.begin(); i != postedEvents.end(); ++i) + { + if (i->handle == handle) + { + postedEvents.erase(i); + return true; + } + } + return false; + } +} + +DBusDispatcher::PostHandle DBusDispatcher::PostDelayed(const clock::duration &delay, PostCallback &&fn) +{ + PostHandle nextHandle = NextHandle(); + { + std::lock_guard lock{postMutex}; + + this->postedEvents.emplace_back( + CallbackEntry{ + std::move(fn), + clock::now() + delay, + nextHandle}); + } + WakeThread(); + return nextHandle; +} + +void DBusDispatcher::Run() +{ + this->eventFd = eventfd(0, 0); + this->serviceThread = std::thread( + [this]() + { this->ThreadProc(); }); +} + +void DBusDispatcher::WakeThread() +{ + uint64_t val = 1; + if (eventFd != -1) + { + write(eventFd, &val, sizeof(val)); + } +} +void DBusDispatcher::ThreadProc() +{ + try + { + + while (true) + { + bool idle; + bool quitting; + while (true) + { + idle = true; + quitting = false; + + while (busConnection->processPendingRequest()) + { + idle = false; + } + { + // process one event. + PostCallback callback; + auto now = clock::now(); + { + std::lock_guard lock{postMutex}; + for (auto iter = postedEvents.begin(); iter != postedEvents.end(); ++iter) + { + if (now >= iter->time) + { + callback = std::move(iter->callback); + postedEvents.erase(iter); + idle = false; + break; + } + } + quitting = this->stopping; // transfer with the mutex held. + } + if (callback) + { + callback(); + } + } + if (idle) + { + break; + } + } + if (idle && signalStopRequested) + { + signalStopRequested = false; + if (!signalStopExecuted) // only ever do this once. + { + signalStopExecuted = true; + std::atomic_thread_fence(std::memory_order::acquire); + signalStopCallback(); + signalStopCallback = std::function(); + this->stopping = true; + idle = false; + } + } + if (idle) + { + if (quitting) + { + if (postedEvents.size() == 0) + { + break; + } + } + sdbus::IConnection::PollData pollData = busConnection->getEventLoopPollData(); + + struct pollfd pollFds[2]; + + pollFds[0].fd = pollData.fd; + pollFds[0].events = pollData.events; + pollFds[0].revents = 0; + pollFds[1].fd = this->eventFd; + pollFds[1].events = POLLIN; + pollFds[1].revents = 0; + int pollTimeout = pollData.getPollTimeout(); + int eventTimeout = GetEventTimeoutMs(); + if (eventTimeout != -1 && eventTimeout < pollTimeout) + { + pollTimeout = eventTimeout;/*+-*/ + } + if (pollTimeout > 250 || pollTimeout == -1) + { + pollTimeout = 250; // poll for quit every 250 ms. + } + if (pollTimeout != 0) + { + poll(pollFds, 2, pollTimeout); + + if (pollFds[1].revents & POLLIN) // received a wakup event? + { + uint64_t counter; + read(pollFds[1].fd, &counter, sizeof(counter)); // reset the wakeup event. + } + } + } + } + } + catch (const std::exception &e) + { + std::string msg = SS("Abnormal termination. " << e.what()); + LogError("DBusDispatcher", "ThreadProc", msg); + } + isFinished = true; + LogTrace("DBusDispatcher", "ThreadProc", "Service thread terminated."); +} + +void DBusDispatcher::Wait() +{ + try + { + if (!threadJoined) + { + threadJoined = true; + serviceThread.join(); + } + } + catch (const std::exception &) + { + } + if (eventFd != -1) + { + close(eventFd); + eventFd = -1; + } +} + +bool DBusDispatcher::IsFinished() +{ + return isFinished; +} +void DBusDispatcher::Stop() +{ + if (!closed) + { + closed = true; + + this->stopping = true; + WakeThread(); + Wait(); + } +} + +void DBusDispatcher::SignalStop(std::function &&callback) +{ + this->signalStopCallback = std::move(callback); + std::atomic_thread_fence(::std::memory_order::release); + this->signalStopRequested = true; +} + +int DBusDispatcher::GetEventTimeoutMs() +{ + std::lock_guard lock{postMutex}; + + clock::time_point nextTime = clock::time_point::max(); + for (const auto &event : this->postedEvents) + { + if (event.time == clock::time_point::min()) + return 0; + if (event.time < nextTime) + { + nextTime = event.time; + } + } + if (nextTime == clock::time_point::max()) + { + return -1; + } + auto clockDuration = nextTime - clock::now(); + auto durationMs = std::chrono::duration_cast(clockDuration); + auto ticks = durationMs.count(); + if (ticks > 250) + return 250; + if (ticks < 0) + return 0; + return (int)ticks; +} + +bool DBusDispatcher::IsStopping() +{ + std::lock_guard lock{postMutex}; + return stopping; +} diff --git a/NetworkManagerP2P/src/DBusDispatcher.hpp b/NetworkManagerP2P/src/DBusDispatcher.hpp new file mode 100644 index 0000000..78a8360 --- /dev/null +++ b/NetworkManagerP2P/src/DBusDispatcher.hpp @@ -0,0 +1,81 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include + +namespace sdbus { + class IConnection; +}; + + +class DBusDispatcher { + DBusDispatcher(const DBusDispatcher&) = delete; +public: + DBusDispatcher(bool systemBus = true); + ~DBusDispatcher(); + + void Run(); + // Stop everything, shutting down gracefully. + void Stop(); + void Wait(); + bool IsFinished(); + + // Stop, but don't wait. Suitable for use in a signal handler. + // The callback is executed by the dispatcher thread, and can therefore call non-signal-safe functions. + void SignalStop(std::function &&callback); + + bool IsStopping(); + + using PostHandle = uint64_t; + using PostCallback = std::function; + PostHandle Post(PostCallback&&fn); + + using clock = std::chrono::steady_clock; + + template + DBusDispatcher::PostHandle PostDelayed(const std::chrono::duration&delay,PostCallback&&fn) + { + return PostDelayed( + std::chrono::duration_cast(delay), + std::move(fn)); + } + + DBusDispatcher::PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn); + + bool CancelPost(DBusDispatcher::PostHandle handle); + + sdbus::IConnection&Connection() { return *busConnection;} + +private: + std::atomic isFinished; + std::atomic signalStopRequested; + bool signalStopExecuted = false; + std::function signalStopCallback; + uint64_t NextHandle() { + return nextHandle.fetch_add(1); + } + int GetEventTimeoutMs(); + std::atomic nextHandle; + int eventFd = -1; + bool closed = false; + void ThreadProc(); + void WakeThread(); + std::unique_ptr busConnection; + + struct CallbackEntry { + PostCallback callback; + clock::time_point time; + PostHandle handle; + }; + + std::atomic stopping; + + std::vector postedEvents; + bool threadJoined; + std::thread serviceThread; + std::mutex postMutex; +}; \ No newline at end of file diff --git a/NetworkManagerP2P/src/DBusEvent.cpp b/NetworkManagerP2P/src/DBusEvent.cpp new file mode 100644 index 0000000..a06f285 --- /dev/null +++ b/NetworkManagerP2P/src/DBusEvent.cpp @@ -0,0 +1,7 @@ +#include "DBusEvent.hpp" + + + +namespace impl { + std::atomic NextHandle; +} \ No newline at end of file diff --git a/NetworkManagerP2P/src/DBusEvent.hpp b/NetworkManagerP2P/src/DBusEvent.hpp new file mode 100644 index 0000000..8cf2b11 --- /dev/null +++ b/NetworkManagerP2P/src/DBusEvent.hpp @@ -0,0 +1,58 @@ +#pragma once +#include +#include +#include +#include +#include +#include + +namespace impl { + extern std::atomic NextHandle; +} + +template +class DBusEvent { +public: + using Callback=std::function; + using Handle=uint64_t; + + Handle add(Callback&&cb) + { + auto handle = impl::NextHandle.fetch_add(1,std::memory_order::acq_rel); + { + std::lock_guard lock{m}; + callbacks[handle] = std::make_shared(std::move(cb)); + } + return handle; + } + void remove(Handle h) + { + std::lock_guard lock{m}; + callbacks.erase(h); + } + + void fire(ARG_TYPES...args) + { + std::vector> cbs; + cbs.reserve(callbacks.size()); + { + std::lock_guard lock{m}; + for (const auto &cb: callbacks) + { + cbs.push_back(cb.second); + } + } + for (auto&cb: cbs) + { + (*cb)(args...); + } + { + // destruct shared_ptrs with mutex held. + std::lock_guard lock{m}; + cbs.clear(); + } + } +private: + std::map> callbacks; + std::mutex m; +}; diff --git a/NetworkManagerP2P/src/DBusLog.cpp b/NetworkManagerP2P/src/DBusLog.cpp new file mode 100644 index 0000000..d3a4668 --- /dev/null +++ b/NetworkManagerP2P/src/DBusLog.cpp @@ -0,0 +1,238 @@ +#include "DBusLog.hpp" +#include +#include "ss.hpp" +#include +#include +#include +#include "ss.hpp" +#include + + +namespace impl { + std::mutex logMutex; + DBusLogLevel dbusLogLevel = DBusLogLevel::Info; + +} + +static std::string getDateTime() +{ + auto now = std::chrono::system_clock::now(); + time_t in_time_t = std::chrono::system_clock::to_time_t(now); + auto ms = std::chrono::duration_cast(now.time_since_epoch()) % 1000; + std::stringstream ss; + ss << std::put_time(std::localtime(&in_time_t),"%Y-%m-%d %H:%M:%S"); + ss << '.' << std::setfill('0') << std::setw(3) << ms.count(); + return ss.str(); +} + +class ConsoleDBusLogger : public IDBusLogger { + +public: + void LogError(const std::string&message) { + std::cout << getDateTime() << " error: " << message << std::endl; + } + void LogWarning(const std::string&message){ + std::cout << getDateTime() << " warning: " << message << std::endl; + } + void LogInfo(const std::string&message) { + std::cout << getDateTime() << " info: " << message << std::endl; + } + void LogDebug(const std::string&message) { + std::cout << getDateTime() << " debug: " << message << std::endl; + } + void LogTrace(const std::string&message) { + std::cout << getDateTime() << " trace: " << message << std::endl; + } + +}; +class FileDBusLogger : public IDBusLogger { + +public: + FileDBusLogger(const std::filesystem::path&path) + { + f.open(path); + if (!f) + { + throw std::runtime_error(SS("Can't open file " << path)); + } + } + void LogError(const std::string&message) { + f << "error: " << message << std::endl; + } + void LogWarning(const std::string&message){ + f << "warning: " << message << std::endl; + } + void LogInfo(const std::string&message) { + f << "info: " << message << std::endl; + } + void LogDebug(const std::string&message) { + f << "debug: " << message << std::endl; + } + void LogTrace(const std::string&message) { + f << "trace: " << message << std::endl; + } +private: + std::ofstream f; +}; + +class SystemdDBusLogger : public IDBusLogger { + +public: + void LogError(const std::string&message) { + sd_journal_print(LOG_ERR,"%s",message.c_str()); + + } + void LogWarning(const std::string&message){ + sd_journal_print(LOG_WARNING,"%s",message.c_str()); + } + void LogInfo(const std::string&message) { + sd_journal_print(LOG_INFO,"%s",message.c_str()); + + } + void LogDebug(const std::string&message) { + sd_journal_print(LOG_DEBUG,"%s",message.c_str()); + } + void LogTrace(const std::string&message) { + // no trace level. just log as debug. + sd_journal_print(LOG_DEBUG,"%s",message.c_str()); + } + +}; + + + + +static std::vector> loggers; + + + +void SetDBusLogLevel(DBusLogLevel level) +{ + impl::dbusLogLevel = level; +} + +void LogError(const std::string&path,const char*method,const std::string&message) +{ + if (impl::dbusLogLevel > DBusLogLevel::Error) return; + std::lock_guard lock{impl::logMutex}; + for (auto &logger: loggers) + { + logger->LogError(SS(path<< "::" << method << ": "<< message)); + } +} +void LogInfo(const std::string&path,const char*method,const std::string&message) +{ + if (impl::dbusLogLevel > DBusLogLevel::Info) return; + std::lock_guard lock{impl::logMutex}; + for (auto &logger: loggers) + { + logger->LogInfo(SS(path<< "::" << method<< ": " << message)); + } +} + +void LogDebug(const std::string&path,const char*method,const std::string&message) +{ + if (impl::dbusLogLevel > DBusLogLevel::Debug) return; + std::lock_guard lock{impl::logMutex}; + + for (auto &logger: loggers) + { + logger->LogDebug(SS(path<< "::" << method << ": "<< message)); + } +} + +void LogDebug(const std::string&path,const char*method,const std::function &text) +{ + if (impl::dbusLogLevel > DBusLogLevel::Debug) return; + std::lock_guard lock{impl::logMutex}; + + for (auto &logger: loggers) + { + logger->LogDebug(SS(path<< "::" << method << ": " << text())); + } +} + +void LogTrace(const std::string&path,const char*method,const std::function &text) +{ + if (impl::dbusLogLevel > DBusLogLevel::Trace) return; + std::lock_guard lock{impl::logMutex}; + for (auto &logger: loggers) + { + logger->LogTrace(SS(path<< "::" << method << ": " << text())); + } +} +void LogWarning(const std::string&path,const char*method,const std::function &text) +{ + if (impl::dbusLogLevel > DBusLogLevel::Warning) return; + std::lock_guard lock{impl::logMutex}; + std::string message = text(); + for (auto &logger: loggers) + { + logger->LogWarning(SS(path<< "::" << method << ": " << message)); + } +} +void LogInfo(const std::string&path,const char*method,const std::function &text) +{ + if (impl::dbusLogLevel > DBusLogLevel::Info) return; + std::lock_guard lock{impl::logMutex}; + std::string message = text();; + for (auto &logger: loggers) + { + logger->LogInfo(SS(path<< "::" << method << ": " << message)); + } +} +void LogError(const std::string&path,const char*method,const std::function &text) +{ + if (impl::dbusLogLevel > DBusLogLevel::Error) return; + std::lock_guard lock{impl::logMutex}; + for (auto &logger: loggers) + { + logger->LogError(SS(path<< "::" << method << ": " << text())); + } +} + + +void LogWarning(const std::string&path,const char*method,const std::string&message) +{ + if (impl::dbusLogLevel > DBusLogLevel::Warning) return; + std::lock_guard lock{impl::logMutex}; + for (auto &logger: loggers) + { + logger->LogWarning(SS(path<< "::" << method << ": " << message)); + } +} + + +void LogTrace(const std::string&path,const char*method,const std::string&message) +{ + if (impl::dbusLogLevel > DBusLogLevel::Trace) return; + + std::lock_guard lock{impl::logMutex}; + for (auto &logger: loggers) + { + logger->LogTrace(SS(path<< "::" << method << ": " << message)); + } +} + + +void SetDBusConsoleLogger() +{ + loggers.clear(); + loggers.push_back(std::make_unique()); +} +void AddDBusConsoleLogger() +{ + loggers.push_back(std::make_unique()); +} +void SetDBusSystemdLogger() +{ + loggers.clear(); + loggers.push_back(std::make_unique()); + +} +void SetDBusFileLogger(const std::filesystem::path &path) +{ + loggers.clear(); + loggers.push_back(std::make_unique(path)); +} + diff --git a/NetworkManagerP2P/src/DBusLog.hpp b/NetworkManagerP2P/src/DBusLog.hpp new file mode 100644 index 0000000..bbbcb12 --- /dev/null +++ b/NetworkManagerP2P/src/DBusLog.hpp @@ -0,0 +1,98 @@ +#pragma once +#include +#include +#include +#include +#include + +enum class DBusLogLevel { + Trace, + Debug, + Info, + Warning, + Error, + None +}; + +namespace impl { + extern std::mutex logMutex; + extern DBusLogLevel dbusLogLevel; +} +extern void SetDBusLogLevel(DBusLogLevel level); +inline DBusLogLevel GetDBusLogLevel() { + return impl::dbusLogLevel; +} +inline bool IsDBusLoggingEnabled(DBusLogLevel level) { + return level >= impl::dbusLogLevel; +} + +class IDBusLogger { +public: + IDBusLogger() {} + virtual ~IDBusLogger() { } + virtual void LogError(const std::string&message) = 0; + virtual void LogWarning(const std::string&message) = 0; + virtual void LogInfo(const std::string&message) = 0; + virtual void LogDebug(const std::string&message) = 0; + virtual void LogTrace(const std::string&message) = 0; + +}; + +void SetDBusConsoleLogger(); +void AddDBusConsoleLogger(); +void SetDBusSystemdLogger(); +void SetDBusFileLogger(const std::filesystem::path &path); + +extern void LogError(const std::string&path,const char*method,const std::string&message); +extern void LogInfo(const std::string&path,const char*method,const std::string&message); +extern void LogDebug(const std::string&path,const char*method,const std::string&message); +extern void LogWarning(const std::string&path,const char*method,const std::string&message); +extern void LogTrace(const std::string&path,const char*method,const std::string&message); + +extern void LogTrace(const std::string&path,const char*method,const std::function &text); +extern void LogDebug(const std::string&path,const char*method,const std::function &text); +extern void LogInfo(const std::string&path,const char*method,const std::function &text); +extern void LogWarning(const std::string&path,const char*method,const std::function &text); +extern void LogError(const std::string&path,const char*method,const std::function &text); + + + +class DBusLog { +protected: + DBusLog(const std::string &path) + :path(path) + { + } +protected: + void LogError(const char*tag,const std::string&message) + { + ::LogError(path,tag,message); + } + void LogWarning(const char *tag, const std::string&message) + { + ::LogWarning(path,tag,message); + } + void LogDebug(const char*tag, const std::string &text) + { + ::LogDebug(path,tag,text); + } + void LogDebug(const char*tag, const std::function &text) + { + if (impl::dbusLogLevel > DBusLogLevel::Debug) return; + ::LogDebug(path,tag,text()); + } + void LogTrace(const char*tag, const std::string &text) + { + ::LogTrace(path,tag,text); + } + void LogTrace(const char*tag, const std::function &text) + { + if (impl::dbusLogLevel > DBusLogLevel::Trace) return; + ::LogTrace(path,tag,text()); + } +private: + std::string path; +}; + + + diff --git a/NetworkManagerP2P/src/DBusVariantHelper.cpp b/NetworkManagerP2P/src/DBusVariantHelper.cpp new file mode 100644 index 0000000..4cea124 --- /dev/null +++ b/NetworkManagerP2P/src/DBusVariantHelper.cpp @@ -0,0 +1,175 @@ +#include "DBusVariantHelper.hpp" +#include +#include + + +//std::ostream &operator<<(std::ostream &s, const std::map &properties) +std::ostream&operator<<(std::ostream&s, const sdbus::Variant&v) +{ + // clang-format off +#define HANDLE_VARIANT_TYPE(type) \ + if (v.containsValueOfType()) \ + { \ + s << v.get(); \ + } + + HANDLE_VARIANT_TYPE(std::string) + else if (v.containsValueOfType()) + { + uint8_t value = v.get(); + s << (int)value; + } + else HANDLE_VARIANT_TYPE(uint32_t) + else HANDLE_VARIANT_TYPE(int32_t) + else HANDLE_VARIANT_TYPE(uint64_t) + else HANDLE_VARIANT_TYPE(int64_t) + else HANDLE_VARIANT_TYPE(uint16_t) + else HANDLE_VARIANT_TYPE(int16_t) + else HANDLE_VARIANT_TYPE(bool) + else HANDLE_VARIANT_TYPE(sdbus::Variant) + else if (v.containsValueOfType()) + { + auto objectPath = v.get(); + s << '[' << objectPath.c_str() << ']'; + } + else if (v.containsValueOfType>()) + { + auto values = v.get>(); + { + s << '['; + bool first = true; + for (const sdbus::ObjectPath&value: values) + { + if (!first) s << ", "; + first = false; + s << value.c_str(); + } + s << ']'; + + } + + } + else if (v.containsValueOfType>()) + { + auto paths = v.get >(); + { + s << '['; + bool first = true; + for (const sdbus::ObjectPath&path: paths) + { + if (!first) s << ", "; + first = false; + s << path.c_str(); + } + s << ']'; + + } + } + else if (v.containsValueOfType>()) + { + std::vector bytes = v.get>(); + s << '['; + bool first = true; + for (uint8_t byte: bytes) + { + if (!first) s << ", "; + first = false; + s << (int)byte; + + } + s << ']'; + + } + else if (v.containsValueOfType>>()) + { + auto arrayOfArrays = v.get>>(); + s << '['; + bool first = true; + for (const auto& array: arrayOfArrays) + { + if (!first) s << ", "; + first = false; + bool first2 = true; + for (auto byte: array) + { + if (!first2) s << ", "; + first2 = false; + s << byte; + + } + } + s << ']'; + + } + else if (v.containsValueOfType>()) + { + std::map map = v.get>(); + s << "{"; + bool first = true; + for (const auto &[key, value]: map) + { + if (!first) s << ","; + first = false; + s << '\"' << key << "\": " << value; + } + s << "}"; + } else if (v.containsValueOfType>>()) + { + std::map> values + = v.get>>(); + s << '{'; + bool first = true; + for (const auto &[key,bytes]: values) + { + if (!first) s << ','; + first = false; + s << "{\"" << key << "\": ["; + bool first2 = true; + for (auto b : bytes) + { + if (!first2) s << ','; + first2 = false; + s << b; + } + s << "]"; + } + s << '}'; + + } + + // else HANDLE_VARIANT_TYPE(float) + // else HANDLE_VARIANT_TYPE(double) + // else HANDLE_VARIANT_TYPE(uint64_t) + // else HANDLE_VARIANT_TYPE(int64_t) + // else HANDLE_VARIANT_TYPE(char) + // else HANDLE_VARIANT_TYPE(uint8_t) + // else HANDLE_VARIANT_TYPE(int8_t) + else + { + s << "UNKNOWN VALUE OF TYPE " << v.peekValueType(); + } +#undef HANDLE_VARIANT_TYPE + // clang-format on + return s; +} +std::ostream&operator<<(std::ostream&s,const std::map& properties) +{ + + s << "{"; + bool first = true; + for (const auto &property : properties) + { + if (!first) + { + s << ", "; + } + first = false; + s << '"' << property.first << "\": "; + + const sdbus::Variant &v = property.second; + s << v; + } + + s << "}"; + return s; +} diff --git a/NetworkManagerP2P/src/DBusVariantHelper.hpp b/NetworkManagerP2P/src/DBusVariantHelper.hpp new file mode 100644 index 0000000..1e71671 --- /dev/null +++ b/NetworkManagerP2P/src/DBusVariantHelper.hpp @@ -0,0 +1,11 @@ +#pragma once +#include +#include +#include + +namespace sdbus { + class Variant; +} + +extern std::ostream&operator<<(std::ostream&s, const sdbus::Variant&v); +extern std::ostream&operator<<(std::ostream&s,const std::map& properties); diff --git a/NetworkManagerP2P/src/DnsMasqService.cpp.bak b/NetworkManagerP2P/src/DnsMasqService.cpp.bak new file mode 100644 index 0000000..6a33c60 --- /dev/null +++ b/NetworkManagerP2P/src/DnsMasqService.cpp.bak @@ -0,0 +1,18 @@ +#include "DnsMasqService.hpp" +#include "SysExec.hpp" +#include "ss.hpp" + + +void DnsMasqService::Start(const std::string&confFile, const std::string&wlan) +{ + std::string exec = SS("dnsmasq --conf-file=" << confFile << " --interface=p2p-"<< wlan << "-*"); + + this->pid = (int64_t)pipedal::sysExecAsync(exec); +} +void DnsMasqService::Stop() +{ + if (this->pid != -1) + { + pipedal::sysExecTerminate(pid,1000,500); + } +} \ No newline at end of file diff --git a/NetworkManagerP2P/src/DnsMasqService.hpp.bak b/NetworkManagerP2P/src/DnsMasqService.hpp.bak new file mode 100644 index 0000000..3423ceb --- /dev/null +++ b/NetworkManagerP2P/src/DnsMasqService.hpp.bak @@ -0,0 +1,10 @@ +#pragma once +#include + +class DnsMasqService { +public: + void Start(const std::string&confFile, const std::string&wlan); + void Stop(); +private: + int64_t pid = -1; +}; \ No newline at end of file diff --git a/NetworkManagerP2P/src/Install.cpp b/NetworkManagerP2P/src/Install.cpp new file mode 100644 index 0000000..5e83a13 --- /dev/null +++ b/NetworkManagerP2P/src/Install.cpp @@ -0,0 +1,18 @@ +#include "Install.hpp" +#include "Sudo.hpp" +#include "cassert" +#include "DBusLog.hpp" + +int InstallService() +{ + assert(IsSudo()); + LogInfo("","InstallService",""); + return EXIT_SUCCESS; +} +int UninstallService() +{ + assert(IsSudo()); + LogInfo("","Uninstall",""); + return EXIT_SUCCESS; + +} \ No newline at end of file diff --git a/NetworkManagerP2P/src/Install.hpp b/NetworkManagerP2P/src/Install.hpp new file mode 100644 index 0000000..e329795 --- /dev/null +++ b/NetworkManagerP2P/src/Install.hpp @@ -0,0 +1,3 @@ +#pragma once +extern int InstallService(); +extern int UninstallService(); \ No newline at end of file diff --git a/NetworkManagerP2P/src/NMManager.cpp b/NetworkManagerP2P/src/NMManager.cpp new file mode 100644 index 0000000..3a92fca --- /dev/null +++ b/NetworkManagerP2P/src/NMManager.cpp @@ -0,0 +1,359 @@ +#include "NMManager.hpp" +#include +#include "NetworkManagerInterfaces.hpp" +#include "WpaInterfaces.hpp" +#include "DBusLog.hpp" +#include "NMP2pSettings.hpp" +#include "ss.hpp" + +//////////////////////////////////////////////////////////// + +class NMManagerImpl : public NMManager +{ +public: + NMManagerImpl(); + virtual ~NMManagerImpl(); + virtual void Init(); + virtual void Run(); + virtual void Stop(); + +private: + void MaybeStartWpas(); + void MaybeStopWpas(); + using PostCallback = DBusDispatcher::PostCallback; + void Post(PostCallback &&callback); + + void OnWpaInterfaceAdded(const sdbus::ObjectPath &path); + void OnWpaInterfaceRemoved(const sdbus::ObjectPath &path); + void StartConnection(const std::vector &peerAddress); + +private: + void InitWpaP2PDevice(WpaP2PDevice::ptr &&device); + void InitWpaP2PGoDevice(WpaP2PDevice::ptr &&device); + P2pSettings settings; + DBusDispatcher dispatcher; + WpaSupplicant::ptr wpaSupplicant; + WpaP2PDevice::ptr wpaP2PDevice; + WpaP2PDevice::ptr wpaP2PGoDevice; + WpaGroup::ptr wpaGroup; + Device::ptr nmDevice; + std::string groupPath; +}; + +//////////////////////////////////////////////////////////// +NMManager::NMManager() +{ +} +NMManager::~NMManager() +{ +} + +NMManagerImpl::NMManagerImpl() + : dispatcher(true) +{ +} + +void NMManagerImpl::InitWpaP2PGoDevice(WpaP2PDevice::ptr &&device) +{ + if (this->wpaP2PGoDevice) + return; + this->wpaP2PGoDevice = std::move(device); +} +void NMManagerImpl::InitWpaP2PDevice(WpaP2PDevice::ptr &&device) +{ + if (this->wpaP2PDevice) + return; + + // make sure the NetworkManager and wpa_supplicant objects are for the same device. + std::string wpaInterfaceName = device->Ifname(); + std::string nmInterface = nmDevice->Interface(); + if (nmInterface != "p2p-dev-" + wpaInterfaceName) + { + return; + } + + this->wpaP2PDevice = std::move(device); + + std::map deviceConfig; + deviceConfig["DeviceName"] = SS(settings.device_name()); + deviceConfig["PrimaryDeviceType"] = std::vector{0x00, 0x01, 0x00, 0x50, 0xF2, 0x04, 0x00, 0x01}; + deviceConfig["PersistentReconnect"] = false; + deviceConfig["SsidPostfix"] = SS("-" << settings.device_name()); + deviceConfig["GOIntent"] = (uint32_t)15; + // deviceConfig["PersistentReconnect"] = (uint32_t)2; + // deviceConfig["ListenRegClass"] = (uint32_t)81; + // deviceConfig["ListenChannel"] = (uint32_t)settings.listen_channel(); + // deviceConfig["OperRegClass"] = (uint32_t)81; + // deviceConfig["OperChannel"] = (uint32_t)settings.op_channel(); // ch 1 + + deviceConfig["IpAddrGo"] = std::vector{172, 23, 0, 1}; + deviceConfig["IpAddrMask"] = std::vector{255, 255, 255, 0}; + deviceConfig["IpAddrStart"] = std::vector{172, 23, 0, 10}; + deviceConfig["IpAddrEnd"] = std::vector{172, 23, 0, 250}; + + + wpaP2PDevice->P2PDeviceConfig(deviceConfig); + + { + WpaWPS::ptr wpsDevice = WpaWPS::Create(dispatcher.Connection(), wpaP2PDevice->getObjectPath()); + wpsDevice->DeviceName(settings.device_name()); + wpsDevice->Manufacturer(settings.manufacturer()); + wpsDevice->ModelName(settings.model_name()); + wpsDevice->ModelNumber(settings.model_number()); + wpsDevice->SerialNumber(settings.serial_number()); + wpsDevice->DeviceType(settings.device_type()); + } + + wpaP2PDevice->OnGroupStarted.add( + [this](const std::map &) + { + try + { + Post([this]() + { + LogDebug("NMManager", "OnGroupStarted", "GroupStarted"); + auto group = this->wpaP2PDevice->Group(); + if (!group.empty()) + { + wpaGroup = WpaGroup::Create(dispatcher.Connection(),group); + wpaGroup->OnPeerJoined.add([this](const sdbus::ObjectPath&path) { + Post([this,path]() + { + try { + LogDebug("NMManager","OnPeerJoined",path.c_str()); + } catch (const std::exception&e) + { + LogError("NMManager","OnPeerJoined",e.what()); + + } + } + ); + }); + wpaGroup->OnPeerDisconnected.add([this](const sdbus::ObjectPath&path){ + Post([this,path](){ + LogDebug("NMManager","OnPeerDisconnected",path.c_str()); + }); + }); + } }); + wpaP2PDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + LogInfo(wpaP2PDevice->getObjectPath().c_str(), "OnGoNegotiationFailure", "P2P GO negotiation failed."); + }); + wpaP2PDevice->OnGroupFormationFailure.add( + [this](const std::string &reason) + { + LogInfo(wpaP2PDevice->getObjectPath().c_str(), "OnGroupFormationFailure", + SS("Group formation failed. " << reason)); + }); + } + + catch (const std::exception &e) + { + LogError("P2pManager", "OnGroupStarted", e.what()); + } + }); + + // std::map startParams; + // startParams["Role"] = "registrar"; + // startParams["Pin"] = settings.pin(); + // wpsDevice->Start(startParams); + + wpaP2PDevice->OnGroupFormationFailure.add( + [this](const std::string &reason) + { + Post([this]() + { + if (this->wpaP2PDevice) + { + try { + } catch (const std::exception&e) + { + LogError("NMManager","OnGroupFormationFailure", SS("Listen failed: " << e.what())); + } + } }); + }); + wpaP2PDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + Post([this]() + { + if (this->wpaP2PDevice) + { + try { + } catch (const std::exception&e) + { + LogError("NMManager","OnGONegotiationFailure", SS("Listen failed: " << e.what())); + } + } }); + }); + + wpaP2PDevice->OnProvisionDiscoveryRequestDisplayPin.add( + [this](const sdbus::ObjectPath &peer_object, const std::string &pin) + { + LogTrace("NMManager", "InitWpaP2PDevice", + SS("OnProvisionDiscoveryRequestDisplayPin - " << peer_object.c_str() << " pin: " << pin)); + + Post( + [this, peer_object]() + { + try + { + if (!this->wpaP2PDevice) + return; + WpaPeer::ptr peer = WpaPeer::Create(dispatcher.Connection(), peer_object); + std::vector deviceAddress = peer->DeviceAddress(); + StartConnection(deviceAddress); + } + catch (const std::exception &e) + { + LogError( + "NMManagerImpl", "OnProvisionDiscoveryRequestDisplayPin", + SS("Connection not started. " << e.what())); + }; + }); + }); + + { + this->wpaP2PDevice->Listen((int32_t)5000); + + std::map listenArgs; + listenArgs["interval"] = (int32_t)5000; // listen for... + listenArgs["period"] = (int32_t)100; // check every... + this->wpaP2PDevice->ExtendedListen(listenArgs); + LogInfo(this->wpaP2PDevice->getObjectPath(), "InitWpaP2PDevice", "Listening"); + }; +} +void NMManagerImpl::MaybeStartWpas() +{ + if (!wpaSupplicant) + return; + + try + { + for (const auto &interfacePath : wpaSupplicant->Interfaces()) + { + try + { + auto p2pDevice = WpaP2PDevice::Create(dispatcher.Connection(), interfacePath); + // must be for the same wpa instance as network manager device. + + std::string role = p2pDevice->Role(); + if (role == "GO") + { + this->InitWpaP2PGoDevice(std::move(p2pDevice)); + } + else if (role == "device") + { + this->InitWpaP2PDevice(std::move(p2pDevice)); + } + } + catch (const std::exception &e) + { + LogWarning("NMManager", "MaybeStartWpas", e.what()); + } + } + } + catch (const std::exception &e) + { + LogError("NMManagerImpl", "MaybeStartWpas", e.what()); + } +} +void NMManagerImpl::MaybeStopWpas() +{ +} +void NMManagerImpl::OnWpaInterfaceAdded(const sdbus::ObjectPath &objectPath) +{ + Post([this]() + { MaybeStartWpas(); }); +} +void NMManagerImpl::OnWpaInterfaceRemoved(const sdbus::ObjectPath &objectPath) +{ + Post([this, objectPath]() + { + if (this->wpaP2PDevice && this->wpaP2PDevice->getObjectPath() == objectPath) + { + this->wpaP2PDevice = nullptr; + } + if (this->wpaP2PGoDevice->getObjectPath() == objectPath) + { + this->wpaP2PGoDevice = nullptr; + } }); + MaybeStopWpas(); +} +void NMManagerImpl::Init() +{ + this->wpaSupplicant = WpaSupplicant::Create(dispatcher.Connection()); + + this->wpaSupplicant->OnInterfaceAdded.add( + [this](const sdbus::ObjectPath &path, const std::map &properties) + { + this->OnWpaInterfaceAdded(path); + }); + this->wpaSupplicant->OnInterfaceRemoved.add( + [this](const sdbus::ObjectPath &path) + { + this->OnWpaInterfaceRemoved(path); + }); + + Post([this]() + { + MaybeStartWpas(); }); +} +NMManagerImpl::~NMManagerImpl() +{ + Stop(); +} + + +NMManager::ptr NMManager::Create() +{ + return std::make_unique(); +} + +void NMManagerImpl::Run() +{ + dispatcher.Run(); +} + +void NMManagerImpl::Stop() +{ + if (this->wpaP2PDevice) + { + // no parameters cancels Extended listen. + std::map listenArgs; + this->wpaP2PDevice->ExtendedListen(listenArgs); + } + + wpaP2PDevice = nullptr; + wpaP2PGoDevice = nullptr; + wpaSupplicant = nullptr; + nmDevice = nullptr; + + dispatcher.Stop(); +} + +void NMManagerImpl::Post(NMManagerImpl::PostCallback &&callback) +{ + dispatcher.Post(std::move(callback)); +} + +static const char hexDigits[] = "0123456789ABCDEFx"; + +static std::string peerToString(const std::vector &peer) +{ + std::stringstream s; + bool firstTime = true; + for (uint8_t byte : peer) + { + if (!firstTime) + s << ':'; + firstTime = false; + s << hexDigits[(byte >> 4) & 0x0F] << hexDigits[byte & 0x0F]; + } + return s.str(); +} + +void NMManagerImpl::StartConnection(const std::vector &peer) +{ +} \ No newline at end of file diff --git a/NetworkManagerP2P/src/NMManager.hpp b/NetworkManagerP2P/src/NMManager.hpp new file mode 100644 index 0000000..ad7a8c8 --- /dev/null +++ b/NetworkManagerP2P/src/NMManager.hpp @@ -0,0 +1,14 @@ +#pragma once +#include + +class NMManager { +protected: + NMManager(); +public: + using ptr = std::unique_ptr; + static ptr Create(); + virtual ~NMManager(); + virtual void Init() =0; + virtual void Run() = 0; + virtual void Stop() = 0; +}; \ No newline at end of file diff --git a/NetworkManagerP2P/src/NMP2pSettings.cpp b/NetworkManagerP2P/src/NMP2pSettings.cpp new file mode 100644 index 0000000..598c733 --- /dev/null +++ b/NetworkManagerP2P/src/NMP2pSettings.cpp @@ -0,0 +1,235 @@ +#include "NMP2pSettings.hpp" +#include "WifiDirectConfigSettings.hpp" +#include "ServiceConfiguration.hpp" +#include +#include "ss.hpp" +#include +#include +#include +#include "WifiRegs.hpp" +#include "ChannelInfo.hpp" +#include "DBusLog.hpp" + +using namespace pipedal; +P2pSettings::P2pSettings(const std::filesystem::path&configDirectoryPath) +{ + this->configDirectoryPath = configDirectoryPath; + +} + +static const char*hexDigits = "0123456789abcdef"; +std::string MakeBssid() +{ + // "de:a6:32:d4:a1:66" + std::random_device rDev; + std::uniform_int_distribution dist(0,255); + uint8_t bssid[6]; + + for (size_t i = 0; i < 6; ++i) + { + bssid[i] = dist(rDev); + } + + std::stringstream ss; + bool firstTime = true; + + for (size_t i = 0; i < 6; ++i) + { + if (!firstTime) + { + ss << ':'; + } + firstTime = false; + ss << hexDigits[(bssid[i] >> 4) & 0x0F]; + ss << hexDigits[(bssid[i] >> 0) & 0x0F]; + + } + return ss.str(); + +} +void P2pSettings::Load() +{ + bool configChanged = true; + + // load our json config. + { + auto filename = config_filename(); + if (std::filesystem::exists(filename)) + { + try { + std::ifstream f; + f.open(filename); + if (!f) + { + throw std::runtime_error(SS("Can't open file.")); + } + try { + json_reader reader{f}; + reader.read(this); + configChanged = false; + } catch (const std::exception &e) + { + throw; + } + } catch (const std::exception &e) + { + throw std::runtime_error(SS(e.what() << " (" << filename.string() << ")")); + } + } + + } + + if (this->bssid_.length() == 0) + { + configChanged = true; + this->bssid_ = MakeBssid(); + } + // copy UI settings into our settings. + WifiDirectConfigSettings wifiDirectSettings; // settings from the UI. + wifiDirectSettings.Load(); + + valid_ = false; + if (!wifiDirectSettings.valid_) + { + LogError("NMP2PSettings","Load","Wifi Direct Config Settings are not valid."); + return; + } + if (!wifiDirectSettings.enable_) + { + LogError("NMP2PSettings","Load","Wifi Direct service is not enabled."); + return; + } + valid_ = true; + bool updateRegClass = false; + if (this->country_ != wifiDirectSettings.countryCode_) + { + this->country_ = wifiDirectSettings.countryCode_; + configChanged = true; + updateRegClass = true; + } + { + int channel = 1; + std::stringstream ss(wifiDirectSettings.channel_); + ss >> channel; + + if (this->op_channel_ != channel || this->listen_channel_ != channel) + { + updateRegClass = true; + configChanged = true; + } + this->op_channel_ = channel; + this->listen_channel_ = channel; + if (updateRegClass || this->listen_reg_class_ == 0 || this->op_reg_class_ == 0) + { + // todo: we currently ignore 80khz ac channels (which pi supports) + // + int32_t reg_class = 0; + if (channel == 0) // don't force a channel + { + reg_class = 0; + } else { + reg_class = getWifiRegClass(this->country_,channel,40); + if (reg_class == -1) + { + throw std::runtime_error(SS("Wifi Channel " << channel << " is not allowed in country " << this->country_)); + } + } + configChanged |= this->op_reg_class_ != reg_class; + configChanged |= this->listen_reg_class_ != reg_class; + + this->op_reg_class_ = reg_class; + this->listen_reg_class_ = reg_class; + } + } + if (updateRegClass) + { + } + + if (wifiDirectSettings.hotspotName_ != this->device_name_) + { + configChanged = true; + this->device_name_ = wifiDirectSettings.hotspotName_; + this->auth_changed_ = true; + } + if (this->pin_ != wifiDirectSettings.pin_) + { + configChanged = true; + this->auth_changed_ = true; + this->pin_ = wifiDirectSettings.pin_; + } + if (this->wlan_ != wifiDirectSettings.wlan_) + { + configChanged = true; + this->auth_changed_ = true; + this->wlan_ = wifiDirectSettings.wlan_; + } + + ServiceConfiguration serviceConfiguration; + serviceConfiguration.Load(); + if ((int)serviceConfiguration.server_port != this->web_server_port_) + { + configChanged = true; + this->web_server_port_ = (int)serviceConfiguration.server_port; + } + if (this->service_uuid() != serviceConfiguration.uuid) + { + configChanged = true; + this->service_uuid_ = serviceConfiguration.uuid; + } + + if (wifiDirectSettings.pinChanged_) + { + wifiDirectSettings.pinChanged_ = false; + wifiDirectSettings.Save(); + } + if (configChanged) + { + Save(); + } + +} +void P2pSettings::Save() +{ + auto filename = config_filename(); + try { + std::ofstream f(filename); + if (!f) + { + throw std::runtime_error("Can't write to file."); + } + json_writer writer{f,false}; + writer.write(this); + } catch (const std::exception &e) + { + throw std::runtime_error(SS(e.what() << " (" << filename.string() << ")")); + } +} + +int32_t P2pSettings::op_frequency() const +{ + return wifiChannelToFrequency(this->op_channel_); + +} +JSON_MAP_BEGIN(P2pSettings) +JSON_MAP_REFERENCE(P2pSettings,wlan) +JSON_MAP_REFERENCE(P2pSettings,driver) +JSON_MAP_REFERENCE(P2pSettings,bssid) +JSON_MAP_REFERENCE(P2pSettings,country) +JSON_MAP_REFERENCE(P2pSettings,persistent_reconnect) +JSON_MAP_REFERENCE(P2pSettings,config_methods) +JSON_MAP_REFERENCE(P2pSettings,manufacturer) +JSON_MAP_REFERENCE(P2pSettings,model_name) +JSON_MAP_REFERENCE(P2pSettings,model_number) +JSON_MAP_REFERENCE(P2pSettings,serial_number) +JSON_MAP_REFERENCE(P2pSettings,pin) +JSON_MAP_REFERENCE(P2pSettings,service_uuid) +JSON_MAP_REFERENCE(P2pSettings,listen_channel) +JSON_MAP_REFERENCE(P2pSettings,listen_reg_class) +JSON_MAP_REFERENCE(P2pSettings,op_channel) +JSON_MAP_REFERENCE(P2pSettings,op_reg_class) +JSON_MAP_REFERENCE(P2pSettings,web_server_port) +JSON_MAP_REFERENCE(P2pSettings,device_name) +JSON_MAP_REFERENCE(P2pSettings,auth_changed) + + +JSON_MAP_END() \ No newline at end of file diff --git a/NetworkManagerP2P/src/NMP2pSettings.hpp b/NetworkManagerP2P/src/NMP2pSettings.hpp new file mode 100644 index 0000000..6e8d11a --- /dev/null +++ b/NetworkManagerP2P/src/NMP2pSettings.hpp @@ -0,0 +1,87 @@ +#pragma once +#include +#include +#include +#include "json.hpp" + + +class P2pSettings { + // adapter between nm p2p settings, and legacy p2p +public: + P2pSettings(const std::filesystem::path&configDirectory = "/etc/pipedal/config"); + + void Load(); + void Save(); + +private: + bool valid_ = false; + std::filesystem::path configDirectoryPath; + bool auth_changed_ = true; + std::vector device_type_{ + 0x00,0x01, 0x00,0x50,0xF2,0x04, 0x00,0x02 /*"1-0050F204-2";*/ + }; + std::string wlan_ = "wlan0"; + std::string driver_ = "nl80211"; + std::string bssid_ = ""; + std::string country_ = "US"; + bool persistent_reconnect_ = true; + std::vector config_methods_ = {"display" }; + std::string manufacturer_ = "PiPedal Project"; + std::string model_name_ = "PiPedal"; + std::string model_number_ = "3"; + std::string serial_number_ = "1"; + std::string pin_ = "12345678"; + std::string service_uuid_ = "233e7c60-9f06-40c5-a53a-875279a44751"; + int32_t op_reg_class_ = 81; + int32_t op_channel_ = 1; + int32_t listen_channel_ = 1; + int32_t listen_reg_class_ = 81; + int web_server_port_ = 80; + std::string device_name_ = "PiPedalS5"; +public: + bool valid() const { return valid_; } + std::string device_name() const { return device_name_; } + + const std::vector& device_type() const { return device_type_; } + bool auth_changed() const { return auth_changed_; } + void auth_changed(bool value) { auth_changed_ = value; } + std::string wlan() const { return wlan_; } + + std::string driver() const { return driver_; } + std::string wpas_config_file() const { + // "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"; } + return (configDirectoryPath / "wpa_supplicant" / "wpa_supplicant-pipedal.conf").string(); + }; + + std::string dnsmasq_config_file() const { + // "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"; } + return (configDirectoryPath / "dnsmasq" / "dnsmasq-pipedal-nm.conf").string(); + }; + std::filesystem::path config_filename() const { + // "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"; } + return (configDirectoryPath / "NetworkManagerP2P.json").string(); + }; + + const std::string& bssid() const { return bssid_; } + std::string country() const { return country_; } + bool persistent_reconnect() const { return persistent_reconnect_; } + uint8_t p2p_go_intent() const { return 15; } + //const std::vector& config_methods() const { return config_methods_;} + const std::string& manufacturer() const { return manufacturer_; } + const std::string& model_name() const { return model_name_; } + const std::string& model_number() const { return model_number_; } + const std::string& serial_number() const {return serial_number_; } + const std::string& pin() const { return pin_; } + + const std::string &service_uuid() const { return service_uuid_; } + int32_t op_reg_class() { return op_reg_class_; } + int32_t op_channel() { return op_channel_; } // Should be social channel 1, 6 or 11. + int32_t op_frequency() const; + + int32_t listen_reg_class() { return listen_reg_class_; } + int32_t listen_channel() { return listen_channel_; /*ch1*/ } // . Should be social channel 1, 6 or 11. + + int web_server_port() { return web_server_port_; } +public: + DECLARE_JSON_MAP(P2pSettings); +}; \ No newline at end of file diff --git a/NetworkManagerP2P/src/NetworkManagerInterfaces.cpp b/NetworkManagerP2P/src/NetworkManagerInterfaces.cpp new file mode 100644 index 0000000..46d5131 --- /dev/null +++ b/NetworkManagerP2P/src/NetworkManagerInterfaces.cpp @@ -0,0 +1,45 @@ +#include "NetworkManagerInterfaces.hpp" +#include "ss.hpp" + +using namespace impl; + +namespace impl +{ + std::string NetworkManagerStateToString(uint32_t state) + { + // STUB: Not clear which state enum we're getting. + std::stringstream s; + s << state; + return s.str(); + } + + std::string NetworkManagerDeviceStateToString(uint32_t state) + { +#define DEVICE_CASE(name, value) \ + case value: \ + return #name; + + switch (state) + { + DEVICE_CASE(NM_DEVICE_STATE_UNKNOWN, 0) + DEVICE_CASE(NM_DEVICE_STATE_UNMANAGED, 10) + DEVICE_CASE(NM_DEVICE_STATE_UNAVAILABLE, 20) + DEVICE_CASE(NM_DEVICE_STATE_DISCONNECTED, 30) + DEVICE_CASE(NM_DEVICE_STATE_PREPARE, 40) + DEVICE_CASE(NM_DEVICE_STATE_CONFIG, 50) + DEVICE_CASE(NM_DEVICE_STATE_NEED_AUTH, 60) + DEVICE_CASE(NM_DEVICE_STATE_IP_CONFIG, 70) + DEVICE_CASE(NM_DEVICE_STATE_IP_CHECK, 80) + DEVICE_CASE(NM_DEVICE_STATE_SECONDARIES, 90) + DEVICE_CASE(NM_DEVICE_STATE_ACTIVATED, 100) + DEVICE_CASE(NM_DEVICE_STATE_DEACTIVATING, 110) + DEVICE_CASE(NM_DEVICE_STATE_FAILED, 120) + default: + { + std::stringstream s; + s << state; + return s.str(); + } + } + } +} diff --git a/NetworkManagerP2P/src/NetworkManagerInterfaces.hpp b/NetworkManagerP2P/src/NetworkManagerInterfaces.hpp new file mode 100644 index 0000000..9046a41 --- /dev/null +++ b/NetworkManagerP2P/src/NetworkManagerInterfaces.hpp @@ -0,0 +1,188 @@ +#pragma once + +#include "DBusEvent.hpp" +#include "DBusLog.hpp" +#include "DBusDispatcher.hpp" + +#include "dbus/hpp/org.freedesktop.NetworkManager.Device.WifiP2P.hpp" +#include "dbus/hpp/org.freedesktop.NetworkManager.Device.hpp" +#include "dbus/hpp/org.freedesktop.NetworkManager.WifiP2PPeer.hpp" +#include "dbus/hpp/org.freedesktop.NetworkManager.hpp" + +namespace impl { + extern std::string NetworkManagerStateToString(uint32_t state); + std::string NetworkManagerDeviceStateToString(uint32_t state); +}; + +class NetworkManager : public sdbus::ProxyInterfaces +{ +public: + using ptr = std::unique_ptr; + NetworkManager(DBusDispatcher &dispatcher) + : sdbus::ProxyInterfaces( + dispatcher.Connection(), + INTERFACE_NAME, + "/org/freedesktop/NetworkManager") + { + registerProxy(); + } + virtual ~NetworkManager() + { + unregisterProxy(); + } + + static ptr Create(DBusDispatcher &dispatcher) { return std::make_unique(dispatcher); } + DBusEvent<> OnCheckPermissions; + DBusEvent OnStateChanged; + DBusEvent OnDeviceAdded; + DBusEvent OnDeviceRemoved; + +private: + void EventTrace(const char*method, const std::string &message) { + LogTrace(getObjectPath(),method,message); + } + virtual void onStateChanged(const uint32_t &state) { + EventTrace("onStateChanged",impl::NetworkManagerStateToString(state)); + OnStateChanged.fire(state); + } + + virtual void onCheckPermissions() { OnCheckPermissions.fire(); } + + virtual void onDeviceAdded(const sdbus::ObjectPath &device_path) { + EventTrace("onDeviceAdded",device_path.c_str()); + OnDeviceAdded.fire(device_path); + } + virtual void onDeviceRemoved(const sdbus::ObjectPath &device_path) { + EventTrace("onDeviceRemoved",device_path.c_str()); + + OnDeviceRemoved.fire(device_path); + } +}; + +class Device : public sdbus::ProxyInterfaces +{ +public: + using ptr = std::unique_ptr; + Device(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path) + : sdbus::ProxyInterfaces( + dispatcher.Connection(), + "org.freedesktop.NetworkManager", + path) + { + registerProxy(); + } + virtual ~Device() + { + unregisterProxy(); + } + + static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path) + { + return std::make_unique(dispatcher, path); + } + DBusEvent OnStateChanged; + +private: + const uint32_t NM_DEVICE_TYPE_WIFI_P2P = 30; // from lbnm-dev package. +public: + bool IsP2pDevice() + { + return this->DeviceType() == NM_DEVICE_TYPE_WIFI_P2P; + } + +private: + void EventTrace(const char*method, const std::string &message) { + LogTrace(getObjectPath(),method,message); + } + + virtual void onStateChanged(const uint32_t &new_state, const uint32_t &old_state, const uint32_t &reason) + { + EventTrace("onStateChanged",impl::NetworkManagerDeviceStateToString(new_state)); + + OnStateChanged.fire(new_state, old_state, reason); + } +}; +class WifiP2P : public sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::Device::WifiP2P_proxy + > +{ +public: + using ptr = std::unique_ptr; + using base = sdbus::ProxyInterfaces< + org::freedesktop::NetworkManager::Device::WifiP2P_proxy + >; + + WifiP2P(DBusDispatcher &dispatcher, const std::string &objectPath) + : base(dispatcher.Connection(), "org.freedesktop.NetworkManager", objectPath) + { + registerProxy(); + } + virtual ~WifiP2P() + { + unregisterProxy(); + } + static ptr Create(DBusDispatcher &dispatcher, const std::string &objectPath) + { + return std::make_unique(dispatcher, objectPath); + } + DBusEvent OnPeerAdded; + DBusEvent OnPeerRemoved; + DBusEvent OnStateChanged; + +private: + void EventTrace(const char*method, const std::string &message) { + LogTrace(getObjectPath(),method,message); + } + virtual void onStateChanged(const uint32_t &new_state, const uint32_t &old_state, const uint32_t &reason) + { + EventTrace("onStateChanged",impl::NetworkManagerStateToString(new_state)); + + OnStateChanged.fire(new_state); + } + + virtual void onPeerAdded(const sdbus::ObjectPath &peer) + { + EventTrace("onPeerAdded",peer); + OnPeerAdded.fire(peer); + } + virtual void onPeerRemoved(const sdbus::ObjectPath &peer) + { + EventTrace("onPeerRemoved",peer); + OnPeerRemoved.fire(peer); + } +}; + +class WifiP2PPeer : public sdbus::ProxyInterfaces +{ +public: + using self=WifiP2PPeer; + using ptr = std::unique_ptr; + + WifiP2PPeer(DBusDispatcher &dispatcher, const sdbus::ObjectPath &objectPath) + : sdbus::ProxyInterfaces( + dispatcher.Connection(), "org.freedesktop.NetworkManager", objectPath) + { + registerProxy(); + } + virtual ~WifiP2PPeer() + { + unregisterProxy(); + } + static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &objectPath) + { + return std::make_unique(dispatcher, objectPath); + } + DBusEvent OnPeerAdded; + DBusEvent OnPeerRemoved; + +private: + virtual void onPeerAdded(const sdbus::ObjectPath &peer) + { + OnPeerAdded.fire(peer); + } + virtual void onPeerRemoved(const sdbus::ObjectPath &peer) + { + OnPeerRemoved.fire(peer); + } +}; + diff --git a/NetworkManagerP2P/src/P2PManager.cpp b/NetworkManagerP2P/src/P2PManager.cpp new file mode 100644 index 0000000..417cbde --- /dev/null +++ b/NetworkManagerP2P/src/P2PManager.cpp @@ -0,0 +1,1442 @@ +#ifndef USE_NETWORKMANAGER +#include "P2PManager.hpp" +#include "ss.hpp" +#include +#include +#include + +#include "WpaInterfaces.hpp" +#include "NMP2pSettings.hpp" +#include +#include +#include + +#include "DBusDispatcher.hpp" +#include "NetworkManagerInterfaces.hpp" +#include "DBusVariantHelper.hpp" +#include "SignalHandler.hpp" + +static const char CONFIG_METHODS[] = "keypad"; +static const char CONFIG_CONNECT_METHOD[] = "display"; + +enum class p2p_status_code +{ + P2P_SC_SUCCESS = 0, + P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1, + P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2, + P2P_SC_FAIL_LIMIT_REACHED = 3, + P2P_SC_FAIL_INVALID_PARAMS = 4, + P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5, + P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6, + P2P_SC_FAIL_NO_COMMON_CHANNELS = 7, + P2P_SC_FAIL_UNKNOWN_GROUP = 8, + P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9, + P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10, + P2P_SC_FAIL_REJECTED_BY_USER = 11, + P2P_SC_SUCCESS_DEFERRED = 12, +}; + +std::string InvitationStatusToString(int32_t status_code_) +{ + if (status_code_ == -1) + { + return "FAIL"; + } + p2p_status_code status_code = (p2p_status_code)status_code_; +#define STATUS_CODE_CASE(x) \ + case p2p_status_code::x: \ + return #x; + switch (status_code) + { + STATUS_CODE_CASE(P2P_SC_SUCCESS) + STATUS_CODE_CASE(P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE) + STATUS_CODE_CASE(P2P_SC_FAIL_INCOMPATIBLE_PARAMS) + STATUS_CODE_CASE(P2P_SC_FAIL_LIMIT_REACHED) + STATUS_CODE_CASE(P2P_SC_FAIL_INVALID_PARAMS) + STATUS_CODE_CASE(P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE) + STATUS_CODE_CASE(P2P_SC_FAIL_PREV_PROTOCOL_ERROR) + STATUS_CODE_CASE(P2P_SC_FAIL_NO_COMMON_CHANNELS) + STATUS_CODE_CASE(P2P_SC_FAIL_UNKNOWN_GROUP) + STATUS_CODE_CASE(P2P_SC_FAIL_BOTH_GO_INTENT_15) + STATUS_CODE_CASE(P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD) + STATUS_CODE_CASE(P2P_SC_FAIL_REJECTED_BY_USER) + STATUS_CODE_CASE(P2P_SC_SUCCESS_DEFERRED) + + default: + return "UNKNOWN_STATUS"; + } +#undef STATUS_CODE_CASE +} +class P2PManagerImpl : public P2PManager +{ +public: + P2PManagerImpl() : dispatcher(true) {} + virtual ~P2PManagerImpl(); + + bool Init() override; + void Run() override; + void Stop() override; + bool IsFinished() override; + void Wait() override; + bool ReloadRequested() override; + bool TerminatedNormally() override; + +private: + using clock = std::chrono::steady_clock; + + void OnServiceDiscoveryRequest(const std::map &sd_request); + + void CancelDelayedConnectDevice(); + void DelayedConnectDevice(const sdbus::ObjectPath&peer_object); + void OnInvitationResult(const sdbus::ObjectPath &objectPath, const std::map &invite_result); + sdbus::ObjectPath GetActivePersistentGroup(); + void StartListen(); + void SignalStop(); + void SignalHangup(); + void ExecuteOrderlyShutdown(); + void ShutdownStage2(); + void TurnOnWifi(); + void UnInitialize(); + void StartWaitUntilDone(); + void PostWaitUntilDone(); + void MaybeRemoveGroup(); + void CancelMaybeRemoveGroup(); + void MaybeCancel(); + + void StartGroup(); + bool HasPersistentGroup(); + void AddExistingInterfaces(); + void RemoveExistingInterfaces(); + void HandleInterfaceAdded(const std::string &objectPath); + void HandleInterfaceRemoved(const std::string &objectPath); + void InitWpaP2PDevice(WpaP2PDevice::ptr&&device); + void InitWpaP2PGoDevice(WpaP2PDevice::ptr&&device); + void ConnectDevice(const sdbus::ObjectPath &peer_object, bool enterRequest); + bool HasClient(); + std::string UpnpServiceName(); + void StartServiceBroadcast(); + void StopServiceBroadcast(); + + std::atomic reloadRequested{false}; + std::atomic signalStop{false}; + std::atomic normalTermination{false}; + bool signalStopStarted = false; + bool shutdownExecuted = false; + bool waited = false; + bool serviceBroadcastStarted = false; + DBusDispatcher dispatcher; + DBusDispatcher::PostHandle maybeCloseHandle = 0; + DBusDispatcher::PostHandle delayedConnectHandle = 0; + std::mutex postMutex; + std::atomic stopping; + std::vector pendingAddedInterfaces; + + using PostCallback = DBusDispatcher::PostCallback; + using PostHandle = DBusDispatcher::PostHandle; + void Post(PostCallback &&fn); + + WpaSupplicant::ptr wpaSupplicant; + WpaP2PDevice::ptr p2pDevice; + WpaP2PDevice::ptr p2pGoDevice; + WpaWPS::ptr wpsDevice; + WpaGroup::ptr wpaGroup; + std::vector connectedPeers; + + sdbus::ObjectPath persistentGroupPath; + P2pSettings settings{}; + + std::string oldWpasDebugLevel; + clock::time_point stage2Timeout; + clock::time_point waitUntilDoneTimeout; +}; + +P2PManager::ptr P2PManager::Create() +{ + return std::make_unique(); +} + +P2PManagerImpl::~P2PManagerImpl() +{ + CancelDelayedConnectDevice(); + Stop(); +} + +static const char hexDigits[] = "0123456789abcdef"; + +static std::string AddressToString(const std::vector &address) +{ + std::stringstream ss; + bool firstTime = true; + for (auto byte : address) + { + if (!firstTime) + { + ss << ":"; + } + firstTime = false; + ss << hexDigits[(byte >> 4) & 0x0F] << hexDigits[byte & 0x0F]; + } + return ss.str(); +} + +void P2PManagerImpl::OnInvitationResult(const sdbus::ObjectPath &objectPath, const std::map &invite_result) +{ + int32_t status; + try + { + status = invite_result.at("status"); + } + catch (const std::exception &) + { + status = -1; + } + std::string strStatus = InvitationStatusToString(status); + if (status == 0) + { + LogDebug(objectPath, "OnInvitationResult", strStatus); + } + else + { + LogInfo(objectPath, "OnInvitationResult", strStatus); + } +} + +void P2PManagerImpl::RemoveExistingInterfaces() +{ + try + { + while (true) + { + if (!this->wpaSupplicant) + break; + + auto interfaces = this->wpaSupplicant->Interfaces(); + if (interfaces.size() == 0) + break; + + wpaSupplicant->RemoveInterface(interfaces[0]); + } + } + catch (const std::exception &e) + { + LogWarning("P2PManagerImpl", "RemoveExistingInterfaces", e.what()); + } +} +bool P2PManagerImpl::Init() +{ + settings.Load(); + if (!settings.valid()) + { + return false; + } + + LogInfo( + "P2PManager", + "Init", + SS( + "Configuration:" + << " " << settings.country() + << " " << settings.wlan() + << " " << settings.device_name() + << " " << settings.web_server_port() + << " " << settings.listen_channel() + << " " << settings.op_channel())); + SignalHandler::HandleSignal( + SignalHandler::Interrupt, + [this]() + { + this->normalTermination = true; // don't restart service + this->SignalStop(); + }); + SignalHandler::HandleSignal( + SignalHandler::Terminate, + [this]() + { + this->normalTermination = true; // don't restart service + this->SignalStop(); + }); + SignalHandler::HandleSignal( + SignalHandler::Hangup, + [this]() + { + this->normalTermination = false; // don't restart service + this->SignalStop(); // we can't restart, but at lease we can do an orderly shutdown. + // disable this, because sdbus::dispatcher doesn't seem to be able to handle a restart. + // this->SignalHangup(); + }); + +#ifdef DEBUG + dispatcher.Connection().setMethodCallTimeout(500 * 1000 * 1000); +#endif + + for (int retry = 0; retry < 4; ++retry) // defend against slow starup of wpa_supplicant + { + try + { + this->wpaSupplicant = WpaSupplicant::Create(dispatcher.Connection()); + this->wpaSupplicant->DebugLevel(); + if (retry != 0) + { + LogInfo("P2PManager", "Init", "wpa_supplicant DBus connection established."); + } + break; + } + catch (std::exception &e) + { + if (retry == 0) + { + LogInfo("P2PManager", "Init", "Waiting for wpa_supplicant DBus connection."); + } + this->wpaSupplicant = nullptr; + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + } + if (!this->wpaSupplicant) + { + throw std::runtime_error("wpa_supplicant service is not reachable by DBus."); + } + + std::string wpaLogLevel = "info"; + switch (GetDBusLogLevel()) + { + default: + case DBusLogLevel::Info: + wpaLogLevel = "info"; + break; + case DBusLogLevel::Debug: + wpaLogLevel = "debug"; + break; + case DBusLogLevel::Warning: + wpaLogLevel = "warning"; + break; + case DBusLogLevel::Error: + wpaLogLevel = "error"; + break; + case DBusLogLevel::Trace: + wpaLogLevel = "debug"; + break; + } + oldWpasDebugLevel = wpaSupplicant->DebugLevel(); + wpaSupplicant->DebugLevel(wpaLogLevel); + + TurnOnWifi(); + + this->wpaSupplicant->OnInterfaceAdded.add( + [this](const sdbus::ObjectPath &path, const std::map &properties) + { + this->HandleInterfaceAdded(path); + }); + this->wpaSupplicant->OnInterfaceRemoved.add( + [this](const sdbus::ObjectPath &path) + { + this->HandleInterfaceRemoved(path); + }); + + RemoveExistingInterfaces(); + if (wpaSupplicant->Interfaces().size() == 0) + { + std::map createArgs; + createArgs["Ifname"] = settings.wlan(); + createArgs["Driver"] = settings.driver(); + createArgs["ConfigFile"] = settings.wpas_config_file(); + wpaSupplicant->CreateInterface(createArgs); + } + return true; +} + +void P2PManagerImpl::AddExistingInterfaces() +{ + if (!this->p2pDevice) + { + for (const auto &objectPath : this->wpaSupplicant->Interfaces()) + { + HandleInterfaceAdded(objectPath); + } + } +} + +void P2PManagerImpl::HandleInterfaceRemoved(const std::string &objectPath) +{ + bool deleted = false; + + // removal from pending list can be done in a handler. + for (auto i = this->pendingAddedInterfaces.begin(); i != pendingAddedInterfaces.end(); ++i) + { + if (*i == objectPath) + { + pendingAddedInterfaces.erase(i); + return; + } + } + // removal of existing objects needs to be posted. + Post([this, objectPath]() + { + if (this->p2pDevice && this->p2pDevice->getObjectPath() == objectPath) + { + CancelDelayedConnectDevice(); + this->p2pDevice = nullptr; + this->wpsDevice = nullptr; + dispatcher.SignalStop( + [this]() + { + UnInitialize(); // shut down, wpa_supplicant has stopped. + }); + } + if (this->p2pGoDevice && this->p2pGoDevice->getObjectPath() == objectPath) + { + this->wpaGroup = nullptr; + this->p2pGoDevice = nullptr; + StartListen(); + } }); +} + +void P2PManagerImpl::HandleInterfaceAdded(const std::string &objectPath) +{ + + // Create the objects in the callback, but defer processing. + // Guard against the interface being synchronously removed before the async post handler excecutes./ + this->pendingAddedInterfaces.push_back(objectPath.c_str()); + { + std::string msg = SS("Device added: " << objectPath.c_str()); + LogDebug("P2PManagerImpl", "HandleInterfaceAdded", msg); + } + + Post([this, + objectPath]() mutable + { + // check to see whether the new interface was removed from pending list. + auto found = std::find(pendingAddedInterfaces.begin(),pendingAddedInterfaces.end(),objectPath); + if (found != pendingAddedInterfaces.end()) + { + pendingAddedInterfaces.erase(found); + try { + auto p2pDevice = WpaP2PDevice::Create(dispatcher.Connection(), objectPath); + + LogDebug(objectPath,"HandleInterfaceAdded",SS("Role: " << p2pDevice->Role())); + if (p2pDevice->Role() == "device" && ((!this->p2pDevice) || this->p2pDevice->getObjectPath() != objectPath)) + { + LogDebug("P2PManagerImpl", "HandleInterfaceAdded", "P2P device found."); + InitWpaP2PDevice(std::move(p2pDevice)); + } + else if (p2pDevice->Role() == "GO" && ((!this->p2pGoDevice) || this->p2pGoDevice->getObjectPath() != objectPath)) + { + LogDebug("P2PManagerImpl", "HandleInterfaceAdded", "P2P GO group interface found."); + + InitWpaP2PGoDevice(std::move(p2pDevice)); + } + } catch (const std::exception&e) + { + LogError("P2PManagerImpl","HandleInterfaceAdded",SS("Failed to add " << objectPath.c_str() << " (" << e.what() << ")")); + } + } }); +} + +void P2PManagerImpl::InitWpaP2PGoDevice(WpaP2PDevice::ptr&&device) +{ + this->p2pGoDevice = std::move(device); + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + auto deviceConfig = p2pGoDevice->P2PDeviceConfig(); + std::stringstream s; + s << deviceConfig; + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("GO Device config: " << s.str())); + } + p2pGoDevice->ConfigMethods(CONFIG_METHODS); + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("ConfigMethods: " << p2pGoDevice->ConfigMethods())); + + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + auto deviceConfig = p2pGoDevice->P2PDeviceConfig(); + std::stringstream s; + s << deviceConfig; + LogTrace("P2PManager", "InitWpaP2PGoDevice", SS("P2PDeviceConfig: " << s.str())); + } + + + p2pGoDevice->OnInvitationResult.add( + [this](const std::map &invite_result) + { + OnInvitationResult(p2pDevice->getObjectPath(), invite_result); + }); + + p2pGoDevice->OnStaAuthorized.add( + [this](const std::string &name) + { + LogInfo( + p2pGoDevice->getObjectPath(), + "OnStationAuthorized", + SS("Station authorized: " << name)); + }); + p2pGoDevice->OnStaDeauthorized.add( + [this](const std::string &name) + { + LogInfo( + p2pGoDevice->getObjectPath(), + "OnStationDeauthorized", + SS("Station deauthorized: " << name)); + }); + + p2pGoDevice->OnWpsFailed.add( + [this](const std::string &name, const std::map &args) + { + { + std::stringstream ss; + ss << name << " " << args << " "; + LogError("P2PManagerImp", "OnWpsFailed", ss.str()); + } + try + { + this->p2pGoDevice->Cancel(); + } + catch (const std::exception &) + { + } + MaybeRemoveGroup(); + }); + p2pGoDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + std::stringstream ss; + ss << info; + LogError(p2pGoDevice->getObjectPath().c_str(),"OnGoNegotiationFailure",ss.str()); }); + p2pGoDevice->OnGroupFormationFailure.add( + [this](const std::string &message) + { + std::stringstream ss; + ss << message; + LogError(p2pGoDevice->getObjectPath().c_str(), "OnGroupFormationFailure", ss.str()); + MaybeRemoveGroup(); + }); + + p2pGoDevice->OnStationAdded.add( + [this](const sdbus::ObjectPath &path, const std::map &properties) { + + }); + p2pGoDevice->OnStationRemoved.add( + [this](const sdbus::ObjectPath &) + { + MaybeRemoveGroup(); + }); + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("GoCountry: " << p2pGoDevice->Country())); + + p2pGoDevice->OnProvisionDiscoveryRequestDisplayPin.add( + [this](const sdbus::ObjectPath &peer_object, const std::string &pin) + { + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", + SS("GO OnProvisionDiscoveryRequestDisplayPin - " << peer_object.c_str() << " pin: " << pin)); + }); +} + +bool P2PManagerImpl::HasClient() +{ + return this->p2pDevice->Stations().size() != 0; +} + +void P2PManagerImpl::CancelDelayedConnectDevice() +{ + if (delayedConnectHandle) { + dispatcher.CancelPost(delayedConnectHandle); + delayedConnectHandle = 0; + } + +} +void P2PManagerImpl::DelayedConnectDevice(const sdbus::ObjectPath&peer_object) +{ + delayedConnectHandle = 0; + if (dispatcher.IsStopping()) return; // brief race window during shutdown. + if (!p2pGoDevice) + { + ConnectDevice(peer_object,false); + } else { + delayedConnectHandle = dispatcher.PostDelayed( + std::chrono::milliseconds(500), + [this,peer_object]() + { + DelayedConnectDevice(peer_object); + } + ); + } +} + +void P2PManagerImpl::ConnectDevice(const sdbus::ObjectPath &peer_object, bool enterRequest) +{ + // The implemented behaviour: if a second connection request comes in, disconnect the first connection + // before establishing the second connection. + // + // I've tried every way I can think of to allow a second group member, without success. + // if we received a connection request with a a currently active group, + // disconnect the group, asynchronously, waiting for the group intefrace to close, and THEN issue the connect call. +#if 1 + CancelDelayedConnectDevice(); + if (this->p2pGoDevice) + { + try { + this->p2pGoDevice->Disconnect(); + } catch (const std::exception &e) + { + LogDebug("P2PManager","ConnectDevice",SS("Disconnect failed. " << e.what())); + try { + this->wpaSupplicant->RemoveInterface(p2pGoDevice->getObjectPath()); // draconian! + } catch (const std::exception&e) + { + LogDebug("P2PManager","ConnectDevice",SS("RemoveInterface failed. " << e.what())); + + } + } + DelayedConnectDevice(peer_object); + return; + } +#endif + +#if 1 + try + { + MaybeCancel(); + if (!this->p2pGoDevice) + { + auto groups = p2pDevice->PersistentGroups(); + if (false && groups.size() >= 2) + { + // p2pDevice, groups[1] -> OnInvitationResult(P2P_SC_FAIL_UNKNOWN_GROUP) + auto groupPath = groups[1]; + // start a new group using an existing persistent group. + std::map inviteArgs; + inviteArgs["peer"] = peer_object; + inviteArgs["persistent_group_object"] = groupPath; + + p2pDevice->Invite(inviteArgs); + } else { + // 2nd connection, join = true: EAP auth failure, PIN_NEEDED. + // 2nd connection, join = false: immedate failure with device busy. + std::map connectArgs; + connectArgs["peer"] = peer_object; + connectArgs["persistent"] = true; + connectArgs["frequency"] = (int32_t)this->settings.op_frequency(); + connectArgs["go_intent"] = (int32_t)this->settings.p2p_go_intent(); + connectArgs["wps_method"] = "display", + connectArgs["pin"] = this->settings.pin(); + connectArgs["authorize_only"] = false; + connectArgs["join"] = false; //false; // HasClient(); + + this->p2pDevice->Connect(connectArgs); + // // start a new group. + // std::map inviteArgs; + // inviteArgs["peer"] = peer_object; + // sdbus::ObjectPath groupPath; + // auto persistentGroups = p2pDevice->PersistentGroups(); + // if (persistentGroups.size() >= 2) + // { + // groupPath = persistentGroups[0]; + + // // inviteArgs["persistent_group_object"] = groupPath; + // p2pDevice->Invite(inviteArgs); + // } else { + // throw std::runtime_error("NOT IMPLEMENTED"); + // } + } + } + else + { + // p2pDevice, Connect,join=true. Bizarre extra group devices. Connected device gets orphaned. borked. + // std::map connectArgs; + // connectArgs["peer"] = peer_object; + // connectArgs["persistent"] = true; + // connectArgs["frequency"] = (int32_t)this->settings.op_frequency(); + // connectArgs["go_intent"] = (int32_t)this->settings.p2p_go_intent(); + // connectArgs["wps_method"] = "display", + // connectArgs["pin"] = this->settings.pin(); + // connectArgs["authorize_only"] = false; + // connectArgs["join"] = true; // HasClient(); + + // this->p2pDevice->Connect(connectArgs); + // join the existing group. + + // 2pGoDevice Join("") -> NO_INFO error. + // p2pDevice Join("") -> Failed to join an active group. looking for wlan0 interfacpe when it should be looking for p2p-wlan-N + // p2pDevice join("GetActivePersistentGroup") -> Failed to create interface p2p-wlan0-2: -16 (Device or resource busy) + + std::map inviteArgs; + inviteArgs["peer"] = peer_object; + // inviteArgs["persistent_group_object"] = GetActivePersistentGroup(); + p2pGoDevice->Invite(inviteArgs); + } + } + catch (const std::exception &e) + { + LogError("P2pManager", "ConnectDevice", e.what()); + return; + } +#else + std::map inviteArgs; + inviteArgs["peer"] = peer_object; + inviteArgs["persistent_group_object"] = this->persistentGroupPath; + p2pDevice->Invite(inviteArgs); +#endif +} + +static bool ValidateSetting(const std::map &properties, const std::string &key, int32_t value) +{ + auto iter = properties.find(key); + if (iter == properties.end()) + return false; + if (!iter->second.containsValueOfType()) + return false; + return iter->second.get() == value; +} +static bool ValidateSetting(const std::map &properties, const std::string &key, const std::string &value) +{ + auto iter = properties.find(key); + if (iter == properties.end()) + return false; + if (!iter->second.containsValueOfType()) + return false; + return iter->second.get() == value; +} +bool P2PManagerImpl::HasPersistentGroup() +{ + auto persistentGroups = p2pDevice->PersistentGroups(); + return persistentGroups.size() != 0; +} + +void P2PManagerImpl::InitWpaP2PDevice(WpaP2PDevice::ptr&&device) +{ + p2pDevice = std::move(device); + this->wpsDevice = WpaWPS::Create(dispatcher.Connection(), p2pDevice->getObjectPath()); + + + p2pDevice->Country(settings.country()); + + std::map deviceConfig; + deviceConfig["DeviceName"] = SS(settings.device_name()); + deviceConfig["PrimaryDeviceType"] = std::vector{0x00, 0x01, 0x00, 0x50, 0xF2, 0x04, 0x00, 0x01}; + deviceConfig["GOIntent"] = (uint32_t)15; + deviceConfig["ListenChannel"] = (uint32_t)settings.listen_channel(); + deviceConfig["ListenRegClass"] = (uint32_t)settings.listen_reg_class(); + deviceConfig["OperChannel"] = (uint32_t)settings.op_channel(); + deviceConfig["OperRegClass"] = (uint32_t)settings.op_reg_class(); + + // + // deviceConfig["ListenChannel"] = (uint32_t)settings.listen_channel(); + + deviceConfig["SsidPostfix"] = SS("-" << settings.device_name()); + deviceConfig["IpAddrGo"] = std::vector{172, 23, 0, 2}; + deviceConfig["IpAddrMask"] = std::vector{255, 255, 0, 0}; + deviceConfig["IpAddrStart"] = std::vector{172, 23, 0, 4}; + deviceConfig["IpAddrEnd"] = std::vector{172, 23, 0, 9}; + // deviceConfig["IntraBss"] = false; + deviceConfig["PersistentReconnect"] = true; + // per_sta_psk + //p2pDevice->MeshFwding("0"); + p2pDevice->P2PDeviceConfig(deviceConfig); + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + auto deviceConfig = p2pDevice->P2PDeviceConfig(); + std::stringstream s; + s << deviceConfig; + LogTrace("P2PManager", "InitWpaP2PDevice", SS("P2PDeviceConfig: " << s.str())); + } + + LogDebug("P2PManager", "InitWpaP2PDevice", SS("ConfigMethods" << p2pDevice->ConfigMethods())); + p2pDevice->ConfigMethods(CONFIG_METHODS); + // p2pDevice->P2pGoHt40(settings.p2p_go_ht40() ? "1" : "0"); + + std::string groupName = p2pDevice->Group().c_str(); + + auto t = wpsDevice->DeviceType(); + + wpsDevice->DeviceName(settings.device_name()); + wpsDevice->Manufacturer(settings.manufacturer()); + wpsDevice->ModelName(settings.model_name()); + wpsDevice->ModelNumber(settings.model_number()); + wpsDevice->SerialNumber(settings.serial_number()); + wpsDevice->DeviceType(settings.device_type()); + + + p2pDevice->OnServiceDiscoveryRequest.add( + [this](const std::map &sd_request) + { + OnServiceDiscoveryRequest(sd_request); + }); + p2pDevice->OnInvitationResult.add( + [this](const std::map &invite_result) + { + OnInvitationResult(p2pDevice->getObjectPath(), invite_result); + }); + p2pDevice->OnGroupStarted.add( + [this](const std::map &args) + { + try + { + LogInfo("P2PManager", "OnGroupStarted", "GroupStarted"); + + const sdbus::Variant &vGroup = args.at("group_object"); + sdbus::ObjectPath group = vGroup; + if (!group.empty()) + { + wpaGroup = WpaGroup::Create(dispatcher.Connection(), group); + wpaGroup->OnPeerJoined.add( + [this](const sdbus::ObjectPath &path) + { + Post( + [this, path]() + { + try + { + LogDebug("P2PManager", "OnPeerJoined", path.c_str()); + this->connectedPeers.push_back(WpaPeer::Create(dispatcher.Connection(), path)); + } + catch (const std::exception &e) + { + LogError("P2PManager", "OnPeerJoined", e.what()); + } + }); + }); + wpaGroup->OnPeerDisconnected.add( + [this](const sdbus::ObjectPath &path) + { + Post( + [this, path]() + { + LogDebug("P2PManager","OnPeerDisconnected",path.c_str()); + this->connectedPeers.push_back(WpaPeer::Create(dispatcher.Connection(),path)); + for (auto iter = this->connectedPeers.begin(); iter != this->connectedPeers.end(); iter++) + { + if ((*iter)->getObjectPath() == path) + { + this->connectedPeers.erase(iter); + break; + } + } }); + }); + } + } + catch (const std::exception &e) + { + LogError("InitWpaP2PDevice", "OnGroupAdded", e.what()); + } + }); + p2pDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + std::stringstream ss; + ss << info; + LogError(p2pDevice->getObjectPath().c_str(), "OnGoNegotiationFailure", ss.str()); + }); + p2pDevice->OnGroupFormationFailure.add( + [this](const std::string &reason) + { + LogError(p2pDevice->getObjectPath().c_str(), "OnGroupFormationFailure", reason); + }); + + p2pDevice->OnGroupFinished.add([this](const std::map &properties) + { + LogInfo("P2PManager","OnGroupFinished",""); + wpaGroup = nullptr; }); + + p2pDevice->OnGroupFormationFailure.add( + [this](const std::string &reason) + { + Post([this]() + { + if (this->p2pDevice) + { + try { + StartListen(); + } catch (const std::exception&e) + { + LogError("P2PManager","OnGroupFormationFailure", SS("Listen failed: " << e.what())); + } + } }); + }); + p2pDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + Post([this]() + { + if (this->p2pDevice) + { + try { + StartListen(); + } catch (const std::exception&e) + { + LogError("P2PManager","OnGONegotiationFailure", SS("Listen failed: " << e.what())); + } + } }); + }); + + p2pDevice->OnProvisionDiscoveryEnterPin.add( + [this](const sdbus::ObjectPath &peer_object) + { + // old android device picks wrong method. pretend they asked for OnProvisionDiscoveryRequestDisplayPin instead + LogDebug(p2pDevice->getObjectPath(), "OnProvisionDiscoveryEnterPin", + peer_object.c_str()); + + Post( + [this, peer_object]() + { + if (!this->p2pDevice) + return; + + ConnectDevice(peer_object, true); + }); + }); + + p2pDevice->OnProvisionDiscoveryRequestDisplayPin.add( + [this](const sdbus::ObjectPath &peer_object, const std::string &pin) + { + LogDebug(p2pDevice->getObjectPath(), "OnProvisionDiscoveryRequestDisplayPin", + SS(peer_object.c_str())); + + Post( + [this, peer_object]() + { + if (!this->p2pDevice) + return; + + ConnectDevice(peer_object, false); + }); + }); + + if (!HasPersistentGroup() || settings.auth_changed()) + { + if (settings.auth_changed()) + { + LogInfo("P2PManagerImpl", "InitWpaP2PDevice", "Auth has changed. Resetting persistent groups"); + } + p2pDevice->RemoveAllPersistentGroups(); + + std::map persistentGroupAddParams; + persistentGroupAddParams["bssid"] = settings.bssid(); + persistentGroupAddParams["ssid"] = settings.device_name(); + persistentGroupAddParams["psk"] = settings.pin(); + persistentGroupAddParams["mode"] = (uint32_t)3; //"3"; + sdbus::ObjectPath persistentGroupPath = p2pDevice->AddPersistentGroup(persistentGroupAddParams); + this->persistentGroupPath = persistentGroupPath; + if (settings.auth_changed()) + { + settings.auth_changed(false); + settings.Save(); + } + } + else + { + this->persistentGroupPath = p2pDevice->PersistentGroups()[0]; + } + + StartListen(); + StartServiceBroadcast(); + + LogInfo(this->p2pDevice->getObjectPath(), "InitWpaP2PDevice", "Listening"); + + dispatcher.Post( + [this]() + { + // StartGroup(); + }); +} + +void P2PManagerImpl::Post(PostCallback &&fn) +{ + dispatcher.Post(std::move(fn)); +} + +void P2PManagerImpl::Run() +{ + + dispatcher.Run(); +} + +void P2PManagerImpl::ExecuteOrderlyShutdown() +{ + dispatcher.Post( + [this]() + { + if (this->shutdownExecuted) + return; + this->shutdownExecuted = true; + + StopServiceBroadcast(); + + CancelMaybeRemoveGroup(); + + if (this->p2pDevice) + { + // no parameters cancels Extended listen. + std::map listenArgs; + this->p2pDevice->ExtendedListen(listenArgs); + } + + if (this->p2pGoDevice) + { + try + { + this->p2pGoDevice->Disconnect(); + } + catch (const std::exception &e) + { + LogWarning("P2PManagerImpl", "Stop", SS("Can't disconnect " << this->p2pGoDevice->Ifname())); + } + } + stage2Timeout = clock::now() + std::chrono::duration_cast(std::chrono::milliseconds(1500)); + ShutdownStage2(); + }); +} + +void P2PManagerImpl::ShutdownStage2() +{ + if (clock::now() > stage2Timeout) + { + LogError("P2PManagerImpl", "ShutdownStage2", "Stage2 shutdown timeout exipred."); + } + else + { + // wait until the Disconnect has completed. + if (this->p2pGoDevice) + { + dispatcher.PostDelayed(std::chrono::milliseconds(50), + [this]() + { + ShutdownStage2(); + }); + return; + } + } + LogDebug("P2PManagerImpl", "ShutdownStage2", "Sutdown Stage2 complete."); + if (this->p2pDevice) + { + this->wpaSupplicant->RemoveInterface(p2pDevice->getObjectPath()); + } + StartWaitUntilDone(); +} +void P2PManagerImpl::Stop() +{ + SignalStop(); + Wait(); +} +bool P2PManagerImpl::IsFinished() +{ + return dispatcher.IsFinished(); +} + +bool P2PManagerImpl::ReloadRequested() +{ + return this->reloadRequested; +} + +void P2PManagerImpl::Wait() +{ + if (!waited) + { + waited = true; + dispatcher.Wait(); + LogInfo("P2PManager", "Stop", "Shutdown complete."); + } +} + +void P2PManagerImpl::StartWaitUntilDone() +{ + this->waitUntilDoneTimeout = clock::now() + std::chrono::duration_cast(std::chrono::milliseconds(1000)); + + PostWaitUntilDone(); +} +void P2PManagerImpl::PostWaitUntilDone() +{ + if (clock::now() > this->waitUntilDoneTimeout) + { + LogError("P2PManager", "PostWaitUntilDone", "WaitUntilDone timeout expired."); + } + else + { + auto interfaces = this->wpaSupplicant->Interfaces(); + if (interfaces.size() > 0) + { + dispatcher.PostDelayed( + std::chrono::milliseconds(100), + [this]() + { + PostWaitUntilDone(); + }); + } + } + // the dispatcher won't exit while there's a pending post. + dispatcher.PostDelayed( + std::chrono::milliseconds(100), + [this]() + { + UnInitialize(); + }); +} +void P2PManagerImpl::StartGroup() +{ + auto groups = p2pDevice->PersistentGroups(); + if (groups.size() == 0) + throw std::runtime_error("StartGroup() called with no persistent groups."); + + std::map args; + args["persistent_group_object"] = groups[0]; + this->p2pDevice->GroupAdd(args); +} + +void P2PManagerImpl::CancelMaybeRemoveGroup() +{ + if (maybeCloseHandle) + { + dispatcher.CancelPost(maybeCloseHandle); + maybeCloseHandle = 0; + } +} +void P2PManagerImpl::MaybeRemoveGroup() +{ + + CancelMaybeRemoveGroup(); + if (dispatcher.IsStopping()) + { + return; + } + maybeCloseHandle = dispatcher.PostDelayed( + std::chrono::milliseconds(100), + [this]() + { + maybeCloseHandle = 0; + + if (this->p2pDevice->Stations().size() == 0) + { + if (this->p2pGoDevice) + { + try + { + p2pGoDevice->Disconnect(); + } + catch (const std::exception &e) + { + LogError(p2pGoDevice->getObjectPath(), "MaybeRemoveGroup", "Failed to disconnect."); + } + } + } + }); +} + +std::vector s_idleStates{ + "disconnected", + "inactive", + "interface_disabled", + "scanning", + //"authenticating", + //"associating", + //"associated", + //"4way_handshake", + //"group_handshake", + "completed", + //"unknown", +}; + +void P2PManagerImpl::MaybeCancel() +{ + std::string state = this->p2pDevice->State(); + for (const auto &idleState : s_idleStates) + { + if (idleState == state) + { + return; + } + } + try + { + LogWarning("P2PManager","MaybeCancel",SS("Cancelling (State=" << state << ")")); + this->p2pDevice->Cancel(); + } + catch (const std::exception &) + { + } +} + +std::string P2PManagerImpl::UpnpServiceName() +{ + return SS("uuid:" << settings.service_uuid() << "::urn:schemas-twoplay-com:service:PiPedal:1" + << "::port:" << settings.web_server_port()); +} + +void P2PManagerImpl::StartServiceBroadcast() +{ + // Upnp service advertising allows the android client to automatically discover pipedal Wifi P2P devices. + try + { + try { + p2pDevice->FlushService(); + } catch (const std::exception&) + { + + } + std::map args; + args["service_type"] = "upnp"; + args["version"] = (int32_t)0x10; + args["service"] = UpnpServiceName(); + std::vector response; + response.push_back(0); + args["response"] = response; + p2pDevice->AddService( + args); + serviceBroadcastStarted = true; + } + catch (const std::exception &e) + { + LogError( + p2pDevice->getObjectPath(), + "StartServiceBroadcast", + SS("Failed to start Wi-Fi service broadcast. " << e.what())); + } +} +void P2PManagerImpl::StopServiceBroadcast() +{ + try + { + if (serviceBroadcastStarted) + { + serviceBroadcastStarted = false; + + std::map args; + args["service_type"] = "upnp"; + args["version"] = (int32_t)10; + args["service"] = UpnpServiceName(); + p2pDevice->DeleteService(args); + } + } + catch (std::exception &e) + { + LogDebug("P2PManager", "StopServiceBroadcast", e.what()); + } +} + +void P2PManagerImpl::UnInitialize() +{ + // should all have been released at this point, + // but still best to be certain. + + // the must NOT survive destruction of the dispatcher. + + this->connectedPeers.clear(); + this->wpaGroup = nullptr; + this->p2pGoDevice = nullptr; + this->wpsDevice = nullptr; + this->p2pDevice = nullptr; + this->wpsDevice = nullptr; + + if (!oldWpasDebugLevel.empty()) + { + wpaSupplicant->DebugLevel(oldWpasDebugLevel); + } + + wpaSupplicant = nullptr; // completely shut down after this. +} + +void P2PManagerImpl::TurnOnWifi() +{ + bool wirelessEnabled; + auto networkManager = NetworkManager::Create(dispatcher); + + try + { + wirelessEnabled = networkManager->WirelessEnabled(); + } + catch (const std::exception &e) + { + LogDebug("P2PManager", "TurnOnWifi", "NetworkManager is not available."); + return; + } + + if (!wirelessEnabled) + { + networkManager->WirelessEnabled(true); + } +} + +void P2PManagerImpl::SignalHangup() +{ + if (signalStop) + return; + // reloadRequested = true; + + dispatcher.SignalStop([this]() + { + dispatcher.Post([this]() + { + LogInfo("P2PManager","SignalHangup","Reload requested."); + ExecuteOrderlyShutdown(); + }); + ExecuteOrderlyShutdown(); }); + signalStop = true; +} +void P2PManagerImpl::SignalStop() +{ + if (signalStop) + return; + dispatcher.SignalStop([this]() + { ExecuteOrderlyShutdown(); }); + signalStop = true; +} +void P2PManagerImpl::StartListen() +{ + if (!dispatcher.IsStopping()) + { + try { + p2pDevice->Listen((int32_t)5); + + std::map listenArgs; + listenArgs["interval"] = (int32_t)3000; // listen for... + listenArgs["period"] = (int32_t)1000; // check every... + this->p2pDevice->ExtendedListen(listenArgs); + } catch (const std::exception&) + { + } + } +} + +static std::string UnquoteSsid(const std::string &ssid) +{ + if (ssid[0] != '\"') return ssid; + return ssid.substr(1,ssid.length()-2); + +} +sdbus::ObjectPath P2PManagerImpl::GetActivePersistentGroup() +{ + if (!wpaGroup) + { + throw std::runtime_error("No active group."); + } + + auto groupSsidBytes = wpaGroup->SSID(); + std::string groupSsid { (const char*)(&groupSsidBytes[0]),groupSsidBytes.size()}; + + for (const auto&persistentGroupPath: p2pDevice->PersistentGroups()) + { + auto persistentGroup = WpaPersistentGroup::Create(dispatcher.Connection(),persistentGroupPath); + auto properties = persistentGroup->Properties(); + std::string persistentGroupSsid = properties["ssid"]; + persistentGroupSsid = UnquoteSsid(persistentGroupSsid); + if (persistentGroupSsid == groupSsid) + { + return persistentGroupPath; + } + } + throw std::runtime_error("Active persistent group not found."); +} + +class ServiceTLV { +public: + enum class ProtocolTypes: uint8_t { All = 0, Bonjour = 1, UPnP = 2, WSDiscovery = 3, WifiDisplay = 4, P2Ps = 11}; + + ServiceTLV() { } + ServiceTLV(const std::vector &tlv) { + size_t length = tlv[1] *256 + tlv[0]; + protocolType = (ProtocolTypes)tlv[2]; + transactionId = tlv[3]; + for (size_t i = 4; i <= length; ++i) + { + queryData.push_back(tlv[i]); + } + } + + ProtocolTypes ProtocolType() const { return protocolType; } + void ProtocolType(ProtocolTypes type) { protocolType = type;} + uint8_t TransactionId() const { return transactionId; } + void TransactionId(uint8_t value) { transactionId = value; } + const std::vector QueryData() const { return queryData; } + std::string UpnpQueryString() const { return std::string((char*)&(queryData[1]),queryData.size()-1);} + + void QueryData(const std::vector &value) { queryData = value; } + uint8_t UpnpVersion() const { return queryData[0]; } + void UpnpQueryString(const std::string &value) { + queryData.resize(0); + queryData.reserve(value.length()+1); + queryData.push_back(10); + for (char c: value) + { + queryData.push_back((uint8_t)c); + } + } + std::vector Build() const { + std::vector result; + size_t length = queryData.size()+4; + result.reserve(length); + result.push_back((uint8_t)length); + result.push_back((uint8_t)(length >> 8)); + result.push_back((uint8_t) protocolType); + result.push_back(transactionId); + for (uint8_t v: queryData) + { + result.push_back(v); + } + return result; + } + +private: + ProtocolTypes protocolType; + uint8_t transactionId; + uint16_t length; + std::vector queryData; +}; + +static bool IsDigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static std::string StripVersion(const std::string&v) +{ + size_t len = v.length(); + while (len > 0 && IsDigit(v[len-1])) + { + --len; + } + if (len > 0 && v[len-1] == '.') + { + --len; + } + return v.substr(0,len); +} +void P2PManagerImpl::OnServiceDiscoveryRequest(const std::map &sd_request) +{ + // try { + // sdbus::ObjectPath peer_object = sd_request.at("peeer_object"); + // int32_t frequency = sd_request.at("frequency"); + // int32_t dialog_token = sd_request.at("dialog_token"); + // std::vector request_tlvs = sd_request.at("tlvs"); + + // ServiceTLV request { request_tlvs}; + // if (request.ProtocolType() != ServiceTLV::ProtocolTypes::Any && request.ProtocolType() != ServiceTLV::ProtocolTypes::UPnP ) + // { + // return; + // } + // std::string requestUrn = request.UpnpQueryString(); + // requestUrn = StripVersion(requestUrn); + // if (requestUrn != "urn:schemas-twoplay-com:service:PiPedal") + // { + // return; + // } + // ServiceTLV response; + // response.ProtocolType(ServiceTLV::ProtocolTypes::UPnP); + // response.TransactionId(request.TransactionId()); + // response.UpnpQueryString(UpnpServiceName()); + + + + + // // [44, 0, 2, 2, 16, 117, 114, 110, 58, 115, 99, 104, 101, 109, 97, 115, 45, 116, 119, 111, 112, 108, 97, 121, 45, 99, 111, 109, 58, 115, 101, 114, 118, 105, 99, 101, 58, 80, 105, 80, 101, 100, 97, 108, 58, 49 + // std::map args; + // args["peer_object"] = peer_object; + // args["frequency"] = frequency; + + // this->p2pDevice->ServiceDiscoveryResponse(args); + // } catch (const std::exception&e) + // { + // LogError("P2PManager","OnServiceDiscoveryRequest",e.what()); + // } +} + +bool P2PManagerImpl::TerminatedNormally() +{ + return normalTermination; +} + + +#endif \ No newline at end of file diff --git a/NetworkManagerP2P/src/P2PManager.cpp.bak b/NetworkManagerP2P/src/P2PManager.cpp.bak new file mode 100644 index 0000000..7747c2f --- /dev/null +++ b/NetworkManagerP2P/src/P2PManager.cpp.bak @@ -0,0 +1,1062 @@ +#ifndef USE_NETWORKMANAGER +#include "P2PManager.hpp" +#include "ss.hpp" +#include +#include +#include + +#include "WpaInterfaces.hpp" +#include "NMP2pSettings.hpp" +#include +#include +#include + +#include "DBusDispatcher.hpp" +#include "NetworkManagerInterfaces.hpp" +#include "DBusVariantHelper.hpp" +#include "SignalHandler.hpp" + +static const char CONFIG_METHODS[] = "keypad"; +static const char CONFIG_CONNECT_METHOD[] = "display"; +class P2PManagerImpl : public P2PManager +{ +public: + P2PManagerImpl() : dispatcher(true) {} + virtual ~P2PManagerImpl(); + + void Init() override; + void Run() override; + void Stop() override; + bool IsFinished() override; + void Wait() override; + bool ReloadRequested() override; + +private: + using clock = std::chrono::steady_clock; + + + void StartListen(); + void SignalStop(); + void SignalHangup(); + void ExecuteOrderlyShutdown(); + void ShutdownStage2(); + void TurnOnWifi(); + void UnInitialize(); + void StartWaitUntilDone(); + void PostWaitUntilDone(); + void MaybeRemoveGroup(); + void CancelMaybeRemoveGroup(); + void MaybeCancel(); + + void StartGroup(); + bool HasPersistentGroup(); + void AddExistingInterfaces(); + void RemoveExistingInterfaces(); + void HandleInterfaceAdded(const std::string &objectPath); + void HandleInterfaceRemoved(const std::string &objectPath); + void InitWpaP2PDevice(); + void InitWpaP2PGoDevice(); + void ConnectDevice(const sdbus::ObjectPath &peer_object); + bool HasClient(); + std::string UpnpServiceName(); + void StartServiceBroadcast(); + void StopServiceBroadcast(); + + std::atomic reloadRequested{false}; + std::atomic signalStop{false}; + bool signalStopStarted = false; + bool shutdownExecuted = false; + bool waited = false; + bool serviceBroadcastStarted = false; + DBusDispatcher dispatcher; + DBusDispatcher::PostHandle maybeCloseHandle = 0; + std::mutex postMutex; + std::atomic stopping; + std::vector pendingAddedInterfaces; + + using PostCallback = DBusDispatcher::PostCallback; + void Post(PostCallback &&fn); + + WpaSupplicant::ptr wpaSupplicant; + + WpaInterface::ptr deviceInterface; + WpaP2PDevice::ptr p2pDevice; + WpaP2PDevice::ptr p2pGoDevice; + WpaWPS::ptr wpsDevice; + sdbus::ObjectPath persistentGroupPath; + P2pSettings settings{}; + WpaGroup::ptr wpaGroup; + + std::vector connectedPeers; + + std::string oldWpasDebugLevel; + clock::time_point stage2Timeout; + clock::time_point waitUntilDoneTimeout; +}; + +P2PManager::ptr P2PManager::Create() +{ + return std::make_unique(); +} + +P2PManagerImpl::~P2PManagerImpl() +{ + Stop(); +} + +static const char hexDigits[] = "0123456789abcdef"; + +static std::string AddressToString(const std::vector &address) +{ + std::stringstream ss; + bool firstTime = true; + for (auto byte : address) + { + if (!firstTime) + { + ss << ":"; + } + firstTime = false; + ss << hexDigits[(byte >> 4) & 0x0F] << hexDigits[byte & 0x0F]; + } + return ss.str(); +} + +void P2PManagerImpl::RemoveExistingInterfaces() +{ + try + { + while (true) + { + if (!this->wpaSupplicant) + break; + + auto interfaces = this->wpaSupplicant->Interfaces(); + if (interfaces.size() == 0) + break; + + wpaSupplicant->RemoveInterface(interfaces[0]); + } + } + catch (const std::exception &e) + { + LogWarning("P2PManagerImpl", "RemoveExistingInterfaces", e.what()); + } +} +void P2PManagerImpl::Init() +{ + settings.Load(); + + + LogInfo( + "P2PManager", + "Init", + SS( + "Configuration:" + << " " << settings.country() + << " " << settings.wlan() + << " " << settings.device_name() + << " " << settings.web_server_port() + << " " << settings.listen_channel() + << " " << settings.op_channel() + )); + SignalHandler::HandleSignal( + SignalHandler::Interrupt, + [this]() + { + this->SignalStop(); + }); + SignalHandler::HandleSignal( + SignalHandler::Terminate, + [this]() + { + this->SignalStop(); + }); + SignalHandler::HandleSignal( + SignalHandler::Hangup, + [this]() + { + this->SignalStop(); // we can't restart, but at lease we can do an orderly shutdown. + // disable this, because sdbus::dispatcher doesn't seem to be able to handle a restart. + // this->SignalHangup(); + }); + + #ifdef DEBUG + dispatcher.Connection().setMethodCallTimeout(500 * 1000 * 1000); + #endif + + for (int retry = 0; retry < 4 ; ++retry) // defend against slow starup of wpa_supplicant + { + try { + this->wpaSupplicant = WpaSupplicant::Create(dispatcher.Connection()); + this->wpaSupplicant->DebugLevel(); + if (retry != 0) + { + LogInfo("P2PManager","Init","wpa_supplicant DBus connection established."); + + } + break; + } catch (std::exception&e) + { + if (retry == 0) + { + LogInfo("P2PManager","Init","Waiting for wpa_supplicant DBus connection."); + } + this->wpaSupplicant = nullptr; + std::this_thread::sleep_for(std::chrono::seconds(5)); + } + } + if (!this->wpaSupplicant) + { + throw std::runtime_error("wpa_supplicant service is not reachable by DBus."); + } + + std::string wpaLogLevel = "info"; + switch (GetDBusLogLevel()) + { + default: + case DBusLogLevel::Info: + wpaLogLevel = "info"; + break; + case DBusLogLevel::Debug: + wpaLogLevel = "debug"; + break; + case DBusLogLevel::Warning: + wpaLogLevel = "warning"; + break; + case DBusLogLevel::Error: + wpaLogLevel = "error"; + break; + case DBusLogLevel::Trace: + wpaLogLevel = "debug"; + break; + } + oldWpasDebugLevel = wpaSupplicant->DebugLevel(); + wpaSupplicant->DebugLevel(wpaLogLevel); + + if (!oldWpasDebugLevel.empty()) + { + wpaSupplicant->DebugLevel(oldWpasDebugLevel); + } + + TurnOnWifi(); + + this->wpaSupplicant->OnInterfaceAdded.add( + [this](const sdbus::ObjectPath &path, const std::map &properties) + { + this->HandleInterfaceAdded(path); + }); + this->wpaSupplicant->OnInterfaceRemoved.add( + [this](const sdbus::ObjectPath &path) + { + this->HandleInterfaceRemoved(path); + }); + + RemoveExistingInterfaces(); + if (wpaSupplicant->Interfaces().size() == 0) + { + std::map createArgs; + createArgs["Ifname"] = settings.wlan(); + createArgs["Driver"] = settings.driver(); + createArgs["ConfigFile"] = settings.wpas_config_file(); + wpaSupplicant->CreateInterface(createArgs); + } +} + +void P2PManagerImpl::AddExistingInterfaces() +{ + if (!this->p2pDevice) + { + for (const auto &objectPath : this->wpaSupplicant->Interfaces()) + { + HandleInterfaceAdded(objectPath); + } + } +} + +void P2PManagerImpl::HandleInterfaceRemoved(const std::string &objectPath) +{ + bool deleted = false; + + // removal from pending list can be done in a handler. + for (auto i = this->pendingAddedInterfaces.begin(); i != pendingAddedInterfaces.end(); ++i) + { + if (*i == objectPath) + { + pendingAddedInterfaces.erase(i); + return; + } + } + // removal of existing objects needs to be posted. + Post([this, objectPath]() + { + if (this->p2pDevice && this->p2pDevice->getObjectPath() == objectPath) + { + this->p2pDevice = nullptr; + this->deviceInterface = nullptr; + this->wpsDevice = nullptr; + } + if (this->p2pGoDevice && this->p2pGoDevice->getObjectPath() == objectPath) + { + this->wpaGroup = nullptr; + this->p2pGoDevice = nullptr; + StartListen(); + } }); +} + +void P2PManagerImpl::HandleInterfaceAdded(const std::string &objectPath) +{ + + // Create the objects in the callback, but defer processing. + // Guard against the interface being synchronously removed before the async post handler excecutes./ + this->pendingAddedInterfaces.push_back(objectPath.c_str()); + { + std::string msg = SS("Device added: " << objectPath.c_str()); + LogDebug("P2PManagerImpl", "HandleInterfaceAdded", msg); + } + + Post([this, + objectPath]() mutable + { + // check to see whether the new interface was removed from pending list. + auto found = std::find(pendingAddedInterfaces.begin(),pendingAddedInterfaces.end(),objectPath); + if (found != pendingAddedInterfaces.end()) + { + pendingAddedInterfaces.erase(found); + try { + auto interface = WpaInterface::Create(dispatcher.Connection(), objectPath); + auto p2pDevice = WpaP2PDevice::Create(dispatcher.Connection(), objectPath); + + LogDebug(objectPath,"HandleInterfaceAdded",SS("Role: " << p2pDevice->Role())); + + if (interface) + { + if (p2pDevice->Role() == "device" && ((!this->p2pDevice) || this->p2pDevice->getObjectPath() != objectPath)) + { + LogDebug("P2PManagerImpl", "HandleInterfaceAdded", "P2P device found."); + this->deviceInterface = std::move(interface); + this->p2pDevice = std::move(p2pDevice); + this->wpsDevice = WpaWPS::Create(dispatcher.Connection(), objectPath); + InitWpaP2PDevice(); + } + else if (p2pDevice->Role() == "GO" && ((!this->p2pGoDevice) || this->p2pGoDevice->getObjectPath() != objectPath)) + { + LogDebug("P2PManagerImpl", "HandleInterfaceAdded", "P2P GO group interface found."); + + this->p2pGoDevice = std::move(p2pDevice); + InitWpaP2PGoDevice(); + } + } + } catch (const std::exception&e) + { + LogError("P2PManagerImpl","HandleInterfaceAdded",SS("Failed to add " << objectPath.c_str() << " (" << e.what() << ")")); + } + } }); +} + + +void P2PManagerImpl::InitWpaP2PGoDevice() +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + auto deviceConfig = p2pGoDevice->P2PDeviceConfig(); + std::stringstream s; + s << deviceConfig; + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("GO Device config: " << s.str())); + } + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("ConfigMethods: " << p2pGoDevice->ConfigMethods())); + p2pGoDevice->OnStaAuthorized.add( + [this](const std::string&name) { + LogInfo( + p2pGoDevice->getObjectPath(), + "OnStationAuthorized", + SS("Station authorized: " << name)); + }); + p2pGoDevice->OnStaDeauthorized.add( + [this](const std::string&name) { + LogInfo( + p2pGoDevice->getObjectPath(), + "OnStationDeauthorized", + SS("Station deauthorized: " << name)); + }); + + p2pGoDevice->OnWpsFailed.add( + [this](const std::string &name, const std::map &args) + { + { + std::stringstream ss; + ss << name << " " << args << " "; + LogError("P2PManagerImp", "OnWpsFailed", ss.str()); + } + try + { + this->p2pGoDevice->Cancel(); + } + catch (const std::exception &) + { + } + MaybeRemoveGroup(); + }); + p2pGoDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + std::stringstream ss; + ss << info; + LogError(p2pGoDevice->getObjectPath().c_str(),"OnGoNegotiationFailure",ss.str()); }); + p2pGoDevice->OnGroupFormationFailure.add( + [this](const std::string &message) + { + std::stringstream ss; + ss << message; + LogError(p2pGoDevice->getObjectPath().c_str(), "OnGroupFormationFailure", ss.str()); + MaybeRemoveGroup(); + }); + + p2pGoDevice->OnStationAdded.add( + [this](const sdbus::ObjectPath &path, const std::map &properties) { + + }); + p2pGoDevice->OnStationRemoved.add( + [this](const sdbus::ObjectPath &) + { + MaybeRemoveGroup(); + }); + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", SS("GoCountry: " << p2pGoDevice->Country())); + + p2pGoDevice->OnProvisionDiscoveryRequestDisplayPin.add( + [this](const sdbus::ObjectPath &peer_object, const std::string &pin) + { + LogTrace("P2PManagerImpl", "InitWpaP2PGoDevice", + SS("GO OnProvisionDiscoveryRequestDisplayPin - " << peer_object.c_str() << " pin: " << pin)); + }); +} + +bool P2PManagerImpl::HasClient() +{ + return this->p2pDevice->Stations().size() != 0; +} +void P2PManagerImpl::ConnectDevice(const sdbus::ObjectPath &peer_object) +{ + +#if 1 + try + { + int retry = 0; + while (true) + { + try + { + std::map connectArgs; + connectArgs["peer"] = peer_object; + connectArgs["persistent"] = true; + // connecconnectArgs["frequency"] = this->settings.frequency(); + connectArgs["go_intent"] = (int32_t)this->settings.p2p_go_intent(); + connectArgs["wps_method"] = CONFIG_CONNECT_METHOD; + connectArgs["pin"] = this->settings.pin(); + connectArgs["authorize_only"] = false; + connectArgs["join"] = false; //HasClient(); + + this->p2pDevice->Connect(connectArgs); + break; + } + catch (const std::exception &e) + { + try + { + p2pDevice->Cancel(); + } + catch (const std::exception &) + { + } + if (++retry == 2) + { + MaybeRemoveGroup(); + throw; + } + } + } + } + catch (const std::exception &e) + { + LogError("P2pManager", "Connect", e.what()); + return; + } +#else + std::map inviteArgs; + inviteArgs["peer"] = peer_object; + inviteArgs["persistent_group_object"] = this->persistentGroupPath; + p2pDevice->Invite(inviteArgs); +#endif +} + +static bool ValidateSetting(const std::map &properties, const std::string &key, int32_t value) +{ + auto iter = properties.find(key); + if (iter == properties.end()) + return false; + if (!iter->second.containsValueOfType()) + return false; + return iter->second.get() == value; +} +static bool ValidateSetting(const std::map &properties, const std::string &key, const std::string &value) +{ + auto iter = properties.find(key); + if (iter == properties.end()) + return false; + if (!iter->second.containsValueOfType()) + return false; + return iter->second.get() == value; +} +bool P2PManagerImpl::HasPersistentGroup() +{ + auto persistentGroups = p2pDevice->PersistentGroups(); + return persistentGroups.size() != 0; +} + +void P2PManagerImpl::InitWpaP2PDevice() +{ + p2pDevice->Country(settings.country()); + + std::map deviceConfig; + deviceConfig["DeviceName"] = SS(settings.device_name()); + deviceConfig["PrimaryDeviceType"] = std::vector{0x00, 0x01, 0x00, 0x50, 0xF2, 0x04, 0x00, 0x01}; + deviceConfig["GOIntent"] = (uint32_t)15; + deviceConfig["ListenChannel"] = (uint32_t)settings.listen_channel(); + deviceConfig["OperChannel"] = (uint32_t)settings.op_channel(); + + // deviceConfig["ListenRegClass"] = (uint32_t)81; + // deviceConfig["ListenChannel"] = (uint32_t)settings.listen_channel(); + // deviceConfig["OperRegClass"] = (uint32_t)81; + // deviceConfig["OperChannel"] = (uint32_t)settings.op_channel(); // ch 1 + + deviceConfig["SsidPostfix"] = SS("-" << settings.device_name()); + deviceConfig["IpAddrGo"] = std::vector{172, 23, 0, 2}; + deviceConfig["IpAddrMask"] = std::vector{255, 255, 0, 0}; + deviceConfig["IpAddrStart"] = std::vector{172, 23, 0, 4}; + deviceConfig["IpAddrEnd"] = std::vector{172, 23, 0, 9}; + deviceConfig["IntraBss"] = false; + deviceConfig["PersistentReconnect"] = true; + // per_sta_psk + + p2pDevice->P2PDeviceConfig(deviceConfig); + { + auto deviceConfig = p2pDevice->P2PDeviceConfig(); + std::stringstream s; + s << deviceConfig; + LogTrace("P2PManager", "InitWpaP2PDevice", SS("P2PDeviceConfig: " << s.str())); + } + + LogDebug("P2PManager","InitWpaP2PDevice",SS("ConfigMethods" << p2pDevice->ConfigMethods())); + p2pDevice->ConfigMethods(CONFIG_METHODS); + // deviceInterface->P2pGoHt40(settings.p2p_go_ht40() ? "1" : "0"); + + std::string groupName = p2pDevice->Group().c_str(); + + auto t = wpsDevice->DeviceType(); + + wpsDevice->DeviceName(settings.device_name()); + wpsDevice->Manufacturer(settings.manufacturer()); + wpsDevice->ModelName(settings.model_name()); + wpsDevice->ModelNumber(settings.model_number()); + wpsDevice->SerialNumber(settings.serial_number()); + wpsDevice->DeviceType(settings.device_type()); + + p2pDevice->OnGroupStarted.add( + [this](const std::map &args) + { + try + { + LogDebug("P2PManager", "OnGroupStarted", "GroupStarted"); + + const sdbus::Variant &vGroup = args.at("group_object"); + sdbus::ObjectPath group = vGroup; + if (!group.empty()) + { + wpaGroup = WpaGroup::Create(dispatcher.Connection(), group); + wpaGroup->OnPeerJoined.add( + [this](const sdbus::ObjectPath &path) + { + Post( + [this, path]() + { + try + { + LogDebug("P2PManager", "OnPeerJoined", path.c_str()); + this->connectedPeers.push_back(WpaPeer::Create(dispatcher.Connection(), path)); + } + catch (const std::exception &e) + { + LogError("P2PManager", "OnPeerJoined", e.what()); + } + }); + }); + wpaGroup->OnPeerDisconnected.add( + [this](const sdbus::ObjectPath &path) + { + Post( + [this, path]() + { + LogDebug("P2PManager","OnPeerDisconnected",path.c_str()); + this->connectedPeers.push_back(WpaPeer::Create(dispatcher.Connection(),path)); + for (auto iter = this->connectedPeers.begin(); iter != this->connectedPeers.end(); iter++) + { + if ((*iter)->getObjectPath() == path) + { + this->connectedPeers.erase(iter); + break; + } + } }); + }); + } + } + catch (const std::exception &e) + { + LogError("InitWpaP2PDevice", "OnGroupAdded", e.what()); + } + }); + p2pDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + std::stringstream ss; + ss << info; + LogError(p2pDevice->getObjectPath().c_str(), "OnGoNegotiationFailure", ss.str()); + }); + p2pDevice->OnGroupFormationFailure.add( + [this](const std::string &reason) + { + LogError(p2pDevice->getObjectPath().c_str(), "OnGroupFormationFailure", reason); + }); + + p2pDevice->OnGroupFinished.add([this](const std::map &properties) + { + LogInfo("P2PManager","OnGroupFinished",""); + wpaGroup = nullptr; }); + + p2pDevice->OnGroupFormationFailure.add( + [this](const std::string &reason) + { + Post([this]() + { + if (this->p2pDevice) + { + try { + StartListen(); + } catch (const std::exception&e) + { + LogError("P2PManager","OnGroupFormationFailure", SS("Listen failed: " << e.what())); + } + } }); + }); + p2pDevice->OnGONegotiationFailure.add( + [this](const std::map &info) + { + Post([this]() + { + if (this->p2pDevice) + { + try { + StartListen(); + } catch (const std::exception&e) + { + LogError("P2PManager","OnGONegotiationFailure", SS("Listen failed: " << e.what())); + } + } }); + }); + + p2pDevice->OnProvisionDiscoveryEnterPin.add( + [this](const sdbus::ObjectPath &peer_object) + { + // old android device picks wrong method. pretend they asked for OnProvisionDiscoveryRequestDisplayPin instead + LogDebug(p2pDevice->getObjectPath(), "OnProvisionDiscoveryEnterPin", + peer_object.c_str()); + + Post( + [this, peer_object]() + { + if (!this->p2pDevice) + return; + + ConnectDevice(peer_object); + }); + }); + + p2pDevice->OnProvisionDiscoveryRequestDisplayPin.add( + [this](const sdbus::ObjectPath &peer_object, const std::string &pin) + { + LogDebug(p2pDevice->getObjectPath(), "OnProvisionDiscoveryRequestDisplayPin", + SS(peer_object.c_str())); + + Post( + [this, peer_object]() + { + if (!this->p2pDevice) + return; + + ConnectDevice(peer_object); + }); + }); + + if (!HasPersistentGroup() || settings.auth_changed()) + { + if (settings.auth_changed()) + { + LogInfo("P2PManagerImpl","InitWpaP2PDevice","Auth has changed. Resetting persistent groups"); + } + p2pDevice->RemoveAllPersistentGroups(); + + std::map persistentGroupAddParams; + persistentGroupAddParams["bssid"] = settings.bssid(); + persistentGroupAddParams["ssid"] = settings.device_name(); + persistentGroupAddParams["psk"] = settings.pin(); + persistentGroupAddParams["mode"] = (uint32_t)3; //"3"; + sdbus::ObjectPath persistentGroupPath = p2pDevice->AddPersistentGroup(persistentGroupAddParams); + this->persistentGroupPath = persistentGroupPath; + if (settings.auth_changed()) + { + settings.auth_changed(false); + settings.Save(); + } + } + else + { + this->persistentGroupPath = p2pDevice->PersistentGroups()[0]; + } + + StartListen(); + StartServiceBroadcast(); + + LogInfo(this->p2pDevice->getObjectPath(), "InitWpaP2PDevice", "Listening"); +} + +void P2PManagerImpl::Post(PostCallback &&fn) +{ + dispatcher.Post(std::move(fn)); +} + +void P2PManagerImpl::Run() +{ + + dispatcher.Run(); +} + +void P2PManagerImpl::ExecuteOrderlyShutdown() +{ + dispatcher.Post( + [this]() + { + if (this->shutdownExecuted) + return; + this->shutdownExecuted = true; + + StopServiceBroadcast(); + + CancelMaybeRemoveGroup(); + + if (this->p2pDevice) + { + // no parameters cancels Extended listen. + std::map listenArgs; + this->p2pDevice->ExtendedListen(listenArgs); + } + + + if (this->p2pGoDevice) + { + try + { + this->p2pGoDevice->Disconnect(); + } + catch (const std::exception &e) + { + LogWarning("P2PManagerImpl", "Stop", SS("Can't disconnect " << this->p2pGoDevice->Ifname())); + } + } + stage2Timeout = clock::now() + std::chrono::duration_cast(std::chrono::milliseconds(1500)); + ShutdownStage2(); + }); +} + +void P2PManagerImpl::ShutdownStage2() +{ + if (clock::now() > stage2Timeout) + { + LogError("P2PManagerImpl","ShutdownStage2","Stage2 shutdown timeout exipred."); + } else { + // wait until the Disconnect has completed. + if (this->p2pGoDevice) + { + dispatcher.PostDelayed(std::chrono::milliseconds(50), + [this]() { + ShutdownStage2(); + }); + return; + } + } + LogDebug("P2PManagerImpl","ShutdownStage2","Sutdown Stage2 complete."); + if (this->p2pDevice) + { + this->wpaSupplicant->RemoveInterface(p2pDevice->getObjectPath()); + } + StartWaitUntilDone(); +} +void P2PManagerImpl::Stop() +{ + SignalStop(); + Wait(); +} +bool P2PManagerImpl::IsFinished() +{ + return dispatcher.IsFinished(); +} + +bool P2PManagerImpl::ReloadRequested() +{ + return this->reloadRequested; +} + +void P2PManagerImpl::Wait() +{ + if (!waited) + { + waited = true; + dispatcher.Wait(); + LogInfo("P2PManager", "Stop", "Shutdown complete."); + } +} + +void P2PManagerImpl::StartWaitUntilDone() +{ + this->waitUntilDoneTimeout = clock::now() + std::chrono::duration_cast(std::chrono::milliseconds(1000)); + + PostWaitUntilDone(); +} +void P2PManagerImpl::PostWaitUntilDone() +{ + if (clock::now() > this->waitUntilDoneTimeout) + { + LogError("P2PManager","PostWaitUntilDone", "WaitUntilDone timeout expired."); + } else { + auto interfaces = this->wpaSupplicant->Interfaces(); + if (interfaces.size() > 0) + { + dispatcher.PostDelayed( + std::chrono::milliseconds(100), + [this]() + { + PostWaitUntilDone(); + }); + } + + } + // the dispatcher won't exit while there's a pending post. + dispatcher.PostDelayed( + std::chrono::milliseconds(100), + [this]() + { + UnInitialize(); + }); +} +void P2PManagerImpl::StartGroup() +{ + std::map args; + args["persistent_group_object"] = this->persistentGroupPath; + this->p2pDevice->GroupAdd(args); +} + +void P2PManagerImpl::CancelMaybeRemoveGroup() +{ + if (maybeCloseHandle) + { + dispatcher.CancelPost(maybeCloseHandle); + maybeCloseHandle = 0; + } +} +void P2PManagerImpl::MaybeRemoveGroup() +{ + CancelMaybeRemoveGroup(); + if (dispatcher.IsStopping()) + { + return; + } + maybeCloseHandle = dispatcher.PostDelayed( + std::chrono::milliseconds(100), + [this]() + { + maybeCloseHandle = 0; + + if (this->p2pDevice->Stations().size() == 0) + { + if (this->p2pGoDevice) + { + try + { + p2pGoDevice->Disconnect(); + } + catch (const std::exception &e) + { + LogTrace(p2pGoDevice->getObjectPath(), "MaybeRemoveGroup", "Failed to disconnect."); + } + } + } + }); +} + +std::vector s_idleStates{ + "disconnected", + "inactive", + "interface_disabled", + "scanning", + //"authenticating", + //"associating", + //"associated", + //"4way_handshake", + //"group_handshake", + "completed", + //"unknown", +}; + +void P2PManagerImpl::MaybeCancel() +{ + std::string state = this->p2pDevice->State(); + for (const auto &idleState : s_idleStates) + { + if (idleState == state) + { + return; + } + } + try + { + this->p2pDevice->Cancel(); + } + catch (const std::exception &) + { + } +} + +std::string P2PManagerImpl::UpnpServiceName() +{ + return SS("uuid:" << settings.service_uuid() << "::urn:schemas-twoplay-com:service:PiPedal:1" + << "::port:" << settings.web_server_port()); +} + +void P2PManagerImpl::StartServiceBroadcast() +{ + // Upnp service advertising allows the android client to automatically discover pipedal Wifi P2P devices. + try + { + std::map args; + args["service_type"] = "upnp"; + args["version"] = (int32_t)10; + args["service"] = UpnpServiceName(); + std::vector response; + args["response"] = response; + p2pDevice->AddService( + args); + serviceBroadcastStarted = true; + } + catch (const std::exception &e) + { + LogError( + p2pDevice->getObjectPath(), + "StartServiceBroadcast", + SS("Failed to start Wi-Fi service broadcast. " << e.what())); + } +} +void P2PManagerImpl::StopServiceBroadcast() +{ + try + { + if (serviceBroadcastStarted) + { + serviceBroadcastStarted = false; + + std::map args; + args["service_type"] = "upnp"; + args["version"] = (int32_t)10; + args["service"] = UpnpServiceName(); + p2pDevice->DeleteService(args); + } + } + catch (std::exception &e) + { + LogDebug("P2PManager", "StopServiceBroadcast", e.what()); + } +} + +void P2PManagerImpl::UnInitialize() +{ + // should all have been released at this point, + // but still best to check. + this->connectedPeers.clear(); + this->wpaGroup = nullptr; + this->p2pGoDevice = nullptr; + this->p2pDevice = nullptr; + this->deviceInterface = nullptr; + this->wpsDevice = nullptr; + + wpaSupplicant->DebugLevel(oldWpasDebugLevel); + + wpaSupplicant = nullptr; // completely shut down after this. +} + +void P2PManagerImpl::TurnOnWifi() +{ + bool wirelessEnabled; + auto networkManager = NetworkManager::Create(dispatcher); + + try + { + wirelessEnabled = networkManager->WirelessEnabled(); + } + catch (const std::exception &e) + { + LogDebug("P2PManager", "TurnOnWifi", "NetworkManager is not available."); + return; + } + + if (!wirelessEnabled) + { + networkManager->WirelessEnabled(true); + } +} + +void P2PManagerImpl::SignalHangup() +{ + if (signalStop) + return; + //reloadRequested = true; + + dispatcher.SignalStop([this]() + { + dispatcher.Post([this]() + { + LogInfo("P2PManager","SignalHangup","Reload requested."); + ExecuteOrderlyShutdown(); + }); + ExecuteOrderlyShutdown(); }); + signalStop = true; +} +void P2PManagerImpl::SignalStop() +{ + if (signalStop) + return; + dispatcher.SignalStop([this]() + { ExecuteOrderlyShutdown(); }); + signalStop = true; +} +void P2PManagerImpl::StartListen() +{ + if (!dispatcher.IsStopping()) + { + p2pDevice->Listen((int32_t)5); + + std::map listenArgs; + listenArgs["interval"] = (int32_t)3000; // listen for... + listenArgs["period"] = (int32_t)250; // check every... + this->p2pDevice->ExtendedListen(listenArgs); + } + + +} +#endif \ No newline at end of file diff --git a/NetworkManagerP2P/src/P2PManager.hpp b/NetworkManagerP2P/src/P2PManager.hpp new file mode 100644 index 0000000..ee98305 --- /dev/null +++ b/NetworkManagerP2P/src/P2PManager.hpp @@ -0,0 +1,26 @@ +#pragma once + +#include + + + +class P2PManager { +protected: + P2PManager() { } +public: + using self=P2PManager; + using ptr = std::unique_ptr; + + static ptr Create(); + + virtual ~P2PManager() {} + + virtual bool Init() = 0; + virtual void Run() = 0; + virtual void Stop() = 0; + virtual bool IsFinished() = 0; + virtual void Wait() = 0; + virtual bool ReloadRequested() = 0; + virtual bool TerminatedNormally() = 0; +}; + diff --git a/NetworkManagerP2P/src/P2PManager.hpp.bak b/NetworkManagerP2P/src/P2PManager.hpp.bak new file mode 100644 index 0000000..8606b30 --- /dev/null +++ b/NetworkManagerP2P/src/P2PManager.hpp.bak @@ -0,0 +1,25 @@ +#pragma once + +#include + + + +class P2PManager { +protected: + P2PManager() { } +public: + using self=P2PManager; + using ptr = std::unique_ptr; + + static ptr Create(); + + virtual ~P2PManager() {} + + virtual void Init() = 0; + virtual void Run() = 0; + virtual void Stop() = 0; + virtual bool IsFinished() = 0; + virtual void Wait() = 0; + virtual bool ReloadRequested() = 0; +}; + diff --git a/NetworkManagerP2P/src/SignalHandler.cpp b/NetworkManagerP2P/src/SignalHandler.cpp new file mode 100644 index 0000000..35357cc --- /dev/null +++ b/NetworkManagerP2P/src/SignalHandler.cpp @@ -0,0 +1,62 @@ +#include "SignalHandler.hpp" + +#include +#include +#include +#include + + +static int ToOsSignalType(SignalHandler::SignalType signalType) +{ + int result; + switch (signalType) + { + case SignalHandler::Terminate: result = SIGTERM; break; + case SignalHandler::SegmentationFault: result = SIGSEGV; break; + case SignalHandler::Interrupt: result = SIGINT; break; + case SignalHandler::IllegalInstruction: result = SIGILL; break; + case SignalHandler::Abort: result = SIGABRT; break; + case SignalHandler::FloatingPointError: return SIGFPE; break; + case SignalHandler::Hangup: result = SIGHUP; break; + + default: + throw std::runtime_error("INvalid signal type"); + } + return result; +} + + +void SignalHandler::HandleSignal(SignalHandler::SignalType signal, SignalCallback&&callback) +{ + int osSignal = ToOsSignalType(signal); + if (osSignal > MAX_SIGNAL) + { + throw std::runtime_error("MAX_SIGNAL isn't large enough."); + } + + handlers[osSignal] = std::move(callback); + std::signal(osSignal,OnSignal); +} + +void SignalHandler::UnhandleSignal(SignalHandler::SignalType signal) +{ + int osSignal = ToOsSignalType(signal); + std::atomic_signal_fence(std::memory_order::release); + std::signal(osSignal,SIG_DFL); + handlers[osSignal] = std::function(); +} + +void SignalHandler::IgnoreSignal(SignalHandler::SignalType signal) +{ + int osSignal = ToOsSignalType(signal); + std::signal(osSignal,SIG_IGN); + handlers[osSignal] = std::function(); +} + +void SignalHandler::OnSignal(int osSignal) +{ + std::atomic_signal_fence(std::memory_order::acquire); + handlers[osSignal](); +} + +SignalHandler::SignalCallback SignalHandler::handlers[MAX_SIGNAL]; diff --git a/NetworkManagerP2P/src/SignalHandler.hpp b/NetworkManagerP2P/src/SignalHandler.hpp new file mode 100644 index 0000000..b61cda1 --- /dev/null +++ b/NetworkManagerP2P/src/SignalHandler.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +class SignalHandler { +public: + // Signal type. Limited to signal types supported by + enum SignalType + { + Terminate, //SIGTERM + SegmentationFault, //SIGSEGV + Interrupt, // SIGINT External interrupt executed by user. + IllegalInstruction, // SIGILL + Abort, // SIGABORT + FloatingPointError, // SIGFPE. + Hangup, // SIGHUP + }; + using SignalCallback = std::function; + + static void HandleSignal(SignalType signal, SignalCallback&&fn); + static void UnhandleSignal(SignalType signal); + static void IgnoreSignal(SignalType signal); +private: + static void OnSignal(int osSignal); + static const int MAX_SIGNAL = 64; + static SignalCallback handlers[MAX_SIGNAL]; +}; \ No newline at end of file diff --git a/NetworkManagerP2P/src/Sudo.cpp b/NetworkManagerP2P/src/Sudo.cpp new file mode 100644 index 0000000..b822fdd --- /dev/null +++ b/NetworkManagerP2P/src/Sudo.cpp @@ -0,0 +1,31 @@ +#include "Sudo.hpp" +#include "unistd.h" +#include "sys/types.h" +#include +#include + +bool IsSudo() +{ + return (geteuid() == 0); +} +void ExecWithSudo(int argc, char**argv) +{ + std::vector newArgs; + newArgs.reserve(argc+2); + newArgs.push_back("sudo"); + for (int i = 0; i < argc; ++i) + { + newArgs.push_back(argv[i]); + } + newArgs.push_back(nullptr); + + execvp("sudo",(char*const*)&newArgs[0]); + throw std::runtime_error("Failed to restart with sudo."); +} + +void ForceSudo(int argc, char**argv) +{ + if (IsSudo()) return; + ExecWithSudo(argc,argv); +} + diff --git a/NetworkManagerP2P/src/Sudo.hpp b/NetworkManagerP2P/src/Sudo.hpp new file mode 100644 index 0000000..e1ee0f6 --- /dev/null +++ b/NetworkManagerP2P/src/Sudo.hpp @@ -0,0 +1,5 @@ +#pragma once + +extern bool IsSudo(); +extern void ExecWithSudo(int argc, char**argv); +extern void ForceSudo(int argc, char**argv); diff --git a/NetworkManagerP2P/src/WpaInterfaces.cpp b/NetworkManagerP2P/src/WpaInterfaces.cpp new file mode 100644 index 0000000..82dd43f --- /dev/null +++ b/NetworkManagerP2P/src/WpaInterfaces.cpp @@ -0,0 +1,366 @@ +#include "WpaInterfaces.hpp" +#include "ss.hpp" +#include "DBusLog.hpp" + +void Interface_proxy_withevents::EventTrace(const char *methodName, const std::string &message) +{ + ::LogTrace(proxy.getObjectPath(), methodName, message); +} + +void Interface_proxy_withevents::onScanDone(const bool &success) +{ + this->EventTrace("onScanDone", SS("ScanDone " << success)); +} + +void Interface_proxy_withevents::onBSSAdded(const sdbus::ObjectPath &path, const std::map &properties) +{ + // too chatty + // this->LogTrace("onBSSAdded", ""); +} + +void Interface_proxy_withevents::onBSSRemoved(const sdbus::ObjectPath &path) +{ + // too chatty. + // this->LogTrace("onBSSRemoved", ""); +} + +void Interface_proxy_withevents::onBlobAdded(const std::string &name) +{ + this->EventTrace("onBlobAdded", ""); +} + +void Interface_proxy_withevents::onBlobRemoved(const std::string &name) +{ + this->EventTrace("onBlobRemoved", ""); +} + +void Interface_proxy_withevents::onNetworkAdded(const sdbus::ObjectPath &path, const std::map &properties) +{ + std::stringstream ss; + ss << properties; + EventTrace("onNetworkAdded", + SS(path.c_str() << ss.str())); + OnNetworkAdded.fire(path, properties); +} + +void Interface_proxy_withevents::onNetworkRemoved(const sdbus::ObjectPath &path) +{ + EventTrace("onNetworkRemoved", + path); + OnNetworkRemoved.fire(path); +} + +void Interface_proxy_withevents::onNetworkSelected(const sdbus::ObjectPath &path) +{ + EventTrace("onNetworkSelected", + path); + OnNetworkSelected.fire(path); +} + +void Interface_proxy_withevents::onPropertiesChanged(const std::map &properties) +{ +} + +void Interface_proxy_withevents::onProbeRequest(const std::map &args) +{ +} + +void Interface_proxy_withevents::onCertification(const std::map &certification) +{ + EventTrace("onCertification", + ""); +} + +void Interface_proxy_withevents::onEAP(const std::string &status, const std::string ¶meter) +{ + EventTrace("onEAP", + SS("status: " << status << " parameter: " << parameter)); +} + +void Interface_proxy_withevents::onStaAuthorized(const std::string &name) +{ + EventTrace("onStaAuthorized", + SS("name: " << name)); + OnStaAuthorized.fire(name); +} + +void Interface_proxy_withevents::onStaDeauthorized(const std::string &name) +{ + EventTrace("onStaDeauthorized", + SS("name: " << name)); + OnStaDeauthorized.fire(name); +} + +void Interface_proxy_withevents::onStationAdded(const sdbus::ObjectPath &path, const std::map &properties) +{ + std::stringstream ss; + ss << properties; + EventTrace("onStationAdded", + SS("path: " << path.c_str() << " properties: " << ss.str())); + OnStationAdded.fire(path, properties); +} + +void Interface_proxy_withevents::onStationRemoved(const sdbus::ObjectPath &path) +{ + EventTrace("onStationRemoved", + SS("path: " << path.c_str())); + OnStationRemoved.fire(path); +} + +void Interface_proxy_withevents::onNetworkRequest(const sdbus::ObjectPath &path, const std::string &field, const std::string &text) +{ + EventTrace("onNetworkRequest", + SS("path: " << path.c_str() << " field: " << field << " text: " << text)); +} + +void Interface_proxy_withevents::onInterworkingAPAdded(const sdbus::ObjectPath &bss, const sdbus::ObjectPath &cred, const std::map &properties) +{ + EventTrace("onInterworkingAPAdded", + ""); +} + +void Interface_proxy_withevents::onInterworkingSelectDone() +{ + EventTrace("onInterworkingSelectDone", + ""); +} + +void WpaP2PDevice::onDeviceFound(const sdbus::ObjectPath &path) +{ + EventTrace("onDeviceFound", + path.c_str()); +} +void WpaP2PDevice::onDeviceFoundProperties(const sdbus::ObjectPath &path, const std::map &properties) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream ss; + ss << properties; + EventTrace("onDeviceFoundProperties", + [this, &path, &properties]() + { + return std::string(); + // return SS("path: " << path.c_str() << "properties: " << ss.str()) + }); + } +} +void WpaP2PDevice::onDeviceLost(const sdbus::ObjectPath &path) +{ + EventTrace("onDeviceLost", + path.c_str()); +} +void WpaP2PDevice::onProvisionDiscoveryResponseDisplayPin(const sdbus::ObjectPath &peer_object, const std::string &pin) +{ + EventTrace("onProvisionDiscoveryResponseDisplayPin", + SS("peer: " << peer_object.c_str())); +} +void WpaP2PDevice::onProvisionDiscoveryRequestEnterPin(const sdbus::ObjectPath &peer_object) +{ + EventTrace("onProvisionDiscoveryRequestEnterPin", + SS("peer: " << peer_object.c_str())); + OnProvisionDiscoveryEnterPin.fire(peer_object); +} +void WpaP2PDevice::onProvisionDiscoveryResponseEnterPin(const sdbus::ObjectPath &peer_object) +{ + EventTrace("onProvisionDiscoveryResponseEnterPin", + SS("peer: " << peer_object.c_str())); +} +void WpaP2PDevice::onProvisionDiscoveryPBCRequest(const sdbus::ObjectPath &peer_object) +{ + EventTrace("onProvisionDiscoveryPBCRequest", + SS("peer: " << peer_object.c_str())); +} +void WpaP2PDevice::onProvisionDiscoveryPBCResponse(const sdbus::ObjectPath &peer_object) +{ + EventTrace("onProvisionDiscoveryPBCRequest", + SS("peer: " << peer_object.c_str())); +} +void WpaP2PDevice::onInvitationResult(const std::map &invite_result) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream ss; + ss << invite_result; + EventTrace("onInvitationResult", + SS("invite_result: " << ss.str())); + } + OnInvitationResult.fire(invite_result); +} +void WpaP2PDevice::onGroupFinished(const std::map &properties) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream ss; + ss << properties; + EventTrace("onGroupFinished", + SS("properties: " << ss.str())); + + } + OnGroupFinished.fire(properties); +} +void WpaP2PDevice::onServiceDiscoveryRequest(const std::map &sd_request) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream ss; + ss << sd_request; + EventTrace("onServiceDiscoveryRequest", + SS("properties: " << ss.str())); + + } + OnServiceDiscoveryRequest.fire(sd_request); +} +void WpaP2PDevice::onServiceDiscoveryResponse(const std::map &sd_response) +{ + EventTrace("onServiceDiscoveryResponse", ""); +} +void WpaP2PDevice::onWpsFailed(const std::string &name, const std::map &args) +{ + EventTrace("onWpsFailed", + SS("name: " << name)); + OnWpsFailed.fire(name, args); +} +void WpaP2PDevice::onInvitationReceived(const std::map &properties) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream s; + s << properties; + EventTrace("onInvitationReceived", SS("properties: " << s.str())); + } + OnInvitationReceived.fire(properties); +} + +void WpaWPS::onPropertiesChanged(const std::map &properties) {} + +void WpaWPS::onCredentials(const std::map &credentials) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream s; + s << credentials; + LogTrace(getObjectPath(), "onCredentials", SS("credentials: " << s.str())); + } +} + +void WpaP2PDevice::onGroupStarted(const std::map &properties) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream s; + s << properties; + LogTrace(this->getObjectPath(), "onGroupStarted", SS("properties: " << s.str())); + } + OnGroupStarted.fire(properties); +} +void WpaP2PDevice::onGroupFormationFailure(const std::string &reason) +{ + LogTrace(this->getObjectPath(), "onGroupFormationFailure", SS("reason:" << reason)); + OnGroupFormationFailure.fire(reason); +} +void WpaP2PDevice::onGONegotiationSuccess(const std::map &properties) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream s; + s << properties; + LogTrace(this->getObjectPath(), "onGONegotiationSuccess", SS("properties: " << s.str())); + } + OnGONegotiationSuccess.fire(properties); +} +void WpaP2PDevice::onGONegotiationFailure(const std::map &properties) +{ +if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream s; + s << properties; + + LogTrace(this->getObjectPath(), "onGONegotiationFailure", SS("properties: " << s.str())); + } + OnGONegotiationFailure.fire(properties); +} +void WpaP2PDevice::onGONegotiationRequest(const sdbus::ObjectPath &path, const uint16_t &dev_passwd_id, const uint8_t &device_go_intent) +{ +if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + + LogTrace(this->getObjectPath(), "onGONegotiationRequest", SS(" path: " << path.c_str() << " dev_passwd_id: " << dev_passwd_id << " device_go_intent: " << (int32_t)device_go_intent)); + } +} + +void WpaP2PDevice::onProvisionDiscoveryRequestDisplayPin(const sdbus::ObjectPath &peer_object, const std::string &pin) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + + EventTrace("onProvisionDiscoveryRequestDisplayPin", SS("peer: " << peer_object.c_str() << " pin: " << pin)); + } + OnProvisionDiscoveryRequestDisplayPin.fire(peer_object, pin); +} + +void WpaP2PDevice::onPersistentGroupAdded(const sdbus::ObjectPath &path, const std::map &properties) +{ +if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream s; + s << properties; + std::string propertiesString = s.str(); + EventTrace("onPersistentGroupAdded", SS("path: " << path.c_str() << " properties: " << propertiesString)); + } + OnPersistentGroupAdded.fire(path, properties); +} +void WpaP2PDevice::onPersistentGroupRemoved(const sdbus::ObjectPath &path) +{ + EventTrace("onPersistentGroupRemoved", SS("path: " << path.c_str())); + OnPersistentGroupRemoved.fire(path); +} + +void WpaP2PDevice::onFindStopped() +{ + EventTrace("onFindStopped", ""); +} + +void WpaP2PDevice::onProvisionDiscoveryFailure(const sdbus::ObjectPath &peer_object, const int32_t &status) +{ +if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + EventTrace("onProvisionDiscoveryFailure", SS("object: " << peer_object << " status: " << status)); + } +} + +void WpaWPS::onEvent(const std::string &name, const std::map &args) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + std::stringstream ss; + ss << args; + LogTrace(getObjectPath(), "onEvent", SS("object: " << name << " status: " << ss.str())); + } +} + +void WpaSupplicant::onInterfaceAdded(const sdbus::ObjectPath &path, const std::map &properties) +{ + if (IsDBusLoggingEnabled(DBusLogLevel::Trace)) + { + + std::stringstream ss; + ss << properties; + LogTrace("onInterfaceAdded", + SS("path: " << path.c_str() + //<< " properties: {" << ss.str() << "}" + )); + } + + OnInterfaceAdded.fire(path, properties); +} +void WpaSupplicant::onInterfaceRemoved(const sdbus::ObjectPath &path) +{ + LogTrace("onInterfaceRemoved", + SS("path: " << path.c_str())); + OnInterfaceRemoved.fire(path); +} + +void WpaP2PDevice::EventTrace(const char *eventName, const std::function &getText) +{ + ::LogTrace(this->getObjectPath(), eventName, getText); +} diff --git a/NetworkManagerP2P/src/WpaInterfaces.hpp b/NetworkManagerP2P/src/WpaInterfaces.hpp new file mode 100644 index 0000000..c120993 --- /dev/null +++ b/NetworkManagerP2P/src/WpaInterfaces.hpp @@ -0,0 +1,301 @@ +#pragma once +#include "dbus/hpp/fi.w1.wpa_supplicant1.hpp" +#include "dbus/hpp/f1.w1.wpa_supplicant1.Interfaces.hpp" +#include "dbus/hpp/f1.w1.wpa_supplicant1.Peer.hpp" +#include "dbus/hpp/f1.w1.wpa_supplicant1.Group.hpp" +#include "dbus/hpp/org.freedesktop.DBus.Properties.hpp" +#include "DBusLog.hpp" +#include "DBusEvent.hpp" +#include "DBusVariantHelper.hpp" +#include +#include + +class Interface_proxy_withevents : public fi::w1::wpa_supplicant1::Interface_proxy +{ +public: + using base = fi::w1::wpa_supplicant1::Interface_proxy; + + Interface_proxy_withevents(sdbus::IProxy &proxy) + : base(proxy), proxy(proxy) + { + } + + DBusEvent &> + OnNetworkAdded; + + DBusEvent OnNetworkRemoved; + DBusEvent OnNetworkSelected; + DBusEvent &> OnStationAdded; + DBusEvent OnStationRemoved; + DBusEvent OnStaAuthorized; + DBusEvent OnStaDeauthorized; + + DBusEvent &> OnInterworkingAPAdded; + DBusEvent<> OnInterworkingSelectDone; + +protected: + void EventTrace(const char *methodName, const std::string &message); +private: + sdbus::IProxy &proxy; + +protected: + virtual void onScanDone(const bool &success); + virtual void onBSSAdded(const sdbus::ObjectPath &path, const std::map &properties); + virtual void onBSSRemoved(const sdbus::ObjectPath &path); + virtual void onBlobAdded(const std::string &name); + virtual void onBlobRemoved(const std::string &name); + virtual void onNetworkAdded(const sdbus::ObjectPath &path, const std::map &properties); + virtual void onNetworkRemoved(const sdbus::ObjectPath &path); + virtual void onNetworkSelected(const sdbus::ObjectPath &path); + virtual void onPropertiesChanged(const std::map &properties); + virtual void onProbeRequest(const std::map &args); + virtual void onCertification(const std::map &certification); + virtual void onEAP(const std::string &status, const std::string ¶meter); + virtual void onStaAuthorized(const std::string &name); + virtual void onStaDeauthorized(const std::string &name); + virtual void onStationAdded(const sdbus::ObjectPath &path, const std::map &properties); + virtual void onStationRemoved(const sdbus::ObjectPath &path); + virtual void onNetworkRequest(const sdbus::ObjectPath &path, const std::string &field, const std::string &text); + virtual void onInterworkingAPAdded(const sdbus::ObjectPath &bss, const sdbus::ObjectPath &cred, const std::map &properties); + virtual void onInterworkingSelectDone(); +}; + +class WpaInterface + : public sdbus::ProxyInterfaces< + Interface_proxy_withevents> +{ +public: + using self = WpaInterface; + using ptr = std::unique_ptr; + static ptr Create(sdbus::IConnection &connection, const sdbus::ObjectPath &dbusPath) { return std::make_unique(connection, dbusPath); } + + WpaInterface(sdbus::IConnection &connection, const sdbus::ObjectPath &dbusPath) + : ProxyInterfaces(connection, "fi.w1.wpa_supplicant1", dbusPath) + { + registerProxy(); + } + virtual ~WpaInterface() + { + unregisterProxy(); + } + +protected: + void Trace(const char *method, const std::string &msg) + { + ::LogTrace(this->getObjectPath(), method, msg); + } +}; + +class WpaPersistentGroup + : public sdbus::ProxyInterfaces< + fi::w1::wpa_supplicant1::PersistentGroup_proxy> +{ +public: + using self = WpaPersistentGroup; + using ptr = std::unique_ptr; + + static ptr Create(sdbus::IConnection &connection, const sdbus::ObjectPath &path) { return std::make_unique(connection, path); } + + WpaPersistentGroup(sdbus::IConnection &connection, const sdbus::ObjectPath &objectPath) + : ProxyInterfaces(connection, "fi.w1.wpa_supplicant1", objectPath) + { + } +}; + +class WpaWPS + : public sdbus::ProxyInterfaces< + fi::w1::wpa_supplicant1::Interface::WPS_proxy> +{ +public: + using self = WpaWPS; + using ptr = std::unique_ptr; + static ptr Create(sdbus::IProxy &proxy) { return std::make_unique(proxy.getObjectPath()); } + static ptr Create(const std::string &path) { return std::make_unique(path); } + static ptr Create(sdbus::IConnection &connection, const std::string &path) { return std::make_unique(connection, path); } + + WpaWPS(std::string objectPath) + : ProxyInterfaces("fi.w1.wpa_supplicant1", objectPath) + { + } + WpaWPS(sdbus::IConnection &connection, std::string objectPath) + : ProxyInterfaces(connection, "fi.w1.wpa_supplicant1", objectPath) + { + } + +protected: + virtual void onEvent(const std::string &name, const std::map &args); + virtual void onCredentials(const std::map &credentials); + virtual void onPropertiesChanged(const std::map &properties); +}; + +class WpaPeer + : public sdbus::ProxyInterfaces< + fi::w1::wpa_supplicant1::Peer_proxy> +{ +public: + using self = WpaPeer; + using ptr = std::unique_ptr; + static ptr Create(sdbus::IConnection &connection, const std::string &dbusPath) { return std::make_unique(connection, dbusPath); } + + WpaPeer(sdbus::IConnection &connection, const std::string &dbusPath) + : ProxyInterfaces(connection, "fi.w1.wpa_supplicant1", dbusPath) + { + registerProxy(); + } + virtual ~WpaPeer() + { + unregisterProxy(); + } + +private: + virtual void onPropertiesChanged(const std::map &properties) {} +}; + +class WpaP2PDevice + : public sdbus::ProxyInterfaces< + fi::w1::wpa_supplicant1::Interface::P2PDevice_proxy, + Interface_proxy_withevents> +{ +public: + using self = WpaP2PDevice; + using ptr = std::unique_ptr; + static ptr Create(const std::string &dbusPath) { return std::make_unique(dbusPath); } + static ptr Create(sdbus::IConnection &connection, const std::string &dbusPath) { return std::make_unique(connection, dbusPath); } + + WpaP2PDevice(const std::string &dbusPath) + : ProxyInterfaces("fi.w1.wpa_supplicant1", dbusPath) + { + registerProxy(); + } + WpaP2PDevice(sdbus::IConnection &connection, const std::string &dbusPath) + : ProxyInterfaces(connection, "fi.w1.wpa_supplicant1", dbusPath) + { + registerProxy(); + } + virtual ~WpaP2PDevice() + { + unregisterProxy(); + } + void Disconnect() + { + fi::w1::wpa_supplicant1::Interface::P2PDevice_proxy::Disconnect(); + } + +public: + DBusEvent OnProvisionDiscoveryEnterPin; + DBusEvent OnProvisionDiscoveryRequestDisplayPin; + DBusEvent &> OnPersistentGroupAdded; + DBusEvent OnPersistentGroupRemoved; + DBusEvent &> OnGroupStarted; + DBusEvent &> OnGroupFinished; + DBusEvent &> OnServiceDiscoveryRequest; + + DBusEvent OnGroupFormationFailure; + DBusEvent &> OnGONegotiationSuccess; + DBusEvent &> OnGONegotiationFailure; + DBusEvent> OnWpsFailed; + DBusEvent> OnInvitationResult; + DBusEvent &> OnInvitationReceived; + +private: + void EventTrace(const char *methodName, const std::string &message) + { + Interface_proxy_withevents::EventTrace(methodName,message); + } + + void EventTrace(const char *eventName, const std::function &getText); +protected: + virtual void onDeviceFound(const sdbus::ObjectPath &path); + virtual void onDeviceFoundProperties(const sdbus::ObjectPath &path, const std::map &properties); + virtual void onDeviceLost(const sdbus::ObjectPath &path); + virtual void onFindStopped(); + virtual void onProvisionDiscoveryRequestDisplayPin(const sdbus::ObjectPath &peer_object, const std::string &pin); + virtual void onProvisionDiscoveryResponseDisplayPin(const sdbus::ObjectPath &peer_object, const std::string &pin); + virtual void onProvisionDiscoveryRequestEnterPin(const sdbus::ObjectPath &peer_object); + virtual void onProvisionDiscoveryResponseEnterPin(const sdbus::ObjectPath &peer_object); + virtual void onProvisionDiscoveryPBCRequest(const sdbus::ObjectPath &peer_object); + virtual void onProvisionDiscoveryPBCResponse(const sdbus::ObjectPath &peer_object); + virtual void onProvisionDiscoveryFailure(const sdbus::ObjectPath &peer_object, const int32_t &status); + + virtual void onGroupStarted(const std::map &properties); + virtual void onGroupFormationFailure(const std::string &reason); + virtual void onGONegotiationSuccess(const std::map &properties); + virtual void onGONegotiationFailure(const std::map &properties); + virtual void onGONegotiationRequest(const sdbus::ObjectPath &path, const uint16_t &dev_passwd_id, const uint8_t &device_go_intent); + virtual void onInvitationResult(const std::map &invite_result); + virtual void onGroupFinished(const std::map &properties); + virtual void onServiceDiscoveryRequest(const std::map &sd_request); + virtual void onServiceDiscoveryResponse(const std::map &sd_response); + virtual void onPersistentGroupAdded(const sdbus::ObjectPath &path, const std::map &properties); + virtual void onPersistentGroupRemoved(const sdbus::ObjectPath &path); + virtual void onWpsFailed(const std::string &name, const std::map &args); + virtual void onInvitationReceived(const std::map &properties); + +}; + +class WpaGroup + : public sdbus::ProxyInterfaces, + public DBusLog +{ +public: + using self = WpaGroup; + using ptr = std::unique_ptr; + static ptr Create(sdbus::IConnection &connection, const sdbus::ObjectPath &path) { return std::make_unique(connection, path); } + + WpaGroup(sdbus::IConnection &connection, const sdbus::ObjectPath &path) + : ProxyInterfaces(connection, "fi.w1.wpa_supplicant1", path), DBusLog(path) + { + registerProxy(); + } + virtual ~WpaGroup() + { + unregisterProxy(); + } + DBusEvent OnPeerJoined; + DBusEvent OnPeerDisconnected; + +private: + virtual void onPeerJoined(const sdbus::ObjectPath &peer) + { + OnPeerJoined.fire(peer); + } + virtual void onPeerDisconnected(const sdbus::ObjectPath &peer) + { + OnPeerDisconnected.fire(peer); + } +}; + +class WpaSupplicant + : public sdbus::ProxyInterfaces, + public DBusLog +{ +public: + using self = WpaSupplicant; + using ptr = std::unique_ptr; + static ptr Create() { return std::make_unique(); } + static ptr Create(sdbus::IConnection &connection) { return std::make_unique(connection); } + + WpaSupplicant() + : ProxyInterfaces("fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1"), + DBusLog("fi/w1/WpaSupplicant1") + { + registerProxy(); + } + WpaSupplicant(sdbus::IConnection &connection) + : ProxyInterfaces(connection, "fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1"), + DBusLog("fi/w1/WpaSupplicant1") + { + registerProxy(); + } + virtual ~WpaSupplicant() + { + unregisterProxy(); + } + DBusEvent &> OnInterfaceAdded; + DBusEvent OnInterfaceRemoved; + +private: + virtual void onInterfaceAdded(const sdbus::ObjectPath &path, const std::map &properties); + virtual void onInterfaceRemoved(const sdbus::ObjectPath &path); + virtual void onPropertiesChanged(const std::map &properties) {} +}; diff --git a/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Group.hpp b/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Group.hpp new file mode 100644 index 0000000..0067e8a --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Group.hpp @@ -0,0 +1,92 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_f1_w1_wpa_supplicant1_Group_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_f1_w1_wpa_supplicant1_Group_hpp__proxy__H__ + +#include +#include +#include + +namespace fi { +namespace w1 { +namespace wpa_supplicant1 { + +class Group_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "fi.w1.wpa_supplicant1.Group"; + +protected: + Group_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("PeerJoined").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer){ this->onPeerJoined(peer); }); + proxy_.uponSignal("PeerDisconnected").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer){ this->onPeerDisconnected(peer); }); + } + + ~Group_proxy() = default; + + virtual void onPeerJoined(const sdbus::ObjectPath& peer) = 0; + virtual void onPeerDisconnected(const sdbus::ObjectPath& peer) = 0; + +public: + std::vector Members() + { + return proxy_.getProperty("Members").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Group() + { + return proxy_.getProperty("Group").onInterface(INTERFACE_NAME); + } + + std::string Role() + { + return proxy_.getProperty("Role").onInterface(INTERFACE_NAME); + } + + std::vector SSID() + { + return proxy_.getProperty("SSID").onInterface(INTERFACE_NAME); + } + + std::vector BSSID() + { + return proxy_.getProperty("BSSID").onInterface(INTERFACE_NAME); + } + + uint16_t Frequency() + { + return proxy_.getProperty("Frequency").onInterface(INTERFACE_NAME); + } + + std::string Passphrase() + { + return proxy_.getProperty("Passphrase").onInterface(INTERFACE_NAME); + } + + std::vector PSK() + { + return proxy_.getProperty("PSK").onInterface(INTERFACE_NAME); + } + + std::vector> WPSVendorExtensions() + { + return proxy_.getProperty("WPSVendorExtensions").onInterface(INTERFACE_NAME); + } + + void WPSVendorExtensions(const std::vector>& value) + { + proxy_.setProperty("WPSVendorExtensions").onInterface(INTERFACE_NAME).toValue(value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Interfaces.hpp b/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Interfaces.hpp new file mode 100644 index 0000000..d0e3863 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Interfaces.hpp @@ -0,0 +1,2254 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_f1_w1_wpa_supplicant1_Interfaces_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_f1_w1_wpa_supplicant1_Interfaces_hpp__proxy__H__ + +#include +#include +#include + +namespace fi { +namespace w1 { +namespace wpa_supplicant1 { + +class Interface_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "fi.w1.wpa_supplicant1.Interface"; + +protected: + Interface_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("ScanDone").onInterface(INTERFACE_NAME).call([this](const bool& success){ this->onScanDone(success); }); + proxy_.uponSignal("BSSAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const std::map& properties){ this->onBSSAdded(path, properties); }); + proxy_.uponSignal("BSSRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onBSSRemoved(path); }); + proxy_.uponSignal("BlobAdded").onInterface(INTERFACE_NAME).call([this](const std::string& name){ this->onBlobAdded(name); }); + proxy_.uponSignal("BlobRemoved").onInterface(INTERFACE_NAME).call([this](const std::string& name){ this->onBlobRemoved(name); }); + proxy_.uponSignal("NetworkAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const std::map& properties){ this->onNetworkAdded(path, properties); }); + proxy_.uponSignal("NetworkRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onNetworkRemoved(path); }); + proxy_.uponSignal("NetworkSelected").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onNetworkSelected(path); }); + proxy_.uponSignal("PropertiesChanged").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onPropertiesChanged(properties); }); + proxy_.uponSignal("ProbeRequest").onInterface(INTERFACE_NAME).call([this](const std::map& args){ this->onProbeRequest(args); }); + proxy_.uponSignal("Certification").onInterface(INTERFACE_NAME).call([this](const std::map& certification){ this->onCertification(certification); }); + proxy_.uponSignal("EAP").onInterface(INTERFACE_NAME).call([this](const std::string& status, const std::string& parameter){ this->onEAP(status, parameter); }); + proxy_.uponSignal("StaAuthorized").onInterface(INTERFACE_NAME).call([this](const std::string& name){ this->onStaAuthorized(name); }); + proxy_.uponSignal("StaDeauthorized").onInterface(INTERFACE_NAME).call([this](const std::string& name){ this->onStaDeauthorized(name); }); + proxy_.uponSignal("StationAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const std::map& properties){ this->onStationAdded(path, properties); }); + proxy_.uponSignal("StationRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onStationRemoved(path); }); + proxy_.uponSignal("NetworkRequest").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const std::string& field, const std::string& text){ this->onNetworkRequest(path, field, text); }); + proxy_.uponSignal("InterworkingAPAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& bss, const sdbus::ObjectPath& cred, const std::map& properties){ this->onInterworkingAPAdded(bss, cred, properties); }); + proxy_.uponSignal("InterworkingSelectDone").onInterface(INTERFACE_NAME).call([this](){ this->onInterworkingSelectDone(); }); + } + + ~Interface_proxy() = default; + + virtual void onScanDone(const bool& success) = 0; + virtual void onBSSAdded(const sdbus::ObjectPath& path, const std::map& properties) = 0; + virtual void onBSSRemoved(const sdbus::ObjectPath& path) = 0; + virtual void onBlobAdded(const std::string& name) = 0; + virtual void onBlobRemoved(const std::string& name) = 0; + virtual void onNetworkAdded(const sdbus::ObjectPath& path, const std::map& properties) = 0; + virtual void onNetworkRemoved(const sdbus::ObjectPath& path) = 0; + virtual void onNetworkSelected(const sdbus::ObjectPath& path) = 0; + virtual void onPropertiesChanged(const std::map& properties) = 0; + virtual void onProbeRequest(const std::map& args) = 0; + virtual void onCertification(const std::map& certification) = 0; + virtual void onEAP(const std::string& status, const std::string& parameter) = 0; + virtual void onStaAuthorized(const std::string& name) = 0; + virtual void onStaDeauthorized(const std::string& name) = 0; + virtual void onStationAdded(const sdbus::ObjectPath& path, const std::map& properties) = 0; + virtual void onStationRemoved(const sdbus::ObjectPath& path) = 0; + virtual void onNetworkRequest(const sdbus::ObjectPath& path, const std::string& field, const std::string& text) = 0; + virtual void onInterworkingAPAdded(const sdbus::ObjectPath& bss, const sdbus::ObjectPath& cred, const std::map& properties) = 0; + virtual void onInterworkingSelectDone() = 0; + +public: + void Scan(const std::map& args) + { + proxy_.callMethod("Scan").onInterface(INTERFACE_NAME).withArguments(args); + } + + std::map SignalPoll() + { + std::map result; + proxy_.callMethod("SignalPoll").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void Disconnect() + { + proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath AddNetwork(const std::map& args) + { + sdbus::ObjectPath result; + proxy_.callMethod("AddNetwork").onInterface(INTERFACE_NAME).withArguments(args).storeResultsTo(result); + return result; + } + + void Reassociate() + { + proxy_.callMethod("Reassociate").onInterface(INTERFACE_NAME); + } + + void Reattach() + { + proxy_.callMethod("Reattach").onInterface(INTERFACE_NAME); + } + + void Reconnect() + { + proxy_.callMethod("Reconnect").onInterface(INTERFACE_NAME); + } + + void RemoveNetwork(const sdbus::ObjectPath& path) + { + proxy_.callMethod("RemoveNetwork").onInterface(INTERFACE_NAME).withArguments(path); + } + + void RemoveAllNetworks() + { + proxy_.callMethod("RemoveAllNetworks").onInterface(INTERFACE_NAME); + } + + void SelectNetwork(const sdbus::ObjectPath& path) + { + proxy_.callMethod("SelectNetwork").onInterface(INTERFACE_NAME).withArguments(path); + } + + void NetworkReply(const sdbus::ObjectPath& path, const std::string& field, const std::string& value) + { + proxy_.callMethod("NetworkReply").onInterface(INTERFACE_NAME).withArguments(path, field, value); + } + + void Roam(const std::string& addr) + { + proxy_.callMethod("Roam").onInterface(INTERFACE_NAME).withArguments(addr); + } + + void AddBlob(const std::string& name, const std::vector& data) + { + proxy_.callMethod("AddBlob").onInterface(INTERFACE_NAME).withArguments(name, data); + } + + std::vector GetBlob(const std::string& name) + { + std::vector result; + proxy_.callMethod("GetBlob").onInterface(INTERFACE_NAME).withArguments(name).storeResultsTo(result); + return result; + } + + void RemoveBlob(const std::string& name) + { + proxy_.callMethod("RemoveBlob").onInterface(INTERFACE_NAME).withArguments(name); + } + + void SetPKCS11EngineAndModulePath(const std::string& pkcs11_engine_path, const std::string& pkcs11_module_path) + { + proxy_.callMethod("SetPKCS11EngineAndModulePath").onInterface(INTERFACE_NAME).withArguments(pkcs11_engine_path, pkcs11_module_path); + } + + void FlushBSS(const uint32_t& age) + { + proxy_.callMethod("FlushBSS").onInterface(INTERFACE_NAME).withArguments(age); + } + + void SubscribeProbeReq() + { + proxy_.callMethod("SubscribeProbeReq").onInterface(INTERFACE_NAME); + } + + void UnsubscribeProbeReq() + { + proxy_.callMethod("UnsubscribeProbeReq").onInterface(INTERFACE_NAME); + } + + void EAPLogoff() + { + proxy_.callMethod("EAPLogoff").onInterface(INTERFACE_NAME); + } + + void EAPLogon() + { + proxy_.callMethod("EAPLogon").onInterface(INTERFACE_NAME); + } + + void AutoScan(const std::string& arg) + { + proxy_.callMethod("AutoScan").onInterface(INTERFACE_NAME).withArguments(arg); + } + + void TDLSDiscover(const std::string& peer_address) + { + proxy_.callMethod("TDLSDiscover").onInterface(INTERFACE_NAME).withArguments(peer_address); + } + + void TDLSSetup(const std::string& peer_address) + { + proxy_.callMethod("TDLSSetup").onInterface(INTERFACE_NAME).withArguments(peer_address); + } + + std::string TDLSStatus(const std::string& peer_address) + { + std::string result; + proxy_.callMethod("TDLSStatus").onInterface(INTERFACE_NAME).withArguments(peer_address).storeResultsTo(result); + return result; + } + + void TDLSTeardown(const std::string& peer_address) + { + proxy_.callMethod("TDLSTeardown").onInterface(INTERFACE_NAME).withArguments(peer_address); + } + + void TDLSChannelSwitch(const std::map& args) + { + proxy_.callMethod("TDLSChannelSwitch").onInterface(INTERFACE_NAME).withArguments(args); + } + + void TDLSCancelChannelSwitch(const std::string& peer_address) + { + proxy_.callMethod("TDLSCancelChannelSwitch").onInterface(INTERFACE_NAME).withArguments(peer_address); + } + + void VendorElemAdd(const int32_t& frame_id, const std::vector& ielems) + { + proxy_.callMethod("VendorElemAdd").onInterface(INTERFACE_NAME).withArguments(frame_id, ielems); + } + + std::vector VendorElemGet(const int32_t& frame_id) + { + std::vector result; + proxy_.callMethod("VendorElemGet").onInterface(INTERFACE_NAME).withArguments(frame_id).storeResultsTo(result); + return result; + } + + void VendorElemRem(const int32_t& frame_id, const std::vector& ielems) + { + proxy_.callMethod("VendorElemRem").onInterface(INTERFACE_NAME).withArguments(frame_id, ielems); + } + + void SaveConfig() + { + proxy_.callMethod("SaveConfig").onInterface(INTERFACE_NAME); + } + + void AbortScan() + { + proxy_.callMethod("AbortScan").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath AddCred(const std::map& args) + { + sdbus::ObjectPath result; + proxy_.callMethod("AddCred").onInterface(INTERFACE_NAME).withArguments(args).storeResultsTo(result); + return result; + } + + void RemoveCred(const sdbus::ObjectPath& path) + { + proxy_.callMethod("RemoveCred").onInterface(INTERFACE_NAME).withArguments(path); + } + + void RemoveAllCreds() + { + proxy_.callMethod("RemoveAllCreds").onInterface(INTERFACE_NAME); + } + + void InterworkingSelect() + { + proxy_.callMethod("InterworkingSelect").onInterface(INTERFACE_NAME); + } + +public: + std::map Capabilities() + { + return proxy_.getProperty("Capabilities").onInterface(INTERFACE_NAME); + } + + std::string State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + + bool Scanning() + { + return proxy_.getProperty("Scanning").onInterface(INTERFACE_NAME); + } + + uint32_t ApScan() + { + return proxy_.getProperty("ApScan").onInterface(INTERFACE_NAME); + } + + void ApScan(const uint32_t& value) + { + proxy_.setProperty("ApScan").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t BSSExpireAge() + { + return proxy_.getProperty("BSSExpireAge").onInterface(INTERFACE_NAME); + } + + void BSSExpireAge(const uint32_t& value) + { + proxy_.setProperty("BSSExpireAge").onInterface(INTERFACE_NAME).toValue(value); + } + + uint32_t BSSExpireCount() + { + return proxy_.getProperty("BSSExpireCount").onInterface(INTERFACE_NAME); + } + + void BSSExpireCount(const uint32_t& value) + { + proxy_.setProperty("BSSExpireCount").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Country() + { + return proxy_.getProperty("Country").onInterface(INTERFACE_NAME); + } + + void Country(const std::string& value) + { + proxy_.setProperty("Country").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Ifname() + { + return proxy_.getProperty("Ifname").onInterface(INTERFACE_NAME); + } + + std::string Driver() + { + return proxy_.getProperty("Driver").onInterface(INTERFACE_NAME); + } + + std::string BridgeIfname() + { + return proxy_.getProperty("BridgeIfname").onInterface(INTERFACE_NAME); + } + + void BridgeIfname(const std::string& value) + { + proxy_.setProperty("BridgeIfname").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ConfigFile() + { + return proxy_.getProperty("ConfigFile").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath CurrentBSS() + { + return proxy_.getProperty("CurrentBSS").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath CurrentNetwork() + { + return proxy_.getProperty("CurrentNetwork").onInterface(INTERFACE_NAME); + } + + std::string CurrentAuthMode() + { + return proxy_.getProperty("CurrentAuthMode").onInterface(INTERFACE_NAME); + } + + std::map> Blobs() + { + return proxy_.getProperty("Blobs").onInterface(INTERFACE_NAME); + } + + std::vector BSSs() + { + return proxy_.getProperty("BSSs").onInterface(INTERFACE_NAME); + } + + std::vector Networks() + { + return proxy_.getProperty("Networks").onInterface(INTERFACE_NAME); + } + + bool FastReauth() + { + return proxy_.getProperty("FastReauth").onInterface(INTERFACE_NAME); + } + + void FastReauth(const bool& value) + { + proxy_.setProperty("FastReauth").onInterface(INTERFACE_NAME).toValue(value); + } + + int32_t ScanInterval() + { + return proxy_.getProperty("ScanInterval").onInterface(INTERFACE_NAME); + } + + void ScanInterval(const int32_t& value) + { + proxy_.setProperty("ScanInterval").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PKCS11EnginePath() + { + return proxy_.getProperty("PKCS11EnginePath").onInterface(INTERFACE_NAME); + } + + std::string PKCS11ModulePath() + { + return proxy_.getProperty("PKCS11ModulePath").onInterface(INTERFACE_NAME); + } + + int32_t DisconnectReason() + { + return proxy_.getProperty("DisconnectReason").onInterface(INTERFACE_NAME); + } + + int32_t AuthStatusCode() + { + return proxy_.getProperty("AuthStatusCode").onInterface(INTERFACE_NAME); + } + + int32_t AssocStatusCode() + { + return proxy_.getProperty("AssocStatusCode").onInterface(INTERFACE_NAME); + } + + uint32_t RoamTime() + { + return proxy_.getProperty("RoamTime").onInterface(INTERFACE_NAME); + } + + bool RoamComplete() + { + return proxy_.getProperty("RoamComplete").onInterface(INTERFACE_NAME); + } + + uint32_t SessionLength() + { + return proxy_.getProperty("SessionLength").onInterface(INTERFACE_NAME); + } + + uint32_t BSSTMStatus() + { + return proxy_.getProperty("BSSTMStatus").onInterface(INTERFACE_NAME); + } + + std::vector Stations() + { + return proxy_.getProperty("Stations").onInterface(INTERFACE_NAME); + } + + std::map> MACAddressRandomizationMask() + { + return proxy_.getProperty("MACAddressRandomizationMask").onInterface(INTERFACE_NAME); + } + + void MACAddressRandomizationMask(const std::map>& value) + { + proxy_.setProperty("MACAddressRandomizationMask").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string CtrlInterface() + { + return proxy_.getProperty("CtrlInterface").onInterface(INTERFACE_NAME); + } + + void CtrlInterface(const std::string& value) + { + proxy_.setProperty("CtrlInterface").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string CtrlInterfaceGroup() + { + return proxy_.getProperty("CtrlInterfaceGroup").onInterface(INTERFACE_NAME); + } + + void CtrlInterfaceGroup(const std::string& value) + { + proxy_.setProperty("CtrlInterfaceGroup").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string EapolVersion() + { + return proxy_.getProperty("EapolVersion").onInterface(INTERFACE_NAME); + } + + void EapolVersion(const std::string& value) + { + proxy_.setProperty("EapolVersion").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Bgscan() + { + return proxy_.getProperty("Bgscan").onInterface(INTERFACE_NAME); + } + + void Bgscan(const std::string& value) + { + proxy_.setProperty("Bgscan").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string UserMpm() + { + return proxy_.getProperty("UserMpm").onInterface(INTERFACE_NAME); + } + + void UserMpm(const std::string& value) + { + proxy_.setProperty("UserMpm").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string MaxPeerLinks() + { + return proxy_.getProperty("MaxPeerLinks").onInterface(INTERFACE_NAME); + } + + void MaxPeerLinks(const std::string& value) + { + proxy_.setProperty("MaxPeerLinks").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string MeshMaxInactivity() + { + return proxy_.getProperty("MeshMaxInactivity").onInterface(INTERFACE_NAME); + } + + void MeshMaxInactivity(const std::string& value) + { + proxy_.setProperty("MeshMaxInactivity").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string MeshFwding() + { + return proxy_.getProperty("MeshFwding").onInterface(INTERFACE_NAME); + } + + void MeshFwding(const std::string& value) + { + proxy_.setProperty("MeshFwding").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Dot11RSNASAERetransPeriod() + { + return proxy_.getProperty("Dot11RSNASAERetransPeriod").onInterface(INTERFACE_NAME); + } + + void Dot11RSNASAERetransPeriod(const std::string& value) + { + proxy_.setProperty("Dot11RSNASAERetransPeriod").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DisableScanOffload() + { + return proxy_.getProperty("DisableScanOffload").onInterface(INTERFACE_NAME); + } + + void DisableScanOffload(const std::string& value) + { + proxy_.setProperty("DisableScanOffload").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string OpenscEnginePath() + { + return proxy_.getProperty("OpenscEnginePath").onInterface(INTERFACE_NAME); + } + + void OpenscEnginePath(const std::string& value) + { + proxy_.setProperty("OpenscEnginePath").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string OpensslCiphers() + { + return proxy_.getProperty("OpensslCiphers").onInterface(INTERFACE_NAME); + } + + void OpensslCiphers(const std::string& value) + { + proxy_.setProperty("OpensslCiphers").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PcscReader() + { + return proxy_.getProperty("PcscReader").onInterface(INTERFACE_NAME); + } + + void PcscReader(const std::string& value) + { + proxy_.setProperty("PcscReader").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PcscPin() + { + return proxy_.getProperty("PcscPin").onInterface(INTERFACE_NAME); + } + + void PcscPin(const std::string& value) + { + proxy_.setProperty("PcscPin").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ExternalSim() + { + return proxy_.getProperty("ExternalSim").onInterface(INTERFACE_NAME); + } + + void ExternalSim(const std::string& value) + { + proxy_.setProperty("ExternalSim").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DriverParam() + { + return proxy_.getProperty("DriverParam").onInterface(INTERFACE_NAME); + } + + void DriverParam(const std::string& value) + { + proxy_.setProperty("DriverParam").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Dot11RSNAConfigPMKLifetime() + { + return proxy_.getProperty("Dot11RSNAConfigPMKLifetime").onInterface(INTERFACE_NAME); + } + + void Dot11RSNAConfigPMKLifetime(const std::string& value) + { + proxy_.setProperty("Dot11RSNAConfigPMKLifetime").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Dot11RSNAConfigPMKReauthThreshold() + { + return proxy_.getProperty("Dot11RSNAConfigPMKReauthThreshold").onInterface(INTERFACE_NAME); + } + + void Dot11RSNAConfigPMKReauthThreshold(const std::string& value) + { + proxy_.setProperty("Dot11RSNAConfigPMKReauthThreshold").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Dot11RSNAConfigSATimeout() + { + return proxy_.getProperty("Dot11RSNAConfigSATimeout").onInterface(INTERFACE_NAME); + } + + void Dot11RSNAConfigSATimeout(const std::string& value) + { + proxy_.setProperty("Dot11RSNAConfigSATimeout").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string UpdateConfig() + { + return proxy_.getProperty("UpdateConfig").onInterface(INTERFACE_NAME); + } + + void UpdateConfig(const std::string& value) + { + proxy_.setProperty("UpdateConfig").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Uuid() + { + return proxy_.getProperty("Uuid").onInterface(INTERFACE_NAME); + } + + void Uuid(const std::string& value) + { + proxy_.setProperty("Uuid").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string AutoUuid() + { + return proxy_.getProperty("AutoUuid").onInterface(INTERFACE_NAME); + } + + void AutoUuid(const std::string& value) + { + proxy_.setProperty("AutoUuid").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DeviceName() + { + return proxy_.getProperty("DeviceName").onInterface(INTERFACE_NAME); + } + + void DeviceName(const std::string& value) + { + proxy_.setProperty("DeviceName").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Manufacturer() + { + return proxy_.getProperty("Manufacturer").onInterface(INTERFACE_NAME); + } + + void Manufacturer(const std::string& value) + { + proxy_.setProperty("Manufacturer").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ModelName() + { + return proxy_.getProperty("ModelName").onInterface(INTERFACE_NAME); + } + + void ModelName(const std::string& value) + { + proxy_.setProperty("ModelName").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ModelNumber() + { + return proxy_.getProperty("ModelNumber").onInterface(INTERFACE_NAME); + } + + void ModelNumber(const std::string& value) + { + proxy_.setProperty("ModelNumber").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SerialNumber() + { + return proxy_.getProperty("SerialNumber").onInterface(INTERFACE_NAME); + } + + void SerialNumber(const std::string& value) + { + proxy_.setProperty("SerialNumber").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DeviceType() + { + return proxy_.getProperty("DeviceType").onInterface(INTERFACE_NAME); + } + + void DeviceType(const std::string& value) + { + proxy_.setProperty("DeviceType").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string OsVersion() + { + return proxy_.getProperty("OsVersion").onInterface(INTERFACE_NAME); + } + + void OsVersion(const std::string& value) + { + proxy_.setProperty("OsVersion").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ConfigMethods() + { + return proxy_.getProperty("ConfigMethods").onInterface(INTERFACE_NAME); + } + + void ConfigMethods(const std::string& value) + { + proxy_.setProperty("ConfigMethods").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsCredProcessing() + { + return proxy_.getProperty("WpsCredProcessing").onInterface(INTERFACE_NAME); + } + + void WpsCredProcessing(const std::string& value) + { + proxy_.setProperty("WpsCredProcessing").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsCredAddSae() + { + return proxy_.getProperty("WpsCredAddSae").onInterface(INTERFACE_NAME); + } + + void WpsCredAddSae(const std::string& value) + { + proxy_.setProperty("WpsCredAddSae").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsVendorExtM1() + { + return proxy_.getProperty("WpsVendorExtM1").onInterface(INTERFACE_NAME); + } + + void WpsVendorExtM1(const std::string& value) + { + proxy_.setProperty("WpsVendorExtM1").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SecDeviceType() + { + return proxy_.getProperty("SecDeviceType").onInterface(INTERFACE_NAME); + } + + void SecDeviceType(const std::string& value) + { + proxy_.setProperty("SecDeviceType").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pListenRegClass() + { + return proxy_.getProperty("P2pListenRegClass").onInterface(INTERFACE_NAME); + } + + void P2pListenRegClass(const std::string& value) + { + proxy_.setProperty("P2pListenRegClass").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pListenChannel() + { + return proxy_.getProperty("P2pListenChannel").onInterface(INTERFACE_NAME); + } + + void P2pListenChannel(const std::string& value) + { + proxy_.setProperty("P2pListenChannel").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pOperRegClass() + { + return proxy_.getProperty("P2pOperRegClass").onInterface(INTERFACE_NAME); + } + + void P2pOperRegClass(const std::string& value) + { + proxy_.setProperty("P2pOperRegClass").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pOperChannel() + { + return proxy_.getProperty("P2pOperChannel").onInterface(INTERFACE_NAME); + } + + void P2pOperChannel(const std::string& value) + { + proxy_.setProperty("P2pOperChannel").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoIntent() + { + return proxy_.getProperty("P2pGoIntent").onInterface(INTERFACE_NAME); + } + + void P2pGoIntent(const std::string& value) + { + proxy_.setProperty("P2pGoIntent").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pSsidPostfix() + { + return proxy_.getProperty("P2pSsidPostfix").onInterface(INTERFACE_NAME); + } + + void P2pSsidPostfix(const std::string& value) + { + proxy_.setProperty("P2pSsidPostfix").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PersistentReconnect() + { + return proxy_.getProperty("PersistentReconnect").onInterface(INTERFACE_NAME); + } + + void PersistentReconnect(const std::string& value) + { + proxy_.setProperty("PersistentReconnect").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pIntraBss() + { + return proxy_.getProperty("P2pIntraBss").onInterface(INTERFACE_NAME); + } + + void P2pIntraBss(const std::string& value) + { + proxy_.setProperty("P2pIntraBss").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGroupIdle() + { + return proxy_.getProperty("P2pGroupIdle").onInterface(INTERFACE_NAME); + } + + void P2pGroupIdle(const std::string& value) + { + proxy_.setProperty("P2pGroupIdle").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoFreqChangePolicy() + { + return proxy_.getProperty("P2pGoFreqChangePolicy").onInterface(INTERFACE_NAME); + } + + void P2pGoFreqChangePolicy(const std::string& value) + { + proxy_.setProperty("P2pGoFreqChangePolicy").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pPassphraseLen() + { + return proxy_.getProperty("P2pPassphraseLen").onInterface(INTERFACE_NAME); + } + + void P2pPassphraseLen(const std::string& value) + { + proxy_.setProperty("P2pPassphraseLen").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pPrefChan() + { + return proxy_.getProperty("P2pPrefChan").onInterface(INTERFACE_NAME); + } + + void P2pPrefChan(const std::string& value) + { + proxy_.setProperty("P2pPrefChan").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pNoGoFreq() + { + return proxy_.getProperty("P2pNoGoFreq").onInterface(INTERFACE_NAME); + } + + void P2pNoGoFreq(const std::string& value) + { + proxy_.setProperty("P2pNoGoFreq").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pAddCliChan() + { + return proxy_.getProperty("P2pAddCliChan").onInterface(INTERFACE_NAME); + } + + void P2pAddCliChan(const std::string& value) + { + proxy_.setProperty("P2pAddCliChan").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pOptimizeListenChan() + { + return proxy_.getProperty("P2pOptimizeListenChan").onInterface(INTERFACE_NAME); + } + + void P2pOptimizeListenChan(const std::string& value) + { + proxy_.setProperty("P2pOptimizeListenChan").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoHt40() + { + return proxy_.getProperty("P2pGoHt40").onInterface(INTERFACE_NAME); + } + + void P2pGoHt40(const std::string& value) + { + proxy_.setProperty("P2pGoHt40").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoVht() + { + return proxy_.getProperty("P2pGoVht").onInterface(INTERFACE_NAME); + } + + void P2pGoVht(const std::string& value) + { + proxy_.setProperty("P2pGoVht").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoHe() + { + return proxy_.getProperty("P2pGoHe").onInterface(INTERFACE_NAME); + } + + void P2pGoHe(const std::string& value) + { + proxy_.setProperty("P2pGoHe").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoEdmg() + { + return proxy_.getProperty("P2pGoEdmg").onInterface(INTERFACE_NAME); + } + + void P2pGoEdmg(const std::string& value) + { + proxy_.setProperty("P2pGoEdmg").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pDisabled() + { + return proxy_.getProperty("P2pDisabled").onInterface(INTERFACE_NAME); + } + + void P2pDisabled(const std::string& value) + { + proxy_.setProperty("P2pDisabled").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoCtwindow() + { + return proxy_.getProperty("P2pGoCtwindow").onInterface(INTERFACE_NAME); + } + + void P2pGoCtwindow(const std::string& value) + { + proxy_.setProperty("P2pGoCtwindow").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pNoGroupIface() + { + return proxy_.getProperty("P2pNoGroupIface").onInterface(INTERFACE_NAME); + } + + void P2pNoGroupIface(const std::string& value) + { + proxy_.setProperty("P2pNoGroupIface").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pIgnoreSharedFreq() + { + return proxy_.getProperty("P2pIgnoreSharedFreq").onInterface(INTERFACE_NAME); + } + + void P2pIgnoreSharedFreq(const std::string& value) + { + proxy_.setProperty("P2pIgnoreSharedFreq").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string IpAddrGo() + { + return proxy_.getProperty("IpAddrGo").onInterface(INTERFACE_NAME); + } + + void IpAddrGo(const std::string& value) + { + proxy_.setProperty("IpAddrGo").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string IpAddrMask() + { + return proxy_.getProperty("IpAddrMask").onInterface(INTERFACE_NAME); + } + + void IpAddrMask(const std::string& value) + { + proxy_.setProperty("IpAddrMask").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string IpAddrStart() + { + return proxy_.getProperty("IpAddrStart").onInterface(INTERFACE_NAME); + } + + void IpAddrStart(const std::string& value) + { + proxy_.setProperty("IpAddrStart").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string IpAddrEnd() + { + return proxy_.getProperty("IpAddrEnd").onInterface(INTERFACE_NAME); + } + + void IpAddrEnd(const std::string& value) + { + proxy_.setProperty("IpAddrEnd").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pCliProbe() + { + return proxy_.getProperty("P2pCliProbe").onInterface(INTERFACE_NAME); + } + + void P2pCliProbe(const std::string& value) + { + proxy_.setProperty("P2pCliProbe").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pDeviceRandomMacAddr() + { + return proxy_.getProperty("P2pDeviceRandomMacAddr").onInterface(INTERFACE_NAME); + } + + void P2pDeviceRandomMacAddr(const std::string& value) + { + proxy_.setProperty("P2pDeviceRandomMacAddr").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pDevicePersistentMacAddr() + { + return proxy_.getProperty("P2pDevicePersistentMacAddr").onInterface(INTERFACE_NAME); + } + + void P2pDevicePersistentMacAddr(const std::string& value) + { + proxy_.setProperty("P2pDevicePersistentMacAddr").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pInterfaceRandomMacAddr() + { + return proxy_.getProperty("P2pInterfaceRandomMacAddr").onInterface(INTERFACE_NAME); + } + + void P2pInterfaceRandomMacAddr(const std::string& value) + { + proxy_.setProperty("P2pInterfaceRandomMacAddr").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2p6ghzDisable() + { + return proxy_.getProperty("P2p6ghzDisable").onInterface(INTERFACE_NAME); + } + + void P2p6ghzDisable(const std::string& value) + { + proxy_.setProperty("P2p6ghzDisable").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string BssMaxCount() + { + return proxy_.getProperty("BssMaxCount").onInterface(INTERFACE_NAME); + } + + void BssMaxCount(const std::string& value) + { + proxy_.setProperty("BssMaxCount").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FilterSsids() + { + return proxy_.getProperty("FilterSsids").onInterface(INTERFACE_NAME); + } + + void FilterSsids(const std::string& value) + { + proxy_.setProperty("FilterSsids").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FilterRssi() + { + return proxy_.getProperty("FilterRssi").onInterface(INTERFACE_NAME); + } + + void FilterRssi(const std::string& value) + { + proxy_.setProperty("FilterRssi").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string MaxNumSta() + { + return proxy_.getProperty("MaxNumSta").onInterface(INTERFACE_NAME); + } + + void MaxNumSta(const std::string& value) + { + proxy_.setProperty("MaxNumSta").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ApIsolate() + { + return proxy_.getProperty("ApIsolate").onInterface(INTERFACE_NAME); + } + + void ApIsolate(const std::string& value) + { + proxy_.setProperty("ApIsolate").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DisassocLowAck() + { + return proxy_.getProperty("DisassocLowAck").onInterface(INTERFACE_NAME); + } + + void DisassocLowAck(const std::string& value) + { + proxy_.setProperty("DisassocLowAck").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Hs20() + { + return proxy_.getProperty("Hs20").onInterface(INTERFACE_NAME); + } + + void Hs20(const std::string& value) + { + proxy_.setProperty("Hs20").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Interworking() + { + return proxy_.getProperty("Interworking").onInterface(INTERFACE_NAME); + } + + void Interworking(const std::string& value) + { + proxy_.setProperty("Interworking").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Hessid() + { + return proxy_.getProperty("Hessid").onInterface(INTERFACE_NAME); + } + + void Hessid(const std::string& value) + { + proxy_.setProperty("Hessid").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string AccessNetworkType() + { + return proxy_.getProperty("AccessNetworkType").onInterface(INTERFACE_NAME); + } + + void AccessNetworkType(const std::string& value) + { + proxy_.setProperty("AccessNetworkType").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GoInterworking() + { + return proxy_.getProperty("GoInterworking").onInterface(INTERFACE_NAME); + } + + void GoInterworking(const std::string& value) + { + proxy_.setProperty("GoInterworking").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GoAccessNetworkType() + { + return proxy_.getProperty("GoAccessNetworkType").onInterface(INTERFACE_NAME); + } + + void GoAccessNetworkType(const std::string& value) + { + proxy_.setProperty("GoAccessNetworkType").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GoInternet() + { + return proxy_.getProperty("GoInternet").onInterface(INTERFACE_NAME); + } + + void GoInternet(const std::string& value) + { + proxy_.setProperty("GoInternet").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GoVenueGroup() + { + return proxy_.getProperty("GoVenueGroup").onInterface(INTERFACE_NAME); + } + + void GoVenueGroup(const std::string& value) + { + proxy_.setProperty("GoVenueGroup").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GoVenueType() + { + return proxy_.getProperty("GoVenueType").onInterface(INTERFACE_NAME); + } + + void GoVenueType(const std::string& value) + { + proxy_.setProperty("GoVenueType").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PbcInM1() + { + return proxy_.getProperty("PbcInM1").onInterface(INTERFACE_NAME); + } + + void PbcInM1(const std::string& value) + { + proxy_.setProperty("PbcInM1").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Autoscan() + { + return proxy_.getProperty("Autoscan").onInterface(INTERFACE_NAME); + } + + void Autoscan(const std::string& value) + { + proxy_.setProperty("Autoscan").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsNfcDevPwId() + { + return proxy_.getProperty("WpsNfcDevPwId").onInterface(INTERFACE_NAME); + } + + void WpsNfcDevPwId(const std::string& value) + { + proxy_.setProperty("WpsNfcDevPwId").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsNfcDhPubkey() + { + return proxy_.getProperty("WpsNfcDhPubkey").onInterface(INTERFACE_NAME); + } + + void WpsNfcDhPubkey(const std::string& value) + { + proxy_.setProperty("WpsNfcDhPubkey").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsNfcDhPrivkey() + { + return proxy_.getProperty("WpsNfcDhPrivkey").onInterface(INTERFACE_NAME); + } + + void WpsNfcDhPrivkey(const std::string& value) + { + proxy_.setProperty("WpsNfcDhPrivkey").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsNfcDevPw() + { + return proxy_.getProperty("WpsNfcDevPw").onInterface(INTERFACE_NAME); + } + + void WpsNfcDevPw(const std::string& value) + { + proxy_.setProperty("WpsNfcDevPw").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ExtPasswordBackend() + { + return proxy_.getProperty("ExtPasswordBackend").onInterface(INTERFACE_NAME); + } + + void ExtPasswordBackend(const std::string& value) + { + proxy_.setProperty("ExtPasswordBackend").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pGoMaxInactivity() + { + return proxy_.getProperty("P2pGoMaxInactivity").onInterface(INTERFACE_NAME); + } + + void P2pGoMaxInactivity(const std::string& value) + { + proxy_.setProperty("P2pGoMaxInactivity").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string AutoInterworking() + { + return proxy_.getProperty("AutoInterworking").onInterface(INTERFACE_NAME); + } + + void AutoInterworking(const std::string& value) + { + proxy_.setProperty("AutoInterworking").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Okc() + { + return proxy_.getProperty("Okc").onInterface(INTERFACE_NAME); + } + + void Okc(const std::string& value) + { + proxy_.setProperty("Okc").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Pmf() + { + return proxy_.getProperty("Pmf").onInterface(INTERFACE_NAME); + } + + void Pmf(const std::string& value) + { + proxy_.setProperty("Pmf").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SaeGroups() + { + return proxy_.getProperty("SaeGroups").onInterface(INTERFACE_NAME); + } + + void SaeGroups(const std::string& value) + { + proxy_.setProperty("SaeGroups").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SaePwe() + { + return proxy_.getProperty("SaePwe").onInterface(INTERFACE_NAME); + } + + void SaePwe(const std::string& value) + { + proxy_.setProperty("SaePwe").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SaePmkidInAssoc() + { + return proxy_.getProperty("SaePmkidInAssoc").onInterface(INTERFACE_NAME); + } + + void SaePmkidInAssoc(const std::string& value) + { + proxy_.setProperty("SaePmkidInAssoc").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DtimPeriod() + { + return proxy_.getProperty("DtimPeriod").onInterface(INTERFACE_NAME); + } + + void DtimPeriod(const std::string& value) + { + proxy_.setProperty("DtimPeriod").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string BeaconInt() + { + return proxy_.getProperty("BeaconInt").onInterface(INTERFACE_NAME); + } + + void BeaconInt(const std::string& value) + { + proxy_.setProperty("BeaconInt").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ApAssocrespElements() + { + return proxy_.getProperty("ApAssocrespElements").onInterface(INTERFACE_NAME); + } + + void ApAssocrespElements(const std::string& value) + { + proxy_.setProperty("ApAssocrespElements").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ApVendorElements() + { + return proxy_.getProperty("ApVendorElements").onInterface(INTERFACE_NAME); + } + + void ApVendorElements(const std::string& value) + { + proxy_.setProperty("ApVendorElements").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string IgnoreOldScanRes() + { + return proxy_.getProperty("IgnoreOldScanRes").onInterface(INTERFACE_NAME); + } + + void IgnoreOldScanRes(const std::string& value) + { + proxy_.setProperty("IgnoreOldScanRes").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FreqList() + { + return proxy_.getProperty("FreqList").onInterface(INTERFACE_NAME); + } + + void FreqList(const std::string& value) + { + proxy_.setProperty("FreqList").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string InitialFreqList() + { + return proxy_.getProperty("InitialFreqList").onInterface(INTERFACE_NAME); + } + + void InitialFreqList(const std::string& value) + { + proxy_.setProperty("InitialFreqList").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ScanCurFreq() + { + return proxy_.getProperty("ScanCurFreq").onInterface(INTERFACE_NAME); + } + + void ScanCurFreq(const std::string& value) + { + proxy_.setProperty("ScanCurFreq").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ScanResValidForConnect() + { + return proxy_.getProperty("ScanResValidForConnect").onInterface(INTERFACE_NAME); + } + + void ScanResValidForConnect(const std::string& value) + { + proxy_.setProperty("ScanResValidForConnect").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SchedScanInterval() + { + return proxy_.getProperty("SchedScanInterval").onInterface(INTERFACE_NAME); + } + + void SchedScanInterval(const std::string& value) + { + proxy_.setProperty("SchedScanInterval").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SchedScanStartDelay() + { + return proxy_.getProperty("SchedScanStartDelay").onInterface(INTERFACE_NAME); + } + + void SchedScanStartDelay(const std::string& value) + { + proxy_.setProperty("SchedScanStartDelay").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string TdlsExternalControl() + { + return proxy_.getProperty("TdlsExternalControl").onInterface(INTERFACE_NAME); + } + + void TdlsExternalControl(const std::string& value) + { + proxy_.setProperty("TdlsExternalControl").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string OsuDir() + { + return proxy_.getProperty("OsuDir").onInterface(INTERFACE_NAME); + } + + void OsuDir(const std::string& value) + { + proxy_.setProperty("OsuDir").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WowlanTriggers() + { + return proxy_.getProperty("WowlanTriggers").onInterface(INTERFACE_NAME); + } + + void WowlanTriggers(const std::string& value) + { + proxy_.setProperty("WowlanTriggers").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string P2pSearchDelay() + { + return proxy_.getProperty("P2pSearchDelay").onInterface(INTERFACE_NAME); + } + + void P2pSearchDelay(const std::string& value) + { + proxy_.setProperty("P2pSearchDelay").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string MacAddr() + { + return proxy_.getProperty("MacAddr").onInterface(INTERFACE_NAME); + } + + void MacAddr(const std::string& value) + { + proxy_.setProperty("MacAddr").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string RandAddrLifetime() + { + return proxy_.getProperty("RandAddrLifetime").onInterface(INTERFACE_NAME); + } + + void RandAddrLifetime(const std::string& value) + { + proxy_.setProperty("RandAddrLifetime").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PreassocMacAddr() + { + return proxy_.getProperty("PreassocMacAddr").onInterface(INTERFACE_NAME); + } + + void PreassocMacAddr(const std::string& value) + { + proxy_.setProperty("PreassocMacAddr").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string KeyMgmtOffload() + { + return proxy_.getProperty("KeyMgmtOffload").onInterface(INTERFACE_NAME); + } + + void KeyMgmtOffload(const std::string& value) + { + proxy_.setProperty("KeyMgmtOffload").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string PassiveScan() + { + return proxy_.getProperty("PassiveScan").onInterface(INTERFACE_NAME); + } + + void PassiveScan(const std::string& value) + { + proxy_.setProperty("PassiveScan").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ReassocSameBssOptim() + { + return proxy_.getProperty("ReassocSameBssOptim").onInterface(INTERFACE_NAME); + } + + void ReassocSameBssOptim(const std::string& value) + { + proxy_.setProperty("ReassocSameBssOptim").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpsPriority() + { + return proxy_.getProperty("WpsPriority").onInterface(INTERFACE_NAME); + } + + void WpsPriority(const std::string& value) + { + proxy_.setProperty("WpsPriority").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FstGroupId() + { + return proxy_.getProperty("FstGroupId").onInterface(INTERFACE_NAME); + } + + void FstGroupId(const std::string& value) + { + proxy_.setProperty("FstGroupId").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FstPriority() + { + return proxy_.getProperty("FstPriority").onInterface(INTERFACE_NAME); + } + + void FstPriority(const std::string& value) + { + proxy_.setProperty("FstPriority").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FstLlt() + { + return proxy_.getProperty("FstLlt").onInterface(INTERFACE_NAME); + } + + void FstLlt(const std::string& value) + { + proxy_.setProperty("FstLlt").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string CertInCb() + { + return proxy_.getProperty("CertInCb").onInterface(INTERFACE_NAME); + } + + void CertInCb(const std::string& value) + { + proxy_.setProperty("CertInCb").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WpaRscRelaxation() + { + return proxy_.getProperty("WpaRscRelaxation").onInterface(INTERFACE_NAME); + } + + void WpaRscRelaxation(const std::string& value) + { + proxy_.setProperty("WpaRscRelaxation").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SchedScanPlans() + { + return proxy_.getProperty("SchedScanPlans").onInterface(INTERFACE_NAME); + } + + void SchedScanPlans(const std::string& value) + { + proxy_.setProperty("SchedScanPlans").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string NonPrefChan() + { + return proxy_.getProperty("NonPrefChan").onInterface(INTERFACE_NAME); + } + + void NonPrefChan(const std::string& value) + { + proxy_.setProperty("NonPrefChan").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string MboCellCapa() + { + return proxy_.getProperty("MboCellCapa").onInterface(INTERFACE_NAME); + } + + void MboCellCapa(const std::string& value) + { + proxy_.setProperty("MboCellCapa").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DisassocImminentRssiThreshold() + { + return proxy_.getProperty("DisassocImminentRssiThreshold").onInterface(INTERFACE_NAME); + } + + void DisassocImminentRssiThreshold(const std::string& value) + { + proxy_.setProperty("DisassocImminentRssiThreshold").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Oce() + { + return proxy_.getProperty("Oce").onInterface(INTERFACE_NAME); + } + + void Oce(const std::string& value) + { + proxy_.setProperty("Oce").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GasAddress3() + { + return proxy_.getProperty("GasAddress3").onInterface(INTERFACE_NAME); + } + + void GasAddress3(const std::string& value) + { + proxy_.setProperty("GasAddress3").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FtmResponder() + { + return proxy_.getProperty("FtmResponder").onInterface(INTERFACE_NAME); + } + + void FtmResponder(const std::string& value) + { + proxy_.setProperty("FtmResponder").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string FtmInitiator() + { + return proxy_.getProperty("FtmInitiator").onInterface(INTERFACE_NAME); + } + + void FtmInitiator(const std::string& value) + { + proxy_.setProperty("FtmInitiator").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GasRandAddrLifetime() + { + return proxy_.getProperty("GasRandAddrLifetime").onInterface(INTERFACE_NAME); + } + + void GasRandAddrLifetime(const std::string& value) + { + proxy_.setProperty("GasRandAddrLifetime").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string GasRandMacAddr() + { + return proxy_.getProperty("GasRandMacAddr").onInterface(INTERFACE_NAME); + } + + void GasRandMacAddr(const std::string& value) + { + proxy_.setProperty("GasRandMacAddr").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DppConfigProcessing() + { + return proxy_.getProperty("DppConfigProcessing").onInterface(INTERFACE_NAME); + } + + void DppConfigProcessing(const std::string& value) + { + proxy_.setProperty("DppConfigProcessing").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DppName() + { + return proxy_.getProperty("DppName").onInterface(INTERFACE_NAME); + } + + void DppName(const std::string& value) + { + proxy_.setProperty("DppName").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DppMudUrl() + { + return proxy_.getProperty("DppMudUrl").onInterface(INTERFACE_NAME); + } + + void DppMudUrl(const std::string& value) + { + proxy_.setProperty("DppMudUrl").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ColocIntfReporting() + { + return proxy_.getProperty("ColocIntfReporting").onInterface(INTERFACE_NAME); + } + + void ColocIntfReporting(const std::string& value) + { + proxy_.setProperty("ColocIntfReporting").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DisableBtm() + { + return proxy_.getProperty("DisableBtm").onInterface(INTERFACE_NAME); + } + + void DisableBtm(const std::string& value) + { + proxy_.setProperty("DisableBtm").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ExtendedKeyId() + { + return proxy_.getProperty("ExtendedKeyId").onInterface(INTERFACE_NAME); + } + + void ExtendedKeyId(const std::string& value) + { + proxy_.setProperty("ExtendedKeyId").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string WowlanDisconnectOnDeinit() + { + return proxy_.getProperty("WowlanDisconnectOnDeinit").onInterface(INTERFACE_NAME); + } + + void WowlanDisconnectOnDeinit(const std::string& value) + { + proxy_.setProperty("WowlanDisconnectOnDeinit").onInterface(INTERFACE_NAME).toValue(value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +namespace fi { +namespace w1 { +namespace wpa_supplicant1 { +namespace Interface { + +class WPS_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "fi.w1.wpa_supplicant1.Interface.WPS"; + +protected: + WPS_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("Event").onInterface(INTERFACE_NAME).call([this](const std::string& name, const std::map& args){ this->onEvent(name, args); }); + proxy_.uponSignal("Credentials").onInterface(INTERFACE_NAME).call([this](const std::map& credentials){ this->onCredentials(credentials); }); + proxy_.uponSignal("PropertiesChanged").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onPropertiesChanged(properties); }); + } + + ~WPS_proxy() = default; + + virtual void onEvent(const std::string& name, const std::map& args) = 0; + virtual void onCredentials(const std::map& credentials) = 0; + virtual void onPropertiesChanged(const std::map& properties) = 0; + +public: + std::map Start(const std::map& args) + { + std::map result; + proxy_.callMethod("Start").onInterface(INTERFACE_NAME).withArguments(args).storeResultsTo(result); + return result; + } + + void Cancel() + { + proxy_.callMethod("Cancel").onInterface(INTERFACE_NAME); + } + +public: + bool ProcessCredentials() + { + return proxy_.getProperty("ProcessCredentials").onInterface(INTERFACE_NAME); + } + + void ProcessCredentials(const bool& value) + { + proxy_.setProperty("ProcessCredentials").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ConfigMethods() + { + return proxy_.getProperty("ConfigMethods").onInterface(INTERFACE_NAME); + } + + void ConfigMethods(const std::string& value) + { + proxy_.setProperty("ConfigMethods").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string DeviceName() + { + return proxy_.getProperty("DeviceName").onInterface(INTERFACE_NAME); + } + + void DeviceName(const std::string& value) + { + proxy_.setProperty("DeviceName").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string Manufacturer() + { + return proxy_.getProperty("Manufacturer").onInterface(INTERFACE_NAME); + } + + void Manufacturer(const std::string& value) + { + proxy_.setProperty("Manufacturer").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ModelName() + { + return proxy_.getProperty("ModelName").onInterface(INTERFACE_NAME); + } + + void ModelName(const std::string& value) + { + proxy_.setProperty("ModelName").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ModelNumber() + { + return proxy_.getProperty("ModelNumber").onInterface(INTERFACE_NAME); + } + + void ModelNumber(const std::string& value) + { + proxy_.setProperty("ModelNumber").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string SerialNumber() + { + return proxy_.getProperty("SerialNumber").onInterface(INTERFACE_NAME); + } + + void SerialNumber(const std::string& value) + { + proxy_.setProperty("SerialNumber").onInterface(INTERFACE_NAME).toValue(value); + } + + std::vector DeviceType() + { + return proxy_.getProperty("DeviceType").onInterface(INTERFACE_NAME); + } + + void DeviceType(const std::vector& value) + { + proxy_.setProperty("DeviceType").onInterface(INTERFACE_NAME).toValue(value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +namespace fi { +namespace w1 { +namespace wpa_supplicant1 { +namespace Interface { + +class P2PDevice_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "fi.w1.wpa_supplicant1.Interface.P2PDevice"; + +protected: + P2PDevice_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("DeviceFound").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onDeviceFound(path); }); + proxy_.uponSignal("DeviceFoundProperties").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const std::map& properties){ this->onDeviceFoundProperties(path, properties); }); + proxy_.uponSignal("DeviceLost").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onDeviceLost(path); }); + proxy_.uponSignal("FindStopped").onInterface(INTERFACE_NAME).call([this](){ this->onFindStopped(); }); + proxy_.uponSignal("ProvisionDiscoveryRequestDisplayPin").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer_object, const std::string& pin){ this->onProvisionDiscoveryRequestDisplayPin(peer_object, pin); }); + proxy_.uponSignal("ProvisionDiscoveryResponseDisplayPin").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer_object, const std::string& pin){ this->onProvisionDiscoveryResponseDisplayPin(peer_object, pin); }); + proxy_.uponSignal("ProvisionDiscoveryRequestEnterPin").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer_object){ this->onProvisionDiscoveryRequestEnterPin(peer_object); }); + proxy_.uponSignal("ProvisionDiscoveryResponseEnterPin").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer_object){ this->onProvisionDiscoveryResponseEnterPin(peer_object); }); + proxy_.uponSignal("ProvisionDiscoveryPBCRequest").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer_object){ this->onProvisionDiscoveryPBCRequest(peer_object); }); + proxy_.uponSignal("ProvisionDiscoveryPBCResponse").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer_object){ this->onProvisionDiscoveryPBCResponse(peer_object); }); + proxy_.uponSignal("ProvisionDiscoveryFailure").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer_object, const int32_t& status){ this->onProvisionDiscoveryFailure(peer_object, status); }); + proxy_.uponSignal("GroupStarted").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onGroupStarted(properties); }); + proxy_.uponSignal("GroupFormationFailure").onInterface(INTERFACE_NAME).call([this](const std::string& reason){ this->onGroupFormationFailure(reason); }); + proxy_.uponSignal("GONegotiationSuccess").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onGONegotiationSuccess(properties); }); + proxy_.uponSignal("GONegotiationFailure").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onGONegotiationFailure(properties); }); + proxy_.uponSignal("GONegotiationRequest").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const uint16_t& dev_passwd_id, const uint8_t& device_go_intent){ this->onGONegotiationRequest(path, dev_passwd_id, device_go_intent); }); + proxy_.uponSignal("InvitationResult").onInterface(INTERFACE_NAME).call([this](const std::map& invite_result){ this->onInvitationResult(invite_result); }); + proxy_.uponSignal("GroupFinished").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onGroupFinished(properties); }); + proxy_.uponSignal("ServiceDiscoveryRequest").onInterface(INTERFACE_NAME).call([this](const std::map& sd_request){ this->onServiceDiscoveryRequest(sd_request); }); + proxy_.uponSignal("ServiceDiscoveryResponse").onInterface(INTERFACE_NAME).call([this](const std::map& sd_response){ this->onServiceDiscoveryResponse(sd_response); }); + proxy_.uponSignal("PersistentGroupAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const std::map& properties){ this->onPersistentGroupAdded(path, properties); }); + proxy_.uponSignal("PersistentGroupRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onPersistentGroupRemoved(path); }); + proxy_.uponSignal("WpsFailed").onInterface(INTERFACE_NAME).call([this](const std::string& name, const std::map& args){ this->onWpsFailed(name, args); }); + proxy_.uponSignal("InvitationReceived").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onInvitationReceived(properties); }); + } + + ~P2PDevice_proxy() = default; + + virtual void onDeviceFound(const sdbus::ObjectPath& path) = 0; + virtual void onDeviceFoundProperties(const sdbus::ObjectPath& path, const std::map& properties) = 0; + virtual void onDeviceLost(const sdbus::ObjectPath& path) = 0; + virtual void onFindStopped() = 0; + virtual void onProvisionDiscoveryRequestDisplayPin(const sdbus::ObjectPath& peer_object, const std::string& pin) = 0; + virtual void onProvisionDiscoveryResponseDisplayPin(const sdbus::ObjectPath& peer_object, const std::string& pin) = 0; + virtual void onProvisionDiscoveryRequestEnterPin(const sdbus::ObjectPath& peer_object) = 0; + virtual void onProvisionDiscoveryResponseEnterPin(const sdbus::ObjectPath& peer_object) = 0; + virtual void onProvisionDiscoveryPBCRequest(const sdbus::ObjectPath& peer_object) = 0; + virtual void onProvisionDiscoveryPBCResponse(const sdbus::ObjectPath& peer_object) = 0; + virtual void onProvisionDiscoveryFailure(const sdbus::ObjectPath& peer_object, const int32_t& status) = 0; + virtual void onGroupStarted(const std::map& properties) = 0; + virtual void onGroupFormationFailure(const std::string& reason) = 0; + virtual void onGONegotiationSuccess(const std::map& properties) = 0; + virtual void onGONegotiationFailure(const std::map& properties) = 0; + virtual void onGONegotiationRequest(const sdbus::ObjectPath& path, const uint16_t& dev_passwd_id, const uint8_t& device_go_intent) = 0; + virtual void onInvitationResult(const std::map& invite_result) = 0; + virtual void onGroupFinished(const std::map& properties) = 0; + virtual void onServiceDiscoveryRequest(const std::map& sd_request) = 0; + virtual void onServiceDiscoveryResponse(const std::map& sd_response) = 0; + virtual void onPersistentGroupAdded(const sdbus::ObjectPath& path, const std::map& properties) = 0; + virtual void onPersistentGroupRemoved(const sdbus::ObjectPath& path) = 0; + virtual void onWpsFailed(const std::string& name, const std::map& args) = 0; + virtual void onInvitationReceived(const std::map& properties) = 0; + +public: + void Find(const std::map& args) + { + proxy_.callMethod("Find").onInterface(INTERFACE_NAME).withArguments(args); + } + + void StopFind() + { + proxy_.callMethod("StopFind").onInterface(INTERFACE_NAME); + } + + void Listen(const int32_t& timeout) + { + proxy_.callMethod("Listen").onInterface(INTERFACE_NAME).withArguments(timeout); + } + + void ExtendedListen(const std::map& args) + { + proxy_.callMethod("ExtendedListen").onInterface(INTERFACE_NAME).withArguments(args); + } + + void PresenceRequest(const std::map& args) + { + proxy_.callMethod("PresenceRequest").onInterface(INTERFACE_NAME).withArguments(args); + } + + void ProvisionDiscoveryRequest(const sdbus::ObjectPath& peer, const std::string& config_method) + { + proxy_.callMethod("ProvisionDiscoveryRequest").onInterface(INTERFACE_NAME).withArguments(peer, config_method); + } + + std::string Connect(const std::map& args) + { + std::string result; + proxy_.callMethod("Connect").onInterface(INTERFACE_NAME).withArguments(args).storeResultsTo(result); + return result; + } + + void GroupAdd(const std::map& args) + { + proxy_.callMethod("GroupAdd").onInterface(INTERFACE_NAME).withArguments(args); + } + + void Cancel() + { + proxy_.callMethod("Cancel").onInterface(INTERFACE_NAME); + } + + void Invite(const std::map& args) + { + proxy_.callMethod("Invite").onInterface(INTERFACE_NAME).withArguments(args); + } + + void Disconnect() + { + proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME); + } + + void RejectPeer(const sdbus::ObjectPath& peer) + { + proxy_.callMethod("RejectPeer").onInterface(INTERFACE_NAME).withArguments(peer); + } + + void RemoveClient(const std::map& args) + { + proxy_.callMethod("RemoveClient").onInterface(INTERFACE_NAME).withArguments(args); + } + + void Flush() + { + proxy_.callMethod("Flush").onInterface(INTERFACE_NAME); + } + + void AddService(const std::map& args) + { + proxy_.callMethod("AddService").onInterface(INTERFACE_NAME).withArguments(args); + } + + void DeleteService(const std::map& args) + { + proxy_.callMethod("DeleteService").onInterface(INTERFACE_NAME).withArguments(args); + } + + void FlushService() + { + proxy_.callMethod("FlushService").onInterface(INTERFACE_NAME); + } + + uint64_t ServiceDiscoveryRequest(const std::map& args) + { + uint64_t result; + proxy_.callMethod("ServiceDiscoveryRequest").onInterface(INTERFACE_NAME).withArguments(args).storeResultsTo(result); + return result; + } + + void ServiceDiscoveryResponse(const std::map& args) + { + proxy_.callMethod("ServiceDiscoveryResponse").onInterface(INTERFACE_NAME).withArguments(args); + } + + void ServiceDiscoveryCancelRequest(const uint64_t& args) + { + proxy_.callMethod("ServiceDiscoveryCancelRequest").onInterface(INTERFACE_NAME).withArguments(args); + } + + void ServiceUpdate() + { + proxy_.callMethod("ServiceUpdate").onInterface(INTERFACE_NAME); + } + + void ServiceDiscoveryExternal(const int32_t& arg) + { + proxy_.callMethod("ServiceDiscoveryExternal").onInterface(INTERFACE_NAME).withArguments(arg); + } + + sdbus::ObjectPath AddPersistentGroup(const std::map& args) + { + sdbus::ObjectPath result; + proxy_.callMethod("AddPersistentGroup").onInterface(INTERFACE_NAME).withArguments(args).storeResultsTo(result); + return result; + } + + void RemovePersistentGroup(const sdbus::ObjectPath& path) + { + proxy_.callMethod("RemovePersistentGroup").onInterface(INTERFACE_NAME).withArguments(path); + } + + void RemoveAllPersistentGroups() + { + proxy_.callMethod("RemoveAllPersistentGroups").onInterface(INTERFACE_NAME); + } + +public: + std::map P2PDeviceConfig() + { + return proxy_.getProperty("P2PDeviceConfig").onInterface(INTERFACE_NAME); + } + + void P2PDeviceConfig(const std::map& value) + { + proxy_.setProperty("P2PDeviceConfig").onInterface(INTERFACE_NAME).toValue(value); + } + + std::vector Peers() + { + return proxy_.getProperty("Peers").onInterface(INTERFACE_NAME); + } + + std::string Role() + { + return proxy_.getProperty("Role").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Group() + { + return proxy_.getProperty("Group").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath PeerGO() + { + return proxy_.getProperty("PeerGO").onInterface(INTERFACE_NAME); + } + + std::vector PersistentGroups() + { + return proxy_.getProperty("PersistentGroups").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +namespace fi { +namespace w1 { +namespace wpa_supplicant1 { + +class PersistentGroup_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "fi.w1.wpa_supplicant1.PersistentGroup"; + +protected: + PersistentGroup_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~PersistentGroup_proxy() = default; + +public: + std::map Properties() + { + return proxy_.getProperty("Properties").onInterface(INTERFACE_NAME); + } + + void Properties(const std::map& value) + { + proxy_.setProperty("Properties").onInterface(INTERFACE_NAME).toValue(value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Peer.hpp b/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Peer.hpp new file mode 100644 index 0000000..0451cf0 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/f1.w1.wpa_supplicant1.Peer.hpp @@ -0,0 +1,120 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_f1_w1_wpa_supplicant1_Peer_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_f1_w1_wpa_supplicant1_Peer_hpp__proxy__H__ + +#include +#include +#include + +namespace fi { +namespace w1 { +namespace wpa_supplicant1 { + +class Peer_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "fi.w1.wpa_supplicant1.Peer"; + +protected: + Peer_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("PropertiesChanged").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onPropertiesChanged(properties); }); + } + + ~Peer_proxy() = default; + + virtual void onPropertiesChanged(const std::map& properties) = 0; + +public: + std::string DeviceName() + { + return proxy_.getProperty("DeviceName").onInterface(INTERFACE_NAME); + } + + std::string Manufacturer() + { + return proxy_.getProperty("Manufacturer").onInterface(INTERFACE_NAME); + } + + std::string ModelName() + { + return proxy_.getProperty("ModelName").onInterface(INTERFACE_NAME); + } + + std::string ModelNumber() + { + return proxy_.getProperty("ModelNumber").onInterface(INTERFACE_NAME); + } + + std::string SerialNumber() + { + return proxy_.getProperty("SerialNumber").onInterface(INTERFACE_NAME); + } + + std::vector PrimaryDeviceType() + { + return proxy_.getProperty("PrimaryDeviceType").onInterface(INTERFACE_NAME); + } + + uint16_t config_method() + { + return proxy_.getProperty("config_method").onInterface(INTERFACE_NAME); + } + + int32_t level() + { + return proxy_.getProperty("level").onInterface(INTERFACE_NAME); + } + + uint8_t devicecapability() + { + return proxy_.getProperty("devicecapability").onInterface(INTERFACE_NAME); + } + + uint8_t groupcapability() + { + return proxy_.getProperty("groupcapability").onInterface(INTERFACE_NAME); + } + + std::vector> SecondaryDeviceTypes() + { + return proxy_.getProperty("SecondaryDeviceTypes").onInterface(INTERFACE_NAME); + } + + std::vector> VendorExtension() + { + return proxy_.getProperty("VendorExtension").onInterface(INTERFACE_NAME); + } + + std::vector IEs() + { + return proxy_.getProperty("IEs").onInterface(INTERFACE_NAME); + } + + std::vector DeviceAddress() + { + return proxy_.getProperty("DeviceAddress").onInterface(INTERFACE_NAME); + } + + std::vector Groups() + { + return proxy_.getProperty("Groups").onInterface(INTERFACE_NAME); + } + + std::vector VSIE() + { + return proxy_.getProperty("VSIE").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/fi.w1.wpa_supplicant1.hpp b/NetworkManagerP2P/src/dbus/hpp/fi.w1.wpa_supplicant1.hpp new file mode 100644 index 0000000..1040eb1 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/fi.w1.wpa_supplicant1.hpp @@ -0,0 +1,123 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_fi_w1_wpa_supplicant1_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_fi_w1_wpa_supplicant1_hpp__proxy__H__ + +#include +#include +#include + +namespace fi { +namespace w1 { + +class wpa_supplicant1_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "fi.w1.wpa_supplicant1"; + +protected: + wpa_supplicant1_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("InterfaceAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path, const std::map& properties){ this->onInterfaceAdded(path, properties); }); + proxy_.uponSignal("InterfaceRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& path){ this->onInterfaceRemoved(path); }); + proxy_.uponSignal("PropertiesChanged").onInterface(INTERFACE_NAME).call([this](const std::map& properties){ this->onPropertiesChanged(properties); }); + } + + ~wpa_supplicant1_proxy() = default; + + virtual void onInterfaceAdded(const sdbus::ObjectPath& path, const std::map& properties) = 0; + virtual void onInterfaceRemoved(const sdbus::ObjectPath& path) = 0; + virtual void onPropertiesChanged(const std::map& properties) = 0; + +public: + sdbus::ObjectPath CreateInterface(const std::map& args) + { + sdbus::ObjectPath result; + proxy_.callMethod("CreateInterface").onInterface(INTERFACE_NAME).withArguments(args).storeResultsTo(result); + return result; + } + + void RemoveInterface(const sdbus::ObjectPath& path) + { + proxy_.callMethod("RemoveInterface").onInterface(INTERFACE_NAME).withArguments(path); + } + + sdbus::ObjectPath GetInterface(const std::string& ifname) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetInterface").onInterface(INTERFACE_NAME).withArguments(ifname).storeResultsTo(result); + return result; + } + + void ExpectDisconnect() + { + proxy_.callMethod("ExpectDisconnect").onInterface(INTERFACE_NAME); + } + +public: + std::string DebugLevel() + { + return proxy_.getProperty("DebugLevel").onInterface(INTERFACE_NAME); + } + + void DebugLevel(const std::string& value) + { + proxy_.setProperty("DebugLevel").onInterface(INTERFACE_NAME).toValue(value); + } + + bool DebugTimestamp() + { + return proxy_.getProperty("DebugTimestamp").onInterface(INTERFACE_NAME); + } + + void DebugTimestamp(const bool& value) + { + proxy_.setProperty("DebugTimestamp").onInterface(INTERFACE_NAME).toValue(value); + } + + bool DebugShowKeys() + { + return proxy_.getProperty("DebugShowKeys").onInterface(INTERFACE_NAME); + } + + void DebugShowKeys(const bool& value) + { + proxy_.setProperty("DebugShowKeys").onInterface(INTERFACE_NAME).toValue(value); + } + + std::vector Interfaces() + { + return proxy_.getProperty("Interfaces").onInterface(INTERFACE_NAME); + } + + std::vector EapMethods() + { + return proxy_.getProperty("EapMethods").onInterface(INTERFACE_NAME); + } + + std::vector Capabilities() + { + return proxy_.getProperty("Capabilities").onInterface(INTERFACE_NAME); + } + + std::vector WFDIEs() + { + return proxy_.getProperty("WFDIEs").onInterface(INTERFACE_NAME); + } + + void WFDIEs(const std::vector& value) + { + proxy_.setProperty("WFDIEs").onInterface(INTERFACE_NAME).toValue(value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.DBus.Properties.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.DBus.Properties.hpp new file mode 100644 index 0000000..4522d8a --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.DBus.Properties.hpp @@ -0,0 +1,56 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_DBus_Properties_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_DBus_Properties_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace DBus { + +class Properties_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties"; + +protected: + Properties_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Properties_proxy() = default; + +public: + sdbus::Variant Get(const std::string& interface, const std::string& propname) + { + sdbus::Variant result; + proxy_.callMethod("Get").onInterface(INTERFACE_NAME).withArguments(interface, propname).storeResultsTo(result); + return result; + } + + std::map GetAll(const std::string& interface) + { + std::map result; + proxy_.callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interface).storeResultsTo(result); + return result; + } + + void Set(const std::string& interface, const std::string& propname, const sdbus::Variant& value) + { + proxy_.callMethod("Set").onInterface(INTERFACE_NAME).withArguments(interface, propname, value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.AccessPoint.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.AccessPoint.hpp new file mode 100644 index 0000000..9cd48ad --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.AccessPoint.hpp @@ -0,0 +1,87 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_AccessPoint_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_AccessPoint_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class AccessPoint_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.AccessPoint"; + +protected: + AccessPoint_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~AccessPoint_proxy() = default; + +public: + uint32_t Flags() + { + return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME); + } + + uint32_t WpaFlags() + { + return proxy_.getProperty("WpaFlags").onInterface(INTERFACE_NAME); + } + + uint32_t RsnFlags() + { + return proxy_.getProperty("RsnFlags").onInterface(INTERFACE_NAME); + } + + std::vector Ssid() + { + return proxy_.getProperty("Ssid").onInterface(INTERFACE_NAME); + } + + uint32_t Frequency() + { + return proxy_.getProperty("Frequency").onInterface(INTERFACE_NAME); + } + + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + uint32_t Mode() + { + return proxy_.getProperty("Mode").onInterface(INTERFACE_NAME); + } + + uint32_t MaxBitrate() + { + return proxy_.getProperty("MaxBitrate").onInterface(INTERFACE_NAME); + } + + uint8_t Strength() + { + return proxy_.getProperty("Strength").onInterface(INTERFACE_NAME); + } + + int32_t LastSeen() + { + return proxy_.getProperty("LastSeen").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.AgentManager.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.AgentManager.hpp new file mode 100644 index 0000000..147f153 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.AgentManager.hpp @@ -0,0 +1,52 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_AgentManager_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_AgentManager_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class AgentManager_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.AgentManager"; + +protected: + AgentManager_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~AgentManager_proxy() = default; + +public: + void Register(const std::string& identifier) + { + proxy_.callMethod("Register").onInterface(INTERFACE_NAME).withArguments(identifier); + } + + void RegisterWithCapabilities(const std::string& identifier, const uint32_t& capabilities) + { + proxy_.callMethod("RegisterWithCapabilities").onInterface(INTERFACE_NAME).withArguments(identifier, capabilities); + } + + void Unregister() + { + proxy_.callMethod("Unregister").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Checkpoint.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Checkpoint.hpp new file mode 100644 index 0000000..7a9915b --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Checkpoint.hpp @@ -0,0 +1,52 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Checkpoint_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Checkpoint_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class Checkpoint_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Checkpoint"; + +protected: + Checkpoint_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Checkpoint_proxy() = default; + +public: + std::vector Devices() + { + return proxy_.getProperty("Devices").onInterface(INTERFACE_NAME); + } + + int64_t Created() + { + return proxy_.getProperty("Created").onInterface(INTERFACE_NAME); + } + + uint32_t RollbackTimeout() + { + return proxy_.getProperty("RollbackTimeout").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Connection.Active.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Connection.Active.hpp new file mode 100644 index 0000000..09b57d2 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Connection.Active.hpp @@ -0,0 +1,126 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Connection_Active_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Connection_Active_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Connection { + +class Active_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Connection.Active"; + +protected: + Active_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const uint32_t& state, const uint32_t& reason){ this->onStateChanged(state, reason); }); + } + + ~Active_proxy() = default; + + virtual void onStateChanged(const uint32_t& state, const uint32_t& reason) = 0; + +public: + sdbus::ObjectPath Connection() + { + return proxy_.getProperty("Connection").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath SpecificObject() + { + return proxy_.getProperty("SpecificObject").onInterface(INTERFACE_NAME); + } + + std::string Id() + { + return proxy_.getProperty("Id").onInterface(INTERFACE_NAME); + } + + std::string Uuid() + { + return proxy_.getProperty("Uuid").onInterface(INTERFACE_NAME); + } + + std::string Type() + { + return proxy_.getProperty("Type").onInterface(INTERFACE_NAME); + } + + std::vector Devices() + { + return proxy_.getProperty("Devices").onInterface(INTERFACE_NAME); + } + + uint32_t State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + + uint32_t StateFlags() + { + return proxy_.getProperty("StateFlags").onInterface(INTERFACE_NAME); + } + + bool Default() + { + return proxy_.getProperty("Default").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Ip4Config() + { + return proxy_.getProperty("Ip4Config").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Dhcp4Config() + { + return proxy_.getProperty("Dhcp4Config").onInterface(INTERFACE_NAME); + } + + bool Default6() + { + return proxy_.getProperty("Default6").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Ip6Config() + { + return proxy_.getProperty("Ip6Config").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Dhcp6Config() + { + return proxy_.getProperty("Dhcp6Config").onInterface(INTERFACE_NAME); + } + + bool Vpn() + { + return proxy_.getProperty("Vpn").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Controller() + { + return proxy_.getProperty("Controller").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Master() + { + return proxy_.getProperty("Master").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DHCP4Config.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DHCP4Config.hpp new file mode 100644 index 0000000..44baae0 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DHCP4Config.hpp @@ -0,0 +1,42 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_DHCP4Config_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_DHCP4Config_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class DHCP4Config_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.DHCP4Config"; + +protected: + DHCP4Config_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~DHCP4Config_proxy() = default; + +public: + std::map Options() + { + return proxy_.getProperty("Options").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DHCP6Config.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DHCP6Config.hpp new file mode 100644 index 0000000..c13839c --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DHCP6Config.hpp @@ -0,0 +1,42 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_DHCP6Config_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_DHCP6Config_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class DHCP6Config_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.DHCP6Config"; + +protected: + DHCP6Config_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~DHCP6Config_proxy() = default; + +public: + std::map Options() + { + return proxy_.getProperty("Options").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Bond.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Bond.hpp new file mode 100644 index 0000000..05c2865 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Bond.hpp @@ -0,0 +1,53 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Bond_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Bond_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Bond_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Bond"; + +protected: + Bond_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Bond_proxy() = default; + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + bool Carrier() + { + return proxy_.getProperty("Carrier").onInterface(INTERFACE_NAME); + } + + std::vector Slaves() + { + return proxy_.getProperty("Slaves").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Dummy.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Dummy.hpp new file mode 100644 index 0000000..6609404 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Dummy.hpp @@ -0,0 +1,43 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Dummy_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Dummy_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Dummy_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Dummy"; + +protected: + Dummy_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Dummy_proxy() = default; + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Generic.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Generic.hpp new file mode 100644 index 0000000..374a607 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Generic.hpp @@ -0,0 +1,48 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Generic_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Generic_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Generic_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Generic"; + +protected: + Generic_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Generic_proxy() = default; + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + std::string TypeDescription() + { + return proxy_.getProperty("TypeDescription").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Loopback.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Loopback.hpp new file mode 100644 index 0000000..e65ebc8 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Loopback.hpp @@ -0,0 +1,37 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Loopback_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Loopback_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Loopback_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Loopback"; + +protected: + Loopback_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Loopback_proxy() = default; + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Modem.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Modem.hpp new file mode 100644 index 0000000..6422bef --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Modem.hpp @@ -0,0 +1,63 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Modem_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Modem_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Modem_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Modem"; + +protected: + Modem_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Modem_proxy() = default; + +public: + uint32_t ModemCapabilities() + { + return proxy_.getProperty("ModemCapabilities").onInterface(INTERFACE_NAME); + } + + uint32_t CurrentCapabilities() + { + return proxy_.getProperty("CurrentCapabilities").onInterface(INTERFACE_NAME); + } + + std::string DeviceId() + { + return proxy_.getProperty("DeviceId").onInterface(INTERFACE_NAME); + } + + std::string OperatorCode() + { + return proxy_.getProperty("OperatorCode").onInterface(INTERFACE_NAME); + } + + std::string Apn() + { + return proxy_.getProperty("Apn").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Statistics.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Statistics.hpp new file mode 100644 index 0000000..6eb0830 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Statistics.hpp @@ -0,0 +1,58 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Statistics_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Statistics_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Statistics_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Statistics"; + +protected: + Statistics_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Statistics_proxy() = default; + +public: + uint32_t RefreshRateMs() + { + return proxy_.getProperty("RefreshRateMs").onInterface(INTERFACE_NAME); + } + + void RefreshRateMs(const uint32_t& value) + { + proxy_.setProperty("RefreshRateMs").onInterface(INTERFACE_NAME).toValue(value); + } + + uint64_t TxBytes() + { + return proxy_.getProperty("TxBytes").onInterface(INTERFACE_NAME); + } + + uint64_t RxBytes() + { + return proxy_.getProperty("RxBytes").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.WifiP2P.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.WifiP2P.hpp new file mode 100644 index 0000000..8ff2ec9 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.WifiP2P.hpp @@ -0,0 +1,64 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_WifiP2P_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_WifiP2P_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class WifiP2P_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.WifiP2P"; + +protected: + WifiP2P_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("PeerAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer){ this->onPeerAdded(peer); }); + proxy_.uponSignal("PeerRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& peer){ this->onPeerRemoved(peer); }); + } + + ~WifiP2P_proxy() = default; + + virtual void onPeerAdded(const sdbus::ObjectPath& peer) = 0; + virtual void onPeerRemoved(const sdbus::ObjectPath& peer) = 0; + +public: + void StartFind(const std::map& options) + { + proxy_.callMethod("StartFind").onInterface(INTERFACE_NAME).withArguments(options); + } + + void StopFind() + { + proxy_.callMethod("StopFind").onInterface(INTERFACE_NAME); + } + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + std::vector Peers() + { + return proxy_.getProperty("Peers").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.WireGuard.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.WireGuard.hpp new file mode 100644 index 0000000..b212030 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.WireGuard.hpp @@ -0,0 +1,53 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_WireGuard_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_WireGuard_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class WireGuard_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.WireGuard"; + +protected: + WireGuard_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~WireGuard_proxy() = default; + +public: + std::vector PublicKey() + { + return proxy_.getProperty("PublicKey").onInterface(INTERFACE_NAME); + } + + uint16_t ListenPort() + { + return proxy_.getProperty("ListenPort").onInterface(INTERFACE_NAME); + } + + uint32_t FwMark() + { + return proxy_.getProperty("FwMark").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wired.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wired.hpp new file mode 100644 index 0000000..df7d5fe --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wired.hpp @@ -0,0 +1,63 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Wired_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Wired_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Wired_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Wired"; + +protected: + Wired_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Wired_proxy() = default; + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + std::string PermHwAddress() + { + return proxy_.getProperty("PermHwAddress").onInterface(INTERFACE_NAME); + } + + uint32_t Speed() + { + return proxy_.getProperty("Speed").onInterface(INTERFACE_NAME); + } + + std::vector S390Subchannels() + { + return proxy_.getProperty("S390Subchannels").onInterface(INTERFACE_NAME); + } + + bool Carrier() + { + return proxy_.getProperty("Carrier").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wireless.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wireless.hpp new file mode 100644 index 0000000..e00de94 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wireless.hpp @@ -0,0 +1,103 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Wireless_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Wireless_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Wireless_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Wireless"; + +protected: + Wireless_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("AccessPointAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& access_point){ this->onAccessPointAdded(access_point); }); + proxy_.uponSignal("AccessPointRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& access_point){ this->onAccessPointRemoved(access_point); }); + } + + ~Wireless_proxy() = default; + + virtual void onAccessPointAdded(const sdbus::ObjectPath& access_point) = 0; + virtual void onAccessPointRemoved(const sdbus::ObjectPath& access_point) = 0; + +public: + std::vector GetAccessPoints() + { + std::vector result; + proxy_.callMethod("GetAccessPoints").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::vector GetAllAccessPoints() + { + std::vector result; + proxy_.callMethod("GetAllAccessPoints").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void RequestScan(const std::map& options) + { + proxy_.callMethod("RequestScan").onInterface(INTERFACE_NAME).withArguments(options); + } + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + std::string PermHwAddress() + { + return proxy_.getProperty("PermHwAddress").onInterface(INTERFACE_NAME); + } + + uint32_t Mode() + { + return proxy_.getProperty("Mode").onInterface(INTERFACE_NAME); + } + + uint32_t Bitrate() + { + return proxy_.getProperty("Bitrate").onInterface(INTERFACE_NAME); + } + + std::vector AccessPoints() + { + return proxy_.getProperty("AccessPoints").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath ActiveAccessPoint() + { + return proxy_.getProperty("ActiveAccessPoint").onInterface(INTERFACE_NAME); + } + + uint32_t WirelessCapabilities() + { + return proxy_.getProperty("WirelessCapabilities").onInterface(INTERFACE_NAME); + } + + int64_t LastScan() + { + return proxy_.getProperty("LastScan").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wpan.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wpan.hpp new file mode 100644 index 0000000..6b1733b --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.Wpan.hpp @@ -0,0 +1,43 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Wpan_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_Wpan_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Device { + +class Wpan_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device.Wpan"; + +protected: + Wpan_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Wpan_proxy() = default; + +public: + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.hpp new file mode 100644 index 0000000..bdb1c90 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Device.hpp @@ -0,0 +1,233 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Device_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class Device_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Device"; + +protected: + Device_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const uint32_t& new_state, const uint32_t& old_state, const uint32_t& reason){ this->onStateChanged(new_state, old_state, reason); }); + } + + ~Device_proxy() = default; + + virtual void onStateChanged(const uint32_t& new_state, const uint32_t& old_state, const uint32_t& reason) = 0; + +public: + void Reapply(const std::map>& connection, const uint64_t& version_id, const uint32_t& flags) + { + proxy_.callMethod("Reapply").onInterface(INTERFACE_NAME).withArguments(connection, version_id, flags); + } + + std::tuple>, uint64_t> GetAppliedConnection(const uint32_t& flags) + { + std::tuple>, uint64_t> result; + proxy_.callMethod("GetAppliedConnection").onInterface(INTERFACE_NAME).withArguments(flags).storeResultsTo(result); + return result; + } + + void Disconnect() + { + proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME); + } + + void Delete() + { + proxy_.callMethod("Delete").onInterface(INTERFACE_NAME); + } + +public: + std::string Udi() + { + return proxy_.getProperty("Udi").onInterface(INTERFACE_NAME); + } + + std::string Path() + { + return proxy_.getProperty("Path").onInterface(INTERFACE_NAME); + } + + std::string Interface() + { + return proxy_.getProperty("Interface").onInterface(INTERFACE_NAME); + } + + std::string IpInterface() + { + return proxy_.getProperty("IpInterface").onInterface(INTERFACE_NAME); + } + + std::string Driver() + { + return proxy_.getProperty("Driver").onInterface(INTERFACE_NAME); + } + + std::string DriverVersion() + { + return proxy_.getProperty("DriverVersion").onInterface(INTERFACE_NAME); + } + + std::string FirmwareVersion() + { + return proxy_.getProperty("FirmwareVersion").onInterface(INTERFACE_NAME); + } + + uint32_t Capabilities() + { + return proxy_.getProperty("Capabilities").onInterface(INTERFACE_NAME); + } + + uint32_t Ip4Address() + { + return proxy_.getProperty("Ip4Address").onInterface(INTERFACE_NAME); + } + + uint32_t State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + + sdbus::Struct StateReason() + { + return proxy_.getProperty("StateReason").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath ActiveConnection() + { + return proxy_.getProperty("ActiveConnection").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Ip4Config() + { + return proxy_.getProperty("Ip4Config").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Dhcp4Config() + { + return proxy_.getProperty("Dhcp4Config").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Ip6Config() + { + return proxy_.getProperty("Ip6Config").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath Dhcp6Config() + { + return proxy_.getProperty("Dhcp6Config").onInterface(INTERFACE_NAME); + } + + bool Managed() + { + return proxy_.getProperty("Managed").onInterface(INTERFACE_NAME); + } + + void Managed(const bool& value) + { + proxy_.setProperty("Managed").onInterface(INTERFACE_NAME).toValue(value); + } + + bool Autoconnect() + { + return proxy_.getProperty("Autoconnect").onInterface(INTERFACE_NAME); + } + + void Autoconnect(const bool& value) + { + proxy_.setProperty("Autoconnect").onInterface(INTERFACE_NAME).toValue(value); + } + + bool FirmwareMissing() + { + return proxy_.getProperty("FirmwareMissing").onInterface(INTERFACE_NAME); + } + + bool NmPluginMissing() + { + return proxy_.getProperty("NmPluginMissing").onInterface(INTERFACE_NAME); + } + + uint32_t DeviceType() + { + return proxy_.getProperty("DeviceType").onInterface(INTERFACE_NAME); + } + + std::vector AvailableConnections() + { + return proxy_.getProperty("AvailableConnections").onInterface(INTERFACE_NAME); + } + + std::string PhysicalPortId() + { + return proxy_.getProperty("PhysicalPortId").onInterface(INTERFACE_NAME); + } + + uint32_t Mtu() + { + return proxy_.getProperty("Mtu").onInterface(INTERFACE_NAME); + } + + uint32_t Metered() + { + return proxy_.getProperty("Metered").onInterface(INTERFACE_NAME); + } + + std::vector> LldpNeighbors() + { + return proxy_.getProperty("LldpNeighbors").onInterface(INTERFACE_NAME); + } + + bool Real() + { + return proxy_.getProperty("Real").onInterface(INTERFACE_NAME); + } + + uint32_t Ip4Connectivity() + { + return proxy_.getProperty("Ip4Connectivity").onInterface(INTERFACE_NAME); + } + + uint32_t Ip6Connectivity() + { + return proxy_.getProperty("Ip6Connectivity").onInterface(INTERFACE_NAME); + } + + uint32_t InterfaceFlags() + { + return proxy_.getProperty("InterfaceFlags").onInterface(INTERFACE_NAME); + } + + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + std::vector Ports() + { + return proxy_.getProperty("Ports").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DnsManager.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DnsManager.hpp new file mode 100644 index 0000000..9cba4bb --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.DnsManager.hpp @@ -0,0 +1,52 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_DnsManager_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_DnsManager_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class DnsManager_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.DnsManager"; + +protected: + DnsManager_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~DnsManager_proxy() = default; + +public: + std::string Mode() + { + return proxy_.getProperty("Mode").onInterface(INTERFACE_NAME); + } + + std::string RcManager() + { + return proxy_.getProperty("RcManager").onInterface(INTERFACE_NAME); + } + + std::vector> Configuration() + { + return proxy_.getProperty("Configuration").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.IP4Config.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.IP4Config.hpp new file mode 100644 index 0000000..7fdd631 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.IP4Config.hpp @@ -0,0 +1,102 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_IP4Config_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_IP4Config_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class IP4Config_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.IP4Config"; + +protected: + IP4Config_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~IP4Config_proxy() = default; + +public: + std::vector> Addresses() + { + return proxy_.getProperty("Addresses").onInterface(INTERFACE_NAME); + } + + std::vector> AddressData() + { + return proxy_.getProperty("AddressData").onInterface(INTERFACE_NAME); + } + + std::string Gateway() + { + return proxy_.getProperty("Gateway").onInterface(INTERFACE_NAME); + } + + std::vector> Routes() + { + return proxy_.getProperty("Routes").onInterface(INTERFACE_NAME); + } + + std::vector> RouteData() + { + return proxy_.getProperty("RouteData").onInterface(INTERFACE_NAME); + } + + std::vector Nameservers() + { + return proxy_.getProperty("Nameservers").onInterface(INTERFACE_NAME); + } + + std::vector> NameserverData() + { + return proxy_.getProperty("NameserverData").onInterface(INTERFACE_NAME); + } + + std::vector Domains() + { + return proxy_.getProperty("Domains").onInterface(INTERFACE_NAME); + } + + std::vector Searches() + { + return proxy_.getProperty("Searches").onInterface(INTERFACE_NAME); + } + + std::vector DnsOptions() + { + return proxy_.getProperty("DnsOptions").onInterface(INTERFACE_NAME); + } + + int32_t DnsPriority() + { + return proxy_.getProperty("DnsPriority").onInterface(INTERFACE_NAME); + } + + std::vector WinsServers() + { + return proxy_.getProperty("WinsServers").onInterface(INTERFACE_NAME); + } + + std::vector WinsServerData() + { + return proxy_.getProperty("WinsServerData").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.IP6Config.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.IP6Config.hpp new file mode 100644 index 0000000..94935fb --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.IP6Config.hpp @@ -0,0 +1,87 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_IP6Config_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_IP6Config_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class IP6Config_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.IP6Config"; + +protected: + IP6Config_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~IP6Config_proxy() = default; + +public: + std::vector, uint32_t, std::vector>> Addresses() + { + return proxy_.getProperty("Addresses").onInterface(INTERFACE_NAME); + } + + std::vector> AddressData() + { + return proxy_.getProperty("AddressData").onInterface(INTERFACE_NAME); + } + + std::string Gateway() + { + return proxy_.getProperty("Gateway").onInterface(INTERFACE_NAME); + } + + std::vector, uint32_t, std::vector, uint32_t>> Routes() + { + return proxy_.getProperty("Routes").onInterface(INTERFACE_NAME); + } + + std::vector> RouteData() + { + return proxy_.getProperty("RouteData").onInterface(INTERFACE_NAME); + } + + std::vector> Nameservers() + { + return proxy_.getProperty("Nameservers").onInterface(INTERFACE_NAME); + } + + std::vector Domains() + { + return proxy_.getProperty("Domains").onInterface(INTERFACE_NAME); + } + + std::vector Searches() + { + return proxy_.getProperty("Searches").onInterface(INTERFACE_NAME); + } + + std::vector DnsOptions() + { + return proxy_.getProperty("DnsOptions").onInterface(INTERFACE_NAME); + } + + int32_t DnsPriority() + { + return proxy_.getProperty("DnsPriority").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.PPP.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.PPP.hpp new file mode 100644 index 0000000..10bd8d7 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.PPP.hpp @@ -0,0 +1,64 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_PPP_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_PPP_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class PPP_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.PPP"; + +protected: + PPP_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~PPP_proxy() = default; + +public: + std::tuple NeedSecrets() + { + std::tuple result; + proxy_.callMethod("NeedSecrets").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SetIp4Config(const std::map& config) + { + proxy_.callMethod("SetIp4Config").onInterface(INTERFACE_NAME).withArguments(config); + } + + void SetIp6Config(const std::map& config) + { + proxy_.callMethod("SetIp6Config").onInterface(INTERFACE_NAME).withArguments(config); + } + + void SetState(const uint32_t& state) + { + proxy_.callMethod("SetState").onInterface(INTERFACE_NAME).withArguments(state); + } + + void SetIfindex(const int32_t& ifindex) + { + proxy_.callMethod("SetIfindex").onInterface(INTERFACE_NAME).withArguments(ifindex); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.SecretAgent.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.SecretAgent.hpp new file mode 100644 index 0000000..7889614 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.SecretAgent.hpp @@ -0,0 +1,59 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_SecretAgent_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_SecretAgent_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class SecretAgent_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.SecretAgent"; + +protected: + SecretAgent_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~SecretAgent_proxy() = default; + +public: + std::map> GetSecrets(const std::map>& connection, const sdbus::ObjectPath& connection_path, const std::string& setting_name, const std::vector& hints, const uint32_t& flags) + { + std::map> result; + proxy_.callMethod("GetSecrets").onInterface(INTERFACE_NAME).withArguments(connection, connection_path, setting_name, hints, flags).storeResultsTo(result); + return result; + } + + void CancelGetSecrets(const sdbus::ObjectPath& connection_path, const std::string& setting_name) + { + proxy_.callMethod("CancelGetSecrets").onInterface(INTERFACE_NAME).withArguments(connection_path, setting_name); + } + + void SaveSecrets(const std::map>& connection, const sdbus::ObjectPath& connection_path) + { + proxy_.callMethod("SaveSecrets").onInterface(INTERFACE_NAME).withArguments(connection, connection_path); + } + + void DeleteSecrets(const std::map>& connection, const sdbus::ObjectPath& connection_path) + { + proxy_.callMethod("DeleteSecrets").onInterface(INTERFACE_NAME).withArguments(connection, connection_path); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Settings.Connection.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Settings.Connection.hpp new file mode 100644 index 0000000..0beb271 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Settings.Connection.hpp @@ -0,0 +1,105 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Settings_Connection_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Settings_Connection_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace Settings { + +class Connection_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Settings.Connection"; + +protected: + Connection_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("Updated").onInterface(INTERFACE_NAME).call([this](){ this->onUpdated(); }); + proxy_.uponSignal("Removed").onInterface(INTERFACE_NAME).call([this](){ this->onRemoved(); }); + } + + ~Connection_proxy() = default; + + virtual void onUpdated() = 0; + virtual void onRemoved() = 0; + +public: + void Update(const std::map>& properties) + { + proxy_.callMethod("Update").onInterface(INTERFACE_NAME).withArguments(properties); + } + + void UpdateUnsaved(const std::map>& properties) + { + proxy_.callMethod("UpdateUnsaved").onInterface(INTERFACE_NAME).withArguments(properties); + } + + void Delete() + { + proxy_.callMethod("Delete").onInterface(INTERFACE_NAME); + } + + std::map> GetSettings() + { + std::map> result; + proxy_.callMethod("GetSettings").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::map> GetSecrets(const std::string& setting_name) + { + std::map> result; + proxy_.callMethod("GetSecrets").onInterface(INTERFACE_NAME).withArguments(setting_name).storeResultsTo(result); + return result; + } + + void ClearSecrets() + { + proxy_.callMethod("ClearSecrets").onInterface(INTERFACE_NAME); + } + + void Save() + { + proxy_.callMethod("Save").onInterface(INTERFACE_NAME); + } + + std::map Update2(const std::map>& settings, const uint32_t& flags, const std::map& args) + { + std::map result; + proxy_.callMethod("Update2").onInterface(INTERFACE_NAME).withArguments(settings, flags, args).storeResultsTo(result); + return result; + } + +public: + bool Unsaved() + { + return proxy_.getProperty("Unsaved").onInterface(INTERFACE_NAME); + } + + uint32_t Flags() + { + return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME); + } + + std::string Filename() + { + return proxy_.getProperty("Filename").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Settings.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Settings.hpp new file mode 100644 index 0000000..1285c17 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.Settings.hpp @@ -0,0 +1,112 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Settings_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_Settings_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class Settings_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.Settings"; + +protected: + Settings_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("NewConnection").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& connection){ this->onNewConnection(connection); }); + proxy_.uponSignal("ConnectionRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& connection){ this->onConnectionRemoved(connection); }); + } + + ~Settings_proxy() = default; + + virtual void onNewConnection(const sdbus::ObjectPath& connection) = 0; + virtual void onConnectionRemoved(const sdbus::ObjectPath& connection) = 0; + +public: + std::vector ListConnections() + { + std::vector result; + proxy_.callMethod("ListConnections").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath GetConnectionByUuid(const std::string& uuid) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetConnectionByUuid").onInterface(INTERFACE_NAME).withArguments(uuid).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath AddConnection(const std::map>& connection) + { + sdbus::ObjectPath result; + proxy_.callMethod("AddConnection").onInterface(INTERFACE_NAME).withArguments(connection).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath AddConnectionUnsaved(const std::map>& connection) + { + sdbus::ObjectPath result; + proxy_.callMethod("AddConnectionUnsaved").onInterface(INTERFACE_NAME).withArguments(connection).storeResultsTo(result); + return result; + } + + std::tuple> AddConnection2(const std::map>& settings, const uint32_t& flags, const std::map& args) + { + std::tuple> result; + proxy_.callMethod("AddConnection2").onInterface(INTERFACE_NAME).withArguments(settings, flags, args).storeResultsTo(result); + return result; + } + + std::tuple> LoadConnections(const std::vector& filenames) + { + std::tuple> result; + proxy_.callMethod("LoadConnections").onInterface(INTERFACE_NAME).withArguments(filenames).storeResultsTo(result); + return result; + } + + bool ReloadConnections() + { + bool result; + proxy_.callMethod("ReloadConnections").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SaveHostname(const std::string& hostname) + { + proxy_.callMethod("SaveHostname").onInterface(INTERFACE_NAME).withArguments(hostname); + } + +public: + std::vector Connections() + { + return proxy_.getProperty("Connections").onInterface(INTERFACE_NAME); + } + + std::string Hostname() + { + return proxy_.getProperty("Hostname").onInterface(INTERFACE_NAME); + } + + bool CanModify() + { + return proxy_.getProperty("CanModify").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.VPN.Connection.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.VPN.Connection.hpp new file mode 100644 index 0000000..c149c2b --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.VPN.Connection.hpp @@ -0,0 +1,51 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_VPN_Connection_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_VPN_Connection_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace VPN { + +class Connection_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.VPN.Connection"; + +protected: + Connection_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("VpnStateChanged").onInterface(INTERFACE_NAME).call([this](const uint32_t& state, const uint32_t& reason){ this->onVpnStateChanged(state, reason); }); + } + + ~Connection_proxy() = default; + + virtual void onVpnStateChanged(const uint32_t& state, const uint32_t& reason) = 0; + +public: + uint32_t VpnState() + { + return proxy_.getProperty("VpnState").onInterface(INTERFACE_NAME); + } + + std::string Banner() + { + return proxy_.getProperty("Banner").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.VPN.Plugin.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.VPN.Plugin.hpp new file mode 100644 index 0000000..e00a275 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.VPN.Plugin.hpp @@ -0,0 +1,106 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_VPN_Plugin_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_VPN_Plugin_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace VPN { + +class Plugin_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.VPN.Plugin"; + +protected: + Plugin_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const uint32_t& state){ this->onStateChanged(state); }); + proxy_.uponSignal("SecretsRequired").onInterface(INTERFACE_NAME).call([this](const std::string& message, const std::vector& secrets){ this->onSecretsRequired(message, secrets); }); + proxy_.uponSignal("Config").onInterface(INTERFACE_NAME).call([this](const std::map& config){ this->onConfig(config); }); + proxy_.uponSignal("Ip4Config").onInterface(INTERFACE_NAME).call([this](const std::map& ip4config){ this->onIp4Config(ip4config); }); + proxy_.uponSignal("Ip6Config").onInterface(INTERFACE_NAME).call([this](const std::map& ip6config){ this->onIp6Config(ip6config); }); + proxy_.uponSignal("LoginBanner").onInterface(INTERFACE_NAME).call([this](const std::string& banner){ this->onLoginBanner(banner); }); + proxy_.uponSignal("Failure").onInterface(INTERFACE_NAME).call([this](const uint32_t& reason){ this->onFailure(reason); }); + } + + ~Plugin_proxy() = default; + + virtual void onStateChanged(const uint32_t& state) = 0; + virtual void onSecretsRequired(const std::string& message, const std::vector& secrets) = 0; + virtual void onConfig(const std::map& config) = 0; + virtual void onIp4Config(const std::map& ip4config) = 0; + virtual void onIp6Config(const std::map& ip6config) = 0; + virtual void onLoginBanner(const std::string& banner) = 0; + virtual void onFailure(const uint32_t& reason) = 0; + +public: + void Connect(const std::map>& connection) + { + proxy_.callMethod("Connect").onInterface(INTERFACE_NAME).withArguments(connection); + } + + void ConnectInteractive(const std::map>& connection, const std::map& details) + { + proxy_.callMethod("ConnectInteractive").onInterface(INTERFACE_NAME).withArguments(connection, details); + } + + std::string NeedSecrets(const std::map>& settings) + { + std::string result; + proxy_.callMethod("NeedSecrets").onInterface(INTERFACE_NAME).withArguments(settings).storeResultsTo(result); + return result; + } + + void Disconnect() + { + proxy_.callMethod("Disconnect").onInterface(INTERFACE_NAME); + } + + void SetConfig(const std::map& config) + { + proxy_.callMethod("SetConfig").onInterface(INTERFACE_NAME).withArguments(config); + } + + void SetIp4Config(const std::map& config) + { + proxy_.callMethod("SetIp4Config").onInterface(INTERFACE_NAME).withArguments(config); + } + + void SetIp6Config(const std::map& config) + { + proxy_.callMethod("SetIp6Config").onInterface(INTERFACE_NAME).withArguments(config); + } + + void SetFailure(const std::string& reason) + { + proxy_.callMethod("SetFailure").onInterface(INTERFACE_NAME).withArguments(reason); + } + + void NewSecrets(const std::map>& connection) + { + proxy_.callMethod("NewSecrets").onInterface(INTERFACE_NAME).withArguments(connection); + } + +public: + uint32_t State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.WiMax.Nsp.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.WiMax.Nsp.hpp new file mode 100644 index 0000000..c652413 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.WiMax.Nsp.hpp @@ -0,0 +1,53 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_WiMax_Nsp_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_WiMax_Nsp_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { +namespace WiMax { + +class Nsp_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.WiMax.Nsp"; + +protected: + Nsp_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~Nsp_proxy() = default; + +public: + std::string Name() + { + return proxy_.getProperty("Name").onInterface(INTERFACE_NAME); + } + + uint32_t SignalQuality() + { + return proxy_.getProperty("SignalQuality").onInterface(INTERFACE_NAME); + } + + uint32_t NetworkType() + { + return proxy_.getProperty("NetworkType").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.WifiP2PPeer.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.WifiP2PPeer.hpp new file mode 100644 index 0000000..80c607c --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.WifiP2PPeer.hpp @@ -0,0 +1,87 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_WifiP2PPeer_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_WifiP2PPeer_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { +namespace NetworkManager { + +class WifiP2PPeer_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager.WifiP2PPeer"; + +protected: + WifiP2PPeer_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + } + + ~WifiP2PPeer_proxy() = default; + +public: + std::string Name() + { + return proxy_.getProperty("Name").onInterface(INTERFACE_NAME); + } + + uint32_t Flags() + { + return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME); + } + + std::string Manufacturer() + { + return proxy_.getProperty("Manufacturer").onInterface(INTERFACE_NAME); + } + + std::string Model() + { + return proxy_.getProperty("Model").onInterface(INTERFACE_NAME); + } + + std::string ModelNumber() + { + return proxy_.getProperty("ModelNumber").onInterface(INTERFACE_NAME); + } + + std::string Serial() + { + return proxy_.getProperty("Serial").onInterface(INTERFACE_NAME); + } + + std::vector WfdIEs() + { + return proxy_.getProperty("WfdIEs").onInterface(INTERFACE_NAME); + } + + std::string HwAddress() + { + return proxy_.getProperty("HwAddress").onInterface(INTERFACE_NAME); + } + + uint8_t Strength() + { + return proxy_.getProperty("Strength").onInterface(INTERFACE_NAME); + } + + int32_t LastSeen() + { + return proxy_.getProperty("LastSeen").onInterface(INTERFACE_NAME); + } + +private: + sdbus::IProxy& proxy_; +}; + +}}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.hpp b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.hpp new file mode 100644 index 0000000..a4e7746 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/hpp/org.freedesktop.NetworkManager.hpp @@ -0,0 +1,320 @@ + +/* + * This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT! + */ + +#ifndef __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_hpp__proxy__H__ +#define __sdbuscpp__dbus_hpp_org_freedesktop_NetworkManager_hpp__proxy__H__ + +#include +#include +#include + +namespace org { +namespace freedesktop { + +class NetworkManager_proxy +{ +public: + static constexpr const char* INTERFACE_NAME = "org.freedesktop.NetworkManager"; + +protected: + NetworkManager_proxy(sdbus::IProxy& proxy) + : proxy_(proxy) + { + proxy_.uponSignal("CheckPermissions").onInterface(INTERFACE_NAME).call([this](){ this->onCheckPermissions(); }); + proxy_.uponSignal("StateChanged").onInterface(INTERFACE_NAME).call([this](const uint32_t& state){ this->onStateChanged(state); }); + proxy_.uponSignal("DeviceAdded").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& device_path){ this->onDeviceAdded(device_path); }); + proxy_.uponSignal("DeviceRemoved").onInterface(INTERFACE_NAME).call([this](const sdbus::ObjectPath& device_path){ this->onDeviceRemoved(device_path); }); + } + + ~NetworkManager_proxy() = default; + + virtual void onCheckPermissions() = 0; + virtual void onStateChanged(const uint32_t& state) = 0; + virtual void onDeviceAdded(const sdbus::ObjectPath& device_path) = 0; + virtual void onDeviceRemoved(const sdbus::ObjectPath& device_path) = 0; + +public: + void Reload(const uint32_t& flags) + { + proxy_.callMethod("Reload").onInterface(INTERFACE_NAME).withArguments(flags); + } + + std::vector GetDevices() + { + std::vector result; + proxy_.callMethod("GetDevices").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + std::vector GetAllDevices() + { + std::vector result; + proxy_.callMethod("GetAllDevices").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath GetDeviceByIpIface(const std::string& iface) + { + sdbus::ObjectPath result; + proxy_.callMethod("GetDeviceByIpIface").onInterface(INTERFACE_NAME).withArguments(iface).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath ActivateConnection(const sdbus::ObjectPath& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object) + { + sdbus::ObjectPath result; + proxy_.callMethod("ActivateConnection").onInterface(INTERFACE_NAME).withArguments(connection, device, specific_object).storeResultsTo(result); + return result; + } + + std::tuple AddAndActivateConnection(const std::map>& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object) + { + std::tuple result; + proxy_.callMethod("AddAndActivateConnection").onInterface(INTERFACE_NAME).withArguments(connection, device, specific_object).storeResultsTo(result); + return result; + } + + std::tuple> AddAndActivateConnection2(const std::map>& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object, const std::map& options) + { + std::tuple> result; + proxy_.callMethod("AddAndActivateConnection2").onInterface(INTERFACE_NAME).withArguments(connection, device, specific_object, options).storeResultsTo(result); + return result; + } + + void DeactivateConnection(const sdbus::ObjectPath& active_connection) + { + proxy_.callMethod("DeactivateConnection").onInterface(INTERFACE_NAME).withArguments(active_connection); + } + + void Sleep(const bool& sleep) + { + proxy_.callMethod("Sleep").onInterface(INTERFACE_NAME).withArguments(sleep); + } + + void Enable(const bool& enable) + { + proxy_.callMethod("Enable").onInterface(INTERFACE_NAME).withArguments(enable); + } + + std::map GetPermissions() + { + std::map result; + proxy_.callMethod("GetPermissions").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + void SetLogging(const std::string& level, const std::string& domains) + { + proxy_.callMethod("SetLogging").onInterface(INTERFACE_NAME).withArguments(level, domains); + } + + std::tuple GetLogging() + { + std::tuple result; + proxy_.callMethod("GetLogging").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + uint32_t CheckConnectivity() + { + uint32_t result; + proxy_.callMethod("CheckConnectivity").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + uint32_t state() + { + uint32_t result; + proxy_.callMethod("state").onInterface(INTERFACE_NAME).storeResultsTo(result); + return result; + } + + sdbus::ObjectPath CheckpointCreate(const std::vector& devices, const uint32_t& rollback_timeout, const uint32_t& flags) + { + sdbus::ObjectPath result; + proxy_.callMethod("CheckpointCreate").onInterface(INTERFACE_NAME).withArguments(devices, rollback_timeout, flags).storeResultsTo(result); + return result; + } + + void CheckpointDestroy(const sdbus::ObjectPath& checkpoint) + { + proxy_.callMethod("CheckpointDestroy").onInterface(INTERFACE_NAME).withArguments(checkpoint); + } + + std::map CheckpointRollback(const sdbus::ObjectPath& checkpoint) + { + std::map result; + proxy_.callMethod("CheckpointRollback").onInterface(INTERFACE_NAME).withArguments(checkpoint).storeResultsTo(result); + return result; + } + + void CheckpointAdjustRollbackTimeout(const sdbus::ObjectPath& checkpoint, const uint32_t& add_timeout) + { + proxy_.callMethod("CheckpointAdjustRollbackTimeout").onInterface(INTERFACE_NAME).withArguments(checkpoint, add_timeout); + } + +public: + std::vector Devices() + { + return proxy_.getProperty("Devices").onInterface(INTERFACE_NAME); + } + + std::vector AllDevices() + { + return proxy_.getProperty("AllDevices").onInterface(INTERFACE_NAME); + } + + std::vector Checkpoints() + { + return proxy_.getProperty("Checkpoints").onInterface(INTERFACE_NAME); + } + + bool NetworkingEnabled() + { + return proxy_.getProperty("NetworkingEnabled").onInterface(INTERFACE_NAME); + } + + bool WirelessEnabled() + { + return proxy_.getProperty("WirelessEnabled").onInterface(INTERFACE_NAME); + } + + void WirelessEnabled(const bool& value) + { + proxy_.setProperty("WirelessEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + bool WirelessHardwareEnabled() + { + return proxy_.getProperty("WirelessHardwareEnabled").onInterface(INTERFACE_NAME); + } + + bool WwanEnabled() + { + return proxy_.getProperty("WwanEnabled").onInterface(INTERFACE_NAME); + } + + void WwanEnabled(const bool& value) + { + proxy_.setProperty("WwanEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + bool WwanHardwareEnabled() + { + return proxy_.getProperty("WwanHardwareEnabled").onInterface(INTERFACE_NAME); + } + + bool WimaxEnabled() + { + return proxy_.getProperty("WimaxEnabled").onInterface(INTERFACE_NAME); + } + + void WimaxEnabled(const bool& value) + { + proxy_.setProperty("WimaxEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + bool WimaxHardwareEnabled() + { + return proxy_.getProperty("WimaxHardwareEnabled").onInterface(INTERFACE_NAME); + } + + uint32_t RadioFlags() + { + return proxy_.getProperty("RadioFlags").onInterface(INTERFACE_NAME); + } + + std::vector ActiveConnections() + { + return proxy_.getProperty("ActiveConnections").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath PrimaryConnection() + { + return proxy_.getProperty("PrimaryConnection").onInterface(INTERFACE_NAME); + } + + std::string PrimaryConnectionType() + { + return proxy_.getProperty("PrimaryConnectionType").onInterface(INTERFACE_NAME); + } + + uint32_t Metered() + { + return proxy_.getProperty("Metered").onInterface(INTERFACE_NAME); + } + + sdbus::ObjectPath ActivatingConnection() + { + return proxy_.getProperty("ActivatingConnection").onInterface(INTERFACE_NAME); + } + + bool Startup() + { + return proxy_.getProperty("Startup").onInterface(INTERFACE_NAME); + } + + std::string Version() + { + return proxy_.getProperty("Version").onInterface(INTERFACE_NAME); + } + + std::vector VersionInfo() + { + return proxy_.getProperty("VersionInfo").onInterface(INTERFACE_NAME); + } + + std::vector Capabilities() + { + return proxy_.getProperty("Capabilities").onInterface(INTERFACE_NAME); + } + + uint32_t State() + { + return proxy_.getProperty("State").onInterface(INTERFACE_NAME); + } + + uint32_t Connectivity() + { + return proxy_.getProperty("Connectivity").onInterface(INTERFACE_NAME); + } + + bool ConnectivityCheckAvailable() + { + return proxy_.getProperty("ConnectivityCheckAvailable").onInterface(INTERFACE_NAME); + } + + bool ConnectivityCheckEnabled() + { + return proxy_.getProperty("ConnectivityCheckEnabled").onInterface(INTERFACE_NAME); + } + + void ConnectivityCheckEnabled(const bool& value) + { + proxy_.setProperty("ConnectivityCheckEnabled").onInterface(INTERFACE_NAME).toValue(value); + } + + std::string ConnectivityCheckUri() + { + return proxy_.getProperty("ConnectivityCheckUri").onInterface(INTERFACE_NAME); + } + + std::map GlobalDnsConfiguration() + { + return proxy_.getProperty("GlobalDnsConfiguration").onInterface(INTERFACE_NAME); + } + + void GlobalDnsConfiguration(const std::map& value) + { + proxy_.setProperty("GlobalDnsConfiguration").onInterface(INTERFACE_NAME).toValue(value); + } + +private: + sdbus::IProxy& proxy_; +}; + +}} // namespaces + +#endif diff --git a/NetworkManagerP2P/src/dbus/server-bindings.xml b/NetworkManagerP2P/src/dbus/server-bindings.xml new file mode 100644 index 0000000..fd0460a --- /dev/null +++ b/NetworkManagerP2P/src/dbus/server-bindings.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Group.xml b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Group.xml new file mode 100644 index 0000000..38d252a --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Group.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Interfaces.xml b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Interfaces.xml new file mode 100644 index 0000000..6430741 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Interfaces.xml @@ -0,0 +1,514 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.P2PGo.xml b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.P2PGo.xml new file mode 100644 index 0000000..a003dcb --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.P2PGo.xml @@ -0,0 +1,32 @@ +('\n' + '\n' + '\n') \ No newline at end of file diff --git a/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Peer.xml b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Peer.xml new file mode 100644 index 0000000..2e1440e --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/f1.w1.wpa_supplicant1.Peer.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/fi.w1.wpa_supplicant1.xml b/NetworkManagerP2P/src/dbus/xml/fi.w1.wpa_supplicant1.xml new file mode 100644 index 0000000..bc64187 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/fi.w1.wpa_supplicant1.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.DBus.Properties.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.DBus.Properties.xml new file mode 100644 index 0000000..d4b398d --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.DBus.Properties.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.AccessPoint.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.AccessPoint.xml new file mode 100644 index 0000000..7340bda --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.AccessPoint.xml @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.AgentManager.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.AgentManager.xml new file mode 100644 index 0000000..66dfea2 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.AgentManager.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Checkpoint.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Checkpoint.xml new file mode 100644 index 0000000..d47407b --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Checkpoint.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Connection.Active.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Connection.Active.xml new file mode 100644 index 0000000..faab73a --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Connection.Active.xml @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DHCP4Config.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DHCP4Config.xml new file mode 100644 index 0000000..ae5c374 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DHCP4Config.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DHCP6Config.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DHCP6Config.xml new file mode 100644 index 0000000..7da61b2 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DHCP6Config.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Bond.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Bond.xml new file mode 100644 index 0000000..34803d1 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Bond.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Dummy.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Dummy.xml new file mode 100644 index 0000000..ccef0b5 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Dummy.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Generic.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Generic.xml new file mode 100644 index 0000000..231b22d --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Generic.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Loopback.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Loopback.xml new file mode 100644 index 0000000..9023633 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Loopback.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Modem.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Modem.xml new file mode 100644 index 0000000..1aa0c83 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Modem.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Statistics.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Statistics.xml new file mode 100644 index 0000000..ab9076c --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Statistics.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.WifiP2P.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.WifiP2P.xml new file mode 100644 index 0000000..73b8cc0 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.WifiP2P.xml @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.WireGuard.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.WireGuard.xml new file mode 100644 index 0000000..b81cae8 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.WireGuard.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wired.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wired.xml new file mode 100644 index 0000000..41ea1c6 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wired.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wireless.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wireless.xml new file mode 100644 index 0000000..c428e99 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wireless.xml @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wpan.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wpan.xml new file mode 100644 index 0000000..f8acde5 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.Wpan.xml @@ -0,0 +1,20 @@ + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.xml new file mode 100644 index 0000000..36f7f5d --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Device.xml @@ -0,0 +1,407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DnsManager.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DnsManager.xml new file mode 100644 index 0000000..702efb8 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.DnsManager.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.IP4Config.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.IP4Config.xml new file mode 100644 index 0000000..f6e18b7 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.IP4Config.xml @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.IP6Config.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.IP6Config.xml new file mode 100644 index 0000000..e47b35f --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.IP6Config.xml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.PPP.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.PPP.xml new file mode 100644 index 0000000..b64414f --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.PPP.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.SecretAgent.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.SecretAgent.xml new file mode 100644 index 0000000..928e39a --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.SecretAgent.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Settings.Connection.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Settings.Connection.xml new file mode 100644 index 0000000..a9240ec --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Settings.Connection.xml @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Settings.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Settings.xml new file mode 100644 index 0000000..ea271df --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.Settings.xml @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.VPN.Connection.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.VPN.Connection.xml new file mode 100644 index 0000000..2167064 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.VPN.Connection.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.VPN.Plugin.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.VPN.Plugin.xml new file mode 100644 index 0000000..b01f7a8 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.VPN.Plugin.xml @@ -0,0 +1,204 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.WiMax.Nsp.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.WiMax.Nsp.xml new file mode 100644 index 0000000..249df7e --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.WiMax.Nsp.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.WifiP2PPeer.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.WifiP2PPeer.xml new file mode 100644 index 0000000..349dc87 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.WifiP2PPeer.xml @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.xml b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.xml new file mode 100644 index 0000000..c92c801 --- /dev/null +++ b/NetworkManagerP2P/src/dbus/xml/org.freedesktop.NetworkManager.xml @@ -0,0 +1,598 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NetworkManagerP2P/src/gen-dbus-imports.sh b/NetworkManagerP2P/src/gen-dbus-imports.sh new file mode 100755 index 0000000..93252fb --- /dev/null +++ b/NetworkManagerP2P/src/gen-dbus-imports.sh @@ -0,0 +1,9 @@ +#!/bin/bash +rm -rf dbus/hpp +# dbus-send --system --type=method_call --print-reply --dest=fi.w1.wpa_supplicant1 /fi/w1/wpa_supplicant1 org.freedesktop.DBus.Introspectable.Introspect +mkdir dbus/hpp +for filename in dbus/xml/*.xml; do + echo $(basename "$filename" .xml) + sdbus-c++-xml2cpp "$filename" --proxy=dbus/hpp/$(basename "$filename" .xml).hpp + +done diff --git a/NetworkManagerP2P/src/main.cpp b/NetworkManagerP2P/src/main.cpp new file mode 100644 index 0000000..c03d137 --- /dev/null +++ b/NetworkManagerP2P/src/main.cpp @@ -0,0 +1,209 @@ + +#include "DBusLog.hpp" +#include "ss.hpp" +#include "CommandLineParser.hpp" +#include "Install.hpp" +#include +#include "Sudo.hpp" +#include +#include + +using namespace std; + +#include "P2PManager.hpp" + +using namespace std; + +static void PrintHelp() +{ + cout << "nm-pipedal-p2p - P2P Manager for NetworkManager network stack." << endl + << "Copyright (c) 2024 Robin Davies." << endl + << endl + << "Provides P2P connections on LINUX distributions that use NetworkManager." << endl + << endl + << "Usage: " << endl + << endl + << " nm-pipedal-p2p [action]" << endl + << " where action is one of" << endl + << endl + << " install Install PiPedal Wi-Fi P2P service." << endl + << " uninstall Uninstall the PiPedal Wi-Fi P2P Services." << endl + << endl + << " If no action is provided, nm-pipedal-p2p runs the service." << endl + << endl + << "Options" << endl + << endl + << " --loglevel trace|debug|info|warning|error" << endl + << " Set the log level" << endl + << " --help, -?" << endl + << " show this message." << endl + << " --systemd" << endl + << " Use systemd logging and notifications." << endl + << endl; +} + +static int RunService(bool underDebugger) +{ + { + try + { + P2PManager::ptr p2pManager = P2PManager::Create(); + if (!p2pManager->Init()) + { + // config files are not correct; message given; indicate to systemd that we don't want a restart. + return EXIT_SUCCESS; + } + char c; + p2pManager->Run(); + + if (underDebugger) + { + char c; + std::cin.get(c); + p2pManager->Stop(); + } + else + { + p2pManager->Wait(); + } + bool reloadRequested = p2pManager->ReloadRequested(); + if (reloadRequested) + { + return EXIT_FAILURE; + } + if (p2pManager->TerminatedNormally()) + { + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + } + catch (const std::exception &e) + { + LogError("P2pManager", "main", e.what()); + sleep(1); + return EXIT_FAILURE; + } + } + + return EXIT_SUCCESS; +} + +static std::map logLevelMap{ + {"trace", DBusLogLevel::Trace}, + {"info", DBusLogLevel::Info}, + {"warning", DBusLogLevel::Warning}, + {"error", DBusLogLevel::Error}, + {"debug", DBusLogLevel::Debug}, +}; + +void SetLogLevel(const std::string &s) +{ + if (logLevelMap.contains(s)) + { + auto level = logLevelMap[s]; + SetDBusLogLevel(level); + } + else + { + throw CommandLineException(SS("Invalid log level: " << s)); + } +} +int main(int argc, char **argv) +{ + // const char *destinationName = "org.freedesktop.NetworkManager"; + // const char *objectPath = "/org/freedesktop/NetworkManager"; + bool help = false; + std::string logLevel = "info"; + std::string logFilePath; + bool underDebugger = false; + bool systemd = false; + bool systemdConsole = false; + bool console = false; + bool logFile = false; + + CommandLineParser commandLine; + commandLine.AddOption("-?", &help); + commandLine.AddOption("--help", &help); + commandLine.AddOption("--loglevel", &logLevel); + commandLine.AddOption("--debug", &underDebugger); // undocumented. wait for getc to shut down, instead of waiting for signals. + commandLine.AddOption("--systemd", &systemd); + commandLine.AddOption("--systemd-console", &systemdConsole); // undocumented. log to both systemd and console. + commandLine.AddOption("--logfile", &logFilePath); + std::string action; + try + { + commandLine.Parse(argc, argv); + if (commandLine.Arguments().size() > 1) + { + throw CommandLineException("Invalid arguments."); + } + if (help) + { + PrintHelp(); + return EXIT_SUCCESS; + } + if (commandLine.Arguments().size() != 0) + { + action = commandLine.Arguments()[0]; + } + + if (!logLevel.empty()) + { + SetLogLevel(logLevel); + } + + if (action.empty()) + { + if (!logFilePath.empty()) + { + SetDBusFileLogger(logFilePath); + } + else if (systemdConsole) + { + SetDBusSystemdLogger(); + AddDBusConsoleLogger(); + } + else if (systemd) + { + SetDBusSystemdLogger(); + } else { + SetDBusConsoleLogger(); + } + if (systemd) + { + sd_notifyf(0, "READY=1\n" + "MAINPID=%u", + (int)getpid()); + } + try + { + return RunService(underDebugger); + } + catch (const exception &e) + { + LogError("", "main", e.what()); + return EXIT_SUCCESS; // i.e. don't ask for a restart. + } + } + throw CommandLineException(SS("Invalid action: " << action)); + } + catch (const std::exception &e) + { + if (!logFilePath.empty()) + { + SetDBusFileLogger(logFilePath); + } + if (systemd) + { + SetDBusSystemdLogger(); + LogError("", "main", e.what()); + return EXIT_FAILURE; + } + else + { + cout << SS("Error: " << e.what()) << std::endl; + return EXIT_FAILURE; + } + } +} diff --git a/src/WifiChannels.hpp b/NetworkManagerP2P/src/ss.hpp similarity index 81% rename from src/WifiChannels.hpp rename to NetworkManagerP2P/src/ss.hpp index d36c236..6b34c10 100644 --- a/src/WifiChannels.hpp +++ b/NetworkManagerP2P/src/ss.hpp @@ -17,19 +17,10 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#pragma once -#include "json.hpp" -namespace pipedal { +#pragma once -class WifiChannel { -public: - std::string channelId_; - std::string channelName_; +#include +#include - DECLARE_JSON_MAP(WifiChannel); -}; - -std::vector getWifiChannels(const char*countryIso3661); - - -} \ No newline at end of file +// usage: SS("xyz" << 123 << 45.6) returning a std::string rvalue. +#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str()) diff --git a/NetworkManagerP2P/src/tmp.txt b/NetworkManagerP2P/src/tmp.txt new file mode 100644 index 0000000..25edba2 --- /dev/null +++ b/NetworkManagerP2P/src/tmp.txt @@ -0,0 +1,6 @@ +method return time=1711400255.798381 sender=:1.5 -> destination=:1.68 serial=210517 reply_serial=2 + string " + + +" diff --git a/NetworkManagerP2P/src/wpa_init b/NetworkManagerP2P/src/wpa_init new file mode 100755 index 0000000..faf8e15 --- /dev/null +++ b/NetworkManagerP2P/src/wpa_init @@ -0,0 +1,17 @@ +wpa_cli -ip2p-dev-wlan0 GET device_name pipedal +wpa_cli -ip2p-dev-wlan0 GET country CA +wpa_cli -ip2p-dev-wlan0 GET device_type 1-0050F204-1 +wpa_cli -ip2p-dev-wlan0 GET persistent_reconnect 1 +wpa_cli -ip2p-dev-wlan0 GET p2p_go_ht40 1 +wpa_cli -ip2p-dev-wlan0 GET update_config 1 +wpa_cli -ip2p-dev-wlan0 GET config_methods keypad +wpa_cli -ip2p-dev-wlan0 GET p2p_go_intent 15 + +wpa_cli -ip2p-dev-wlan0 SET device_name pipedal +wpa_cli -ip2p-dev-wlan0 SET country CA +wpa_cli -ip2p-dev-wlan0 SET device_type 1-0050F204-1 +wpa_cli -ip2p-dev-wlan0 SET persistent_reconnect 1 +wpa_cli -ip2p-dev-wlan0 SET p2p_go_ht40 1 +wpa_cli -ip2p-dev-wlan0 SET update_config 1 +wpa_cli -ip2p-dev-wlan0 SET config_methods keypad +wpa_cli -ip2p-dev-wlan0 SET p2p_go_intent 15 \ No newline at end of file diff --git a/PiPedalCommon/CMakeLists.txt b/PiPedalCommon/CMakeLists.txt new file mode 100644 index 0000000..5cfe6da --- /dev/null +++ b/PiPedalCommon/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory("src") diff --git a/PiPedalCommon/README.md b/PiPedalCommon/README.md new file mode 100644 index 0000000..2fa0437 --- /dev/null +++ b/PiPedalCommon/README.md @@ -0,0 +1,4 @@ +A static library providing common PiPedal code used between projects. + +Most particularly, PiPedalCommon provides code for serializing and deserializing configuration files. + diff --git a/PiPedalCommon/src/CMakeLists.txt b/PiPedalCommon/src/CMakeLists.txt new file mode 100644 index 0000000..b6d34e6 --- /dev/null +++ b/PiPedalCommon/src/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.19.0) + + +# specify the C++ standard +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED True)# apt get lbsdbus-c++-dev + +find_package(sdbus-c++ REQUIRED) + +include(FindPkgConfig) + +set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror") + +if (CMAKE_BUILD_TYPE MATCHES Debug) + message(STATUS "Debug build") + + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -DDEBUG" ) +endif() + +# Can't get the pkg_check to work. +# pkg_check_modules(LIBNL3 "nl-genl-3") +# if(!LIBNL3_FOUND) +# message(ERROR "libnl-genl-3-dev package not installed.") +# else() +# message(STATUS "LIBNL3 libraries: ${LIBNL3_LIBRARIES}") +# message(STATUS "LBNL3 includes: ${LIBNL3_INCLUDE_DIRS}") +# endif() + +# nlgenl-3 library. +execute_process(COMMAND ls /usr/include/libnl3/netlink/netlink.h RESULT_VARIABLE LNL3_MISSING OUTPUT_QUIET ERROR_QUIET) +if(LNL3_MISSING) + message(ERROR " Need to: sudo apt install libnl-3-dev libnl-genl-3-dev ") +endif() +set(LIBNL3_INCLUDE_DIRS /usr/include/libnl3) +set(LIBNL3_LIBRARIES nl-3 nl-genl-3) + + + +message(STATUS "NMPIPEDAL CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") + + +# Use the sdbus-c++ target in SDBusCpp namespace +add_library(PiPedalCommon STATIC + ConfigSerializer.cpp include/ConfigSerializer.hpp + WifiRegs.cpp include/WifiRegs.hpp + WifiRegulations.cpp include/WifiRegulations.hpp + WifiDirectConfigSettings.cpp include/WifiDirectConfigSettings.hpp + WifiConfigSettings.cpp include/WifiConfigSettings.hpp + ServiceConfiguration.cpp include/ServiceConfiguration.hpp + WriteTemplateFile.cpp include/WriteTemplateFile.hpp + #NetLinkChannelInfo.cpp include/NetLinkChannelInfo.hpp + ChannelInfo.cpp include/ChannelInfo.hpp + HtmlHelper.cpp include/HtmlHelper.hpp + RegDb.cpp include/RegDb.hpp + ConfigUtil.cpp include/ConfigUtil.hpp + SysExec.cpp include/SysExec.hpp + util.cpp include/util.hpp + json.cpp include/json.hpp + + json_variant.cpp include/json_variant.hpp + include/autoptr_vector.h + + include/P2pConfigFiles.hpp + + ss.hpp +) +target_include_directories(PiPedalCommon PUBLIC "include" ${LIBNL3_INCLUDE_DIRS}) +target_link_libraries(PiPedalCommon PUBLIC ${LIBNL3_LIBRARIES} ) + + + diff --git a/PiPedalCommon/src/ChannelInfo.cpp b/PiPedalCommon/src/ChannelInfo.cpp new file mode 100644 index 0000000..dffbe1f --- /dev/null +++ b/PiPedalCommon/src/ChannelInfo.cpp @@ -0,0 +1,370 @@ +#include "ChannelInfo.hpp" +#include "WifiRegulations.hpp" +#include "RegDb.hpp" +#include +#include +#include "ss.hpp" + +using namespace pipedal; + +// To do: no support for ac 80GHz channels (which pi supports). +// Wifi 6 ax channels are explicitly disabled (pi doesn't support them). + + +struct OpClassChannels +{ + WifiMode band; + int32_t regDomain; + int32_t firstChannel; + int32_t lastChannel; + int32_t increment; + WifiBandwidth bandwidth; + bool p2p_support; +}; +// from wpa_supplicant. +static std::vector opClasses = { + {WifiMode::IEEE80211G, 81, 1, 13, 1, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211G, 82, 14, 14, 1, WifiBandwidth::BW20, false}, + + /* Do not enable HT40 on 2.4 GHz for P2P use for now */ + {WifiMode::IEEE80211G, 83, 1, 9, 1, WifiBandwidth::BW40PLUS, false}, + {WifiMode::IEEE80211G, 84, 5, 13, 1, WifiBandwidth::BW40MINUS, false}, + + {WifiMode::IEEE80211A, 115, 36, 48, 4, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211A, 116, 36, 44, 8, WifiBandwidth::BW40PLUS, true}, + {WifiMode::IEEE80211A, 117, 40, 48, 8, WifiBandwidth::BW40MINUS, true}, + {WifiMode::IEEE80211A, 118, 52, 64, 4, WifiBandwidth::BW20, false}, + {WifiMode::IEEE80211A, 119, 52, 60, 8, WifiBandwidth::BW40PLUS, false}, + {WifiMode::IEEE80211A, 120, 56, 64, 8, WifiBandwidth::BW40MINUS, false}, + {WifiMode::IEEE80211A, 121, 100, 140, 4, WifiBandwidth::BW20, false}, + {WifiMode::IEEE80211A, 122, 100, 132, 8, WifiBandwidth::BW40PLUS, false}, + {WifiMode::IEEE80211A, 123, 104, 136, 8, WifiBandwidth::BW40MINUS, false}, + {WifiMode::IEEE80211A, 124, 149, 161, 4, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211A, 125, 149, 177, 4, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211A, 126, 149, 173, 8, WifiBandwidth::BW40PLUS, true}, + {WifiMode::IEEE80211A, 127, 153, 177, 8, WifiBandwidth::BW40MINUS, true}, + + /* + * IEEE P802.11ax/D8.0 (WIFI 6)Table E-4 actually talks about channel center + * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing + * of 80 MHz, but currently use the following definition for simplicity + * (these center frequencies are not actual channels, which makes + * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take + * care of removing invalid channels. + */ + + // WiFi 5. + // {WifiMode::IEEE80211A, 128, 36, 177, 4, WifiBandwidth::BW80, true}, + // {WifiMode::IEEE80211A, 129, 36, 177, 4, WifiBandwidth::BW160, true}, + // {WifiMode::IEEE80211A, 130, 36, 177, 4, WifiBandwidth::BW80P80, true}, + + // WiFi 6. + // {WifiMode::IEEE80211AX, 131, 1, 233, 4, WifiBandwidth::BW20, true}, + // {WifiMode::IEEE80211AX, 132, 1, 233, 8, WifiBandwidth::BW40PLUS, true}, + // {WifiMode::IEEE80211AX, 133, 1, 233, 16, WifiBandwidth::BW80, true}, + // {WifiMode::IEEE80211AX, 134, 1, 233, 32, WifiBandwidth::BW160, true}, + // {WifiMode::IEEE80211AX, 135, 1, 233, 16, WifiBandwidth::BW80P80, false}, + // {WifiMode::IEEE80211AX, 136, 2, 2, 4, WifiBandwidth::BW20, false}, + + + /* IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes. + * Class 180 has the legacy channels 1-6. Classes 181-183 include + * channels which implement channel bonding features. + */ + // {WifiMode::IEEE80211AD, 180, 1, 6, 1, WifiBandwidth::BW2160, true}, + // {WifiMode::IEEE80211AD, 181, 9, 13, 1, WifiBandwidth::BW4320, true}, + // {WifiMode::IEEE80211AD, 182, 17, 20, 1, WifiBandwidth::BW6480, true}, + // {WifiMode::IEEE80211AD, 183, 25, 27, 1, WifiBandwidth::BW8640, true}, + +}; + +static int32_t ChannelToFrequency(int32_t channel) +{ + if (channel >= 1 && channel <= 13) + { + return 2412 + (channel - 1) * 5; + } + if (channel == 14) + { + return 2484; + } + if (channel >= 36 && channel <= 165) + { + return 5180 + (channel - 36) * 5; + } + return -1; +} +static bool BandwidthPermitted(int32_t frequency,WifiBandwidth bandwidth, const WifiRule &rule) +{ + int32_t channelWidth = -1; + switch (bandwidth) + { + case WifiBandwidth::BW20: + channelWidth = 20; + break; + case WifiBandwidth::BW40PLUS: + channelWidth = 40; + if (rule.HasFlag(RegRuleFlags::NO_HT40PLUS)) + return false; + break; + case WifiBandwidth::BW40MINUS: + if (rule.HasFlag(RegRuleFlags::NO_HT40MINUS)) + return false; + channelWidth = 40; + break; + case WifiBandwidth::BW40: // wifi 6 only. do NOT use for a/g channels. + channelWidth = 40; + break; + case WifiBandwidth::BW80: + if (rule.HasFlag(RegRuleFlags::NO_80MHZ)) + return false; + channelWidth = 80; + break; + case WifiBandwidth::BW160: + if (rule.HasFlag(RegRuleFlags::NO_160MHZ)) + return false; + channelWidth = 160; + break; + case WifiBandwidth::BW80P80: + if (rule.HasFlag(RegRuleFlags::NO_160MHZ)) + return false; + channelWidth = 160; + break; + case WifiBandwidth::BW2160: + channelWidth = 2160; + break; + case WifiBandwidth::BW4320: + channelWidth = 4320; + break; + case WifiBandwidth::BW6480: + channelWidth = 6480; + break; + case WifiBandwidth::BW8640: + channelWidth = 8640; + break; + + default: + return false; + } + if (channelWidth * 1000 > rule.max_bandwidth_khz) + { + return false; + } + int32_t minFrequency = frequency-channelWidth/2; + int32_t maxFrequency = minFrequency+channelWidth; + if (bandwidth == WifiBandwidth::BW40PLUS) + { + minFrequency = frequency-channelWidth/4; + maxFrequency = minFrequency+channelWidth; + } else if (bandwidth == WifiBandwidth::BW40MINUS) + { + maxFrequency = frequency+channelWidth/4; + minFrequency = maxFrequency-channelWidth; + } + if (minFrequency*1000 < rule.start_freq_khz || maxFrequency*1000 > rule.end_freq_khz) + { + return false; + } + return true; +} + +WifiInfo pipedal::getWifiInfo(const std::string&countryIso3661) +{ + const RegDb ®Db = RegDb::GetInstance(); + const WifiRegulations ®ulations = regDb.getWifiRegulations(countryIso3661); + + WifiInfo info; + info.reg_alpha2 = regulations.reg_alpha2; + info.dfsRegion = regulations.dfs_region; + + + for (const auto &classMap : opClasses) + { + if (!classMap.p2p_support) + { + continue; + } + if (classMap.band != WifiMode::IEEE80211A && classMap.band != WifiMode::IEEE80211G) + { + continue; + } + for (auto channel = classMap.firstChannel; channel <= classMap.lastChannel; channel += classMap.increment) + { + if (!classMap.p2p_support) + continue; + + int32_t frequency = ChannelToFrequency(channel); + if (frequency == -1) + continue; + + const auto *rule = regulations.GetRule(frequency); + if (!rule) + continue; + + if (rule->HasFlag( + RegRuleFlags::NO_IR | RegRuleFlags::DFS | RegRuleFlags::PTP_ONLY | RegRuleFlags::PTMP_ONLY)) + { + continue; + } + if (rule->HasFlag(RegRuleFlags::DFS)) + { + continue; + } + + WifiBandwidth bandwidth = classMap.bandwidth; + if (!BandwidthPermitted(frequency,bandwidth, *rule)) + { + continue; + } + + WifiChannelInfo channelInfo; + channelInfo.channelNumber = channel; + channelInfo.hardwareMode = classMap.band; + channelInfo.disabled = false; + channelInfo.indoorOnly = rule->HasFlag(RegRuleFlags::NO_OUTDOOR); + channelInfo.outdoorsOnly = rule->HasFlag(RegRuleFlags::NO_INDOOR); + channelInfo.no10MHz = rule->max_bandwidth_khz < 10 * 1000; + channelInfo.no20MHz = rule->max_bandwidth_khz < 20 * 1000; + channelInfo.no80MHz = rule->max_bandwidth_khz < 80 * 1000; + channelInfo.noHt40Minus = rule->max_bandwidth_khz < 40 * 1000 || rule->HasFlag(RegRuleFlags::NO_HT40MINUS); + channelInfo.noHt40Plus = rule->max_bandwidth_khz < 40 * 1000 || rule->HasFlag(RegRuleFlags::NO_HT40PLUS); + + channelInfo.mhz = frequency; + channelInfo.no10MHz = rule->HasFlag(RegRuleFlags::NO_IR); + channelInfo.regDomain = classMap.regDomain; + channelInfo.maxAntennaGain = rule->max_antenna_gain; + channelInfo.maxEirp = rule->max_eirp; + channelInfo.bandwidth = bandwidth; + + info.channels.push_back(std::move(channelInfo)); + } + } + return info; +} + + +std::vector pipedal::getValidChannels(const std::string&countryIso3661,int32_t maxChannelWidthMhz) +{ + std::set channels; + + + WifiBandwidth maxBandwidth; + if (maxChannelWidthMhz <= 20) + { + maxBandwidth = WifiBandwidth::BW20; + } else if (maxChannelWidthMhz <= 40) + { + maxBandwidth = WifiBandwidth::BW40; + } else if (maxChannelWidthMhz <= 80) + { + maxBandwidth = WifiBandwidth::BW80; + } else // if (maxChannelWidthMhz <= 160) + { + maxBandwidth = WifiBandwidth::BW160; + } + RegDb ®Db = RegDb::GetInstance(); + auto info = pipedal::getWifiInfo(countryIso3661); + + for (const auto&channelInfo: info.channels) + { + channels.insert(channelInfo.channelNumber); + } + + + std::vector result; + result.reserve(channels.size()); + for (auto v : channels) + { + result.push_back(v); + } + std::sort(result.begin(),result.end()); + return result; +} +int32_t pipedal::getWifiRegClass(const std::string &countryIso3661, int32_t channel, int32_t maxChannelWidthMhz) +{ + WifiBandwidth maxBandwidth; + if (maxChannelWidthMhz <= 20) + { + maxBandwidth = WifiBandwidth::BW20; + } else if (maxChannelWidthMhz <= 40) + { + maxBandwidth = WifiBandwidth::BW40; + } else if (maxChannelWidthMhz <= 80) + { + maxBandwidth = WifiBandwidth::BW80; + } else // if (maxChannelWidthMhz <= 160) + { + maxBandwidth = WifiBandwidth::BW160; + } + RegDb ®Db = RegDb::GetInstance(); + auto info = pipedal::getWifiInfo(countryIso3661); + + const WifiChannelInfo *bestChannel = nullptr; + for (const auto&channelInfo: info.channels) + { + if (channelInfo.channelNumber == channel && channelInfo.bandwidth <= maxBandwidth) + { + if (bestChannel == nullptr || bestChannel->bandwidth < channelInfo.bandwidth) + { + bestChannel = &channelInfo; + } + + } + } + if (bestChannel) + { + if (channel >= 1 && channel <= 13) { // alway 20Ghz. + return 81; + } + return bestChannel->regDomain; + } + std::vector valid_channels; + try { + valid_channels = getValidChannels(countryIso3661,40); + } + catch (const std::exception& /**/) + { + std::stringstream ss; + ss << "Channel " << channel << " is not permitted in the country " << countryIso3661 << "."; + throw std::runtime_error(ss.str()); + + } + + { + std::stringstream ss; + ss << "Channel " << channel << " is not permitted in the country " << countryIso3661 << ". Permitted channels:\n "; + bool first = true; + for (auto channel: valid_channels) + { + if (!first) ss << ", "; + first = false; + ss << channel; + } + ss << "."; + throw std::runtime_error(ss.str()); + } + + + // Hard-coded values lifted from wpa_supplicant sources. I don't really think it respect the regulatory db. + + /* Operating class 81 - 2.4 GHz band channels 1..13 */ + // int32_t regClass = -1; + // if (channel >= 1 && channel <= 11) + // { + // regClass = 81; + // } + // // lower 5 GHZ. + // if (channel == 36 || channel == 40 || channel == 44 || channel == 48) + // { + // regClass = 115; // 20 Ghz + // } + // if (channel == 149 || channel == 153 || channel == 157 || channel == 161) + // { + // regClass = 124; // 20Ghz nomadic. + // } + // if (regClass == -1) + // { + // return -1; + // } +} + diff --git a/src/ConfigSerializer.cpp b/PiPedalCommon/src/ConfigSerializer.cpp similarity index 99% rename from src/ConfigSerializer.cpp rename to PiPedalCommon/src/ConfigSerializer.cpp index d5bcfdf..fb2ee54 100644 --- a/src/ConfigSerializer.cpp +++ b/PiPedalCommon/src/ConfigSerializer.cpp @@ -22,7 +22,7 @@ * SOFTWARE. */ -#include "ConfigSerializer.h" +#include "ConfigSerializer.hpp" using namespace config_serializer; diff --git a/src/ConfigUtil.cpp b/PiPedalCommon/src/ConfigUtil.cpp similarity index 100% rename from src/ConfigUtil.cpp rename to PiPedalCommon/src/ConfigUtil.cpp diff --git a/src/HtmlHelper.cpp b/PiPedalCommon/src/HtmlHelper.cpp similarity index 99% rename from src/HtmlHelper.cpp rename to PiPedalCommon/src/HtmlHelper.cpp index 89057ef..ac7c218 100644 --- a/src/HtmlHelper.cpp +++ b/PiPedalCommon/src/HtmlHelper.cpp @@ -17,7 +17,6 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "pch.h" #include "HtmlHelper.hpp" #include #include diff --git a/PiPedalCommon/src/NetLinkChannelInfo.cpp b/PiPedalCommon/src/NetLinkChannelInfo.cpp new file mode 100644 index 0000000..7d24513 --- /dev/null +++ b/PiPedalCommon/src/NetLinkChannelInfo.cpp @@ -0,0 +1,1148 @@ +/* +Copyright (c) 2007, 2008 Johannes Berg +Copyright (c) 2007 Andy Lutomirski +Copyright (c) 2007 Mike Kershaw +Copyright (c) 2008 Luis R. Rodriguez +Copyright (c) 2024 Robin Davies +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ +/* + Heavily based on code borrowed from iw (1) command. + https://kernel.googlesource.com/pub/scm/linux/kernel/git/jberg/iw/+/v0.9/COPYING +*/ + +// code lifed from WPA_SUPPLICANT +/* +Copyright (c) 2002-2019, Jouni Malinen + +This software may be distributed, used, and modified under the terms of +BSD license: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "NetLinkChannelInfo.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ss.hpp" + +using namespace pipedal; + +namespace pipedal::impl +{ + class NetLink + { + private: + bool responseReceived = false; + bool ackReceived = false; + WifiInfo info; + WifiRegulations regulations; + nl_sock *socket = nullptr; + nl_cache *cache = nullptr; + genl_family *nl80211 = nullptr; + + int errorCode = -1; + + static int finish_handler(struct nl_msg *msg, void *arg); + static int ack_handler(struct nl_msg *msg, void *arg); + + static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, + void *arg); + + static int info_handler(struct nl_msg *msg, void *arg); + static int reg_handler(struct nl_msg *msg, void *arg); + int InfoHandler(struct nl_msg *msg); + int RegHandler(struct nl_msg *msg); + + public: + ~NetLink(); + NetLink(); + + WifiInfo GetAvailableChannels(const char *phyName, const char *countryregode); + WifiRegulations GetRegulations(const char *phyName, const char *countryCode); + }; + +} + +using namespace pipedal::impl; + + +struct ChannelInfo +{ + int32_t freq; + WifiBandwidth chanWidth; + SecondaryChannelLocation secondaryChannelLocation; + int32_t op_class; + int32_t channel; + WifiMode hardwareMode; +}; + +bool ieeeChannelInfo(unsigned int freq, + WifiBandwidth chanwidth, + ChannelInfo *channelInfo); + +struct NlMHzToChannel +{ + char band; + int channel; + int mhz; +}; + +static std::vector mhzToChannels = { + {'g', 1, 2412}, + {'g', 2, 2417}, + {'g', 3, 2422}, + {'g', 4, 2427}, + {'g', 5, 2432}, + {'g', 6, 2437}, + {'g', 7, 2442}, + {'g', 8, 2447}, + {'g', 9, 2452}, + {'g', 10, 2457}, + {'g', 11, 2462}, + {'g', 12, 2467}, + {'g', 13, 2472}, + {'g', 14, 2484}, + {'a', 7, 5035}, + {'a', 8, 5040}, + {'a', 9, 5045}, + {'a', 11, 5055}, + {'a', 12, 5060}, + {'a', 16, 5080}, + {'a', 32, 5160}, + {'a', 34, 5170}, + {'a', 36, 5180}, + {'a', 38, 5190}, + {'a', 40, 5200}, + {'a', 42, 5210}, + {'a', 44, 5220}, + {'a', 46, 5230}, + {'a', 48, 5240}, + {'a', 50, 5250}, + {'a', 52, 5260}, + {'a', 54, 5270}, + {'a', 56, 5280}, + {'a', 58, 5290}, + {'a', 60, 5300}, + {'a', 62, 5310}, + {'a', 64, 5320}, + {'a', 68, 5340}, + {'a', 96, 5480}, + {'a', 100, 5500}, + {'a', 102, 5510}, + {'a', 104, 5520}, + {'a', 106, 5530}, + {'a', 108, 5540}, + {'a', 110, 5550}, + {'a', 112, 5560}, + {'a', 114, 5570}, + {'a', 116, 5580}, + {'a', 118, 5590}, + {'a', 120, 5600}, + {'a', 122, 5610}, + {'a', 124, 5620}, + {'a', 126, 5630}, + {'a', 128, 5640}, + {'a', 132, 5660}, + {'a', 134, 5670}, + {'a', 136, 5680}, + {'a', 138, 5690}, + {'a', 140, 5700}, + {'a', 142, 5710}, + {'a', 144, 5720}, + {'a', 149, 5745}, + {'a', 151, 5755}, + {'a', 153, 5765}, + {'a', 155, 5775}, + {'a', 157, 5785}, + {'a', 159, 5795}, + {'a', 161, 5805}, + {'a', 163, 5815}, + {'a', 165, 5825}, + {'a', 167, 5835}, + {'a', 169, 5845}, + {'a', 171, 5855}, + {'a', 173, 5865}, + {'a', 175, 5875}, + {'a', 177, 5885}, + {'a', 180, 5900}, + {'a', 182, 5910}, + {'a', 183, 5915}, + {'a', 184, 5920}, + {'a', 187, 5935}, + {'a', 188, 5940}, + {'a', 189, 5945}, + {'a', 192, 5960}, + {'a', 196, 5980}, +}; + +static bool MHzToChannelNumber(int mhz, char *pBand, int *pChannel) +{ + for (size_t i = 0; i < mhzToChannels.size(); ++i) + { + if (std::abs(mhz - mhzToChannels[i].mhz) <= 1) + { + *pBand = mhzToChannels[i].band; + *pChannel = mhzToChannels[i].channel; + return true; + } + } + return false; +} + +static nla_policy *makeFreqPolicy() +{ + nla_policy *result = new nla_policy[NL80211_FREQUENCY_ATTR_MAX + 1]; + memset(result, 0, sizeof(nla_policy[NL80211_FREQUENCY_ATTR_MAX + 1])); + + result[NL80211_FREQUENCY_ATTR_FREQ] = {NLA_U32, 0, 0}; + result[NL80211_FREQUENCY_ATTR_DISABLED] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_IR] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_RADAR] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_INDOOR_ONLY] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_INDOOR_ONLY] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_20MHZ] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_20MHZ] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_80MHZ] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_160MHZ] = {NLA_FLAG, 0, 0}; + return result; +} + +static struct nla_policy *freq_policy = makeFreqPolicy(); + +static nla_policy *makeRatePolicy() +{ + nla_policy *result = new nla_policy[NL80211_BITRATE_ATTR_MAX + 1]; + memset(result, 0, sizeof(nla_policy[NL80211_BITRATE_ATTR_MAX + 1])); + result[NL80211_BITRATE_ATTR_RATE] = {.type = NLA_U32}; + result[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = {.type = NLA_FLAG}; + return result; +}; + +static struct nla_policy *rate_policy = makeRatePolicy(); + +struct IfType +{ + enum nl80211_iftype iftype; + const char *name; +}; +static struct IfType ifTypes[] = { + {NL80211_IFTYPE_UNSPECIFIED, "Unspecified"}, + {NL80211_IFTYPE_ADHOC, "Adhoc"}, + {NL80211_IFTYPE_STATION, "Station"}, + {NL80211_IFTYPE_AP, "AP"}, + {NL80211_IFTYPE_AP_VLAN, "VLAN"}, + {NL80211_IFTYPE_WDS, "WDS"}, + {NL80211_IFTYPE_MONITOR, "Monitor"}, + {NL80211_IFTYPE_MESH_POINT, "Mesh point"}, + {NL80211_IFTYPE_P2P_CLIENT, "Client"}, + {NL80211_IFTYPE_P2P_GO, "P2P Go"}, + {NL80211_IFTYPE_P2P_DEVICE, "P2P"}, + {NL80211_IFTYPE_OCB, "OCB"}, + {NL80211_IFTYPE_NAN, "NAN"}, + +}; +static const char *iftype_name(enum nl80211_iftype iftype) +{ + for (size_t i = 0; i < sizeof(ifTypes) / sizeof(ifTypes[0]); ++i) + { + if (ifTypes[i].iftype == iftype) + { + return ifTypes[i].name; + } + } + return "Unknown"; +} + +static int phy_lookup(const char *name) +{ + char buf[200]; + int fd, pos; + snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); + fd = open(buf, O_RDONLY); + pos = read(fd, buf, sizeof(buf) - 1); + if (pos < 0) + return -1; + buf[pos] = '\0'; + return atoi(buf); +} + +WifiInfo pipedal::getWifiInfo(const char *phyName, const char *isoCountryCode) +{ + int index = phy_lookup(phyName); + try + { + if (index == -1) + { + throw std::runtime_error("No such device."); + } + + NetLink netLink; + netLink.GetRegulations(phyName, isoCountryCode); + WifiInfo result = netLink.GetAvailableChannels(phyName, isoCountryCode); + return result; + } + catch (const std::exception &e) + { + throw std::runtime_error(SS("Failed to get Wifi info from nl80211. " << e.what())); + } +} + +const char *allowOutdoorsLocales[] = { + "US", + "TW", + "SG", + +}; + +static bool allowOutdoors(const char *countryCode) +{ + for (size_t i = 0; i < sizeof(allowOutdoorsLocales) / sizeof(allowOutdoorsLocales[0]); ++i) + { + if (strcmp(allowOutdoorsLocales[i], countryCode) == 0) + return true; + } + return false; +} + +int NetLink::finish_handler(struct nl_msg *msg, void *arg) +{ + NetLink *this_ = (NetLink *)arg; + this_->responseReceived = true; + return NL_SKIP; +} +int NetLink::ack_handler(struct nl_msg *msg, void *arg) +{ + NetLink *this_ = (NetLink *)arg; + this_->ackReceived = true; + return NL_STOP; +} + +int NetLink::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, + void *arg) +{ + NetLink *this_ = (NetLink *)arg; + this_->errorCode = err->error; + this_->responseReceived = true; + + return NL_STOP; +} + +int NetLink::reg_handler(struct nl_msg *msg, void *arg) +{ + return ((NetLink *)arg)->RegHandler(msg); +} + +int NetLink::info_handler(struct nl_msg *msg, void *arg) +{ + return ((NetLink *)arg)->InfoHandler(msg); +} +int NetLink::InfoHandler(struct nl_msg *msg) +{ + this->responseReceived = true; + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = (genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; + struct nlattr *nl_band; + struct nlattr *nl_freq; + struct nlattr *nl_rate; + struct nlattr *nl_mode; + int bandidx = 1; + int rem_band, rem_freq, rem_rate, rem_mode; + int open; + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) + return NL_SKIP; + // if (tb_msg[NL80211_ATTR_WIPHY_NAME]) + // this->info.name = nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]); + nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) + { + nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (nlattr *)nla_data(nl_band), + nla_len(nl_band), NULL); + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) + { + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, (nlattr *)nla_data(nl_freq), + nla_len(nl_freq), freq_policy); + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + + WifiChannelInfo channel; + + channel.mhz = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + open = 0; + channel.ir = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) + channel.disabled = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) + channel.ir = false; + if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) + channel.radarDetection = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_10MHZ]) + channel.no10MHz = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY]) + channel.indoorOnly = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ]) + channel.no20MHz = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS]) + channel.noHt40Minus = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS]) + channel.noHt40Plus = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ]) + channel.no80MHz = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ]) + channel.no160MHz = true; + + ChannelInfo channelInfo; + if (ieeeChannelInfo(channel.mhz, + WifiBandwidth::BW20, + &channelInfo)) + { + channel.hardwareMode = channelInfo.hardwareMode; + channel.channelNumber = channelInfo.channel; + + this->info.channels.push_back(std::move(channel)); + } + else + { + // throw std::runtime_error("Frequency not recognized."); + } + } + nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) + { + nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, (nlattr *)nla_data(nl_rate), + nla_len(nl_rate), rate_policy); + if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) + continue; + // channel.bitRates.push_back(0.1f * nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); + } + } + if (!tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) + return NL_SKIP; + + nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) + this->info.supportedIfTypes.push_back(iftype_name((nl80211_iftype)(nl_mode->nla_type))); + return NL_SKIP; +} +int NetLink::RegHandler(struct nl_msg *msg) +{ + this->responseReceived = true; + + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = (genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb_rule[NL80211_REG_RULE_ATTR_MAX + 1]; + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; + struct nlattr *nl_rule; + struct nlattr *nl_freq; + struct nlattr *nl_rate; + struct nlattr *nl_mode; + int ruleidx = 1; + int rem_rules, rem_freq, rem_rate, rem_mode; + int open; + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb_msg[NL80211_ATTR_REG_RULES]) + return NL_SKIP; + if (tb_msg[NL80211_ATTR_REG_ALPHA2]) + this->regulations.reg_alpha2 = nla_get_string(tb_msg[NL80211_ATTR_REG_ALPHA2]); + nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rules) + { + WifiRule rule; + + nla_parse(tb_rule, NL80211_REG_RULE_ATTR_MAX, (nlattr *)nla_data(nl_rule), + nla_len(nl_rule), NULL); + rule.flags = (RegRuleFlags)(nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS])); + rule.start_freq_khz = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]); + rule.end_freq_khz = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]); + rule.max_bandwidth_khz = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]); + rule.max_antenna_gain = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); + rule.max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]); + rule.dfs_cac_ms = nla_get_u32(tb_rule[NL80211_ATTR_DFS_CAC_TIME]); + // not available in bookworm + // if (tb_rule[NL80211_ATTR_POWER_RULE_PSD]) + // { + // rule.psd = nla_get_s8(tb_rule[NL80211_ATTR_POWER_RULE_PSD]); + // }; + + this->regulations.rules.push_back(rule); + } + return NL_SKIP; +} + +NetLink::~NetLink() +{ + if (this->cache) + { + nl_cache_free(cache); + cache = nullptr; + } + if (nl80211 != nullptr) + { + genl_family_put(nl80211); // (release reference) + nl80211 = nullptr; + } + if (socket) + { + nl_close(socket); + nl_socket_free(socket); + socket = nullptr; + } +} + +NetLink::NetLink() +{ + socket = nl_socket_alloc(); + if (!socket) + { + throw std::runtime_error("Can't allocate netlink socket."); + } + nl_socket_set_buffer_size(socket, 8192, 8192); + + if (genl_connect(socket)) + { + throw std::runtime_error("Failed to connect to netlink socket."); + } + if (genl_ctrl_alloc_cache(this->socket, &this->cache) != 0) + { + throw std::runtime_error("Failed to allocate generic netlink cache."); + } + this->nl80211 = genl_ctrl_search_by_name(this->cache, "nl80211"); + if (!this->nl80211) + { + throw std::runtime_error("nl80211 family not found."); + } +} + +WifiRegulations NetLink::GetRegulations(const char *phyName, const char *countryCode) +{ + + struct nl_msg *msg = nullptr; + struct nl_cb *cb = nullptr; + int devidx = 0; + int err; + + devidx = phy_lookup(phyName); + try + { + + msg = nlmsg_alloc(); + if (!msg) + { + throw std::runtime_error("failed to allocate netlink message"); + } + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + { + throw std::runtime_error("failed to allocate netlink callbacks"); + } + genlmsg_put(msg, 0, 0, genl_family_get_id(this->nl80211), 0, + 0, NL80211_CMD_GET_REG, 0); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); + // NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, countryCode); + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, reg_handler, this); + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, this); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, this); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, this); + + this->errorCode = 0; + + err = nl_send_auto(this->socket, msg); + msg = nullptr; + + if (err < 0) + throw std::runtime_error("Send failed."); + responseReceived = false; + ackReceived = false; + while (!responseReceived || !ackReceived) + { + err = nl_recvmsgs_report(this->socket, cb); + if (err < 0) + { + throw std::runtime_error("Receive failed."); + } + } + nlmsg_free(msg); + msg = nullptr; + if (this->errorCode != 0) + { + throw std::runtime_error("Command failed."); + } + nl_cb_put(cb); + cb = nullptr; + return this->regulations; + nla_put_failure: + throw std::runtime_error("NLA Put failure."); + } + catch (const std::exception &e) + { + if (cb != nullptr) + { + nl_cb_put(cb); + cb = nullptr; + } + if (msg != nullptr) + { + nlmsg_free(msg); + msg = nullptr; + } + throw; + } +} + +WifiInfo NetLink::GetAvailableChannels(const char *phyName, const char *countryCode) +{ + + struct nl_msg *msg = nullptr; + struct nl_cb *cb = nullptr; + int devidx = 0; + int err; + + devidx = phy_lookup(phyName); + try + { + + msg = nlmsg_alloc(); + if (!msg) + { + throw std::runtime_error("failed to allocate netlink message"); + } + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + { + throw std::runtime_error("failed to allocate netlink callbacks"); + } + genlmsg_put(msg, 0, 0, genl_family_get_id(this->nl80211), 0, + 0, NL80211_CMD_GET_WIPHY, 0); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); + // NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, countryCode); + + this->errorCode = 0; + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, info_handler, this); + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, this); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, this); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, this); + + err = nl_send_auto(this->socket, msg); + + if (err < 0) + throw std::runtime_error("Command failed."); + responseReceived = false; + + ackReceived = false; + while (!responseReceived || !ackReceived) + { + err = nl_recvmsgs_report(this->socket, cb); + + if (err < 0) + throw std::runtime_error("Receive failed."); + } + + nlmsg_free(msg); + msg = nullptr; + if (this->errorCode != 0) + { + throw std::runtime_error("Command failed."); + } + nl_cb_put(cb); + cb = nullptr; + return info; + nla_put_failure: + throw std::runtime_error("NLA Put failure."); + } + catch (const std::exception &e) + { + if (cb != nullptr) + { + nl_cb_put(cb); + cb = nullptr; + } + if (msg != nullptr) + { + nlmsg_free(msg); + msg = nullptr; + } + throw; + } +} + +const WifiChannelInfo *WifiInfo::getChannelInfo(int channel) const +{ + for (const auto &band : bands) + { + for (const auto &channelInfo : band.channels) + { + if (channelInfo.channelNumber == channel) + { + return &channelInfo; + } + } + } + return nullptr; +} + +struct P2POpClassMap +{ + WifiMode band; + int32_t regDomain; + int32_t firstChannel; + int32_t lastChannel; + int32_t increment; + WifiBandwidth bandwidth; + bool p2p_support; +}; +// from wpa_supplicant. +static std::vector global_op_class = { + {WifiMode::IEEE80211G, 81, 1, 13, 1, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211G, 82, 14, 14, 1, WifiBandwidth::BW20, false}, + + /* Do not enable HT40 on 2.4 GHz for P2P use for now */ + {WifiMode::IEEE80211G, 83, 1, 9, 1, WifiBandwidth::BW40PLUS, false}, + {WifiMode::IEEE80211G, 84, 5, 13, 1, WifiBandwidth::BW40MINUS, false}, + + {WifiMode::IEEE80211A, 115, 36, 48, 4, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211A, 116, 36, 44, 8, WifiBandwidth::BW40PLUS, true}, + {WifiMode::IEEE80211A, 117, 40, 48, 8, WifiBandwidth::BW40MINUS, true}, + {WifiMode::IEEE80211A, 118, 52, 64, 4, WifiBandwidth::BW20, false}, + {WifiMode::IEEE80211A, 119, 52, 60, 8, WifiBandwidth::BW40PLUS, false}, + {WifiMode::IEEE80211A, 120, 56, 64, 8, WifiBandwidth::BW40MINUS, false}, + {WifiMode::IEEE80211A, 121, 100, 140, 4, WifiBandwidth::BW20, false}, + {WifiMode::IEEE80211A, 122, 100, 132, 8, WifiBandwidth::BW40PLUS, false}, + {WifiMode::IEEE80211A, 123, 104, 136, 8, WifiBandwidth::BW40MINUS, false}, + {WifiMode::IEEE80211A, 124, 149, 161, 4, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211A, 125, 149, 177, 4, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211A, 126, 149, 173, 8, WifiBandwidth::BW40PLUS, true}, + {WifiMode::IEEE80211A, 127, 153, 177, 8, WifiBandwidth::BW40MINUS, true}, + + /* + * IEEE P802.11ax/D8.0 (WIFI 6)Table E-4 actually talks about channel center + * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing + * of 80 MHz, but currently use the following definition for simplicity + * (these center frequencies are not actual channels, which makes + * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take + * care of removing invalid channels. + */ + {WifiMode::IEEE80211AX, 128, 36, 177, 4, WifiBandwidth::BW80, true}, + {WifiMode::IEEE80211AX, 129, 36, 177, 4, WifiBandwidth::BW160, true}, + {WifiMode::IEEE80211AX, 130, 36, 177, 4, WifiBandwidth::BW80P80, true}, + {WifiMode::IEEE80211AX, 131, 1, 233, 4, WifiBandwidth::BW20, true}, + {WifiMode::IEEE80211AX, 132, 1, 233, 8, WifiBandwidth::BW40, true}, + {WifiMode::IEEE80211AX, 133, 1, 233, 16, WifiBandwidth::BW80, true}, + {WifiMode::IEEE80211AX, 134, 1, 233, 32, WifiBandwidth::BW160, true}, + {WifiMode::IEEE80211AX, 135, 1, 233, 16, WifiBandwidth::BW80P80, false}, + {WifiMode::IEEE80211AX, 136, 2, 2, 4, WifiBandwidth::BW20, false}, + + /* + * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes. + * Class 180 has the legacy channels 1-6. Classes 181-183 include + * channels which implement channel bonding features. + */ + {WifiMode::IEEE80211AD, 180, 1, 6, 1, WifiBandwidth::BW2160, true}, + {WifiMode::IEEE80211AD, 181, 9, 13, 1, WifiBandwidth::BW4320, true}, + {WifiMode::IEEE80211AD, 182, 17, 20, 1, WifiBandwidth::BW6480, true}, + {WifiMode::IEEE80211AD, 183, 25, 27, 1, WifiBandwidth::BW8640, true}, + + /* Keep the operating class 130 as the last entry as a workaround for + * the OneHundredAndThirty Delimiter value used in the Supported + * Operating Classes element to indicate the end of the Operating + * Classes field. */ +}; + +std::vector pipedal::getWifiP2pInfo(const char *phyName, const char *isoCountryCode) +{ + WifiInfo info = getWifiInfo(phyName, isoCountryCode); + std::vector result; + + for (const P2POpClassMap &classMap : global_op_class) + { + if (!classMap.p2p_support) + { + continue; + } + if (classMap.band != WifiMode::IEEE80211A && classMap.band != WifiMode::IEEE80211G) + { + continue; + } + for (auto channel = classMap.firstChannel; channel <= classMap.lastChannel; channel += classMap.increment) + { + const auto *channelInfo = info.getChannelInfo(channel); + if (!channelInfo) + continue; + WifiP2PChannelInfo t; + // slice copy the channelInfo + (WifiChannelInfo &)t = *channelInfo; + + ChannelInfo p2pInfo; + if (ieeeChannelInfo(channelInfo->mhz, + classMap.bandwidth, + &p2pInfo)) + { + switch (p2pInfo.hardwareMode) + { + case WifiMode::IEEE80211A: + case WifiMode::IEEE80211B: + case WifiMode::IEEE80211G: + t.regDomain = p2pInfo.op_class; + result.push_back(std::move(t)); + break; + } + } + else + { + // throw std::runtime_error("Frequency not recognized."); + } + t.regDomain = classMap.regDomain; + result.push_back(t); + } + } + return result; +} + +/** + * ieee80211_freq_to_channel_ext - Convert frequency into channel info + * for HT40, VHT, and HE. DFS channels are not covered. + * @freq: Frequency (MHz) to convert + * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below + * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*) + * @op_class: Buffer for returning operating class + * @channel: Buffer for returning channel number + * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure + */ + +bool ieeeChannelInfo(unsigned int freq, + WifiBandwidth chanwidth, + ChannelInfo *channelInfo) +{ + + // convert to the convetions used by original code. + SecondaryChannelLocation sec_channel = SecondaryChannelLocation::None; + if (chanwidth == WifiBandwidth::BW40MINUS) + { + chanwidth = WifiBandwidth::BW40; + sec_channel = SecondaryChannelLocation::Below; + } + else if (chanwidth == WifiBandwidth::BW40PLUS) + { + chanwidth = WifiBandwidth::BW40; + sec_channel = SecondaryChannelLocation::Above; + } + + // based on wpa_supplicatn ieee801_11_common.c ieee80211_freq_to_channel_ext + int32_t vht_opclass; + + /* TODO: more operating classes */ + + channelInfo->freq = freq; + channelInfo->chanWidth = chanwidth; + + if (freq >= 2412 && freq <= 2472) + { + if ((freq - 2407) % 5) + return false; + + /* 2.407 GHz, channels 1..13 */ + if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 83; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 84; + else + channelInfo->op_class = 81; + + channelInfo->channel = (freq - 2407) / 5; + channelInfo->hardwareMode = WifiMode::IEEE80211G; + return true; + } + + if (freq == 2484) + { + if (sec_channel != SecondaryChannelLocation::None || chanwidth > WifiBandwidth::BW40) + return false; + + channelInfo->op_class = 82; /* channel 14 */ + channelInfo->channel = 14; + + channelInfo->hardwareMode = WifiMode::IEEE80211B; + return true; + } + + if (freq >= 4900 && freq < 5000) + { + if ((freq - 4000) % 5) + return false; + channelInfo->channel = (freq - 4000) / 5; + channelInfo->op_class = 0; /* TODO */ + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return false; + } + + switch (chanwidth) + { + case WifiBandwidth::BW80: + vht_opclass = 128; + break; + case WifiBandwidth::BW160: + vht_opclass = 129; + break; + case WifiBandwidth::BW80P80: + vht_opclass = 130; + break; + default: + vht_opclass = 0; + break; + } + + /* 5 GHz, channels 36..48 */ + if (freq >= 5180 && freq <= 5240) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 116; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 117; + else + channelInfo->op_class = 115; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return true; + } + + /* 5 GHz, channels 52..64 */ + if (freq >= 5260 && freq <= 5320) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 119; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 120; + else + channelInfo->op_class = 118; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return true; + } + + /* 5 GHz, channels 149..177 */ + if (freq >= 5745 && freq <= 5885) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 126; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 127; + else if (freq <= 5805) + channelInfo->op_class = 124; + else + channelInfo->op_class = 125; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return true; + } + + /* 5 GHz, channels 100..144 */ + if (freq >= 5500 && freq <= 5720) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 122; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 123; + else + channelInfo->op_class = 121; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return true; + } + + if (freq >= 5000 && freq < 5900) + { + if ((freq - 5000) % 5) + return false; + channelInfo->channel = (freq - 5000) / 5; + channelInfo->op_class = 0; /* TODO */ + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return false; /* TODO */ + } + + if (freq > 5950 && freq <= 7115) + { + if ((freq - 5950) % 5) + return false; + + switch (chanwidth) + { + case WifiBandwidth::BW80: + channelInfo->op_class = 133; + break; + case WifiBandwidth::BW160: + channelInfo->op_class = 134; + break; + case WifiBandwidth::BW80P80: + channelInfo->op_class = 135; + break; + default: + if (sec_channel == SecondaryChannelLocation::None) + channelInfo->op_class = 132; + else + channelInfo->op_class = 131; + break; + } + + channelInfo->channel = (freq - 5950) / 5; + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return true; + } + + if (freq == 5935) + { + channelInfo->op_class = 136; + channelInfo->channel = (freq - 5925) / 5; + channelInfo->hardwareMode = WifiMode::IEEE80211A; + return true; + } + + /* 56.16 GHz, channel 1..6 */ + if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) + { + if (sec_channel != SecondaryChannelLocation::None) + return false; + + switch (chanwidth) + { + case WifiBandwidth::BW20: + case WifiBandwidth::BW40: + case WifiBandwidth::BW2160: + channelInfo->channel = (freq - 56160) / 2160; + channelInfo->op_class = 180; + break; + case WifiBandwidth::BW4320: + /* EDMG channels 9 - 13 */ + if (freq > 56160 + 2160 * 5) + return false; + + channelInfo->channel = (freq - 56160) / 2160 + 8; + channelInfo->op_class = 181; + break; + case WifiBandwidth::BW6480: + /* EDMG channels 17 - 20 */ + if (freq > 56160 + 2160 * 4) + return false; + + channelInfo->channel = (freq - 56160) / 2160 + 16; + channelInfo->op_class = 182; + break; + case WifiBandwidth::BW8640: + /* EDMG channels 25 - 27 */ + if (freq > 56160 + 2160 * 3) + return false; + + channelInfo->channel = (freq - 56160) / 2160 + 24; + channelInfo->op_class = 183; + break; + default: + return false; + } + + channelInfo->hardwareMode = WifiMode::IEEE80211AD; + return true; + } + + return false; +} +// * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed +// * @NL80211_RRF_NO_CCK: CCK modulation not allowed +// * @NL80211_RRF_NO_INDOOR: indoor operation not allowed +// * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed +// * @NL80211_RRF_DFS: DFS support is required to be used +// * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links +// * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links +// * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, diff --git a/PiPedalCommon/src/NetLinkChannelInfo.cpp.bak b/PiPedalCommon/src/NetLinkChannelInfo.cpp.bak new file mode 100644 index 0000000..0012cd6 --- /dev/null +++ b/PiPedalCommon/src/NetLinkChannelInfo.cpp.bak @@ -0,0 +1,1166 @@ +/* +Copyright (c) 2007, 2008 Johannes Berg +Copyright (c) 2007 Andy Lutomirski +Copyright (c) 2007 Mike Kershaw +Copyright (c) 2008 Luis R. Rodriguez +Copyright (c) 2024 Robin Davies +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ +/* + Heavily based on code borrowed from iw (1) command. + https://kernel.googlesource.com/pub/scm/linux/kernel/git/jberg/iw/+/v0.9/COPYING +*/ + +// code lifed from WPA_SUPPLICANT +/* +Copyright (c) 2002-2019, Jouni Malinen + +This software may be distributed, used, and modified under the terms of +BSD license: + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name(s) of the above-listed copyright holder(s) nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "NetLinkChannelInfo.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ss.hpp" + +using namespace pipedal; + +namespace pipedal::impl +{ + class NetLink + { + private: + bool responseReceived = false; + bool ackReceived = false; + WifiInfo info; + WifiRegulations regulations; + nl_sock *socket = nullptr; + nl_cache *cache = nullptr; + genl_family *nl80211 = nullptr; + + int errorCode = -1; + + static int finish_handler(struct nl_msg *msg, void *arg); + static int ack_handler(struct nl_msg *msg, void *arg); + + static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, + void *arg); + + static int info_handler(struct nl_msg *msg, void *arg); + static int reg_handler(struct nl_msg *msg, void *arg); + int InfoHandler(struct nl_msg *msg); + int RegHandler(struct nl_msg *msg); + + public: + ~NetLink(); + NetLink(); + + WifiInfo GetAvailableChannels(const char *phyName, const char *countryregode); + WifiRegulations GetRegulations(const char *phyName, const char *countryCode); + }; + +} + +using namespace pipedal::impl; + +enum class Bandwidth +{ + BW20, + BW40, + BW40PLUS, + BW40MINUS, + BW80, + BW160, + BW80P80, + BW2160, + BW4320, + BW6480, + BW8640 +}; + +struct ChannelInfo +{ + int32_t freq; + Bandwidth chanWidth; + SecondaryChannelLocation secondaryChannelLocation; + int32_t op_class; + int32_t channel; + HardwareMode hardwareMode; +}; + +bool ieeeChannelInfo(unsigned int freq, + Bandwidth chanwidth, + ChannelInfo *channelInfo); + +struct NlMHzToChannel +{ + char band; + int channel; + int mhz; +}; + +static std::vector mhzToChannels = { + {'g', 1, 2412}, + {'g', 2, 2417}, + {'g', 3, 2422}, + {'g', 4, 2427}, + {'g', 5, 2432}, + {'g', 6, 2437}, + {'g', 7, 2442}, + {'g', 8, 2447}, + {'g', 9, 2452}, + {'g', 10, 2457}, + {'g', 11, 2462}, + {'g', 12, 2467}, + {'g', 13, 2472}, + {'g', 14, 2484}, + {'a', 7, 5035}, + {'a', 8, 5040}, + {'a', 9, 5045}, + {'a', 11, 5055}, + {'a', 12, 5060}, + {'a', 16, 5080}, + {'a', 32, 5160}, + {'a', 34, 5170}, + {'a', 36, 5180}, + {'a', 38, 5190}, + {'a', 40, 5200}, + {'a', 42, 5210}, + {'a', 44, 5220}, + {'a', 46, 5230}, + {'a', 48, 5240}, + {'a', 50, 5250}, + {'a', 52, 5260}, + {'a', 54, 5270}, + {'a', 56, 5280}, + {'a', 58, 5290}, + {'a', 60, 5300}, + {'a', 62, 5310}, + {'a', 64, 5320}, + {'a', 68, 5340}, + {'a', 96, 5480}, + {'a', 100, 5500}, + {'a', 102, 5510}, + {'a', 104, 5520}, + {'a', 106, 5530}, + {'a', 108, 5540}, + {'a', 110, 5550}, + {'a', 112, 5560}, + {'a', 114, 5570}, + {'a', 116, 5580}, + {'a', 118, 5590}, + {'a', 120, 5600}, + {'a', 122, 5610}, + {'a', 124, 5620}, + {'a', 126, 5630}, + {'a', 128, 5640}, + {'a', 132, 5660}, + {'a', 134, 5670}, + {'a', 136, 5680}, + {'a', 138, 5690}, + {'a', 140, 5700}, + {'a', 142, 5710}, + {'a', 144, 5720}, + {'a', 149, 5745}, + {'a', 151, 5755}, + {'a', 153, 5765}, + {'a', 155, 5775}, + {'a', 157, 5785}, + {'a', 159, 5795}, + {'a', 161, 5805}, + {'a', 163, 5815}, + {'a', 165, 5825}, + {'a', 167, 5835}, + {'a', 169, 5845}, + {'a', 171, 5855}, + {'a', 173, 5865}, + {'a', 175, 5875}, + {'a', 177, 5885}, + {'a', 180, 5900}, + {'a', 182, 5910}, + {'a', 18, 5915}, + {'a', 184, 5920}, + {'a', 187, 5935}, + {'a', 188, 5940}, + {'a', 189, 5945}, + {'a', 192, 5960}, + {'a', 196, 5980}, +}; + +static bool MHzToChannelNumber(int mhz, char *pBand, int *pChannel) +{ + for (size_t i = 0; i < mhzToChannels.size(); ++i) + { + if (std::abs(mhz - mhzToChannels[i].mhz) <= 1) + { + *pBand = mhzToChannels[i].band; + *pChannel = mhzToChannels[i].channel; + return true; + } + } + return false; +} + +static nla_policy *makeFreqPolicy() +{ + nla_policy *result = new nla_policy[NL80211_FREQUENCY_ATTR_MAX + 1]; + memset(result, 0, sizeof(nla_policy[NL80211_FREQUENCY_ATTR_MAX + 1])); + + result[NL80211_FREQUENCY_ATTR_FREQ] = {NLA_U32, 0, 0}; + result[NL80211_FREQUENCY_ATTR_DISABLED] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_IR] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_RADAR] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_INDOOR_ONLY] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_INDOOR_ONLY] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_20MHZ] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_20MHZ] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_80MHZ] = {NLA_FLAG, 0, 0}; + result[NL80211_FREQUENCY_ATTR_NO_160MHZ] = {NLA_FLAG, 0, 0}; + return result; +} + +static struct nla_policy *freq_policy = makeFreqPolicy(); + +static nla_policy *makeRatePolicy() +{ + nla_policy *result = new nla_policy[NL80211_BITRATE_ATTR_MAX + 1]; + memset(result, 0, sizeof(nla_policy[NL80211_BITRATE_ATTR_MAX + 1])); + result[NL80211_BITRATE_ATTR_RATE] = {.type = NLA_U32}; + result[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = {.type = NLA_FLAG}; + return result; +}; + +static struct nla_policy *rate_policy = makeRatePolicy(); + +struct IfType +{ + enum nl80211_iftype iftype; + const char *name; +}; +static struct IfType ifTypes[] = { + {NL80211_IFTYPE_UNSPECIFIED, "Unspecified"}, + {NL80211_IFTYPE_ADHOC, "Adhoc"}, + {NL80211_IFTYPE_STATION, "Station"}, + {NL80211_IFTYPE_AP, "AP"}, + {NL80211_IFTYPE_AP_VLAN, "VLAN"}, + {NL80211_IFTYPE_WDS, "WDS"}, + {NL80211_IFTYPE_MONITOR, "Monitor"}, + {NL80211_IFTYPE_MESH_POINT, "Mesh point"}, + {NL80211_IFTYPE_P2P_CLIENT, "Client"}, + {NL80211_IFTYPE_P2P_GO, "P2P Go"}, + {NL80211_IFTYPE_P2P_DEVICE, "P2P"}, + {NL80211_IFTYPE_OCB, "OCB"}, + {NL80211_IFTYPE_NAN, "NAN"}, + +}; +static const char *iftype_name(enum nl80211_iftype iftype) +{ + for (size_t i = 0; i < sizeof(ifTypes) / sizeof(ifTypes[0]); ++i) + { + if (ifTypes[i].iftype == iftype) + { + return ifTypes[i].name; + } + } + return "Unknown"; +} + +static int phy_lookup(const char *name) +{ + char buf[200]; + int fd, pos; + snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); + fd = open(buf, O_RDONLY); + pos = read(fd, buf, sizeof(buf) - 1); + if (pos < 0) + return -1; + buf[pos] = '\0'; + return atoi(buf); +} + +WifiInfo pipedal::getWifiInfo(const char *phyName, const char *isoCountryCode) +{ + int index = phy_lookup(phyName); + try + { + if (index == -1) + { + throw std::runtime_error("No such device."); + } + + NetLink netLink; + netLink.GetRegulations(phyName, isoCountryCode); + WifiInfo result = netLink.GetAvailableChannels(phyName, isoCountryCode); + return result; + } + catch (const std::exception &e) + { + throw std::runtime_error(SS("Failed to get Wifi info from nl80211. " << e.what())); + } +} + +const char *allowOutdoorsLocales[] = { + "US", + "TW", + "SG", + +}; + +static bool allowOutdoors(const char *countryCode) +{ + for (size_t i = 0; i < sizeof(allowOutdoorsLocales) / sizeof(allowOutdoorsLocales[0]); ++i) + { + if (strcmp(allowOutdoorsLocales[i], countryCode) == 0) + return true; + } + return false; +} + +int NetLink::finish_handler(struct nl_msg *msg, void *arg) +{ + NetLink *this_ = (NetLink *)arg; + this_->responseReceived = true; + return NL_SKIP; +} +int NetLink::ack_handler(struct nl_msg *msg, void *arg) +{ + NetLink *this_ = (NetLink *)arg; + this_->ackReceived = true; + return NL_STOP; +} + +int NetLink::error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, + void *arg) +{ + NetLink *this_ = (NetLink *)arg; + this_->errorCode = err->error; + this_->responseReceived = true; + + return NL_STOP; +} + +int NetLink::reg_handler(struct nl_msg *msg, void *arg) +{ + return ((NetLink *)arg)->RegHandler(msg); +} + +int NetLink::info_handler(struct nl_msg *msg, void *arg) +{ + return ((NetLink *)arg)->InfoHandler(msg); +} +int NetLink::InfoHandler(struct nl_msg *msg) +{ + this->responseReceived = true; + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = (genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; + struct nlattr *nl_band; + struct nlattr *nl_freq; + struct nlattr *nl_rate; + struct nlattr *nl_mode; + int bandidx = 1; + int rem_band, rem_freq, rem_rate, rem_mode; + int open; + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) + return NL_SKIP; + if (tb_msg[NL80211_ATTR_WIPHY_NAME]) + this->info.name = nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]); + nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) + { + WifiBand band; + band.index = bandidx; + + bandidx++; + nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (nlattr *)nla_data(nl_band), + nla_len(nl_band), NULL); + + nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) + { + nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, (nlattr *)nla_data(nl_freq), + nla_len(nl_freq), freq_policy); + if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) + continue; + + WifiChannelInfo channel; + + channel.mhz = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); + open = 0; + channel.ir = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) + channel.disabled = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) + channel.ir = false; + if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) + channel.radarDetection = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_10MHZ]) + channel.no10MHz = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY]) + channel.indoorOnly = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ]) + channel.no20MHz = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS]) + channel.noHt40Minus = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS]) + channel.noHt40Plus = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ]) + channel.no80MHz = true; + if (tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ]) + channel.no160MHz = true; + + ChannelInfo channelInfo; + if (ieeeChannelInfo(channel.mhz, + Bandwidth::BW20, + &channelInfo)) + { + channel.hardwareMode = channelInfo.hardwareMode; + channel.channelNumber = channelInfo.channel; + band.channels.push_back(std::move(channel)); + } + else + { + // throw std::runtime_error("Frequency not recognized."); + } + } + nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) + { + nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, (nlattr *)nla_data(nl_rate), + nla_len(nl_rate), rate_policy); + if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) + continue; + // channel.bitRates.push_back(0.1f * nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); + } + this->info.bands.push_back(std::move(band)); + } + if (!tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) + return NL_SKIP; + + nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) + this->info.supportedIfTypes.push_back(iftype_name((nl80211_iftype)(nl_mode->nla_type))); + return NL_SKIP; +} +int NetLink::RegHandler(struct nl_msg *msg) +{ + this->responseReceived = true; + + struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; + struct genlmsghdr *gnlh = (genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); + struct nlattr *tb_rule[NL80211_REG_RULE_ATTR_MAX + 1]; + struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; + struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; + struct nlattr *nl_rule; + struct nlattr *nl_freq; + struct nlattr *nl_rate; + struct nlattr *nl_mode; + int ruleidx = 1; + int rem_rules, rem_freq, rem_rate, rem_mode; + int open; + nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), + genlmsg_attrlen(gnlh, 0), NULL); + if (!tb_msg[NL80211_ATTR_REG_RULES]) + return NL_SKIP; + if (tb_msg[NL80211_ATTR_REG_ALPHA2]) + this->regulations.reg_alpha2 = nla_get_string(tb_msg[NL80211_ATTR_REG_ALPHA2]); + nla_for_each_nested(nl_rule, tb_msg[NL80211_ATTR_REG_RULES], rem_rules) + { + WifiRule rule; + + nla_parse(tb_rule, NL80211_REG_RULE_ATTR_MAX, (nlattr *)nla_data(nl_rule), + nla_len(nl_rule), NULL); + rule.flags = (RegRuleFlags)(nla_get_u32(tb_rule[NL80211_ATTR_REG_RULE_FLAGS])); + rule.start_freq_khz = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_START]); + rule.end_freq_khz = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_END]); + rule.max_bandwidth_khz = nla_get_u32(tb_rule[NL80211_ATTR_FREQ_RANGE_MAX_BW]); + rule.max_antenna_gain = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN]); + rule.max_eirp = nla_get_u32(tb_rule[NL80211_ATTR_POWER_RULE_MAX_EIRP]); + rule.dfs_cac_ms = nla_get_u32(tb_rule[NL80211_ATTR_DFS_CAC_TIME]); + // not available in bookworm + // if (tb_rule[NL80211_ATTR_POWER_RULE_PSD]) + // { + // rule.psd = nla_get_s8(tb_rule[NL80211_ATTR_POWER_RULE_PSD]); + // }; + + this->regulations.regulations.push_back(rule); + } + return NL_SKIP; +} + +NetLink::~NetLink() +{ + if (this->cache) + { + nl_cache_free(cache); + cache = nullptr; + } + if (nl80211 != nullptr) + { + genl_family_put(nl80211); // (release reference) + nl80211 = nullptr; + } + if (socket) + { + nl_close(socket); + nl_socket_free(socket); + socket = nullptr; + } +} + +NetLink::NetLink() +{ + socket = nl_socket_alloc(); + if (!socket) + { + throw std::runtime_error("Can't allocate netlink socket."); + } + nl_socket_set_buffer_size(socket, 8192, 8192); + + if (genl_connect(socket)) + { + throw std::runtime_error("Failed to connect to netlink socket."); + } + if (genl_ctrl_alloc_cache(this->socket, &this->cache) != 0) + { + throw std::runtime_error("Failed to allocate generic netlink cache."); + } + this->nl80211 = genl_ctrl_search_by_name(this->cache, "nl80211"); + if (!this->nl80211) + { + throw std::runtime_error("nl80211 family not found."); + } +} + +WifiRegulations NetLink::GetRegulations(const char *phyName, const char *countryCode) +{ + + struct nl_msg *msg = nullptr; + struct nl_cb *cb = nullptr; + int devidx = 0; + int err; + + devidx = phy_lookup(phyName); + try + { + + msg = nlmsg_alloc(); + if (!msg) + { + throw std::runtime_error("failed to allocate netlink message"); + } + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + { + throw std::runtime_error("failed to allocate netlink callbacks"); + } + genlmsg_put(msg, 0, 0, genl_family_get_id(this->nl80211), 0, + 0, NL80211_CMD_GET_REG, 0); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); + // NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, countryCode); + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, reg_handler, this); + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, this); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, this); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, this); + + this->errorCode = 0; + + err = nl_send_auto(this->socket, msg); + msg = nullptr; + + if (err < 0) + throw std::runtime_error("Send failed."); + responseReceived = false; + ackReceived = false; + while (!responseReceived || !ackReceived) + { + err = nl_recvmsgs_report(this->socket, cb); + if (err < 0) + { + throw std::runtime_error("Receive failed."); + } + } + nlmsg_free(msg); + msg = nullptr; + if (this->errorCode != 0) + { + throw std::runtime_error("Command failed."); + } + nl_cb_put(cb); + cb = nullptr; + return this->regulations; + nla_put_failure: + throw std::runtime_error("NLA Put failure."); + } + catch (const std::exception &e) + { + if (cb != nullptr) + { + nl_cb_put(cb); + cb = nullptr; + } + if (msg != nullptr) + { + nlmsg_free(msg); + msg = nullptr; + } + throw; + } +} + +WifiInfo NetLink::GetAvailableChannels(const char *phyName, const char *countryCode) +{ + + struct nl_msg *msg = nullptr; + struct nl_cb *cb = nullptr; + int devidx = 0; + int err; + + devidx = phy_lookup(phyName); + try + { + + msg = nlmsg_alloc(); + if (!msg) + { + throw std::runtime_error("failed to allocate netlink message"); + } + cb = nl_cb_alloc(NL_CB_DEFAULT); + if (!cb) + { + throw std::runtime_error("failed to allocate netlink callbacks"); + } + genlmsg_put(msg, 0, 0, genl_family_get_id(this->nl80211), 0, + 0, NL80211_CMD_GET_WIPHY, 0); + NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); + // NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, countryCode); + + this->errorCode = 0; + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, info_handler, this); + + nl_cb_err(cb, NL_CB_CUSTOM, error_handler, this); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, this); + nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, this); + + err = nl_send_auto(this->socket, msg); + + if (err < 0) + throw std::runtime_error("Command failed."); + responseReceived = false; + + ackReceived = false; + while (!responseReceived || !ackReceived) + { + err = nl_recvmsgs_report(this->socket, cb); + + if (err < 0) + throw std::runtime_error("Receive failed."); + } + + nlmsg_free(msg); + msg = nullptr; + if (this->errorCode != 0) + { + throw std::runtime_error("Command failed."); + } + nl_cb_put(cb); + cb = nullptr; + return info; + nla_put_failure: + throw std::runtime_error("NLA Put failure."); + } + catch (const std::exception &e) + { + if (cb != nullptr) + { + nl_cb_put(cb); + cb = nullptr; + } + if (msg != nullptr) + { + nlmsg_free(msg); + msg = nullptr; + } + throw; + } +} + +const WifiChannelInfo *WifiInfo::getChannelInfo(int channel) const +{ + for (const auto &band : bands) + { + for (const auto &channelInfo : band.channels) + { + if (channelInfo.channelNumber == channel) + { + return &channelInfo; + } + } + } + return nullptr; +} + +struct P2POpClassMap +{ + HardwareMode band; + int32_t regDomain; + int32_t firstChannel; + int32_t lastChannel; + int32_t increment; + Bandwidth bandwidth; + bool p2p_support; +}; +// from wpa_supplicant. +static std::vector global_op_class = { + {HardwareMode::IEEE80211G, 81, 1, 13, 1, Bandwidth::BW20, true}, + {HardwareMode::IEEE80211G, 82, 14, 14, 1, Bandwidth::BW20, false}, + + /* Do not enable HT40 on 2.4 GHz for P2P use for now */ + {HardwareMode::IEEE80211G, 83, 1, 9, 1, Bandwidth::BW40PLUS, false}, + {HardwareMode::IEEE80211G, 84, 5, 13, 1, Bandwidth::BW40MINUS, false}, + + {HardwareMode::IEEE80211A, 115, 36, 48, 4, Bandwidth::BW20, true}, + {HardwareMode::IEEE80211A, 116, 36, 44, 8, Bandwidth::BW40PLUS, true}, + {HardwareMode::IEEE80211A, 117, 40, 48, 8, Bandwidth::BW40MINUS, true}, + {HardwareMode::IEEE80211A, 118, 52, 64, 4, Bandwidth::BW20, false}, + {HardwareMode::IEEE80211A, 119, 52, 60, 8, Bandwidth::BW40PLUS, false}, + {HardwareMode::IEEE80211A, 120, 56, 64, 8, Bandwidth::BW40MINUS, false}, + {HardwareMode::IEEE80211A, 121, 100, 140, 4, Bandwidth::BW20, false}, + {HardwareMode::IEEE80211A, 122, 100, 132, 8, Bandwidth::BW40PLUS, false}, + {HardwareMode::IEEE80211A, 123, 104, 136, 8, Bandwidth::BW40MINUS, false}, + {HardwareMode::IEEE80211A, 124, 149, 161, 4, Bandwidth::BW20, true}, + {HardwareMode::IEEE80211A, 125, 149, 177, 4, Bandwidth::BW20, true}, + {HardwareMode::IEEE80211A, 126, 149, 173, 8, Bandwidth::BW40PLUS, true}, + {HardwareMode::IEEE80211A, 127, 153, 177, 8, Bandwidth::BW40MINUS, true}, + + /* + * IEEE P802.11ax/D8.0 (WIFI 6)Table E-4 actually talks about channel center + * frequency index 42, 58, 106, 122, 138, 155, 171 with channel spacing + * of 80 MHz, but currently use the following definition for simplicity + * (these center frequencies are not actual channels, which makes + * wpas_p2p_verify_channel() fail). wpas_p2p_verify_80mhz() should take + * care of removing invalid channels. + */ + {HardwareMode::IEEE80211AX, 128, 36, 177, 4, Bandwidth::BW80, true}, + {HardwareMode::IEEE80211AX, 129, 36, 177, 4, Bandwidth::BW160, true}, + {HardwareMode::IEEE80211AX, 130, 36, 177, 4, Bandwidth::BW80P80, true}, + {HardwareMode::IEEE80211AX, 131, 1, 233, 4, Bandwidth::BW20, true}, + {HardwareMode::IEEE80211AX, 132, 1, 233, 8, Bandwidth::BW40, true}, + {HardwareMode::IEEE80211AX, 133, 1, 233, 16, Bandwidth::BW80, true}, + {HardwareMode::IEEE80211AX, 134, 1, 233, 32, Bandwidth::BW160, true}, + {HardwareMode::IEEE80211AX, 135, 1, 233, 16, Bandwidth::BW80P80, false}, + {HardwareMode::IEEE80211AX, 136, 2, 2, 4, Bandwidth::BW20, false}, + + /* + * IEEE Std 802.11ad-2012 and P802.ay/D5.0 60 GHz operating classes. + * Class 180 has the legacy channels 1-6. Classes 181-183 include + * channels which implement channel bonding features. + */ + {HardwareMode::IEEE80211AD, 180, 1, 6, 1, Bandwidth::BW2160, true}, + {HardwareMode::IEEE80211AD, 181, 9, 13, 1, Bandwidth::BW4320, true}, + {HardwareMode::IEEE80211AD, 182, 17, 20, 1, Bandwidth::BW6480, true}, + {HardwareMode::IEEE80211AD, 183, 25, 27, 1, Bandwidth::BW8640, true}, + + /* Keep the operating class 130 as the last entry as a workaround for + * the OneHundredAndThirty Delimiter value used in the Supported + * Operating Classes element to indicate the end of the Operating + * Classes field. */ +}; + +std::vector pipedal::getWifiP2pInfo(const char *phyName, const char *isoCountryCode) +{ + WifiInfo info = getWifiInfo(phyName, isoCountryCode); + std::vector result; + + for (const P2POpClassMap &classMap : global_op_class) + { + if (!classMap.p2p_support) + { + continue; + } + if (classMap.band != HardwareMode::IEEE80211A && classMap.band != HardwareMode::IEEE80211G) + { + continue; + } + for (auto channel = classMap.firstChannel; channel <= classMap.lastChannel; channel += classMap.increment) + { + const auto *channelInfo = info.getChannelInfo(channel); + if (!channelInfo) + continue; + WifiP2PChannelInfo t; + // slice copy the channelInfo + (WifiChannelInfo &)t = *channelInfo; + + ChannelInfo p2pInfo; + if (ieeeChannelInfo(channelInfo->mhz, + classMap.bandwidth, + &p2pInfo)) + { + switch (p2pInfo.hardwareMode) + { + case HardwareMode::IEEE80211A: + case HardwareMode::IEEE80211B: + case HardwareMode::IEEE80211G: + t.regDomain = p2pInfo.op_class; + result.push_back(std::move(t)); + break; + } + } + else + { + // throw std::runtime_error("Frequency not recognized."); + } + t.regDomain = classMap.regDomain; + result.push_back(t); + } + } + return result; +} + +/** + * ieee80211_freq_to_channel_ext - Convert frequency into channel info + * for HT40, VHT, and HE. DFS channels are not covered. + * @freq: Frequency (MHz) to convert + * @sec_channel: 0 = non-HT40, 1 = sec. channel above, -1 = sec. channel below + * @chanwidth: VHT/EDMG channel width (CHANWIDTH_*) + * @op_class: Buffer for returning operating class + * @channel: Buffer for returning channel number + * Returns: hw_mode on success, NUM_HOSTAPD_MODES on failure + */ + +bool ieeeChannelInfo(unsigned int freq, + Bandwidth chanwidth, + ChannelInfo *channelInfo) +{ + + // convert to the convetions used by original code. + SecondaryChannelLocation sec_channel = SecondaryChannelLocation::None; + if (chanwidth == Bandwidth::BW40MINUS) + { + chanwidth = Bandwidth::BW40; + sec_channel = SecondaryChannelLocation::Below; + } + else if (chanwidth == Bandwidth::BW40PLUS) + { + chanwidth = Bandwidth::BW40; + sec_channel = SecondaryChannelLocation::Above; + } + + // based on wpa_supplicatn ieee801_11_common.c ieee80211_freq_to_channel_ext + int32_t vht_opclass; + + /* TODO: more operating classes */ + + channelInfo->freq = freq; + channelInfo->chanWidth = chanwidth; + + if (freq >= 2412 && freq <= 2472) + { + if ((freq - 2407) % 5) + return false; + + /* 2.407 GHz, channels 1..13 */ + if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 83; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 84; + else + channelInfo->op_class = 81; + + channelInfo->channel = (freq - 2407) / 5; + channelInfo->hardwareMode = HardwareMode::IEEE80211G; + return true; + } + + if (freq == 2484) + { + if (sec_channel != SecondaryChannelLocation::None || chanwidth > Bandwidth::BW40) + return false; + + channelInfo->op_class = 82; /* channel 14 */ + channelInfo->channel = 14; + + channelInfo->hardwareMode = HardwareMode::IEEE80211B; + return true; + } + + if (freq >= 4900 && freq < 5000) + { + if ((freq - 4000) % 5) + return false; + channelInfo->channel = (freq - 4000) / 5; + channelInfo->op_class = 0; /* TODO */ + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return false; + } + + switch (chanwidth) + { + case Bandwidth::BW80: + vht_opclass = 128; + break; + case Bandwidth::BW160: + vht_opclass = 129; + break; + case Bandwidth::BW80P80: + vht_opclass = 130; + break; + default: + vht_opclass = 0; + break; + } + + /* 5 GHz, channels 36..48 */ + if (freq >= 5180 && freq <= 5240) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 116; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 117; + else + channelInfo->op_class = 115; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return true; + } + + /* 5 GHz, channels 52..64 */ + if (freq >= 5260 && freq <= 5320) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 119; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 120; + else + channelInfo->op_class = 118; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return true; + } + + /* 5 GHz, channels 149..177 */ + if (freq >= 5745 && freq <= 5885) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 126; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 127; + else if (freq <= 5805) + channelInfo->op_class = 124; + else + channelInfo->op_class = 125; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return true; + } + + /* 5 GHz, channels 100..144 */ + if (freq >= 5500 && freq <= 5720) + { + if ((freq - 5000) % 5) + return false; + + if (vht_opclass) + channelInfo->op_class = vht_opclass; + else if (sec_channel == SecondaryChannelLocation::Above) + channelInfo->op_class = 122; + else if (sec_channel == SecondaryChannelLocation::Below) + channelInfo->op_class = 123; + else + channelInfo->op_class = 121; + + channelInfo->channel = (freq - 5000) / 5; + + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return true; + } + + if (freq >= 5000 && freq < 5900) + { + if ((freq - 5000) % 5) + return false; + channelInfo->channel = (freq - 5000) / 5; + channelInfo->op_class = 0; /* TODO */ + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return false; /* TODO */ + } + + if (freq > 5950 && freq <= 7115) + { + if ((freq - 5950) % 5) + return false; + + switch (chanwidth) + { + case Bandwidth::BW80: + channelInfo->op_class = 133; + break; + case Bandwidth::BW160: + channelInfo->op_class = 134; + break; + case Bandwidth::BW80P80: + channelInfo->op_class = 135; + break; + default: + if (sec_channel == SecondaryChannelLocation::None) + channelInfo->op_class = 132; + else + channelInfo->op_class = 131; + break; + } + + channelInfo->channel = (freq - 5950) / 5; + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return true; + } + + if (freq == 5935) + { + channelInfo->op_class = 136; + channelInfo->channel = (freq - 5925) / 5; + channelInfo->hardwareMode = HardwareMode::IEEE80211A; + return true; + } + + /* 56.16 GHz, channel 1..6 */ + if (freq >= 56160 + 2160 * 1 && freq <= 56160 + 2160 * 6) + { + if (sec_channel != SecondaryChannelLocation::None) + return false; + + switch (chanwidth) + { + case Bandwidth::BW20: + case Bandwidth::BW40: + case Bandwidth::BW2160: + channelInfo->channel = (freq - 56160) / 2160; + channelInfo->op_class = 180; + break; + case Bandwidth::BW4320: + /* EDMG channels 9 - 13 */ + if (freq > 56160 + 2160 * 5) + return false; + + channelInfo->channel = (freq - 56160) / 2160 + 8; + channelInfo->op_class = 181; + break; + case Bandwidth::BW6480: + /* EDMG channels 17 - 20 */ + if (freq > 56160 + 2160 * 4) + return false; + + channelInfo->channel = (freq - 56160) / 2160 + 16; + channelInfo->op_class = 182; + break; + case Bandwidth::BW8640: + /* EDMG channels 25 - 27 */ + if (freq > 56160 + 2160 * 3) + return false; + + channelInfo->channel = (freq - 56160) / 2160 + 24; + channelInfo->op_class = 183; + break; + default: + return false; + } + + channelInfo->hardwareMode = HardwareMode::IEEE80211AD; + return true; + } + + return false; +} +// * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed +// * @NL80211_RRF_NO_CCK: CCK modulation not allowed +// * @NL80211_RRF_NO_INDOOR: indoor operation not allowed +// * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed +// * @NL80211_RRF_DFS: DFS support is required to be used +// * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links +// * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links +// * @NL80211_RRF_NO_IR: no mechanisms that initiate radiation are allowed, diff --git a/PiPedalCommon/src/RegDb.cpp b/PiPedalCommon/src/RegDb.cpp new file mode 100644 index 0000000..b057a2a --- /dev/null +++ b/PiPedalCommon/src/RegDb.cpp @@ -0,0 +1,642 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "RegDb.hpp" +#include "ss.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#define REGDB_MAGIC 0x52474442 +#define REGDB_VERSION 19 // pre-bookwork +#define REGDB_VERSION_2 20 // bookworm and later. + +using namespace pipedal; +using namespace std; + +static std::unique_ptr g_Instance; +RegDb&RegDb::GetInstance() +{ + if (!g_Instance) + { + g_Instance = std::make_unique(); + } + return *g_Instance; +} + +const WifiRegulations& RegDb::getWifiRegulations(const std::string&countryIso3661) const +{ + for (const auto ®ulation: this->regulations) + { + if (regulation.reg_alpha2 == countryIso3661) + { + return regulation; + } + } + throw std::runtime_error("Invalid country code."); +} + + +template +T NlSwap(T value) +{ + if constexpr (std::endian::native == std::endian::big) + { + return value; + } else { + auto value_rep = std::bit_cast,T >(value); + std::ranges::reverse(value_rep); + return std::bit_cast(value_rep); + } +} + +template +class BigEndian { +public: + BigEndian(): m_value(0) { } + explicit BigEndian(T value): m_value(NlSwap(value)) {} + T value() const { return NlSwap(m_value);} + bool operator==(const BigEndian&other) const { return m_value == other.m_value; } + explicit operator bool() const { return m_value != 0; } +private: + T m_value; +}; + +struct RegDbFileHeader19 +{ + uint32_t magic; + uint32_t version; + uint32_t countryOffset; + uint32_t countryCount; + uint32_t signatureLength; + + void toNs() + { + this->magic = NlSwap(this->magic); + this->version = NlSwap(this->version); + this->countryOffset = NlSwap(this->countryOffset); + this->countryCount = NlSwap(this->countryCount); + this->signatureLength = NlSwap(this->signatureLength); + } +}; + +struct CountryHeader +{ + char alpha2[2]; + uint8_t pad; + uint8_t dfsRegion; // first 2 bits only. + uint32_t rulesOffset; + + void toNs() + { + this->rulesOffset = NlSwap(rulesOffset); + } +}; + +struct Rule +{ + uint32_t frequencyRangeOffset; + uint32_t powerRuleOffset; + uint32_t flags; + + void toNs() + { + frequencyRangeOffset = NlSwap(frequencyRangeOffset); + powerRuleOffset = NlSwap(powerRuleOffset); + flags = NlSwap(flags); + } +}; + +struct RulesCollection19 +{ + uint32_t ruleCount; + uint32_t ruleOffsets[1]; + + void toNs() + { + this->ruleCount = NlSwap(this->ruleCount); + } + Rule*getRule( + uint32_t nRule, + char *pData + ) + { + uint32_t ruleOffset = NlSwap(ruleOffsets[nRule]); + return (Rule*)(pData+ruleOffset); + } +}; + + +struct FrequencyRange +{ + uint32_t startFrequency; // in khz. + uint32_t endFrequency; // in khz. + uint32_t maxBandwidth; // in khz. + void toNs() + { + startFrequency = NlSwap(startFrequency); + endFrequency = NlSwap(endFrequency); + maxBandwidth = NlSwap(maxBandwidth); + } +}; +struct PowerRule +{ + uint32_t maximumAntennaGain; + uint32_t maximumEirp; + void toNs() + { + maximumAntennaGain = NlSwap(maximumAntennaGain); + maximumEirp = NlSwap(maximumEirp); + } +}; + +const char *filePaths[] = + { + "/lib/firmware/regulatory.db", // bookworm, buster. + "/usr/lib/crda/regulatory.bin" // previous versions?. +}; + +static std::filesystem::path getFilePath() +{ + for (size_t i = 0; i < sizeof(filePaths) / sizeof(filePaths[0]); ++i) + { + std::filesystem::path path(filePaths[i]); + if (std::filesystem::exists(path)) + { + return path; + } + } + throw std::runtime_error("Could not find 'regulatory.bin' file."); +} + +RegDb::~RegDb() +{ +} + +RegDb::RegDb() + : RegDb(getFilePath()) +{ +} +RegDb::RegDb(const std::filesystem::path &path) +: pData(nullptr) +{ + ifstream f(path); + if (!f.is_open()) + { + stringstream s; + s << "Can't read " << path; + throw std::runtime_error(s.str()); + } + size_t fileSize = std::filesystem::file_size(path); + data.resize(fileSize); + f.read((char *)&data[0], fileSize); + if (!f) + { + stringstream s; + s << "Can't read " << path; + throw std::runtime_error(s.str()); + } + + RegDbFileHeader19 header = *(RegDbFileHeader19 *)ptr(); + header.toNs(); + + if (header.magic != REGDB_MAGIC) + { + throw std::runtime_error(SS("Invalid file format. " << path)); + } + if (header.version == 19) + { + Load19(); + } + else if (header.version == 20) + { + Load20(); + } + else + { + throw std::runtime_error(SS("Unknown file version. " << path)); + } +} +void RegDb::Load19() +{ + char *pData = (char *)ptr(); + RegDbFileHeader19 fileHeader = *(RegDbFileHeader19 *)ptr(); + fileHeader.toNs(); + + this->regulations.resize(0); + + CountryHeader *pCountryHeader = (CountryHeader *)(pData + fileHeader.countryOffset); + for (uint32_t i = 0; i < fileHeader.countryCount; ++i) + { + WifiRegulations wifiRegulations; + + + CountryHeader countryHeader = pCountryHeader[i]; + countryHeader.toNs(); + wifiRegulations.reg_alpha2 = SS(countryHeader.alpha2[0] << countryHeader.alpha2[1]); + wifiRegulations.dfs_region = (DfsRegion)(countryHeader.dfsRegion & 0x03); + + RulesCollection19 *pRules = (RulesCollection19 *)(pData + countryHeader.rulesOffset); + uint32_t ruleCount = NlSwap(pRules->ruleCount); + for (uint32_t nRule = 0; nRule < ruleCount; ++nRule) + { + Rule *pRule = pRules->getRule(nRule,pData); + Rule rule = *pRule; + rule.toNs(); + + FrequencyRange fr = *(FrequencyRange *)(pData + rule.frequencyRangeOffset); + fr.toNs(); + + PowerRule pr = *(PowerRule *)(pData + rule.powerRuleOffset); + pr.toNs(); + + WifiRule wifiRegulation; + wifiRegulation.flags = (RegRuleFlags)rule.flags; + wifiRegulation.start_freq_khz = fr.startFrequency; + wifiRegulation.end_freq_khz = fr.endFrequency; + wifiRegulation.max_bandwidth_khz = fr.maxBandwidth; + wifiRegulation.max_antenna_gain = pr.maximumAntennaGain; + wifiRegulation.max_eirp = pr.maximumEirp; + wifiRegulations.rules.push_back(wifiRegulation); + } + this->regulations.push_back(std::move(wifiRegulations)); + } + this->isValid = true; +} + +//////////////////////////////////////////////////////////////////////////////// +// glue +#define IEEE80211_NUM_ACS 4 // linux/ieee80211.h Number of hardware queues? + +#define __aligned(n) +#define __packed + +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; + +using __be32 = BigEndian; +using __be16 = BigEndian; +#define BIT(n) (1 << n) + +template +T ALIGN(T value,int bits) +{ + intptr_t v = (intptr_t)value; + + intptr_t mask = (1 << bits)-1; + v = (v + mask) & (~mask); + return (T)v; + +} + + +inline BigEndian cpu_to_be32(uint32_t value) +{ + return BigEndian(value); +} + +inline BigEndian cpu_to_be16(uint16_t value) +{ + return BigEndian(value); +} + + +inline uint16_t be16_to_cpu(const BigEndian&value) +{ + return value.value(); +} +inline uint32_t be32_to_cpu(const BigEndian&value) +{ + return value.value(); +} + +bool regdb_has_valid_signature(const u8 *data, unsigned int size) { return true; } + +#define offsetofend(TYPE,FIELD) ((uint32_t)(offsetof(TYPE,FIELD)+sizeof(((TYPE*)0)->FIELD))) +#define ASSERT_RTNL() // in the original, assert that rtnl is not locked. + +///////////////////////// +// shamelessly lifted from linux net/wireless/reg.c + +struct fwdb_country { + u8 alpha2[2]; + __be16 coll_ptr; + /* this struct cannot be extended */ +} __packed __aligned(4); + +struct fwdb_collection { + u8 len; + u8 n_rules; + u8 dfs_region; + /* no optional data yet */ + /* aligned to 2, then followed by __be16 array of rule pointers */ +} __packed __aligned(4); + +struct fwdb_header { + __be32 magic; + __be32 version; + struct fwdb_country country[]; +} __packed __aligned(4); + + +enum fwdb_flags { + FWDB_FLAG_NO_OFDM = BIT(0), + FWDB_FLAG_NO_OUTDOOR = BIT(1), + FWDB_FLAG_DFS = BIT(2), + FWDB_FLAG_NO_IR = BIT(3), + FWDB_FLAG_AUTO_BW = BIT(4), +}; + +struct fwdb_wmm_ac { + u8 ecw; + u8 aifsn; + __be16 cot; +} __packed; + +struct fwdb_wmm_rule { + struct fwdb_wmm_ac client[IEEE80211_NUM_ACS]; + struct fwdb_wmm_ac ap[IEEE80211_NUM_ACS]; +} __packed; + +struct fwdb_rule { + u8 len; + u8 flags; + __be16 max_eirp; + __be32 start, end, max_bw; + /* start of optional data */ + __be16 cac_timeout; + __be16 wmm_ptr; +} __packed __aligned(4); + +#define FWDB_MAGIC 0x52474442 +#define FWDB_VERSION 20 + + +static int ecw2cw(int ecw) +{ + return (1 << ecw) - 1; +} + +static bool valid_wmm(struct fwdb_wmm_rule *rule) +{ + struct fwdb_wmm_ac *ac = (struct fwdb_wmm_ac *)rule; + int i; + + for (i = 0; i < IEEE80211_NUM_ACS * 2; i++) { + u16 cw_min = ecw2cw((ac[i].ecw & 0xf0) >> 4); + u16 cw_max = ecw2cw(ac[i].ecw & 0x0f); + u8 aifsn = ac[i].aifsn; + + if (cw_min >= cw_max) + return false; + + if (aifsn < 1) + return false; + } + + return true; +} + +static bool valid_rule(const u8 *data, unsigned int size, u16 rule_ptr) +{ + struct fwdb_rule *rule = (fwdb_rule *)(data + (rule_ptr << 2)); + + if ((u8 *)rule + sizeof(rule->len) > data + size) + return false; + + /* mandatory fields */ + if (rule->len < offsetofend(struct fwdb_rule, max_bw)) + return false; + if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) { + u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2; + struct fwdb_wmm_rule *wmm; + + if (wmm_ptr + sizeof(struct fwdb_wmm_rule) > size) + return false; + + wmm = (fwdb_wmm_rule *)(data + wmm_ptr); + + if (!valid_wmm(wmm)) + return false; + } + return true; +} + + +static bool valid_country(const u8 *data, unsigned int size, + const struct fwdb_country *country) +{ + unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2; + struct fwdb_collection *coll = (struct fwdb_collection *)(data + ptr); + __be16 *rules_ptr; + unsigned int i; + + /* make sure we can read len/n_rules */ + if ((u8 *)coll + offsetofend(typeof(*coll), n_rules) > data + size) + return false; + + /* make sure base struct and all rules fit */ + if ((u8 *)coll + ALIGN(coll->len, 2) + + (coll->n_rules * 2) > data + size) + return false; + + /* mandatory fields must exist */ + if (coll->len < offsetofend(struct fwdb_collection, dfs_region)) + return false; + + rules_ptr = (__be16 *)((u8 *)coll + ALIGN(coll->len, 2)); + + for (i = 0; i < coll->n_rules; i++) { + u16 rule_ptr = be16_to_cpu(rules_ptr[i]); + + if (!valid_rule(data, size, rule_ptr)) + return false; + } + + return true; +} + + +static bool valid_regdb(const u8 *data, unsigned int size) +{ + const struct fwdb_header *hdr = (fwdb_header *)data; + const struct fwdb_country *country; + + if (size < sizeof(*hdr)) + return false; + + if (hdr->magic != cpu_to_be32(FWDB_MAGIC)) + return false; + + if (hdr->version != cpu_to_be32(FWDB_VERSION)) + return false; + + if (!regdb_has_valid_signature(data, size)) + return false; + + country = &hdr->country[0]; + while ((u8 *)(country + 1) <= data + size) { + if (!country->coll_ptr) + break; + if (!valid_country(data, size, country)) + return false; + country++; + } + + return true; +} + +static void set_wmm_rule(const struct fwdb_header *db, + const struct fwdb_country *country, + const struct fwdb_rule *rule, + WifiRule*rrule) +{ + // not implemented. + return; +} +// struct ieee80211_wmm_rule *wmm_rule = &rrule->wmm_rule; +// struct fwdb_wmm_rule *wmm; +// unsigned int i, wmm_ptr; + +// wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2; +// wmm = (fwdb_wmm_rule *)((u8 *)db + wmm_ptr); + +// if (!valid_wmm(wmm)) { +// std::cout +// << "Invalid regulatory WMM rule " +// << be32_to_cpu(rule->start) +// << "-" << be32_to_cpu(rule->end) +// << " in domain " << country->alpha2[0] << country->alpha2[1] +// << std::endl; +// return; +// } + +// for (i = 0; i < IEEE80211_NUM_ACS; i++) { +// wmm_rule->client[i].cw_min = +// ecw2cw((wmm->client[i].ecw & 0xf0) >> 4); +// wmm_rule->client[i].cw_max = ecw2cw(wmm->client[i].ecw & 0x0f); +// wmm_rule->client[i].aifsn = wmm->client[i].aifsn; +// wmm_rule->client[i].cot = +// 1000 * be16_to_cpu(wmm->client[i].cot); +// wmm_rule->ap[i].cw_min = ecw2cw((wmm->ap[i].ecw & 0xf0) >> 4); +// wmm_rule->ap[i].cw_max = ecw2cw(wmm->ap[i].ecw & 0x0f); +// wmm_rule->ap[i].aifsn = wmm->ap[i].aifsn; +// wmm_rule->ap[i].cot = 1000 * be16_to_cpu(wmm->ap[i].cot); +// } + +// rrule->has_wmm = true; +// } + + +static WifiRegulations regdb_load_country(const struct fwdb_header *db, + const struct fwdb_country *country) +{ + unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2; + struct fwdb_collection *coll = (fwdb_collection *)((u8 *)db + ptr); + unsigned int i; + + WifiRegulations wifiRegulations; + + wifiRegulations.reg_alpha2 = SS(country->alpha2[0] << country->alpha2[1]); + wifiRegulations.dfs_region = (DfsRegion)(coll->dfs_region); + unsigned int nRules = coll->n_rules; + + for (i = 0; i < nRules; i++) { + const __be16 *rules_ptr = (const __be16 *)((u8 *)coll + ALIGN(coll->len, 2)); + unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2; + struct fwdb_rule *rule = (fwdb_rule *)((u8 *)db + rule_ptr); + + WifiRule wifiRule; + wifiRule.start_freq_khz = be32_to_cpu(rule->start); + wifiRule.end_freq_khz = be32_to_cpu(rule->end); + wifiRule.max_bandwidth_khz = be32_to_cpu(rule->max_bw); + wifiRule.max_antenna_gain = 0; + wifiRule.max_eirp = be16_to_cpu(rule->max_eirp); + wifiRule.flags = RegRuleFlags::NONE; + + if (rule->flags & FWDB_FLAG_NO_OFDM) + wifiRule.flags |= RegRuleFlags::NO_OFDM; + if (rule->flags & FWDB_FLAG_NO_OUTDOOR) + wifiRule.flags |= RegRuleFlags::NO_OUTDOOR; + if (rule->flags & FWDB_FLAG_DFS) + wifiRule.flags |= RegRuleFlags::DFS; + if (rule->flags & FWDB_FLAG_NO_IR) + wifiRule.flags |= RegRuleFlags::NO_IR; + if (rule->flags & FWDB_FLAG_AUTO_BW) + wifiRule.flags |= RegRuleFlags::AUTO_BW; + + wifiRule.dfs_cac_ms = 0; + + /* handle optional data */ + if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout)) + wifiRule.dfs_cac_ms = + 1000 * be16_to_cpu(rule->cac_timeout); + // if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) + // set_wmm_rule(db, country, rule, &wifiRule); + wifiRegulations.rules.push_back(std::move(wifiRule)); + } + + return wifiRegulations; +} + + +static std::vector load_regdb(u8*pData) +{ + const struct fwdb_header *hdr = (const fwdb_header*)pData; + const struct fwdb_country *country; + + ASSERT_RTNL(); + if (!pData) + { + throw std::runtime_error("Regdb not loaded."); + } + std::vector result; + + country = &hdr->country[0]; + while (country->coll_ptr) { + result.push_back(regdb_load_country(hdr, country)); + country++; + } + return result; + +} + + +void RegDb::Load20() +{ + u8*data = (u8*)ptr(); + unsigned int size = (unsigned int)this->data.size(); + if (!valid_regdb(data,size)) + { + throw std::runtime_error("Invalid file format."); + + } + this->regulations = load_regdb(data); + this->isValid = true; +} \ No newline at end of file diff --git a/src/ServiceConfiguration.cpp b/PiPedalCommon/src/ServiceConfiguration.cpp similarity index 100% rename from src/ServiceConfiguration.cpp rename to PiPedalCommon/src/ServiceConfiguration.cpp diff --git a/src/SysExec.cpp b/PiPedalCommon/src/SysExec.cpp similarity index 53% rename from src/SysExec.cpp rename to PiPedalCommon/src/SysExec.cpp index 00d625e..e97cb41 100644 --- a/src/SysExec.cpp +++ b/PiPedalCommon/src/SysExec.cpp @@ -17,14 +17,21 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "pch.h" #include "SysExec.hpp" #include #include -#include "PiPedalException.hpp" +#include +#include #include #include +#include +#include #include // for PATH_MAX +#include +#include +#include "ss.hpp" +#include +#include using namespace pipedal; using namespace std; @@ -60,7 +67,7 @@ static std::filesystem::path findOnSystemPath(const std::string &command) } std::stringstream s; s << "'" << command << "' is not installed."; - throw PiPedalException(s.str()); + throw std::runtime_error(s.str()); } int pipedal::silentSysExec(const char *szCommand) @@ -113,7 +120,8 @@ int pipedal::sysExec(const char *szCommand) } if (!std::filesystem::exists(execPath)) { - throw PiPedalException(SS("Path does not exist: " << execPath << ".")); + free((void *)args); + throw std::runtime_error(SS("Path does not exist: " << execPath << ".")); } argv[0] = (char *)(execPath.c_str()); @@ -140,7 +148,122 @@ std::string pipedal::getSelfExePath() { char result[PATH_MAX+1]; ssize_t count = readlink("/proc/self/exe", result, PATH_MAX); - if (count < 0) throw PiPedalException("Can't find EXE path."); + if (count < 0) throw std::runtime_error("Can't find EXE path."); result[count] = 0; return result; -} \ No newline at end of file +} + +ProcessId pipedal::sysExecAsync(const std::string&command) +{ + char *args = strdup(command.c_str()); + int argc; + std::vector argv; + + char *p = args; + while (*p) + { + argv.push_back(p); + + while (*p && *p != ' ') + { + ++p; + } + if (*p) + { + *p++ = '\0'; + while (*p && *p == ' ') + { + ++p; + } + } + } + argv.push_back(nullptr); + + std::filesystem::path execPath = argv[0]; + if (execPath.is_relative()) + { + execPath = findOnSystemPath(execPath); + } + if (!std::filesystem::exists(execPath)) + { + free((void *)args); + throw std::runtime_error(SS("Path does not exist: " << execPath << ".")); + } + argv[0] = (char *)(execPath.c_str()); + + char **rawArgv = &argv[0]; + int pbPid; + + if ((pbPid = fork()) == 0) + { + // redirect output to /dev/null + int null_fd = open("/dev/null",O_WRONLY); + if (null_fd == -1) + { + std::cerr << "Failed to open /dev/null" << std::endl; + exit(EXIT_FAILURE); + } + dup2(null_fd,STDOUT_FILENO); + dup2(null_fd,STDERR_FILENO); + close(null_fd); + return execv(argv[0], rawArgv); + } + else + { + free((void *)args); + return pbPid; + } + +} + +void pipedal::sysExecTerminate(ProcessId pid_,int termTimeoutMs,int killTimeoutMs ) +{ + pid_t pid = (pid_t)pid_; + if (pid == -1) return; + if (kill(pid,SIGTERM) == -1) { + throw std::runtime_error("Failed to send SIGTERM"); + } + auto start = std::chrono::steady_clock::now(); + int status; + do { + pid_t result; + result = waitpid(pid,&status,WNOHANG); + if (result > 0) + { + return; + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } while ( + std::chrono::duration_cast( + std::chrono::steady_clock::now()-start).count() < termTimeoutMs + ); + start = std::chrono::steady_clock::now(); + if (kill(pid,SIGKILL) == -1) // some odd async effect? + { + return; + } + do { + pid_t result; + result = waitpid(pid,&status,WNOHANG); + if (result > 0) + { + return; + } + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } while ( + std::chrono::duration_cast( + std::chrono::steady_clock::now()-start).count() < killTimeoutMs + ); + + throw std::runtime_error("Failed to terminate process."); + +} +int pipedal::sysExecWait(ProcessId pid_) +{ + pid_t pid = (pid_t)pid_; + int returnValue; + waitpid(pid, &returnValue, 0); + int exitStatus = WEXITSTATUS(returnValue); + return exitStatus; + +} diff --git a/src/WifiConfigSettings.cpp b/PiPedalCommon/src/WifiConfigSettings.cpp similarity index 69% rename from src/WifiConfigSettings.cpp rename to PiPedalCommon/src/WifiConfigSettings.cpp index cdb886b..2ef58c5 100644 --- a/src/WifiConfigSettings.cpp +++ b/PiPedalCommon/src/WifiConfigSettings.cpp @@ -17,9 +17,10 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "pch.h" #include "WifiConfigSettings.hpp" #include +#include "ss.hpp" +#include "ChannelInfo.hpp" using namespace pipedal; using namespace std; @@ -43,8 +44,7 @@ bool WifiConfigSettings::ValidateCountryCode(const std::string&value) return true; } - -uint32_t pipedal::ChannelToWifiFrequency(const std::string &channel) +int32_t pipedal::ChannelToChannelNumber(const std::string&channel) { std::string t = channel; // remove dprecated band specs. @@ -52,6 +52,21 @@ uint32_t pipedal::ChannelToWifiFrequency(const std::string &channel) { t = t.substr(1); } + int32_t channelNumber = 1; + std::stringstream ss(t); + ss >> channelNumber; + return channelNumber; + +} + +static uint32_t ParseChannel(const std::string & channel) +{ + std::string t = channel; + // remove dprecated band specs. + if (t.size() > 1 && t[0] == 'a' || t[0] == 'g') + { + t = t.substr(1); + } size_t size = t.length(); unsigned long long lChannel = std::stoull(t,&size); @@ -59,7 +74,13 @@ uint32_t pipedal::ChannelToWifiFrequency(const std::string &channel) { throw invalid_argument("Expecting a number: '" + t + "'."); } - return ChannelToWifiFrequency((uint32_t)lChannel); + return (uint32_t)lChannel; +} + +uint32_t pipedal::ChannelToWifiFrequency(const std::string &channel_) +{ + uint32_t channel = ParseChannel(channel_); + return ChannelToWifiFrequency(channel); } uint32_t pipedal::ChannelToWifiFrequency(uint32_t channel) @@ -92,24 +113,43 @@ uint32_t pipedal::ChannelToWifiFrequency(uint32_t channel) { return 5500 + (channel-100)/5; } - throw invalid_argument(SS("Invalid channel: " << channel)); + throw invalid_argument(SS("Invalid WiFi channel: " << channel)); } -bool WifiConfigSettings::ValidateChannel(const std::string&value) +bool WifiConfigSettings::ValidateChannel(const std::string&countryCode,const std::string&value) { - // 1) frequency in khz. - // 2) unadorned channel number 1, 2,3 &c. - // 3) With band annotated: g1, a51. - try { - ChannelToWifiFrequency(value); - return true; - } catch (const std::string&/**/) + if (value == "0") // = "Autoselect". { - return false; + return true; } - // come back to this. + // 1) unadorned channel number 1, 2,3 &c. + // 2) With band annotated: g1, a51. + if (countryCode.empty()) + { + throw std::invalid_argument("Please supply a country code."); + } + if (countryCode.length() != 2) + { + throw std::invalid_argument(SS("Invalid country code: " << countryCode)); + } + auto regDom = getWifiRegClass(countryCode,ParseChannel(value),40); + if (regDom == -1) { + std::vector valid_channels = getValidChannels(countryCode,40); + std::stringstream ss; + ss << "Channel " << value << " is not permitted in the selected country.\n Valid channels: "; + bool first = true; + for (auto channel: valid_channels) + { + if (!first) ss << ", "; + first = false; + ss << channel; + } + throw invalid_argument(ss.str()); + } + + ChannelToWifiFrequency(value); return true; } @@ -135,10 +175,14 @@ bool WifiConfigSettings::ValidateChannel(const std::string&value) if (this->hotspotName_.length() < 1) throw invalid_argument("Hotspot name is too short."); if (this->password_.size() != 0 && this->password_.size() < 8) throw invalid_argument("Passphrase must be at least 8 characters long."); - if (!ValidateChannel(this->channel_)) + if (!ValidateChannel(this->countryCode_,this->channel_)) { throw invalid_argument("Channel is not valid."); } + + // validate that the channel number is supported for the given country code. + + this->valid_ = true; } diff --git a/src/WifiDirectConfigSettings.cpp b/PiPedalCommon/src/WifiDirectConfigSettings.cpp similarity index 88% rename from src/WifiDirectConfigSettings.cpp rename to PiPedalCommon/src/WifiDirectConfigSettings.cpp index b24d590..eb9c9ac 100644 --- a/src/WifiDirectConfigSettings.cpp +++ b/PiPedalCommon/src/WifiDirectConfigSettings.cpp @@ -20,6 +20,7 @@ // #include "pch.h" #include "WifiDirectConfigSettings.hpp" #include "P2pConfigFiles.hpp" +#include "ChannelInfo.hpp" #include "WifiConfigSettings.hpp" #include @@ -80,9 +81,10 @@ void WifiDirectConfigSettings::ParseArguments(const std::vector &ar this->enable_ = true; + Load(); + if (arguments.size() == 0) { - Load(); this->enable_ = true; } else { if (arguments.size() < 2 || arguments.size() > 4) @@ -91,12 +93,19 @@ void WifiDirectConfigSettings::ParseArguments(const std::vector &ar } this->countryCode_ = arguments[0]; this->hotspotName_ = arguments[1]; - this->pin_ = arguments.size() >= 3 ? arguments[2] : ""; - this->channel_ = arguments.size() >= 4? arguments[3]: ""; + if (arguments.size() >= 3) + { + this->pin_ = arguments[2]; + } + if (arguments.size() >= 4) { + this->channel_ = arguments[3]; + } } - if (this->channel_ == "") { + if (this->channel_ == "") + { this->channel_ = "1"; } + size_t maxLength = 32-string("DIRECT-XX-").length(); if (hotspotName_.size() >= maxLength) { throw invalid_argument("Device name is too long."); } if (hotspotName_.size() < 1) { throw invalid_argument("Device name is too short."); } @@ -109,9 +118,12 @@ void WifiDirectConfigSettings::ParseArguments(const std::vector &ar pin_ = MakePin(); } ValidatePin(pin_); // throws. - if (!WifiConfigSettings::ValidateChannel(channel_)) + + // validate that the channel number is supported for the given country code. + + if (!WifiConfigSettings::ValidateChannel(this->countryCode_,channel_)) { - throw invalid_argument("Invalid channel."); + throw invalid_argument(SS("Invalid WiFi channel: " << channel_)); } } @@ -134,6 +146,7 @@ void WifiDirectConfigSettings::Save() const map["ENABLED"] = this->enable_ ? "true": "false"; map["WIFI_GROUP_FREQUENCY"] = SS(ChannelToWifiFrequency(this->channel_)); map["INSTANCE_ID_FILE"] = DEVICE_GUID_FILE; + map["WLAN"] = this->wlan_; WriteTemplateFile(map, PIPEDAL_P2PD_CONF_PATH); @@ -149,6 +162,14 @@ void WifiDirectConfigSettings::Load() { this->enable_ = (strEnable == "true" || strEnable == "1"); } + std::string strWlan; + if (ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","wlan",&strWlan)) + { + this->wlan_ = strWlan; + } else { + this->wlan_ = "wlan0"; + } + if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_device_name",&this->hotspotName_)) diff --git a/PiPedalCommon/src/WifiRegs.cpp b/PiPedalCommon/src/WifiRegs.cpp new file mode 100644 index 0000000..3dd0273 --- /dev/null +++ b/PiPedalCommon/src/WifiRegs.cpp @@ -0,0 +1,153 @@ +// Copyright (c) 2024 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#include "WifiRegs.hpp" +#include "RegDb.hpp" +#include +#include "ss.hpp" +#include +#include +#include +#include "ChannelInfo.hpp" + +using namespace pipedal; + +static std::unique_ptr g_regDb; + +static std::unique_ptr g_wifiInfo; + + +struct RegMHzToChannel { + char band; + int32_t channel; + int32_t mhz; +}; + +static std::vector mhzToChannels = { +{'g', 1, 2412}, +{'g',2, 2417}, +{'g',3, 2422}, +{'g',4, 2427}, +{'g',5, 2432}, +{'g',6, 2437}, +{'g',7, 2442}, +{'g',8, 2447}, +{'g',9, 2452}, +{'g',10, 2457}, +{'g',11, 2462}, +{'g',12, 2467}, +{'g',13, 2472}, +{'g',14, 2484}, +{'a',7, 5035}, +{'a',8, 5040}, +{'a',9, 5045}, +{'a',11, 5055}, +{'a',12, 5060}, +{'a',16, 5080}, +{'a',32, 5160}, +{'a',34, 5170}, +{'a',36, 5180}, +{'a',38, 5190}, +{'a',40, 5200}, +{'a',42, 5210}, +{'a',44, 5220}, +{'a',46, 5230}, +{'a',48, 5240}, +{'a',50, 5250}, +{'a',52, 5260}, +{'a',54, 5270}, +{'a',56, 5280}, +{'a',58, 5290}, +{'a',60, 5300}, +{'a',62, 5310}, +{'a',64, 5320}, +{'a',68, 5340}, +{'a',96, 5480}, +{'a',100, 5500}, +{'a',102, 5510}, +{'a',104, 5520}, +{'a',106, 5530}, +{'a',108, 5540}, +{'a',110, 5550}, +{'a',112, 5560}, +{'a',114, 5570}, +{'a',116, 5580}, +{'a',118, 5590}, +{'a',120, 5600}, +{'a',122, 5610}, +{'a',124, 5620}, +{'a',126, 5630}, +{'a',128, 5640}, +{'a',132, 5660}, +{'a',134, 5670}, +{'a',136, 5680}, +{'a',138, 5690}, +{'a',140, 5700}, +{'a',142, 5710}, +{'a',144, 5720}, +{'a',149, 5745}, +{'a',151, 5755}, +{'a',153, 5765}, +{'a',155, 5775}, +{'a',157, 5785}, +{'a',159, 5795}, +{'a',161, 5805}, +{'a',163, 5815}, +{'a',165, 5825}, +{'a',167, 5835}, +{'a',169, 5845}, +{'a',171, 5855}, +{'a',173, 5865}, +{'a',175, 5875}, +{'a',177, 5885}, +{'a',180, 5900}, +{'a',182, 5910}, +{'a',18, 5915}, +{'a',184, 5920}, +{'a',187, 5935}, +{'a',188, 5940}, +{'a',189, 5945}, +{'a',192, 5960}, +{'a',196, 5980}, +}; + + +int32_t pipedal::wifiFrequencyToChannel(int32_t freqMHz) +{ + for (const auto&item: mhzToChannels) + { + if (std::abs(freqMHz == item.mhz) <= 1) + { + return item.channel; + } + } + return -1; +} + +int32_t pipedal::wifiChannelToFrequency(int32_t channel) +{ + for (const auto&item: mhzToChannels) + { + if (item.channel == channel) + { + return item.mhz; + } + } + return -1; +} diff --git a/PiPedalCommon/src/WifiRegulations.cpp b/PiPedalCommon/src/WifiRegulations.cpp new file mode 100644 index 0000000..9ba51bc --- /dev/null +++ b/PiPedalCommon/src/WifiRegulations.cpp @@ -0,0 +1,16 @@ +#include "WifiRegulations.hpp" + +using namespace pipedal; + +const WifiRule*WifiRegulations::GetRule(int32_t frequencyMhz) const +{ + int32_t frequencyKhz = frequencyMhz*1000; + + for (const auto&rule: rules) { + if (frequencyKhz >= rule.start_freq_khz && frequencyKhz < rule.end_freq_khz) + { + return &rule; + } + } + return nullptr; +} diff --git a/src/WriteTemplateFile.cpp b/PiPedalCommon/src/WriteTemplateFile.cpp similarity index 92% rename from src/WriteTemplateFile.cpp rename to PiPedalCommon/src/WriteTemplateFile.cpp index 942ca67..84720e0 100644 --- a/src/WriteTemplateFile.cpp +++ b/PiPedalCommon/src/WriteTemplateFile.cpp @@ -16,11 +16,11 @@ // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "pch.h" + #include "WriteTemplateFile.hpp" #include -#include "PiPedalException.hpp" +#include using namespace pipedal; @@ -42,7 +42,7 @@ void pipedal::WriteTemplateFile( if (!in.is_open()) { - throw PiPedalArgumentException("File not found: " + inputFile.string()); + throw std::runtime_error("File not found: " + inputFile.string()); } while (in.peek() != -1) @@ -64,7 +64,7 @@ void pipedal::WriteTemplateFile( } catch (const std::exception &) { - throw PiPedalException("Unexpected end of file. Expecting '}'."); + throw std::runtime_error("Unexpected end of file. Expecting '}'."); } std::string s = map.at(sName.str()); out << s; diff --git a/PiPedalCommon/src/include/ChannelInfo.hpp b/PiPedalCommon/src/include/ChannelInfo.hpp new file mode 100644 index 0000000..81ca348 --- /dev/null +++ b/PiPedalCommon/src/include/ChannelInfo.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +#include "WifiRegulations.hpp" +struct nl_sock; +struct nl_cache; +struct genl_family; + +namespace pipedal +{ + + WifiInfo getWifiInfo(const std::string&countryIso3661); + int32_t getWifiRegClass(const std::string &countryIso3661, int32_t channel,int32_t maxChannelWidthMhz); + std::vector getValidChannels(const std::string&countryIso3661,int32_t maxChannelWidthMhz); + + +} \ No newline at end of file diff --git a/src/ConfigSerializer.h b/PiPedalCommon/src/include/ConfigSerializer.hpp similarity index 100% rename from src/ConfigSerializer.h rename to PiPedalCommon/src/include/ConfigSerializer.hpp diff --git a/src/ConfigUtil.hpp b/PiPedalCommon/src/include/ConfigUtil.hpp similarity index 100% rename from src/ConfigUtil.hpp rename to PiPedalCommon/src/include/ConfigUtil.hpp diff --git a/PiPedalCommon/src/include/EnumFlags.hpp b/PiPedalCommon/src/include/EnumFlags.hpp new file mode 100644 index 0000000..ee4a6e4 --- /dev/null +++ b/PiPedalCommon/src/include/EnumFlags.hpp @@ -0,0 +1,60 @@ +#include + +#define ENABLE_ENUM_FLAGS(enum_type)\ +template<> struct enum_traits :\ + enum_traits<>::allow_bitops {};\ + + +template struct enum_traits {}; + +template<> struct enum_traits { + struct _allow_bitops { + static constexpr bool allow_bitops = true; + }; + using allow_bitops = _allow_bitops; + + template + using t = typename std::enable_if::value and + enum_traits::allow_bitops, R>::type; + + template + using u = typename std::underlying_type::type; +}; + +template +constexpr enum_traits<>::t operator~(T a) { + return static_cast(~static_cast::u>(a)); +} +template +constexpr enum_traits<>::t operator|(T a, T b) { + return static_cast( + static_cast::u>(a) | + static_cast::u>(b)); +} +template +constexpr enum_traits<>::t operator&(T a, T b) { + return static_cast( + static_cast::u>(a) & + static_cast::u>(b)); +} +template +constexpr enum_traits<>::t operator^(T a, T b) { + return static_cast( + static_cast::u>(a) ^ + static_cast::u>(b)); +} +template +constexpr enum_traits<>::t operator|=(T& a, T b) { + a = a | b; + return a; +} +template +constexpr enum_traits<>::t operator&=(T& a, T b) { + a = a & b; + return a; +} +template +constexpr enum_traits<>::t operator^=(T& a, T b) { + a = a ^ b; + return a; +} \ No newline at end of file diff --git a/src/HtmlHelper.hpp b/PiPedalCommon/src/include/HtmlHelper.hpp similarity index 100% rename from src/HtmlHelper.hpp rename to PiPedalCommon/src/include/HtmlHelper.hpp diff --git a/PiPedalCommon/src/include/NetLinkChannelInfo.hpp.bak b/PiPedalCommon/src/include/NetLinkChannelInfo.hpp.bak new file mode 100644 index 0000000..9853d8b --- /dev/null +++ b/PiPedalCommon/src/include/NetLinkChannelInfo.hpp.bak @@ -0,0 +1,52 @@ +/* +Copyright (c) 2007, 2008 Johannes Berg +Copyright (c) 2007 Andy Lutomirski +Copyright (c) 2007 Mike Kershaw +Copyright (c) 2008 Luis R. Rodriguez +Copyright (c) 2024 Robin Davies +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ +/* + Heavily based on code borrowed from iw (1) command. + https://kernel.googlesource.com/pub/scm/linux/kernel/git/jberg/iw/+/v0.9/COPYING +*/ + +#pragma once +#include +#include + +#include "WifiRegulations.hpp" +struct nl_sock; +struct nl_cache; +struct genl_family; + + +namespace pipedal +{ + + WifiInfo getWifiInfo(const char *phyName, const char *countryIso3661); + std::vector getWifiP2pInfo(const char *phyName, const char *countryIso3661); + +} \ No newline at end of file diff --git a/PiPedalCommon/src/include/NetLinkChannelInfo.hpp.x b/PiPedalCommon/src/include/NetLinkChannelInfo.hpp.x new file mode 100644 index 0000000..8e07521 --- /dev/null +++ b/PiPedalCommon/src/include/NetLinkChannelInfo.hpp.x @@ -0,0 +1,52 @@ +/* +Copyright (c) 2007, 2008 Johannes Berg +Copyright (c) 2007 Andy Lutomirski +Copyright (c) 2007 Mike Kershaw +Copyright (c) 2008 Luis R. Rodriguez +Copyright (c) 2024 Robin Davies +All rights reserved. + +Redistribution and use in sourcpe and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. +*/ +/* + Heavily based on code borrowed from iw (1) command. + https://kernel.googlesource.com/pub/scm/linux/kernel/git/jberg/iw/+/v0.9/COPYING +*/ + +#pragma once +#include +#include + +#include "WifiRegulations.hpp" +struct nl_sock; +struct nl_cache; +struct genl_family; + + +namespace pipedal +{ + + WifiInfo getWifiInfo(const char *phyName, const char *countryIso3661); + std::vector getWifiP2pInfo(const char *phyName, const char *countryIso3661); + +} \ No newline at end of file diff --git a/src/P2pConfigFiles.hpp b/PiPedalCommon/src/include/P2pConfigFiles.hpp similarity index 100% rename from src/P2pConfigFiles.hpp rename to PiPedalCommon/src/include/P2pConfigFiles.hpp diff --git a/PiPedalCommon/src/include/RegDb.hpp b/PiPedalCommon/src/include/RegDb.hpp new file mode 100644 index 0000000..6a27b02 --- /dev/null +++ b/PiPedalCommon/src/include/RegDb.hpp @@ -0,0 +1,75 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include +#include +#include +#include "WifiRegulations.hpp" +#include + +namespace pipedal +{ + + + + // struct FrequencyRule + // { + // uint32_t minFrequencyKHz; + // uint32_t maxFrequencyKhz; + // uint32_t maximumAntennaGain; // in mBiu (100*dBi) + // uint32_t maximumEirp; // in mBm (100*dBm) + // RegRuleFlags flags; + + // bool hasFlag(RegRuleFlags flag) const { return (((int)flag) & (int)this->flags) != 0; } + // }; + + + class RegDb + { + private: + friend class CrdbRules; + uint8_t *pData; + + public: + static RegDb&GetInstance(); + + RegDb(); + RegDb(const std::filesystem::path&path); // for testing only. + ~RegDb(); + + const std::vector&Regulations() const { return regulations;} + + bool IsValid() const { return isValid; } + + const WifiRegulations&getWifiRegulations(const std::string&countryIso3661) const; + + private: + bool isValid = false; + + std::vector data; + void *ptr() { return (void *)&(data[0]); } + void Load19(); + void Load20(); + + std::vector regulations; + }; + +} \ No newline at end of file diff --git a/src/ServiceConfiguration.hpp b/PiPedalCommon/src/include/ServiceConfiguration.hpp similarity index 98% rename from src/ServiceConfiguration.hpp rename to PiPedalCommon/src/include/ServiceConfiguration.hpp index eb70fbb..e437ec2 100644 --- a/src/ServiceConfiguration.hpp +++ b/PiPedalCommon/src/include/ServiceConfiguration.hpp @@ -25,7 +25,7 @@ #pragma once #include -#include "ConfigSerializer.h" +#include "ConfigSerializer.hpp" namespace pipedal { using namespace config_serializer; diff --git a/src/SysExec.hpp b/PiPedalCommon/src/include/SysExec.hpp similarity index 80% rename from src/SysExec.hpp rename to PiPedalCommon/src/include/SysExec.hpp index ca493af..1bacde5 100644 --- a/src/SysExec.hpp +++ b/PiPedalCommon/src/include/SysExec.hpp @@ -18,7 +18,7 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #pragma once - +#include namespace pipedal { // exec a command, returning the actual exit code (unlike execXX() or system() ) @@ -27,5 +27,13 @@ int sysExec(const char*szCommand); // execute a command, suppressing output. int silentSysExec(const char *szCommand); + +using ProcessId = int64_t; // platform-agnostic wrapper for pid_t; +// Returns a pid or -1 on errror. +ProcessId sysExecAsync(const std::string&command); + +void sysExecTerminate(ProcessId pid_,int termTimeoutMs = 1000,int killTimeoutMs = 500 ); // returns the process's exit status. +int sysExecWait(ProcessId pid); + std::string getSelfExePath(); } \ No newline at end of file diff --git a/src/WifiConfigSettings.hpp b/PiPedalCommon/src/include/WifiConfigSettings.hpp similarity index 92% rename from src/WifiConfigSettings.hpp rename to PiPedalCommon/src/include/WifiConfigSettings.hpp index aefde44..6c1315d 100644 --- a/src/WifiConfigSettings.hpp +++ b/PiPedalCommon/src/include/WifiConfigSettings.hpp @@ -26,6 +26,7 @@ namespace pipedal { uint32_t ChannelToWifiFrequency(const std::string &channel); uint32_t ChannelToWifiFrequency(uint32_t channel); + int32_t ChannelToChannelNumber(const std::string&channel); class WifiConfigSettings { public: @@ -41,8 +42,8 @@ namespace pipedal { std::string channel_ = "g6"; void ParseArguments(const std::vector &arguments); - static bool ValidateChannel(const std::string&value); static bool ValidateCountryCode(const std::string&value); + static bool ValidateChannel(const std::string&countryCode,const std::string&value); public: DECLARE_JSON_MAP(WifiConfigSettings); }; diff --git a/src/WifiDirectConfigSettings.hpp b/PiPedalCommon/src/include/WifiDirectConfigSettings.hpp similarity index 91% rename from src/WifiDirectConfigSettings.hpp rename to PiPedalCommon/src/include/WifiDirectConfigSettings.hpp index ef78f13..dd15adb 100644 --- a/src/WifiDirectConfigSettings.hpp +++ b/PiPedalCommon/src/include/WifiDirectConfigSettings.hpp @@ -33,11 +33,12 @@ namespace pipedal { bool valid_ = false; bool rebootRequired_ = false; bool enable_ = false; - std::string countryCode_ = "US"; // iso 3661 + std::string countryCode_ = ""; // iso 3661 std::string hotspotName_ = "pipedal"; bool pinChanged_ = false; std::string pin_; - std::string channel_ = "6"; + std::string channel_ = "0"; // "0" -> select automatically. + std::string wlan_ = "wlan0"; void ParseArguments(const std::vector &arguments); void Save() const; diff --git a/PiPedalCommon/src/include/WifiRegs.hpp b/PiPedalCommon/src/include/WifiRegs.hpp new file mode 100644 index 0000000..79d14d9 --- /dev/null +++ b/PiPedalCommon/src/include/WifiRegs.hpp @@ -0,0 +1,29 @@ +// Copyright (c) 2024 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +#pragma once +#include +#include + +namespace pipedal { + // returns frequency in MHz. + int32_t wifiChannelToFrequency(int32_t channel); + int32_t wifiFrequencyToChannel( + int32_t frequency // frequency in Mhz + ); +} \ No newline at end of file diff --git a/PiPedalCommon/src/include/WifiRegulations.hpp b/PiPedalCommon/src/include/WifiRegulations.hpp new file mode 100644 index 0000000..5a2bfc9 --- /dev/null +++ b/PiPedalCommon/src/include/WifiRegulations.hpp @@ -0,0 +1,137 @@ +#pragma once +#include +#include +#include +#include "EnumFlags.hpp" + + +namespace pipedal +{ + + enum class SecondaryChannelLocation + { + None, + Above, + Below + }; + + enum class WifiMode + { + IEEE80211G, + IEEE80211A, + IEEE80211B, + IEEE80211AD, + IEEE80211AX, + IEEE80211ANY, + }; + + enum class WifiBandwidth + { + BW20, + BW40MINUS, // g and a. + BW40PLUS, + BW40, // wifi 6 only. Must come after BW40PLUS, BW40MINUS. + BW80, + BW160, + BW80P80, + BW2160, + BW4320, + BW6480, + BW8640 + }; + + enum class DfsRegion + { + Unset = 0, + Fcc = 1, + Etsi = 2, + Japan = 3 + }; + + // sync with flags) != 0; + } + }; + + struct WifiRegulations + { + + std::string reg_alpha2; + DfsRegion dfs_region; + std::vector rules; + const WifiRule*GetRule(int32_t frequencyMhz) const; + }; + + struct WifiChannelInfo + { + int channelNumber = -1; + WifiMode hardwareMode; + int mhz = 0; + bool disabled = false; + bool ir = true; + bool radarDetection = false; + std::vector bitrates; + bool indoorOnly = false; + bool outdoorsOnly = false; + bool noHt40Minus = false; + bool noHt40Plus = false; + bool no10MHz = false; + bool no20MHz = false; + bool no80MHz = false; + bool no160MHz = false; + int32_t maxAntennaGain = 0; + int32_t maxEirp = 0; + WifiBandwidth bandwidth; + int32_t regDomain = -1; + }; + + struct WifiP2PChannelInfo : public WifiChannelInfo + { + }; + + struct WifiInfo + { + std::string reg_alpha2; + std::vector supportedIfTypes; + DfsRegion dfsRegion; + std::vector channels; + + const WifiChannelInfo *getChannelInfo(int channel) const; + }; + +} +ENABLE_ENUM_FLAGS(pipedal::RegRuleFlags) diff --git a/src/WriteTemplateFile.hpp b/PiPedalCommon/src/include/WriteTemplateFile.hpp similarity index 100% rename from src/WriteTemplateFile.hpp rename to PiPedalCommon/src/include/WriteTemplateFile.hpp diff --git a/src/autoptr_vector.h b/PiPedalCommon/src/include/autoptr_vector.h similarity index 100% rename from src/autoptr_vector.h rename to PiPedalCommon/src/include/autoptr_vector.h diff --git a/src/json.hpp b/PiPedalCommon/src/include/json.hpp similarity index 95% rename from src/json.hpp rename to PiPedalCommon/src/include/json.hpp index 8f270bd..57c37a0 100644 --- a/src/json.hpp +++ b/PiPedalCommon/src/include/json.hpp @@ -28,25 +28,25 @@ #include "HtmlHelper.hpp" #include #include -#include "PiPedalException.hpp" #include #include #include #include +#include #define DECLARE_JSON_MAP(CLASSNAME) \ - static json_map::storage_type jmap + static pipedal::json_map::storage_type jmap #define JSON_MAP_BEGIN(CLASSNAME) \ - json_map::storage_type CLASSNAME::jmap \ + pipedal::json_map::storage_type CLASSNAME::jmap \ { \ { #define JSON_MAP_REFERENCE(class, name) \ - json_map::reference(#name, &class ::name##_), + pipedal::json_map::reference(#name, &class ::name##_), #define JSON_MAP_REFERENCE_CONDITIONAL(class, name, conditionFn) \ - json_map::conditional_reference(#name, &class ::name##_, conditionFn), + pipedal::json_map::conditional_reference(#name, &class ::name##_, conditionFn), #define JSON_MAP_END() \ } \ @@ -55,7 +55,14 @@ namespace pipedal { - + class JsonException: public std::runtime_error { + public: + using base = std::runtime_error; + JsonException(const std::string&msg) + :base(msg) + { + } + }; // a function pointer of type bool (*)(const CLASS*,const MEMBER_TYPE&value) (because pre-C++ 20 templated function pointers are *hard*) template @@ -468,28 +475,28 @@ namespace pipedal os << "]"; } - template < - class Category, - class T, - class Distance = std::ptrdiff_t, - class Pointer = T *, - class Reference = T &> - void write(std::iterator &it) - { - start_array(); - bool first = true; - for (Reference ref : it) - { - if (!first) - { - os << ", "; - os << CRLF; - } - indent(); - os << ref; - } - end_array(); - } + // template < + // class Category, + // class T, + // class Distance = std::ptrdiff_t, + // class Pointer = T *, + // class Reference = T &> + // void write(std::iterator &it) + // { + // start_array(); + // bool first = true; + // for (Reference ref : it) + // { + // if (!first) + // { + // os << ", "; + // os << CRLF; + // } + // indent(); + // os << ref; + // } + // end_array(); + // } void write_json_member(const char *name, const char *json_text) { @@ -880,39 +887,39 @@ namespace pipedal skip_whitespace(); is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } void read(long *value) { is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } void read(long long *value) { skip_whitespace(); is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } void read(unsigned int *value) { is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } void read(unsigned long *value) { is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } void read(unsigned long long *value) { skip_whitespace(); is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } void read(float *value) @@ -929,7 +936,7 @@ namespace pipedal } is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } void read(double *value) { @@ -947,7 +954,7 @@ namespace pipedal is_ >> *value; if (is_.fail()) - throw PiPedalException("Invalid format."); + throw JsonException("Invalid format."); } template void read(std::vector *value) diff --git a/src/json_variant.hpp b/PiPedalCommon/src/include/json_variant.hpp similarity index 100% rename from src/json_variant.hpp rename to PiPedalCommon/src/include/json_variant.hpp diff --git a/src/util.hpp b/PiPedalCommon/src/include/util.hpp similarity index 100% rename from src/util.hpp rename to PiPedalCommon/src/include/util.hpp diff --git a/src/json.cpp b/PiPedalCommon/src/json.cpp similarity index 99% rename from src/json.cpp rename to PiPedalCommon/src/json.cpp index 2183aa1..ee6b163 100644 --- a/src/json.cpp +++ b/PiPedalCommon/src/json.cpp @@ -17,11 +17,9 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "pch.h" #include "json.hpp" #include #include -#include "PiPedalException.hpp" #include "json_variant.hpp" #include "util.hpp" using namespace pipedal; @@ -630,7 +628,7 @@ void json_reader::throw_format_error(const char*error) } s << "'."; std::string message = s.str(); - throw PiPedalException(message); + throw JsonException(message); } diff --git a/src/json_variant.cpp b/PiPedalCommon/src/json_variant.cpp similarity index 100% rename from src/json_variant.cpp rename to PiPedalCommon/src/json_variant.cpp diff --git a/PiPedalCommon/src/ss.hpp b/PiPedalCommon/src/ss.hpp new file mode 100644 index 0000000..6b34c10 --- /dev/null +++ b/PiPedalCommon/src/ss.hpp @@ -0,0 +1,26 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#pragma once + +#include +#include + +// usage: SS("xyz" << 123 << 45.6) returning a std::string rvalue. +#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str()) diff --git a/src/util.cpp b/PiPedalCommon/src/util.cpp similarity index 100% rename from src/util.cpp rename to PiPedalCommon/src/util.cpp diff --git a/README.md b/README.md index cab643e..373ed9b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@
-Download: v1.1.31 +Download: v1.2.31 Website: [https://rerdavies.github.io/pipedal](https://rerdavies.github.io/pipedal). -> NEW version 1.1.39 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +> NEW version 1.2.32 beta1 release, providing support for Raspberry Pi OS Bookworm. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet. PiPedal running on a Raspberry Pi 4 provides stable super-low-latency audio via external USB audio devices, or internal Raspberry Pi audio hats. diff --git a/configuration_notes.txt b/configuration_notes.txt deleted file mode 100644 index 610f501..0000000 --- a/configuration_notes.txt +++ /dev/null @@ -1,23 +0,0 @@ - -https://raspberrypi.stackexchange.com/questions/119026/connect-to-wifi-access-point-repeater-when-uplink-is-not-present/119178#119178?newreg=1aefd433cbd64cd4aaadbd0557d59391 - - -/etc/wpa_supplicant/wpa_supplicant.conf: - -add - - p2p_disable=1 - -Delete the network - - - -/etc/dnsmasq.d/dnsmasq.config - -Remove server= line. - -Add 172.24.1.1 piddle to /etc/hosts - - - - diff --git a/debian/control b/debian/control index 05a675f..76dfce6 100644 --- a/debian/control +++ b/debian/control @@ -9,6 +9,6 @@ Package: pipedal Pre-Depends: hostapd;authbind;dnsmasq Priority: optional Section: sound -Version: 1.1.31 +Version: 1.2.32 Installed-Size: 15147 diff --git a/default_presets/presets/Default+Bank.bank b/default_presets/presets/Default+Bank.bank index 172ec14..322eb90 100644 --- a/default_presets/presets/Default+Bank.bank +++ b/default_presets/presets/Default+Bank.bank @@ -1 +1,1487 @@ -{"name": "","nextInstanceId": 20,"selectedPreset": 15,"presets": [{"instanceId": 13,"preset": {"name": "Jazz","input_volume_db": 0,"output_volume_db": 0,"items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -49.1093903},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 18,"uri": "http://two-play.com/plugins/toob-tone-stack","isEnabled": true,"controlValues": [{"key": "bass","value": 0.11666666},{"key": "mid","value": 0.5},{"key": "treble","value": 0.283333331},{"key": "ampmodel","value": 1}],"pluginName": "TooB Tone Stack","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 30,"uri": "http://two-play.com/plugins/toob-power-stage-2","isEnabled": true,"controlValues": [{"key": "trim1","value": 0},{"key": "locut1","value": 30},{"key": "hicut1","value": 19000},{"key": "shape1","value": 0},{"key": "gain1","value": 0.458333343},{"key": "bias1","value": 0},{"key": "trim2","value": 0},{"key": "locut2","value": 30},{"key": "hicut2","value": 19000},{"key": "shape2","value": 0},{"key": "gain2","value": 0.383333325},{"key": "bias2","value": 0},{"key": "gain2_enable","value": 1},{"key": "trim3","value": 0},{"key": "locut3","value": 30},{"key": "hicut3","value": 19000},{"key": "shape3","value": 0},{"key": "gain3","value": 0},{"key": "bias3","value": 0},{"key": "gain3_enable","value": 1},{"key": "sag","value": 0.316666663},{"key": "sagd","value": 0.325000018},{"key": "master","value": -12.75},{"key": "sagf","value": 13}],"pluginName": "TooB Power Stage","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 20,"uri": "http://two-play.com/plugins/toob-cab-sim","isEnabled": true,"controlValues": [{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "comb","value": 0},{"key": "combf","value": 2000},{"key": "trim","value": 0}],"pluginName": "TooB Cab Simulator","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 33,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 12},{"key": "feedback","value": 39}],"pluginName": "TooB Delay","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": false,"controlValues": [{"key": "dryWet","value": 0.300000012},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.491666675}],"pluginName": "TooB Freeverb","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]}],"nextInstanceId": 33}},{"instanceId": 15,"preset": {"name": "Jazz ML","input_volume_db": 0,"output_volume_db": 0,"items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 37,"uri": "uri://two-play/pipedal/pedalboard#Empty","isEnabled": true,"controlValues": [ ],"pluginName": "","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 38,"uri": "uri://two-play/pipedal/pedalboard#Empty","isEnabled": true,"controlValues": [ ],"pluginName": "","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "bass","value": 0.5},{"key": "mid","value": 0.5},{"key": "treble","value": 0.5},{"key": "model","value": 0},{"key": "gain","value": 3},{"key": "master","value": 0}],"pluginName": "TooB ML Amplifier","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 35,"uri": "uri://two-play/pipedal/pedalboard#Empty","isEnabled": true,"controlValues": [ ],"pluginName": "","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]}],"nextInstanceId": 39}},{"instanceId": 17,"preset": {"name": "Sparkling Clean","input_volume_db": 0,"output_volume_db": 0,"items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 27},{"key": "feedback","value": 39}],"pluginName": "TooB Delay","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": -3},{"key": "bass","value": 0.650000036},{"key": "mid","value": 0.5},{"key": "treble","value": 0.550000012},{"key": "model","value": 19},{"key": "gain","value": 0},{"key": "master","value": 1.5}],"pluginName": "TooB ML Amplifier","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]}],"nextInstanceId": 45}},{"instanceId": 18,"preset": {"name": "Light Crunch","input_volume_db": 0,"output_volume_db": 0,"items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -80},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 27},{"key": "feedback","value": 39}],"pluginName": "TooB Delay","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 2.5},{"key": "bass","value": 0.650000036},{"key": "mid","value": 0.5},{"key": "treble","value": 0.266666681},{"key": "model","value": 17},{"key": "gain","value": 0},{"key": "master","value": 2}],"pluginName": "TooB ML Amplifier","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]}],"nextInstanceId": 45}},{"instanceId": 19,"preset": {"name": "Heavy","input_volume_db": 0,"output_volume_db": 0,"items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -23.1093884},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": 0},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -65.5},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 27},{"key": "feedback","value": 39.1666679}],"pluginName": "TooB Delay","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 2.5},{"key": "bass","value": 0.650000036},{"key": "mid","value": 0.5},{"key": "treble","value": 0.266666681},{"key": "model","value": 18},{"key": "gain","value": 0},{"key": "master","value": -10}],"pluginName": "TooB ML Amplifier","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.150000006},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]}],"nextInstanceId": 45}},{"instanceId": 20,"preset": {"name": "Scream","input_volume_db": 0,"output_volume_db": 0,"items": [{"instanceId": 16,"uri": "http://two-play.com/plugins/toob-tuner","isEnabled": true,"controlValues": [{"key": "REFFREQ","value": 440},{"key": "THRESHOLD","value": -54},{"key": "MUTE","value": 0}],"pluginName": "TooB Tuner","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 17,"uri": "http://two-play.com/plugins/toob-input_stage","isEnabled": true,"controlValues": [{"key": "trim","value": -15.75},{"key": "locut","value": 120},{"key": "bright","value": 0},{"key": "brightf","value": 1300},{"key": "hicut","value": 6000},{"key": "gate_t","value": -64.5},{"key": "boost","value": 0}],"pluginName": "TooB Input Stage","midiBindings": [{"channel": -1,"symbol": "__bypass","bindingType": 2,"note": 72,"control": 4,"minValue": 0,"maxValue": 1,"rotaryScale": 1,"linearControlType": 0,"switchControlType": 0}],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 47,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 12.5},{"key": "model","value": 29},{"key": "gain","value": 3},{"key": "master","value": 6.5},{"key": "bass","value": 0.5},{"key": "mid","value": 0.5},{"key": "treble","value": 0.5}],"pluginName": "TooB ML Amplifier","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 42,"uri": "http://two-play.com/plugins/toob-chorus","isEnabled": false,"controlValues": [{"key": "rate","value": 0.291666657},{"key": "depth","value": 0.375}],"pluginName": "TooB CE-2 Chorus","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 41,"uri": "http://two-play.com/plugins/toob-delay","isEnabled": true,"controlValues": [{"key": "delay","value": 340},{"key": "level","value": 10.333333},{"key": "feedback","value": 39.1666679}],"pluginName": "TooB Delay","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 39,"uri": "http://two-play.com/plugins/toob-ml","isEnabled": true,"controlValues": [{"key": "trim","value": 2.5},{"key": "bass","value": 0.5},{"key": "mid","value": 0.5},{"key": "treble","value": 0.5},{"key": "model","value": 12},{"key": "gain","value": 10},{"key": "master","value": -10}],"pluginName": "TooB ML Amplifier","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]},{"instanceId": 31,"uri": "http://two-play.com/plugins/toob-freeverb","isEnabled": true,"controlValues": [{"key": "dryWet","value": 0.0416666716},{"key": "roomSize","value": 0.625},{"key": "damping","value": 0.574999988}],"pluginName": "TooB Freeverb","midiBindings": [ ],"stateUpdateCount": 0,"lv2State": [false,{}]}],"nextInstanceId": 47}}]} \ No newline at end of file +{ + "name": "", + "nextInstanceId": 21, + "selectedPreset": 15, + "presets": [ + { + "instanceId": 13, + "preset": { + "name": "Jazz", + "input_volume_db": 0, + "output_volume_db": 0, + "items": [ + { + "instanceId": 16, + "uri": "http://two-play.com/plugins/toob-tuner", + "isEnabled": true, + "controlValues": [ + { + "key": "REFFREQ", + "value": 440 + }, + { + "key": "THRESHOLD", + "value": -49.1093903 + }, + { + "key": "MUTE", + "value": 0 + } + ], + "pluginName": "TooB Tuner", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 17, + "uri": "http://two-play.com/plugins/toob-input_stage", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 0 + }, + { + "key": "locut", + "value": 120 + }, + { + "key": "bright", + "value": 0 + }, + { + "key": "brightf", + "value": 1300 + }, + { + "key": "hicut", + "value": 6000 + }, + { + "key": "gate_t", + "value": -80 + }, + { + "key": "boost", + "value": 0 + } + ], + "pluginName": "TooB Input Stage", + "midiBindings": [ + { + "channel": -1, + "symbol": "__bypass", + "bindingType": 2, + "note": 72, + "control": 4, + "minValue": 0, + "maxValue": 1, + "rotaryScale": 1, + "linearControlType": 0, + "switchControlType": 0 + } + ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 18, + "uri": "http://two-play.com/plugins/toob-tone-stack", + "isEnabled": true, + "controlValues": [ + { + "key": "bass", + "value": 0.11666666 + }, + { + "key": "mid", + "value": 0.5 + }, + { + "key": "treble", + "value": 0.283333331 + }, + { + "key": "ampmodel", + "value": 1 + } + ], + "pluginName": "TooB Tone Stack", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 30, + "uri": "http://two-play.com/plugins/toob-power-stage-2", + "isEnabled": true, + "controlValues": [ + { + "key": "trim1", + "value": 0 + }, + { + "key": "locut1", + "value": 30 + }, + { + "key": "hicut1", + "value": 19000 + }, + { + "key": "shape1", + "value": 0 + }, + { + "key": "gain1", + "value": 0.458333343 + }, + { + "key": "bias1", + "value": 0 + }, + { + "key": "trim2", + "value": 0 + }, + { + "key": "locut2", + "value": 30 + }, + { + "key": "hicut2", + "value": 19000 + }, + { + "key": "shape2", + "value": 0 + }, + { + "key": "gain2", + "value": 0.383333325 + }, + { + "key": "bias2", + "value": 0 + }, + { + "key": "gain2_enable", + "value": 1 + }, + { + "key": "trim3", + "value": 0 + }, + { + "key": "locut3", + "value": 30 + }, + { + "key": "hicut3", + "value": 19000 + }, + { + "key": "shape3", + "value": 0 + }, + { + "key": "gain3", + "value": 0 + }, + { + "key": "bias3", + "value": 0 + }, + { + "key": "gain3_enable", + "value": 1 + }, + { + "key": "sag", + "value": 0.316666663 + }, + { + "key": "sagd", + "value": 0.325000018 + }, + { + "key": "master", + "value": -12.75 + }, + { + "key": "sagf", + "value": 13 + } + ], + "pluginName": "TooB Power Stage", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 20, + "uri": "http://two-play.com/plugins/toob-cab-sim", + "isEnabled": true, + "controlValues": [ + { + "key": "locut", + "value": 120 + }, + { + "key": "bright", + "value": 0 + }, + { + "key": "brightf", + "value": 1300 + }, + { + "key": "hicut", + "value": 6000 + }, + { + "key": "comb", + "value": 0 + }, + { + "key": "combf", + "value": 2000 + }, + { + "key": "trim", + "value": 0 + } + ], + "pluginName": "TooB Cab Simulator", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 33, + "uri": "http://two-play.com/plugins/toob-delay", + "isEnabled": true, + "controlValues": [ + { + "key": "delay", + "value": 340 + }, + { + "key": "level", + "value": 12 + }, + { + "key": "feedback", + "value": 39 + } + ], + "pluginName": "TooB Delay", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 31, + "uri": "http://two-play.com/plugins/toob-freeverb", + "isEnabled": false, + "controlValues": [ + { + "key": "dryWet", + "value": 0.300000012 + }, + { + "key": "roomSize", + "value": 0.625 + }, + { + "key": "damping", + "value": 0.491666675 + } + ], + "pluginName": "TooB Freeverb", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + } + ], + "nextInstanceId": 33 + } + }, + { + "instanceId": 15, + "preset": { + "name": "Jazz ML", + "input_volume_db": 0, + "output_volume_db": 0, + "items": [ + { + "instanceId": 16, + "uri": "http://two-play.com/plugins/toob-tuner", + "isEnabled": true, + "controlValues": [ + { + "key": "REFFREQ", + "value": 440 + }, + { + "key": "THRESHOLD", + "value": -23.1093884 + }, + { + "key": "MUTE", + "value": 0 + } + ], + "pluginName": "TooB Tuner", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 17, + "uri": "http://two-play.com/plugins/toob-input_stage", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 0 + }, + { + "key": "locut", + "value": 120 + }, + { + "key": "bright", + "value": 0 + }, + { + "key": "brightf", + "value": 1300 + }, + { + "key": "hicut", + "value": 6000 + }, + { + "key": "gate_t", + "value": -80 + }, + { + "key": "boost", + "value": 0 + } + ], + "pluginName": "TooB Input Stage", + "midiBindings": [ + { + "channel": -1, + "symbol": "__bypass", + "bindingType": 2, + "note": 72, + "control": 4, + "minValue": 0, + "maxValue": 1, + "rotaryScale": 1, + "linearControlType": 0, + "switchControlType": 0 + } + ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 41, + "uri": "http://two-play.com/plugins/toob-chorus", + "isEnabled": false, + "controlValues": [ + { + "key": "rate", + "value": 0.5 + }, + { + "key": "depth", + "value": 0.5 + } + ], + "pluginName": "TooB CE-2 Chorus", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 39, + "uri": "http://two-play.com/plugins/toob-ml", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 0 + }, + { + "key": "bass", + "value": 0.5 + }, + { + "key": "mid", + "value": 0.5 + }, + { + "key": "treble", + "value": 0.5 + }, + { + "key": "model", + "value": 0 + }, + { + "key": "gain", + "value": 3 + }, + { + "key": "master", + "value": 0 + }, + { + "key": "sag", + "value": 0 + }, + { + "key": "sagd", + "value": 0 + }, + { + "key": "sagf", + "value": 13 + } + ], + "pluginName": "TooB ML Amplifier", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 31, + "uri": "http://two-play.com/plugins/toob-freeverb", + "isEnabled": true, + "controlValues": [ + { + "key": "dryWet", + "value": 0.150000006 + }, + { + "key": "roomSize", + "value": 0.625 + }, + { + "key": "damping", + "value": 0.574999988 + } + ], + "pluginName": "TooB Freeverb", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + } + ], + "nextInstanceId": 41 + } + }, + { + "instanceId": 17, + "preset": { + "name": "Sparkling Clean", + "input_volume_db": 0, + "output_volume_db": 0, + "items": [ + { + "instanceId": 16, + "uri": "http://two-play.com/plugins/toob-tuner", + "isEnabled": true, + "controlValues": [ + { + "key": "REFFREQ", + "value": 440 + }, + { + "key": "THRESHOLD", + "value": -23.1093884 + }, + { + "key": "MUTE", + "value": 0 + } + ], + "pluginName": "TooB Tuner", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 17, + "uri": "http://two-play.com/plugins/toob-input_stage", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 0 + }, + { + "key": "locut", + "value": 120 + }, + { + "key": "bright", + "value": 0 + }, + { + "key": "brightf", + "value": 1300 + }, + { + "key": "hicut", + "value": 6000 + }, + { + "key": "gate_t", + "value": -80 + }, + { + "key": "boost", + "value": 0 + } + ], + "pluginName": "TooB Input Stage", + "midiBindings": [ + { + "channel": -1, + "symbol": "__bypass", + "bindingType": 2, + "note": 72, + "control": 4, + "minValue": 0, + "maxValue": 1, + "rotaryScale": 1, + "linearControlType": 0, + "switchControlType": 0 + } + ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 42, + "uri": "http://two-play.com/plugins/toob-chorus", + "isEnabled": false, + "controlValues": [ + { + "key": "rate", + "value": 0.291666657 + }, + { + "key": "depth", + "value": 0.375 + } + ], + "pluginName": "TooB CE-2 Chorus", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 41, + "uri": "http://two-play.com/plugins/toob-delay", + "isEnabled": true, + "controlValues": [ + { + "key": "delay", + "value": 340 + }, + { + "key": "level", + "value": 27 + }, + { + "key": "feedback", + "value": 39 + } + ], + "pluginName": "TooB Delay", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 39, + "uri": "http://two-play.com/plugins/toob-ml", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": -3 + }, + { + "key": "bass", + "value": 0.650000036 + }, + { + "key": "mid", + "value": 0.5 + }, + { + "key": "treble", + "value": 0.550000012 + }, + { + "key": "model", + "value": 19 + }, + { + "key": "gain", + "value": 0 + }, + { + "key": "master", + "value": 1.5 + } + ], + "pluginName": "TooB ML Amplifier", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 31, + "uri": "http://two-play.com/plugins/toob-freeverb", + "isEnabled": true, + "controlValues": [ + { + "key": "dryWet", + "value": 0.150000006 + }, + { + "key": "roomSize", + "value": 0.625 + }, + { + "key": "damping", + "value": 0.574999988 + } + ], + "pluginName": "TooB Freeverb", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + } + ], + "nextInstanceId": 45 + } + }, + { + "instanceId": 18, + "preset": { + "name": "Light Crunch", + "input_volume_db": 0, + "output_volume_db": 0, + "items": [ + { + "instanceId": 16, + "uri": "http://two-play.com/plugins/toob-tuner", + "isEnabled": true, + "controlValues": [ + { + "key": "REFFREQ", + "value": 440 + }, + { + "key": "THRESHOLD", + "value": -23.1093884 + }, + { + "key": "MUTE", + "value": 0 + } + ], + "pluginName": "TooB Tuner", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 17, + "uri": "http://two-play.com/plugins/toob-input_stage", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 0 + }, + { + "key": "locut", + "value": 120 + }, + { + "key": "bright", + "value": 0 + }, + { + "key": "brightf", + "value": 1300 + }, + { + "key": "hicut", + "value": 6000 + }, + { + "key": "gate_t", + "value": -80 + }, + { + "key": "boost", + "value": 0 + } + ], + "pluginName": "TooB Input Stage", + "midiBindings": [ + { + "channel": -1, + "symbol": "__bypass", + "bindingType": 2, + "note": 72, + "control": 4, + "minValue": 0, + "maxValue": 1, + "rotaryScale": 1, + "linearControlType": 0, + "switchControlType": 0 + } + ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 42, + "uri": "http://two-play.com/plugins/toob-chorus", + "isEnabled": false, + "controlValues": [ + { + "key": "rate", + "value": 0.291666657 + }, + { + "key": "depth", + "value": 0.375 + } + ], + "pluginName": "TooB CE-2 Chorus", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 41, + "uri": "http://two-play.com/plugins/toob-delay", + "isEnabled": true, + "controlValues": [ + { + "key": "delay", + "value": 340 + }, + { + "key": "level", + "value": 27 + }, + { + "key": "feedback", + "value": 39 + } + ], + "pluginName": "TooB Delay", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 39, + "uri": "http://two-play.com/plugins/toob-ml", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 2.5 + }, + { + "key": "bass", + "value": 0.650000036 + }, + { + "key": "mid", + "value": 0.5 + }, + { + "key": "treble", + "value": 0.266666681 + }, + { + "key": "model", + "value": 17 + }, + { + "key": "gain", + "value": 0 + }, + { + "key": "master", + "value": 2 + } + ], + "pluginName": "TooB ML Amplifier", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 31, + "uri": "http://two-play.com/plugins/toob-freeverb", + "isEnabled": true, + "controlValues": [ + { + "key": "dryWet", + "value": 0.150000006 + }, + { + "key": "roomSize", + "value": 0.625 + }, + { + "key": "damping", + "value": 0.574999988 + } + ], + "pluginName": "TooB Freeverb", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + } + ], + "nextInstanceId": 45 + } + }, + { + "instanceId": 19, + "preset": { + "name": "Heavy", + "input_volume_db": 0, + "output_volume_db": 0, + "items": [ + { + "instanceId": 16, + "uri": "http://two-play.com/plugins/toob-tuner", + "isEnabled": true, + "controlValues": [ + { + "key": "REFFREQ", + "value": 440 + }, + { + "key": "THRESHOLD", + "value": -23.1093884 + }, + { + "key": "MUTE", + "value": 0 + } + ], + "pluginName": "TooB Tuner", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 17, + "uri": "http://two-play.com/plugins/toob-input_stage", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 0 + }, + { + "key": "locut", + "value": 120 + }, + { + "key": "bright", + "value": 0 + }, + { + "key": "brightf", + "value": 1300 + }, + { + "key": "hicut", + "value": 6000 + }, + { + "key": "gate_t", + "value": -65.5 + }, + { + "key": "boost", + "value": 0 + } + ], + "pluginName": "TooB Input Stage", + "midiBindings": [ + { + "channel": -1, + "symbol": "__bypass", + "bindingType": 2, + "note": 72, + "control": 4, + "minValue": 0, + "maxValue": 1, + "rotaryScale": 1, + "linearControlType": 0, + "switchControlType": 0 + } + ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 42, + "uri": "http://two-play.com/plugins/toob-chorus", + "isEnabled": false, + "controlValues": [ + { + "key": "rate", + "value": 0.291666657 + }, + { + "key": "depth", + "value": 0.375 + } + ], + "pluginName": "TooB CE-2 Chorus", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 41, + "uri": "http://two-play.com/plugins/toob-delay", + "isEnabled": true, + "controlValues": [ + { + "key": "delay", + "value": 340 + }, + { + "key": "level", + "value": 27 + }, + { + "key": "feedback", + "value": 39.1666679 + } + ], + "pluginName": "TooB Delay", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 39, + "uri": "http://two-play.com/plugins/toob-ml", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 2.5 + }, + { + "key": "bass", + "value": 0 + }, + { + "key": "mid", + "value": 0.5 + }, + { + "key": "treble", + "value": 0.266666681 + }, + { + "key": "model", + "value": 18 + }, + { + "key": "gain", + "value": 0 + }, + { + "key": "master", + "value": -10 + }, + { + "key": "sag", + "value": 0 + }, + { + "key": "sagd", + "value": 0 + }, + { + "key": "sagf", + "value": 13 + } + ], + "pluginName": "TooB ML Amplifier", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 31, + "uri": "http://two-play.com/plugins/toob-freeverb", + "isEnabled": true, + "controlValues": [ + { + "key": "dryWet", + "value": 0.150000006 + }, + { + "key": "roomSize", + "value": 0.625 + }, + { + "key": "damping", + "value": 0.574999988 + } + ], + "pluginName": "TooB Freeverb", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + } + ], + "nextInstanceId": 45 + } + }, + { + "instanceId": 20, + "preset": { + "name": "Scream", + "input_volume_db": 0, + "output_volume_db": 0, + "items": [ + { + "instanceId": 16, + "uri": "http://two-play.com/plugins/toob-tuner", + "isEnabled": true, + "controlValues": [ + { + "key": "REFFREQ", + "value": 440 + }, + { + "key": "THRESHOLD", + "value": -54 + }, + { + "key": "MUTE", + "value": 0 + } + ], + "pluginName": "TooB Tuner", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 17, + "uri": "http://two-play.com/plugins/toob-input_stage", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": -15.75 + }, + { + "key": "locut", + "value": 120 + }, + { + "key": "bright", + "value": 0 + }, + { + "key": "brightf", + "value": 1300 + }, + { + "key": "hicut", + "value": 6000 + }, + { + "key": "gate_t", + "value": -64.5 + }, + { + "key": "boost", + "value": 0 + } + ], + "pluginName": "TooB Input Stage", + "midiBindings": [ + { + "channel": -1, + "symbol": "__bypass", + "bindingType": 2, + "note": 72, + "control": 4, + "minValue": 0, + "maxValue": 1, + "rotaryScale": 1, + "linearControlType": 0, + "switchControlType": 0 + } + ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 47, + "uri": "http://two-play.com/plugins/toob-ml", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 12.5 + }, + { + "key": "model", + "value": 29 + }, + { + "key": "gain", + "value": 3 + }, + { + "key": "master", + "value": 6.5 + }, + { + "key": "bass", + "value": 0.5 + }, + { + "key": "mid", + "value": 0.5 + }, + { + "key": "treble", + "value": 0.5 + } + ], + "pluginName": "TooB ML Amplifier", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 42, + "uri": "http://two-play.com/plugins/toob-chorus", + "isEnabled": false, + "controlValues": [ + { + "key": "rate", + "value": 0.291666657 + }, + { + "key": "depth", + "value": 0.375 + } + ], + "pluginName": "TooB CE-2 Chorus", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 41, + "uri": "http://two-play.com/plugins/toob-delay", + "isEnabled": true, + "controlValues": [ + { + "key": "delay", + "value": 340 + }, + { + "key": "level", + "value": 10.333333 + }, + { + "key": "feedback", + "value": 39.1666679 + } + ], + "pluginName": "TooB Delay", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 39, + "uri": "http://two-play.com/plugins/toob-ml", + "isEnabled": true, + "controlValues": [ + { + "key": "trim", + "value": 2.5 + }, + { + "key": "bass", + "value": 0.5 + }, + { + "key": "mid", + "value": 0.5 + }, + { + "key": "treble", + "value": 0.5 + }, + { + "key": "model", + "value": 12 + }, + { + "key": "gain", + "value": 10 + }, + { + "key": "master", + "value": -10 + } + ], + "pluginName": "TooB ML Amplifier", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + }, + { + "instanceId": 31, + "uri": "http://two-play.com/plugins/toob-freeverb", + "isEnabled": true, + "controlValues": [ + { + "key": "dryWet", + "value": 0.0416666716 + }, + { + "key": "roomSize", + "value": 0.625 + }, + { + "key": "damping", + "value": 0.574999988 + } + ], + "pluginName": "TooB Freeverb", + "midiBindings": [ ], + "stateUpdateCount": 0, + "lv2State": [ +false,{ + + } ] +, + "lilvPresetUri": "" + } + ], + "nextInstanceId": 47 + } + } + ] +} \ No newline at end of file diff --git a/docs/BuildPrerequisites.md b/docs/BuildPrerequisites.md index 33a4c0d..2f1512b 100644 --- a/docs/BuildPrerequisites.md +++ b/docs/BuildPrerequisites.md @@ -8,14 +8,14 @@ Run the following commands to install build tools required by the PiPedal build. The PiPedal build process also requires version 12 or later of `node.js`. Type `node --version` to see if you have a version of `node.js` installed already. Otherwise run the following commands as root to install the v14.x lts version of `node.js`: - +` sudo apt install nodejs npm If your distribution doesn't provide a suitable version of nodejs, you can install the current LTS version of nodejs with # install NodeJS latest LTS release. - curl -fsSL https://deb.nodesource.com/setup_14.x | sudo -E bash - + curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - sudo apt-get install -y nodejs @@ -23,9 +23,12 @@ Run the following commands to install dependent libraries required by the PiPeda sudo apt update sudo apt install -y liblilv-dev libboost-dev jackd2 libjack-jackd2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev catch - sudo apt install -y libasound2-dev jackd2 uuid-dev - sudo apt install -y libwebsocketpp-dev authbind + sudo apt install -y libasound2-dev jackd2 uuid-dev libxrandr-dev + sudo apt install -y authbind sudo apt install -y libavahi-client-dev + sudo apt install -y libnm-dev + sudo apt install -y libsdbus-c++-dev + ### Installing Sources @@ -39,7 +42,8 @@ Clone the rerdavies/pipdal package from github. Use the source control tools fro cd ~/src # or whereever you keep your source repositories. git clone https://github.com/rerdavies/pipedal.git -In the project root, run the following commands to initialze and update pipedal submodules +In the project root, run the following commands to initialze and update pipedal submodules. These steps +must be performed even if you used Visual Studio Code to initially install the project. cd ~/src/pipedal git submodule init diff --git a/docs/Debugging.md b/docs/Debugging.md index f4591b9..623684b 100644 --- a/docs/Debugging.md +++ b/docs/Debugging.md @@ -111,18 +111,9 @@ You will need to add your userid to the pipedal_d group if you plan to share the You will need to reboot your machine to get the group membership change to take effect,or log out and log back in if you can do that. -Or you can avoid all of this, by configuring the debug instance to use a data folder in your home directory. Edit -`debugConfig/config.json`: +To run pipedald in a debugger, you need to use the following command-line to launch pipedal: - { - ... - "local_storage_path": "~/var/pipedal", - ... - } - -Run pipedald in a debugger, you need to use the following command-line to launch pipedal: - - build/src/pipedald /etc/pipedal/config /etc/pipedal/react -port0.0.0.0:8080 + build/src/pipedald /etc/pipedal/config /etc/pipedal/react -port 0.0.0.0:8080 The first argument specifies where the pipedal daemon's configuration files are. The second argument specifies where built static web pages for the web application are. And the port option specifies the port on which the daemon will @@ -162,5 +153,7 @@ If you are using Visual Studio Code, you might find it useful to add the followi }, ... } + ----- + [<< The Build System](TheBuildSystem.md) | [Up](Documentation.md) | [PiPedal Architecture >>](Architecture.md) diff --git a/docs/Installing.md b/docs/Installing.md index fb5118e..1c72277 100644 --- a/docs/Installing.md +++ b/docs/Installing.md @@ -13,15 +13,20 @@ page_icon: img/Install4.jpg Download the most recent Debian (.deb) package for your platform: -- [Ubuntu/Raspberry Pi OS (64-bit) v1.1.31](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb) +- [Raspberry Pi OS bookworm (64-bit) v1.2.32 beta1](https://github.com/rerdavies/pipedal/releases/download/ +- [Ubuntu/Raspberry Pi OS buster (64-bit) v1.2.32](https://github.com/rerdavies/pipedal/releases/download/v1.1.31/pipedal_1.1.31_arm64.deb) + +Version 1.2.32 has not yet been tested Ubuntu and Raspberry Pi OS buster. On these platforms, we recommend that you use version 1.1.31. Install the package by running ``` sudo apt update cd ~/Downloads - sudo apt-get install ./pipedal_1.1.31_arm64.deb + sudo apt-get install ./pipedal_1.1.32_arm64.deb ``` +Adjust accordingly if you have downloaded v1.1.31. + On Raspberry Pi OS, if you have a graphical desktop installed, you can also install the package by double-clicking on the downloaded package in the File Manager. diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index 2cc39d8..4857420 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -1,4 +1,8 @@ # Release Notes +## PiPedal 1.2.32 + +- Raspberry PI OS Bookworm Compatibility. + ## PiPedal 1.1.31 - Use system preferences for dark mode when connecting from Android app. diff --git a/docs/UsingLv2Plugins.md b/docs/UsingLv2Plugins.md index 549c90c..5b193e2 100644 --- a/docs/UsingLv2Plugins.md +++ b/docs/UsingLv2Plugins.md @@ -8,7 +8,7 @@ PiPedal uses LV2 audio plugins. There are literally thousands of freely availabl By default, PiPedal comes with a basic set of plugins from the ToobAmp plugin collection. You will probably want to install more. -Here is a brief list of particularly recommended plugin collections. +Here is a brief list of particularly recommended plugin collections.dhcp | Collection | To Install | Description | |---------------------------------|---------------------------------------|------------------| diff --git a/docs/_includes/header.html b/docs/_includes/header.html index 30f82ba..59c121a 100644 --- a/docs/_includes/header.html +++ b/docs/_includes/header.html @@ -77,7 +77,7 @@ Sponsor - -v1.1.31 +v1.2.32   To download PiPedal, click [here](download.md). -> NEW version 1.1.31 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. +> NEW version 1.2.32 release. See the [release notes](https://rerdavies.github.io/pipedal/ReleaseNotes) for details. Use your Raspberry Pi as a guitar effects pedal. Configure and control PiPedal with your phone or tablet. diff --git a/install.sh b/install.sh index 3113e24..620618d 100755 --- a/install.sh +++ b/install.sh @@ -1,4 +1,4 @@ -#!/usr/bin/bash +#!/usr/bin/sudo bash # copy files to installation directories cmake --install build --prefix /usr --config Release -v # Done as an install action by the debian package. diff --git a/lv2/aarch64/ToobAmp.lv2/CabIR.ttl b/lv2/aarch64/ToobAmp.lv2/CabIR.ttl index e2d1b16..0ebbf0e 100644 --- a/lv2/aarch64/ToobAmp.lv2/CabIR.ttl +++ b/lv2/aarch64/ToobAmp.lv2/CabIR.ttl @@ -88,7 +88,7 @@ cabir:impulseFile3 doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ TooB Cab IR is a convolution-based guitar cabinet impulse response simulator. diff --git a/lv2/aarch64/ToobAmp.lv2/CabSim.ttl b/lv2/aarch64/ToobAmp.lv2/CabSim.ttl index 0023eb8..34d19e0 100644 --- a/lv2/aarch64/ToobAmp.lv2/CabSim.ttl +++ b/lv2/aarch64/ToobAmp.lv2/CabSim.ttl @@ -49,7 +49,7 @@ toob:frequencyResponseVector doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; mod:brand "TooB"; mod:label "TooB CabSim"; diff --git a/lv2/aarch64/ToobAmp.lv2/ConvolutionReverb.ttl b/lv2/aarch64/ToobAmp.lv2/ConvolutionReverb.ttl index a071c4e..603ddae 100644 --- a/lv2/aarch64/ToobAmp.lv2/ConvolutionReverb.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ConvolutionReverb.ttl @@ -51,7 +51,7 @@ toobimpulse:impulseFile doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ Convolution reverb is a notoriously compute-intensive effect. If you are having performance issues, use the Max T control to constrain the length of the impulse file to diff --git a/lv2/aarch64/ToobAmp.lv2/ConvolutionReverbStereo.ttl b/lv2/aarch64/ToobAmp.lv2/ConvolutionReverbStereo.ttl index 52274e2..31618ab 100644 --- a/lv2/aarch64/ToobAmp.lv2/ConvolutionReverbStereo.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ConvolutionReverbStereo.ttl @@ -49,7 +49,7 @@ toobimpulse:impulseFile doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ diff --git a/lv2/aarch64/ToobAmp.lv2/InputStage.ttl b/lv2/aarch64/ToobAmp.lv2/InputStage.ttl index 47e5380..afd17e0 100644 --- a/lv2/aarch64/ToobAmp.lv2/InputStage.ttl +++ b/lv2/aarch64/ToobAmp.lv2/InputStage.ttl @@ -65,7 +65,7 @@ inputStage:filterGroup doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; mod:brand "TooB"; mod:label "TooB Input"; diff --git a/lv2/aarch64/ToobAmp.lv2/SpectrumAnalyzer.ttl b/lv2/aarch64/ToobAmp.lv2/SpectrumAnalyzer.ttl index 9f2e884..c663a03 100644 --- a/lv2/aarch64/ToobAmp.lv2/SpectrumAnalyzer.ttl +++ b/lv2/aarch64/ToobAmp.lv2/SpectrumAnalyzer.ttl @@ -58,7 +58,7 @@ doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment "TooB spectrum analyzer" ; mod:brand "TooB"; diff --git a/lv2/aarch64/ToobAmp.lv2/ToneStack.ttl b/lv2/aarch64/ToobAmp.lv2/ToneStack.ttl index cd9cace..462252a 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToneStack.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToneStack.ttl @@ -13,10 +13,10 @@ @prefix mod: . @prefix param: . @prefix work: . +@prefix pg: . @prefix atom: . @prefix patch: . -@prefix plug: . @prefix rdfs: . @prefix state: . @prefix urid: . @@ -32,6 +32,12 @@ toob:frequencyResponseVector rdfs:label "Frequency Response"; rdfs:range atom:Vector. +tonestack:eqGroup + a param:ControlGroup , + pg:InputGroup ; + lv2:name "EQ" ; + lv2:symbol "eq" . + a foaf:Person ; @@ -42,13 +48,14 @@ toob:frequencyResponseVector a lv2:Plugin , lv2:SimulatorPlugin ; - doap:name "TooB Tone Stack" , + doap:name "TooB Tone Stack" , "TooB Tone Stack"@en-gb ; + doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; uiext:ui ; @@ -69,6 +76,7 @@ tone stack used in Polytone and HiWatt amps. [ a lv2:InputPort , lv2:ControlPort ; + pg:group tonestack:eqGroup ; lv2:index 0 ; lv2:symbol "bass" ; @@ -79,6 +87,7 @@ tone stack used in Polytone and HiWatt amps. ], [ a lv2:InputPort , lv2:ControlPort ; + pg:group tonestack:eqGroup ; lv2:index 1 ; lv2:symbol "mid" ; @@ -90,6 +99,7 @@ tone stack used in Polytone and HiWatt amps. ], [ a lv2:InputPort , lv2:ControlPort ; + pg:group tonestack:eqGroup ; lv2:index 2 ; lv2:symbol "treble" ; diff --git a/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.0 b/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.0 index f1b1efc..10db7b5 120000 --- a/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.0 +++ b/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.0 @@ -1 +1 @@ -ToobAmp.so.1.1.30 \ No newline at end of file +ToobAmp.so.1.1.31 \ No newline at end of file diff --git a/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.1.1.30 b/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.1.1.30 index 5accf6c..83370f1 100644 Binary files a/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.1.1.30 and b/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.1.1.30 differ diff --git a/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.1.1.31 b/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.1.1.31 new file mode 100644 index 0000000..3958e99 Binary files /dev/null and b/lv2/aarch64/ToobAmp.lv2/ToobAmp.so.1.1.31 differ diff --git a/lv2/aarch64/ToobAmp.lv2/ToobAmpUI.so b/lv2/aarch64/ToobAmp.lv2/ToobAmpUI.so index 4fe6f3b..a294e6c 100644 Binary files a/lv2/aarch64/ToobAmp.lv2/ToobAmpUI.so and b/lv2/aarch64/ToobAmp.lv2/ToobAmpUI.so differ diff --git a/lv2/aarch64/ToobAmp.lv2/ToobChorus.ttl b/lv2/aarch64/ToobAmp.lv2/ToobChorus.ttl index f6ef565..8e65c73 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobChorus.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobChorus.ttl @@ -40,7 +40,7 @@ doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ Emulation of a Boss CE-2 Chorus. diff --git a/lv2/aarch64/ToobAmp.lv2/ToobDelay.ttl b/lv2/aarch64/ToobAmp.lv2/ToobDelay.ttl index 4d1df37..899b0bb 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobDelay.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobDelay.ttl @@ -41,7 +41,7 @@ doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ A straightforward no-frills digital delay. diff --git a/lv2/aarch64/ToobAmp.lv2/ToobFlanger.ttl b/lv2/aarch64/ToobAmp.lv2/ToobFlanger.ttl index 3c709e3..c81f2af 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobFlanger.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobFlanger.ttl @@ -41,7 +41,7 @@ doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ Emulation of a Boss BF-2 Flanger, based on circuit analysis and simulation of the original. diff --git a/lv2/aarch64/ToobAmp.lv2/ToobFlangerStereo.ttl b/lv2/aarch64/ToobAmp.lv2/ToobFlangerStereo.ttl index 6faf685..4b58c27 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobFlangerStereo.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobFlangerStereo.ttl @@ -41,7 +41,7 @@ doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ Digital emulation of a Boss BF-2 Flanger. diff --git a/lv2/aarch64/ToobAmp.lv2/ToobFreeverb.ttl b/lv2/aarch64/ToobAmp.lv2/ToobFreeverb.ttl index 92c73a3..27defcc 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobFreeverb.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobFreeverb.ttl @@ -41,7 +41,7 @@ doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ Toob Freeverb is an Lv2 implementation of the famous Freeverb reverb effect. FreeVerb delivers a well-balanced reverb with very little tonal coloration. diff --git a/lv2/aarch64/ToobAmp.lv2/ToobML.ttl b/lv2/aarch64/ToobAmp.lv2/ToobML.ttl index 7bf96f7..7713756 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobML.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobML.ttl @@ -55,7 +55,7 @@ toobml:sagGroup doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ The TooB ML Amplifier plugin provides emulation of a variety of amplifiers and overdrive pedals that are implemented using neural-network-based machine learning models of real amplifiers. diff --git a/lv2/aarch64/ToobAmp.lv2/ToobNeuralAmpModeler.ttl b/lv2/aarch64/ToobAmp.lv2/ToobNeuralAmpModeler.ttl index 34e7139..088dd09 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobNeuralAmpModeler.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobNeuralAmpModeler.ttl @@ -58,7 +58,7 @@ toobNam:eqGroup doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ A port of Steven Atkinson's Neural Amp Modeler to LV2. diff --git a/lv2/aarch64/ToobAmp.lv2/ToobTuner.ttl b/lv2/aarch64/ToobAmp.lv2/ToobTuner.ttl index 0ccc0c3..7e97986 100644 --- a/lv2/aarch64/ToobAmp.lv2/ToobTuner.ttl +++ b/lv2/aarch64/ToobAmp.lv2/ToobTuner.ttl @@ -40,7 +40,7 @@ doap:license ; doap:maintainer ; lv2:minorVersion 0 ; - lv2:microVersion 30 ; + lv2:microVersion 31 ; rdfs:comment """ TooB Tuner is a chromatic guitar tuner. """ ; diff --git a/lv2/aarch64/ToobAmp.lv2/manifest.ttl b/lv2/aarch64/ToobAmp.lv2/manifest.ttl index a0070bc..63afba4 100644 --- a/lv2/aarch64/ToobAmp.lv2/manifest.ttl +++ b/lv2/aarch64/ToobAmp.lv2/manifest.ttl @@ -31,10 +31,9 @@ rdfs:seeAlso . -# Deprecated. -# a lv2:Plugin ; -# lv2:binary ; -# rdfs:seeAlso . + a lv2:Plugin ; + lv2:binary ; + rdfs:seeAlso . a lv2:Plugin ; lv2:binary ; diff --git a/modules/websocketpp b/modules/websocketpp index 1b11fd3..b9aeec6 160000 --- a/modules/websocketpp +++ b/modules/websocketpp @@ -1 +1 @@ -Subproject commit 1b11fd301531e6df35a6107c1e8665b1e77a2d8e +Subproject commit b9aeec6eaf3d5610503439b4fae3581d9aff08e8 diff --git a/react/public/var/config.json b/react/public/var/config.json index 80d344a..bf8d4ce 100644 --- a/react/public/var/config.json +++ b/react/public/var/config.json @@ -1,5 +1,5 @@ { - "socket_server_port": 80, + "socket_server_port": 8080, "socket_server_address": "*", "debug": true, "max_upload_size": 1048576, diff --git a/react/src/AboutDialog.tsx b/react/src/AboutDialog.tsx index 11ec5c4..ab7716f 100644 --- a/react/src/AboutDialog.tsx +++ b/react/src/AboutDialog.tsx @@ -186,7 +186,7 @@ const AboutDialog = withStyles(styles, { withTheme: true })( let classes = this.props.classes; return ( - { this.props.onClose() }} TransitionComponent={Transition} style={{ userSelect: "none" }} > diff --git a/react/src/AppThemed.tsx b/react/src/AppThemed.tsx index a3490ba..94b00b1 100644 --- a/react/src/AppThemed.tsx +++ b/react/src/AppThemed.tsx @@ -53,7 +53,6 @@ import ZoomedUiControl from './ZoomedUiControl' import MainPage from './MainPage'; import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; -import Dialog from '@mui/material/Dialog'; import DialogActions from '@mui/material/DialogActions'; import ListSubheader from '@mui/material/ListSubheader'; import { BankIndex, BankIndexEntry } from './Banks'; @@ -67,6 +66,7 @@ import {ReactComponent as SaveBankAsIcon} from './svg/ic_save_bank_as.svg'; import {ReactComponent as EditBanksIcon} from './svg/ic_edit_banks.svg'; import {ReactComponent as SettingsIcon} from './svg/ic_settings.svg'; import {ReactComponent as HelpOutlineIcon} from './svg/ic_help_outline.svg'; +import DialogEx from './DialogEx'; const appStyles = (theme: Theme) => createStyles({ @@ -511,11 +511,12 @@ const AppThemed = withStyles(appStyles)(class extends ResizeResponsiveComponent< } private unmountListener(e: Event) { - e.preventDefault(); if ((!this.model_.reloadRequested) && this.model_.state.get() === State.Ready && !this.model_.isAndroidHosted()) { + e.preventDefault(); (e as any).returnValue = "Are you sure you want to leave this page?"; return "Are you sure you want to leave this page?"; } + return undefined; } componentDidMount() { @@ -862,7 +863,8 @@ render() { onDialogClosed={() => { this.model_.zoomedUiControl.set(undefined); } } /> - - + {this.state.showStatusMonitor && ()}
+
this.handleItemClick(bankEntry.instanceId)} @@ -403,7 +403,7 @@ const BankDialog = withStyles(styles, { withTheme: true })( let defaultSelectedIndex = this.getSelectedIndex(); return ( - { this.handleDialogClose() }} TransitionComponent={Transition} style={{userSelect: "none"}} > diff --git a/react/src/ControlViewFactory.tsx b/react/src/ControlViewFactory.tsx index 115434a..8c91334 100644 --- a/react/src/ControlViewFactory.tsx +++ b/react/src/ControlViewFactory.tsx @@ -27,10 +27,15 @@ import SplitControlView from './SplitControlView'; import Typography from '@mui/material/Typography'; import IControlViewFactory from './IControlViewFactory'; import { GxTunerViewFactory } from './GxTunerView'; - +import ToobPowerstage2ViewFactory from './ToobPowerStage2View'; +import ToobSpectrumAnalyzerViewFactory from './ToobSpectrumAnalyzerView'; +// import ToobMLViewFactory from './ToobMLView'; let pluginFactories: IControlViewFactory[] = [ new GxTunerViewFactory(), + new ToobPowerstage2ViewFactory(), + new ToobSpectrumAnalyzerViewFactory(), + //new ToobMLViewFactory() ]; diff --git a/react/src/FilePropertyDialog.tsx b/react/src/FilePropertyDialog.tsx index 1880e4b..b430359 100644 --- a/react/src/FilePropertyDialog.tsx +++ b/react/src/FilePropertyDialog.tsx @@ -274,7 +274,7 @@ export default class FilePropertyDialog extends ResizeResponsiveComponent this.props.onCancel()} open={this.props.open} tag="FilePropertyDialog" fullWidth maxWidth="xl" style={{ height: "90%" }} + this.props.onCancel()} open={this.props.open} tag="fileProperty" fullWidth maxWidth="xl" style={{ height: "90%" }} PaperProps={{ style: { minHeight: "90%", maxHeight: "90%", overflowY: "visible" } }} > diff --git a/react/src/FullScreenIME.tsx b/react/src/FullScreenIME.tsx index 22e1539..d706603 100644 --- a/react/src/FullScreenIME.tsx +++ b/react/src/FullScreenIME.tsx @@ -25,7 +25,7 @@ import withStyles from '@mui/styles/withStyles'; import { PiPedalModel, PiPedalModelFactory } from './PiPedalModel'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; import { UiControl } from './Lv2Plugin'; -import Dialog from '@mui/material/Dialog'; +import DialogEx from './DialogEx'; import Input from '@mui/material/Input'; import { nullCast } from './Utility'; import Typography from '@mui/material/Typography'; @@ -196,7 +196,7 @@ const FullScreenIME = let value = this.props.value; return ( - this.handleClose(e, r)} > + this.handleClose(e, r)} >
-
+
); } diff --git a/react/src/GxTunerControl.tsx b/react/src/GxTunerControl.tsx index efc4a52..4db0ad9 100644 --- a/react/src/GxTunerControl.tsx +++ b/react/src/GxTunerControl.tsx @@ -181,7 +181,7 @@ const GxTunerControl = hz = -1; midiNote = -1; } else { - midiNote = Math.log2(hz/refFrequency)*12 + aOffset; + midiNote = Math.log2(hz/refFrequency)*tet + aOffset; } } diff --git a/react/src/JackServerSettingsDialog.tsx b/react/src/JackServerSettingsDialog.tsx index 9e38d53..34b3fec 100644 --- a/react/src/JackServerSettingsDialog.tsx +++ b/react/src/JackServerSettingsDialog.tsx @@ -28,7 +28,7 @@ import withStyles from '@mui/styles/withStyles'; import Button from '@mui/material/Button'; import DialogActions from '@mui/material/DialogActions'; -import Dialog from '@mui/material/Dialog'; +import DialogEx from './DialogEx'; import JackServerSettings from './JackServerSettings'; @@ -271,7 +271,7 @@ const JackServerSettingsDialog = withStyles(styles)( } return ( - +
@@ -365,13 +365,13 @@ const JackServerSettingsDialog = withStyles(styles)( - -
+
); } }); diff --git a/react/src/ListSelectDialog.tsx b/react/src/ListSelectDialog.tsx index 05898cb..0124104 100644 --- a/react/src/ListSelectDialog.tsx +++ b/react/src/ListSelectDialog.tsx @@ -28,7 +28,7 @@ import ListItemButton from '@mui/material/ListItemButton'; import ListItemIcon from '@mui/material/ListItemIcon'; import ListItemText from '@mui/material/ListItemText'; -import Dialog from '@mui/material/Dialog'; +import DialogEx from './DialogEx'; import DialogActions from '@mui/material/DialogActions'; import ResizeResponsiveComponent from './ResizeResponsiveComponent'; @@ -82,7 +82,7 @@ export default class ListSelectDialog extends ResizeResponsiveComponentthis.props.onClose()} open={this.props.open}> + this.props.onClose()} open={this.props.open}> { this.props.items.map( @@ -110,7 +110,7 @@ export default class ListSelectDialog extends ResizeResponsiveComponent - + ); } } \ No newline at end of file diff --git a/react/src/LoadPluginDialog.tsx b/react/src/LoadPluginDialog.tsx index f818115..5c7c93b 100644 --- a/react/src/LoadPluginDialog.tsx +++ b/react/src/LoadPluginDialog.tsx @@ -28,7 +28,7 @@ import MenuItem from '@mui/material/MenuItem'; import Typography from '@mui/material/Typography'; import PluginInfoDialog from './PluginInfoDialog' import PluginIcon from './PluginIcon' -import Dialog from '@mui/material/Dialog'; +import DialogEx from './DialogEx'; import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogTitle from '@mui/material/DialogTitle'; @@ -657,7 +657,7 @@ export const LoadPluginDialog = let isFavorite = this.state.favoritesList[this.state.selected_uri ?? ""]; return ( - { this.handleKeyPress(e); }} fullScreen={true} TransitionComponent={undefined} @@ -847,7 +847,7 @@ export const LoadPluginDialog = )}
- + ); } diff --git a/react/src/Lv2Plugin.tsx b/react/src/Lv2Plugin.tsx index 0d03c4c..978ceb1 100644 --- a/react/src/Lv2Plugin.tsx +++ b/react/src/Lv2Plugin.tsx @@ -451,7 +451,8 @@ export enum ControlType { Tuner, Vu, - DbVu + DbVu, + OutputSelect } export class UiControl implements Deserializable { @@ -499,6 +500,8 @@ export class UiControl implements Deserializable { } else if (this.units === Units.db) { this.controlType = ControlType.DbVu; + } else if (this.enumeration_property) { + this.controlType = ControlType.OutputSelect; } else { this.controlType = ControlType.Vu; } @@ -614,6 +617,10 @@ export class UiControl implements Deserializable { isSelect() : boolean { return this.controlType === ControlType.Select; } + isOutputSelect() : boolean { + return !this.is_input && this.controlType === ControlType.OutputSelect; + } + isLamp(): boolean { return this.toggled_property && this.scale_points.length === 0 && !this.is_input; diff --git a/react/src/MainPage.tsx b/react/src/MainPage.tsx index 790d536..7f1db1f 100644 --- a/react/src/MainPage.tsx +++ b/react/src/MainPage.tsx @@ -353,7 +353,7 @@ export const MainPage = alignItems: "center" }}>
- + {title}
@@ -522,9 +522,9 @@ export const MainPage =
{ missing ? ( -
+
Error: Plugin is not installed. - {pluginUri} + {pluginUri}
) : diff --git a/react/src/MidiBindingsDialog.tsx b/react/src/MidiBindingsDialog.tsx index 63629f1..5b9efb8 100644 --- a/react/src/MidiBindingsDialog.tsx +++ b/react/src/MidiBindingsDialog.tsx @@ -226,6 +226,14 @@ export const MidiBindingDialog = for (let i = 0; i < plugin.controls.length; ++i) { let control = plugin.controls[i]; + if (control.isHidden()) + { + continue; + } + if (!control.is_input) + { + continue; + } let symbol = control.symbol; result.push( @@ -269,7 +277,7 @@ export const MidiBindingDialog = } return ( - diff --git a/react/src/OkCancelDialog.tsx b/react/src/OkCancelDialog.tsx index cd5ba57..72f8ab4 100644 --- a/react/src/OkCancelDialog.tsx +++ b/react/src/OkCancelDialog.tsx @@ -62,7 +62,7 @@ export default class OkCancelDialog extends React.Component diff --git a/react/src/PedalboardView.tsx b/react/src/PedalboardView.tsx index 6ff6022..c5014bc 100644 --- a/react/src/PedalboardView.tsx +++ b/react/src/PedalboardView.tsx @@ -906,7 +906,14 @@ const PedalboardView = throw new PiPedalStateError("scroll container not found."); } - pedalButton(instanceId: number, iconType: PluginType, draggable: boolean, enabled: boolean,hasBorder: boolean = true): ReactNode { + pedalButton( + instanceId: number, + iconType: PluginType, + draggable: boolean, + enabled: boolean, + hasBorder: boolean = true, + pluginNotFound: boolean) + : ReactNode { let classes = this.props.classes; return (
{ e.preventDefault(); }}> @@ -920,7 +927,7 @@ const PedalboardView = this.getScrollContainer()} onDragEnd={(x, y) => { this.onDragEnd(instanceId, x, y) }} > - + @@ -984,7 +991,7 @@ const PedalboardView = result.push(
- {this.pedalButton(START_CONTROL, item.pluginType,false,true,false)} + {this.pedalButton(START_CONTROL, item.pluginType,false,true,false,false)}
); break; @@ -992,7 +999,7 @@ const PedalboardView = result.push(
- {this.pedalButton(END_CONTROL, item.pluginType, false,true,false)} + {this.pedalButton(END_CONTROL, item.pluginType, false,true,false,false)}
); break; @@ -1001,7 +1008,7 @@ const PedalboardView = result.push(
- {this.pedalButton(item.pedalItem?.instanceId ?? -1, this.getSplitterIcon(item), false,true)} + {this.pedalButton(item.pedalItem?.instanceId ?? -1, this.getSplitterIcon(item), false,true,true,false)}
); @@ -1016,8 +1023,10 @@ const PedalboardView = >{item.name}
) + let uiPlugin = this.model.getUiPlugin(item.pedalItem?.uri??""); + let pluginMissing = uiPlugin == null; result.push(
- {this.pedalButton(item.pedalItem?.instanceId ?? -1, item.pluginType, !item.isEmpty(), item.pedalItem?.isEnabled ?? false)} + {this.pedalButton(item.pedalItem?.instanceId ?? -1, item.pluginType, !item.isEmpty(), item.pedalItem?.isEnabled ?? false,true,pluginMissing)}
); diff --git a/react/src/PiPedalModel.tsx b/react/src/PiPedalModel.tsx index 83bc538..fe277dd 100644 --- a/react/src/PiPedalModel.tsx +++ b/react/src/PiPedalModel.tsx @@ -2356,13 +2356,17 @@ export class PiPedalModel //implements PiPedalModel serverConfigSettings ) .then(() => { - resolve(); + //resolve(); }) .catch((err) => { - reject(err); + //resolve(); }); + // yyy + resolve(); }); + this.restartExpected = true; + this.webSocket?.reconnect(); // close immediately, and wait for recoonnect. return result; } diff --git a/react/src/PluginIcon.tsx b/react/src/PluginIcon.tsx index 22643e9..5e6e6c0 100644 --- a/react/src/PluginIcon.tsx +++ b/react/src/PluginIcon.tsx @@ -64,6 +64,10 @@ import { ReactComponent as FxEmptyIcon } from './svg/fx_empty.svg'; import { ReactComponent as FxTerminalIcon } from './svg/fx_terminal.svg'; +import {isDarkMode} from './DarkMode'; +import { Color } from '@mui/material'; + + const styles = (theme: Theme) => createStyles({ @@ -75,6 +79,7 @@ const styles = (theme: Theme) => color: theme.palette.text.primary, fill: theme.palette.text.primary }, + }); export interface PluginIconProps extends WithStyles { @@ -82,10 +87,16 @@ export interface PluginIconProps extends WithStyles { opacity?: number; offsetY?: number; pluginType: PluginType; + pluginMissing?: boolean; } -export function SelectSvgIcon(plugin_type: PluginType, className: string, size: number = 24, opacity: number = 1.0) { - let myStyle = { width: size, height: size, opacity: opacity }; +export function SelectSvgIcon(plugin_type: PluginType, className: string, size: number = 24, opacity: number = 1.0, missingPlugin: boolean = false) { + let color = ""; + if (missingPlugin) + { + color = isDarkMode()? "#C00000": "#B00000"; + } + let myStyle = { width: size, height: size, opacity: opacity, color: color, fill: color }; switch (plugin_type) { case PluginType.PhaserPlugin: return ; @@ -276,13 +287,15 @@ export function SelectIconUri(plugin_type: PluginType) { } const PluginIcon = withStyles(styles)((props: PluginIconProps) => { - const { classes, pluginType, opacity } = props; + const { classes, pluginType, opacity,pluginMissing } = props; + + let pluginMissing_ : boolean = pluginMissing??false; let size: number = 24; if (props.size) size = props.size; let topVal: number = (props.offsetY ?? 0); - let svgIcon = SelectSvgIcon(pluginType, classes.icon, size, opacity); + let svgIcon = SelectSvgIcon(pluginType, classes.icon, size, opacity,pluginMissing_); if (svgIcon) { return svgIcon; } diff --git a/react/src/PluginInfoDialog.tsx b/react/src/PluginInfoDialog.tsx index 75c9591..465361a 100644 --- a/react/src/PluginInfoDialog.tsx +++ b/react/src/PluginInfoDialog.tsx @@ -23,7 +23,7 @@ import { WithStyles } from '@mui/styles'; import createStyles from '@mui/styles/createStyles'; import withStyles from '@mui/styles/withStyles'; import Button from '@mui/material/Button'; -import Dialog from '@mui/material/Dialog'; +import DialogEx from './DialogEx'; import MuiDialogTitle from '@mui/material/DialogTitle'; import MuiDialogContent from '@mui/material/DialogContent'; import MuiDialogActions from '@mui/material/DialogActions'; @@ -235,7 +235,7 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => { {open && ( - +
@@ -321,7 +321,7 @@ const PluginInfoDialog = withStyles(styles)((props: PluginInfoProps) => { OK -
+
)}
); diff --git a/react/src/PluginOutputControl.tsx b/react/src/PluginOutputControl.tsx index ca62b2f..3b5e8ab 100644 --- a/react/src/PluginOutputControl.tsx +++ b/react/src/PluginOutputControl.tsx @@ -309,7 +309,7 @@ const PluginOutputControl = } } - let isSelect = control.isSelect(); + let isSelect = control.isOutputSelect(); let item_width: number | undefined = isSelect ? 160 : 80; if (isSelect) { @@ -424,7 +424,32 @@ const PluginOutputControl =
); - } else { + } if (control.isOutputSelect()) { + return ( +
+ {/* TITLE SECTION */} +
+ {control.name} +
+ {/* CONTROL SECTION */} + +
+ + {text} + +
+ + {/* LABEL/EDIT SECTION*, strictly a placeholder for visual alignment purposes.*/} +
+   +
+
+ ); + + }else { return (
{/* TITLE SECTION */} diff --git a/react/src/PluginPresetsDialog.tsx b/react/src/PluginPresetsDialog.tsx index b2dda66..35bd05a 100644 --- a/react/src/PluginPresetsDialog.tsx +++ b/react/src/PluginPresetsDialog.tsx @@ -359,7 +359,7 @@ const PluginPresetsDialog = withStyles(styles, { withTheme: true })( return ( - { this.handleDialogClose() }} TransitionComponent={Transition} style={{userSelect: "none"}}>
diff --git a/react/src/PresetDialog.tsx b/react/src/PresetDialog.tsx index 76a22e8..6f7d159 100644 --- a/react/src/PresetDialog.tsx +++ b/react/src/PresetDialog.tsx @@ -338,7 +338,7 @@ const PresetDialog = withStyles(styles, { withTheme: true })( let defaultSelectedIndex = this.getSelectedIndex(); return ( - { this.handleDialogClose() }} TransitionComponent={Transition} style={{userSelect: "none"}}>
diff --git a/react/src/RenameDialog.tsx b/react/src/RenameDialog.tsx index 5ee0bf9..a99c631 100644 --- a/react/src/RenameDialog.tsx +++ b/react/src/RenameDialog.tsx @@ -98,7 +98,7 @@ export default class RenameDialog extends ResizeResponsiveComponent diff --git a/react/src/SelectChannelsDialog.tsx b/react/src/SelectChannelsDialog.tsx index f74ddb1..de9edd6 100644 --- a/react/src/SelectChannelsDialog.tsx +++ b/react/src/SelectChannelsDialog.tsx @@ -24,7 +24,7 @@ import ListItem from '@mui/material/ListItem'; import ListItemText from '@mui/material/ListItemText'; import DialogTitle from '@mui/material/DialogTitle'; import DialogActions from '@mui/material/DialogActions'; -import Dialog from '@mui/material/Dialog'; +import DialogEx from './DialogEx'; import FormControlLabel from '@mui/material/FormControlLabel'; import Checkbox from '@mui/material/Checkbox'; @@ -90,7 +90,7 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) { return ( - + Select Channels {availableChannels.map((channel) => ( @@ -114,7 +114,7 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) { OK - + ); } else { @@ -154,7 +154,7 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) { } return ( - + handleListItemClick("Stereo")} key={"Stereo"} selected={selectionKey === "Stereo"} > @@ -167,7 +167,7 @@ function SelectChannelsDialog(props: SelectChannelsDialogProps) { - + ); } } diff --git a/react/src/SelectMidiChannelsDialog.tsx b/react/src/SelectMidiChannelsDialog.tsx index 832e0e9..bd51194 100644 --- a/react/src/SelectMidiChannelsDialog.tsx +++ b/react/src/SelectMidiChannelsDialog.tsx @@ -23,12 +23,11 @@ import List from '@mui/material/List'; import ListItem from '@mui/material/ListItem'; import DialogTitle from '@mui/material/DialogTitle'; import DialogActions from '@mui/material/DialogActions'; -import Dialog from '@mui/material/Dialog'; import FormControlLabel from '@mui/material/FormControlLabel'; import Checkbox from '@mui/material/Checkbox'; import {AlsaMidiDeviceInfo} from './AlsaMidiDeviceInfo'; - +import DialogEx from './DialogEx'; @@ -94,7 +93,7 @@ function SelectMidiChannelsDialog(props: SelectMidiChannelsDialogProps) { return ( - + Select MIDI Device {availableChannels.map((channel) => ( @@ -118,7 +117,7 @@ function SelectMidiChannelsDialog(props: SelectMidiChannelsDialogProps) { OK - + ); } diff --git a/react/src/SelectThemeDialog.tsx b/react/src/SelectThemeDialog.tsx index 83e3074..f928663 100644 --- a/react/src/SelectThemeDialog.tsx +++ b/react/src/SelectThemeDialog.tsx @@ -23,7 +23,7 @@ import Button from '@mui/material/Button'; import DialogTitle from '@mui/material/DialogTitle'; import DialogContent from '@mui/material/DialogContent'; import DialogActions from '@mui/material/DialogActions'; -import Dialog from '@mui/material/Dialog'; +import DialogEx from './DialogEx'; import FormControlLabel from '@mui/material/FormControlLabel'; import FormControl from '@mui/material/FormControl'; @@ -64,7 +64,7 @@ function SelectThemesDialog(props: SelectThemesDialogProps) { return ( - + Theme @@ -82,11 +82,11 @@ function SelectThemesDialog(props: SelectThemesDialogProps) { - - + ); } diff --git a/react/src/SettingsDialog.tsx b/react/src/SettingsDialog.tsx index 8308aa3..53f5da5 100644 --- a/react/src/SettingsDialog.tsx +++ b/react/src/SettingsDialog.tsx @@ -522,7 +522,7 @@ const SettingsDialog = withStyles(styles, { withTheme: true })( let disableShutdown = this.state.shuttingDown || this.state.restarting; return ( - { this.props.onClose() }} TransitionComponent={Transition} style={{ userSelect: "none" }} > diff --git a/react/src/SystemMidiBindingsDialog.tsx b/react/src/SystemMidiBindingsDialog.tsx index ce9f417..33185bc 100644 --- a/react/src/SystemMidiBindingsDialog.tsx +++ b/react/src/SystemMidiBindingsDialog.tsx @@ -283,7 +283,7 @@ export const SystemMidiBindingDialog = } return ( - diff --git a/react/src/UploadFileDialog.tsx b/react/src/UploadFileDialog.tsx index ab9c24d..f6b0d72 100644 --- a/react/src/UploadFileDialog.tsx +++ b/react/src/UploadFileDialog.tsx @@ -307,7 +307,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent this.handleClose()} + this.handleClose()} fullScreen={this.state.fullScreen} style={{ userSelect: "none" }} > @@ -399,7 +399,7 @@ export default class UploadFileDialog extends ResizeResponsiveComponent this.handleClose()} color="secondary"> + diff --git a/react/src/UploadPresetDialog.tsx b/react/src/UploadPresetDialog.tsx index 76dce88..9381473 100644 --- a/react/src/UploadPresetDialog.tsx +++ b/react/src/UploadPresetDialog.tsx @@ -157,7 +157,7 @@ export default class UploadPresetDialog extends ResizeResponsiveComponent this.handleClose()} + this.handleClose()} fullScreen={this.state.fullScreen} style={{userSelect: "none"}} > diff --git a/react/src/WifiConfigDialog.tsx b/react/src/WifiConfigDialog.tsx index 685bf91..eef12fa 100644 --- a/react/src/WifiConfigDialog.tsx +++ b/react/src/WifiConfigDialog.tsx @@ -259,7 +259,7 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })( }; return ( - { this.state.fullScreen && ( @@ -340,7 +340,7 @@ const WifiConfigDialog = withStyles(styles, { withTheme: true })( - diff --git a/react/src/WifiDirectConfigDialog.tsx b/react/src/WifiDirectConfigDialog.tsx index dfdac9e..1402c08 100644 --- a/react/src/WifiDirectConfigDialog.tsx +++ b/react/src/WifiDirectConfigDialog.tsx @@ -306,7 +306,7 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })( }; return ( - {this.state.landscapeLayout && ( @@ -315,10 +315,10 @@ const WifiDirectConfigDialog = withStyles(styles, { withTheme: true })( {this.props.onClose(); }} + onClick={() => { this.props.onClose(); }} aria-label="back" size="large"> - + )} {(!this.state.landscapeLayout) && ( - +
Cancel - diff --git a/react/src/ZoomedUiControl.tsx b/react/src/ZoomedUiControl.tsx index 5dbffa7..9833e98 100644 --- a/react/src/ZoomedUiControl.tsx +++ b/react/src/ZoomedUiControl.tsx @@ -211,7 +211,7 @@ const ZoomedUiControl = withStyles(styles, { withTheme: true })( displayValue = "\u00A0"; } return ( - { this.props.onDialogClose() }} onAbort={() => { this.props.onDialogClose() }} > diff --git a/src/AlsaDriver.cpp b/src/AlsaDriver.cpp index 4ef8711..f08e725 100644 --- a/src/AlsaDriver.cpp +++ b/src/AlsaDriver.cpp @@ -31,6 +31,7 @@ #include "JackServerSettings.hpp" #include #include "RtInversionGuard.hpp" +#include "PiPedalException.hpp" #include "CpuUse.hpp" diff --git a/src/AutoLilvNode.hpp b/src/AutoLilvNode.hpp index 732e02e..b4d3ba9 100644 --- a/src/AutoLilvNode.hpp +++ b/src/AutoLilvNode.hpp @@ -33,6 +33,10 @@ namespace pipedal { public: + AutoLilvNode(const AutoLilvNode&) = delete; + AutoLilvNode&operator=(const AutoLilvNode&) = delete; + AutoLilvNode(AutoLilvNode&&) = default; + AutoLilvNode() { } @@ -89,6 +93,7 @@ namespace pipedal AutoLilvNode &operator=(AutoLilvNode &&other) { std::swap(this->node, other.node); + std::swap(this->isConst,other.isConst); return *this; } @@ -101,7 +106,14 @@ namespace pipedal void Free() { if (node != nullptr && !isConst) - lilv_node_free(node); + { + try { + lilv_node_free(node); + } catch (const std::exception&) + { + + } + } node = nullptr; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 986eac4..f0b5dd3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -46,22 +46,6 @@ endif() -# Can't get the pkg_check to work. -# pkg_check_modules(LIBNL3 "nl-genl-3") -# if(!LIBNL3_FOUND) -# message(ERROR "libnl-genl-3-dev package not installed.") -# else() -# message(STATUS "LIBNL3 libraries: ${LIBNL3_LIBRARIES}") -# message(STATUS "LBNL3 includes: ${LIBNL3_INCLUDE_DIRS}") -# endif() - -# nlgenl-3 library. -execute_process(COMMAND ls /usr/include/libnl3/netlink/netlink.h RESULT_VARIABLE LNL3_MISSING OUTPUT_QUIET ERROR_QUIET) -if(LNL3_MISSING) - message(ERROR " Need to: sudo apt install libnl-3-dev libnl-genl-3-dev ") -endif() -set(LIBNL3_INCLUDE_DIRS /usr/include/libnl3) -set(LIBNL3_LIBRARIES nl-3 nl-genl-3) pkg_check_modules(SYSTEMD "systemd") @@ -81,8 +65,14 @@ endif() # Use LV2 headers from the /usr/lib directory. #set (LV2DEV_INCLUDE_DIRS /usr/lib) -set (LV2DEV_INCLUDE_DIRS ) +set (LV2DEV_INCLUDE_DIRS ) # use lvt headers fro /usr/include + +# Use submodules/websocketpp heders taken from websocketpp/develop branch, because debian-provided +# version of websocketpp cannot compile under GCC 12.x. + +set (WEBSOCKETPP_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/modules/websocketpp) +message(STATUS "WEBSOCKETPP_INCLUDE_DIRS ${WEBSOCKETPP_INCLUDE_DIRS}" ) pkg_check_modules(JACK "jack") if(!JACK_FOUND) message(ERROR "jack package not installed.") @@ -148,8 +138,8 @@ set (PIPEDAL_SOURCES inverting_mutex.hpp DbDezipper.hpp DbDezipper.cpp WebServerLog.hpp + WifiChannelSelectors.cpp WifiChannelSelectors.hpp - util.hpp util.cpp PiPedalUI.hpp PiPedalUI.cpp MapPathFeature.hpp @@ -165,25 +155,15 @@ set (PIPEDAL_SOURCES AutoLilvNode.cpp RtInversionGuard.hpp CpuUse.hpp CpuUse.cpp - P2pConfigFiles.hpp AvahiService.cpp AvahiService.hpp - ServiceConfiguration.cpp ServiceConfiguration.hpp - WriteTemplateFile.cpp WriteTemplateFile.hpp - ConfigUtil.hpp ConfigUtil.cpp - ConfigSerializer.h ConfigSerializer.cpp StdErrorCapture.hpp StdErrorCapture.cpp Ipv6Helpers.cpp Ipv6Helpers.hpp PluginPreset.cpp PluginPreset.hpp CpuGovernor.cpp CpuGovernor.hpp GovernorSettings.cpp GovernorSettings.hpp - SysExec.cpp SysExec.hpp - WebServer.cpp WebServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp - WifiConfigSettings.hpp WifiConfigSettings.cpp - WifiDirectConfigSettings.hpp WifiDirectConfigSettings.cpp - ConfigUtil.hpp ConfigUtil.cpp + WebServer.cpp WebServer.hpp pch.h Uri.cpp Uri.hpp - RequestHandler.hpp json.cpp json.hpp - json_variant.hpp json_variant.cpp + RequestHandler.hpp Scratch.cpp PluginHost.hpp PluginHost.cpp PluginType.hpp PluginType.cpp Lv2Log.hpp Lv2Log.cpp @@ -220,9 +200,6 @@ set (PIPEDAL_SOURCES Locale.hpp Locale.cpp Lv2EventBufferWriter.hpp Lv2EventBufferWriter.cpp IpSubnet.hpp - WifiChannels.hpp - WifiChannels.cpp - RegDb.cpp RegDb.hpp PiPedalAlsa.hpp PiPedalAlsa.cpp InheritPriorityMutex.hpp InheritPriorityMutex.cpp UnixSocket.cpp UnixSocket.hpp @@ -237,12 +214,16 @@ set (PIPEDAL_SOURCES configure_file(config.hpp.in config.hpp) -include_directories( ${pipedald_SOURCE_DIR}/. ../build/src) +include_directories( + ${pipedald_SOURCE_DIR}/. + ../build/src + ) set (PIPEDAL_INCLUDES ${LV2DEV_INCLUDE_DIRS} - ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${LIBNL3_INCLUDE_DIRS} + ${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${VST3_INCLUDES} + ${WEBSOCKETPP_INCLUDE_DIRS} . ) @@ -251,7 +232,6 @@ set(PIPEDAL_LIBS libpipedald ${VST3_LIBRARIES} ${LILV_0_LIBRARIES} # ${JACK_LIBRARIES} - pending delete for JACK support. - ${LIBNL3_LIBRARIES} ) @@ -263,6 +243,8 @@ add_library(libpipedald STATIC ${PIPEDAL_SOURCES}) target_include_directories(libpipedald PRIVATE ${PIPEDAL_INCLUDES} ) +target_link_libraries(libpipedald PUBLIC PiPedalCommon) + if(${USE_PCH}) target_precompile_headers(libpipedald PRIVATE pch.h) endif() @@ -275,7 +257,7 @@ add_executable(pipedald ) target_include_directories(pipedald PRIVATE ${PIPEDAL_INCLUDES}) -target_link_libraries(pipedald PRIVATE +target_link_libraries(pipedald PRIVATE PiPedalCommon ${PIPEDAL_LIBS} ) @@ -285,12 +267,8 @@ add_executable(pipedaltest testMain.cpp InvertingMutexTest.cpp jsonTest.cpp - json_variant.cpp - json_variant.hpp utilTest.cpp - util.cpp - util.hpp AlsaDriverTest.cpp AvahiServiceTest.cpp @@ -307,21 +285,15 @@ add_executable(pipedaltest testMain.cpp MemDebug.cpp MemDebug.hpp ) - +target_link_libraries(pipedaltest PRIVATE PiPedalCommon) target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES} ) add_executable(jsonTest testMain.cpp jsonTest.cpp - json.hpp - json.cpp - json_variant.cpp - json_variant.hpp MapFeature.cpp MapFeature.hpp - HtmlHelper.cpp - HtmlHelper.hpp AtomConverter.hpp AtomConverter.cpp AtomConverterTest.cpp @@ -329,6 +301,7 @@ add_executable(jsonTest Promise.hpp PromiseTest.cpp ) +target_link_libraries(jsonTest PRIVATE PiPedalCommon) target_include_directories(jsonTest PRIVATE ${PIPEDAL_INCLUDES} ) @@ -575,40 +548,26 @@ add_test(NAME DevTest COMMAND pipedaltest "[Dev]") add_executable(pipedalconfig PrettyPrinter.hpp - ServiceConfiguration.cpp ServiceConfiguration.hpp - json.cpp json.hpp - HtmlHelper.cpp HtmlHelper.hpp + SetWifiConfig.cpp SetWifiConfig.hpp CommandLineParser.hpp - WriteTemplateFile.hpp WriteTemplateFile.cpp PiPedalException.hpp - ConfigSerializer.h ConfigSerializer.cpp ConfigMain.cpp - WifiConfigSettings.cpp WifiConfigSettings.hpp - WifiDirectConfigSettings.cpp WifiDirectConfigSettings.hpp - ConfigUtil.hpp ConfigUtil.cpp JackServerSettings.hpp JackServerSettings.cpp - SetWifiConfig.hpp SetWifiConfig.cpp SystemConfigFile.hpp SystemConfigFile.cpp - WriteTemplateFile.hpp WriteTemplateFile.cpp - SysExec.hpp SysExec.cpp + WifiChannelSelectors.cpp WifiChannelSelectors.hpp asan_options.cpp Lv2Log.cpp Lv2Log.hpp - P2pConfigFiles.hpp ) -target_link_libraries(pipedalconfig PRIVATE pthread atomic uuid stdc++fs +target_link_libraries(pipedalconfig PRIVATE PiPedalCommon pthread atomic uuid stdc++fs ) add_executable(pipedal_latency_test - util.hpp - util.cpp PrettyPrinter.hpp CommandLineParser.hpp PiLatencyMain.cpp PiPedalAlsa.hpp PiPedalAlsa.cpp - json.hpp json.cpp - HtmlHelper.cpp HtmlHelper.hpp asan_options.cpp Lv2Log.cpp Lv2Log.hpp AlsaDriver.cpp AlsaDriver.hpp @@ -616,11 +575,9 @@ add_executable(pipedal_latency_test JackServerSettings.hpp JackServerSettings.cpp CpuUse.hpp CpuUse.cpp - - ) -target_link_libraries(pipedal_latency_test PRIVATE pthread asound +target_link_libraries(pipedal_latency_test PRIVATE pthread asound PiPedalCommon ) @@ -639,34 +596,25 @@ target_link_libraries(capturepresets ${PIPEDAL_LIBS}) add_executable(pipedaladmind AdminMain.cpp CommandLineParser.hpp UnixSocket.cpp UnixSocket.hpp - ServiceConfiguration.cpp ServiceConfiguration.hpp - ConfigSerializer.h ConfigSerializer.cpp - autoptr_vector.h + + SetWifiConfig.cpp SetWifiConfig.hpp JackServerSettings.hpp JackServerSettings.cpp - json.hpp json.cpp HtmlHelper.hpp HtmlHelper.cpp Lv2Log.hpp Lv2Log.cpp Lv2SystemdLogger.hpp Lv2SystemdLogger.cpp - WifiConfigSettings.cpp WifiConfigSettings.hpp - WriteTemplateFile.cpp WriteTemplateFile.hpp - WifiDirectConfigSettings.cpp WifiDirectConfigSettings.hpp - ConfigUtil.hpp ConfigUtil.cpp - SetWifiConfig.hpp SetWifiConfig.cpp + Lv2Log.cpp Lv2Log.hpp SystemConfigFile.hpp SystemConfigFile.cpp - SysExec.hpp SysExec.cpp CpuGovernor.cpp CpuGovernor.hpp asan_options.cpp - P2pConfigFiles.hpp ) -target_link_libraries(pipedaladmind PRIVATE pthread atomic stdc++fs systemd) +target_link_libraries(pipedaladmind PRIVATE PiPedalCommon pthread atomic stdc++fs systemd ) add_executable(processcopyrights copyrightMain.cpp CommandLineParser.hpp PiPedalException.hpp - HtmlHelper.hpp HtmlHelper.cpp asan_options.cpp ) -target_link_libraries(processcopyrights PRIVATE stdc++fs) +target_link_libraries(processcopyrights PRIVATE PiPedalCommon stdc++fs) set (REACT_BUILD_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/../build/react/build/) set (REACT_NOTICES_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../build/src/notices.txt) @@ -690,7 +638,7 @@ add_custom_command(OUTPUT ${REACT_NOTICES_FILE} COMMAND "$" --output ${REACT_NOTICES_FILE} --projectCopyright ${DEBIAN_COPYRIGHT_FILE} - liblilv-0-0 ${BOOST_COPYRIGHT_DIR} libnl-3-dev libnl-3-dev lv2-dev + liblilv-0-0 ${BOOST_COPYRIGHT_DIR} lv2-dev libsdbus-c++-dev librsvg2-2 libpango-1.0-0 libx11-6 libxrandr2 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DEPENDS ${DEBIAN_COPYRIGHT_FILE} "$" COMMENT "Updating copyright notices." @@ -702,7 +650,10 @@ add_custom_target ( ) -install (TARGETS pipedalconfig pipedald pipedaladmind pipedal_latency_test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin +install (TARGETS pipedalconfig pipedal_latency_test DESTINATION ${CMAKE_INSTALL_PREFIX}/bin EXPORT pipedalTargets) + install (TARGETS pipedald pipedaladmind DESTINATION ${CMAKE_INSTALL_PREFIX}/sbin + EXPORT pipedalSbinTargets) + diff --git a/src/ConfigMain.cpp b/src/ConfigMain.cpp index 84cfadb..4961e2f 100644 --- a/src/ConfigMain.cpp +++ b/src/ConfigMain.cpp @@ -21,7 +21,6 @@ #include #include #include "CommandLineParser.hpp" -#include "PiPedalException.hpp" #include #include #include "WriteTemplateFile.hpp" @@ -37,7 +36,7 @@ #include #include #include "AudioConfig.hpp" - +#include "WifiChannelSelectors.hpp" #if JACK_HOST #define INSTALL_JACK_SERVICE 1 @@ -47,7 +46,6 @@ #define UNINSTALL_JACK_SERVICE 1 - #define SS(x) (((std::stringstream &)(std::stringstream() << x)).str()) #define TEMPLATE_PATH(filename) ("/etc/pipedal/config/templates/" filename ".service") @@ -70,9 +68,11 @@ using namespace pipedal; #define CHMOD_BIN "/usr/bin/chmod" #define SERVICE_PATH "/usr/lib/systemd/system" -#define NATIVE_SERVICE "pipedald" +#define PIPEDALD_SERVICE "pipedald" #define ADMIN_SERVICE "pipedaladmind" #define PIPEDAL_P2PD_SERVICE "pipedal_p2pd" +#define PIPEDAL_NM_P2PD_SERVICE "pipedal_nm_p2pd" +#define NETWORK_MANAGER_SERIVCE "NetworkManager" #define JACK_SERVICE "jack" #define REMOVE_OLD_SERVICE 0 // Grandfathering: whether to remove the old shutdown service (now pipedaladmind) @@ -105,14 +105,14 @@ std::filesystem::path findOnPath(const std::string &command) } std::stringstream s; s << "'" << command << "' is not installed."; - throw PiPedalException(s.str()); + throw std::runtime_error(s.str()); } void EnableService() { - if (sysExec(SYSTEMCTL_BIN " enable " NATIVE_SERVICE ".service") != EXIT_SUCCESS) + if (sysExec(SYSTEMCTL_BIN " enable " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS) { - cout << "Error: Failed to enable the " NATIVE_SERVICE " service.\n"; + cout << "Error: Failed to enable the " PIPEDALD_SERVICE " service.\n"; } if (sysExec(SYSTEMCTL_BIN " enable " ADMIN_SERVICE ".service") != EXIT_SUCCESS) { @@ -121,17 +121,17 @@ void EnableService() } void DisableService() { - #if INSTALL_JACK_SERVICE || UNINSTALL_JACK_SERVICE +#if INSTALL_JACK_SERVICE || UNINSTALL_JACK_SERVICE if (silentSysExec(SYSTEMCTL_BIN " disable " JACK_SERVICE ".service") != EXIT_SUCCESS) { - #if INSTALL_JACK_SERVICE - // cout << "Error: Failed to disable the " JACK_SERVICE " service."; - #endif +#if INSTALL_JACK_SERVICE +// cout << "Error: Failed to disable the " JACK_SERVICE " service."; +#endif } - #endif - if (sysExec(SYSTEMCTL_BIN " disable " NATIVE_SERVICE ".service") != EXIT_SUCCESS) +#endif + if (sysExec(SYSTEMCTL_BIN " disable " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS) { - cout << "Error: Failed to disable the " NATIVE_SERVICE " service.\n"; + cout << "Error: Failed to disable the " PIPEDALD_SERVICE " service.\n"; } if (sysExec(SYSTEMCTL_BIN " disable " ADMIN_SERVICE ".service") != EXIT_SUCCESS) { @@ -147,9 +147,9 @@ void DisableService() void StopService(bool excludeShutdownService = false) { - if (sysExec(SYSTEMCTL_BIN " stop " NATIVE_SERVICE ".service") != EXIT_SUCCESS) + if (sysExec(SYSTEMCTL_BIN " stop " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS) { - cout << "Error: Failed to stop the " NATIVE_SERVICE " service.\n"; + cout << "Error: Failed to stop the " PIPEDALD_SERVICE " service.\n"; } if (!excludeShutdownService) { @@ -167,9 +167,9 @@ void StopService(bool excludeShutdownService = false) #if INSTALL_JACK_SERVICE || UNINSTALL_JACK_SERVICE if (silentSysExec(SYSTEMCTL_BIN " stop " JACK_SERVICE ".service") != EXIT_SUCCESS) { - #if INSTALL_JACK_SERVICE - // cout << PiPedalException("Failed to stop the " JACK_SERVICE " service."); - #endif +#if INSTALL_JACK_SERVICE +// cout << std::runtime_error("Failed to stop the " JACK_SERVICE " service."); +#endif } #endif } @@ -182,12 +182,12 @@ void StartService(bool excludeShutdownService = false) { if (sysExec(SYSTEMCTL_BIN " start " ADMIN_SERVICE ".service") != EXIT_SUCCESS) { - throw PiPedalException("Failed to start the " ADMIN_SERVICE " service."); + throw std::runtime_error("Failed to start the " ADMIN_SERVICE " service."); } } - if (sysExec(SYSTEMCTL_BIN " start " NATIVE_SERVICE ".service") != EXIT_SUCCESS) + if (sysExec(SYSTEMCTL_BIN " start " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS) { - throw PiPedalException("Failed to start the " NATIVE_SERVICE " service."); + throw std::runtime_error("Failed to start the " PIPEDALD_SERVICE " service."); } #if INSTALL_JACK_SERVICE JackServerSettings serverSettings; @@ -196,7 +196,7 @@ void StartService(bool excludeShutdownService = false) { if (sysExec(SYSTEMCTL_BIN " start " JACK_SERVICE ".service") != EXIT_SUCCESS) { - throw PiPedalException("Failed to start the " JACK_SERVICE " service."); + throw std::runtime_error("Failed to start the " JACK_SERVICE " service."); } } #endif @@ -246,7 +246,7 @@ static void RemoveLine(const std::string &path, const std::string lineToRemove) ifstream f(path); if (!f.is_open()) { - throw PiPedalException(SS("Can't open " << path)); + throw std::runtime_error(SS("Can't open " << path)); } while (true) { @@ -265,7 +265,7 @@ static void RemoveLine(const std::string &path, const std::string lineToRemove) std::ofstream f(path); if (!f.is_open()) { - throw PiPedalException(SS("Can't write to " << path)); + throw std::runtime_error(SS("Can't write to " << path)); } for (auto &line : lines) { @@ -303,7 +303,7 @@ void InstallPamEnv() ifstream f(path); if (!f.is_open()) { - throw PiPedalException(SS("Can't open " << path)); + throw std::runtime_error(SS("Can't open " << path)); } while (true) { @@ -328,7 +328,7 @@ void InstallPamEnv() std::ofstream f(path); if (!f.is_open()) { - throw PiPedalException(SS("Can't write to " << path)); + throw std::runtime_error(SS("Can't write to " << path)); } for (auto &line : lines) { @@ -348,7 +348,7 @@ void InstallLimits() { if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS) { - throw PiPedalException("Failed to create audio service group."); + throw std::runtime_error("Failed to create audio service group."); } std::filesystem::path limitsConfig = "/etc/security/limits.d/audio.conf"; @@ -365,7 +365,6 @@ void InstallLimits() } } - #if JACK_HOST void MaybeStartJackService() { @@ -390,13 +389,13 @@ void InstallAudioService() #if INSTALL_JACK_SERVICE if (sysExec(GROUPADD_BIN " -f " JACK_SERVICE_GROUP_NAME) != EXIT_SUCCESS) { - throw PiPedalException("Failed to create jack service group."); + throw std::runtime_error("Failed to create jack service group."); } if (!userExists(JACK_SERVICE_ACCOUNT_NAME)) { if (sysExec(USERADD_BIN " " JACK_SERVICE_ACCOUNT_NAME " -g " JACK_SERVICE_GROUP_NAME " -m -N -r") != EXIT_SUCCESS) { - // throw PiPedalException("Failed to create service account."); + // throw std::runtime_error("Failed to create service account."); } // lock account for login. silentSysExec("passwd -l " JACK_SERVICE_ACCOUNT_NAME); @@ -417,18 +416,32 @@ void InstallAudioService() MaybeStartJackService(); #endif - } -int SudoExec(char **argv) +int SudoExec(int argc, char**argv) { + // re-execute with SUDO in order to prompt for SUDO credentials once only. + std::vector args; + std::string pkexec = "/usr/bin/sudo"; // staged because "ISO C++ forbids converting a string constant to std::vector::value_type"(!) + args.push_back((char *)(pkexec.c_str())); + + std::string sPath = getSelfExePath(); + args.push_back(const_cast(sPath.c_str())); + for (int arg = 1; arg < argc; ++arg) + { + args.push_back(const_cast(argv[arg])); + } + + args.push_back(nullptr); + + char **newArgs = &args[0]; + int pbPid; int returnValue = 0; if ((pbPid = fork()) == 0) { - execv(argv[0], argv); - exit(-1); + return execv(newArgs[0], newArgs); } else { @@ -445,38 +458,36 @@ static bool IsP2pServiceEnabled() return settings.enable_; } -static void RestartP2pdService() -{ - if (IsP2pServiceEnabled()) - { - silentSysExec(SYSTEMCTL_BIN " restart " PIPEDAL_P2PD_SERVICE); - } -} - -static void UninstallP2pdService() -{ - silentSysExec("systemctl stop " PIPEDAL_P2PD_SERVICE); - silentSysExec("systemctl disable " PIPEDAL_P2PD_SERVICE); -} - - void Uninstall() { try { + try + { + if (IsP2pServiceEnabled()) + { + WifiDirectConfigSettings settings; + settings.Load(); + settings.enable_ = false; + settings.Save(); + SetWifiDirectConfig(settings); + } + } + catch (const std::exception e) + { + std::cout << "Error: Unable to disable the Wiifi P2P service. " << e.what() << std::endl; + } OnWifiUninstall(); StopService(); DisableService(); - UninstallP2pdService(); #if UNINSTALL_JACK_SERVICE silentSysExec(SYSTEMCTL_BIN " stop jack"); silentSysExec(SYSTEMCTL_BIN " disable jack"); #endif - try { std::filesystem::remove("/usr/bin/systemd/system/" OLD_SHUTDOWN_SERVICE ".service"); @@ -493,6 +504,13 @@ void Uninstall() { } try + { + std::filesystem::remove("/usr/bin/systemd/system/" PIPEDAL_NM_P2PD_SERVICE ".service"); + } + catch (...) + { + } + try { std::filesystem::remove("/usr/bin/systemd/system/" PIPEDAL_P2PD_SERVICE ".service"); } @@ -502,7 +520,7 @@ void Uninstall() try { - std::filesystem::remove("/usr/bin/systemd/system/" NATIVE_SERVICE ".service"); + std::filesystem::remove("/usr/bin/systemd/system/" PIPEDALD_SERVICE ".service"); } catch (...) { @@ -521,12 +539,12 @@ void Uninstall() } catch (const std::exception &e) { - // We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe. + // We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe. cout << "ERROR: Unexpected error while uninstalling pipedal. (" << e.what() << ")" << endl; } catch (...) { - // We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe. + // We should NEVER get here. But the consequences of failure are high (causes permanent apt installs/uninstall problems), so be safe. cout << "ERROR: Unexpected error while uninstalling pipedal." << endl; } } @@ -577,15 +595,14 @@ static std::string RandomChars(int nchars) static void PrepareServiceConfigurationFile(uint16_t portNumber) { ServiceConfiguration serviceConfiguration; - try { - serviceConfiguration.Load(); - } catch (const std::exception &) + try { - + serviceConfiguration.Load(); } - if (serviceConfiguration.deviceName == "" || serviceConfiguration.uuid == "" - || portNumber != serviceConfiguration.server_port - ) + catch (const std::exception &) + { + } + if (serviceConfiguration.deviceName == "" || serviceConfiguration.uuid == "" || portNumber != serviceConfiguration.server_port) { if (serviceConfiguration.deviceName == "") { @@ -600,190 +617,230 @@ static void PrepareServiceConfigurationFile(uint16_t portNumber) } } - +void CopyWpaSupplicantConfigFile() +{ + try { + const char NM_SUPPLICANT_CONFIG_PATH[] = "/etc/pipedal/config/wpa_supplicant/wpa_supplicant-pipedal.conf"; + const char NM_SUPPLICANT_CONFIG_SOURCE_PATH[] = "/etc/pipedal/config/templates/wpa_supplicant-pipedal.conf"; + std::filesystem::path destinationPath = NM_SUPPLICANT_CONFIG_PATH; + std::filesystem::path sourcePath = NM_SUPPLICANT_CONFIG_SOURCE_PATH; + + std::filesystem::create_directories(destinationPath.parent_path()); + std::filesystem::copy_file(sourcePath,destinationPath,std::filesystem::copy_options::overwrite_existing); + } catch (const std::exception&e) + { + cout << "ERROR: " << e.what() << endl; + } +} void Install(const std::filesystem::path &programPrefix, const std::string endpointAddress) { - if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS) - { - throw PiPedalException("Failed to create audio service group."); - } - if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS) - { - throw PiPedalException("Failed to create pipedald service group."); - } - - InstallAudioService(); - auto endpos = endpointAddress.find_last_of(':'); - if (endpos == string::npos) - { - throw PiPedalException("Invalid endpoint address: " + endpointAddress); - } - uint16_t port; - auto strPort = endpointAddress.substr(endpos + 1); + cout << "Configuring pipedal" << endl; try { - auto lport = std::stoul(strPort); - if (lport == 0 || lport >= std::numeric_limits::max()) + if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS) { - throw PiPedalException("out of range."); + throw std::runtime_error("Failed to create audio service group."); } - port = (uint16_t)lport; - std::stringstream s; - s << port; - strPort = s.str(); // normalized. - } - catch (const std::exception &) - { - std::stringstream s; - s << "Invalid port number: " << strPort; - throw PiPedalException(s.str()); - } - PrepareServiceConfigurationFile(port); - - - - bool authBindRequired = port < 512; - - // Create and configure service account. - - if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS) - { - throw PiPedalException("Failed to create service group."); - } - - if (!userExists(SERVICE_ACCOUNT_NAME)) - { - if (sysExec(USERADD_BIN " " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -m --home /var/pipedal/home -N -r") != EXIT_SUCCESS) + if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS) { - // throw PiPedalException("Failed to create service account."); + throw std::runtime_error("Failed to create pipedald service group."); } - // lock account for login. - silentSysExec("passwd -l " SERVICE_ACCOUNT_NAME); - } - - // Add to audio groups. - sysExec(USERMOD_BIN " -a -G " AUDIO_SERVICE_GROUP_NAME " " SERVICE_ACCOUNT_NAME); - - // create and configure /var directory. - - std::filesystem::path varDirectory("/var/pipedal"); - std::filesystem::create_directory(varDirectory); - - { - std::stringstream s; - s << CHGRP_BIN " " SERVICE_GROUP_NAME " " << varDirectory.c_str(); - sysExec(s.str().c_str()); - } - { - std::stringstream s; - s << CHOWN_BIN << " " << SERVICE_ACCOUNT_NAME << " " << varDirectory.c_str(); - sysExec(s.str().c_str()); - } - - { - std::stringstream s; - s << CHMOD_BIN << " 775 " << varDirectory.c_str(); - sysExec(s.str().c_str()); - } - { - std::stringstream s; - s << CHMOD_BIN << " g+s " << varDirectory.c_str(); // child files/directories inherit ownership. - sysExec(s.str().c_str()); - } - - // authbind port. - - if (authBindRequired) - { - std::filesystem::create_directories("/etc/authbind/byport"); - std::filesystem::path portAuthFile = std::filesystem::path("/etc/authbind/byport") / strPort; - + // defensively disable wifi p2p if some leftover config file left it enabled. + try { - // create it. - std::ofstream f(portAuthFile); - if (!f.is_open()) + if (IsP2pServiceEnabled()) { - throw PiPedalException("Failed to create " + portAuthFile.string()); + WifiDirectConfigSettings settings; + settings.Load(); + settings.enable_ = false; + settings.Save(); } } + catch (const std::exception &) { - // own it. - std::stringstream s; - s << CHOWN_BIN << " " SERVICE_ACCOUNT_NAME " " << portAuthFile.c_str(); - sysExec(s.str().c_str()); } + + InstallAudioService(); + auto endpos = endpointAddress.find_last_of(':'); + if (endpos == string::npos) { - // group own it. + throw std::runtime_error("Invalid endpoint address: " + endpointAddress); + } + uint16_t port; + auto strPort = endpointAddress.substr(endpos + 1); + try + { + auto lport = std::stoul(strPort); + if (lport == 0 || lport >= std::numeric_limits::max()) + { + throw std::runtime_error("out of range."); + } + port = (uint16_t)lport; std::stringstream s; - s << CHGRP_BIN << " " SERVICE_GROUP_NAME " " << portAuthFile.c_str(); + s << port; + strPort = s.str(); // normalized. + } + catch (const std::exception &) + { + std::stringstream s; + s << "Invalid port number: " << strPort; + throw std::runtime_error(s.str()); + } + PrepareServiceConfigurationFile(port); + + bool authBindRequired = port < 512; + + // Create and configure service account. + + if (sysExec(GROUPADD_BIN " -f " SERVICE_GROUP_NAME) != EXIT_SUCCESS) + { + throw std::runtime_error("Failed to create service group."); + } + + if (!userExists(SERVICE_ACCOUNT_NAME)) + { + if (sysExec(USERADD_BIN " " SERVICE_ACCOUNT_NAME " -g " SERVICE_GROUP_NAME " -m --home /var/pipedal/home -N -r") != EXIT_SUCCESS) + { + // throw std::runtime_error("Failed to create service account."); + } + // lock account for login. + silentSysExec("passwd -l " SERVICE_ACCOUNT_NAME); + } + + // Add to audio groups. + sysExec(USERMOD_BIN " -a -G " AUDIO_SERVICE_GROUP_NAME " " SERVICE_ACCOUNT_NAME); + + // create and configure /var directory. + + std::filesystem::path varDirectory("/var/pipedal"); + std::filesystem::create_directory(varDirectory); + + { + std::stringstream s; + s << CHGRP_BIN " " SERVICE_GROUP_NAME " " << varDirectory.c_str(); sysExec(s.str().c_str()); } { std::stringstream s; - s << CHMOD_BIN << " 770 " << portAuthFile.c_str(); + s << CHOWN_BIN << " " << SERVICE_ACCOUNT_NAME << " " << varDirectory.c_str(); sysExec(s.str().c_str()); } - } - cout << "Creating Systemd file." - << "\n"; + { + std::stringstream s; + s << CHMOD_BIN << " 775 " << varDirectory.c_str(); + sysExec(s.str().c_str()); + } + { + std::stringstream s; + s << CHMOD_BIN << " g+s " << varDirectory.c_str(); // child files/directories inherit ownership. + sysExec(s.str().c_str()); + } - std::map map; - - int shutdownPort = 3147; - map["DESCRIPTION"] = "PiPedal Web Service"; - { - std::stringstream s; + // authbind port. if (authBindRequired) { - s << findOnPath("authbind").string() << " --deep "; + std::filesystem::create_directories("/etc/authbind/byport"); + std::filesystem::path portAuthFile = std::filesystem::path("/etc/authbind/byport") / strPort; + + { + // create it. + std::ofstream f(portAuthFile); + if (!f.is_open()) + { + throw std::runtime_error("Failed to create " + portAuthFile.string()); + } + } + { + // own it. + std::stringstream s; + s << CHOWN_BIN << " " SERVICE_ACCOUNT_NAME " " << portAuthFile.c_str(); + sysExec(s.str().c_str()); + } + { + // group own it. + std::stringstream s; + s << CHGRP_BIN << " " SERVICE_GROUP_NAME " " << portAuthFile.c_str(); + sysExec(s.str().c_str()); + } + { + std::stringstream s; + s << CHMOD_BIN << " 770 " << portAuthFile.c_str(); + sysExec(s.str().c_str()); + } } - s - << (programPrefix / "bin" / NATIVE_SERVICE).string() - << " /etc/pipedal/config /etc/pipedal/react -port " << endpointAddress << " -systemd"; - map["COMMAND"] = s.str(); + std::map map; + + int shutdownPort = 3147; + map["DESCRIPTION"] = "PiPedal Web Service"; + { + std::stringstream s; + + if (authBindRequired) + { + s << findOnPath("authbind").string() << " --deep "; + } + s + << (programPrefix / "sbin" / PIPEDALD_SERVICE).string() + << " /etc/pipedal/config /etc/pipedal/react -port " << endpointAddress << " -systemd"; + + map["COMMAND"] = s.str(); + } + WriteTemplateFile(map, GetServiceFileName(PIPEDALD_SERVICE)); + + map["DESCRIPTION"] = "PiPedal Admin Service"; + { + std::stringstream s; + + s + << (programPrefix / "sbin" / ADMIN_SERVICE).string() + << " -port " << shutdownPort; + + map["COMMAND"] = s.str(); + } + WriteTemplateFile(map, GetServiceFileName(ADMIN_SERVICE)); + + // /usr/bin/pipedal_p2pd --config-file /etc/pipedal/config/template_p2pd.conf + + if (UsingNetworkManager()) + { + std::string pipedal_nm_p2pd_cmd = SS( + (programPrefix / "sbin" / "pipedal_nm_p2pd").string() + //<< " --config-file " << PIPEDAL_P2PD_CONF_PATH + ); + map["COMMAND"] = pipedal_nm_p2pd_cmd; + + WriteTemplateFile(map, GetServiceFileName(PIPEDAL_NM_P2PD_SERVICE)); + } + else + { + std::string pipedal_p2pd_cmd = SS( + (programPrefix / "sbin" / "pipedal_p2pd").string() + << " --config-file " << PIPEDAL_P2PD_CONF_PATH); + map["COMMAND"] = pipedal_p2pd_cmd; + + WriteTemplateFile(map, GetServiceFileName(PIPEDAL_P2PD_SERVICE)); + } + CopyWpaSupplicantConfigFile(); + + sysExec(SYSTEMCTL_BIN " daemon-reload"); + + RestartService(false); + EnableService(); } - WriteTemplateFile(map, GetServiceFileName(NATIVE_SERVICE)); - - map["DESCRIPTION"] = "PiPedal Admin Service"; + catch (const std::exception &e) { - std::stringstream s; - - s - << (programPrefix / "bin" / ADMIN_SERVICE).string() - << " -port " << shutdownPort; - - map["COMMAND"] = s.str(); + // don't allow abnormal termination, which leaves the package in a state that's + // difficult to uninstall. + cout << "Error: " << e.what(); } - WriteTemplateFile(map, GetServiceFileName(ADMIN_SERVICE)); - - // /usr/bin/pipedal_p2pd --config-file /etc/pipedal/config/template_p2pd.conf - - std::string pipedal_p2pd_cmd = SS( - (programPrefix / "bin" / "pipedal_p2pd").string() - << " --config-file " << PIPEDAL_P2PD_CONF_PATH); - map["COMMAND"] = pipedal_p2pd_cmd; - - WriteTemplateFile(map, GetServiceFileName(PIPEDAL_P2PD_SERVICE)); - - sysExec(SYSTEMCTL_BIN " daemon-reload"); - - cout << "Starting services" - << "\n"; - RestartService(false); - EnableService(); - - RestartP2pdService(); - - cout << "Complete" - << "\n"; } static std::string GetCurrentWebServicePort() { - std::filesystem::path servicePath = GetServiceFileName(NATIVE_SERVICE); + std::filesystem::path servicePath = GetServiceFileName(PIPEDALD_SERVICE); try { if (std::filesystem::exists(servicePath)) @@ -792,7 +849,7 @@ static std::string GetCurrentWebServicePort() ifstream f(servicePath); if (!f.is_open()) { - throw PiPedalException(SS("Can't open " << servicePath)); + throw std::runtime_error(SS("Can't open " << servicePath)); } while (true) { @@ -805,11 +862,11 @@ static std::string GetCurrentWebServicePort() auto startPos = line.find("-port "); if (startPos != std::string::npos) { - startPos = startPos+6; + startPos = startPos + 6; auto endPos = line.find(" -systemd"); if (endPos != std::string::npos) { - std::string result = line.substr(startPos,endPos-startPos); + std::string result = line.substr(startPos, endPos - startPos); return result; } } @@ -818,7 +875,7 @@ static std::string GetCurrentWebServicePort() } } } - catch (const std::exception &/*ignored*/) + catch (const std::exception & /*ignored*/) { } return ""; @@ -909,21 +966,25 @@ static void PrintHelp() << "Channel number defaults to 1." << "\n\n" - << HangingIndent() << " --disable-p2p\tDisabled Wi-Fi Direct access." + << HangingIndent() << " --disable-p2p\tDisable Wi-Fi Direct access." << "\n\n" - << HangingIndent() << " --enable-legacy-ap\t \tEnable a legacy Wi-Fi access point." - << "\n\n" - << "Enable a legacy Wi-Fi access point. \n\n" - << "country_code is the 2-letter ISO-3166 country code for " - << "the country you are in. see below for further notes." - << "\n\n" - << "See below for an explanation of when you might want to use a legacy Wi-Fi access point instead of Wifi-Direct access." - << "an explanation of when you might want to use a legacy Access Point instead of " - << "a P2P (Wi-Fi Direct) connection. Generally, you should prefer a P2p connection " - << "to an ordinary Hotspot connection." + << HangingIndent() << " --list-p2p-channels [] \tList valid p2p channels for the current/specified country." << "\n\n" + + // << HangingIndent() << " --enable-legacy-ap\t \tEnable a legacy Wi-Fi access point." + // << "\n\n" + // << "Enable a legacy Wi-Fi access point. \n\n" + // << "country_code is the 2-letter ISO-3166 country code for " + // << "the country you are in. see below for further notes." + // << "\n\n" + // << "See below for an explanation of when you might want to use a legacy Wi-Fi access point instead of Wifi-Direct access." + // << "an explanation of when you might want to use a legacy Access Point instead of " + // << "a P2P (Wi-Fi Direct) connection. Generally, you should prefer a P2p connection " + // << "to an ordinary Hotspot connection." + // << "\n\n" + << HangingIndent() << " --disable-legacy-ap\tDisabled the legacy Wi-Fi access point." << "\n\n" @@ -962,6 +1023,40 @@ static void PrintHelp() "therefore preferrable under almost all circumstances.\n\n"; } +static int ListP2PChannels(const std::vector&arguments) +{ + try { + std::string country; + if (arguments.size() >= 2) + { + throw std::runtime_error("Invalid arguments."); + } if (arguments.size() == 1) + { + country = arguments[0]; + } else { + // use the currently selected country by default. + WifiDirectConfigSettings settings; + settings.Load(); + if (settings.countryCode_.empty()) + { + throw std::runtime_error("A country has not yet been selected. Please provde a country code."); + } + country = settings.countryCode_; + } + auto channelSelectors = getWifiChannelSelectors(country.c_str(),true); + for (const auto &channelSelector: channelSelectors) + { + cout << channelSelector.channelName_ << endl; + } + } catch (const std::exception &e) + { + cout << "ERROR: " << e.what() << endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; + +} + int main(int argc, char **argv) { CommandLineParser parser; @@ -973,13 +1068,14 @@ int main(int argc, char **argv) bool enable = false, disable = false, restart = false; bool enable_ap = false, disable_ap = false; bool enable_p2p = false, disable_p2p = false; + bool list_p2p_channels = false; bool get_current_port = false; - bool nopkexec = false; + bool nosudo = false; bool excludeShutdownService = false; std::string prefixOption; std::string portOption; - parser.AddOption("--nopkexec", &nopkexec); // strictly a debugging aid. + parser.AddOption("--nosudo", &nosudo); // strictly a debugging aid. Run without sudo, until we fail because of permissions. parser.AddOption("--install", &install); parser.AddOption("--uninstall", &uninstall); parser.AddOption("--stop", &stop); @@ -991,10 +1087,12 @@ int main(int argc, char **argv) parser.AddOption("--help", &help); parser.AddOption("--prefix", &prefixOption); parser.AddOption("--port", &portOption); - parser.AddOption("--enable-legacy-ap", &enable_ap); + //parser.AddOption("--enable-legacy-ap", &enable_ap); parser.AddOption("--disable-ap", &disable_ap); parser.AddOption("--enable-p2p", &enable_p2p); parser.AddOption("--disable-p2p", &disable_p2p); + parser.AddOption("--list-p2p-channels", &list_p2p_channels); + parser.AddOption("--get-current-port", &get_current_port); // private. For debug use only. @@ -1003,20 +1101,25 @@ int main(int argc, char **argv) { parser.Parse(argc, (const char **)argv); - int actionCount = get_current_port + install + uninstall + stop + start + enable + disable + enable_ap + disable_ap + restart + enable_p2p + disable_p2p; + int actionCount = + help + get_current_port + install + uninstall + stop + start + enable + disable + + enable_ap + disable_ap + restart + enable_p2p + disable_p2p + + list_p2p_channels + ; if (actionCount > 1) { - throw PiPedalException("Please provide only one action."); + throw std::runtime_error("Please provide only one action."); } - if (argc == 1 ) + if (argc == 1) { help = true; - } else if (actionCount == 0) + } + else if (actionCount == 0) { - throw PiPedalException("No action provided."); + throw std::runtime_error("No action provided."); } - if ((!enable_p2p) && (!enable_ap)) + if ((!enable_p2p) && (!enable_ap) && (!list_p2p_channels)) { if (parser.Arguments().size() != 0) { @@ -1045,7 +1148,11 @@ int main(int argc, char **argv) if (get_current_port) { std::cout << "current port: " << GetCurrentWebServicePort() << std::endl; - return 0; + return EXIT_SUCCESS; + } + if (list_p2p_channels) + { + return ListP2PChannels(parser.Arguments()); } if (portOption.size() != 0 && !install) { @@ -1055,24 +1162,9 @@ int main(int argc, char **argv) } auto uid = getuid(); - if (uid != 0 && !nopkexec) + if (uid != 0 && !nosudo) { - // re-execute with PKEXEC in order to prompt for SUDO credentials once only. - std::vector args; - std::string pkexec = "/usr/bin/pkexec"; // staged because "ISO C++ forbids converting a string constant to std::vector::value_type"(!) - args.push_back((char *)(pkexec.c_str())); - - std::string sPath = getSelfExePath(); - args.push_back(const_cast(sPath.c_str())); - for (int arg = 1; arg < argc; ++arg) - { - args.push_back(const_cast(argv[arg])); - } - - args.push_back(nullptr); - - char **rawArgv = &args[0]; - return SudoExec(rawArgv); + return SudoExec(argc,argv); } try @@ -1088,12 +1180,12 @@ int main(int argc, char **argv) { prefix = std::filesystem::path(argv[0]).parent_path().parent_path(); - std::filesystem::path pipedalPath = prefix / "bin/pipedald"; + std::filesystem::path pipedalPath = prefix / "sbin" / "pipedald"; if (!std::filesystem::exists(pipedalPath)) { std::stringstream s; s << "Can't find pipedald executable at " << pipedalPath << ". Try again using the -prefix option."; - throw PiPedalException(s.str()); + throw std::runtime_error(s.str()); } } @@ -1137,13 +1229,19 @@ int main(int argc, char **argv) } else if (enable_p2p) { - auto argv = parser.Arguments(); - WifiDirectConfigSettings settings; - settings.ParseArguments(argv); - settings.valid_ = true; - settings.enable_ = true; - SetWifiDirectConfig(settings); - RestartService(true); // also have to retart web service so that it gets the correct device name. + try { + auto argv = parser.Arguments(); + WifiDirectConfigSettings settings; + settings.ParseArguments(argv); + settings.valid_ = true; + settings.enable_ = true; + SetWifiDirectConfig(settings); + RestartService(true); // also have to retart web service so that it gets the correct device name. + } catch (const std::exception&e) + { + cout << "ERROR: " << e.what() << endl; + return EXIT_FAILURE; + } } else if (disable_p2p) { diff --git a/src/JackServerSettings.hpp b/src/JackServerSettings.hpp index 1e052e0..50ee49c 100644 --- a/src/JackServerSettings.hpp +++ b/src/JackServerSettings.hpp @@ -33,8 +33,8 @@ namespace pipedal bool rebootRequired_ = false; std::string alsaDevice_; uint64_t sampleRate_ = 0; - uint32_t bufferSize_ = 0; - uint32_t numberOfBuffers_ = 0; + uint32_t bufferSize_ = 64; + uint32_t numberOfBuffers_ = 2; public: JackServerSettings(); diff --git a/src/Lv2Effect.hpp b/src/Lv2Effect.hpp index c4bb19c..5a84ec3 100644 --- a/src/Lv2Effect.hpp +++ b/src/Lv2Effect.hpp @@ -244,7 +244,7 @@ namespace pipedal { if (index == -1) { - this->bypass = value != 0; + SetBypass(value != 0); } else { controlValues[index] = value; } diff --git a/src/MimeTypes.cpp b/src/MimeTypes.cpp index 91538cb..637df49 100644 --- a/src/MimeTypes.cpp +++ b/src/MimeTypes.cpp @@ -136,7 +136,7 @@ static std::string toLower(const std::string&value) void MimeTypes::AddMimeType(const std::string&extension_, const std::string&mimeType) { - std::string extension = "." + toLower(extension_); + std::string extension = std::string(".") + toLower(extension_); mimeTypeToExtension[mimeType] = extension; extensionToMimeType[extension] = mimeType; if (mimeType.starts_with("audio/")) diff --git a/src/PiPedalException.hpp b/src/PiPedalException.hpp index 54a9c9e..a2505d0 100644 --- a/src/PiPedalException.hpp +++ b/src/PiPedalException.hpp @@ -19,6 +19,7 @@ #pragma once #include +#include namespace pipedal { diff --git a/src/PiPedalSocket.cpp b/src/PiPedalSocket.cpp index 8f43dbb..3ab0abd 100644 --- a/src/PiPedalSocket.cpp +++ b/src/PiPedalSocket.cpp @@ -36,7 +36,7 @@ #include "AdminClient.hpp" #include "WifiConfigSettings.hpp" #include "WifiDirectConfigSettings.hpp" -#include "WifiChannels.hpp" +#include "WifiChannelSelectors.hpp" #include "SysExec.hpp" #include "PiPedalAlsa.hpp" #include @@ -973,7 +973,7 @@ public: { std::string country; pReader->read(&country); - std::vector channels = pipedal::getWifiChannels(country.c_str()); + std::vector channels = pipedal::getWifiChannelSelectors(country.c_str()); this->Reply(replyTo, "getWifiChannels", channels); } else if (message == "getPluginPresets") diff --git a/src/PiPedalUI.cpp b/src/PiPedalUI.cpp index 923f1aa..7b7a295 100644 --- a/src/PiPedalUI.cpp +++ b/src/PiPedalUI.cpp @@ -35,7 +35,7 @@ PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::files { auto pWorld = pHost->getWorld(); - AutoLilvNodes fileNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.pipedalUI__fileProperties, nullptr); + AutoLilvNodes fileNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris->pipedalUI__fileProperties, nullptr); LILV_FOREACH(nodes, i, fileNodes) { const LilvNode *fileNode = lilv_nodes_get(fileNodes, i); @@ -49,7 +49,7 @@ PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::files pHost->LogWarning(SS("Failed to read pipedalui::fileProperties. " << e.what())); } } - AutoLilvNodes frequencyPlotNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.pipedalUI__frequencyPlot, nullptr); + AutoLilvNodes frequencyPlotNodes = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris->pipedalUI__frequencyPlot, nullptr); LILV_FOREACH(nodes, i, frequencyPlotNodes) { const LilvNode *frequencyPlotNode = lilv_nodes_get(frequencyPlotNodes, i); @@ -65,7 +65,7 @@ PiPedalUI::PiPedalUI(PluginHost *pHost, const LilvNode *uiNode, const std::files } } - AutoLilvNodes portNotifications = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris.ui__portNotification, nullptr); + AutoLilvNodes portNotifications = lilv_world_find_nodes(pWorld, uiNode, pHost->lilvUris->ui__portNotification, nullptr); LILV_FOREACH(nodes, i, portNotifications) { const LilvNode *portNotificationNode = lilv_nodes_get(portNotifications, i); @@ -88,7 +88,7 @@ UiFileType::UiFileType(PluginHost *pHost, const LilvNode *node) AutoLilvNode label = lilv_world_get( pWorld, node, - pHost->lilvUris.rdfs__label, + pHost->lilvUris->rdfs__label, nullptr); if (label) { @@ -101,7 +101,7 @@ UiFileType::UiFileType(PluginHost *pHost, const LilvNode *node) AutoLilvNode fileExtension = lilv_world_get( pWorld, node, - pHost->lilvUris.pipedalUI__fileExtension, + pHost->lilvUris->pipedalUI__fileExtension, nullptr); if (fileExtension) { @@ -114,7 +114,7 @@ UiFileType::UiFileType(PluginHost *pHost, const LilvNode *node) AutoLilvNode mimeType = lilv_world_get( pWorld, node, - pHost->lilvUris.pipedalUI__mimeType, + pHost->lilvUris->pipedalUI__mimeType, nullptr); if (mimeType) { @@ -140,7 +140,7 @@ UiFileProperty::UiFileProperty(PluginHost *pHost, const LilvNode *node, const st AutoLilvNode label = lilv_world_get( pWorld, node, - pHost->lilvUris.rdfs__label, + pHost->lilvUris->rdfs__label, nullptr); if (label) { @@ -153,7 +153,7 @@ UiFileProperty::UiFileProperty(PluginHost *pHost, const LilvNode *node, const st AutoLilvNode index = lilv_world_get( pWorld, node, - pHost->lilvUris.lv2core__index, + pHost->lilvUris->lv2core__index, nullptr); if (index) { @@ -167,7 +167,7 @@ UiFileProperty::UiFileProperty(PluginHost *pHost, const LilvNode *node, const st AutoLilvNode directory = lilv_world_get( pWorld, node, - pHost->lilvUris.pipedalUI__directory, + pHost->lilvUris->pipedalUI__directory, nullptr); if (directory) { @@ -185,7 +185,7 @@ UiFileProperty::UiFileProperty(PluginHost *pHost, const LilvNode *node, const st AutoLilvNode patchProperty = lilv_world_get( pWorld, node, - pHost->lilvUris.pipedalUI__patchProperty, + pHost->lilvUris->pipedalUI__patchProperty, nullptr); if (patchProperty) { @@ -196,13 +196,13 @@ UiFileProperty::UiFileProperty(PluginHost *pHost, const LilvNode *node, const st throw std::logic_error("PiPedal FileProperty is missing pipedalui:patchProperty value."); } - AutoLilvNode portGroup = lilv_world_get(pWorld,node,pHost->lilvUris.portgroups__group,nullptr); + AutoLilvNode portGroup = lilv_world_get(pWorld,node,pHost->lilvUris->portgroups__group,nullptr); if (portGroup) { this->portGroup_ = portGroup.AsUri(); } - this->fileTypes_ = UiFileType::GetArray(pHost, node, pHost->lilvUris.pipedalUI__fileTypes); + this->fileTypes_ = UiFileType::GetArray(pHost, node, pHost->lilvUris->pipedalUI__fileTypes); } std::vector UiFileType::GetArray(PluginHost *pHost, const LilvNode *node, const LilvNode *uri) @@ -210,7 +210,7 @@ std::vector UiFileType::GetArray(PluginHost *pHost, const LilvNode * std::vector result; LilvWorld *pWorld = pHost->getWorld(); - LilvNodes *fileTypeNodes = lilv_world_find_nodes(pWorld, node, pHost->lilvUris.pipedalUI__fileTypes, nullptr); + LilvNodes *fileTypeNodes = lilv_world_find_nodes(pWorld, node, pHost->lilvUris->pipedalUI__fileTypes, nullptr); LILV_FOREACH(nodes, i, fileTypeNodes) { const LilvNode *fileTypeNode = lilv_nodes_get(fileTypeNodes, i); @@ -297,7 +297,7 @@ UiPortNotification::UiPortNotification(PluginHost *pHost, const LilvNode *node) // ] LilvWorld *pWorld = pHost->getWorld(); - AutoLilvNode portIndex = lilv_world_get(pWorld, node, pHost->lilvUris.ui__portIndex, nullptr); + AutoLilvNode portIndex = lilv_world_get(pWorld, node, pHost->lilvUris->ui__portIndex, nullptr); if (!portIndex) { this->portIndex_ = -1; @@ -306,7 +306,7 @@ UiPortNotification::UiPortNotification(PluginHost *pHost, const LilvNode *node) { this->portIndex_ = (uint32_t)lilv_node_as_int(portIndex); } - AutoLilvNode symbol = lilv_world_get(pWorld, node, pHost->lilvUris.lv2__symbol, nullptr); + AutoLilvNode symbol = lilv_world_get(pWorld, node, pHost->lilvUris->lv2__symbol, nullptr); if (!symbol) { this->symbol_ = ""; @@ -315,7 +315,7 @@ UiPortNotification::UiPortNotification(PluginHost *pHost, const LilvNode *node) { this->symbol_ = symbol.AsString(); } - AutoLilvNode plugin = lilv_world_get(pWorld, node, pHost->lilvUris.ui__plugin, nullptr); + AutoLilvNode plugin = lilv_world_get(pWorld, node, pHost->lilvUris->ui__plugin, nullptr); if (!plugin) { this->plugin_ = ""; @@ -324,7 +324,7 @@ UiPortNotification::UiPortNotification(PluginHost *pHost, const LilvNode *node) { this->plugin_ = plugin.AsUri(); } - AutoLilvNode protocol = lilv_world_get(pWorld, node, pHost->lilvUris.ui__protocol, nullptr); + AutoLilvNode protocol = lilv_world_get(pWorld, node, pHost->lilvUris->ui__protocol, nullptr); if (!protocol) { this->protocol_ = ""; @@ -399,7 +399,7 @@ UiFrequencyPlot::UiFrequencyPlot(PluginHost*pHost, const LilvNode*node, AutoLilvNode patchProperty = lilv_world_get( pWorld, node, - pHost->lilvUris.pipedalUI__patchProperty, + pHost->lilvUris->pipedalUI__patchProperty, nullptr); if (patchProperty) { @@ -414,7 +414,7 @@ UiFrequencyPlot::UiFrequencyPlot(PluginHost*pHost, const LilvNode*node, AutoLilvNode index = lilv_world_get( pWorld, node, - pHost->lilvUris.lv2core__index, + pHost->lilvUris->lv2core__index, nullptr); if (index) { @@ -425,17 +425,17 @@ UiFrequencyPlot::UiFrequencyPlot(PluginHost*pHost, const LilvNode*node, this->index_ = -1; } - AutoLilvNode portGroup = lilv_world_get(pWorld,node,pHost->lilvUris.portgroups__group,nullptr); + AutoLilvNode portGroup = lilv_world_get(pWorld,node,pHost->lilvUris->portgroups__group,nullptr); if (portGroup) { this->portGroup_ = portGroup.AsUri(); } - this->xLeft_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__xLeft,100); - this->xRight_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__xRight,22000); - this->yTop_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__yTop,5); - this->yBottom_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__yBottom,-35); - this->xLog_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__xLog,-35); - this->width_ = GetFloat(pWorld,node,pHost->lilvUris.pipedalUI__width,60); + this->xLeft_ = GetFloat(pWorld,node,pHost->lilvUris->pipedalUI__xLeft,100); + this->xRight_ = GetFloat(pWorld,node,pHost->lilvUris->pipedalUI__xRight,22000); + this->yTop_ = GetFloat(pWorld,node,pHost->lilvUris->pipedalUI__yTop,5); + this->yBottom_ = GetFloat(pWorld,node,pHost->lilvUris->pipedalUI__yBottom,-35); + this->xLog_ = GetFloat(pWorld,node,pHost->lilvUris->pipedalUI__xLog,-35); + this->width_ = GetFloat(pWorld,node,pHost->lilvUris->pipedalUI__width,60); } diff --git a/src/PluginHost.cpp b/src/PluginHost.cpp index 606b9cb..ea74f97 100644 --- a/src/PluginHost.cpp +++ b/src/PluginHost.cpp @@ -281,9 +281,11 @@ void PluginHost::OnConfigurationChanged(const JackConfiguration &configuration, PluginHost::~PluginHost() { - lilvUris.Free(); - free_world(); + delete lilvUris; + lilvUris = nullptr; delete urids; + urids = nullptr; + free_world(); } void PluginHost::free_world() @@ -408,7 +410,8 @@ void PluginHost::Load(const char *lv2Path) // LilvNode*lv2_path = lilv_new_file_uri(pWorld,NULL,lv2Path); // lilv_world_set_option(world,LILV_OPTION_LV2_PATH,lv) - lilvUris.Initialize(pWorld); + lilvUris = new LilvUris(); + lilvUris->Initialize(pWorld); const LilvPlugins *plugins = lilv_world_get_all_plugins(pWorld); @@ -549,7 +552,7 @@ const char *PluginHost::RDFS__range = "http://www.w3.org/2000/01/rdf-schema#" LilvNode *PluginHost::get_comment(const std::string &uri) { AutoLilvNode uriNode = lilv_new_uri(pWorld, uri.c_str()); - LilvNode *result = lilv_world_get(pWorld, uriNode, lilvUris.rdfs__Comment, nullptr); + LilvNode *result = lilv_world_get(pWorld, uriNode, lilvUris->rdfs__Comment, nullptr); return result; } @@ -560,7 +563,7 @@ static bool ports_sort_compare(std::shared_ptr &p1, const std::shar bool Lv2PluginInfo::HasFactoryPresets(PluginHost *lv2Host, const LilvPlugin *plugin) { - AutoLilvNodes nodes = lilv_plugin_get_related(plugin, lv2Host->lilvUris.presets__preset); + AutoLilvNodes nodes = lilv_plugin_get_related(plugin, lv2Host->lilvUris->presets__preset); bool result = false; LILV_FOREACH(nodes, iNode, nodes) { @@ -583,7 +586,7 @@ std::shared_ptr Lv2PluginInfo::FindWritablePathProperties(PluginHost LilvWorld *pWorld = lv2Host->getWorld(); AutoLilvNode pluginUri = lilv_plugin_get_uri(pPlugin); - AutoLilvNodes patchWritables = lilv_world_find_nodes(pWorld, pluginUri, lv2Host->lilvUris.patch__writable, nullptr); + AutoLilvNodes patchWritables = lilv_world_find_nodes(pWorld, pluginUri, lv2Host->lilvUris->patch__writable, nullptr); std::vector fileProperties; @@ -593,12 +596,12 @@ std::shared_ptr Lv2PluginInfo::FindWritablePathProperties(PluginHost if (propertyUri) { // a lv2:Parameter? - if (lilv_world_ask(pWorld, propertyUri, lv2Host->lilvUris.isA, lv2Host->lilvUris.lv2core__Parameter)) + if (lilv_world_ask(pWorld, propertyUri, lv2Host->lilvUris->isA, lv2Host->lilvUris->lv2core__Parameter)) { // rfs:range atom:Path? - if (lilv_world_ask(pWorld, propertyUri, lv2Host->lilvUris.rdfs__range, lv2Host->lilvUris.atom__Path)) + if (lilv_world_ask(pWorld, propertyUri, lv2Host->lilvUris->rdfs__range, lv2Host->lilvUris->atom__Path)) { - AutoLilvNode label = lilv_world_get(pWorld, propertyUri, lv2Host->lilvUris.rdfs__label, nullptr); + AutoLilvNode label = lilv_world_get(pWorld, propertyUri, lv2Host->lilvUris->rdfs__label, nullptr); std::string strLabel = label.AsString(); if (strLabel.length() != 0) { @@ -611,7 +614,7 @@ std::shared_ptr Lv2PluginInfo::FindWritablePathProperties(PluginHost std::make_shared( strLabel, propertyUri.AsUri(), lv2DirectoryName); - AutoLilvNodes dc_types = lilv_world_find_nodes(pWorld, propertyUri, lv2Host->lilvUris.dc__format, nullptr); + AutoLilvNodes dc_types = lilv_world_find_nodes(pWorld, propertyUri, lv2Host->lilvUris->dc__format, nullptr); LILV_FOREACH(nodes, i, dc_types) { AutoLilvNode dc_type = lilv_nodes_get(dc_types, i); @@ -657,10 +660,10 @@ Lv2PluginInfo::Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvP AutoLilvNode name = (lilv_plugin_get_name(pPlugin)); this->name_ = nodeAsString(name); - AutoLilvNode brand = lilv_world_get(pWorld,plugUri,lv2Host->lilvUris.mod__brand, nullptr); + AutoLilvNode brand = lilv_world_get(pWorld,plugUri,lv2Host->lilvUris->mod__brand, nullptr); this->brand_ = nodeAsString(brand); - AutoLilvNode label = lilv_world_get(pWorld,plugUri,lv2Host->lilvUris.mod__label, nullptr); + AutoLilvNode label = lilv_world_get(pWorld,plugUri,lv2Host->lilvUris->mod__label, nullptr); this->label_ = nodeAsString(label); if (label_.length() == 0) { @@ -738,7 +741,7 @@ Lv2PluginInfo::Lv2PluginInfo(PluginHost *lv2Host, LilvWorld *pWorld, const LilvP AutoLilvNode pipedalUINode = lilv_world_get( pWorld, lilv_plugin_get_uri(pPlugin), - lv2Host->lilvUris.pipedalUI__ui, + lv2Host->lilvUris->pipedalUI__ui, nullptr); if (pipedalUINode) { @@ -872,12 +875,12 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP if (default_value_ < min_value_) default_value_ = min_value_; - this->is_logarithmic_ = lilv_port_has_property(plugin, pPort, host->lilvUris.port_logarithmic); + this->is_logarithmic_ = lilv_port_has_property(plugin, pPort, host->lilvUris->port_logarithmic); // typo in invada plugins. - this->is_logarithmic_ |= lilv_port_has_property(plugin, pPort, host->lilvUris.invada_portprops__logarithmic); + this->is_logarithmic_ |= lilv_port_has_property(plugin, pPort, host->lilvUris->invada_portprops__logarithmic); - AutoLilvNodes priority_nodes = lilv_port_get_value(plugin, pPort, host->lilvUris.port__display_priority); + AutoLilvNodes priority_nodes = lilv_port_get_value(plugin, pPort, host->lilvUris->port__display_priority); this->display_priority_ = -1; if (priority_nodes) @@ -889,7 +892,7 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP } } - AutoLilvNodes range_steps_nodes = lilv_port_get_value(plugin, pPort, host->lilvUris.port_range_steps); + AutoLilvNodes range_steps_nodes = lilv_port_get_value(plugin, pPort, host->lilvUris->port_range_steps); this->range_steps_ = 0; if (range_steps_nodes) { @@ -899,13 +902,13 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP this->range_steps_ = lilv_node_as_int(range_steps_node); } } - this->integer_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris.integer_property_uri); + this->integer_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris->integer_property_uri); - this->enumeration_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris.enumeration_property_uri); + this->enumeration_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris->enumeration_property_uri); - this->toggled_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris.core__toggled); - this->not_on_gui_ = lilv_port_has_property(plugin, pPort, host->lilvUris.portprops__not_on_gui_property_uri); - this->connection_optional_ = lilv_port_has_property(plugin, pPort, host->lilvUris.core__connectionOptional); + this->toggled_property_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__toggled); + this->not_on_gui_ = lilv_port_has_property(plugin, pPort, host->lilvUris->portprops__not_on_gui_property_uri); + this->connection_optional_ = lilv_port_has_property(plugin, pPort, host->lilvUris->core__connectionOptional); LilvScalePoints *pScalePoints = lilv_port_get_scale_points(plugin, pPort); LILV_FOREACH(scale_points, iSP, pScalePoints) @@ -929,16 +932,16 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP is_atom_port_ = is_a(host, LV2_ATOM__AtomPort); is_cv_port_ = is_a(host, LV2_CORE__CVPort); - supports_midi_ = lilv_port_supports_event(plugin, pPort, host->lilvUris.midi__event); - supports_time_position_ = lilv_port_supports_event(plugin, pPort, host->lilvUris.time_Position); + supports_midi_ = lilv_port_supports_event(plugin, pPort, host->lilvUris->midi__event); + supports_time_position_ = lilv_port_supports_event(plugin, pPort, host->lilvUris->time_Position); - AutoLilvNode designationValue = lilv_port_get(plugin, pPort, host->lilvUris.core__designation); + AutoLilvNode designationValue = lilv_port_get(plugin, pPort, host->lilvUris->core__designation); designation_ = nodeAsString(designationValue); - AutoLilvNode portGroup_value = lilv_port_get(plugin, pPort, host->lilvUris.portgroups__group); + AutoLilvNode portGroup_value = lilv_port_get(plugin, pPort, host->lilvUris->portgroups__group); port_group_ = nodeAsString(portGroup_value); - AutoLilvNode unitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris.units__unit); + AutoLilvNode unitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris->units__unit); if (unitsValueUri) { this->units_ = UriToUnits(nodeAsString(unitsValueUri)); @@ -946,7 +949,7 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP else { // invada plugins use the wrong URI. - AutoLilvNode invadaUnitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris.invada_units__unit); + AutoLilvNode invadaUnitsValueUri = lilv_port_get(plugin, pPort, host->lilvUris->invada_units__unit); if (invadaUnitsValueUri) { std::string uri = nodeAsString(invadaUnitsValueUri); @@ -964,10 +967,10 @@ Lv2PortInfo::Lv2PortInfo(PluginHost *host, const LilvPlugin *plugin, const LilvP } } - AutoLilvNode commentNode = lilv_port_get(plugin, pPort, host->lilvUris.rdfs__Comment); + AutoLilvNode commentNode = lilv_port_get(plugin, pPort, host->lilvUris->rdfs__Comment); this->comment_ = nodeAsString(commentNode); - AutoLilvNode bufferType = lilv_port_get(plugin, pPort, host->lilvUris.atom__bufferType); + AutoLilvNode bufferType = lilv_port_get(plugin, pPort, host->lilvUris->atom__bufferType); this->buffer_type_ = ""; if (bufferType) @@ -1186,7 +1189,7 @@ std::vector PluginHost::LoadFactoryPluginPreset( throw PiPedalStateException("No such plugin."); } - LilvNodes *presets = lilv_plugin_get_related(plugin, lilvUris.presets__preset); + LilvNodes *presets = lilv_plugin_get_related(plugin, lilvUris->presets__preset); LILV_FOREACH(nodes, i, presets) { const LilvNode *preset = lilv_nodes_get(presets, i); @@ -1268,7 +1271,7 @@ PluginPresets PluginHost::GetFactoryPluginPresets(const std::string &pluginUri) PluginPresets result; result.pluginUri_ = pluginUri; - LilvNodes *presets = lilv_plugin_get_related(plugin, lilvUris.presets__preset); + LilvNodes *presets = lilv_plugin_get_related(plugin, lilvUris->presets__preset); LILV_FOREACH(nodes, i, presets) { const LilvNode *preset = lilv_nodes_get(presets, i); @@ -1344,9 +1347,9 @@ Lv2PortGroup::Lv2PortGroup(PluginHost *lv2Host, const std::string &groupUri) this->uri_ = groupUri; AutoLilvNode uri = lilv_new_uri(pWorld, groupUri.c_str()); - LilvNode *symbolNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris.lv2core__symbol, nullptr); + LilvNode *symbolNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris->lv2core__symbol, nullptr); symbol_ = nodeAsString(symbolNode); - LilvNode *nameNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris.lv2core__name, nullptr); + LilvNode *nameNode = lilv_world_get(pWorld, uri, lv2Host->lilvUris->lv2core__name, nullptr); name_ = nodeAsString(nameNode); } diff --git a/src/PluginHost.hpp b/src/PluginHost.hpp index 2a8423f..9423ff2 100644 --- a/src/PluginHost.hpp +++ b/src/PluginHost.hpp @@ -727,7 +727,7 @@ namespace pipedal AutoLilvNode dc__format; }; - LilvUris lilvUris; + LilvUris* lilvUris = nullptr; private: bool vst3Enabled = true; diff --git a/src/RegDb.cpp b/src/RegDb.cpp deleted file mode 100644 index e79e533..0000000 --- a/src/RegDb.cpp +++ /dev/null @@ -1,249 +0,0 @@ -// Copyright (c) 2022 Robin Davies -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#include "pch.h" -#include "RegDb.hpp" -#include -#include -#include -#include -#include "PiPedalException.hpp" -#include -#include - -#define REGDB_MAGIC 0x52474442 -#define REGDB_VERSION 19 - - -using namespace pipedal; -using namespace std; - -struct RegDbFileHeader { - uint32_t magic; - uint32_t version; - uint32_t countryOffset; - uint32_t countryCount; - uint32_t signatureLength; - - void toNs() { - this->magic = htonl(this->magic); - this->version = htonl(this->version); - this->countryOffset = htonl(this->countryOffset); - this->countryCount = htonl(this->countryCount); - this->signatureLength = htonl(this->signatureLength); - } -}; - -struct CountryHeader { - char alpha2[2]; - uint8_t pad; - uint8_t dfsRegion; // first 2 bits only. - uint32_t rulesOffset; - - void toNs() { - this->rulesOffset = htonl(rulesOffset); - } - -}; -struct RulesCollection { - uint32_t ruleCount; - uint32_t ruleOffsets[1]; - - void toNs() { - this->ruleCount = htonl(this->ruleCount); - uint32_t *p = ruleOffsets; - for (uint32_t i = 0; i < this->ruleCount; ++i) - { - *p = htonl(*p); - ++p; - } - } -}; - -struct Rule { - uint32_t frequencyRangeOffset; - uint32_t powerRuleOffset; - uint32_t flags; - - void toNs() { - frequencyRangeOffset = htonl(frequencyRangeOffset); - powerRuleOffset = htonl(powerRuleOffset); - flags = htonl(flags); - } -}; - -struct FrequencyRange { - uint32_t startFrequency; // in khz. - uint32_t endFrequency; // in khz. - uint32_t maxBandwidth; // in khz. - void toNs() { - startFrequency = htonl(startFrequency); - endFrequency = htonl(endFrequency); - maxBandwidth = htonl(maxBandwidth); - } -}; -struct PowerRule { - uint32_t maximumAntennaGain; - uint32_t maximumEirp; - void toNs() { - maximumAntennaGain = htonl(maximumAntennaGain); - maximumEirp = htonl(maximumEirp); - } -}; - - - -const char*filePaths[] = -{ - "/usr/lib/crda/regulatory.bin" -}; - -static std::filesystem::path getFilePath() -{ - for (size_t i = 0; i < sizeof(filePaths)/sizeof(filePaths[0]); ++i) - { - std::filesystem::path path(filePaths[i]); - if (std::filesystem::exists(path)) { - return path; - } - } - throw PiPedalException("Could not find 'regulatory.bin' file."); -} - -RegDb::~RegDb() -{ - delete[] pData; -} - -RegDb::RegDb() -:pData(nullptr) -{ - RegDbFileHeader header; - std::filesystem::path path = getFilePath(); - ifstream f(path); - if (!f.is_open()) { - stringstream s; - s << "Can't read " << path; - throw PiPedalException(s.str()); - } - size_t fileSize = std::filesystem::file_size(path); - this->pData = new uint8_t[fileSize]; - f.read((char*)this->pData,fileSize); - - // convert from big-endian to local byte order; - RegDbFileHeader *fileHeader = (RegDbFileHeader*)pData; - fileHeader->toNs(); - if (fileHeader->magic != REGDB_MAGIC) - { - throw PiPedalException("Invalid file format."); - } - std::unordered_set visited; - - CountryHeader*countryHeader = (CountryHeader*)(pData + fileHeader->countryOffset); - for (uint32_t i = 0; i < fileHeader->countryCount; ++i) - { - countryHeader->toNs(); - if (visited.count(countryHeader->rulesOffset) == 0) - { - visited.insert(countryHeader->rulesOffset); - RulesCollection*pRules = (RulesCollection*)(pData + countryHeader->rulesOffset); - pRules->toNs(); - for (uint32_t nRule = 0; nRule < pRules->ruleCount; ++nRule) - { - uint32_t ruleOffset = pRules->ruleOffsets[nRule]; - if (visited.count(ruleOffset) == 0) - { - visited.insert(ruleOffset); - Rule *pRule = (Rule*)(pData + ruleOffset); - pRule->toNs(); - - if (visited.count(pRule->frequencyRangeOffset) == 0) - { - visited.insert(pRule->frequencyRangeOffset); - - FrequencyRange*pf = (FrequencyRange*)(pData + pRule->frequencyRangeOffset); - pf->toNs(); - } - if (visited.count(pRule->powerRuleOffset) == 0) - { - visited.insert(pRule->powerRuleOffset); - - PowerRule *pr = (PowerRule*)(pData + pRule->powerRuleOffset); - pr->toNs(); - } - } - } - } - ++countryHeader; - } - -} -bool CrdbRules::GetFrequencyRule(uint32_t frequencyRuleMHz, FrequencyRule*pResult) -{ - memset(pResult,0,sizeof(FrequencyRule)); - RulesCollection*pRules = (RulesCollection*)(regDb->pData + countryOffset); - uint32_t frequencyRuleKHz = frequencyRuleMHz*1000; - for (uint32_t i = 0; i < pRules->ruleCount; ++i) - { - Rule *pRule = (Rule*)(regDb->pData + pRules->ruleOffsets[i]); - FrequencyRange*pf = (FrequencyRange*)(regDb->pData + pRule->frequencyRangeOffset); - if (frequencyRuleKHz >= pf->startFrequency && frequencyRuleKHz < pf->endFrequency) - { - PowerRule *pr = (PowerRule*)(regDb->pData + pRule->powerRuleOffset); - pResult->flags = (RegRuleFlags)(pRule->flags); - pResult->maximumAntennaGain = pr->maximumAntennaGain; - pResult->maximumEirp = pr->maximumEirp; - return true; - } - } - return false; -} -CrdbRules*RegDb::GetCrdbRules(const char*countryCodeIso633) -{ - const char c0 = countryCodeIso633[0]; - if (c0 == '\0') return nullptr; - const char c1 = countryCodeIso633[1]; - - RegDbFileHeader *fileHeader = (RegDbFileHeader*)pData; - CountryHeader*countryHeader = (CountryHeader*)(pData + fileHeader->countryOffset); - for (uint32_t i = 0; i < fileHeader->countryCount; ++i) - { - if (countryHeader->alpha2[0] == c0 && countryHeader->alpha2[1] == c1) { - return new CrdbRules( - this, - countryHeader->rulesOffset, - (DfsRegion)(countryHeader->dfsRegion & 0x03) - ); - } - ++countryHeader; - } - return nullptr; -} - -CrdbRules::CrdbRules(RegDb *regDb,uint32_t countryOffset, DfsRegion dfsRegion ) -: regDb(regDb), - countryOffset(countryOffset), - dfsRegion(dfsRegion) -{ -} - -DfsRegion CrdbRules::GetDfsRegion() const { - return this->dfsRegion; -} - diff --git a/src/RegDb.hpp b/src/RegDb.hpp deleted file mode 100644 index 26d0f76..0000000 --- a/src/RegDb.hpp +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) 2022 Robin Davies -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -#pragma once - -#include - -namespace pipedal { - -// sync with flags) != 0; } -}; - -class RegDb; - -class CrdbRules { - friend class RegDb; - RegDb *regDb = nullptr; - uint32_t countryOffset; - DfsRegion dfsRegion; - CrdbRules(RegDb *regDb,uint32_t countryOffset, DfsRegion dfsRegion ); -public: - virtual DfsRegion GetDfsRegion() const; - virtual bool GetFrequencyRule(uint32_t frequencyMHz,FrequencyRule*pResult); -}; - -class RegDb { -private: - friend class CrdbRules; - uint8_t*pData; - -public: - RegDb(); - ~RegDb(); - CrdbRules *GetCrdbRules(const char*countryCodeIso6333); - bool isValid() const { return pData != nullptr; } -}; - -} \ No newline at end of file diff --git a/src/SetWifiConfig.cpp b/src/SetWifiConfig.cpp index 4070e53..035f049 100644 --- a/src/SetWifiConfig.cpp +++ b/src/SetWifiConfig.cpp @@ -17,7 +17,6 @@ // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -#include "pch.h" #include "ss.hpp" #include "P2pConfigFiles.hpp" @@ -44,17 +43,46 @@ using namespace std; static char DNSMASQ_APD_PATH[] = "/etc/dnsmasq.d/30-pipedal-apd.conf"; static char DNSMASQ_P2P_SOURCE_PATH[] = "/etc/pipedal/config/templates/30-pipedal-p2p.conf"; - static char DNSMASQ_P2P_PATH[] = "/etc/dnsmasq.d/30-pipedal-p2p.conf"; +static char NETWORK_MANAGER_DNSMASQ_P2P_SOURCE_PATH[] = "/etc/pipedal/config/templates/30-pipedal-p2p-dnsmasq-nm.conf"; +static char NETWORK_MANAGER_DNSMASQ_P2P_PATH[] = "/etc/dnsmasq.d/30-pipedal-p2p-dnsmasq-nm.conf"; + +static char NETWORK_MANAGER_SERVICE_PATH[] = "/usr/lib/systemd/system/NetworkManager.service"; +static char NETWORK_MANAGER_CONFIG_PATH[] = "/etc/NetworkManager/conf.d/50-pipedal-nm.conf"; +static char NETWORK_MANAGER_CONFIG_SOURCE_PATH[] = "/etc/pipedal/config/templates/50-pipedal-nm.conf"; + +//forward declarations +static void ConfigDhcpcdForP2p(); +static void applyNetworkManagerP2pConfig(); +static void applyDnsmasqP2pConfig(); + + +static std::string gWlanAddress = "wlan0"; + +void pipedal::SetWifiConfigWLanAddress(const std::string &wLanAddress) +{ + gWlanAddress = wLanAddress; +} +const std::string &pipedal::GetWifiConfigWlanAddress() +{ + return gWlanAddress; +} + +bool pipedal::UsingNetworkManager() +{ + // does the neworkManager service path exists? + return std::filesystem::exists(NETWORK_MANAGER_SERVICE_PATH); +} + static bool IsApdInstalled() { - + return std::filesystem::exists(DNSMASQ_APD_PATH); } static bool IsP2pInstalled() { - return std::filesystem::exists(DNSMASQ_P2P_PATH); + return std::filesystem::exists(DNSMASQ_P2P_PATH) | std::filesystem::exists(NETWORK_MANAGER_DNSMASQ_P2P_PATH); } static void restoreApdDhcpdConfFile() @@ -112,7 +140,7 @@ static void restoreP2pDhcpdConfFile() dhcpcd.SetLineValue(line, hostNameLine); } - line = dhcpcd.GetLineNumber("interface p2p-wlan0-0"); + line = dhcpcd.GetLineNumber("interface p2p-wlan0-0"); // pre bookworm. if (line != -1) { dhcpcd.EraseLine(line); @@ -129,6 +157,14 @@ static void restoreP2pDhcpdConfFile() } } } + line = dhcpcd.GetLineNumberStartingWith("allowinterfaces p2p-"); // bookworm + if (line != -1) + { + while (line < dhcpcd.GetLineCount()) + { + dhcpcd.EraseLine(line); + } + } dhcpcd.Save(dhcpcdConfig); } } @@ -143,10 +179,19 @@ static void restoreApdDnsmasqConfFile() } static void restoreP2pDnsmasqConfFile() { - std::filesystem::path path(DNSMASQ_P2P_PATH); - if (std::filesystem::exists(path)) { - std::filesystem::remove(path); + std::filesystem::path path(DNSMASQ_P2P_PATH); + if (std::filesystem::exists(path)) + { + std::filesystem::remove(path); + } + } + { + std::filesystem::path path(NETWORK_MANAGER_DNSMASQ_P2P_PATH); + if (std::filesystem::exists(path)) + { + std::filesystem::remove(path); + } } } @@ -168,6 +213,89 @@ static void UninstallHostApd() } } +static void InstallP2p(const WifiDirectConfigSettings &settings) +{ + cout << "Enabling P2P" << endl; + + settings.Save(); + // ******************* device_uuid + + ServiceConfiguration deviceIdFile; + deviceIdFile.Load(); + deviceIdFile.deviceName = settings.hotspotName_; + deviceIdFile.Save(); + + // ******************** dsnmasq ****** + + std::filesystem::remove(DNSMASQ_P2P_PATH); + std::filesystem::remove(NETWORK_MANAGER_DNSMASQ_P2P_PATH); + + // dnsmasq + if (UsingNetworkManager()) + { + applyDnsmasqP2pConfig(); + } + else + { + std::filesystem::copy_file(DNSMASQ_P2P_SOURCE_PATH, DNSMASQ_P2P_PATH); + } + + // ****** dhcpd.conf ***/ + std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf"); + if (std::filesystem::exists(dhcpcdConfig)) + { + ConfigDhcpcdForP2p(); + } + + /* Network manager */ + if (UsingNetworkManager()) + { + applyNetworkManagerP2pConfig(); + } + + // **************** start services ************ + + cout << "Starting P2P services." << endl; + sysExec("rfkill unblock wlan"); + + sysExec(SYSTEMCTL_BIN " daemon-reload"); + sysExec(SYSTEMCTL_BIN " stop pipedal_nm_p2pd"); + sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd"); + sysExec(SYSTEMCTL_BIN " stop dhcpcd"); + if (UsingNetworkManager()) + { + sysExec(SYSTEMCTL_BIN " restart NetworkManager"); + // NetworkManager takes care of resetting wpa_supplicant. + } + else + { + sysExec(SYSTEMCTL_BIN " restart wpa_supplicant"); + } + sysExec(SYSTEMCTL_BIN " start dhcpcd"); + + sysExec(SYSTEMCTL_BIN " enable wpa_supplicant"); // ?? Not sure that's still right. :-/ + sysExec(SYSTEMCTL_BIN " start dnsmasq"); + sysExec(SYSTEMCTL_BIN " enable dnsmasq"); + if (UsingNetworkManager()) + { + if (sysExec(SYSTEMCTL_BIN " start pipedal_nm_p2pd") != EXIT_SUCCESS) + { + throw PiPedalException("Unable to start the Wi-Fi Direct access point service (pipedal_nm_p2pd)."); + } + sysExec(SYSTEMCTL_BIN " enable pipedal_nm_p2pd"); + } + else + { + if (sysExec(SYSTEMCTL_BIN " start pipedal_p2pd") != EXIT_SUCCESS) + { + throw PiPedalException("Unable to start the Wi-Fi Direct access point service (pipedal_p2pd)."); + } + sysExec(SYSTEMCTL_BIN " enable pipedal_p2pd"); + } + + sysExec(SYSTEMCTL_BIN " restart pipedald"); +} + static void UninstallP2p(); void pipedal::SetWifiConfig(const WifiConfigSettings &settings) @@ -371,18 +499,53 @@ interface p2p-wlan0-0 Watch resolv.conf to make sure we don't lose DNS servers. ************************************************************************************/ +using namespace pipedal; + +static void restoreNetworkManagerP2pConfig() +{ + std::filesystem::path path(NETWORK_MANAGER_CONFIG_PATH); + if (std::filesystem::exists(path)) + { + std::filesystem::remove(path); + } +} +static void applyNetworkManagerP2pConfig() +{ + std::filesystem::path path(NETWORK_MANAGER_CONFIG_PATH); + + std::map map; + map["WLAN"] = GetWifiConfigWlanAddress(); + WriteTemplateFile(map, NETWORK_MANAGER_CONFIG_SOURCE_PATH, NETWORK_MANAGER_CONFIG_PATH); +} + +static void applyDnsmasqP2pConfig() +{ + std::map map; + map["WLAN"] = GetWifiConfigWlanAddress(); + WriteTemplateFile(map, NETWORK_MANAGER_DNSMASQ_P2P_SOURCE_PATH, NETWORK_MANAGER_DNSMASQ_P2P_PATH); +} + void UninstallP2p() { if (IsP2pInstalled()) { - sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd"); - sysExec(SYSTEMCTL_BIN " disable pipedal_p2pd"); + if (UsingNetworkManager()) + { + sysExec(SYSTEMCTL_BIN " stop pipedal_nm_p2pd"); + sysExec(SYSTEMCTL_BIN " disable pipedal_nm_p2pd"); + } + else + { + sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd"); + sysExec(SYSTEMCTL_BIN " disable pipedal_p2pd"); + } sysExec(SYSTEMCTL_BIN " stop dnsmasq"); sysExec(SYSTEMCTL_BIN " disable dnsmasq"); restoreP2pDhcpdConfFile(); restoreP2pDnsmasqConfFile(); + restoreNetworkManagerP2pConfig(); sysExec(SYSTEMCTL_BIN " restart dhcpcd"); @@ -393,6 +556,91 @@ void UninstallP2p() } } +static void RemoveDhcpcdConfig() +{ + std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf"); + SystemConfigFile dhcpcd(dhcpcdConfig); + + int line = dhcpcd.GetLineNumber("interface p2p-wlan0-0"); + if (line != -1) + { + dhcpcd.EraseLine(line); + while (line < dhcpcd.GetLineCount()) + { + const std::string &lineValue = dhcpcd.GetLineValue(line); + if (lineValue.length() > 0 && (lineValue[0] == ' ' || lineValue[0] == '\t')) + { + dhcpcd.EraseLine(line); + } + else + { + break; + } + } + } + line = dhcpcd.GetLineNumberStartingWith("allowinterfaces p2p-"); + if (line != -1) + { + dhcpcd.EraseLine(line); + while (line < dhcpcd.GetLineCount()) + { + dhcpcd.EraseLine(line); + } + } +} +static void ConfigDhcpcdForP2p() +{ + RemoveDhcpcdConfig(); + + std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf"); + cout << "Updating /etc/dhcpcd.conf" << endl; + SystemConfigFile dhcpcd(dhcpcdConfig); + + // dhcpcd.conf: + // ====== + // interface p2p-wlan0-0 + // static ip_address=172.24.0.1/24 + // domain_name_server=172.24.0.1 + + int line = dhcpcd.GetLineThatStartsWith("hostname"); + std::string hostNameLine; + hostNameLine = "hostname"; // the default value. + if (line != -1) + { + dhcpcd.SetLineValue(line, hostNameLine); + } + else + { + dhcpcd.AppendLine(hostNameLine); + } + + if (!UsingNetworkManager()) + { + line = dhcpcd.GetLineCount(); + // interface p2p-wlan0-0 + // static ip_address=172.24.0.1/16 (trying int on .1.) + // domain_name_server=172.24.0.1 + + dhcpcd.InsertLine(line++, "interface p2p-wlan0-0"); + dhcpcd.InsertLine(line++, " static ip_address=" P2P_INTERFACE_ADDR); + dhcpcd.InsertLine(line++, " nohook wpa_supplicant"); + } + else + { + if (line == -1) + { + line = dhcpcd.GetLineCount(); + } + // interface p2p-wlan0-0 + // static ip_address=172.24.0.1/16 (trying int on .1.) + // domain_name_server=172.24.0.1 + + dhcpcd.InsertLine(line++, SS("allowinterfaces p2p-" << GetWifiConfigWlanAddress() << "-*").c_str()); + dhcpcd.InsertLine(line++, "static ip_address=" P2P_INTERFACE_ADDR); + dhcpcd.InsertLine(line++, "nohook wpa_supplicant"); + } + dhcpcd.Save(dhcpcdConfig); +} void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings) { @@ -414,107 +662,7 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings) } else { - cout << "Enabling P2P" << endl; - - settings.Save(); - // ******************* device_uuid - - ServiceConfiguration deviceIdFile; - deviceIdFile.Load(); - deviceIdFile.deviceName = settings.hotspotName_; - deviceIdFile.Save(); - - // ******************** dsnmasq ****** - - std::filesystem::remove(DNSMASQ_P2P_PATH); - std::filesystem::copy_file(DNSMASQ_P2P_SOURCE_PATH, DNSMASQ_P2P_PATH); - - // ****** dhcpd.conf ***/ - std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf"); - if (std::filesystem::exists(dhcpcdConfig)) - { - cout << "Updating /etc/dhcpcd.conf" << endl; - SystemConfigFile dhcpcd(dhcpcdConfig); - - // dhcpcd.conf: - // ====== - // interface p2p-wlan0-0 - // static ip_address=172.24.0.1/24 - // domain_name_server=172.24.0.1 - - int line = dhcpcd.GetLineThatStartsWith("hostname"); - std::string hostNameLine; - if (false) - { - // hostNameLine = "hostname " + settings.mdnsName_; - } - else - { - hostNameLine = "hostname"; // the default value. - } - if (line != -1) - { - dhcpcd.SetLineValue(line, hostNameLine); - } - else - { - dhcpcd.AppendLine(hostNameLine); - } - - // erase any existing interface for p2p-wlan0-0 - line = dhcpcd.GetLineNumber("interface p2p-wlan0-0"); - if (line != -1) - { - dhcpcd.EraseLine(line); - while (line < dhcpcd.GetLineCount()) - { - const std::string &lineValue = dhcpcd.GetLineValue(line); - if (lineValue.length() > 0 && (lineValue[0] == ' ' || lineValue[0] == '\t')) - { - dhcpcd.EraseLine(line); - } - else - { - break; - } - } - } - if (line == -1) - { - dhcpcd.AppendLine(""); - line = dhcpcd.GetLineCount(); - } - // interface p2p-wlan0-0 - // static ip_address=172.24.0.1/16 (trying int on .1.) - // domain_name_server=172.24.0.1 - - dhcpcd.InsertLine(line++, "interface p2p-wlan0-0"); - dhcpcd.InsertLine(line++, " static ip_address=" P2P_INTERFACE_ADDR); - dhcpcd.InsertLine(line++, " nohook wpa_supplicant"); - // dhcpcd.InsertLine(line++, " domain_name_servers=" P2P_IP_ADDRESS); - dhcpcd.Save(dhcpcdConfig); - } - - // **************** start services ************ - - cout << "Starting P2P services." << endl; - sysExec("rfkill unblock wlan"); - - sysExec(SYSTEMCTL_BIN " daemon-reload"); - - sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd"); - sysExec(SYSTEMCTL_BIN " restart dhcpcd"); - sysExec(SYSTEMCTL_BIN " start wpa_supplicant"); - sysExec(SYSTEMCTL_BIN " enable wpa_supplicant"); // ?? Not sure that's still right. :-/ - sysExec(SYSTEMCTL_BIN " start dnsmasq"); - sysExec(SYSTEMCTL_BIN " enable dnsmasq"); - sysExec(SYSTEMCTL_BIN " start pipedal_p2pd"); - if (sysExec(SYSTEMCTL_BIN " start pipedal_p2pd") != 0) - { - throw PiPedalException("Unable to start the Wi-Fi Direct access point."); - } - - sysExec(SYSTEMCTL_BIN " enable pipedal_p2pd"); + InstallP2p(settings); sysExec(SYSTEMCTL_BIN " restart pipedald"); } } @@ -531,7 +679,7 @@ void pipedal::OnWifiUninstall() { UninstallHostApd(); } - else if (IsP2pInstalled()) + if (IsP2pInstalled()) { UninstallP2p(); } @@ -548,3 +696,12 @@ void pipedal::OnWifiInstallComplete() // sysExec(SYSTEMCTL_BIN " daemon-reload"); // } } + +static void restartNetworkManagerService() +{ + if (UsingNetworkManager()) + { + sysExec(SYSTEMCTL_BIN " restart NetworkManager"); + } +} + diff --git a/src/SetWifiConfig.hpp b/src/SetWifiConfig.hpp index 3c3f09c..e902b60 100644 --- a/src/SetWifiConfig.hpp +++ b/src/SetWifiConfig.hpp @@ -22,6 +22,9 @@ #include "WifiDirectConfigSettings.hpp" namespace pipedal { + void SetWifiConfigWLanAddress(const std::string&wLanAddress); + const std::string &GetWifiConfigWlanAddress(); + void SetWifiConfig(const WifiConfigSettings&settings); void SetWifiDirectConfig(const WifiDirectConfigSettings&settings); @@ -29,4 +32,5 @@ namespace pipedal { void OnWifiUninstall(); void OnWifiInstallComplete(); + bool UsingNetworkManager(); } // namespace. \ No newline at end of file diff --git a/src/SystemConfigFile.cpp b/src/SystemConfigFile.cpp index ea0099d..c82db9a 100644 --- a/src/SystemConfigFile.cpp +++ b/src/SystemConfigFile.cpp @@ -297,8 +297,20 @@ int SystemConfigFile::GetLineNumber(const std::string &line) const { } } return -1; +} + +int SystemConfigFile::GetLineNumberStartingWith(const std::string &line) const { + for (int i = 0; i < lines.size(); ++i) + { + if (lines[i].starts_with(line)) + { + return i; + } + } + return -1; } + void SystemConfigFile::EraseLine(int i) { if (i < 0 || i >= lines.size()) throw PiPedalArgumentException("Range error."); diff --git a/src/SystemConfigFile.hpp b/src/SystemConfigFile.hpp index e9c9671..f4842ae 100644 --- a/src/SystemConfigFile.hpp +++ b/src/SystemConfigFile.hpp @@ -56,6 +56,7 @@ public: int64_t Insert(int64_t position, const std::string&key, const std::string&value); int64_t Insert(int64_t position, const std::string&line); int GetLineNumber(const std::string&line) const; + int GetLineNumberStartingWith(const std::string&line) const; bool HasLine(const std::string&line) const { return GetLineNumber(line) != -1; } void EraseLine(int i); int GetLineThatStartsWith(const std::string&text) const; diff --git a/src/WifiChannelSelectors.cpp b/src/WifiChannelSelectors.cpp new file mode 100644 index 0000000..8a04c99 --- /dev/null +++ b/src/WifiChannelSelectors.cpp @@ -0,0 +1,139 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include +// #include + +// #include +#include "PiPedalException.hpp" +#include "WifiChannelSelectors.hpp" +#include "Lv2Log.hpp" +#include + +#include "RegDb.hpp" + +#include "ChannelInfo.hpp" + +using namespace pipedal; + + + +// static bool firstTime = true; +// static std::unique_ptr g_regDb; + +std::vector pipedal::getWifiChannelSelectors(const char*countryIso3661, bool forCommandline) +{ + // Use the wifi physical device to get a list of channels + // that the hardware supports. + // The override the hardware's regulation flags using regulation.bin + // database info for the selected country code. + // If the regulation.bin database doesn't have a matching record, + // just pass the data that the wifi reported. + + // regdb is broken on bookworm. + // if (firstTime) { + // firstTime = false; + // try { + // g_regDb = std::make_unique(); + // } catch (const std::exception& e) + // { + // std::stringstream s; + // s << "Failed to open the Wi-Fi regulatory.bin database. " << e.what(); + // Lv2Log::error(s.str()); + // } + // } + std::vector result; + + + if (forCommandline) { + WifiChannelSelector autoSelect; + autoSelect.channelId_ = "0"; + autoSelect.channelName_ = "0 Select automatically"; + result.push_back(autoSelect); + } else { + WifiChannelSelector autoSelect; + autoSelect.channelId_ = "0"; + autoSelect.channelName_ = "Select automatically"; + result.push_back(autoSelect); + } + WifiInfo wifiInfo = getWifiInfo(countryIso3661); + + std::set visitedChannels; + for (auto &channel: wifiInfo.channels) { + if ((!channel.disabled) && (!channel.radarDetection)) + { + if (channel.no20MHz) + { + continue; + } + // ignore duplicates + if (visitedChannels.contains(channel.channelNumber)) + { + continue; + } + visitedChannels.insert(channel.channelNumber); + WifiChannelSelector ch; + std::stringstream s; + s << channel.channelNumber; + ch.channelId_ = s.str(); + + std::stringstream t; + t << channel.channelNumber; + switch (channel.hardwareMode) + { + case WifiMode::IEEE80211G: + t << " (2.4GHz)"; + break; + case WifiMode::IEEE80211A: + case WifiMode::IEEE80211B: + t << " (5GHz)"; + break; + default: + continue; + } + if (channel.indoorOnly) { + t << " Indoors only"; + } + if (channel.outdoorsOnly) { + t << " Outdoors only"; + } + ch.channelName_ = t.str(); + result.push_back(ch); + } + } + return result; +} + + +JSON_MAP_BEGIN(WifiChannelSelector) + JSON_MAP_REFERENCE(WifiChannelSelector,channelId) + JSON_MAP_REFERENCE(WifiChannelSelector,channelName) +JSON_MAP_END() + + diff --git a/src/WifiChannelSelectors.hpp b/src/WifiChannelSelectors.hpp new file mode 100644 index 0000000..844db14 --- /dev/null +++ b/src/WifiChannelSelectors.hpp @@ -0,0 +1,37 @@ +// Copyright (c) 2022 Robin Davies +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +#pragma once +#include "json.hpp" +namespace pipedal +{ + + class WifiChannelSelector + { + public: + std::string channelId_; + std::string channelName_; + + DECLARE_JSON_MAP(WifiChannelSelector); + }; + + std::vector getWifiChannelSelectors(const char *countryIso3661, bool forCommandline = false); + +} \ No newline at end of file diff --git a/src/WifiChannels.cpp b/src/WifiChannels.cpp deleted file mode 100644 index 0bf7f06..0000000 --- a/src/WifiChannels.cpp +++ /dev/null @@ -1,637 +0,0 @@ -// Copyright (c) 2022 Robin Davies -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - -#include "pch.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "PiPedalException.hpp" -#include "WifiChannels.hpp" -#include "Lv2Log.hpp" - -#include "RegDb.hpp" - -/* - Heavily based on code from iw (1) command. - https://kernel.googlesource.com/pub/scm/linux/kernel/git/jberg/iw/+/v0.9/COPYING - -Copyright (c) 2007, 2008 Johannes Berg -Copyright (c) 2007 Andy Lutomirski -Copyright (c) 2007 Mike Kershaw -Copyright (c) 2008 Luis R. Rodriguez -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. -3. The name of the author may not be used to endorse or promote products - derived from this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED -AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF -SUCH DAMAGE. -*/ - -using namespace pipedal; - -struct MHzToChannel { - char band; - int channel; - int mhz; -}; - -MHzToChannel mhzToChannels[] = { -{'g', 1, 2412}, -{'g',2, 2417}, -{'g',3, 2422}, -{'g',4, 2427}, -{'g',5, 2432}, -{'g',6, 2437}, -{'g',7, 2442}, -{'g',8, 2447}, -{'g',9, 2452}, -{'g',10, 2457}, -{'g',11, 2462}, -{'g',12, 2467}, -{'g',13, 2472}, -{'g',14, 2484}, -{'a',7, 5035}, -{'a',8, 5040}, -{'a',9, 5045}, -{'a',11, 5055}, -{'a',12, 5060}, -{'a',16, 5080}, -{'a',32, 5160}, -{'a',34, 5170}, -{'a',36, 5180}, -{'a',38, 5190}, -{'a',40, 5200}, -{'a',42, 5210}, -{'a',44, 5220}, -{'a',46, 5230}, -{'a',48, 5240}, -{'a',50, 5250}, -{'a',52, 5260}, -{'a',54, 5270}, -{'a',56, 5280}, -{'a',58, 5290}, -{'a',60, 5300}, -{'a',62, 5310}, -{'a',64, 5320}, -{'a',68, 5340}, -{'a',96, 5480}, -{'a',100, 5500}, -{'a',102, 5510}, -{'a',104, 5520}, -{'a',106, 5530}, -{'a',108, 5540}, -{'a',110, 5550}, -{'a',112, 5560}, -{'a',114, 5570}, -{'a',116, 5580}, -{'a',118, 5590}, -{'a',120, 5600}, -{'a',122, 5610}, -{'a',124, 5620}, -{'a',126, 5630}, -{'a',128, 5640}, -{'a',132, 5660}, -{'a',134, 5670}, -{'a',136, 5680}, -{'a',138, 5690}, -{'a',140, 5700}, -{'a',142, 5710}, -{'a',144, 5720}, -{'a',149, 5745}, -{'a',151, 5755}, -{'a',153, 5765}, -{'a',155, 5775}, -{'a',157, 5785}, -{'a',159, 5795}, -{'a',161, 5805}, -{'a',163, 5815}, -{'a',165, 5825}, -{'a',167, 5835}, -{'a',169, 5845}, -{'a',171, 5855}, -{'a',173, 5865}, -{'a',175, 5875}, -{'a',177, 5885}, -{'a',180, 5900}, -{'a',182, 5910}, -{'a',18, 5915}, -{'a',184, 5920}, -{'a',187, 5935}, -{'a',188, 5940}, -{'a',189, 5945}, -{'a',192, 5960}, -{'a',196, 5980}, -}; - - -bool MHzToChannelNumber(int mhz, char*pBand, int*pChannel) -{ - for (size_t i = 0; i < sizeof(mhzToChannels)/sizeof(mhzToChannels[0]); ++i) - { - if (std::abs(mhz-mhzToChannels[i].mhz) <= 1) { - *pBand = mhzToChannels[i].band; - *pChannel = mhzToChannels[i].channel; - return true; - } - } - return false; -} - -static nla_policy *makeFreqPolicy() -{ - nla_policy* result = new nla_policy[NL80211_FREQUENCY_ATTR_MAX + 1]; - memset(result,0,sizeof(nla_policy[NL80211_FREQUENCY_ATTR_MAX + 1])); - - result[NL80211_FREQUENCY_ATTR_FREQ] = {NLA_U32,0,0}; - result[NL80211_FREQUENCY_ATTR_DISABLED] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_NO_IR] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_RADAR] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_INDOOR_ONLY] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_INDOOR_ONLY] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_NO_20MHZ] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_NO_20MHZ] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_NO_80MHZ] = {NLA_FLAG,0,0}; - result[NL80211_FREQUENCY_ATTR_NO_160MHZ] = {NLA_FLAG,0,0}; - return result; -} - -static struct nla_policy* freq_policy = makeFreqPolicy(); - - -static nla_policy *makeRatePolicy() { - nla_policy* result = new nla_policy[NL80211_BITRATE_ATTR_MAX + 1]; - memset(result,0,sizeof(nla_policy[NL80211_BITRATE_ATTR_MAX + 1])); - result[NL80211_BITRATE_ATTR_RATE] = {.type = NLA_U32}; - result[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = {.type = NLA_FLAG}; - return result; -}; - -static struct nla_policy* rate_policy = makeRatePolicy(); - -struct IfType { - enum nl80211_iftype iftype; - const char*name; -}; -static struct IfType ifTypes[] = { - {NL80211_IFTYPE_UNSPECIFIED,"Unspecified"}, - {NL80211_IFTYPE_ADHOC,"Adhoc"}, - {NL80211_IFTYPE_STATION,"Station"}, - {NL80211_IFTYPE_AP,"AP"}, - {NL80211_IFTYPE_AP_VLAN,"VLAN"}, - {NL80211_IFTYPE_WDS,"WDS"}, - {NL80211_IFTYPE_MONITOR,"Monitor"}, - {NL80211_IFTYPE_MESH_POINT,"Mesh point"}, - {NL80211_IFTYPE_P2P_CLIENT,"Client"}, - {NL80211_IFTYPE_P2P_GO,"P2P Go"}, - {NL80211_IFTYPE_P2P_DEVICE,"P2P"}, - {NL80211_IFTYPE_OCB,"OCB"}, - {NL80211_IFTYPE_NAN,"NAN"}, - -}; -const char *iftype_name(enum nl80211_iftype iftype) -{ - for (size_t i = 0; i < sizeof(ifTypes)/sizeof(ifTypes[0]); ++i) - { - if (ifTypes[i].iftype == iftype) - { - return ifTypes[i].name; - } - } - return "Unknown"; -} -static int phy_lookup(const char *name) -{ - char buf[200]; - int fd, pos; - snprintf(buf, sizeof(buf), "/sys/class/ieee80211/%s/index", name); - fd = open(buf, O_RDONLY); - pos = read(fd, buf, sizeof(buf) - 1); - if (pos < 0) - return -1; - buf[pos] = '\0'; - return atoi(buf); -} - -static int getWifiName_callback(struct nl_msg *msg, void *arg); -static int getWifiInfo_callback(struct nl_msg *msg, void *arg); - -struct WifiChannelInfo -{ - int channelNumber = -1; - char band = 'g'; // 'g' or 'a' - int mhz = 0; - bool disabled = false; - bool ir = true; - bool radarDetection = false; - std::vector bitrates; - bool indoorOnly = false; - bool noHt40Minus = false; - bool noHt40Plus = false; - bool no10MHz = false; - bool no20MHz = false; - bool no80MHz = false; - bool no160MHz = false; -}; - -struct WifiBand -{ - int index; - std::vector channels; -}; - -struct WifiInfo -{ - std::string name; - std::vector bands; - std::vector supportedIfTypes; -}; -class NetLink -{ -private: - - std::vector result; - nl_sock*socket = nullptr; - nl_cache*cache = nullptr; - genl_family*nl80211 = nullptr; - - int errorCode = -1; - - static int finish_handler(struct nl_msg *msg, void *arg) - { - NetLink*this_ = (NetLink*)arg; - this_->errorCode = 0; - return NL_SKIP; - } - static int ack_handler(struct nl_msg *msg, void *arg) - { - NetLink*this_ = (NetLink*)arg; - this_->errorCode = 0; - return NL_STOP; - } - - static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err, - void *arg) - { - NetLink*this_ = (NetLink*)arg; - this_->errorCode = err->error; - return NL_STOP; - } - - - static int info_phy_handler(struct nl_msg *msg, void *arg) - { - return ((NetLink *)arg)->InfoPhyHandler(msg, (WifiInfo *)arg); - } - int InfoPhyHandler(struct nl_msg *msg, WifiInfo *result) - { - struct nlattr *tb_msg[NL80211_ATTR_MAX + 1]; - struct genlmsghdr *gnlh = (genlmsghdr *)nlmsg_data(nlmsg_hdr(msg)); - struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1]; - struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1]; - struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1]; - struct nlattr *nl_band; - struct nlattr *nl_freq; - struct nlattr *nl_rate; - struct nlattr *nl_mode; - int bandidx = 1; - int rem_band, rem_freq, rem_rate, rem_mode; - int open; - nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0), - genlmsg_attrlen(gnlh, 0), NULL); - if (!tb_msg[NL80211_ATTR_WIPHY_BANDS]) - return NL_SKIP; - if (tb_msg[NL80211_ATTR_WIPHY_NAME]) - result->name = nla_get_string(tb_msg[NL80211_ATTR_WIPHY_NAME]); - - nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) - { - WifiBand band; - band.index = bandidx; - - bandidx++; - nla_parse(tb_band, NL80211_BAND_ATTR_MAX, (nlattr *)nla_data(nl_band), - nla_len(nl_band), NULL); - - nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) - { - nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, (nlattr *)nla_data(nl_freq), - nla_len(nl_freq), freq_policy); - if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ]) - continue; - - WifiChannelInfo channel; - - channel.mhz = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]); - open = 0; - if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED]) - channel.disabled = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IR]) - channel.ir = false; - if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR]) - channel.radarDetection = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_10MHZ]) - channel.no10MHz = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_INDOOR_ONLY]) - channel.indoorOnly = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_20MHZ]) - channel.no20MHz = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_MINUS]) - channel.noHt40Minus = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_HT40_PLUS]) - channel.noHt40Plus = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_80MHZ]) - channel.no80MHz = true; - if (tb_freq[NL80211_FREQUENCY_ATTR_NO_160MHZ]) - channel.no160MHz = true; - - if (MHzToChannelNumber(channel.mhz,&channel.band, &channel.channelNumber)) - { - band.channels.push_back(std::move(channel)); - } else { - // throw PiPedalException("Frequency not recognized."); - } - } - nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) - { - nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, (nlattr *)nla_data(nl_rate), - nla_len(nl_rate), rate_policy); - if (!tb_rate[NL80211_BITRATE_ATTR_RATE]) - continue; - //channel.bitRates.push_back(0.1f * nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]); - } - result->bands.push_back(std::move(band)); - } - if (!tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES]) - return NL_SKIP; - - nla_for_each_nested(nl_mode, tb_msg[NL80211_ATTR_SUPPORTED_IFTYPES], rem_mode) - result->supportedIfTypes.push_back(iftype_name((nl80211_iftype)(nl_mode->nla_type))); - return NL_SKIP; - } - -public: - ~NetLink() - { - if (this->cache) - { - nl_cache_free(cache); - cache = nullptr; - } - if (nl80211 != nullptr) - { - genl_family_put(nl80211); // (release reference) - nl80211 = nullptr; - } - if (socket) - { - nl_close(socket); - nl_socket_free(socket); - socket = nullptr; - } - } - NetLink() - { - socket = nl_socket_alloc(); - if (!socket) - { - throw PiPedalException("Can't allocate netlink socket."); - } - nl_socket_set_buffer_size(socket, 8192, 8192); - - if (genl_connect(socket)) - { - throw PiPedalException("Failed to connect to netlink socket."); - } - if (genl_ctrl_alloc_cache(this->socket,&this->cache) != 0) { - throw PiPedalException("Failed to allocate generic netlink cache."); - } - this->nl80211 = genl_ctrl_search_by_name(this->cache, "nl80211"); - if (!this->nl80211) { - throw PiPedalException("nl80211 family not found."); - } - } - void GetAvailableChannels(const char *phyName, WifiInfo *result) - { - - struct nl_msg *msg = nullptr; - struct nl_cb*cb = nullptr; - int devidx = 0; - int err; - - devidx = phy_lookup(phyName); - try { - - - msg = nlmsg_alloc(); - if (!msg) - { - throw PiPedalException("failed to allocate netlink message"); - } - cb = nl_cb_alloc(NL_CB_DEFAULT); - if (!cb) - { - throw PiPedalException("failed to allocate netlink callbacks"); - } - genlmsg_put(msg, 0, 0, genl_family_get_id(this->nl80211), 0, - 0, NL80211_CMD_GET_WIPHY, 0); - NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, devidx); - - this->errorCode = 0; - nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, info_phy_handler, result); - - nl_cb_err(cb, NL_CB_CUSTOM, error_handler, this); - nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, this); - nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, this); - - err = nl_send_auto_complete(this->socket, msg); - - if (err < 0) - throw PiPedalException("Command failed."); - nl_recvmsgs(this->socket, cb); - nlmsg_free(msg); - if (this->errorCode != 0) - { - throw PiPedalException("Command failed."); - } - nl_cb_put(cb); - return; - nla_put_failure: - throw PiPedalException("NLA Put failure."); - } catch (const std::exception&e) - { - if (cb != nullptr) - { - nl_cb_put(cb); - cb = nullptr; - } - if (msg != nullptr) - { - nlmsg_free(msg); - msg = nullptr; - } - throw; - } - } -}; - -WifiInfo getWifiInfo(const char *phyName) -{ - int index = phy_lookup(phyName); - if (index == -1) - { - throw PiPedalArgumentException("No such device."); - } - - NetLink netLink; - WifiInfo result; - netLink.GetAvailableChannels(phyName,&result); - return result; -} - -const char*allowOutdoorsLocales[] = { - "US","TW","SG", - -}; - -static bool allowOutdoors(const char*countryCode) -{ - for (size_t i = 0; i < sizeof(allowOutdoorsLocales)/sizeof(allowOutdoorsLocales[0]); ++i) - { - if (strcmp(allowOutdoorsLocales[i],countryCode) == 0) return true; - } - return false; -} - -static bool firstTime = true; -static std::unique_ptr g_regDb; -std::vector pipedal::getWifiChannels(const char*countryIso3661) -{ - // Use the wifi physical device to get a list of channels - // that the hardware supports. - // The override the hardware's regulation flags using regulation.bin - // database info for the selected country code. - // If the regulation.bin database doesn't have a matching record, - // just pass the data that the wifi reported. - - if (firstTime) { - firstTime = false; - try { - g_regDb = std::make_unique(); - } catch (const std::exception& e) - { - std::stringstream s; - s << "Failed to open the Wi-Fi regulations.bin database. " << e.what(); - Lv2Log::error(s.str()); - } - } - std::vector result; - - WifiInfo wifiInfo = getWifiInfo("phy0"); - std::unique_ptr crdbRules = nullptr; - if (g_regDb) { - crdbRules = std::unique_ptr(g_regDb->GetCrdbRules(countryIso3661)); - if (!crdbRules) { - crdbRules = std::unique_ptr(g_regDb->GetCrdbRules("00")); // unset default. - } - } - for (auto &band : wifiInfo.bands) - { - for (auto &channel: band.channels) { - if (crdbRules) - { - FrequencyRule crdbRule; - if (crdbRules->GetFrequencyRule(channel.mhz,&crdbRule)) - { - channel.disabled = false; - channel.radarDetection = crdbRule.hasFlag(RegRuleFlags::DFS); - channel.ir = !crdbRule.hasFlag(RegRuleFlags::NO_IR); - channel.indoorOnly = crdbRule.hasFlag(RegRuleFlags::NO_OUTDOOR); - if (crdbRule.hasFlag(RegRuleFlags::PTP_ONLY) - || crdbRule.hasFlag(RegRuleFlags::PTMP_ONLY)) - { - channel.disabled = true; - - } - } else { - channel.disabled = true; - } - } - if ((!channel.disabled) && (!channel.radarDetection) && channel.ir) - { - WifiChannel ch; - std::stringstream s; - s << channel.band << channel.channelNumber; - ch.channelId_ = s.str(); - - std::stringstream t; - t << channel.channelNumber; - if (channel.band == 'a') - t << " (5GHz)"; - else - t << " (2.4GHz)"; - - if (channel.indoorOnly) { - t << " Indoors only"; - } - ch.channelName_ = t.str(); - result.push_back(ch); - } - } - } - return result; -} - - -JSON_MAP_BEGIN(WifiChannel) - JSON_MAP_REFERENCE(WifiChannel,channelId) - JSON_MAP_REFERENCE(WifiChannel,channelName) -JSON_MAP_END() - - diff --git a/src/WifiChannelsTest.cpp b/src/WifiChannelsTest.cpp index 05bfa51..7ba602c 100644 --- a/src/WifiChannelsTest.cpp +++ b/src/WifiChannelsTest.cpp @@ -23,36 +23,219 @@ #include #include -#include "WifiChannels.hpp" - - +#include "WifiChannelSelectors.hpp" +#include "ChannelInfo.hpp" +#include "RegDb.hpp" +#include using namespace pipedal; -static WifiChannel GetChannel(std::vector channels, const std::string&channelId) +static WifiChannelSelector GetChannel(const std::vector &channels, const std::string &channelId) { - for (auto &channel: channels) + for (auto &channel : channels) { if (channel.channelId_ == channelId) { return channel; } } - throw PiPedalException("Channel not found.");; + throw std::runtime_error("Channel not found."); + ; } - - - -TEST_CASE( "Wifi Channel Test", "[wifi_channels_test]" ) { - std::vector result = pipedal::getWifiChannels("CA"); +void TestWifiChannels() +{ + using namespace std; + cout << " ==== CA Channels ====" << endl; + std::vector result = pipedal::getWifiChannelSelectors("CA"); + for (const auto &channel : result) + { + std::cout << " " << channel.channelName_ << std::endl; + } // channel 36 is indoors only (CA) - WifiChannel channel = GetChannel(result,"a36"); + WifiChannelSelector channel = GetChannel(result, "36"); + + + // present before bookworm. no longer. REQUIRE(channel.channelName_.find("Indoors") != std::string::npos); + + + for (const auto &channel : result) + { + std::cout << " " << channel.channelName_ << std::endl; + } // channel 36 is not indoors only (US) - result = pipedal::getWifiChannels("US"); - channel = GetChannel(result,"a36"); + cout << " ==== US Channels ====" << endl; + + result = pipedal::getWifiChannelSelectors("US"); + for (const auto &channel : result) + { + std::cout << " " << channel.channelName_ << std::endl; + } + channel = GetChannel(result, "36"); REQUIRE(channel.channelName_.find("Indoors") == std::string::npos); } +struct RegulatoryDomain { + RegulatoryDomain(int32_t domain) : domain(domain) { } + RegulatoryDomain(int32_t domain,const std::vector&channels) : domain(domain),channels(channels) { } + void AddChannel(int32_t channel) + { + std::vector::iterator i; + for (i = channels.begin(); i != channels.end(); ++i) + { + if ((*i) == channel) return; + if (*i > channel) break; + } + channels.insert(i,channel); + } + bool operator==(const RegulatoryDomain&other) const + { + if (this->domain != other.domain) return false; + return std::equal(channels.begin(),channels.end(),other.channels.begin(),other.channels.end()); + } + int32_t domain; + std::vector channels; +}; + +class ChannelsByRegDomain { +public: + ChannelsByRegDomain() { } + ChannelsByRegDomain(const std::vector&domains): regulations(domains) { } + void AddChannel(int32_t domain, int32_t channel) + { + RegulatoryDomain®Domain = GetDomain(domain); + regDomain.AddChannel(channel); + } + std::string toString() const { + std::stringstream s; + bool first = true; + for (const auto&domain: regulations) + { + if (!first) s << " "; + first = false; + s << domain.domain << ":"; + bool firstChan = true; + for (const auto c : domain.channels) + { + if(!firstChan) s << ","; + firstChan = false; + + s << c; + } + } + return s.str(); + } + bool operator==(const ChannelsByRegDomain&other) const + { + return std::equal(regulations.begin(),regulations.end(),other.regulations.begin(),other.regulations.end()); + } +private: + RegulatoryDomain&GetDomain(int32_t domain) { + + std::vector::iterator i; + for (i = regulations.begin(); i != regulations.end(); i++) + { + if (i->domain == domain) return *i; + if (i->domain > domain) break; + } + i = regulations.insert(i,RegulatoryDomain(domain)); + return *i; + + } + std::vector regulations; +}; + +void DisplayP2pChannels(const char*isoCountry, const ChannelsByRegDomain&expected) +{ + std::cout << " " << isoCountry <<":"; + + ChannelsByRegDomain result; + auto wifiInfo = pipedal::getWifiInfo("CA"); + for (const auto&channel: wifiInfo.channels) + { + result.AddChannel(channel.regDomain,channel.channelNumber); + } + std::cout << result.toString() << std::endl; + if (result != expected) + { + throw std::runtime_error("Incorrect results.."); + } + +} + +void TestBookwormRegDbLoad() +{ + std::filesystem::path dbPath = "test_data/debian_bookworm_regulatory.db"; + RegDb regdb{dbPath}; + REQUIRE(regdb.IsValid()); +} +void TestP2pChannels() +{ + std::cout << "---- TestP2PChannels ---" << std::endl; + + // expecting (for CA) + //81:1,2,3,4,5,6,7,8,9,10,11 115:36,40,44,48 116:36,44 117:40,48 124:149,153,157,161 125:149,153,157,161,165 126:149,157 + //81:1,2,3,4,5,6,7,8,9,10,11 115:36,40,44,48 116:36,44 117:40,48 124:149,153,157,161 125:149,153,157,161,165 126:149,157 127:153,161 + // 127:153,161 128:36,40,44,48,149,153,157,161 130:36,40,44,48,149,153,157,161,165 + // 127:153,161 + + + ChannelsByRegDomain expectedCaDomains = + { + std::vector{ + {81, { 1,2,3,4,5,6,7,8,9,10,11}}, + { 115, {36,40,44,48}}, + { 116, {36,44}}, + { 117, { 40,48}}, + { 124, {149,153,157,161}}, + { 125, {149,153,157,161,165}}, + { 126, {149,157 }}, + { 127, {153,161}}, + // ignore 80ghz ac channels (which pi supports, but we don't). + // { 128, {36,40,44,48,149,153,157,161}}, + // { 130, {36,40,44,48,149,153,157,161,165}} + } + }; + DisplayP2pChannels("CA",expectedCaDomains); + // DisplayP2pChannels("US"); + // DisplayP2pChannels("JP"); + // DisplayP2pChannels("00"); + +} + +static void DisplayRegulations(const std::string& country) +{ + using namespace std; + RegDb®Db = RegDb::GetInstance(); + + cout << " ---- " << country << " regulations --- " << endl; + const auto& regulations = regDb.getWifiRegulations(country); + for (const auto&rule: regulations.rules) + { + cout << rule.start_freq_khz/1000 << "-" << rule.end_freq_khz/1000 << " (" << rule.max_bandwidth_khz/1000 << ")"; + cout << (rule.HasFlag(RegRuleFlags::NO_INDOOR) ? " NO_INDOORS" : "") + << (rule.HasFlag(RegRuleFlags::NO_OUTDOOR) ? " NO_OUTDOOR" : "") + << (rule.HasFlag(RegRuleFlags::DFS) ? " RADAR" : "") + << (rule.HasFlag(RegRuleFlags::NO_IR) ? " NO_IR" : "") + << (rule.HasFlag(RegRuleFlags::NO_OFDM) ? " NO_OFDM" : "") + << (rule.HasFlag(RegRuleFlags::NO_HE) ? " NO_HE" : "") + << (rule.HasFlag(RegRuleFlags::NO_HT40MINUS) ? " NO_HT40MINUS" : "") + << (rule.HasFlag(RegRuleFlags::NO_HT40PLUS) ? " NO_HT40PLUS" : "") + << (rule.HasFlag(RegRuleFlags::AUTO_BW) ? " AUTO_BW" : "") + << (rule.HasFlag(RegRuleFlags::PTP_ONLY) ? " PTP_ONLY" : "") + << (rule.HasFlag(RegRuleFlags::PTMP_ONLY) ? " PTMP_ONLY" : "") + << endl; + } +} + +TEST_CASE("Wifi Channel Test", "[wifi_channels_test]") +{ + DisplayRegulations("CA"); + DisplayRegulations("US"); + DisplayRegulations("JP"); + TestBookwormRegDbLoad(); + TestWifiChannels(); + TestP2pChannels(); +} diff --git a/src/copyrightMain.cpp b/src/copyrightMain.cpp index 35e6c01..1a4d221 100644 --- a/src/copyrightMain.cpp +++ b/src/copyrightMain.cpp @@ -19,6 +19,10 @@ std::vector unknownLicense ={ "These copyright notices were found, but we were unable to automatically identify an associated license." }; +bool ContainsName(const std::string ©right, const char*name) +{ + return copyright.find(name) != -1; +} class Copyrights { struct License { @@ -56,7 +60,7 @@ class Copyrights { } - void addCopyright(std::string license,const std::string ©right) + void addCopyright(std::string license,std::string copyright) { if (copyright.length() == 0) return; if (copyright == "no-info-found") return; @@ -65,6 +69,11 @@ class Copyrights { { license = UNKNOWN_LICENSE; } + const static std::string UNSPECIFIED = "(unspecified) "; + if (copyright.starts_with(UNSPECIFIED)) + { + copyright = copyright.substr(UNSPECIFIED.length()); + } auto currentLicense = licenseMap.find(license); if (currentLicense == licenseMap.end()) { @@ -342,7 +351,7 @@ int main(int argc, const char*argv[]) { cerr << endl; } - cout << "Syntax: processcopyrights --projectCopyright debian/copyright -output []*" << endl; + cout << "Syntax: processcopyrights --projectCopyright debian/copyright -output []*" << endl; return helpError? EXIT_FAILURE: EXIT_SUCCESS; } diff --git a/src/templates/30-pipedal-p2p-dnsmasq-nm.conf b/src/templates/30-pipedal-p2p-dnsmasq-nm.conf new file mode 100644 index 0000000..75349b9 --- /dev/null +++ b/src/templates/30-pipedal-p2p-dnsmasq-nm.conf @@ -0,0 +1,11 @@ + + +interface=p2p-${WLAN}-* + #disable dns, dhcp only.a" + port=0 + dhcp-range=172.23.0.20,172.23.0.127,15m + domain=local + address=/pipedal-p2p.local/172.23.0.2 + +except-interface=eth0 +except-interface=${WLAN} diff --git a/src/templates/50-pipedal-nm.conf b/src/templates/50-pipedal-nm.conf new file mode 100644 index 0000000..f79cd36 --- /dev/null +++ b/src/templates/50-pipedal-nm.conf @@ -0,0 +1,2 @@ +[keyfile] +unmanaged-devices=interface-name:${WLAN},interface-name:p2p-dev-${WLAN} diff --git a/src/templates/dnsmasq-pipedal-nm.conf b/src/templates/dnsmasq-pipedal-nm.conf new file mode 100644 index 0000000..e11d09f --- /dev/null +++ b/src/templates/dnsmasq-pipedal-nm.conf @@ -0,0 +1,10 @@ +# PiPedal dnsmasq settings for p2p +#disable dns, dhcp only." +port=0 +dhcp-range=172.23.0.3,172.23.0.127,15m +domain=local +address=/pipedal-p2p.local/172.23.0.2 + +# defensive. Not actually required. +except-interface=eth0 +except-interface=wlan0 diff --git a/src/templates/pipedal_nm_p2pd.service.template b/src/templates/pipedal_nm_p2pd.service.template new file mode 100644 index 0000000..79df5e8 --- /dev/null +++ b/src/templates/pipedal_nm_p2pd.service.template @@ -0,0 +1,20 @@ +[Unit] +Description=PiPedal P2P Session Manager +After=network.target +After=nss-lookup.target +After=wpa_supplicant.service +After=NetworkManager.service +After=dhcpcd.service +StartLimitIntervalSec=300 +StartLimitBurst=8 + +[Service] +ExecStart=${COMMAND} --systemd --loglevel info +Type=notify +WorkingDirectory=/var/pipedal +Restart=on-failure +TimeoutStopSec=5 +RestartSec=5s + +[Install] +WantedBy=multi-user.target diff --git a/src/templates/pipedal_p2pd.service.template b/src/templates/pipedal_p2pd.service.template index 67e31e1..402c271 100644 --- a/src/templates/pipedal_p2pd.service.template +++ b/src/templates/pipedal_p2pd.service.template @@ -8,7 +8,7 @@ StartLimitIntervalSec=300 StartLimitBurst=8 [Service] -ExecStart=${COMMAND} --systemd --log-level debug +ExecStart=${COMMAND} --systemd --log-level info Type=notify WorkingDirectory=/var/pipedal TimeoutStopSec=5 diff --git a/src/templates/wpa_supplicant-pipedal.conf b/src/templates/wpa_supplicant-pipedal.conf new file mode 100644 index 0000000..082a2d7 --- /dev/null +++ b/src/templates/wpa_supplicant-pipedal.conf @@ -0,0 +1,4 @@ +ctrl_interface=DIR=/run/wpa_supplicant GROUP=netdev +update_config=1 +driver_param=p2p_device=6 + diff --git a/submodules/pipedal_p2pd b/submodules/pipedal_p2pd index 862a029..dfa4820 160000 --- a/submodules/pipedal_p2pd +++ b/submodules/pipedal_p2pd @@ -1 +1 @@ -Subproject commit 862a02937db00fa0fb582dd362089404c46ecdf8 +Subproject commit dfa4820e49cbc075a3ff9a47b109d20d68005079 diff --git a/test_data/debian_bookworm_regulatory.db b/test_data/debian_bookworm_regulatory.db new file mode 100644 index 0000000..1c1131b Binary files /dev/null and b/test_data/debian_bookworm_regulatory.db differ diff --git a/todo.txt b/todo.txt index 189b5ff..385b5a9 100644 --- a/todo.txt +++ b/todo.txt @@ -1,16 +1,24 @@ -JackConfiguration Input midi ports. +x group EQ congrols on Toob Preamp. +-x Bug with FLAC libs in debian package. +-x check default presets. +-x check Toob power stage is installed. +X check FLAC decode. +- make app use the same theme settings as the website. +- BUG: gcs when we have an animated output control +- Shutdown/reboot midi bindings +- versioning. +- sample launch.json file. +- add tubeamp mods to release notes. +- do we want to take a second crack at establishin multi-p2p connections with the driver_param? +- merge ToobML gain control fixes AFTER we do the commit so we can enforce formatting. -JackSettings Input midi ports. -Midi Port selection UI. +sudo apt install libsdbus-c++-dev libnm-dev + -CPU Use should be % of AVAILABLE time, not % of total. -MIDI device selection. -raw Alsa midi. Pri Description ----------------- 5 Re-use plugin instances when rebuilding pedalboard. -3 OpenSound support. diff --git a/uninstall b/uninstall deleted file mode 100755 index 54cacf3..0000000 --- a/uninstall +++ /dev/null @@ -1,5 +0,0 @@ -export PREFIX=/usr/ - -rm $PREFIX/bin/pipedal*.* -rm -rf /etc/pipedal/ - diff --git a/uninstall.sh b/uninstall.sh new file mode 100755 index 0000000..d3b937f --- /dev/null +++ b/uninstall.sh @@ -0,0 +1,10 @@ +#/usr/bin/sudo /usr/bin/bash +# CMake doesn't have an uninstall option, so remove files manually. +export PREFIX=/usr + +rm $PREFIX/bin/pipedal* +rm $PREFIX/sbin/pipedal* +rm -rf /etc/pipedal/ +rm -rf /var/pipedal/ +rm -rf /usr/lib/lv2/ToobAmp.lv2/ +