Auto hotspot implementation

This commit is contained in:
Robin Davies
2024-09-11 00:06:52 -04:00
parent bbfd0a07fd
commit 448979e7fe
61 changed files with 5234 additions and 178 deletions
+2 -1
View File
@@ -96,7 +96,8 @@
"nm-device-wifi-p2p.h": "c",
"strstream": "cpp",
"p2p_i.h": "c",
"p2p.h": "c"
"p2p.h": "c",
"hash_set": "cpp"
},
"cSpell.words": [
"Guitarix",
+7
View File
@@ -50,6 +50,13 @@ install(
install(
FILES ${PROJECT_SOURCE_DIR}/debian/copyright DESTINATION /usr/share/doc/pipedal
)
#install (
# DIRECTORY ${PROJECT_SOURCE_DIR}/src/polkit-1/rules/10-pipedal-networkmanager.rule DESTINATION /var/lib/polkit-1/localauthority/
#)
install (
FILES ${PROJECT_SOURCE_DIR}/src/polkit-1/rules/55-pipedal-networkmanager.rule DESTINATION /etc/polkit-1/rules.d/
)
install (
DIRECTORY ${REACT_BUILD_DIRECTORY} DESTINATION /etc/pipedal/react
)
+5
View File
@@ -215,6 +215,11 @@ void LogTrace(const std::string&path,const char*method,const std::string&message
}
}
void SetDBusLogger(std::unique_ptr<IDBusLogger> && logger)
{
loggers.clear();
loggers.push_back(std::move(logger));
}
void SetDBusConsoleLogger()
{
+1
View File
@@ -42,6 +42,7 @@ void SetDBusConsoleLogger();
void AddDBusConsoleLogger();
void SetDBusSystemdLogger();
void SetDBusFileLogger(const std::filesystem::path &path);
void SetDBusLogger(std::unique_ptr<IDBusLogger>&&logger);
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);
+2 -2
View File
@@ -193,7 +193,7 @@ void P2pSettings::Load()
}
static void openWithPerms(
static void openWithRestrictedPerms(
pipedal::ofstream_synced &f,
const std::filesystem::path &path,
std::filesystem::perms perms =
@@ -229,7 +229,7 @@ void P2pSettings::Save()
auto filename = config_filename();
try {
pipedal::ofstream_synced f;
openWithPerms(f,filename);
openWithRestrictedPerms(f,filename);
if (!f.is_open())
{
+29 -1
View File
@@ -41,6 +41,34 @@ message(STATUS "NMPIPEDAL CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}")
# Use the sdbus-c++ target in SDBusCpp namespace
add_library(PiPedalCommon STATIC
include/dbus/org.freedesktop.NetworkManager.Device.Statistics.hpp
include/dbus/org.freedesktop.NetworkManager.Settings.Connection.hpp
include/dbus/org.freedesktop.NetworkManager.IP6Config.hpp
include/dbus/org.freedesktop.NetworkManager.Connection.Active.hpp
include/dbus/org.freedesktop.NetworkManager.DnsManager.hpp
include/dbus/org.freedesktop.NetworkManager.IP4Config.hpp
include/dbus/org.freedesktop.NetworkManager.Settings.hpp
include/dbus/org.freedesktop.NetworkManager.Device.hpp
include/dbus/org.freedesktop.NetworkManager.DHCP6Config.hpp
include/dbus/org.freedesktop.NetworkManager.AccessPoint.hpp
include/dbus/org.freedesktop.NetworkManager.Device.WifiP2P.hpp
include/dbus/org.freedesktop.NetworkManager.WifiP2PPeer.hpp
include/dbus/org.freedesktop.NetworkManager.hpp
include/dbus/org.freedesktop.NetworkManager.Device.Wireless.hpp
include/dbus/org.freedesktop.NetworkManager.DHCP4Config.hpp
NetworkManagerInterfaces.cpp
include/NetworkManagerInterfaces.hpp
DBusEvent.cpp
DBusVariantHelper.cpp
DBusLog.cpp
DBusDispatcher.cpp
include/DBusDispatcher.hpp
include/DBusEvent.hpp
include/DBusLog.hpp
include/DBusVariantHelper.hpp
ofstream_synced.cpp include/ofstream_synced.hpp
ConfigSerializer.cpp include/ConfigSerializer.hpp
WifiRegs.cpp include/WifiRegs.hpp
@@ -66,7 +94,7 @@ add_library(PiPedalCommon STATIC
ss.hpp
)
target_include_directories(PiPedalCommon PUBLIC "include" ${LIBNL3_INCLUDE_DIRS})
target_link_libraries(PiPedalCommon PUBLIC ${LIBNL3_LIBRARIES} )
target_link_libraries(PiPedalCommon PUBLIC ${LIBNL3_LIBRARIES} SDBusCpp::sdbus-c++ )
+273
View File
@@ -0,0 +1,273 @@
#include "DBusDispatcher.hpp"
#include "DBusLog.hpp"
#include <sdbus-c++/IConnection.h>
#include <poll.h>
#include <sys/eventfd.h>
#include "ss.hpp"
#include <chrono>
#include <cassert>
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)
{
std::ignore = 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<void(void)>();
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;
std::ignore = 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<void(void)> &&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<std::chrono::milliseconds>(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;
}
+7
View File
@@ -0,0 +1,7 @@
#include "DBusEvent.hpp"
namespace impl {
std::atomic<uint64_t> NextHandle;
}
+255
View File
@@ -0,0 +1,255 @@
#include "DBusLog.hpp"
#include <memory>
#include "ss.hpp"
#include <systemd/sd-journal.h>
#include <fstream>
#include <stdexcept>
#include "ss.hpp"
#include <chrono>
#include "ofstream_synced.hpp"
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<std::chrono::milliseconds>(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();
ss << " ";
return ss.str();
}
class ConsoleDBusLogger : public IDBusLogger {
public:
ConsoleDBusLogger(bool showTime = true)
:showTime(showTime)
{
}
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;
}
private:
std::string getDateTime() {
return (showTime) ? getDateTime(): "";
}
bool showTime;
};
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:
pipedal::ofstream_synced 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<std::unique_ptr<IDBusLogger>> loggers;
void SetDBusLogger(std::unique_ptr<IDBusLogger> && logger)
{
loggers.clear();
loggers.push_back(std::move(logger));
}
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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::string ()> &text)
{
if (impl::dbusLogLevel > DBusLogLevel::Debug) return;
std::lock_guard<std::mutex> 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<std::string ()> &text)
{
if (impl::dbusLogLevel > DBusLogLevel::Trace) return;
std::lock_guard<std::mutex> 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<std::string ()> &text)
{
if (impl::dbusLogLevel > DBusLogLevel::Warning) return;
std::lock_guard<std::mutex> 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<std::string ()> &text)
{
if (impl::dbusLogLevel > DBusLogLevel::Info) return;
std::lock_guard<std::mutex> 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<std::string ()> &text)
{
if (impl::dbusLogLevel > DBusLogLevel::Error) return;
std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lock{impl::logMutex};
for (auto &logger: loggers)
{
logger->LogTrace(SS(path<< "::" << method << ": " << message));
}
}
void SetDBusConsoleLogger()
{
loggers.clear();
loggers.push_back(std::make_unique<ConsoleDBusLogger>());
}
void AddDBusConsoleLogger()
{
loggers.push_back(std::make_unique<ConsoleDBusLogger>());
}
void SetDBusSystemdLogger()
{
loggers.clear();
loggers.push_back(std::make_unique<SystemdDBusLogger>());
}
void SetDBusFileLogger(const std::filesystem::path &path)
{
loggers.clear();
loggers.push_back(std::make_unique<FileDBusLogger>(path));
}
+175
View File
@@ -0,0 +1,175 @@
#include "DBusVariantHelper.hpp"
#include <sdbus-c++/Types.h>
#include <iostream>
//std::ostream &operator<<(std::ostream &s, const std::map<std::string, sdbus::Variant> &properties)
std::ostream&operator<<(std::ostream&s, const sdbus::Variant&v)
{
// clang-format off
#define HANDLE_VARIANT_TYPE(type) \
if (v.containsValueOfType<type>()) \
{ \
s << v.get<type>(); \
}
HANDLE_VARIANT_TYPE(std::string)
else if (v.containsValueOfType<uint8_t>())
{
uint8_t value = v.get<uint8_t>();
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<sdbus::ObjectPath>())
{
auto objectPath = v.get<sdbus::ObjectPath>();
s << '[' << objectPath.c_str() << ']';
}
else if (v.containsValueOfType<std::vector<sdbus::Variant>>())
{
auto values = v.get<std::vector<sdbus::Variant>>();
{
s << '[';
bool first = true;
for (const sdbus::ObjectPath&value: values)
{
if (!first) s << ", ";
first = false;
s << value.c_str();
}
s << ']';
}
}
else if (v.containsValueOfType<std::vector<sdbus::ObjectPath>>())
{
auto paths = v.get<std::vector<sdbus::ObjectPath> >();
{
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<uint8_t>>())
{
std::vector<uint8_t> bytes = v.get<std::vector<uint8_t>>();
s << '[';
bool first = true;
for (uint8_t byte: bytes)
{
if (!first) s << ", ";
first = false;
s << (int)byte;
}
s << ']';
}
else if (v.containsValueOfType<std::vector<std::vector<uint8_t>>>())
{
auto arrayOfArrays = v.get<std::vector<std::vector<uint8_t>>>();
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<std::string,sdbus::Variant>>())
{
std::map<std::string,sdbus::Variant> map = v.get<std::map<std::string,sdbus::Variant>>();
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<std::string,std::vector<uint8_t>>>())
{
std::map<std::string,std::vector<uint8_t>> values
= v.get<std::map<std::string,std::vector<uint8_t>>>();
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<std::string, sdbus::Variant>& 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;
}
@@ -0,0 +1,46 @@
#include "NetworkManagerInterfaces.hpp"
#include "ss.hpp"
using namespace dbus::networkmanager;
using namespace dbus::networkmanager::nm_impl;
namespace dbus::networkmanager::nm_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();
}
}
}
}
+617 -55
View File
@@ -21,30 +21,412 @@
#include <stdexcept>
#include "ss.hpp"
#include "ChannelInfo.hpp"
#include <filesystem>
#include "ofstream_synced.hpp"
#include <stdexcept>
#include <cctype>
#include "SysExec.hpp"
#include <sdbus-c++/sdbus-c++.h>
#include <iostream>
#include <memory>
using namespace pipedal;
using namespace std;
namespace fs = std::filesystem;
JSON_MAP_BEGIN(WifiConfigSettings)
JSON_MAP_REFERENCE(WifiConfigSettings,valid)
JSON_MAP_REFERENCE(WifiConfigSettings,wifiWarningGiven)
JSON_MAP_REFERENCE(WifiConfigSettings,rebootRequired)
JSON_MAP_REFERENCE(WifiConfigSettings,enable)
JSON_MAP_REFERENCE(WifiConfigSettings,hotspotName)
JSON_MAP_REFERENCE(WifiConfigSettings,mdnsName)
JSON_MAP_REFERENCE(WifiConfigSettings,hasPassword)
JSON_MAP_REFERENCE(WifiConfigSettings,password)
JSON_MAP_REFERENCE(WifiConfigSettings,countryCode)
JSON_MAP_REFERENCE(WifiConfigSettings,channel)
JSON_MAP_END()
static const fs::path CONFIG_PATH = "/var/pipedal/config/wifiConfig.json";
bool WifiConfigSettings::ValidateCountryCode(const std::string&value)
WifiConfigSettings::WifiConfigSettings()
{
if (value.size() < 2 || value.size() > 3) return false;
return true;
Load();
}
int32_t pipedal::ChannelToChannelNumber(const std::string&channel)
static std::string getWifiCountryCode()
{
try
{
SysExecOutput result = sysExecForOutput("iw", "reg get");
if (result.exitCode != EXIT_SUCCESS)
{
return "";
}
const std::string &output = result.output;
size_t pos = output.find("country");
if (pos != std::string::npos)
{
std::string result = output.substr(pos + 8, 2);
if (WifiConfigSettings::ValidateCountryCode(result))
{
return result;
}
}
}
catch (const std::exception &e)
{
return ""; // unset.
}
return "";
}
static void setWifiCountryCode(const std::string &countryCode)
{
if (!WifiConfigSettings::ValidateCountryCode(countryCode))
{
throw std::runtime_error("Invalid country code.");
}
SysExecOutput result = sysExecForOutput("iw", SS("reg set " << countryCode));
if (result.exitCode != EXIT_SUCCESS)
{
throw std::runtime_error(SS("Failed to set country code: " << result.output));
}
}
bool WifiConfigSettings::ValidateCountryCode(const std::string &text)
{
if (text.length() != 2)
return false;
return std::isalpha(text[0]) && std::isalpha(text[1]);
}
void WifiConfigSettings::Load()
{
try
{
if (fs::exists(CONFIG_PATH))
{
std::ifstream f(CONFIG_PATH);
if (!f)
{
throw std::runtime_error("Can't open file.");
}
json_reader reader(f);
reader.read(this);
}
this->countryCode_ = getWifiCountryCode();
}
catch (const std::exception &e)
{
throw std::runtime_error(SS("Can't load WifiConfigSettings. " << e.what()));
}
}
static void openWithPerms(
pipedal::ofstream_synced &f,
const std::filesystem::path &path,
std::filesystem::perms perms =
std::filesystem::perms::owner_read | std::filesystem::perms::owner_write |
std::filesystem::perms::group_read | std::filesystem::perms::group_write)
{
auto directory = path.parent_path();
if (!std::filesystem::exists(directory))
{
std::filesystem::create_directories(directory);
// open and close to make an existing empty file.
// close it.
{
std::ofstream f;
f.open(path);
f.close();
}
try {
// set the perms.
std::filesystem::permissions(
path,
perms,
std::filesystem::perm_options::replace);
} catch (const std::exception&) {
}
}
// open for re3al.
f.open(path);
}
void WifiConfigSettings::Save()
{
try
{
ofstream_synced f;
openWithPerms(f,CONFIG_PATH);
json_writer writer(f);
writer.write(this);
}
catch (const std::exception &e)
{
throw std::runtime_error(SS("Can't save WifiConfigSettings. " << e.what()));
}
}
namespace pipedal::priv
{
class Device
{
public:
Device(const std::string &path)
: m_proxy(sdbus::createProxy(
sdbus::createSystemBusConnection(),
"org.freedesktop.NetworkManager",
path))
{
}
uint32_t GetDeviceType() const
{
sdbus::Variant device_type_variant;
m_proxy->callMethod("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments("org.freedesktop.NetworkManager.Device", "DeviceType")
.storeResultsTo(device_type_variant);
return device_type_variant.get<uint32_t>();
}
std::string GetPath() const
{
return m_proxy->getObjectPath();
}
private:
std::unique_ptr<sdbus::IProxy> m_proxy;
};
class NetworkManager
{
public:
NetworkManager()
: m_proxy(sdbus::createProxy(
sdbus::createSystemBusConnection(),
"org.freedesktop.NetworkManager",
"/org/freedesktop/NetworkManager")),
m_settings_proxy(sdbus::createProxy(
sdbus::createSystemBusConnection(),
"org.freedesktop.NetworkManager",
"/org/freedesktop/NetworkManager/Settings"))
{
}
struct HotspotInfo
{
std::string connection_path;
std::string active_connection_path;
};
std::string AddConnection(const std::map<std::string, std::map<std::string, sdbus::Variant>> &connection)
{
std::string path;
m_settings_proxy->callMethod("AddConnection")
.onInterface("org.freedesktop.NetworkManager.Settings")
.withArguments(connection)
.storeResultsTo(path);
return path;
}
std::string AddConnection(const std::string &ssid, const std::string &password)
{
// Create connection
std::map<std::string, std::map<std::string, sdbus::Variant>> connection;
connection["connection"]["type"] = sdbus::Variant("802-11-wireless");
connection["connection"]["id"] = sdbus::Variant(ssid);
std::vector<uint8_t> ssid_bytes(ssid.begin(), ssid.end());
connection["802-11-wireless"]["ssid"] = sdbus::Variant(ssid_bytes);
connection["802-11-wireless"]["mode"] = sdbus::Variant(std::string("ap"));
connection["802-11-wireless-security"]["key-mgmt"] = sdbus::Variant(std::string("wpa-psk"));
connection["802-11-wireless-security"]["psk"] = sdbus::Variant(password);
connection["ipv4"]["method"] = sdbus::Variant(std::string("shared"));
connection["ipv6"]["method"] = sdbus::Variant(std::string("ignore"));
return AddConnection(connection);
}
std::string ActivateConnection(const std::string &connection_path, const std::string &device_path)
{
std::string active_connection_path;
m_proxy->callMethod("ActivateConnection")
.onInterface("org.freedesktop.NetworkManager")
.withArguments(connection_path, device_path, "/")
.storeResultsTo(active_connection_path);
return active_connection_path;
}
void DeactivateConnection(const std::string &active_connection_path)
{
m_proxy->callMethod("DeactivateConnection")
.onInterface("org.freedesktop.NetworkManager")
.withArguments(active_connection_path);
}
std::string GetWirelessDevicePath()
{
auto devices = GetAllDevices();
for (const auto &device : devices)
{
if (device.GetDeviceType() == 2)
{ // 2 is the value for Wi-Fi devices
return device.GetPath();
}
}
throw std::runtime_error("No Wi-Fi device found");
}
std::string CreateHotspot(const std::string &ssid, const std::string &password)
{
// Create connection
std::map<std::string, std::map<std::string, sdbus::Variant>> connection;
connection["connection"]["type"] = sdbus::Variant("802-11-wireless");
connection["connection"]["id"] = sdbus::Variant(ssid);
std::vector<uint8_t> ssid_bytes(ssid.begin(), ssid.end());
connection["802-11-wireless"]["ssid"] = sdbus::Variant(ssid_bytes);
connection["802-11-wireless"]["mode"] = sdbus::Variant(std::string("ap"));
connection["802-11-wireless-security"]["key-mgmt"] = sdbus::Variant(std::string("wpa-psk"));
connection["802-11-wireless-security"]["psk"] = sdbus::Variant(password);
connection["ipv4"]["method"] = sdbus::Variant(std::string("shared"));
connection["ipv6"]["method"] = sdbus::Variant(std::string("ignore"));
auto connection_path = AddConnection(connection);
return connection_path;
}
std::string EnableHotspot(const std::string &connection_path)
{
// Enable hotspot
std::string device_path = GetWirelessDevicePath();
std::string active_connection_path = ActivateConnection(connection_path, device_path);
return active_connection_path;
}
void RemoveConnection(const std::string &connection)
{
auto connection_proxy = sdbus::createProxy(
m_proxy->getConnection(),
"org.freedesktop.NetworkManager",
connection);
connection_proxy->callMethod("Delete")
.onInterface("org.freedesktop.NetworkManager.Settings.Connection");
}
std::optional<std::string> GetActiveConnection(const std::string &device_path)
{
std::vector<sdbus::ObjectPath> active_connections;
m_proxy->callMethod("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments("org.freedesktop.NetworkManager", "ActiveConnections")
.storeResultsTo(active_connections);
for (const auto &conn : active_connections)
{
auto conn_proxy = sdbus::createProxy(
m_proxy->getConnection(),
"org.freedesktop.NetworkManager",
conn);
sdbus::ObjectPath conn_device;
conn_proxy->callMethod("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments("org.freedesktop.NetworkManager.Connection.Active", "Devices")
.storeResultsTo(conn_device);
if (conn_device == device_path)
{
return conn;
}
}
return std::nullopt;
}
std::string GetHotspotConnectionPath(const std::string &ssid)
{
std::vector<sdbus::ObjectPath> connections;
m_settings_proxy->callMethod("ListConnections")
.onInterface("org.freedesktop.NetworkManager.Settings")
.storeResultsTo(connections);
for (const auto &conn_path : connections)
{
auto conn_proxy = sdbus::createProxy(sdbus::createSystemBusConnection(),
"org.freedesktop.NetworkManager",
conn_path);
sdbus::Variant settings_variant;
conn_proxy->callMethod("GetSettings")
.onInterface("org.freedesktop.NetworkManager.Settings.Connection")
.storeResultsTo(settings_variant);
auto settings = settings_variant.get<std::map<std::string, std::map<std::string, sdbus::Variant>>>();
// Check if this is a Wi-Fi connection
if (settings["connection"]["type"].get<std::string>() == "802-11-wireless")
{
// Check if it's an access point (hotspot) connection
if (settings["802-11-wireless"]["mode"].get<std::string>() == "ap")
{
// Check if the SSID matches
std::vector<uint8_t> conn_ssid = settings["802-11-wireless"]["ssid"].get<std::vector<uint8_t>>();
std::string conn_ssid_str(conn_ssid.begin(), conn_ssid.end());
if (conn_ssid_str == ssid)
{
return conn_path;
}
}
}
}
return ""; // No matching hotspot connection found
}
private:
std::vector<Device> GetAllDevices()
{
sdbus::Variant devices_variant;
m_proxy->callMethod("Get")
.onInterface("org.freedesktop.DBus.Properties")
.withArguments("org.freedesktop.NetworkManager", "AllDevices")
.storeResultsTo(devices_variant);
std::vector<sdbus::ObjectPath> device_paths = devices_variant.get<std::vector<sdbus::ObjectPath>>();
std::vector<Device> devices;
for (const auto &path : device_paths)
{
devices.emplace_back(path);
}
return devices;
}
std::unique_ptr<sdbus::IProxy> m_proxy;
std::unique_ptr<sdbus::IProxy> m_settings_proxy;
};
}
JSON_MAP_BEGIN(WifiConfigSettings)
JSON_MAP_REFERENCE(WifiConfigSettings, valid)
JSON_MAP_REFERENCE(WifiConfigSettings, wifiWarningGiven)
JSON_MAP_REFERENCE(WifiConfigSettings, rebootRequired)
JSON_MAP_REFERENCE(WifiConfigSettings, enable)
JSON_MAP_REFERENCE(WifiConfigSettings, hotspotName)
JSON_MAP_REFERENCE(WifiConfigSettings, mdnsName)
JSON_MAP_REFERENCE(WifiConfigSettings, hasPassword)
JSON_MAP_REFERENCE(WifiConfigSettings, password)
JSON_MAP_REFERENCE(WifiConfigSettings, countryCode)
JSON_MAP_REFERENCE(WifiConfigSettings, channel)
JSON_MAP_REFERENCE(WifiConfigSettings, alwaysOn)
JSON_MAP_REFERENCE(WifiConfigSettings, homeNetworks)
JSON_MAP_END()
int32_t pipedal::ChannelToChannelNumber(const std::string &channel)
{
std::string t = channel;
// remove deprecated band specs.
if (t.size() > 1 && t[0] == 'a' || t[0] == 'g')
{
t = t.substr(1);
}
int32_t channelNumber = 0;
std::stringstream ss(t);
ss >> channelNumber;
return channelNumber;
}
static uint32_t ParseChannel(const std::string &channel)
{
std::string t = channel;
// remove dprecated band specs.
@@ -52,24 +434,9 @@ int32_t pipedal::ChannelToChannelNumber(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);
unsigned long long lChannel = std::stoull(t, &size);
if (size != t.length())
{
throw invalid_argument("Expecting a number: '" + t + "'.");
@@ -92,7 +459,7 @@ uint32_t pipedal::ChannelToWifiFrequency(uint32_t channel)
// 2.4GHz.
if (channel >= 1 && channel <= 13)
{
return 2412 + 5*(channel-1);
return 2412 + 5 * (channel - 1);
}
if (channel == 14)
{
@@ -101,26 +468,25 @@ uint32_t pipedal::ChannelToWifiFrequency(uint32_t channel)
// 802.11y
if (channel >= 131 && channel < 137)
{
return 3660 + (channel-131)*5;
return 3660 + (channel - 131) * 5;
}
if (channel >= 32 && channel <= 68 && (channel & 1) == 0)
{
return 5160 + (channel-32)/2*10;
return 5160 + (channel - 32) / 2 * 10;
}
if (channel == 96) return 5480;
if (channel == 96)
return 5480;
if (channel >= 100 && channel <= 196)
{
return 5500 + (channel-100)/5;
return 5500 + (channel - 100) / 5;
}
throw invalid_argument(SS("Invalid WiFi channel: " << channel));
}
bool WifiConfigSettings::ValidateChannel(const std::string&countryCode,const std::string&value)
bool WifiConfigSettings::ValidateChannel(const std::string &countryCode, const std::string &value)
{
if (value == "0") // = "Autoselect".
if (value == "0") // = "Autoselect".
{
return true;
}
@@ -134,15 +500,17 @@ bool WifiConfigSettings::ValidateChannel(const std::string&countryCode,const std
{
throw std::invalid_argument(SS("Invalid country code: " << countryCode));
}
auto regDom = getWifiRegClass(countryCode,ParseChannel(value),40);
if (regDom == -1) {
std::vector<int32_t> valid_channels = getValidChannels(countryCode,40);
auto regDom = getWifiRegClass(countryCode, ParseChannel(value), 40);
if (regDom == -1)
{
std::vector<int32_t> 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)
for (auto channel : valid_channels)
{
if (!first) ss << ", ";
if (!first)
ss << ", ";
first = false;
ss << channel;
}
@@ -153,10 +521,136 @@ bool WifiConfigSettings::ValidateChannel(const std::string&countryCode,const std
return true;
}
void WifiConfigSettings::ParseArguments(const std::vector<std::string> &argv)
{
static const char* trueValues[] {
"true",
"on",
"yes"
"1",
nullptr
};
static const char* falseValues[] {
"false",
"off",
"no",
"0",
nullptr
};
static bool Matches(const std::string&value, const char**matches)
{
while(*matches)
{
if (value == *matches) return true;
++matches;
}
return false;
}
static bool TryStringToBool(const std::string &value, bool*outputValue)
{
if (Matches(value,trueValues))
{
*outputValue = true;
return true;
}
if (Matches(value, falseValues)) {
*outputValue = false;
return true;
}
*outputValue = false;
return false;
}
static WifiConfigSettings::ssid_t readSsid(std::istream&ss)
{
using ssid_t = WifiConfigSettings::ssid_t;
char c;
ssid_t result;
while (ss.peek() == ' ')
{
ss >> c;
}
if (ss.peek() == '"')
{
ss >> c;
while (!ss.eof() && ss.peek() != '"')
{
ss >> c;
if (c == '\\')
{
if (ss.eof())
{
break;
}
ss >> c;
switch (c) {
case 'n':
result.push_back((uint8_t)'\n');
break;
case 'r':
result.push_back((uint8_t)'\r');
break;
case 't':
result.push_back((uint8_t)'\t');
break;
case 'b':
result.push_back((uint8_t)'\b');
break;
default:
result.push_back((uint8_t)c);
break;
}
} else {
result.push_back((uint8_t)c);
}
}
} else {
while (!ss.eof())
{
if (c == ':')
{
break;
}
ss >> c;
if (c == ':')
{
break;
}
result.push_back((uint8_t)c);
}
}
return result;
}
static std::vector<WifiConfigSettings::ssid_t> stringToSsidArray(const std::string&value)
{
using ssid_t = WifiConfigSettings::ssid_t;
std::istringstream ss(value);
std::vector<WifiConfigSettings::ssid_t> result;
while (true)
{
ssid_t ssid = readSsid(ss);
if (ssid.size() == 0)
{
break;
}
result.push_back(ssid);
if (ss.peek() == ':')
{
char c;
ss >> c;
}
}
return result;
}
void WifiConfigSettings::ParseArguments(const std::vector<std::string> &argv)
{
this->valid_ = false;
if (argv.size() != 4) {
if (argv.size() < 4 || argv.size() > 6)
{
throw invalid_argument("Invalid number of arguments.");
}
this->enable_ = true;
@@ -166,23 +660,91 @@ bool WifiConfigSettings::ValidateChannel(const std::string&countryCode,const std
this->password_ = argv[2];
this->channel_ = argv[3];
this->hasPassword_ = this->password_.length() != 0;
this->homeNetworks_ = std::vector<ssid_t>();
this->alwaysOn_ = false;
if (!ValidateCountryCode(this->countryCode_))
{
throw invalid_argument("Invalid country code.");
}
if (this->hotspotName_.length() > 31) throw invalid_argument("Hotspot name is too long.");
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 (this->hotspotName_.length() > 31)
throw invalid_argument("Hotspot name is too long.");
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->countryCode_,this->channel_))
if (!ValidateChannel(this->countryCode_, this->channel_))
{
throw invalid_argument("Channel is not valid.");
}
if (argv.size() >= 5)
{
if (!TryStringToBool(argv[4],&this->alwaysOn_))
{
throw std::runtime_error(SS("Invalid boolean value: " << argv[4]));
}
}
if (argv.size() >= 6)
{
this->homeNetworks_ = stringToSsidArray(argv[5]);
}
// validate that the channel number is supported for the given country code.
this->valid_ = true;
}
bool WifiConfigSettings::ConfigurationChanged(const WifiConfigSettings&other) const
{
return !(
this->valid_ == other.valid_ &&
this->rebootRequired_ == other.rebootRequired_ &&
this->enable_ == other.enable_ &&
this->countryCode_ == other.countryCode_ &&
this->mdnsName_ == other.mdnsName_ &&
this->hasPassword_ == other.hasPassword_ &&
this->password_ == other.password_ &&
this->channel_ == other.channel_ &&
this->homeNetworks_ == other.homeNetworks_ &&
this->alwaysOn_ == other.alwaysOn_
);
}
bool WifiConfigSettings::operator==(const WifiConfigSettings&other) const
{
return !ConfigurationChanged(other) && this->wifiWarningGiven_ == other.wifiWarningGiven_;
}
bool WifiConfigSettings::WantsHotspot(bool ethernetConnected, const std::vector<ssid_t> &availableNetworks)
{
if ((!this->valid_) || (!this->enable_))
return false;
if (ethernetConnected)
{
return false;
}
if (!homeNetworks_.empty())
{
for (auto &network: availableNetworks)
{
for (auto&homeNetwork: homeNetworks_)
{
if (network == homeNetwork)
{
return false;
}
}
}
}
if (alwaysOn_)
{
return true;
}
return availableNetworks.size() == 0;
}
}
@@ -0,0 +1,84 @@
#pragma once
#include <memory>
#include <functional>
#include <thread>
#include <mutex>
#include <vector>
#include <chrono>
#include <atomic>
namespace sdbus {
class IConnection;
};
class DBusDispatcher {
DBusDispatcher(const DBusDispatcher&) = delete;
DBusDispatcher(DBusDispatcher&&) = delete;
DBusDispatcher & operator=(const DBusDispatcher&) = delete;
DBusDispatcher & operator=(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<void(void)> &&callback);
bool IsStopping();
using PostHandle = uint64_t;
using PostCallback = std::function<void()>;
PostHandle Post(PostCallback&&fn);
using clock = std::chrono::steady_clock;
template<class REP,class PERIOD>
DBusDispatcher::PostHandle PostDelayed(const std::chrono::duration<REP,PERIOD>&delay,PostCallback&&fn)
{
return PostDelayed(
std::chrono::duration_cast<clock::duration,REP,PERIOD>(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<bool> isFinished;
std::atomic<bool> signalStopRequested;
bool signalStopExecuted = false;
std::function<void(void)> signalStopCallback;
uint64_t NextHandle() {
return nextHandle.fetch_add(1);
}
int GetEventTimeoutMs();
std::atomic<PostHandle> nextHandle;
int eventFd = -1;
bool closed = false;
void ThreadProc();
void WakeThread();
std::unique_ptr<sdbus::IConnection> busConnection;
struct CallbackEntry {
PostCallback callback;
clock::time_point time;
PostHandle handle;
};
std::atomic<bool> stopping;
std::vector<CallbackEntry> postedEvents;
bool threadJoined;
std::thread serviceThread;
std::mutex postMutex;
};
+62
View File
@@ -0,0 +1,62 @@
#pragma once
#include <functional>
#include <atomic>
#include <map>
#include <vector>
#include <mutex>
#include <memory>
namespace impl {
extern std::atomic<uint64_t> NextHandle;
}
using DBusEventHandle=uint64_t;
constexpr DBusEventHandle INVALID_DBUS_EVENT_HANDLE = 0;
template <typename... ARG_TYPES>
class DBusEvent {
public:
using Callback=std::function<void (ARG_TYPES...)>;
DBusEventHandle add(Callback&&cb)
{
auto handle = impl::NextHandle.fetch_add(1,std::memory_order::acq_rel);
{
std::lock_guard<std::mutex> lock{m};
callbacks[handle] = std::make_shared<Callback>(std::move(cb));
}
return handle;
}
void remove(DBusEventHandle h)
{
std::lock_guard<std::mutex> lock{m};
callbacks.erase(h);
}
void fire(ARG_TYPES...args)
{
std::vector<std::shared_ptr<Callback>> cbs;
cbs.reserve(callbacks.size());
{
std::lock_guard<std::mutex> 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<std::mutex> lock{m};
cbs.clear();
}
}
private:
std::map<DBusEventHandle,std::shared_ptr<Callback>> callbacks;
std::mutex m;
};
+99
View File
@@ -0,0 +1,99 @@
#pragma once
#include <string>
#include <iostream>
#include <functional>
#include <mutex>
#include <filesystem>
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);
void SetDBusLogger(std::unique_ptr<IDBusLogger>&&logger);
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<std::string ()> &text);
extern void LogDebug(const std::string&path,const char*method,const std::function<std::string ()> &text);
extern void LogInfo(const std::string&path,const char*method,const std::function<std::string ()> &text);
extern void LogWarning(const std::string&path,const char*method,const std::function<std::string ()> &text);
extern void LogError(const std::string&path,const char*method,const std::function<std::string ()> &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<std::string ()> &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<std::string ()> &text)
{
if (impl::dbusLogLevel > DBusLogLevel::Trace) return;
::LogTrace(path,tag,text());
}
private:
std::string path;
};
@@ -0,0 +1,11 @@
#pragma once
#include <map>
#include <string>
#include <ostream>
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<std::string, sdbus::Variant>& properties);
@@ -0,0 +1,348 @@
#pragma once
#include "DBusEvent.hpp"
#include "DBusLog.hpp"
#include "DBusDispatcher.hpp"
#include "dbus/org.freedesktop.NetworkManager.Device.WifiP2P.hpp"
#include "dbus/org.freedesktop.NetworkManager.Device.hpp"
#include "dbus/org.freedesktop.NetworkManager.Device.Wireless.hpp"
#include "dbus/org.freedesktop.NetworkManager.Settings.Connection.hpp"
#include "dbus/org.freedesktop.NetworkManager.WifiP2PPeer.hpp"
#include "dbus/org.freedesktop.NetworkManager.AccessPoint.hpp"
#include "dbus/org.freedesktop.NetworkManager.Connection.Active.hpp"
#include "dbus/org.freedesktop.NetworkManager.hpp"
#include "libnm/nm-dbus-interface.h"
namespace dbus::networkmanager {
namespace nm_impl
{
extern std::string NetworkManagerStateToString(uint32_t state);
std::string NetworkManagerDeviceStateToString(uint32_t state);
};
class NetworkManager : public sdbus::ProxyInterfaces<org::freedesktop::NetworkManager_proxy>
{
public:
using ptr = std::unique_ptr<NetworkManager>;
NetworkManager(DBusDispatcher &dispatcher)
: sdbus::ProxyInterfaces<org::freedesktop::NetworkManager_proxy>(
dispatcher.Connection(),
INTERFACE_NAME,
"/org/freedesktop/NetworkManager")
{
registerProxy();
}
virtual ~NetworkManager()
{
unregisterProxy();
}
static ptr Create(DBusDispatcher &dispatcher) { return std::make_unique<NetworkManager>(dispatcher); }
DBusEvent<> OnCheckPermissions;
DBusEvent<uint32_t> OnStateChanged;
DBusEvent<const sdbus::ObjectPath &> OnDeviceAdded;
DBusEvent<const sdbus::ObjectPath &> OnDeviceRemoved;
private:
void EventTrace(const char *method, const std::string &message)
{
LogTrace(getObjectPath(), method, message);
}
virtual void onStateChanged(const uint32_t &state)
{
EventTrace("onStateChanged", nm_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<org::freedesktop::NetworkManager::Device_proxy>
{
public:
using ptr = std::unique_ptr<Device>;
Device(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
: sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::Device_proxy>(
dispatcher.Connection(),
"org.freedesktop.NetworkManager",
path)
{
registerProxy();
}
virtual ~Device()
{
unregisterProxy();
}
static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
{
return std::make_unique<Device>(dispatcher, path);
}
DBusEvent<uint32_t, uint32_t, uint32_t> 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", nm_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<WifiP2P>;
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<WifiP2P>(dispatcher, objectPath);
}
DBusEvent<const sdbus::ObjectPath &> OnPeerAdded;
DBusEvent<const sdbus::ObjectPath &> OnPeerRemoved;
DBusEvent<uint32_t> 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", nm_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 Connection : public sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::Settings::Connection_proxy>
{
public:
using self = Connection;
using ptr = std::unique_ptr<self>;
Connection(DBusDispatcher &dispatcher, const sdbus::ObjectPath &objectPath)
: sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::Settings::Connection_proxy>(
dispatcher.Connection(), "org.freedesktop.NetworkManager", objectPath)
{
registerProxy();
}
static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &objectPath)
{
return std::make_unique<self>(dispatcher, objectPath);
}
virtual ~Connection()
{
unregisterProxy();
}
DBusEvent<> OnUpdated;
DBusEvent<> OnRemoved;
private:
virtual void onUpdated() override
{
OnUpdated.fire();
}
virtual void onRemoved() override
{
OnRemoved.fire();
}
};
class WifiP2PPeer : public sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::WifiP2PPeer_proxy>
{
public:
using self = WifiP2PPeer;
using ptr = std::unique_ptr<self>;
WifiP2PPeer(DBusDispatcher &dispatcher, const sdbus::ObjectPath &objectPath)
: sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::WifiP2PPeer_proxy>(
dispatcher.Connection(), "org.freedesktop.NetworkManager", objectPath)
{
registerProxy();
}
virtual ~WifiP2PPeer()
{
unregisterProxy();
}
static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &objectPath)
{
return std::make_unique<self>(dispatcher, objectPath);
}
DBusEvent<const sdbus::ObjectPath &> OnPeerAdded;
DBusEvent<const sdbus::ObjectPath &> OnPeerRemoved;
private:
virtual void onPeerAdded(const sdbus::ObjectPath &peer)
{
OnPeerAdded.fire(peer);
}
virtual void onPeerRemoved(const sdbus::ObjectPath &peer)
{
OnPeerRemoved.fire(peer);
}
};
class DeviceWireless : public sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::Device::Wireless_proxy>
{
public:
using self = DeviceWireless;
using ptr = std::unique_ptr<self>;
using proxy_t = org::freedesktop::NetworkManager::Device::Wireless_proxy;
DeviceWireless(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
: sdbus::ProxyInterfaces<proxy_t>(
dispatcher.Connection(),
"org.freedesktop.NetworkManager",
path)
{
registerProxy();
}
virtual ~DeviceWireless()
{
unregisterProxy();
}
static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
{
return std::make_unique<self>(dispatcher, path);
}
DBusEvent<const sdbus::ObjectPath&> OnAccessPointAdded;
DBusEvent<const sdbus::ObjectPath&> OnAccessPointRemoved;
protected:
void EventTrace(const char *method, const std::string &message)
{
LogTrace(getObjectPath(), method, message);
}
virtual void onAccessPointAdded(const sdbus::ObjectPath& access_point) override {
EventTrace("onAccessPointAdded", access_point.c_str());
OnAccessPointAdded.fire(access_point);
}
virtual void onAccessPointRemoved(const sdbus::ObjectPath& access_point) {
EventTrace("onAccessPointRemoved",access_point.c_str());
OnAccessPointRemoved.fire(access_point);
}
};
class AccessPoint : public sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::AccessPoint_proxy>
{
public:
using self = AccessPoint;
using ptr = std::unique_ptr<self>;
using proxy_t = org::freedesktop::NetworkManager::AccessPoint_proxy;
AccessPoint(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
: sdbus::ProxyInterfaces<proxy_t>(
dispatcher.Connection(),
"org.freedesktop.NetworkManager",
path)
{
registerProxy();
}
virtual ~AccessPoint()
{
unregisterProxy();
}
static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
{
return std::make_unique<self>(dispatcher, path);
}
protected:
void EventTrace(const char *method, const std::string &message)
{
LogTrace(getObjectPath(), method, message);
}
};
class ActiveConnection : public sdbus::ProxyInterfaces<org::freedesktop::NetworkManager::Connection::Active_proxy>
{
public:
using self = ActiveConnection;
using ptr = std::unique_ptr<self>;
using proxy_t = org::freedesktop::NetworkManager::Connection::Active_proxy;
ActiveConnection(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
: sdbus::ProxyInterfaces<proxy_t>(
dispatcher.Connection(),
"org.freedesktop.NetworkManager",
path)
{
registerProxy();
}
virtual ~ActiveConnection()
{
unregisterProxy();
}
static ptr Create(DBusDispatcher &dispatcher, const sdbus::ObjectPath &path)
{
return std::make_unique<self>(dispatcher, path);
}
DBusEvent<uint32_t,uint32_t> OnStateChanged;
protected:
void EventTrace(const char *method, const std::string &message)
{
LogTrace(getObjectPath(), method, message);
}
virtual void onStateChanged(const uint32_t& state, const uint32_t& reason) {
OnStateChanged.fire(state,reason);
}
};
} // namespace
@@ -21,6 +21,23 @@
#include "json.hpp"
#ifndef NEW_WIFI_CONFIG
// 0-> Old hostapd-based hotspot. Now dead code. Works with buster only.
// 1-> NetworkManager-based hotspot (supported on bookworm or later).
#define NEW_WIFI_CONFIG 1
#endif
// Wifi P2P broken completely on Debian 12 updates on raspberry pi.
//
// Setting it to enable uses current-orphaned dead code as of PiPedal v1.2.49
//
// 0: disable.
// 1: enable.
#ifndef ENABLE_WIFI_P2P
#define ENABLE_WIFI_P2P 0
#endif
namespace pipedal {
@@ -30,6 +47,12 @@ namespace pipedal {
class WifiConfigSettings {
public:
using ssid_t = std::vector<uint8_t>;
WifiConfigSettings();
void Load();
void Save();
bool valid_ = false;
bool wifiWarningGiven_ = false;
bool rebootRequired_ = false;
@@ -37,13 +60,20 @@ namespace pipedal {
std::string countryCode_ = "US"; // iso 3661
std::string hotspotName_ = "pipedal";
std::string mdnsName_ = "pipedal";
std::vector<ssid_t> homeNetworks_;
bool hasPassword_ = false;
std::string password_;
std::string channel_ = "g6";
std::string channel_ = "";
bool alwaysOn_ = false;
void ParseArguments(const std::vector<std::string> &arguments);
static bool ValidateCountryCode(const std::string&value);
static bool ValidateChannel(const std::string&countryCode,const std::string&value);
bool operator==(const WifiConfigSettings&other) const;
bool ConfigurationChanged(const WifiConfigSettings&other) const;
bool WantsHotspot(bool ethernetConnected,const std::vector<ssid_t> &availableNetworks);
public:
DECLARE_JSON_MAP(WifiConfigSettings);
};
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<uint8_t> 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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<sdbus::ObjectPath> 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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string, sdbus::Variant> Options()
{
return proxy_.getProperty("Options").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string, sdbus::Variant> Options()
{
return proxy_.getProperty("Options").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string, sdbus::Variant>& 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<sdbus::ObjectPath> Peers()
{
return proxy_.getProperty("Peers").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<sdbus::ObjectPath> GetAccessPoints()
{
std::vector<sdbus::ObjectPath> result;
proxy_.callMethod("GetAccessPoints").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::vector<sdbus::ObjectPath> GetAllAccessPoints()
{
std::vector<sdbus::ObjectPath> result;
proxy_.callMethod("GetAllAccessPoints").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
void RequestScan(const std::map<std::string, sdbus::Variant>& 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<sdbus::ObjectPath> 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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string, std::map<std::string, sdbus::Variant>>& connection, const uint64_t& version_id, const uint32_t& flags)
{
proxy_.callMethod("Reapply").onInterface(INTERFACE_NAME).withArguments(connection, version_id, flags);
}
std::tuple<std::map<std::string, std::map<std::string, sdbus::Variant>>, uint64_t> GetAppliedConnection(const uint32_t& flags)
{
std::tuple<std::map<std::string, std::map<std::string, sdbus::Variant>>, 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<uint32_t, uint32_t> 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<sdbus::ObjectPath> 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<std::map<std::string, sdbus::Variant>> 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<sdbus::ObjectPath> Ports()
{
return proxy_.getProperty("Ports").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::map<std::string, sdbus::Variant>> Configuration()
{
return proxy_.getProperty("Configuration").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::vector<uint32_t>> Addresses()
{
return proxy_.getProperty("Addresses").onInterface(INTERFACE_NAME);
}
std::vector<std::map<std::string, sdbus::Variant>> AddressData()
{
return proxy_.getProperty("AddressData").onInterface(INTERFACE_NAME);
}
std::string Gateway()
{
return proxy_.getProperty("Gateway").onInterface(INTERFACE_NAME);
}
std::vector<std::vector<uint32_t>> Routes()
{
return proxy_.getProperty("Routes").onInterface(INTERFACE_NAME);
}
std::vector<std::map<std::string, sdbus::Variant>> RouteData()
{
return proxy_.getProperty("RouteData").onInterface(INTERFACE_NAME);
}
std::vector<uint32_t> Nameservers()
{
return proxy_.getProperty("Nameservers").onInterface(INTERFACE_NAME);
}
std::vector<std::map<std::string, sdbus::Variant>> NameserverData()
{
return proxy_.getProperty("NameserverData").onInterface(INTERFACE_NAME);
}
std::vector<std::string> Domains()
{
return proxy_.getProperty("Domains").onInterface(INTERFACE_NAME);
}
std::vector<std::string> Searches()
{
return proxy_.getProperty("Searches").onInterface(INTERFACE_NAME);
}
std::vector<std::string> DnsOptions()
{
return proxy_.getProperty("DnsOptions").onInterface(INTERFACE_NAME);
}
int32_t DnsPriority()
{
return proxy_.getProperty("DnsPriority").onInterface(INTERFACE_NAME);
}
std::vector<uint32_t> WinsServers()
{
return proxy_.getProperty("WinsServers").onInterface(INTERFACE_NAME);
}
std::vector<std::string> WinsServerData()
{
return proxy_.getProperty("WinsServerData").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<sdbus::Struct<std::vector<uint8_t>, uint32_t, std::vector<uint8_t>>> Addresses()
{
return proxy_.getProperty("Addresses").onInterface(INTERFACE_NAME);
}
std::vector<std::map<std::string, sdbus::Variant>> AddressData()
{
return proxy_.getProperty("AddressData").onInterface(INTERFACE_NAME);
}
std::string Gateway()
{
return proxy_.getProperty("Gateway").onInterface(INTERFACE_NAME);
}
std::vector<sdbus::Struct<std::vector<uint8_t>, uint32_t, std::vector<uint8_t>, uint32_t>> Routes()
{
return proxy_.getProperty("Routes").onInterface(INTERFACE_NAME);
}
std::vector<std::map<std::string, sdbus::Variant>> RouteData()
{
return proxy_.getProperty("RouteData").onInterface(INTERFACE_NAME);
}
std::vector<std::vector<uint8_t>> Nameservers()
{
return proxy_.getProperty("Nameservers").onInterface(INTERFACE_NAME);
}
std::vector<std::string> Domains()
{
return proxy_.getProperty("Domains").onInterface(INTERFACE_NAME);
}
std::vector<std::string> Searches()
{
return proxy_.getProperty("Searches").onInterface(INTERFACE_NAME);
}
std::vector<std::string> DnsOptions()
{
return proxy_.getProperty("DnsOptions").onInterface(INTERFACE_NAME);
}
int32_t DnsPriority()
{
return proxy_.getProperty("DnsPriority").onInterface(INTERFACE_NAME);
}
private:
sdbus::IProxy& proxy_;
};
}}} // namespaces
#endif
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<std::string, std::map<std::string, sdbus::Variant>>& properties)
{
proxy_.callMethod("Update").onInterface(INTERFACE_NAME).withArguments(properties);
}
void UpdateUnsaved(const std::map<std::string, std::map<std::string, sdbus::Variant>>& properties)
{
proxy_.callMethod("UpdateUnsaved").onInterface(INTERFACE_NAME).withArguments(properties);
}
void Delete()
{
proxy_.callMethod("Delete").onInterface(INTERFACE_NAME);
}
std::map<std::string, std::map<std::string, sdbus::Variant>> GetSettings()
{
std::map<std::string, std::map<std::string, sdbus::Variant>> result;
proxy_.callMethod("GetSettings").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::map<std::string, std::map<std::string, sdbus::Variant>> GetSecrets(const std::string& setting_name)
{
std::map<std::string, std::map<std::string, sdbus::Variant>> 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<std::string, sdbus::Variant> Update2(const std::map<std::string, std::map<std::string, sdbus::Variant>>& settings, const uint32_t& flags, const std::map<std::string, sdbus::Variant>& args)
{
std::map<std::string, sdbus::Variant> 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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<sdbus::ObjectPath> ListConnections()
{
std::vector<sdbus::ObjectPath> 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<std::string, std::map<std::string, sdbus::Variant>>& connection)
{
sdbus::ObjectPath result;
proxy_.callMethod("AddConnection").onInterface(INTERFACE_NAME).withArguments(connection).storeResultsTo(result);
return result;
}
sdbus::ObjectPath AddConnectionUnsaved(const std::map<std::string, std::map<std::string, sdbus::Variant>>& connection)
{
sdbus::ObjectPath result;
proxy_.callMethod("AddConnectionUnsaved").onInterface(INTERFACE_NAME).withArguments(connection).storeResultsTo(result);
return result;
}
std::tuple<sdbus::ObjectPath, std::map<std::string, sdbus::Variant>> AddConnection2(const std::map<std::string, std::map<std::string, sdbus::Variant>>& settings, const uint32_t& flags, const std::map<std::string, sdbus::Variant>& args)
{
std::tuple<sdbus::ObjectPath, std::map<std::string, sdbus::Variant>> result;
proxy_.callMethod("AddConnection2").onInterface(INTERFACE_NAME).withArguments(settings, flags, args).storeResultsTo(result);
return result;
}
std::tuple<bool, std::vector<std::string>> LoadConnections(const std::vector<std::string>& filenames)
{
std::tuple<bool, std::vector<std::string>> 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<sdbus::ObjectPath> 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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<uint8_t> 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
@@ -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 <sdbus-c++/sdbus-c++.h>
#include <string>
#include <tuple>
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<sdbus::ObjectPath> GetDevices()
{
std::vector<sdbus::ObjectPath> result;
proxy_.callMethod("GetDevices").onInterface(INTERFACE_NAME).storeResultsTo(result);
return result;
}
std::vector<sdbus::ObjectPath> GetAllDevices()
{
std::vector<sdbus::ObjectPath> 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<sdbus::ObjectPath, sdbus::ObjectPath> AddAndActivateConnection(const std::map<std::string, std::map<std::string, sdbus::Variant>>& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object)
{
std::tuple<sdbus::ObjectPath, sdbus::ObjectPath> result;
proxy_.callMethod("AddAndActivateConnection").onInterface(INTERFACE_NAME).withArguments(connection, device, specific_object).storeResultsTo(result);
return result;
}
std::tuple<sdbus::ObjectPath, sdbus::ObjectPath, std::map<std::string, sdbus::Variant>> AddAndActivateConnection2(const std::map<std::string, std::map<std::string, sdbus::Variant>>& connection, const sdbus::ObjectPath& device, const sdbus::ObjectPath& specific_object, const std::map<std::string, sdbus::Variant>& options)
{
std::tuple<sdbus::ObjectPath, sdbus::ObjectPath, std::map<std::string, sdbus::Variant>> 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<std::string, std::string> GetPermissions()
{
std::map<std::string, std::string> 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<std::string, std::string> GetLogging()
{
std::tuple<std::string, std::string> 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<sdbus::ObjectPath>& 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<std::string, uint32_t> CheckpointRollback(const sdbus::ObjectPath& checkpoint)
{
std::map<std::string, uint32_t> 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<sdbus::ObjectPath> Devices()
{
return proxy_.getProperty("Devices").onInterface(INTERFACE_NAME);
}
std::vector<sdbus::ObjectPath> AllDevices()
{
return proxy_.getProperty("AllDevices").onInterface(INTERFACE_NAME);
}
std::vector<sdbus::ObjectPath> 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<sdbus::ObjectPath> 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<uint32_t> VersionInfo()
{
return proxy_.getProperty("VersionInfo").onInterface(INTERFACE_NAME);
}
std::vector<uint32_t> 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<std::string, sdbus::Variant> GlobalDnsConfiguration()
{
return proxy_.getProperty("GlobalDnsConfiguration").onInterface(INTERFACE_NAME);
}
void GlobalDnsConfiguration(const std::map<std::string, sdbus::Variant>& value)
{
proxy_.setProperty("GlobalDnsConfiguration").onInterface(INTERFACE_NAME).toValue(value);
}
private:
sdbus::IProxy& proxy_;
};
}} // namespaces
#endif
+15
View File
@@ -327,6 +327,14 @@ namespace pipedal
bool allowNaN() const { return allowNaN_; }
void allowNaN(bool allow) { allowNaN_ = allow; }
void write(uint8_t value)
{
os << value;
}
void write(int8_t value)
{
os << value;
}
void write(long long value)
{
os << value;
@@ -882,6 +890,13 @@ namespace pipedal
skip_whitespace();
*value = read_boolean();
}
void read(uint8_t*value)
{
skip_whitespace();
is_ >> *value;
if (is_.fail())
throw JsonException("Invalid format.");
}
void read(int *value)
{
skip_whitespace();
+1 -1
View File
@@ -1,5 +1,5 @@
{
"socket_server_port": 81,
"socket_server_port": 8080,
"socket_server_address": "*",
"debug": true,
"max_upload_size": 536870912,
+1 -1
View File
@@ -942,7 +942,7 @@ export class PiPedalModel //implements PiPedalModel
return this.webSocket.connect();
})
.catch((error) => {
this.setError("Failed to connect to server." + error.toString());
this.setError("Failed to connect to server. " + this.socketServerUrl);
return false;
})
.then(() => {
+1 -2
View File
@@ -278,7 +278,7 @@ class PiPedalSocket {
ws.onerror = null;
reject("Connection closed unexpectedly.");
};
ws.onerror = (event: Event) => {
ws.onerror = (evWheent: Event) => {
ws.onclose = null;
ws.onerror = null;
reject("Failed to connect.");
@@ -286,7 +286,6 @@ class PiPedalSocket {
ws.onopen = (event: Event) => {
ws.onerror = self.handleError.bind(self);
ws.onclose = self.handleClose.bind(self);
alert("Web socket connected."); //yyy
ws.onopen = null;
resolve(ws);
};
+22 -17
View File
@@ -24,7 +24,7 @@ import ListSelectDialog from './ListSelectDialog';
import IconButton from '@mui/material/IconButton';
import Typography from '@mui/material/Typography';
import { PiPedalModel, PiPedalModelFactory, State } from './PiPedalModel';
import {ColorTheme} from './DarkMode';
import { ColorTheme } from './DarkMode';
import ButtonBase from "@mui/material/ButtonBase";
import AppBar from '@mui/material/AppBar';
import Button from '@mui/material/Button';
@@ -394,11 +394,10 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
});
}
handleCheckForUpdates()
{
handleCheckForUpdates() {
this.model.showUpdateDialog();
}
handleMidiMessageSettings() {
this.setState({
showSystemMidiBindingsDialog: true
@@ -702,13 +701,13 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<ButtonBase
className={classes.setting} disabled={!this.state.wifiConfigSettings.valid}
onClick={() => this.handleShowWifiDirectConfigDialog()} >
onClick={() => this.handleShowWifiConfigDialog()} >
<SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}>
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
Configure Wi-Fi Direct hotspot</Typography>
Wi-Fi auto hotspot</Typography>
<Typography display="block" variant="caption" noWrap color="textSecondary">
{this.state.wifiDirectConfigSettings.getSummaryText()}
{this.state.wifiConfigSettings.getSummaryText()}
</Typography>
</div>
@@ -756,8 +755,8 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<Typography className={classes.primaryItem} display="block" variant="body2" color="textPrimary" noWrap>
Color theme</Typography>
<Typography className={classes.secondaryItem} display="block" variant="caption" color="textSecondary" noWrap>
{ this.model.getTheme() === ColorTheme.Dark ? "Dark" :
(this.model.getTheme() === ColorTheme.Light ? "Light": "System")}
{this.model.getTheme() === ColorTheme.Dark ? "Dark" :
(this.model.getTheme() === ColorTheme.Light ? "Light" : "System")}
</Typography>
</div>
</ButtonBase>
@@ -765,9 +764,9 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
<ButtonBase
className={classes.setting}
onClick={() => {
onClick={() => {
this.model.setShowStatusMonitor(!this.state.showStatusMonitor)
}} >
}} >
<SelectHoverBackground selected={false} showHover={true} />
<div style={{ width: "100%" }}>
<div style={{
@@ -900,20 +899,26 @@ const SettingsDialog = withStyles(styles, { withTheme: true })(
(this.state.showThemeSelectDialog) &&
(
<SelectThemeDialog open={this.state.showThemeSelectDialog}
onClose={()=> { this.setState({showThemeSelectDialog: false});} }
onClose={() => { this.setState({ showThemeSelectDialog: false }); }}
onOk={(selectedTheme: ColorTheme) => {
this.model.setTheme(selectedTheme);
this.setState({showThemeSelectDialog: false});
this.setState({ showThemeSelectDialog: false });
}}
defaultTheme={this.model.getTheme()}
/>
)
}
<WifiConfigDialog wifiConfigSettings={this.state.wifiConfigSettings} open={this.state.showWifiConfigDialog}
onClose={() => this.setState({ showWifiConfigDialog: false })}
onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)}
/>
{
(this.state.showWifiConfigDialog) &&
(
<WifiConfigDialog wifiConfigSettings={this.state.wifiConfigSettings} open={this.state.showWifiConfigDialog}
onClose={() => this.setState({ showWifiConfigDialog: false })}
onOk={(wifiConfigSettings) => this.handleApplyWifiConfig(wifiConfigSettings)}
/>
)
}
<WifiDirectConfigDialog wifiDirectConfigSettings={this.state.wifiDirectConfigSettings} open={this.state.showWifiDirectConfigDialog}
onClose={() => this.setState({ showWifiDirectConfigDialog: false })}
onOk={(wifiDirectConfigSettings: WifiDirectConfigSettings) => this.handleApplyWifiDirectConfig(wifiDirectConfigSettings)}
+13 -1
View File
@@ -9,6 +9,8 @@ set(CXX_STANDARD 20)
include(FindPkgConfig)
find_package(sdbus-c++ REQUIRED)
if(DEFINED ENV{GITHUB_ACTIONS})
message(STATUS "Building in GitHub Actions environment")
@@ -144,6 +146,8 @@ else()
endif()
set (PIPEDAL_SOURCES
DBusToLv2Log.cpp DBusToLv2Log.hpp
HotspotManager.cpp HotspotManager.hpp
UpdateResults.cpp UpdateResults.hpp
UpdaterSecurity.hpp
Updater.cpp Updater.hpp
@@ -252,6 +256,7 @@ set (PIPEDAL_INCLUDES
)
set(PIPEDAL_LIBS libpipedald zip
PiPedalCommon
icui18n
icuuc
icudata
@@ -290,6 +295,13 @@ target_link_libraries(pipedald PRIVATE PiPedalCommon
)
#################################
add_executable(hotspotManagerTest
hotspotManagerTestMain.cpp
HotspotManager.cpp HotspotManager.hpp Lv2Log.cpp Lv2Log.hpp)
target_link_libraries(hotspotManagerTest PRIVATE ${PIPEDAL_LIBS})
add_executable(pipedaltest testMain.cpp
InvertingMutexTest.cpp
@@ -313,7 +325,7 @@ add_executable(pipedaltest testMain.cpp
MemDebug.cpp
MemDebug.hpp
)
target_link_libraries(pipedaltest PRIVATE PiPedalCommon)
target_link_libraries(pipedaltest PRIVATE ${PIPEDAL_LIBS})
target_include_directories(pipedaltest PRIVATE ${PIPEDAL_INCLUDES}
)
+19
View File
@@ -1,3 +1,22 @@
// Copyright (c) 2022-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 "Storage.hpp"
#include "CommandLineParser.hpp"
#include <filesystem>
+99 -5
View File
@@ -22,6 +22,8 @@
#include <stdlib.h>
#include <unistd.h>
#include "CommandLineParser.hpp"
#include "SystemConfigFile.hpp"
#include <filesystem>
#include <stdlib.h>
#include "WriteTemplateFile.hpp"
@@ -42,6 +44,7 @@
#include <grp.h>
#include "ofstream_synced.hpp"
#define P2PD_DISABLED
#if JACK_HOST
#define INSTALL_JACK_SERVICE 1
@@ -64,6 +67,7 @@ namespace fs = std::filesystem;
#define JACK_SERVICE_ACCOUNT_NAME "jack"
#define AUDIO_SERVICE_GROUP_NAME "audio"
#define JACK_SERVICE_GROUP_NAME AUDIO_SERVICE_GROUP_NAME
#define NETDEV_GROUP_NAME "netdev"
#define SYSTEMCTL_BIN "/usr/bin/systemctl"
#define GROUPADD_BIN "/usr/sbin/groupadd"
@@ -151,6 +155,86 @@ void DisableService()
#endif
}
static void RestartAvahiService()
{
silentSysExec(SS(SYSTEMCTL_BIN << " restart avahi-daemon.service").c_str());
}
static void AvahiInstall()
{
// disable IPv6 mdns broadcasts. Avahi broadcasts link-local IPV6 addresses which are unusually difficult to deal with.
try
{
std::filesystem::path avahiConfig("/etc/avahi/avahi-daemon.conf");
SystemConfigFile avahi(avahiConfig);
bool changed = avahi.RemoveUndoableActions();
int line = avahi.GetLineThatStartsWith("use-ipv6=yes");
if (line != -1)
{
avahi.UndoableReplaceLine(line, "use-ipv6=no");
changed = true;
}
else
{
if (avahi.GetLineThatStartsWith("use-ipv6=no") == -1)
{
line = avahi.GetLineThatStartsWith("[server]");
if (line == 1)
{
throw std::runtime_error("Unable to find [server] section.");
}
{
// increment to end of section.
while (line < avahi.GetLineCount())
{
const auto &txt = avahi.Get(line);
if (txt.empty())
{
break;
}
if (txt.starts_with("[")) // start of next section.
{
break;
}
++line;
}
}
avahi.UndoableAddLine(avahi.GetLineCount(), "use-ipv6=no");
changed = true;
}
}
if (changed)
{
avahi.Save();
RestartAvahiService();
}
}
catch (const std::exception &e)
{
cout << "Warning: Unabled to disable Ipv6 mDNS announcements. " << e.what() << endl;
}
}
static void AvahiUninstall()
{
try
{
std::filesystem::path avahiConfig("/etc/avahi/avahi-daemon.conf");
SystemConfigFile avahi(avahiConfig);
if (avahi.RemoveUndoableActions())
{
avahi.Save();
RestartAvahiService();
}
}
catch (const std::exception &e)
{
cout << " Warning: Unable to restore Avahi Daemon configuration. " << e.what() << endl;
}
}
void StopService(bool excludeShutdownService = false)
{
if (sysExec(SYSTEMCTL_BIN " stop " PIPEDALD_SERVICE ".service") != EXIT_SUCCESS)
@@ -526,6 +610,8 @@ void Uninstall()
{
}
UninstallPamEnv();
AvahiUninstall();
// UninstallLimits();
sysExec(SYSTEMCTL_BIN " daemon-reload");
}
@@ -676,7 +762,8 @@ static void FixPermissions()
struct passwd *passwd;
if ((passwd = getpwnam("pipedal_d")) == nullptr)
{
cout << "Error: " << "User 'pipedal_d' does not exist." << endl;
cout << "Error: "
<< "User 'pipedal_d' does not exist." << endl;
return;
}
uid = passwd->pw_uid;
@@ -790,7 +877,6 @@ void InstallPgpKey()
{
cout << "Error: Failed to create update keyring." << endl;
}
}
{
std::ostringstream ss;
@@ -800,7 +886,6 @@ void InstallPgpKey()
{
cout << "Error: Failed to add update key." << endl;
}
}
{
std::stringstream ss;
@@ -825,6 +910,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
throw std::runtime_error("Failed to create pipedald service group.");
}
// defensively disable wifi p2p if some leftover config file left it enabled.
#ifdef P2PD_DISABLED
try
{
if (IsP2pServiceEnabled())
@@ -838,6 +924,7 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
catch (const std::exception &)
{
}
#endif
InstallAudioService();
auto endpos = endpointAddress.find_last_of(':');
@@ -888,6 +975,9 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
// Add to audio groups.
sysExec(USERMOD_BIN " -a -G " AUDIO_SERVICE_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
// add to netdev group
sysExec(USERMOD_BIN " -a -G " NETDEV_GROUP_NAME " " SERVICE_ACCOUNT_NAME);
// create and configure /var directory.
@@ -1007,12 +1097,16 @@ void Install(const fs::path &programPrefix, const std::string endpointAddress)
sysExec(SYSTEMCTL_BIN " daemon-reload");
FixPermissions();
RestartService(false);
StopService(false);
AvahiInstall();
InstallPgpKey();
StartService(false);
EnableService();
// Restart WiFi Direct if neccessary.
OnWifiReinstall();
InstallPgpKey();
}
catch (const std::exception &e)
{
+55
View File
@@ -0,0 +1,55 @@
// 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 "DBusToLv2Log.hpp"
#include "DBusLog.hpp"
#include "Lv2Log.hpp"
using namespace pipedal;
class DBus2ToLv2Logger : public IDBusLogger
{
public:
virtual void LogError(const std::string &message) override
{
Lv2Log::error(message);
}
virtual void LogWarning(const std::string &message) override
{
Lv2Log::warning(message);
}
virtual void LogInfo(const std::string &message) override
{
Lv2Log::info(message);
}
virtual void LogDebug(const std::string &message) override
{
Lv2Log::debug(message);
}
virtual void LogTrace(const std::string &message) override
{
Lv2Log::debug(message);
}
};
void pipedal::DbusLogToLv2Log()
{
SetDBusLogger(std::make_unique<DBus2ToLv2Logger>());
}
+25
View File
@@ -0,0 +1,25 @@
// 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
namespace pipedal {
void DbusLogToLv2Log();
}
+851
View File
@@ -0,0 +1,851 @@
// 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 "HotspotManager.hpp"
#include <thread>
#include "Lv2Log.hpp"
#include "DBusLog.hpp"
#include "DBusEvent.hpp"
#include "DBusDispatcher.hpp"
#include "NetworkManagerInterfaces.hpp"
#include "ss.hpp"
#include "WifiConfigSettings.hpp"
#include "ServiceConfiguration.hpp"
#include <unordered_set>
#include <mutex>
using namespace pipedal;
using namespace dbus::networkmanager;
namespace pipedal::impl
{
constexpr std::string PIPEDAL_HOTSPOT_NAME = "PiPedal Hotspot";
class HotspotManagerImpl : public HotspotManager
{
public:
using ssid_t = WifiConfigSettings::ssid_t;
HotspotManagerImpl();
virtual ~HotspotManagerImpl() noexcept;
virtual void Open() override;
virtual void Reload() override;
virtual void Close() override;
virtual PostHandle Post(PostCallback&&fn) override;
virtual PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn) override;
virtual bool CancelPost(PostHandle handle) override;
virtual void SetNetworkChangingListener(NetworkChangingListener &&listener) override;
private:
enum class State
{
Initial,
WaitingForNetworkManager,
Disabled,
Monitoring,
HotspotConnecting,
HotspotConnected,
Error,
Closed
};
void SetState(State state);
State state = State::Initial;
void onClose();
void onError(const std::string &message);
void onInitialize();
void onDevicesChanged();
void onDisconnect();
void onReload();
void onDisableHotspot();
void DisableHotspot();
void EnableHotspot();
void StartHotspot();
void StopHotspot();
void onStartMonitoring();
void onAccessPointChanged();
void onAccessPointsChanged();
void CancelAccessPointsChangedTimer();
void WaitForNetworkManager();
void StartWaitForNetworkManagerTimer();
void CancelWaitForNetworkManagerTimer();
void UpdateNetworkManagerStatus();
void CancelDeviceChangedTimer();
void ReleaseNetworkManager();
void OnEthernetStateChanged(uint32_t state);
void OnWlanStateChanged(uint32_t state);
std::vector<ssid_t> GetAutoConnectSsids();
std::vector<ssid_t> GetKnownVisibleAccessPoints();
void FireNetworkChanging();
void MaybeStartHotspot();
void StartScanTimer();
void StopScanTimer();
void ScanNow();
Connection::ptr FindExistingConnection();
Device::ptr GetDevice(uint32_t nmDeviceType);
std::atomic<bool> closed;
DBusDispatcher dbusDispatcher;
std::unique_ptr<std::thread> thread;
void ThreadProc();
WifiConfigSettings wifiConfigSettings;
NetworkManager::ptr networkManager;
Device::ptr ethernetDevice;
Device::ptr wlanDevice;
DeviceWireless::ptr wlanWirelessDevice;
ActiveConnection::ptr activeConnection;
std::recursive_mutex networkChangingListenerMutex;
NetworkChangingListener networkChangingListener;
bool ethernetConnected = true;
bool wlanConnected = true;
bool isAutoWlanConnectionVisible = true;
DBusEventHandle onDeviceAddedHandle = INVALID_DBUS_EVENT_HANDLE;
DBusEventHandle onDeviceRemovedHandle = INVALID_DBUS_EVENT_HANDLE;
DBusDispatcher::PostHandle devicesChangedTimerHandle = 0;
DBusDispatcher::PostHandle networkManagerTimerHandle = 0;
DBusDispatcher::PostHandle accessPointsChangedTimerHandle = 0;
DBusDispatcher::PostHandle scanTimerHandle = 0;
};
}
using namespace pipedal::impl;
HotspotManagerImpl::HotspotManagerImpl()
{
SetDBusLogLevel(DBusLogLevel::None);
}
void HotspotManagerImpl::Open()
{
dbusDispatcher.Run();
dbusDispatcher.Post(
[this]()
{
UpdateNetworkManagerStatus(); // waits for valid network manager state, and calls onInitialize when ready.
});
}
void HotspotManagerImpl::onClose()
{
onDisableHotspot();
ReleaseNetworkManager();
Lv2Log::debug("HotspotManager: state=Closed");
SetState(State::Closed);
}
void HotspotManagerImpl::onError(const std::string &message)
{
Lv2Log::error(message);
ReleaseNetworkManager();
Lv2Log::debug("HotspotManager: state=Error");
SetState(State::Error);
}
void HotspotManagerImpl::SetState(State state)
{
this->state = state;
}
void HotspotManagerImpl::onInitialize()
{
if (closed)
return;
if (state != State::Initial && state != State::WaitingForNetworkManager)
{
onError("Invalid state (onInitialize).");
return;
}
try
{
wifiConfigSettings.Load();
if (wifiConfigSettings.valid_ && wifiConfigSettings.enable_)
{
onStartMonitoring();
}
else
{
onDisableHotspot();
}
}
catch (const std::exception &e)
{
onError(SS("HotspotManager: " << e.what()));
}
}
void HotspotManagerImpl::onDisconnect()
{
if (state != State::Initial && state != State::WaitingForNetworkManager)
{
WaitForNetworkManager();
}
}
void HotspotManagerImpl::UpdateNetworkManagerStatus()
{
try
{
if (!networkManager)
{
networkManager = NetworkManager::Create(dbusDispatcher);
}
// turn on wifi if required.
auto ethernetDevice = GetDevice(NM_DEVICE_TYPE_ETHERNET);
auto wlanDevice = GetDevice(NM_DEVICE_TYPE_WIFI);
if (ethernetDevice && wlanDevice)
{
if (state == State::Initial || state == State::WaitingForNetworkManager)
{
CancelWaitForNetworkManagerTimer();
this->onInitialize();
}
return;
}
// check to see whether we have BOTH an eth0 device and a wlan0 device.
}
catch (const std::exception &e)
{
}
if (state != State::WaitingForNetworkManager)
{
this->WaitForNetworkManager();
}
else
{
this->StartWaitForNetworkManagerTimer();
}
}
void HotspotManagerImpl::CancelDeviceChangedTimer()
{
if (devicesChangedTimerHandle)
{
dbusDispatcher.CancelPost(devicesChangedTimerHandle);
devicesChangedTimerHandle = 0;
}
}
void HotspotManagerImpl::ReleaseNetworkManager()
{
StopScanTimer();
CancelAccessPointsChangedTimer();
CancelWaitForNetworkManagerTimer();
CancelDeviceChangedTimer();
DisableHotspot();
ethernetDevice = nullptr;
wlanDevice = nullptr;
wlanWirelessDevice = nullptr;
networkManager = nullptr;
this->onDeviceRemovedHandle = INVALID_DBUS_EVENT_HANDLE;
this->onDeviceAddedHandle = INVALID_DBUS_EVENT_HANDLE;
}
void HotspotManagerImpl::onDevicesChanged()
{
UpdateNetworkManagerStatus();
}
Device::ptr HotspotManagerImpl::GetDevice(uint32_t nmDeviceType)
{
const auto &allDevices = networkManager->GetAllDevices();
for (const auto &devicePath : allDevices)
{
auto device = Device::Create(dbusDispatcher, devicePath);
if (device->DeviceType() == nmDeviceType)
{
return device;
}
}
return nullptr;
}
void HotspotManagerImpl::OnEthernetStateChanged(uint32_t state)
{
bool newValue = (state == 100);
if (newValue != this->ethernetConnected)
{
this->ethernetConnected = newValue;
Lv2Log::debug(SS("HotspotMonitor: ethernetConnected=" << ethernetConnected));
FireNetworkChanging();
MaybeStartHotspot();
}
}
void HotspotManagerImpl::OnWlanStateChanged(uint32_t state)
{
this->wlanConnected = (state == 100);
Lv2Log::debug(SS("HotspotMonitor: OnWlanStateChanged"));
MaybeStartHotspot();
}
void HotspotManagerImpl::onStartMonitoring()
{
try
{
ReleaseNetworkManager();
this->networkManager = NetworkManager::Create(dbusDispatcher);
if (!networkManager->WirelessEnabled())
{
networkManager->WirelessEnabled(true);
}
this->onDeviceAddedHandle = this->networkManager->OnDeviceAdded.add(
[this](const sdbus::ObjectPath &)
{
onDevicesChanged();
});
this->onDeviceRemovedHandle = this->networkManager->OnDeviceRemoved.add(
[this](const sdbus::ObjectPath &objectPath)
{
if (this->ethernetDevice && this->ethernetDevice->getObjectPath() == objectPath)
{
onDisconnect();
}
else if (this->wlanDevice && this->wlanDevice->getObjectPath() == objectPath)
{
onDisconnect();
}
});
ethernetDevice = GetDevice(NM_DEVICE_TYPE_ETHERNET);
if (!ethernetDevice)
{
throw std::runtime_error("eth0 device not found.");
}
this->ethernetDevice->OnStateChanged.add(
[this](uint32_t, uint32_t, uint32_t)
{
OnEthernetStateChanged(ethernetDevice->State());
});
wlanDevice = GetDevice(NM_DEVICE_TYPE_WIFI);
if (!wlanDevice)
{
throw std::runtime_error("wlan0 device not found.");
}
wlanWirelessDevice = DeviceWireless::Create(dbusDispatcher, wlanDevice->getObjectPath());
wlanWirelessDevice->OnAccessPointAdded.add(
[this](const sdbus::ObjectPath &accessPoint)
{
onAccessPointChanged();
});
wlanWirelessDevice->OnAccessPointRemoved.add(
[this](const sdbus::ObjectPath &accessPoint)
{
onAccessPointChanged();
});
this->wlanDevice->OnStateChanged.add(
[this](uint32_t, uint32_t, uint32_t)
{
OnWlanStateChanged(ethernetDevice->State());
});
Lv2Log::debug("HotspotManager: state=Monitoring");
SetState(State::Monitoring);
Lv2Log::info("HotspotManager: Monitoring network status.");
OnEthernetStateChanged(ethernetDevice->State());
OnWlanStateChanged(wlanDevice->State());
StartScanTimer();
onAccessPointChanged();
}
catch (const std::exception &e)
{
Lv2Log::error(SS("HotspotManager: " << e.what()));
WaitForNetworkManager();
}
}
void HotspotManagerImpl::StartWaitForNetworkManagerTimer()
{
CancelWaitForNetworkManagerTimer();
networkManagerTimerHandle = dbusDispatcher.PostDelayed(
std::chrono::seconds(5),
[this]()
{
networkManagerTimerHandle = 0;
this->UpdateNetworkManagerStatus();
});
}
void HotspotManagerImpl::CancelWaitForNetworkManagerTimer()
{
if (networkManagerTimerHandle)
{
dbusDispatcher.CancelPost(networkManagerTimerHandle);
networkManagerTimerHandle = 0;
}
}
void HotspotManagerImpl::WaitForNetworkManager()
{
Lv2Log::debug("HotspotManager: state=WaitingForNetworkManager");
SetState(State::WaitingForNetworkManager);
ReleaseNetworkManager();
StartWaitForNetworkManagerTimer();
}
void HotspotManagerImpl::onDisableHotspot()
{
if (this->state != State::Disabled)
{
ReleaseNetworkManager();
Lv2Log::debug("HotspotManager: state=Disabled");
SetState(State::Disabled);
Lv2Log::info("HotspotManager: Hotspot disabled.");
}
}
void HotspotManagerImpl::onReload()
{
if (closed)
return;
WifiConfigSettings oldSettings = this->wifiConfigSettings;
;
wifiConfigSettings.Load();
switch (state)
{
case State::Initial:
// ignore.
return;
case State::Disabled:
if (wifiConfigSettings.valid_ && wifiConfigSettings.enable_)
{
onStartMonitoring();
}
return;
default:
this->onDisableHotspot();
break;
}
}
HotspotManagerImpl::~HotspotManagerImpl()
{
Close();
}
void HotspotManagerImpl::ThreadProc()
{
try
{
}
catch (const std::exception &e)
{
Lv2Log::error(SS("Hotspot Manager thread terminated. " << e.what()));
}
}
void HotspotManagerImpl::Reload()
{
dbusDispatcher.Post([this]()
{ onReload(); });
}
void HotspotManagerImpl::Close()
{
if (!closed)
{
closed = true;
dbusDispatcher.Post([this]
{ onClose(); });
dbusDispatcher.Stop();
}
}
HotspotManager::ptr HotspotManager::Create()
{
return std::make_unique<HotspotManagerImpl>();
}
template <typename T>
class VectorHash
{
public:
std::size_t operator()(const std::vector<T> &vec) const
{
std::size_t hash = vec.size();
for (auto &i : vec)
{
hash += static_cast<size_t>(i);
hash = ((hash >> 32) ^ hash) * 0x119de1F3;
}
return hash;
}
};
static std::string ssidToString(const std::vector<uint8_t> &ssid)
{
std::stringstream s;
for (auto v: ssid)
{
if (v == 0) break; // breaks for some arguably legal ssids, but I can live with that.
s << (char)v;
}
return s.str();
}
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetKnownVisibleAccessPoints()
{
std::vector<std::vector<uint8_t>> knownSsids = this->GetAutoConnectSsids();
std::unordered_set<std::vector<uint8_t>, VectorHash<uint8_t>> index{knownSsids.begin(), knownSsids.end()};
std::vector<ssid_t> result;
for (const auto &accessPointPath : wlanWirelessDevice->AccessPoints())
{
auto accessPoint = AccessPoint::Create(dbusDispatcher, accessPointPath);
auto ssid = accessPoint->Ssid();
if (index.contains(ssid))
{
result.push_back(ssid);
}
}
return result;
}
std::vector<std::vector<uint8_t>> HotspotManagerImpl::GetAutoConnectSsids()
{
auto availableConnections = wlanDevice->AvailableConnections();
std::vector<std::vector<uint8_t>> ssids;
for (const auto &connectionPath : availableConnections)
{
auto connection = Connection::Create(dbusDispatcher, connectionPath);
try
{
auto settings = connection->GetSettings();
bool autoConnect = true;
if (settings["connect"].count("autoconnect") > 0)
{
autoConnect = settings["connect"]["autoconnect"];
}
bool isInfrastructure =
settings["802-11-wireless"].count("mode") > 0 && settings["802-11-wireless"]["mode"].get<std::string>() == "infrastructure";
if (isInfrastructure && autoConnect)
{
std::vector<uint8_t> ssid =
settings["802-11-wireless"]["ssid"];
ssids.push_back(std::move(ssid));
}
}
catch (const std::exception &ignored)
{
// not totally sure of structure of all connection types.
}
}
return ssids;
}
void HotspotManagerImpl::onAccessPointsChanged()
{
MaybeStartHotspot();
}
void HotspotManagerImpl::CancelAccessPointsChangedTimer()
{
if (accessPointsChangedTimerHandle)
{
dbusDispatcher.CancelPost(accessPointsChangedTimerHandle);
accessPointsChangedTimerHandle = 0;
}
}
void HotspotManagerImpl::onAccessPointChanged()
{
// coalesce large bursts of AccessPointChanged calls using a timer.
if (!accessPointsChangedTimerHandle)
{
accessPointsChangedTimerHandle = dbusDispatcher.PostDelayed(
std::chrono::milliseconds(512),
[this]()
{
accessPointsChangedTimerHandle = 0;
onAccessPointsChanged(); // coalesced handling of one or more changes.
});
}
}
void HotspotManagerImpl::MaybeStartHotspot()
{
std::vector<std::vector<uint8_t>> connectableSsids = GetKnownVisibleAccessPoints(); // all the ssids currently visible for which we have credentials.
bool wantsHotspot = this->wifiConfigSettings.WantsHotspot(
this->ethernetConnected,connectableSsids);
this->isAutoWlanConnectionVisible = connectableSsids.size() != 0;
if (this->state == State::Monitoring && wantsHotspot)
{
StartHotspot();
}
else
{
if ((!wantsHotspot) && (this->state == State::HotspotConnected || this->state == State::HotspotConnecting))
{
StopHotspot();
}
}
}
void HotspotManagerImpl::EnableHotspot()
{
}
void HotspotManagerImpl::DisableHotspot()
{
StopHotspot();
}
Connection::ptr HotspotManagerImpl::FindExistingConnection()
{
if (wlanDevice)
{
for (const auto &connectionPath : wlanDevice->AvailableConnections())
{
auto connection = Connection::Create(dbusDispatcher, connectionPath);
auto settings = connection->GetSettings();
bool isHotspot =
settings["802-11-wireless"].count("mode") > 0 && settings["802-11-wireless"]["mode"].get<std::string>() == "ap";
if (isHotspot)
{
std::string id;
if (settings["connection"].count("id") > 0)
{
id = settings["connection"]["id"].get<std::string>();
}
if (id.starts_with(PIPEDAL_HOTSPOT_NAME))
{
return connection;
}
}
}
}
return nullptr;
}
void HotspotManagerImpl::StartHotspot()
{
if (this->state == State::Monitoring)
{
try
{
ServiceConfiguration serviceConfiguration;
serviceConfiguration.Load();
Lv2Log::debug("HotspotManager: state=HotspotConnecting");
SetState(State::HotspotConnecting);
Lv2Log::info("HotspotManager: Enabling PiPedal hotspot.");
// do it ONLY if we're in monitoring state.
// Create a proxy for NetworkManager
// Create connection settings for the hotspot
std::map<std::string, std::map<std::string, sdbus::Variant>> settings;
std::map<std::string, sdbus::Variant> &connection = settings["connection"];
connection["type"] = "802-11-wireless";
connection["autoconnect"] = false;
connection["id"] = PIPEDAL_HOTSPOT_NAME;
connection["interface-name"] = wlanDevice->Interface();
connection["uuid"] = serviceConfiguration.uuid;
std::map<std::string, sdbus::Variant> &wireless = settings["802-11-wireless"];
std::string ssid = this->wifiConfigSettings.hotspotName_;
std::vector<uint8_t> vSsid{ssid.begin(), ssid.end()};
wireless["ssid"] = vSsid;
wireless["mode"] = "ap";
wireless["band"] = "a";
wireless["band"] = "bg";
uint32_t iChannel;
auto channel = this->wifiConfigSettings.channel_;
if (channel.length() != 0)
{
std::stringstream ss{channel};
ss >> iChannel;
}
if (iChannel != 0)
{
wireless["channel"] = iChannel;
}
std::map<std::string, sdbus::Variant> &wirelessSecurity = settings["802-11-wireless-security"];
wirelessSecurity["key-mgmt"] = "wpa-psk";
wirelessSecurity["psk"] = wifiConfigSettings.password_;
settings["ipv4"]["method"] = "shared";
settings["ipv6"]["method"] = "shared";
// settings["ipv6"]["addr-gen-mode"] = "stable-privacy";
std::map<std::string, sdbus::Variant> options;
options["persist"] = "disk";
Connection::ptr existingConnection = FindExistingConnection();
if (existingConnection)
{
existingConnection->Update(settings);
auto activeConnectionPath = networkManager->ActivateConnection(
existingConnection->getObjectPath(),
wlanDevice->getObjectPath(),
"/");
this->activeConnection = ActiveConnection::Create(dbusDispatcher, activeConnectionPath);
}
else
{
// Call AddAndActivateConnection2 method to create and activate the hotspot
sdbus::ObjectPath nullPath("/");
auto result = networkManager->AddAndActivateConnection2(
settings, wlanDevice->getObjectPath(), "/", options
);
auto connectionPath = std::get<0>(result);
auto activeConnectionPath = std::get<1>(result);
// auto resultArgs = std::get<2>(result);
this->activeConnection = ActiveConnection::Create(dbusDispatcher, activeConnectionPath);
}
SetState(State::HotspotConnected);
Lv2Log::info("HotspotManager: Hotspot activated.");
FireNetworkChanging();
}
catch (const std::exception &e)
{
onError(SS("HotspotManager: Activation failed: " << e.what()));
}
}
else
{
onError("HotspotManager: Illegal state (StartHotspot)");
}
}
void HotspotManagerImpl::StopHotspot()
{
// do it regardless of state.
try
{
if (activeConnection)
{
networkManager->DeactivateConnection(activeConnection->getObjectPath());
activeConnection = nullptr;
FireNetworkChanging();
}
}
catch (const std::exception &e)
{
Lv2Log::error("HotspotManager: Failed to deactivate hotspot.");
activeConnection = nullptr;
}
if (this->state == State::HotspotConnected || this->state == State::HotspotConnecting)
{
Lv2Log::info("HotspotManager: state=HotspotMonitoring");
SetState(State::Monitoring);
Lv2Log::info("HotspotManager: PiPedal hotspot disabled.");
}
}
static const std::chrono::seconds scanInterval { 60};
void HotspotManagerImpl::StartScanTimer()
{
StopScanTimer();
ScanNow();
}
void HotspotManagerImpl::StopScanTimer()
{
if (this->scanTimerHandle) {
dbusDispatcher.CancelPost(this->scanTimerHandle);
this->scanTimerHandle = 0;
}
}
void HotspotManagerImpl::ScanNow()
{
this->scanTimerHandle = 0;
if (wlanWirelessDevice) {
std::map<std::string, sdbus::Variant> options;
try {
Lv2Log::debug("Scanning");
wlanWirelessDevice->RequestScan(options);
} catch (const std::exception &e)
{
Lv2Log::error(SS("HotspotMonitor: Wi-Fi RequestScan failed." << e.what()));
return;
}
this->scanTimerHandle = this->dbusDispatcher.PostDelayed(
std::chrono::duration_cast<std::chrono::steady_clock::duration>(scanInterval),
[this]() {
ScanNow();
}
);
}
}
HotspotManagerImpl::PostHandle HotspotManagerImpl::Post(PostCallback&&fn)
{
return dbusDispatcher.Post(std::move(fn));
}
HotspotManagerImpl::PostHandle HotspotManagerImpl::PostDelayed(const clock::duration&delay,PostCallback&&fn)
{
return dbusDispatcher.PostDelayed(delay,std::move(fn));
}
bool HotspotManagerImpl::CancelPost(PostHandle handle) {
return dbusDispatcher.CancelPost(handle);
}
void HotspotManagerImpl::SetNetworkChangingListener(NetworkChangingListener &&listener)
{
std::lock_guard<std::recursive_mutex> lock { this->networkChangingListenerMutex};
this->networkChangingListener = std::move(listener);
}
void HotspotManagerImpl::FireNetworkChanging() {
std::lock_guard<std::recursive_mutex> lock { this->networkChangingListenerMutex};
if (this->networkChangingListener)
{
this->networkChangingListener(this->ethernetConnected,!!activeConnection);
}
}
+74
View File
@@ -0,0 +1,74 @@
// 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 <memory>
#include <functional>
#include <chrono>
namespace pipedal {
class HotspotManager {
// no move, no delete.
HotspotManager(const HotspotManager&) = delete;
HotspotManager(HotspotManager&&) = delete;
HotspotManager & operator=(const HotspotManager&) = delete;
HotspotManager & operator=(const HotspotManager&&) = delete;
protected:
HotspotManager() {} // use Create().
public:
using clock = std::chrono::steady_clock;
using ptr = std::unique_ptr<HotspotManager>;
static ptr Create();
virtual ~HotspotManager() noexcept { }
virtual void Open() = 0;
virtual void Reload() = 0;
virtual void Close() = 0;
using NetworkChangingListener = std::function<void(bool ethernetConnected,bool hotspotEnabled)>;
virtual void SetNetworkChangingListener(NetworkChangingListener &&listener) = 0;
using PostHandle = uint64_t;
using PostCallback = std::function<void()>;
virtual PostHandle Post(PostCallback&&fn) = 0;
virtual PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn) = 0;
virtual bool CancelPost(PostHandle handle) = 0;
template<class REP,class PERIOD>
PostHandle PostDelayed(const std::chrono::duration<REP,PERIOD>&delay,PostCallback&&fn)
{
return PostDelayed(
std::chrono::duration_cast<clock::duration,REP,PERIOD>(delay),
std::move(fn));
}
};
}
+84 -4
View File
@@ -35,6 +35,8 @@
#include "PiPedalUI.hpp"
#include "atom_object.hpp"
#include "Lv2PluginChangeMonitor.hpp"
#include "HotspotManager.hpp"
#include "DBusToLv2Log.hpp"
#ifndef NO_MLOCK
#include <sys/mman.h>
@@ -79,6 +81,17 @@ PiPedalModel::PiPedalModel()
{
this->OnUpdateStatusChanged(updateStatus);
});
DbusLogToLv2Log();
hotspotManager = HotspotManager::Create();
hotspotManager->SetNetworkChangingListener(
[this](bool ethernetConnected, bool hotspotEnabling) {
OnNetworkChanging(ethernetConnected,hotspotEnabling);
}
);
hotspotManager->Open();
}
void PiPedalModel::Close()
@@ -106,7 +119,10 @@ void PiPedalModel::Close()
PiPedalModel::~PiPedalModel()
{
pluginChangeMonitor = nullptr;
CancelNetworkChangingTimer();
hotspotManager = nullptr; // turn off the hotspot.
pluginChangeMonitor = nullptr; // stop monitorin LV2 directories.
try
{
adminClient.UnmonitorGovernor();
@@ -952,11 +968,23 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
{
std::lock_guard<std::recursive_mutex> lock(mutex);
adminClient.SetWifiConfig(wifiConfigSettings);
#if NEW_WIFI_CONFIG
if (this->storage.SetWifiConfigSettings(wifiConfigSettings))
{
if (this->hotspotManager)
{
this->hotspotManager->Reload();
}
}
#else
this->storage.SetWifiConfigSettings(wifiConfigSettings);
adminClient.SetWifiConfig(wifiConfigSettings);
#endif
{
// yyy: review locking semantics here. This is wrong. Convert to shared pointers?
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
for (size_t i = 0; i < subscribers.size(); ++i)
{
@@ -964,11 +992,11 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
}
size_t n = this->subscribers.size();
WifiConfigSettings tWifiConfigSettings = storage.GetWifiConfigSettings(); // (the passwordless version)
WifiConfigSettings settingsWithNoSecrets = storage.GetWifiConfigSettings(); // (the passwordless version)
for (size_t i = 0; i < n; ++i)
{
t[i]->OnWifiConfigSettingsChanged(tWifiConfigSettings);
t[i]->OnWifiConfigSettingsChanged(settingsWithNoSecrets);
}
delete[] t;
}
@@ -2259,3 +2287,55 @@ void PiPedalModel::WaitForAudioDeviceToComeOnline()
// pre-cache device info before we let audio services run.
GetAlsaDevices();
}
PiPedalModel::PostHandle PiPedalModel::Post(PostCallback&&fn)
{
// I know. odd place to forward this to, but it's a very serviceable dispatcher implementation.
// Why? because it's there, and PiPedalModel has no thread of its own to do dispatching.
if (!hotspotManager)
{
throw std::runtime_error("Too early. It's not ready yet.");
}
return hotspotManager->Post(std::move(fn));
}
PiPedalModel::PostHandle PiPedalModel::PostDelayed(const clock::duration&delay,PostCallback&&fn)
{
if (!hotspotManager)
{
throw std::runtime_error("Too early. It's not ready yet.");
}
return hotspotManager->PostDelayed(delay,std::move(fn));
}
bool PiPedalModel::CancelPost(PostHandle handle) {
if (!hotspotManager)
{
throw std::runtime_error("Too early. It's not ready yet.");
}
return hotspotManager->CancelPost(handle);
}
void PiPedalModel::CancelNetworkChangingTimer()
{
if (networkChangingDelayHandle)
{
CancelPost(networkChangingDelayHandle);
networkChangingDelayHandle = 0;
}
}
void PiPedalModel::OnNetworkChanging(bool ethernetConnected,bool hotspotConnected)
{
CancelNetworkChangingTimer();
this->networkChangingDelayHandle =
PostDelayed(std::chrono::seconds(5),
[this,ethernetConnected,hotspotConnected]() {
this->networkChangingDelayHandle = 0;
OnNetworkChanged(ethernetConnected,hotspotConnected);
}
);
}
void PiPedalModel::OnNetworkChanged(bool ethernetConnected, bool hotspotConnected)
{
FireNetworkChanged();
}
+42
View File
@@ -84,9 +84,20 @@ namespace pipedal
virtual void Close() = 0;
};
class HotspotManager;
class PiPedalModel : private IAudioHostCallbacks
{
public:
using clock = std::chrono::steady_clock;
using PostHandle = uint64_t;
using PostCallback = std::function<void()>;
using NetworkChangedListener = std::function<void(void)>;
private:
std::unique_ptr<HotspotManager> hotspotManager;
UpdateStatus currentUpdateStatus;
Updater updater;
@@ -140,6 +151,14 @@ namespace pipedal
Storage storage;
bool hasPresetChanged = false;
NetworkChangedListener networkChangedListener;
void FireNetworkChanged() {
if (networkChangedListener)
{
networkChangedListener();
}
}
std::unique_ptr<AudioHost> audioHost;
JackConfiguration jackConfiguration;
std::shared_ptr<Lv2Pedalboard> lv2Pedalboard;
@@ -193,6 +212,11 @@ namespace pipedal
virtual void OnNotifyNextMidiProgram(const RealtimeNextMidiProgramRequest&request) override;
virtual void OnNotifyLv2RealtimeError(int64_t instanceId,const std::string &error) override;
PostHandle networkChangingDelayHandle = 0;
void CancelNetworkChangingTimer();
void OnNetworkChanging(bool ethernetConnected,bool hotspotConnected);
void OnNetworkChanged(bool ethernetConnected, bool hotspotConnected);
void UpdateVst3Settings(Pedalboard &pedalboard);
@@ -203,6 +227,24 @@ namespace pipedal
PiPedalModel();
virtual ~PiPedalModel();
virtual PostHandle Post(PostCallback&&fn);
virtual PostHandle PostDelayed(const clock::duration&delay,PostCallback&&fn);
virtual bool CancelPost(PostHandle handle);
template<class REP,class PERIOD>
PostHandle PostDelayed(const std::chrono::duration<REP,PERIOD>&delay,PostCallback&&fn)
{
return PostDelayed(
std::chrono::duration_cast<clock::duration,REP,PERIOD>(delay),
std::move(fn));
}
void SetNetworkChangedListener(NetworkChangedListener listener) {
networkChangedListener = listener;
}
void WaitForAudioDeviceToComeOnline();
UpdateStatus GetUpdateStatus();
+51 -6
View File
@@ -76,16 +76,19 @@ bool pipedal::UsingNetworkManager()
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) | std::filesystem::exists(NETWORK_MANAGER_DNSMASQ_P2P_PATH);
}
static bool IsApdInstalled()
{
return std::filesystem::exists(DNSMASQ_APD_PATH);
}
#if !NEW_WIFI_CONFIG
static void restoreApdDhcpdConfFile()
{
// remove the interface wlan0 section.
@@ -123,6 +126,7 @@ static void restoreApdDhcpdConfFile()
dhcpcd.Save(dhcpcdConfig);
}
}
#endif
static void restoreP2pDhcpdConfFile()
{
@@ -170,6 +174,7 @@ static void restoreP2pDhcpdConfFile()
}
}
#if !NEW_WIFI_CONFIG
static void restoreApdDnsmasqConfFile()
{
std::filesystem::path path(DNSMASQ_APD_PATH);
@@ -178,6 +183,7 @@ static void restoreApdDnsmasqConfFile()
std::filesystem::remove(path);
}
}
#endif
static void restoreP2pDnsmasqConfFile()
{
{
@@ -196,6 +202,7 @@ static void restoreP2pDnsmasqConfFile()
}
}
#if !NEW_WIFI_CONFIG
static void UninstallHostApd()
{
if (IsApdInstalled())
@@ -213,6 +220,7 @@ static void UninstallHostApd()
sysExec(SYSTEMCTL_BIN " start wpa_supplicant");
}
}
#endif
static void InstallP2p(const WifiDirectConfigSettings &settings)
{
@@ -299,7 +307,8 @@ static void InstallP2p(const WifiDirectConfigSettings &settings)
static void UninstallP2p();
void pipedal::SetWifiConfig(const WifiConfigSettings &settings)
#if !NEW_WIFI_CONFIG
static void SetHostapdWifiConfig(const WifiConfigSettings &settings)
{
char band;
if (!settings.enable_)
@@ -476,6 +485,25 @@ void pipedal::SetWifiConfig(const WifiConfigSettings &settings)
}
::sync();
}
#endif
#if NEW_WIFI_CONFIG
static void SetNetworkManagerWifiConfig(WifiConfigSettings &settings)
{
settings.Save();
}
#endif
void pipedal::SetWifiConfig(WifiConfigSettings &settings)
{
#if NEW_WIFI_CONFIG
SetNetworkManagerWifiConfig(settings);
#else
SetHostapdWifiConfig(const WifiConfigSettings &settings);
#endif
}
/*********************************************************************************
@@ -686,6 +714,7 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
::sync();
}
void pipedal::OnWifiReinstall() {
#if ENABLE_WIFI_P2P // Do not enable P2P going forward.
WifiDirectConfigSettings settings;
settings.Load();
if (settings.enable_)
@@ -693,14 +722,30 @@ void pipedal::OnWifiReinstall() {
SetWifiDirectConfig(settings);
::sync();
}
#endif
#if NEW_WIFI_CONFIG
{
// no action required.
// pipedald will pick up the old settings at runtime.
}
#endif
}
void pipedal::OnWifiUninstall(bool preserveState)
{
// intaller hook
#if NEW_WIFI_CONFIG
{
// no action required.
// shutting down pipedald is sufficient.
}
#else
if (IsApdInstalled())
{
UninstallHostApd();
}
#endif
if (IsP2pInstalled())
{
WifiDirectConfigSettings settings;
+2 -1
View File
@@ -21,12 +21,13 @@
#include "WifiConfigSettings.hpp"
#include "WifiDirectConfigSettings.hpp"
namespace pipedal {
void SetWifiConfigWLanAddress(const std::string&wLanAddress);
const std::string &GetWifiConfigWlanAddress();
void SetWifiConfig(const WifiConfigSettings&settings);
void SetWifiConfig(WifiConfigSettings&settings);
void SetWifiDirectConfig(const WifiDirectConfigSettings&settings);
void OnWifiUninstall(bool preserveState = false);
+18 -56
View File
@@ -38,7 +38,6 @@ using namespace pipedal;
const char *BANK_EXTENSION = ".bank";
const char *BANKS_FILENAME = "index.banks";
#define WIFI_CONFIG_SETTINGS_FILENAME "wifiConfigSettings.json";
#define USER_SETTINGS_FILENAME "userSettings.json";
Storage::Storage()
@@ -953,43 +952,22 @@ std::string Storage::GetGovernorSettings() const
return this->userSettings.governor_;
}
void Storage::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
bool Storage::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
{
WifiConfigSettings copyToSave = wifiConfigSettings;
copyToSave.rebootRequired_ = false;
if (!copyToSave.enable_)
WifiConfigSettings previousValue;
previousValue.Load();
if (!copyToSave.hasPassword_)
{
copyToSave.hasPassword_ = false;
copyToSave.hasPassword_ = previousValue.hasPassword_;
copyToSave.password_ = previousValue.hasPassword_;
}
copyToSave.password_ = "";
std::filesystem::path path = this->dataRoot / WIFI_CONFIG_SETTINGS_FILENAME;
{
pipedal::ofstream_synced f(path);
if (!f.is_open())
{
throw PiPedalException("Unable to write to " + ((std::string)path));
}
json_writer writer(f, false);
writer.write(&copyToSave);
}
WifiConfigSettings copyToStore = wifiConfigSettings;
if (copyToStore.enable_)
{
copyToStore.hasPassword_ = copyToStore.password_.length() != 0 || this->wifiConfigSettings.hasPassword_;
}
else
{
copyToStore.hasPassword_ = false;
}
copyToStore.password_ = "";
copyToStore.rebootRequired_ = false;
if (copyToStore.enable_ && !copyToStore.hasPassword_)
{
copyToStore.hasPassword_ = this->wifiConfigSettings.hasPassword_;
}
this->wifiConfigSettings = copyToStore;
bool configChanged = wifiConfigSettings.ConfigurationChanged(previousValue);
copyToSave.Save();
this->wifiConfigSettings = copyToSave;
this->wifiConfigSettings.hasPassword_ = false;
this->wifiConfigSettings.password_ = "";
return configChanged;
}
void Storage::SetWifiDirectConfigSettings(const WifiDirectConfigSettings &wifiDirectConfigSettings)
@@ -1030,27 +1008,8 @@ void Storage::LoadUserSettings()
}
void Storage::LoadWifiConfigSettings()
{
std::filesystem::path path = this->dataRoot / WIFI_CONFIG_SETTINGS_FILENAME;
try
{
if (std::filesystem::is_regular_file(path))
{
std::ifstream f(path);
if (!f.is_open())
{
throw PiPedalException("Unable to write to " + ((std::string)path));
}
json_reader reader(f);
WifiConfigSettings wifiConfigSettings;
reader.read(&wifiConfigSettings);
this->wifiConfigSettings = wifiConfigSettings;
}
}
catch (const std::exception &)
{
}
this->wifiConfigSettings.valid_ = true;
this->wifiConfigSettings.Load();
this->wifiConfigSettings.valid_ = this->wifiConfigSettings.hasPassword_ && !this->wifiConfigSettings.countryCode_.empty();
}
void Storage::LoadWifiDirectConfigSettings()
{
@@ -1065,7 +1024,10 @@ void Storage::LoadWifiDirectConfigSettings()
WifiConfigSettings Storage::GetWifiConfigSettings()
{
return this->wifiConfigSettings;
WifiConfigSettings result = this->wifiConfigSettings;
result.hasPassword_ = false;
result.password_ = "";
return result;
}
WifiDirectConfigSettings Storage::GetWifiDirectConfigSettings()
{
+2 -1
View File
@@ -158,7 +158,8 @@ public:
void SetJackChannelSelection(const JackChannelSelection&channelSelection);
const JackChannelSelection&GetJackChannelSelection(const JackConfiguration &jackConfiguration);
void SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings);
// returns true if services needs to be updated.
bool SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings);
WifiConfigSettings GetWifiConfigSettings();
void SetWifiDirectConfigSettings(const WifiDirectConfigSettings & wifiDirectConfigSettings);
+45
View File
@@ -23,6 +23,7 @@
#include <fstream>
#include <string>
#include <regex>
#include "ss.hpp"
using namespace pipedal;
using namespace std;
@@ -107,6 +108,7 @@ static inline std::string ValuePart(const std::string &line)
throw PiPedalException("Value not found.");
return line.substr(pos + 1);
}
std::string SystemConfigFile::Get(const std::string &key) const
{
int64_t lineIndex = GetLine(key);
@@ -346,3 +348,46 @@ void SystemConfigFile::AppendLine(const std::string &line)
lines.push_back(line);
}
static const std::string REPLACE_SLUG = "# PiPedal replace:";
static const std::string ADD_SLUG = "# PiPedal add:";
void SystemConfigFile::UndoableReplaceLine(int line,const std::string&text)
{
std::string undoComment = SS(REPLACE_SLUG << lines[line]);
lines[line] = undoComment;
InsertLine(line+1,text);
}
int SystemConfigFile::UndoableAddLine(int line,const std::string&text)
{
std::string undoComment = ADD_SLUG;
InsertLine(line,undoComment);
InsertLine(line+1,text);
return line+2;
}
bool SystemConfigFile::RemoveUndoableActions()
{
bool changed = false;
for (int i = 0; i < GetLineCount(); ++i)
{
if (lines[i].starts_with("# PiPedal"))
{
if (lines[i].starts_with(REPLACE_SLUG))
{
std::string oldText = lines[i].substr(REPLACE_SLUG.length());
lines[i] = oldText;
this->EraseLine(i+1);
changed = true;
} else if (lines[i].starts_with(ADD_SLUG))
{
EraseLine(i);
EraseLine(i);
changed = true;
}
}
}
return changed;
}
+5
View File
@@ -47,6 +47,7 @@ public:
bool HasValue(const std::string&key) const;
bool Get(const std::string&key,std::string*pResult) const;
std::string Get(const std::string&key) const;
const std::string& Get(int position) const { return lines[position]; }
void Set(const std::string&key,const std::string &value);
void Set(const std::string&key,const std::string &value, const std::string&comment);
void SetDefault(const std::string&key, const std::string &value);
@@ -66,6 +67,10 @@ public:
void InsertLine(int position, const std::string&line);
void AppendLine(const std::string&line);
void SetLineValue(int index, const std::string&line) { lines[index] = line; }
void UndoableReplaceLine(int line,const std::string&text);
int UndoableAddLine(int line,const std::string&text);
bool RemoveUndoableActions();
};
};
+29 -21
View File
@@ -1160,23 +1160,7 @@ namespace pipedal
m_endpoint.set_close_handler(bind(&WebServerImpl::on_close, this, _1));
m_endpoint.set_http_handler(bind(&WebServerImpl::on_http, this, _1));
std::string hostName = getHostName();
if (hostName.length() != 0)
{
std::stringstream ss;
ss << "Listening on " << hostName << ".local:" << this->port;
Lv2Log::info(ss.str());
}
std::string ipv4Address = getIpv4Address("eth0");
if (ipv4Address.length() != 0)
{
Lv2Log::info(SS("Listening on " << ipv4Address << ":" << this->port));
}
std::string wifiAddress = getIpv4Address("wlan0");
if (wifiAddress.length() != 0)
{
Lv2Log::info(SS("Listening on Wi-Fi address " << wifiAddress << ":" << this->port));
}
DisplayIpAddresses();
std::stringstream ss;
ss << port;
@@ -1252,11 +1236,12 @@ namespace pipedal
for (auto it = m_connections.begin(); it != m_connections.end(); ++it)
{
try {
m_endpoint.close(*it, websocketpp::close::status::normal, "");
} catch (const std::exception&ignored)
try
{
m_endpoint.close(*it, websocketpp::close::status::normal, "");
}
catch (const std::exception &ignored)
{
}
}
}
@@ -1280,6 +1265,8 @@ namespace pipedal
this->pBgThread = new std::thread(ThreadProc, this);
}
virtual void DisplayIpAddresses() override;
WebServerImpl(const std::string &address, int port, const char *rootPath, int threads, size_t maxUploadSize);
};
} // namespace pipedal
@@ -1314,3 +1301,24 @@ std::shared_ptr<WebServer> pipedal::WebServer::create(
{
return std::shared_ptr<WebServer>(new WebServerImpl(address.to_string(), port, rootPath, threads, maxUploadSize));
}
void WebServerImpl::DisplayIpAddresses()
{
std::string hostName = getHostName();
if (hostName.length() != 0)
{
std::stringstream ss;
ss << "Listening on mDns address " << hostName << ":" << this->port;
Lv2Log::info(ss.str());
}
std::string ipv4Address = getIpv4Address("eth0");
if (ipv4Address.length() != 0)
{
Lv2Log::info(SS("Listening on eth0 address " << ipv4Address << ":" << this->port));
}
std::string wifiAddress = getIpv4Address("wlan0");
if (wifiAddress.length() != 0)
{
Lv2Log::info(SS("Listening on Wi-Fi address " << wifiAddress << ":" << this->port));
}
}
+1
View File
@@ -222,6 +222,7 @@ public:
virtual ~WebServer() { }
virtual void SetLogHttpRequests(bool enableLogging) = 0;
virtual void DisplayIpAddresses() = 0;
virtual void AddRequestHandler(std::shared_ptr<RequestHandler> requestHandler) = 0;
virtual void AddSocketFactory(std::shared_ptr<ISocketFactory> &socketHandler) = 0;
+61
View File
@@ -0,0 +1,61 @@
#include "HotspotManager.hpp"
#include "WifiConfigSettings.hpp"
#include <iostream>
#include "Lv2Log.hpp"
#include "DBusLog.hpp"
using namespace pipedal;
int main(int argc, char**argv)
{
WifiConfigSettings settings;
settings.Load();
if (!settings.valid_ || !settings.hasPassword_)
{
settings.valid_ = true;
settings.channel_ = "1";
settings.hotspotName_ = "pipedal";
settings.password_ = "password";
settings.hasPassword_ = true;
settings.Save();
}
Lv2Log::log_level(LogLevel::Debug);
SetDBusLogLevel(DBusLogLevel::Trace);
HotspotManager::ptr hotspotManager = HotspotManager::Create();
hotspotManager->Open();
while (true)
{
std::string line;
std::cout << "e=enable,x=disable,q=quit > " << std::endl;;
std::getline(std::cin,line);
if (line == "e")
{
settings.Load();
settings.enable_ = true;
settings.Save();
hotspotManager->Reload();
} else if (line == "x")
{
settings.Load();
settings.enable_ = false;
settings.Save();
hotspotManager->Reload();
} else if (line == "q") {
break;
} else {
std::cout << "Invalid command." << std::endl;
}
}
hotspotManager->Close();
hotspotManager = nullptr;
return EXIT_SUCCESS;
}
+9 -1
View File
@@ -117,7 +117,7 @@ int main(int argc, char *argv[])
if (help || parser.Arguments().size() == 0)
{
std::cout << "pipedald - Pipedal web socket server.\n"
"Copyright (c) 2022 Robin Davies.\n"
"Copyright (c) 2022-2024 Robin Davies.\n"
"\n";
}
}
@@ -241,6 +241,14 @@ int main(int argc, char *argv[])
PiPedalModel model;
model.SetNetworkChangedListener(
[&server]() mutable {
if (server)
{
server->DisplayIpAddresses();
}
}
);
model.SetRestartListener(
[]()
@@ -0,0 +1,6 @@
[Adding or changing system-wide NetworkManager connections]
Identity=unix-group:pipedal_d
Action=org.freedesktop.NetworkManager.settings.modify.system
ResultAny=yes
ResultInactive=yes
ResultActive=yes
@@ -0,0 +1,6 @@
// grant NetworkManager dbus permissions (no-prompts) to the pipedald systemd service.
polpolkit.addRule(function(action, subject) {
if (action.id.indexOf("org.freedesktop.NetworkManager.") == 0 && subject.isInGroup("pipedal_d")) {
return polkit.Result.YES;
}
});
+22
View File
@@ -1,3 +1,25 @@
Installer:
sudo systemctl restart polkitd.service
- Scanning.
- verify that scanning doesn't cause overruns.
- UI changes.
- test behaviour when Osgilliad is offline.
- docs changes.
- unicode commandline arguments.
- unicode filenames.
- update configMain.
- address change handlers in client (and browser?)
- Notify hotspotManager on settings changed.
- Midi binding for hotspotManager.
- Keybaord escape for hotspotManager.
- verify stripping in installer.
- verify update with no keyring.
-verify clean removal of dhcpcd and nm_p2p2d
- Back button after reloads on Android.
- pidedal_nm_p2p2 service not started from web ui.
- pipedal_nm_p2pd connection not visible.