Wi-Fi Direct cmdline
This commit is contained in:
Vendored
+94
-2
@@ -5,13 +5,45 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "(gdb) generic",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
// Resolved by CMake Tools:
|
||||
"program": "${command:cmake.launchTargetPath}",
|
||||
"args": [ ],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [
|
||||
{
|
||||
// add the directory where our target was built to the PATHs
|
||||
// it gets resolved by CMake Tools:
|
||||
"name": "PATH",
|
||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
||||
},
|
||||
{
|
||||
"name": "ASAN_OPTIONS",
|
||||
"value": "detect_leaks=0"
|
||||
|
||||
}
|
||||
],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "(gdb) pipedaltest Launch",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
// Resolved by CMake Tools:
|
||||
"program": "${command:cmake.launchTargetPath}",
|
||||
"args": [ "[Dev]" ],
|
||||
"args": [ "[avahi_service]" ],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [
|
||||
@@ -61,6 +93,11 @@
|
||||
"name": "PATH",
|
||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
||||
},
|
||||
{
|
||||
"name": "ASAN_OPTIONS",
|
||||
"value": "detect_leaks=0"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "OTHER_VALUE",
|
||||
"value": "Something something"
|
||||
@@ -98,6 +135,12 @@
|
||||
"name": "PATH",
|
||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
||||
},
|
||||
{
|
||||
"name": "ASAN_OPTIONS",
|
||||
"value": "detect_leaks=0"
|
||||
|
||||
},
|
||||
|
||||
{
|
||||
"name": "OTHER_VALUE",
|
||||
"value": "Something something"
|
||||
@@ -120,7 +163,8 @@
|
||||
// Resolved by CMake Tools:
|
||||
"program": "${command:cmake.launchTargetPath}",
|
||||
"args": [
|
||||
|
||||
"--enable-p2p" , "--nopkexec"
|
||||
//,"CA", "PiPedalTest","12345678","1"
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
@@ -132,6 +176,52 @@
|
||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
||||
},
|
||||
{
|
||||
"name": "ASAN_OPTIONS",
|
||||
"value": "detect_leaks=0"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "OTHER_VALUE",
|
||||
"value": "Something something"
|
||||
}
|
||||
],
|
||||
"externalConsole": false,
|
||||
"MIMode": "gdb",
|
||||
"setupCommands": [
|
||||
{
|
||||
"description": "Enable pretty-printing for gdb",
|
||||
"text": "-enable-pretty-printing",
|
||||
"ignoreFailures": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
"name": "(gdb) pipedal_p2pd",
|
||||
"type": "cppdbg",
|
||||
"request": "launch",
|
||||
// Resolved by CMake Tools:
|
||||
"program": "${command:cmake.launchTargetPath}",
|
||||
"args": [
|
||||
"--config-file", "/etc/pipedal/config/pipedal_p2pd.conf"
|
||||
, "--trace-messages", "--log-level", "debug",
|
||||
|
||||
],
|
||||
"stopAtEntry": false,
|
||||
"cwd": "${workspaceFolder}",
|
||||
"environment": [
|
||||
{
|
||||
// add the directory where our target was built to the PATHs
|
||||
// it gets resolved by CMake Tools:
|
||||
"name": "PATH",
|
||||
"value": "$PATH:${command:cmake.launchTargetDirectory}"
|
||||
},
|
||||
{
|
||||
"name": "ASAN_OPTIONS",
|
||||
"value": "detect_leaks=0"
|
||||
|
||||
},
|
||||
{
|
||||
"name": "OTHER_VALUE",
|
||||
"value": "Something something"
|
||||
}
|
||||
@@ -148,5 +238,7 @@
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
]
|
||||
}
|
||||
+4
-8
@@ -51,14 +51,10 @@ install (
|
||||
install (FILES ${PROJECT_SOURCE_DIR}/build/src/notices.txt
|
||||
DESTINATION /etc/pipedal/react/var/)
|
||||
|
||||
install (FILES ${PROJECT_SOURCE_DIR}/src/template.service
|
||||
${PROJECT_SOURCE_DIR}/src/templateAdmin.service
|
||||
${PROJECT_SOURCE_DIR}/src/templateJack.service
|
||||
${PROJECT_SOURCE_DIR}/src/defaultFavorites.json
|
||||
${PROJECT_SOURCE_DIR}/src/templateP2pd.service
|
||||
${PROEJCT_SOURCE_DIR}/src/template_p2pd.conf
|
||||
|
||||
DESTINATION /etc/pipedal/config )
|
||||
install (
|
||||
DIRECTORY ${PROJECT_SOURCE_DIR}/src/templates
|
||||
DESTINATION /etc/pipedal/config/
|
||||
)
|
||||
|
||||
install (DIRECTORY ${LV2_SOURCE_DIRECTORY}
|
||||
DESTINATION /usr/lib/lv2
|
||||
|
||||
@@ -0,0 +1,188 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "pch.h"
|
||||
#include "AdminClient.hpp"
|
||||
#include "PiPedalException.hpp"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "Lv2Log.hpp"
|
||||
#include <sstream>
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
const char ADMIN_SOCKET_NAME[] = "/run/pipedal/pipedal_admin";
|
||||
|
||||
AdminClient::AdminClient()
|
||||
{
|
||||
}
|
||||
|
||||
AdminClient::~AdminClient()
|
||||
{
|
||||
}
|
||||
|
||||
bool AdminClient::CanUseShutdownClient()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AdminClient::RequestShutdown(bool restart)
|
||||
{
|
||||
const char *message = restart ? "restart\n" : "shutdown\n";
|
||||
return WriteMessage(message);
|
||||
}
|
||||
|
||||
bool AdminClient::WriteMessage(const char *message)
|
||||
{
|
||||
std::lock_guard lock{mutex};
|
||||
|
||||
if (!socket.IsOpen())
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.Connect(ADMIN_SOCKET_NAME, "pipedal_d");
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error(SS("Failed to connect to PiPedal Admin service."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
socket.Send(message, strlen(message));
|
||||
|
||||
char responseBuffer[1024];
|
||||
|
||||
socket.Receive(responseBuffer, sizeof(responseBuffer));
|
||||
|
||||
int response = atoi(responseBuffer);
|
||||
if (response == -2) // throw exception with message
|
||||
{
|
||||
const char *p = responseBuffer;
|
||||
while (*p != ' ' && *p != '\n' && *p != '\0')
|
||||
{
|
||||
++p;
|
||||
}
|
||||
if (*p != 0)
|
||||
++p;
|
||||
throw PiPedalStateException(p);
|
||||
}
|
||||
return response == 0;
|
||||
}
|
||||
|
||||
bool AdminClient::SetJackServerConfiguration(const JackServerSettings &jackServerSettings)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "setJackConfiguration ";
|
||||
|
||||
json_writer writer(s, true);
|
||||
writer.write(jackServerSettings);
|
||||
s << std::endl;
|
||||
return WriteMessage(s.str().c_str());
|
||||
}
|
||||
|
||||
void AdminClient::SetWifiConfig(const WifiConfigSettings &settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't perform this operation when debugging.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "WifiConfigSettings ";
|
||||
json_writer writer(cmd, true);
|
||||
writer.write(settings);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result)
|
||||
{ // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
void AdminClient::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't perform this operation when debugging.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "WifiDirectConfigSettings ";
|
||||
json_writer writer(cmd, true);
|
||||
writer.write(settings);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result)
|
||||
{ // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void AdminClient::SetGovernorSettings(const std::string &settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't use AdminClient when running interactively.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "GovernorSettings ";
|
||||
json_writer writer(cmd, true);
|
||||
writer.write(settings);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result)
|
||||
{ // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void AdminClient::MonitorGovernor(const std::string &governor)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "MonitorGovernor ";
|
||||
json_writer writer(cmd, true);
|
||||
writer.write(governor);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result)
|
||||
{ // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
void AdminClient::UnmonitorGovernor()
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "UnmonitorGovernor";
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result)
|
||||
{ // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
@@ -22,20 +22,29 @@
|
||||
#include <string>
|
||||
#include "JackServerSettings.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include "WifiDirectConfigSettings.hpp"
|
||||
#include "UnixSocket.hpp"
|
||||
#include <mutex>
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
|
||||
class ShutdownClient {
|
||||
static bool WriteMessage(const char*message);
|
||||
class AdminClient {
|
||||
bool WriteMessage(const char*message);
|
||||
public:
|
||||
static bool CanUseShutdownClient();
|
||||
static bool RequestShutdown(bool restart);
|
||||
static bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings);
|
||||
static void SetWifiConfig(const WifiConfigSettings & settings);
|
||||
static void SetGovernorSettings(const std::string & governor);
|
||||
static void MonitorGovernor(const std::string &governor);
|
||||
static void UnmonitorGovernor();
|
||||
AdminClient();
|
||||
~AdminClient();
|
||||
bool CanUseShutdownClient();
|
||||
bool RequestShutdown(bool restart);
|
||||
bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings);
|
||||
void SetWifiConfig(const WifiConfigSettings & settings);
|
||||
void SetWifiDirectConfig(const WifiDirectConfigSettings & settings);
|
||||
void SetGovernorSettings(const std::string & governor);
|
||||
void MonitorGovernor(const std::string &governor);
|
||||
void UnmonitorGovernor();
|
||||
private:
|
||||
std::mutex mutex;
|
||||
UnixSocket socket;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
@@ -22,14 +22,14 @@
|
||||
// non-interactive services are not allowed to execute)
|
||||
|
||||
#include "pch.h"
|
||||
#include <sys/stat.h>
|
||||
#include <grp.h>
|
||||
#include "ss.hpp"
|
||||
#include "CommandLineParser.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/asio/ip/address_v4.hpp>
|
||||
#include <iostream>
|
||||
#include <boost/bind.hpp>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <stdlib.h>
|
||||
@@ -45,14 +45,13 @@
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include "UnixSocket.hpp"
|
||||
#include <signal.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
using namespace boost;
|
||||
using namespace boost::asio;
|
||||
using ip::tcp;
|
||||
|
||||
const size_t MAX_LENGTH = 128;
|
||||
const char ADMIN_SOCKET_NAME[] = "/run/pipedal/pipedal_admin";
|
||||
|
||||
class GovernorMonitorThread
|
||||
{
|
||||
@@ -69,12 +68,13 @@ public:
|
||||
this->governor = governor;
|
||||
cancelled = false;
|
||||
wake = false;
|
||||
pThread = std::make_unique<std::thread>([this]()
|
||||
{ this->ServiceProc(); });
|
||||
} else {
|
||||
pThread = std::make_unique<std::thread>([this]() { this->ServiceProc(); });
|
||||
}
|
||||
else
|
||||
{
|
||||
this->governor = governor;
|
||||
wake = true;
|
||||
|
||||
|
||||
lock.unlock();
|
||||
cv.notify_one();
|
||||
}
|
||||
@@ -121,13 +121,13 @@ private:
|
||||
cv.wait_until(
|
||||
lock,
|
||||
timeToWaitFor,
|
||||
[this]()
|
||||
{ return wake; });
|
||||
[this]() { return wake; });
|
||||
wake = false;
|
||||
governor = this->governor;
|
||||
cancelled = this->cancelled;
|
||||
}
|
||||
if (cancelled) {
|
||||
if (cancelled)
|
||||
{
|
||||
break;
|
||||
}
|
||||
std::string activeGovernor = pipedal::GetCpuGovernor();
|
||||
@@ -156,7 +156,7 @@ void StopGovernorMonitorThread()
|
||||
{
|
||||
governorMonitorThread.Stop();
|
||||
}
|
||||
void StartGovernorMonitorThread(const std::string&governor)
|
||||
void StartGovernorMonitorThread(const std::string &governor)
|
||||
{
|
||||
governorMonitorThread.Start(governor);
|
||||
}
|
||||
@@ -214,96 +214,26 @@ bool setJackConfiguration(JackServerSettings serverSettings)
|
||||
return true;
|
||||
}
|
||||
|
||||
class Reader : public std::enable_shared_from_this<Reader>
|
||||
class AdminServer
|
||||
{
|
||||
private:
|
||||
tcp::socket socket;
|
||||
int readAvailable = MAX_LENGTH;
|
||||
char data[MAX_LENGTH];
|
||||
char *writePointer;
|
||||
ssize_t writeLength;
|
||||
std::stringstream message;
|
||||
|
||||
size_t writePosition = 0;
|
||||
std::string response;
|
||||
|
||||
public:
|
||||
Reader(asio::io_service &ios)
|
||||
: socket(ios)
|
||||
{
|
||||
}
|
||||
static std::shared_ptr<Reader> Create(asio::io_service &ios)
|
||||
{
|
||||
return std::make_shared<Reader>(ios);
|
||||
}
|
||||
|
||||
tcp::socket &Socket() { return socket; }
|
||||
|
||||
void Start()
|
||||
{
|
||||
ReadSome();
|
||||
}
|
||||
char buffer[4096];
|
||||
|
||||
private:
|
||||
void ReadSome()
|
||||
bool HandleCommand()
|
||||
{
|
||||
socket.async_read_some(
|
||||
boost::asio::buffer(data, readAvailable),
|
||||
boost::bind(&Reader::HandleRead,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
void WriteSome()
|
||||
{
|
||||
if (writePosition == response.size())
|
||||
{
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
socket.async_write_some(
|
||||
boost::asio::buffer(response.c_str() + writePosition, response.length() - writePosition),
|
||||
boost::bind(&Reader::HandleWrite,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
boost::asio::placeholders::bytes_transferred));
|
||||
}
|
||||
std::string sender;
|
||||
size_t length = socket.ReceiveFrom(buffer, sizeof(buffer), &sender);
|
||||
if (length > 0 && buffer[length - 1] == '\n')
|
||||
--length;
|
||||
buffer[length] = 0;
|
||||
|
||||
private:
|
||||
void HandleWrite(const boost::system::error_code &err, size_t bytes_transferred)
|
||||
{
|
||||
writePosition += bytes_transferred;
|
||||
WriteSome();
|
||||
}
|
||||
void HandleRead(const boost::system::error_code &err, size_t bytes_transferred)
|
||||
{
|
||||
if (!err)
|
||||
{
|
||||
for (size_t i = 0; i < bytes_transferred; ++i)
|
||||
{
|
||||
char c = data[i];
|
||||
if (c == '\n')
|
||||
{
|
||||
std::string command = message.str();
|
||||
cout << command << endl;
|
||||
HandleCommand(command);
|
||||
socket.close();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
message.put(data[i]);
|
||||
}
|
||||
}
|
||||
ReadSome();
|
||||
}
|
||||
else
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
void HandleCommand(const std::string &text)
|
||||
{
|
||||
std::string text{buffer};
|
||||
int result = -1;
|
||||
std::string command;
|
||||
std::string args;
|
||||
@@ -317,6 +247,10 @@ private:
|
||||
command = text.substr(0, pos);
|
||||
args = text.substr(pos + 1);
|
||||
}
|
||||
if (command == "__quit")
|
||||
{
|
||||
return false;
|
||||
}
|
||||
try
|
||||
{
|
||||
if (command == "UnmonitorGovernor")
|
||||
@@ -372,6 +306,22 @@ private:
|
||||
pipedal::SetWifiConfig(settings);
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "WifiDirectConfigSettings")
|
||||
{
|
||||
std::stringstream ss(args);
|
||||
WifiDirectConfigSettings settings;
|
||||
try
|
||||
{
|
||||
json_reader reader(ss);
|
||||
reader.read(&settings);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
pipedal::SetWifiDirectConfig(settings);
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "shutdown")
|
||||
{
|
||||
result = sysExec("/usr/sbin/shutdown -P now");
|
||||
@@ -405,77 +355,104 @@ private:
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::stringstream t;
|
||||
t << "-2 " << e.what() << "\n";
|
||||
this->response = t.str();
|
||||
this->writePosition = 0;
|
||||
WriteSome();
|
||||
return;
|
||||
|
||||
std::string reply = SS("-2 " << e.what() << "\n");
|
||||
|
||||
try
|
||||
{
|
||||
socket.SendTo(reply.c_str(), reply.length(), sender);
|
||||
}
|
||||
catch (const std::exception /*ignored*/)
|
||||
{
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
std::stringstream t;
|
||||
t << result << "\n";
|
||||
this->response = t.str();
|
||||
this->writePosition = 0;
|
||||
WriteSome();
|
||||
}
|
||||
};
|
||||
|
||||
class Server
|
||||
{
|
||||
private:
|
||||
tcp::acceptor acceptor_;
|
||||
boost::asio::io_service &io_service;
|
||||
|
||||
void HandleAccept(std::shared_ptr<Reader> connection, const boost::system::error_code &err)
|
||||
{
|
||||
if (!err)
|
||||
std::string reply;
|
||||
reply = SS(result << "\n");
|
||||
try
|
||||
{
|
||||
connection->Start();
|
||||
socket.SendTo(reply.c_str(), reply.length(), sender);
|
||||
}
|
||||
StartAccept();
|
||||
catch (const std::exception /*ignored*/)
|
||||
{
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void StartAccept()
|
||||
{
|
||||
// socket
|
||||
std::shared_ptr<Reader> reader = Reader::Create(io_service);
|
||||
private:
|
||||
UnixSocket socket;
|
||||
UnixSocket cancelSocket;
|
||||
|
||||
// asynchronous accept operation and wait for a new connection.
|
||||
acceptor_.async_accept(reader->Socket(),
|
||||
boost::bind(&Server::HandleAccept, this, reader,
|
||||
boost::asio::placeholders::error));
|
||||
std::unique_ptr<std::thread> serviceThread;
|
||||
void ServiceProc()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (!HandleCommand())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// constructor for accepting connection from client
|
||||
Server(boost::asio::io_service &io_service, const tcp::endpoint &endpoint)
|
||||
: acceptor_(io_service, endpoint),
|
||||
io_service(io_service)
|
||||
void Start()
|
||||
{
|
||||
socket.Bind(ADMIN_SOCKET_NAME, "pipedal_d");
|
||||
cancelSocket.Connect(ADMIN_SOCKET_NAME, "pipedal_d");
|
||||
|
||||
{
|
||||
StartAccept();
|
||||
serviceThread = std::make_unique<std::thread>([this] {
|
||||
this->ServiceProc();
|
||||
});
|
||||
}
|
||||
~Server()
|
||||
|
||||
void Stop()
|
||||
{
|
||||
|
||||
if (serviceThread)
|
||||
{
|
||||
std::string msg{"__quit\n"};
|
||||
try
|
||||
{
|
||||
cancelSocket.Send(msg.c_str(), msg.length());
|
||||
}
|
||||
catch (const std::exception &ignored)
|
||||
{
|
||||
};
|
||||
|
||||
serviceThread->join();
|
||||
serviceThread = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void runServer(uint16_t port)
|
||||
{
|
||||
asio::ip::tcp::endpoint endpoint(ip::make_address_v4("127.0.0.1"), port);
|
||||
asio::io_service ios;
|
||||
static bool signaled = false;
|
||||
|
||||
try
|
||||
{
|
||||
Server server(ios, endpoint);
|
||||
ios.run();
|
||||
cout << "Processing terminated." << endl;
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
cout << "Error: " << e.what() << endl;
|
||||
}
|
||||
static void sigHandler(int signal)
|
||||
{
|
||||
signaled = true;
|
||||
}
|
||||
|
||||
struct sigaction saInt, oldActionInt;
|
||||
struct sigaction saTerm, oldActionTerm;
|
||||
|
||||
static void setSignalHandlers()
|
||||
{
|
||||
memset(&saInt, 0, sizeof(saInt));
|
||||
saInt.sa_handler = sigHandler;
|
||||
sigaction(SIGINT, &saInt, &oldActionInt);
|
||||
|
||||
memset(&saTerm, 0, sizeof(saTerm));
|
||||
saTerm.sa_handler = sigHandler;
|
||||
sigaction(SIGTERM, &saTerm, &oldActionTerm);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
@@ -485,7 +462,7 @@ int main(int argc, char **argv)
|
||||
|
||||
uint16_t port = 0;
|
||||
|
||||
parser.AddOption("-port", &port);
|
||||
parser.AddOption("-port", &port); // ignored legacy option.
|
||||
|
||||
try
|
||||
{
|
||||
@@ -500,12 +477,29 @@ int main(int argc, char **argv)
|
||||
cout << "Error: " << e.what() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (port == 0)
|
||||
|
||||
mkdir("/run/pipedal", S_IRWXU | S_IRWXG);
|
||||
|
||||
struct group *group_;
|
||||
group_ = getgrnam("pipedal_d");
|
||||
if (group_ == nullptr)
|
||||
{
|
||||
std::cerr << "Error: port not specified." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
throw UnixSocketException("Group not found.");
|
||||
}
|
||||
runServer(port);
|
||||
|
||||
chown("/run/pipedal", -1, group_->gr_gid);
|
||||
|
||||
setSignalHandlers();
|
||||
|
||||
AdminServer server;
|
||||
server.Start();
|
||||
|
||||
while (!signaled)
|
||||
{
|
||||
usleep(300000);
|
||||
}
|
||||
server.Stop();
|
||||
|
||||
governorMonitorThread.Stop();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,340 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 "AvahiService.hpp"
|
||||
#include <string.h>
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
#include <avahi-common/alternative.h>
|
||||
#include <avahi-common/simple-watch.h>
|
||||
#include <avahi-common/thread-watch.h>
|
||||
#include <avahi-common/malloc.h>
|
||||
#include <avahi-common/error.h>
|
||||
#include <avahi-common/timeval.h>
|
||||
#include <unistd.h>
|
||||
#include "Lv2Log.hpp"
|
||||
#include "ss.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
void AvahiService::Announce(
|
||||
int portNumber,
|
||||
const std::string &name,
|
||||
const std::string &instanceId,
|
||||
const std::string &mdnsName)
|
||||
{
|
||||
Unannounce();
|
||||
|
||||
this->portNumber = portNumber;
|
||||
this->instanceId = instanceId;
|
||||
this->mdnsName = mdnsName;
|
||||
|
||||
this->name = avahi_strdup(name.c_str());
|
||||
|
||||
Start();
|
||||
}
|
||||
|
||||
void AvahiService::Unannounce()
|
||||
{
|
||||
Stop();
|
||||
if (name)
|
||||
{
|
||||
avahi_free(name);
|
||||
this->name = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void AvahiService::entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userData)
|
||||
{
|
||||
((AvahiService *)userData)->EntryGroupCallback(g, state);
|
||||
}
|
||||
void AvahiService::EntryGroupCallback(AvahiEntryGroup *g, AvahiEntryGroupState state)
|
||||
{
|
||||
group = g;
|
||||
/* Called whenever the entry group state changes */
|
||||
switch (state)
|
||||
{
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED:
|
||||
/* The entry group has been established successfully */
|
||||
Lv2Log::debug(SS("Service " << name << " successfully established."));
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_COLLISION:
|
||||
{
|
||||
char *n;
|
||||
/* A service name collision with a remote service
|
||||
* happened. Let's pick a new name */
|
||||
n = avahi_alternative_service_name(name);
|
||||
avahi_free(name);
|
||||
name = n;
|
||||
Lv2Log::debug(SS("Service name collision, renaming service to '" << name << "'\n"));
|
||||
/* And recreate the services */
|
||||
create_group(avahi_entry_group_get_client(g));
|
||||
break;
|
||||
}
|
||||
case AVAHI_ENTRY_GROUP_FAILURE:
|
||||
Lv2Log::error(SS("Entry group failure: " << avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))) << "\n"));
|
||||
/* Some kind of failure happened while we were registering our services */
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
break;
|
||||
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||
case AVAHI_ENTRY_GROUP_REGISTERING:;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int toRawDns(char*rawResult,size_t size, const std::string &name)
|
||||
{
|
||||
// from standard name format to <nn>xyz<nn>foo<nn>com<00> format
|
||||
size_t len = name.length();
|
||||
|
||||
rawResult[0] = 0;
|
||||
if (len+1 >= size-1) return 0;
|
||||
|
||||
rawResult[len+1] = 0;
|
||||
int count = 0;
|
||||
for (int i = len-1; i >= 0; --i)
|
||||
{
|
||||
if (name[i] == '.')
|
||||
{
|
||||
rawResult[i+1] = (char)count;
|
||||
count = 0;
|
||||
} else {
|
||||
rawResult[i+1] = name[i];
|
||||
++count;
|
||||
}
|
||||
}
|
||||
rawResult[0] = count;
|
||||
return len+1;
|
||||
|
||||
}
|
||||
void AvahiService::create_group(AvahiClient *c)
|
||||
{
|
||||
char *n;
|
||||
int ret;
|
||||
assert(c);
|
||||
/* If this is the first time we're called, let's create a new
|
||||
* entry group if necessary */
|
||||
if (!group)
|
||||
{
|
||||
if (!(group = avahi_entry_group_new(c, entry_group_callback, (void *)this)))
|
||||
{
|
||||
Lv2Log::error(SS("avahi_entry_group_new() failed: " << avahi_strerror(avahi_client_errno(c))));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
/* If the group is empty (either because it was just created, or
|
||||
* because it was reset previously, add our entries. */
|
||||
if (avahi_entry_group_is_empty(group))
|
||||
{
|
||||
Lv2Log::debug(SS("Adding service '" << name));
|
||||
|
||||
std::string instanceTxtRecord = SS("pipedal_id=" << this->instanceId);
|
||||
|
||||
#define PIPEDAL_SERVICE_TYPE "_pipedal._tcp"
|
||||
|
||||
if ((ret = avahi_entry_group_add_service(
|
||||
group,
|
||||
AVAHI_IF_UNSPEC,
|
||||
AVAHI_PROTO_UNSPEC,
|
||||
(AvahiPublishFlags)0,
|
||||
name,
|
||||
PIPEDAL_SERVICE_TYPE,
|
||||
NULL,
|
||||
NULL,
|
||||
portNumber,
|
||||
|
||||
// txt records.
|
||||
instanceTxtRecord.c_str(),
|
||||
NULL)) < 0)
|
||||
{
|
||||
if (ret == AVAHI_ERR_COLLISION)
|
||||
goto collision;
|
||||
Lv2Log::error(SS("Failed to add _pipedal._tcp service: " << avahi_strerror(ret)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Tell the server to register the service */
|
||||
if ((ret = avahi_entry_group_commit(group)) < 0)
|
||||
{
|
||||
Lv2Log::error(SS("Failed to commit entry group: " << avahi_strerror(ret)));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return;
|
||||
collision:
|
||||
/* A service name collision with a local service happened. Let's
|
||||
* pick a new name */
|
||||
n = avahi_alternative_service_name(name);
|
||||
avahi_free(name);
|
||||
name = n;
|
||||
Lv2Log::warning(SS("Service name collision, renaming service to '" << name << "'"));
|
||||
avahi_entry_group_reset(group);
|
||||
create_group(c);
|
||||
return;
|
||||
fail:
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
}
|
||||
|
||||
void AvahiService::client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void *userdata)
|
||||
{
|
||||
((AvahiService *)userdata)->ClientCallback(c, state);
|
||||
}
|
||||
|
||||
void AvahiService::ClientCallback(AvahiClient *c, AvahiClientState state)
|
||||
{
|
||||
assert(c);
|
||||
/* Called whenever the client or server state changes */
|
||||
switch (state)
|
||||
{
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
/* The server has startup successfully and registered its host
|
||||
* name on the network, so it's time to create our services */
|
||||
create_group(c);
|
||||
break;
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
this->clientErrno = avahi_client_errno(c);
|
||||
|
||||
if (this->clientErrno == AVAHI_ERR_DISCONNECTED)
|
||||
{
|
||||
// tear the client down and restart it
|
||||
Lv2Log::info("Avahi connection lost. Reconnecting.");
|
||||
|
||||
if (group)
|
||||
{
|
||||
avahi_entry_group_reset(group);
|
||||
group = nullptr;
|
||||
}
|
||||
|
||||
if (client)
|
||||
{
|
||||
avahi_client_free(client);
|
||||
client = nullptr;
|
||||
}
|
||||
int error;
|
||||
client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), AvahiClientFlags::AVAHI_CLIENT_NO_FAIL, client_callback, (void *)this, &error);
|
||||
/* Check wether creating the client object succeeded */
|
||||
if (!client)
|
||||
{
|
||||
Lv2Log::error(SS("Failed to create client: " << avahi_strerror(error)));
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Lv2Log::error(SS("Client failure: " << avahi_strerror(avahi_client_errno(c))));
|
||||
avahi_threaded_poll_quit(threadedPoll);
|
||||
}
|
||||
break;
|
||||
case AVAHI_CLIENT_S_COLLISION:
|
||||
/* Let's drop our registered services. When the server is back
|
||||
* in AVAHI_SERVER_RUNNING state we will register them
|
||||
* again with the new host name. */
|
||||
case AVAHI_CLIENT_S_REGISTERING:
|
||||
/* The server records are now being established. This
|
||||
* might be caused by a host name change. We need to wait
|
||||
* for our own records to register until the host name is
|
||||
* properly esatblished. */
|
||||
if (group)
|
||||
avahi_entry_group_reset(group);
|
||||
break;
|
||||
case AVAHI_CLIENT_CONNECTING:;
|
||||
}
|
||||
}
|
||||
|
||||
void AvahiService::Start()
|
||||
{
|
||||
|
||||
int error;
|
||||
int ret = 1;
|
||||
struct timeval tv;
|
||||
this->clientErrno = 0;
|
||||
while (true)
|
||||
{
|
||||
/* Allocate main loop object */
|
||||
if (!(this->threadedPoll = avahi_threaded_poll_new()))
|
||||
{
|
||||
Lv2Log::error("Failed to create Avahi poll object.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Allocate a new client */
|
||||
client = avahi_client_new(avahi_threaded_poll_get(threadedPoll), AvahiClientFlags::AVAHI_CLIENT_NO_FAIL, client_callback, (void *)this, &error);
|
||||
/* Check wether creating the client object succeeded */
|
||||
if (!client)
|
||||
{
|
||||
Lv2Log::error(SS("Failed to create client: " << avahi_strerror(error)));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
avahi_threaded_poll_start(threadedPoll);
|
||||
ret = 0;
|
||||
return;
|
||||
fail:
|
||||
/* Cleanup things */
|
||||
if (client)
|
||||
{
|
||||
avahi_client_free(client);
|
||||
client = nullptr;
|
||||
}
|
||||
if (group)
|
||||
{
|
||||
avahi_entry_group_reset(group);
|
||||
group = nullptr;
|
||||
}
|
||||
if (threadedPoll)
|
||||
{
|
||||
avahi_threaded_poll_free(threadedPoll);
|
||||
threadedPoll = nullptr;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void AvahiService::Stop()
|
||||
{
|
||||
|
||||
if (threadedPoll)
|
||||
{
|
||||
avahi_threaded_poll_stop(threadedPoll);
|
||||
}
|
||||
/* Cleanup things */
|
||||
// client owns the group?
|
||||
// if (group)
|
||||
// {
|
||||
// avahi_entry_group_reset(group);
|
||||
// group = nullptr;
|
||||
// }`
|
||||
|
||||
if (client)
|
||||
{
|
||||
avahi_client_free(client);
|
||||
client = nullptr;
|
||||
}
|
||||
if (threadedPoll)
|
||||
{
|
||||
avahi_threaded_poll_free(threadedPoll);
|
||||
threadedPoll = nullptr;
|
||||
}
|
||||
group = nullptr;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 <thread>
|
||||
#include <string>
|
||||
|
||||
// forward declarations.
|
||||
class AvahiEntryGroup;
|
||||
class AvahiThreadedPoll;
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class AvahiService {
|
||||
public:
|
||||
~AvahiService() { Unannounce(); }
|
||||
void Announce(int portNumber, const std::string &name, const std::string &instanceId, const std::string&mdnsName);
|
||||
|
||||
void Unannounce();
|
||||
|
||||
private:
|
||||
void Start();
|
||||
void Stop();
|
||||
static void entry_group_callback(AvahiEntryGroup*g, AvahiEntryGroupState state, void *userData);
|
||||
void EntryGroupCallback(AvahiEntryGroup*g, AvahiEntryGroupState state);
|
||||
|
||||
static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata);
|
||||
void ClientCallback(AvahiClient *c, AvahiClientState state);
|
||||
|
||||
|
||||
void create_group(AvahiClient *c);
|
||||
|
||||
void threadProc();
|
||||
|
||||
int clientErrno = 0;
|
||||
|
||||
int portNumber = -1;
|
||||
std::string instanceId;
|
||||
std::string mdnsName;
|
||||
|
||||
AvahiClient *client = NULL;
|
||||
AvahiEntryGroup *group = NULL;
|
||||
AvahiThreadedPoll *threadedPoll = NULL;
|
||||
char*name = NULL;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 "catch.hpp"
|
||||
#include "AvahiService.hpp"
|
||||
#include "ss.hpp"
|
||||
#include <unistd.h>
|
||||
#include <cassert>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
TEST_CASE("Avahi Service Test", "[avahi_service][dev]")
|
||||
{
|
||||
|
||||
{
|
||||
AvahiService service;
|
||||
|
||||
service.Announce(81, "Test Announcement", "0a6045b0-1753-4104-b3e4-b9713b9cc358","pipedal");
|
||||
|
||||
sleep(10);
|
||||
|
||||
service.Unannounce();
|
||||
service.Announce(81, "Test Announcement 2", "0a6045b0-1753-4104-b3e4-b9713b9cc358","pipedal");
|
||||
sleep(10000);
|
||||
}
|
||||
}
|
||||
+24
-18
@@ -14,6 +14,7 @@ find_package(sdbus-c++ REQUIRED)
|
||||
|
||||
|
||||
|
||||
|
||||
# Can't get the pkg_check to work.
|
||||
# pkg_check_modules(LIBNL3 "nl-genl-3")
|
||||
# if(!LIBNL3_FOUND)
|
||||
@@ -88,21 +89,13 @@ message (STATUS "Cxx flags: ${CMAKE_CXX_FLAGS}" )
|
||||
|
||||
add_definitions(-DBOOST_ERROR_CODE_HEADER_ONLY -DBOOST_BIND_GLOBAL_PLACEHOLDERS -DONBOARDING)
|
||||
|
||||
# build Bluez dbus proxies
|
||||
# requires apt install libsdbus-c++-bin
|
||||
add_custom_command(
|
||||
OUTPUT ${PROJECT_SOURCE_DIR}/src/dbus/bluez_proxy.h ${PROJECT_SOURCE_DIR}/src/dbus/bluez_adaptor.h
|
||||
DEPENDS ${PROJECT_SOURCE_DIR}/src/dbus/bluez.xml
|
||||
COMMAND sdbus-c++-xml2cpp ${PROJECT_SOURCE_DIR}/src/dbus/bluez.xml
|
||||
--proxy=${PROJECT_SOURCE_DIR}/src/dbus/bluez_proxy.h
|
||||
--adaptor=${PROJECT_SOURCE_DIR}/src/dbus/bluez_adaptor.h
|
||||
|
||||
COMMENT "Generating D-Bus bindings for bluez"
|
||||
)
|
||||
|
||||
|
||||
set (PIPEDAL_SOURCES
|
||||
P2pConfigFiles.hpp
|
||||
AvahiService.cpp AvahiService.hpp
|
||||
DeviceIdFile.cpp DeviceIdFile.hpp
|
||||
|
||||
StdErrorCapture.hpp StdErrorCapture.cpp
|
||||
Ipv6Helpers.cpp Ipv6Helpers.hpp
|
||||
PluginPreset.cpp PluginPreset.hpp
|
||||
@@ -112,6 +105,8 @@ set (PIPEDAL_SOURCES
|
||||
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
||||
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
||||
WifiDirectConfigSettings.hpp WifiDirectConfigSettings.cpp
|
||||
ConfigUtil.hpp ConfigUtil.cpp
|
||||
|
||||
RequestHandler.hpp json.cpp json.hpp Scratch.cpp Lv2Host.hpp Lv2Host.cpp
|
||||
PluginType.hpp PluginType.cpp
|
||||
Lv2Log.hpp Lv2Log.cpp
|
||||
@@ -142,7 +137,7 @@ set (PIPEDAL_SOURCES
|
||||
CommandLineParser.hpp
|
||||
Lv2SystemdLogger.hpp Lv2SystemdLogger.cpp
|
||||
JackServerSettings.hpp JackServerSettings.cpp
|
||||
ShutdownClient.hpp ShutdownClient.cpp
|
||||
AdminClient.hpp AdminClient.cpp
|
||||
MidiBinding.hpp MidiBinding.cpp
|
||||
PiPedalMath.hpp
|
||||
Locale.hpp Locale.cpp
|
||||
@@ -153,6 +148,8 @@ set (PIPEDAL_SOURCES
|
||||
RegDb.cpp RegDb.hpp
|
||||
PiPedalAlsa.hpp PiPedalAlsa.cpp
|
||||
InheritPriorityMutex.hpp InheritPriorityMutex.cpp
|
||||
UnixSocket.cpp UnixSocket.hpp
|
||||
|
||||
)
|
||||
|
||||
configure_file(config.hpp.in config.hpp)
|
||||
@@ -173,17 +170,17 @@ target_include_directories(pipedald PRIVATE
|
||||
${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${LIBNL3_INCLUDE_DIRS} ${LVDEV_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(pipedald PRIVATE pthread atomic stdc++fs asound
|
||||
target_link_libraries(pipedald PRIVATE pthread atomic stdc++fs asound avahi-common avahi-client
|
||||
${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${LIBNL3_LIBRARIES} systemd SDBusCpp::sdbus-c++
|
||||
)
|
||||
|
||||
#################################
|
||||
add_executable(pipedaltest ${PIPEDAL_SOURCES} testMain.cpp
|
||||
dbus/bluez_proxy.h dbus/bluez_adaptor.h
|
||||
dbus/bluez_test.cpp
|
||||
jsonTest.cpp
|
||||
AvahiServiceTest.cpp
|
||||
WifiChannelsTest.cpp
|
||||
PiPedalAlsaTest.cpp
|
||||
UnixSocketTest.cpp
|
||||
|
||||
Lv2HostLeakTest.cpp
|
||||
|
||||
@@ -207,7 +204,7 @@ target_include_directories(pipedaltest PRIVATE
|
||||
${JACK_INCLUDE_DIRS} ${LILV_0_INCLUDE_DIRS} ${LIBNL3_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(pipedaltest PRIVATE pthread atomic stdc++fs asound
|
||||
target_link_libraries(pipedaltest PRIVATE pthread atomic stdc++fs asound avahi-common avahi-client
|
||||
${LILV_0_LIBRARIES} ${JACK_LIBRARIES} ${LIBNL3_LIBRARIES} systemd SDBusCpp::sdbus-c++
|
||||
)
|
||||
|
||||
@@ -223,6 +220,7 @@ add_test(NAME DevTest COMMAND pipedaltest "[Dev]")
|
||||
|
||||
add_executable(pipedalconfig
|
||||
PrettyPrinter.hpp
|
||||
DeviceIdFile.cpp DeviceIdFile.hpp
|
||||
json.cpp json.hpp
|
||||
HtmlHelper.cpp HtmlHelper.hpp
|
||||
CommandLineParser.hpp
|
||||
@@ -231,9 +229,11 @@ add_executable(pipedalconfig
|
||||
ConfigMain.cpp
|
||||
WifiConfigSettings.cpp WifiConfigSettings.hpp
|
||||
WifiDirectConfigSettings.cpp WifiDirectConfigSettings.hpp
|
||||
ConfigUtil.hpp ConfigUtil.cpp
|
||||
JackServerSettings.hpp JackServerSettings.cpp
|
||||
SetWifiConfig.hpp SetWifiConfig.cpp
|
||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||
WriteTemplateFile.hpp WriteTemplateFile.cpp
|
||||
SysExec.hpp SysExec.cpp
|
||||
asan_options.cpp
|
||||
Lv2Log.cpp Lv2Log.hpp
|
||||
@@ -241,15 +241,21 @@ add_executable(pipedalconfig
|
||||
|
||||
)
|
||||
|
||||
target_link_libraries(pipedalconfig PRIVATE pthread atomic stdc++fs
|
||||
target_link_libraries(pipedalconfig PRIVATE pthread atomic uuid stdc++fs
|
||||
)
|
||||
|
||||
add_executable(pipedaladmind ShutdownMain.cpp CommandLineParser.hpp
|
||||
add_executable(pipedaladmind AdminMain.cpp CommandLineParser.hpp
|
||||
UnixSocket.cpp UnixSocket.hpp
|
||||
DeviceIdFile.cpp DeviceIdFile.hpp
|
||||
|
||||
JackServerSettings.hpp JackServerSettings.cpp
|
||||
json.hpp json.cpp HtmlHelper.hpp HtmlHelper.cpp Lv2Log.hpp Lv2Log.cpp
|
||||
Lv2SystemdLogger.hpp Lv2SystemdLogger.cpp
|
||||
WifiConfigSettings.cpp WifiConfigSettings.hpp
|
||||
WriteTemplateFile.cpp WriteTemplateFile.hpp
|
||||
WifiDirectConfigSettings.cpp WifiDirectConfigSettings.hpp
|
||||
ConfigUtil.hpp ConfigUtil.cpp
|
||||
|
||||
SetWifiConfig.hpp SetWifiConfig.cpp
|
||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||
SysExec.hpp SysExec.cpp
|
||||
|
||||
+71
-10
@@ -33,9 +33,14 @@
|
||||
#include "JackServerSettings.hpp"
|
||||
#include "P2pConfigFiles.hpp"
|
||||
#include "PrettyPrinter.hpp"
|
||||
#include "DeviceIdFile.hpp"
|
||||
#include <uuid/uuid.h>
|
||||
#include <random>
|
||||
|
||||
#define SS(x) (((std::stringstream &)(std::stringstream() << x)).str())
|
||||
|
||||
#define TEMPLATE_PATH(filename) ("/etc/pipedal/config/templates/" filename ".service")
|
||||
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
|
||||
@@ -380,7 +385,7 @@ void InstallJackService()
|
||||
// deploy the systemd service file
|
||||
std::map<std::string, std::string> map; // nothing to customize.
|
||||
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/templateJack.service"), GetServiceFileName(JACK_SERVICE));
|
||||
WriteTemplateFile(map, GetServiceFileName(JACK_SERVICE));
|
||||
|
||||
MaybeStartJackService();
|
||||
}
|
||||
@@ -424,13 +429,65 @@ void Uninstall()
|
||||
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||
}
|
||||
|
||||
std::random_device randdev;
|
||||
|
||||
|
||||
std::string MakeUuid()
|
||||
{
|
||||
uuid_t uuid;
|
||||
uuid_generate(uuid);
|
||||
char strUid[36 + 1];
|
||||
uuid_unparse(uuid, strUid);
|
||||
return strUid;
|
||||
}
|
||||
|
||||
static std::string RandomChars(int nchars)
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
std::uniform_int_distribution distr(0,26+26+10-1);
|
||||
|
||||
for (int i = 0; i < nchars; ++i)
|
||||
{
|
||||
int v = distr(randdev);
|
||||
char c;
|
||||
if (v < 10)
|
||||
{
|
||||
c = (char)('0' + v);
|
||||
} else {
|
||||
v -= 10;
|
||||
if (v < 26) {
|
||||
c = (char)('a'+v);
|
||||
} else {
|
||||
v -= 26;
|
||||
c = (char)('A'+v);
|
||||
}
|
||||
}
|
||||
s << c;
|
||||
}
|
||||
return s.str();
|
||||
}
|
||||
|
||||
static void PrepareDeviceidFile()
|
||||
{
|
||||
if (!std::filesystem::exists(DeviceIdFile::DEVICEID_FILE_NAME))
|
||||
{
|
||||
DeviceIdFile deviceIdFile;
|
||||
|
||||
deviceIdFile.deviceName = "PiPedal-" + RandomChars(2);
|
||||
deviceIdFile.uuid = MakeUuid();
|
||||
deviceIdFile.Save();
|
||||
}
|
||||
}
|
||||
|
||||
void Install(const std::filesystem::path &programPrefix, const std::string endpointAddress)
|
||||
{
|
||||
if (sysExec(GROUPADD_BIN " -f " AUDIO_SERVICE_GROUP_NAME) != EXIT_SUCCESS)
|
||||
{
|
||||
throw PiPedalException("Failed to create audio service group.");
|
||||
}
|
||||
|
||||
|
||||
PrepareDeviceidFile();
|
||||
InstallJackService();
|
||||
auto endpos = endpointAddress.find_last_of(':');
|
||||
if (endpos == string::npos)
|
||||
@@ -556,13 +613,13 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
}
|
||||
s
|
||||
<< (programPrefix / "bin" / NATIVE_SERVICE).string()
|
||||
<< " /etc/pipedal/config /etc/pipedal/react -port " << endpointAddress << " -systemd -shutdownPort " << shutdownPort;
|
||||
<< " /etc/pipedal/config /etc/pipedal/react -port " << endpointAddress << " -systemd";
|
||||
|
||||
map["COMMAND"] = s.str();
|
||||
}
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/template.service"), GetServiceFileName(NATIVE_SERVICE));
|
||||
WriteTemplateFile(map, GetServiceFileName(NATIVE_SERVICE));
|
||||
|
||||
map["DESCRIPTION"] = "PiPedal Shutdown Service";
|
||||
map["DESCRIPTION"] = "PiPedal Admin Service";
|
||||
{
|
||||
std::stringstream s;
|
||||
|
||||
@@ -572,7 +629,7 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
|
||||
map["COMMAND"] = s.str();
|
||||
}
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/templateAdmin.service"), GetServiceFileName(ADMIN_SERVICE));
|
||||
WriteTemplateFile(map, GetServiceFileName(ADMIN_SERVICE));
|
||||
|
||||
// /usr/bin/pipedal_p2pd --config-file /etc/pipedal/config/template_p2pd.conf
|
||||
|
||||
@@ -581,7 +638,7 @@ void Install(const std::filesystem::path &programPrefix, const std::string endpo
|
||||
<< " --config-file " << PIPEDAL_P2PD_CONF_PATH);
|
||||
map["COMMAND"] = pipedal_p2pd_cmd;
|
||||
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/templateP2pd.service"), GetServiceFileName(PIPEDAL_P2PD_SERVICE));
|
||||
WriteTemplateFile(map, GetServiceFileName(PIPEDAL_P2PD_SERVICE));
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||
|
||||
@@ -638,8 +695,10 @@ static void PrintHelp()
|
||||
<< HangingIndent() << " --restart\tRestart the pipedal services." << "\n"
|
||||
<< "\n"
|
||||
|
||||
<< HangingIndent() << " --enable-p2p <country_code> <ssid> [[<pin>] <channel>]\t"
|
||||
<< HangingIndent() << " --enable-p2p [<country_code> <ssid> [[<pin>] <channel>] ]\t"
|
||||
<< "Enable the P2P (Wi-Fi Direct) hotspot." << "\n\n"
|
||||
<< "With no additional arguments, the P2P channel is enabled with most-recent settings."
|
||||
<< "\n\n"
|
||||
<< "<country_code> is the 2-letter ISO-3166 country code for "
|
||||
"the country you are in. see below for further notes."
|
||||
<< "\n\n"
|
||||
@@ -658,7 +717,7 @@ static void PrintHelp()
|
||||
<< "device to PiPedal. (It's also available on the Settings page of PiPedal, if you have access to PiPedal UI on another device.)"
|
||||
<< "\n\n"
|
||||
<< "For best performance, the channel number should be 1, 6, or 11 (the Wifi Direct \"social\" channels). "
|
||||
<< "If you don't supply a channel number, PiPedal will select the least-busy of channels 1, 6 and 11."
|
||||
<< "Channel number defaults to 1."
|
||||
<< "\n\n"
|
||||
|
||||
<< HangingIndent() << " --disable-p2p\tDisabled Wi-Fi Direct access."
|
||||
@@ -878,8 +937,10 @@ int main(int argc, char **argv)
|
||||
WifiDirectConfigSettings settings;
|
||||
settings.ParseArguments(argv);
|
||||
settings.valid_ = true;
|
||||
settings.enable_ = false;
|
||||
settings.enable_ = true;
|
||||
SetWifiDirectConfig(settings);
|
||||
RestartService(true); // also have to retart web service so that it gets the correct device name.
|
||||
|
||||
}
|
||||
else if (disable_p2p)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 "ConfigUtil.hpp"
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
|
||||
using namespace pipedal;
|
||||
using namespace std;
|
||||
|
||||
static std::string getKey(const std::string &line, size_t length)
|
||||
{
|
||||
std::stringstream s;
|
||||
size_t start = 0;
|
||||
size_t end = length;
|
||||
char c;
|
||||
while (start < end && (line[start] == ' ' || line[start] == '\t'))
|
||||
++start;
|
||||
|
||||
while (end > start && (line[end - 1] == ' ' || line[end - 1] == '\t'))
|
||||
--end;
|
||||
|
||||
return line.substr(start, end - start);
|
||||
}
|
||||
static std::string trim(const std::string &value)
|
||||
{
|
||||
size_t start = 0;
|
||||
size_t end = value.length();
|
||||
|
||||
while (start < end && ( value[start] == ' ' || value[start] == '\t'))
|
||||
++start;
|
||||
|
||||
while (end > start && (value[end - 1] == ' ' || value[end - 1] == '\t'))
|
||||
--end;
|
||||
|
||||
return value.substr(start, end - start);
|
||||
}
|
||||
static std::string unquote(const std::string &value)
|
||||
{
|
||||
if (value.length() > 2)
|
||||
{
|
||||
if (
|
||||
(value[0] == '\'' && value[value.length() - 1] == '\'') || (value[0] == '\"' && value[value.length() - 1] == '\"'))
|
||||
{
|
||||
char quotChar = value[0];
|
||||
|
||||
std::stringstream ss;
|
||||
for (size_t i = 1; i < value.length() - 1; ++i)
|
||||
{
|
||||
char c = value[i];
|
||||
if (c == '\\')
|
||||
{
|
||||
++i;
|
||||
c = value[i];
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
c = '\r';
|
||||
break;
|
||||
case 'n':
|
||||
c = '\n';
|
||||
break;
|
||||
case 't':
|
||||
c = '\t';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ss << c;
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << c;
|
||||
}
|
||||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
||||
return value;
|
||||
}
|
||||
bool ConfigUtil::GetConfigLine(const std::string & filePath,const std::string & key, std::string *pValue)
|
||||
{
|
||||
|
||||
ifstream f;
|
||||
f.open(filePath);
|
||||
if (f.is_open())
|
||||
{
|
||||
std::string line;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (f.eof() || f.fail())
|
||||
{
|
||||
break;
|
||||
}
|
||||
getline(f, line);
|
||||
auto pos = line.find_first_of('#');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
line = line.substr(0, pos);
|
||||
}
|
||||
pos = line.find_first_of('=');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
std::string thisKey = getKey(line, pos);
|
||||
if (thisKey == key)
|
||||
{
|
||||
std::string value = line.substr(pos + 1);
|
||||
|
||||
*pValue = unquote(trim(value));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -22,17 +22,13 @@
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
[Unit]
|
||||
Description=PiPedal P2P Session Manager
|
||||
After=network.target
|
||||
#pragma once
|
||||
|
||||
[Service]
|
||||
ExecStart=${COMMAND}
|
||||
Type=notify
|
||||
Restart=always
|
||||
RestartSec=60
|
||||
WorkingDirectory=/var/pipedal
|
||||
#include <string>
|
||||
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
namespace pipedal {
|
||||
class ConfigUtil {
|
||||
public:
|
||||
static bool GetConfigLine(const std::string & filePath,const std::string & key, std::string *pValue);
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 "DeviceIdFile.hpp"
|
||||
#include <fstream>
|
||||
#include <stdexcept>
|
||||
#include <grp.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
const char DeviceIdFile::DEVICEID_FILE_NAME[] = "/etc/pipedal/config/device_uuid";
|
||||
|
||||
void DeviceIdFile::Load()
|
||||
{
|
||||
ifstream f;
|
||||
|
||||
f.open(DEVICEID_FILE_NAME);
|
||||
if (!f.is_open())
|
||||
{
|
||||
throw invalid_argument("Can't open file " + std::string(DEVICEID_FILE_NAME));
|
||||
}
|
||||
|
||||
std::getline(f, uuid);
|
||||
std::getline(f, deviceName);
|
||||
}
|
||||
void DeviceIdFile::Save()
|
||||
{
|
||||
{
|
||||
std::string path = DEVICEID_FILE_NAME;
|
||||
ofstream f;
|
||||
f.open(path, ios_base::trunc);
|
||||
if (!f.is_open())
|
||||
{
|
||||
throw invalid_argument("Can't write to file " + path);
|
||||
}
|
||||
|
||||
struct group *group_;
|
||||
group_ = getgrnam("pipedal_d");
|
||||
if (group_ == nullptr)
|
||||
{
|
||||
throw logic_error("Group not found: pipedal_d");
|
||||
}
|
||||
chown(path.c_str(),-1,group_->gr_gid);
|
||||
chmod(path.c_str(), S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
|
||||
|
||||
|
||||
f << uuid << endl;
|
||||
f << deviceName << endl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 <string>
|
||||
|
||||
namespace pipedal {
|
||||
class DeviceIdFile {
|
||||
public:
|
||||
static const char DEVICEID_FILE_NAME[];
|
||||
|
||||
void Load();
|
||||
void Save();
|
||||
|
||||
|
||||
std::string uuid;
|
||||
std::string deviceName;
|
||||
};
|
||||
}
|
||||
+4
-2
@@ -55,7 +55,7 @@ using namespace pipedal;
|
||||
|
||||
#define JACK_SESSION_CALLBACKS 0
|
||||
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "AdminClient.hpp"
|
||||
|
||||
const double VU_UPDATE_RATE_S = 1.0 / 30;
|
||||
const double OVERRUN_GRACE_PERIOD_S = 15;
|
||||
@@ -1363,7 +1363,9 @@ private:
|
||||
this_->restarting = true;
|
||||
// this_->Close(); (JackServerConfiguration now does a service restart.)
|
||||
try {
|
||||
ShutdownClient::SetJackServerConfiguration(jackServerSettings);
|
||||
AdminClient client;
|
||||
|
||||
client.SetJackServerConfiguration(jackServerSettings);
|
||||
//this_->Open(this_->channelSelection);
|
||||
this_->restarting = false;
|
||||
onComplete(true, "");
|
||||
|
||||
@@ -27,5 +27,5 @@
|
||||
|
||||
#define DEVICE_GUID_FILE "/etc/pipedal/config/device_uuid"
|
||||
|
||||
#define PIPEDAL_P2PD_CONF_PATH "/etc/pipedal/config/template_p2pd.conf"
|
||||
#define PIPEDAL_P2PD_CONF_PATH "/etc/pipedal/config/pipedal_p2pd.conf"
|
||||
|
||||
|
||||
@@ -106,6 +106,7 @@ public:
|
||||
}
|
||||
return socketServerAddress_.substr(0,pos);
|
||||
}
|
||||
|
||||
uint16_t GetSocketServerPort() const {
|
||||
try {
|
||||
size_t pos = this->socketServerAddress_.find_last_of(':');
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
#include "Lv2Log.hpp"
|
||||
#include <set>
|
||||
#include "PiPedalConfiguration.hpp"
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "AdminClient.hpp"
|
||||
#include "SplitEffect.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
|
||||
@@ -78,7 +78,7 @@ void PiPedalModel::Close()
|
||||
PiPedalModel::~PiPedalModel()
|
||||
{
|
||||
try {
|
||||
ShutdownClient::UnmonitorGovernor();
|
||||
adminClient.UnmonitorGovernor();
|
||||
} catch (...) // noexcept here!
|
||||
{
|
||||
|
||||
@@ -153,7 +153,7 @@ void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
||||
this->webRoot = configuration.GetWebRoot();
|
||||
this->jackServerSettings.ReadJackConfiguration();
|
||||
|
||||
ShutdownClient::MonitorGovernor(storage.GetGovernorSettings());
|
||||
adminClient.MonitorGovernor(storage.GetGovernorSettings());
|
||||
|
||||
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
||||
|
||||
@@ -633,7 +633,7 @@ GovernorSettings PiPedalModel::GetGovernorSettings()
|
||||
void PiPedalModel::SetGovernorSettings(const std::string& governor)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
ShutdownClient::SetGovernorSettings(governor);
|
||||
adminClient.SetGovernorSettings(governor);
|
||||
|
||||
this->storage.SetGovernorSettings(governor);
|
||||
|
||||
@@ -657,7 +657,7 @@ void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSet
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
ShutdownClient::SetWifiConfig(wifiConfigSettings);
|
||||
adminClient.SetWifiConfig(wifiConfigSettings);
|
||||
|
||||
this->storage.SetWifiConfigSettings(wifiConfigSettings);
|
||||
|
||||
@@ -1022,7 +1022,7 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
if (!ShutdownClient::CanUseShutdownClient())
|
||||
if (!adminClient.CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't change server settings when running a debug server.");
|
||||
}
|
||||
@@ -1043,7 +1043,7 @@ void PiPedalModel::SetJackServerSettings(const JackServerSettings &jackServerSet
|
||||
}
|
||||
delete[] t;
|
||||
|
||||
if (ShutdownClient::CanUseShutdownClient())
|
||||
if (adminClient.CanUseShutdownClient())
|
||||
{
|
||||
|
||||
// save the current (edited) preset now in case the service shutdown isn't clean.
|
||||
|
||||
@@ -33,6 +33,10 @@
|
||||
#include "PiPedalConfiguration.hpp"
|
||||
#include "JackServerSettings.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include "AdminClient.hpp"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
@@ -68,6 +72,8 @@ private:
|
||||
PiPedalAlsaDevices alsaDevices;
|
||||
std::recursive_mutex mutex;
|
||||
|
||||
AdminClient adminClient;
|
||||
|
||||
|
||||
class MidiListener {
|
||||
public:
|
||||
@@ -142,6 +148,10 @@ public:
|
||||
virtual ~PiPedalModel();
|
||||
|
||||
void Close();
|
||||
|
||||
AdminClient&GetAdminClient() { return adminClient; }
|
||||
|
||||
|
||||
void LoadLv2PluginInfo(const PiPedalConfiguration&configuration);
|
||||
void Load(const PiPedalConfiguration&configuration);
|
||||
|
||||
|
||||
+40
-34
@@ -30,7 +30,7 @@
|
||||
#include <atomic>
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "AdminClient.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include "WifiChannels.hpp"
|
||||
#include "SysExec.hpp"
|
||||
@@ -334,41 +334,16 @@ JSON_MAP_END()
|
||||
|
||||
|
||||
|
||||
static void requestShutdown(bool restart)
|
||||
{
|
||||
if (ShutdownClient::CanUseShutdownClient())
|
||||
{
|
||||
ShutdownClient::RequestShutdown(restart);
|
||||
}
|
||||
else {
|
||||
// ONLY works when interactively logged in.
|
||||
std::stringstream s;
|
||||
s << "/usr/sbin/shutdown ";
|
||||
if (restart)
|
||||
{
|
||||
s << "-r";
|
||||
} else
|
||||
{
|
||||
s << "-P";
|
||||
}
|
||||
s << " now";
|
||||
|
||||
if (sysExec(s.str().c_str()) != EXIT_SUCCESS)
|
||||
{
|
||||
Lv2Log::error("shutdown failed.");
|
||||
if (restart) {
|
||||
throw new PiPedalStateException("Restart request failed.");
|
||||
} else {
|
||||
throw new PiPedalStateException("Shutdown request failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PiPedalSocketHandler : public SocketHandler, public IPiPedalModelSubscriber
|
||||
{
|
||||
private:
|
||||
AdminClient& GetAdminClient() const {
|
||||
return model.GetAdminClient();
|
||||
}
|
||||
void RequestShutdown(bool restart);
|
||||
|
||||
std::recursive_mutex writeMutex;
|
||||
PiPedalModel &model;
|
||||
static std::atomic<uint64_t> nextClientId;
|
||||
@@ -819,7 +794,7 @@ public:
|
||||
else if (message == "setWifiConfigSettings") {
|
||||
WifiConfigSettings wifiConfigSettings;
|
||||
pReader->read(&wifiConfigSettings);
|
||||
if (!ShutdownClient::CanUseShutdownClient())
|
||||
if (!GetAdminClient().CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't change server settings when running interactively.");
|
||||
}
|
||||
@@ -963,13 +938,13 @@ public:
|
||||
{
|
||||
PresetIndex newIndex;
|
||||
|
||||
requestShutdown(false);
|
||||
RequestShutdown(false);
|
||||
this->Reply(replyTo,"shutdown");
|
||||
}
|
||||
else if (message == "restart")
|
||||
{
|
||||
PresetIndex newIndex;
|
||||
requestShutdown(true);
|
||||
RequestShutdown(true);
|
||||
this->Reply(replyTo,"restart");
|
||||
}
|
||||
else if (message == "deletePresetItem")
|
||||
@@ -1548,3 +1523,34 @@ std::shared_ptr<ISocketFactory> pipedal::MakePiPedalSocketFactory(PiPedalModel &
|
||||
return std::make_shared<PiPedalSocketFactory>(model);
|
||||
}
|
||||
|
||||
|
||||
void PiPedalSocketHandler::RequestShutdown(bool restart)
|
||||
{
|
||||
if (GetAdminClient().CanUseShutdownClient())
|
||||
{
|
||||
GetAdminClient().RequestShutdown(restart);
|
||||
}
|
||||
else {
|
||||
// ONLY works when interactively logged in.
|
||||
std::stringstream s;
|
||||
s << "/usr/sbin/shutdown ";
|
||||
if (restart)
|
||||
{
|
||||
s << "-r";
|
||||
} else
|
||||
{
|
||||
s << "-P";
|
||||
}
|
||||
s << " now";
|
||||
|
||||
if (sysExec(s.str().c_str()) != EXIT_SUCCESS)
|
||||
{
|
||||
Lv2Log::error("shutdown failed.");
|
||||
if (restart) {
|
||||
throw new PiPedalStateException("Restart request failed.");
|
||||
} else {
|
||||
throw new PiPedalStateException("Shutdown request failed.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace pipedal
|
||||
PrettyPrinter()
|
||||
: s(std::cout)
|
||||
{
|
||||
lineBuffer.resize(lineWidth * 2);
|
||||
lineBuffer.reserve(120);
|
||||
}
|
||||
std::ostream&Stream() const { return s;}
|
||||
|
||||
|
||||
+96
-70
@@ -21,6 +21,7 @@
|
||||
#include "ss.hpp"
|
||||
|
||||
#include "P2pConfigFiles.hpp"
|
||||
#include "DeviceIdFile.hpp"
|
||||
#include "SetWifiConfig.hpp"
|
||||
#include "PiPedalException.hpp"
|
||||
#include "SystemConfigFile.hpp"
|
||||
@@ -43,7 +44,10 @@ using namespace std;
|
||||
|
||||
|
||||
static char DNSMASQ_APD_PATH[] = "/etc/dnsmasq.d/30-pipedal-apd.conf";
|
||||
static char DNSMASQ_P2P_PATH[] = "/etc/dnsmasqdnsmaqsq.d/30-pipedal-p2p.conf";
|
||||
|
||||
static char DNSMASQ_P2P_SOURCE_PATH[] = "/etc/pipedal/config/templates/30-pipedal-p2p.conf";
|
||||
|
||||
static char DNSMASQ_P2P_PATH[] = "/etc/dnsmasq.d/30-pipedal-p2p.conf";
|
||||
|
||||
|
||||
static bool IsApdInstalled() {
|
||||
@@ -54,53 +58,6 @@ static bool IsP2pInstalled() {
|
||||
}
|
||||
|
||||
|
||||
uint32_t pipedal::ChannelToWifiFrequency(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);
|
||||
if (size != t.length())
|
||||
{
|
||||
throw invalid_argument("Expecting a number: '" + t + "'.");
|
||||
}
|
||||
return ChannelToWifiFrequency((uint32_t)lChannel);
|
||||
}
|
||||
|
||||
uint32_t pipedal::ChannelToWifiFrequency(uint32_t channel)
|
||||
{
|
||||
// 2.4GHz.
|
||||
if (channel >= 1 && channel <= 13)
|
||||
{
|
||||
return 2412 + 5*(channel-1);
|
||||
}
|
||||
if (channel == 14)
|
||||
{
|
||||
return 2484;
|
||||
}
|
||||
// 802.11y
|
||||
if (channel >= 131 && channel < 137)
|
||||
{
|
||||
return 3660 + (channel-131)*5;
|
||||
}
|
||||
if (channel >= 32 && channel <= 68 && (channel & 1) == 0)
|
||||
{
|
||||
return 5160 + (channel-32)/2*10;
|
||||
}
|
||||
if (channel == 96) return 5480;
|
||||
|
||||
if (channel >= 100 && channel <= 196)
|
||||
{
|
||||
return 5500 + (channel-100)/5;
|
||||
}
|
||||
throw invalid_argument(SS("Invalid channel: " << channel));
|
||||
|
||||
}
|
||||
|
||||
static void restoreApdDhcpdConfFile()
|
||||
{
|
||||
@@ -140,6 +97,44 @@ static void restoreApdDhcpdConfFile()
|
||||
}
|
||||
}
|
||||
|
||||
static void restoreP2pDhcpdConfFile()
|
||||
{
|
||||
// remove the interface wlan0 section.
|
||||
std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf");
|
||||
if (std::filesystem::exists(dhcpcdConfig))
|
||||
{
|
||||
SystemConfigFile dhcpcd(dhcpcdConfig);
|
||||
|
||||
int line = dhcpcd.GetLineThatStartsWith("hostname");
|
||||
std::string hostNameLine;
|
||||
hostNameLine = "hostname"; // the default value.
|
||||
|
||||
if (line != -1)
|
||||
{
|
||||
dhcpcd.SetLineValue(line, hostNameLine);
|
||||
}
|
||||
|
||||
line = dhcpcd.GetLineNumber("interface p2p-wlan0-0");
|
||||
if (line != -1)
|
||||
{
|
||||
dhcpcd.EraseLine(line);
|
||||
while (line < dhcpcd.GetLineCount())
|
||||
{
|
||||
const std::string &lineValue = dhcpcd.GetLineValue(line);
|
||||
if (lineValue.length() > 0 && (lineValue[0] == ' ' || lineValue[0] == '\t'))
|
||||
{
|
||||
dhcpcd.EraseLine(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
dhcpcd.Save(dhcpcdConfig);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void restoreApdDnsmasqConfFile()
|
||||
{
|
||||
@@ -149,6 +144,14 @@ static void restoreApdDnsmasqConfFile()
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
}
|
||||
static void restoreP2pDnsmasqConfFile()
|
||||
{
|
||||
std::filesystem::path path(DNSMASQ_P2P_PATH);
|
||||
if (std::filesystem::exists(path))
|
||||
{
|
||||
std::filesystem::remove(path);
|
||||
}
|
||||
}
|
||||
|
||||
static void UninstallHostApd()
|
||||
{
|
||||
@@ -324,7 +327,7 @@ void pipedal::SetWifiConfig(const WifiConfigSettings &settings)
|
||||
sysExec("rfkill unblock wlan");
|
||||
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " mask wpa_supplicant");
|
||||
// sysExec(SYSTEMCTL_BIN " mask wpa_supplicant");
|
||||
sysExec(SYSTEMCTL_BIN " stop wpa_supplicant");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " unmask hostapd");
|
||||
@@ -339,7 +342,7 @@ void pipedal::SetWifiConfig(const WifiConfigSettings &settings)
|
||||
sysExec(SYSTEMCTL_BIN " enable hostapd");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " stop wpa_supplicant");
|
||||
sysExec(SYSTEMCTL_BIN " mask wpa_supplicant");
|
||||
// sysExec(SYSTEMCTL_BIN " mask wpa_supplicant");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " restart dnsmasq");
|
||||
sysExec(SYSTEMCTL_BIN " enable dnsmasq");
|
||||
@@ -355,9 +358,9 @@ p2p configuration:
|
||||
dnsmaqsq.d/30-pipedal-p2p.conf:
|
||||
|
||||
interface=p2p-wlan0-0
|
||||
dhcp-range=p2p-wlan0,172.24.0.3,172.24.0.127,1h
|
||||
dhcp-range=p2p-wlan0,173.24.0.3,172.23.0.127,1h
|
||||
domain=local
|
||||
address=/pipedal.local/172.24.0.1 # do this through DNS-SD?
|
||||
address=/pipedal.local/172.23.0.2
|
||||
|
||||
except-interface=eth0
|
||||
except-interface=wlan0
|
||||
@@ -368,7 +371,7 @@ dhcpcd.conf:
|
||||
======
|
||||
interface p2p-wlan0-0
|
||||
static ip_address=172.24.0.1/16
|
||||
domain_name_server=172.24.0.1
|
||||
domain_name_servers=172.24.0.1
|
||||
|
||||
Watch resolv.conf to make sure we don't lose DNS servers.
|
||||
************************************************************************************/
|
||||
@@ -378,14 +381,14 @@ void UninstallP2p()
|
||||
{
|
||||
if (IsP2pInstalled())
|
||||
{
|
||||
sysExec(SYSTEMCTL_BIN " stop pipidal_p2pd");
|
||||
sysExec(SYSTEMCTL_BIN " disable pipidal_p2pd");
|
||||
sysExec(SYSTEMCTL_BIN " stop pipedal_p2pd");
|
||||
sysExec(SYSTEMCTL_BIN " disable pipedal_p2pd");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " stop dnsmasq");
|
||||
sysExec(SYSTEMCTL_BIN " disable dnsmasq");
|
||||
|
||||
restoreApdDhcpdConfFile();
|
||||
restoreApdDnsmasqConfFile();
|
||||
restoreP2pDhcpdConfFile();
|
||||
restoreP2pDnsmasqConfFile();
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " enable wpa_supplicant");
|
||||
sysExec(SYSTEMCTL_BIN " start wpa_supplicant");
|
||||
@@ -395,9 +398,11 @@ void UninstallP2p()
|
||||
|
||||
void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
||||
{
|
||||
|
||||
char band;
|
||||
if (!settings.enable_)
|
||||
{
|
||||
cout << "Disabling P2P" << endl;
|
||||
UninstallP2p();
|
||||
}
|
||||
else
|
||||
@@ -419,11 +424,21 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
||||
map["INSTANCE_ID_FILE"] = DEVICE_GUID_FILE;
|
||||
|
||||
|
||||
WriteTemplateFile(map, std::filesystem::path("/etc/pipedal/config/template_p2pd.conf"), PIPEDAL_P2PD_CONF_PATH);
|
||||
WriteTemplateFile(map, PIPEDAL_P2PD_CONF_PATH);
|
||||
|
||||
}
|
||||
// ******************* device_uuid
|
||||
|
||||
DeviceIdFile deviceIdFile;
|
||||
deviceIdFile.Load();
|
||||
deviceIdFile.deviceName = settings.hotspotName_;
|
||||
deviceIdFile.Save();
|
||||
|
||||
// ******************** dsnmasq ******
|
||||
|
||||
std::filesystem::copy_file(DNSMASQ_P2P_SOURCE_PATH, DNSMASQ_P2P_PATH);
|
||||
|
||||
#if JUNK // copy into place instaead.
|
||||
std::filesystem::path dnsMasqPath(DNSMASQ_P2P_PATH);
|
||||
SystemConfigFile dnsMasq;
|
||||
|
||||
@@ -447,15 +462,24 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
||||
|
||||
|
||||
dnsMasq.Set("interface", "p2p-wlan0-0", "Name of the Wi-Fi interface");
|
||||
dnsMasq.Set("listen-address", APD_IP_ADDRESS);
|
||||
dnsMasq.Set("listen-address", P2P_IP_ADDRESS);
|
||||
|
||||
dnsMasq.SetDefault("dhcp-range", P2P_IP_PREFIX ".3," P2P_IP_PREFIX ".127,1h", "dhcp configuration");
|
||||
dnsMasq.SetDefault("domain", "local");
|
||||
std::string strAddress = SS("/" << settings.mdnsName_ << ".local/" P2P_IP_PREFIX << ".2");
|
||||
dnsMasq.Set("address", strAddress);
|
||||
|
||||
dnsMasq.EraseLine("except-interface=eth0");
|
||||
dnsMasq.EraseLine("except-interface=wlan0");
|
||||
dnsMasq.EraseLine("except-interface=lo");
|
||||
|
||||
dnsMasq.AppendLine("except-interface=eth0");
|
||||
dnsMasq.AppendLine("except-interface=wlan0");
|
||||
dnsMasq.AppendLine("except-interface=lo");
|
||||
|
||||
dnsMasq.Save(dnsMasqPath);
|
||||
|
||||
#endif
|
||||
|
||||
// ****** dhcpd.conf ***/
|
||||
std::filesystem::path dhcpcdConfig("/etc/dhcpcd.conf");
|
||||
@@ -518,34 +542,36 @@ void pipedal::SetWifiDirectConfig(const WifiDirectConfigSettings &settings)
|
||||
|
||||
dhcpcd.InsertLine(line++, "interface p2p-wlan0-0");
|
||||
dhcpcd.InsertLine(line++, " static ip_address=" P2P_INTERFACE_ADDR);
|
||||
dhcpcd.InsertLine(line++, " domain_name_servier=" P2P_IP_ADDRESS);
|
||||
dhcpcd.InsertLine(line++, " domain_name_servers=" P2P_IP_ADDRESS);
|
||||
dhcpcd.Save(dhcpcdConfig);
|
||||
}
|
||||
|
||||
// ***** save the config files ***
|
||||
|
||||
dnsMasq.Save(dnsMasqPath);
|
||||
|
||||
// **************** start services ************
|
||||
|
||||
cout << "Starting services." << endl;
|
||||
sysExec("rfkill unblock wlan");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " daemon-reload");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " restart wpa_supplicant");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " restart dnsmasq");
|
||||
sysExec(SYSTEMCTL_BIN " enable dnsmasq");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " restart dhcpcd");
|
||||
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " unmask pipedal_p2pd");
|
||||
cout << "."; cout.flush();
|
||||
if (sysExec(SYSTEMCTL_BIN " restart pipedal_p2pd") != 0)
|
||||
{
|
||||
throw PiPedalException("Unable to start the pipedal_p2pd.");
|
||||
}
|
||||
if (sysExec("systemctl is-active --quiet pipedal_p2pd") != 0)
|
||||
{
|
||||
throw PiPedalException("Unable to start the access point.");
|
||||
}
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " enable pipedal_p2pd");
|
||||
|
||||
sysExec(SYSTEMCTL_BIN " restart dnsmasq");
|
||||
sysExec(SYSTEMCTL_BIN " enable dnsmasq");
|
||||
}
|
||||
cout << "Ready." << endl;
|
||||
}
|
||||
|
||||
void pipedal::OnWifiUninstall()
|
||||
|
||||
@@ -23,8 +23,6 @@
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
uint32_t ChannelToWifiFrequency(const std::string &channel);
|
||||
uint32_t ChannelToWifiFrequency(uint32_t channel);
|
||||
void SetWifiConfig(const WifiConfigSettings&settings);
|
||||
void SetWifiDirectConfig(const WifiDirectConfigSettings&settings);
|
||||
|
||||
|
||||
@@ -1,235 +0,0 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "pch.h"
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "PiPedalException.hpp"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "Lv2Log.hpp"
|
||||
#include <sstream>
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
|
||||
|
||||
extern uint16_t g_ShutdownPort; // set in main.cpp
|
||||
|
||||
|
||||
bool ShutdownClient::CanUseShutdownClient()
|
||||
{
|
||||
return g_ShutdownPort != 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool ShutdownClient::RequestShutdown(bool restart)
|
||||
{
|
||||
const char*message = restart? "restart\n": "shutdown\n";
|
||||
return WriteMessage(message);
|
||||
}
|
||||
|
||||
bool ShutdownClient::WriteMessage(const char*message) {
|
||||
|
||||
uint16_t shutdownServerPort = g_ShutdownPort;
|
||||
if (g_ShutdownPort == 0)
|
||||
{
|
||||
throw PiPedalException("No shutdown server available.");
|
||||
}
|
||||
|
||||
struct sockaddr_in serv_addr;
|
||||
|
||||
memset(&serv_addr,0,sizeof(serv_addr));
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(shutdownServerPort);
|
||||
if (inet_pton(AF_INET,"127.0.0.1",&serv_addr.sin_addr) <= 0)
|
||||
{
|
||||
Lv2Log::error("Failed to parse socket address.");
|
||||
return false;
|
||||
}
|
||||
int sock = socket(AF_INET,SOCK_STREAM,0);
|
||||
if (sock < 0)
|
||||
{
|
||||
Lv2Log::error("Can't create socket.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (connect(sock,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "Connect to 127.0.0.1:" << shutdownServerPort << " failed.";
|
||||
Lv2Log::error(s.str());
|
||||
close(sock);
|
||||
return false;
|
||||
}
|
||||
int length = strlen(message);
|
||||
const char *p = message;
|
||||
|
||||
bool success = true;
|
||||
while (length != 0) {
|
||||
auto nWritten = write(sock,p,length);
|
||||
if (nWritten < 0)
|
||||
{
|
||||
success = false;
|
||||
Lv2Log::error("Shutdown server write failed.");
|
||||
close(sock);
|
||||
return false;
|
||||
}
|
||||
p += nWritten;
|
||||
length -= nWritten;
|
||||
}
|
||||
shutdown(sock, SHUT_WR);
|
||||
char responseBuffer[1024];
|
||||
ssize_t available = sizeof(responseBuffer);
|
||||
char *pWrite = responseBuffer;
|
||||
char*pEndOfLine = responseBuffer;
|
||||
|
||||
bool eolFound = false;
|
||||
while (!eolFound)
|
||||
{
|
||||
ssize_t nRead = read(sock,pWrite,available);
|
||||
if (nRead == -1)
|
||||
{
|
||||
*pWrite = 0;
|
||||
break;
|
||||
}
|
||||
if (nRead <= 0) {
|
||||
Lv2Log::error("Failed to read shutdown server response.");
|
||||
close(sock);
|
||||
return false;
|
||||
|
||||
}
|
||||
pWrite += nRead;
|
||||
available -= nRead;
|
||||
if (available == 0)
|
||||
{
|
||||
Lv2Log::error("Bad response from shutdown server.");
|
||||
close(sock);
|
||||
return false;
|
||||
}
|
||||
|
||||
while (pEndOfLine != pWrite)
|
||||
{
|
||||
if (*pEndOfLine++ == '\n')
|
||||
{
|
||||
eolFound = true;
|
||||
pEndOfLine[-1] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
int response = atoi(responseBuffer);
|
||||
close(sock);
|
||||
if (response == -2) // throw exception with message
|
||||
{
|
||||
const char *p = responseBuffer;
|
||||
while (*p != ' ' && *p != '\n' && *p != '\0')
|
||||
{
|
||||
++p;
|
||||
}
|
||||
if (*p != 0) ++p;
|
||||
throw PiPedalStateException(p);
|
||||
}
|
||||
return response == 0;
|
||||
}
|
||||
|
||||
bool ShutdownClient::SetJackServerConfiguration(const JackServerSettings & jackServerSettings)
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "setJackConfiguration ";
|
||||
|
||||
json_writer writer(s,true);
|
||||
writer.write(jackServerSettings);
|
||||
s << std::endl;
|
||||
return WriteMessage(s.str().c_str());
|
||||
}
|
||||
|
||||
|
||||
void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't perform this operation when debugging.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "WifiConfigSettings ";
|
||||
json_writer writer(cmd,true);
|
||||
writer.write(settings);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result) { // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownClient::SetGovernorSettings(const std::string & settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't use ShutdownClient when running interactively.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "GovernorSettings ";
|
||||
json_writer writer(cmd,true);
|
||||
writer.write(settings);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result) { // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
}
|
||||
|
||||
void ShutdownClient::MonitorGovernor(const std::string &governor)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "MonitorGovernor ";
|
||||
json_writer writer(cmd,true);
|
||||
writer.write(governor);
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result) { // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
|
||||
}
|
||||
void ShutdownClient::UnmonitorGovernor()
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
return;
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "UnmonitorGovernor";
|
||||
cmd << '\n';
|
||||
bool result = WriteMessage(cmd.str().c_str());
|
||||
if (!result) { // unexpected. Should throw exception on failure.
|
||||
throw PiPedalException("Operation failed.");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 "UnixSocket.hpp"
|
||||
#include <atomic>
|
||||
#include <filesystem>
|
||||
#include <grp.h>
|
||||
#include <stdexcept>
|
||||
#include "gsl/util"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/un.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include "ss.hpp"
|
||||
|
||||
using namespace std;
|
||||
namespace pipedal
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class UnixSocketData
|
||||
{
|
||||
public:
|
||||
UnixSocketData()
|
||||
{
|
||||
memset(&localAddress, 0, sizeof(localAddress));
|
||||
memset(&remoteAddress, 0, sizeof(remoteAddress));
|
||||
localAddress.sun_family = AF_UNIX;
|
||||
remoteAddress.sun_family = AF_UNIX;
|
||||
}
|
||||
int socket = -1;
|
||||
struct sockaddr_un localAddress;
|
||||
struct sockaddr_un remoteAddress;
|
||||
};
|
||||
}
|
||||
}
|
||||
using namespace pipedal;
|
||||
using namespace pipedal::detail;
|
||||
using namespace gsl;
|
||||
|
||||
|
||||
bool UnixSocket::IsOpen() const { return data->socket != -1; }
|
||||
|
||||
UnixSocketException::UnixSocketException(int errno_)
|
||||
: what_(strerror(errno_)), errno_(errno_)
|
||||
{
|
||||
}
|
||||
|
||||
UnixSocketException::UnixSocketException(const std::string what_, int errno_)
|
||||
: what_(what_ + " " + strerror(errno_) + ")"), errno_(errno_)
|
||||
{
|
||||
}
|
||||
UnixSocketException::UnixSocketException(const std::string what_)
|
||||
: what_(what_), errno_(0)
|
||||
{
|
||||
}
|
||||
|
||||
void UnixSocket::Bind(const std::string &socketName, const std::string &permissionGroup)
|
||||
{
|
||||
if (socketName.length() >= sizeof(data->localAddress.sun_path) - 1)
|
||||
{
|
||||
throw UnixSocketException("Socket name too long.", E2BIG);
|
||||
}
|
||||
int s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
auto socket_cleanup = finally([&]() {
|
||||
if (s != -1)
|
||||
{
|
||||
close(s);
|
||||
s = -1;
|
||||
}
|
||||
});
|
||||
strcpy(data->localAddress.sun_path, socketName.c_str());
|
||||
|
||||
for (int retry = 0; /**/; ++retry)
|
||||
{
|
||||
int err = bind(s, (struct sockaddr *)&data->localAddress, sizeof(data->localAddress));
|
||||
|
||||
if (err < 0)
|
||||
{
|
||||
if (retry != 2)
|
||||
{
|
||||
unlink(data->localAddress.sun_path);
|
||||
continue;
|
||||
}
|
||||
throw UnixSocketException("Can't bind socket " + socketName, errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (permissionGroup != "")
|
||||
{
|
||||
gid_t gid;
|
||||
struct group *group_;
|
||||
group_ = getgrnam(permissionGroup.c_str());
|
||||
if (group_ == nullptr)
|
||||
{
|
||||
throw UnixSocketException("Group not found.");
|
||||
}
|
||||
gid = group_->gr_gid;
|
||||
|
||||
chown(data->localAddress.sun_path, -1, gid);
|
||||
chmod(data->localAddress.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
}
|
||||
|
||||
data->socket = s;
|
||||
s = -1;
|
||||
}
|
||||
|
||||
UnixSocket::UnixSocket()
|
||||
{
|
||||
data = new UnixSocketData();
|
||||
}
|
||||
|
||||
void UnixSocket::Close()
|
||||
{
|
||||
if (data->socket != -1)
|
||||
{
|
||||
close(data->socket);
|
||||
unlink(data->localAddress.sun_path);
|
||||
}
|
||||
}
|
||||
UnixSocket::~UnixSocket()
|
||||
{
|
||||
Close();
|
||||
delete data;
|
||||
}
|
||||
|
||||
static std::atomic<uint64_t> instanceId;
|
||||
|
||||
void UnixSocket::Connect(const std::string &remoteSocketName, const std::string &permissionGroup)
|
||||
{
|
||||
|
||||
const std::string localSocketName =
|
||||
SS("/tmp/ppadmin-" << getpid() << "-" << (instanceId++));
|
||||
|
||||
if (localSocketName.length() >= sizeof(data->localAddress.sun_path) - 1)
|
||||
{
|
||||
throw UnixSocketException("Local socket path is too long. ", E2BIG);
|
||||
}
|
||||
strcpy(data->localAddress.sun_path, localSocketName.c_str());
|
||||
|
||||
int s = socket(PF_UNIX, SOCK_DGRAM, 0);
|
||||
auto socket_cleanup = finally([&]() {
|
||||
if (s != -1)
|
||||
{
|
||||
close(s);
|
||||
s = -1;
|
||||
unlink(data->localAddress.sun_path);
|
||||
}
|
||||
});
|
||||
|
||||
int e = bind(s, (sockaddr *)&data->localAddress, sizeof(data->localAddress));
|
||||
|
||||
if (permissionGroup.length() != 0)
|
||||
{
|
||||
struct group *g = getgrnam(permissionGroup.c_str());
|
||||
if (g == nullptr)
|
||||
{
|
||||
throw UnixSocketException("Group not found");
|
||||
}
|
||||
gid_t gid = g->gr_gid;
|
||||
|
||||
chown(data->localAddress.sun_path, -1, gid);
|
||||
chmod(data->localAddress.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
|
||||
}
|
||||
|
||||
strcpy(data->remoteAddress.sun_path, remoteSocketName.c_str());
|
||||
e = connect(s, (sockaddr *)&data->remoteAddress, sizeof(data->remoteAddress));
|
||||
if (e < 0)
|
||||
{
|
||||
throw UnixSocketException("Can't connect to socket " + remoteSocketName, errno);
|
||||
}
|
||||
data->socket = s;
|
||||
s = -1;
|
||||
}
|
||||
|
||||
size_t UnixSocket::Send(const void *buffer, size_t length)
|
||||
{
|
||||
ssize_t size = send(data->socket, buffer, length, 0);
|
||||
if (size < 0)
|
||||
{
|
||||
throw UnixSocketException(errno);
|
||||
}
|
||||
return (size_t)size;
|
||||
}
|
||||
|
||||
size_t UnixSocket::Receive(void *buffer, size_t length)
|
||||
{
|
||||
ssize_t received = recv(data->socket, buffer, length, 0);
|
||||
if (received < 0)
|
||||
{
|
||||
throw UnixSocketException(errno);
|
||||
}
|
||||
return (size_t)received;
|
||||
}
|
||||
|
||||
size_t UnixSocket::ReceiveFrom(void *buffer, size_t length, std::string *pFrom)
|
||||
{
|
||||
sockaddr_un sockAddr;
|
||||
socklen_t sockAddrLen = sizeof(sockAddr);
|
||||
|
||||
ssize_t received = recvfrom(data->socket, buffer, length, 0, (sockaddr *)&sockAddr, &sockAddrLen);
|
||||
if (received < 0)
|
||||
{
|
||||
throw UnixSocketException(errno);
|
||||
}
|
||||
*pFrom = std::string(sockAddr.sun_path);
|
||||
return (size_t)received;
|
||||
}
|
||||
|
||||
size_t UnixSocket::SendTo(const void *buffer, size_t length, const std::string &toAddress)
|
||||
{
|
||||
sockaddr_un sockAddr;
|
||||
if (toAddress.length() >= sizeof(sockAddr.sun_path) - 1)
|
||||
{
|
||||
throw UnixSocketException("Address too long.", E2BIG);
|
||||
}
|
||||
strcpy(sockAddr.sun_path, toAddress.c_str());
|
||||
sockAddr.sun_family = AF_UNIX;
|
||||
|
||||
ssize_t size = sendto(data->socket, buffer, length, 0, (sockaddr *)&sockAddr, sizeof(sockaddr_un));
|
||||
if (size < 0)
|
||||
{
|
||||
throw UnixSocketException(errno);
|
||||
}
|
||||
return (size_t)size;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 <string>
|
||||
#include <exception>
|
||||
|
||||
struct sockaddr_un;
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class UnixSocketException : public std::exception {
|
||||
public:
|
||||
UnixSocketException(int errno_);
|
||||
UnixSocketException(const std::string what_,int errno_);
|
||||
UnixSocketException(const std::string what_);
|
||||
|
||||
const char*what() const noexcept { return what_.c_str(); }
|
||||
|
||||
int get_errno() const { return errno_; }
|
||||
private:
|
||||
int errno_;
|
||||
std::string what_;
|
||||
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
class UnixSocketData;
|
||||
}
|
||||
class UnixSocket {
|
||||
public:
|
||||
using sockaddr_t = sockaddr_un;
|
||||
|
||||
UnixSocket();
|
||||
~UnixSocket();
|
||||
|
||||
bool IsOpen() const;
|
||||
|
||||
/**
|
||||
* @brief Prepare a server socket to recive data.
|
||||
*
|
||||
* permissionGroup controls permissions on the socekt.
|
||||
* Proceses that wish to read or write to the socket must belong to permissionGroup.
|
||||
* @param socketName Server socket name.
|
||||
* @param permissionGroup The group which is allowed to connect to this socket.
|
||||
*/
|
||||
void Bind(const std::string&socketName,const std::string&permissionGroup);
|
||||
|
||||
/**
|
||||
* @brief Prepare a socket to write to a server socket.
|
||||
*
|
||||
* The optional groupPermission is applied to the client socket to allow
|
||||
* server process that are not highly privileged to write replies. The
|
||||
* server process must belong the group named by permissionGroup.
|
||||
*
|
||||
* @param remoteSocketName The name of the server socket.
|
||||
* @param permissionGroup` The permission to appy to the client socket.
|
||||
*/
|
||||
void Connect(const std::string&remoteSocketName, const std::string &groupPermission = "");
|
||||
|
||||
void Close();
|
||||
|
||||
|
||||
size_t Send(const void*buffer, size_t length);
|
||||
size_t Receive(void *buffer, size_t length);
|
||||
|
||||
size_t ReceiveFrom(void*buffer, size_t length,std::string*fromAddress);
|
||||
size_t SendTo(const void*buffer, size_t length,const std::string&toAddress);
|
||||
|
||||
|
||||
private:
|
||||
detail::UnixSocketData *data;
|
||||
};
|
||||
|
||||
};
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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 "catch.hpp"
|
||||
#include "UnixSocket.hpp"
|
||||
#include "ss.hpp"
|
||||
#include <unistd.h>
|
||||
#include <cassert>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
|
||||
TEST_CASE( "Unix Socket Test", "[unix_socket_test][dev]" ) {
|
||||
UnixSocket serverSocket;
|
||||
UnixSocket clientSocket;
|
||||
|
||||
std::string serverSocketName = SS("/tmp/ServerSocketTest-Server-" << getpid() << "-0");
|
||||
|
||||
char buffer[1024];
|
||||
serverSocket.Bind(serverSocketName,"pipedal_d");
|
||||
clientSocket.Connect(serverSocketName,"pipedal_d");
|
||||
|
||||
std::string testData = "abc123";
|
||||
clientSocket.Send(testData.c_str(),testData.length());
|
||||
|
||||
size_t length = serverSocket.Receive(buffer,sizeof(buffer));
|
||||
assert(length == testData.length());
|
||||
|
||||
buffer[length] = 0;
|
||||
assert(testData == buffer);
|
||||
|
||||
clientSocket.Send(testData.c_str(),testData.length());
|
||||
|
||||
std::string fromAddress;
|
||||
length = serverSocket.ReceiveFrom(buffer,sizeof(buffer),&fromAddress);
|
||||
|
||||
serverSocket.SendTo(buffer,length,fromAddress);
|
||||
|
||||
size_t length2 = clientSocket.Receive(buffer,length);
|
||||
assert(length == length2);
|
||||
buffer[length2] = 0;
|
||||
assert(testData == std::string(buffer));
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -44,11 +44,71 @@ bool WifiConfigSettings::ValidateCountryCode(const std::string&value)
|
||||
}
|
||||
|
||||
|
||||
bool WifiConfigSettings::ValidateChannel(const std::string&arguments)
|
||||
uint32_t pipedal::ChannelToWifiFrequency(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);
|
||||
if (size != t.length())
|
||||
{
|
||||
throw invalid_argument("Expecting a number: '" + t + "'.");
|
||||
}
|
||||
return ChannelToWifiFrequency((uint32_t)lChannel);
|
||||
}
|
||||
|
||||
uint32_t pipedal::ChannelToWifiFrequency(uint32_t channel)
|
||||
{
|
||||
if (channel > 1000) // must be a frequency.
|
||||
{
|
||||
return channel;
|
||||
}
|
||||
// 2.4GHz.
|
||||
if (channel >= 1 && channel <= 13)
|
||||
{
|
||||
return 2412 + 5*(channel-1);
|
||||
}
|
||||
if (channel == 14)
|
||||
{
|
||||
return 2484;
|
||||
}
|
||||
// 802.11y
|
||||
if (channel >= 131 && channel < 137)
|
||||
{
|
||||
return 3660 + (channel-131)*5;
|
||||
}
|
||||
if (channel >= 32 && channel <= 68 && (channel & 1) == 0)
|
||||
{
|
||||
return 5160 + (channel-32)/2*10;
|
||||
}
|
||||
if (channel == 96) return 5480;
|
||||
|
||||
if (channel >= 100 && channel <= 196)
|
||||
{
|
||||
return 5500 + (channel-100)/5;
|
||||
}
|
||||
throw invalid_argument(SS("Invalid channel: " << channel));
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool WifiConfigSettings::ValidateChannel(const std::string&value)
|
||||
{
|
||||
// 1) frequency in khz.
|
||||
// 2) unadorned channel number 1, 2,3 &c.
|
||||
// 3) With band annotated: g1, a51.
|
||||
try {
|
||||
ChannelToWifiFrequency(value);
|
||||
return true;
|
||||
} catch (const std::string&/**/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
// come back to this.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
|
||||
uint32_t ChannelToWifiFrequency(const std::string &channel);
|
||||
uint32_t ChannelToWifiFrequency(uint32_t channel);
|
||||
|
||||
class WifiConfigSettings {
|
||||
public:
|
||||
bool valid_ = false;
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "WifiConfigSettings.hpp"
|
||||
#include <stdexcept>
|
||||
#include <random>
|
||||
#include "ConfigUtil.hpp"
|
||||
#include "DeviceIdFile.hpp"
|
||||
|
||||
|
||||
using namespace pipedal;
|
||||
using namespace std;
|
||||
@@ -71,17 +74,48 @@ static void ValidatePin(const std::string&pin)
|
||||
void WifiDirectConfigSettings::ParseArguments(const std::vector<std::string> &arguments)
|
||||
{
|
||||
this->valid_ = false;
|
||||
if (arguments.size() < 2 || arguments.size() > 4)
|
||||
{
|
||||
throw invalid_argument("Incorrect number of arguments supplied");
|
||||
}
|
||||
|
||||
this->enable_ = true;
|
||||
|
||||
this->countryCode_ = arguments[0];
|
||||
this->hotspotName_ = arguments[1];
|
||||
this->pin_ = arguments.size() >= 3 ? arguments[2] : "";
|
||||
this->channel_ = arguments.size() >= 4? arguments[3]: "";
|
||||
if (arguments.size() == 0)
|
||||
{
|
||||
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","country_code",&this->countryCode_))
|
||||
{
|
||||
throw invalid_argument("Default value for country code not found.");
|
||||
}
|
||||
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","p2p_pin",&this->pin_))
|
||||
{
|
||||
throw invalid_argument("Default value for pin not found.");
|
||||
}
|
||||
if (!ConfigUtil::GetConfigLine("/etc/pipedal/config/pipedal_p2pd.conf","wifiGroupFrequency",&this->channel_))
|
||||
{
|
||||
throw invalid_argument("Default value for pin not found.");
|
||||
}
|
||||
try {
|
||||
DeviceIdFile deviceIdFile;
|
||||
deviceIdFile.Load();
|
||||
if (deviceIdFile.deviceName == "")
|
||||
{
|
||||
throw std::invalid_argument("");
|
||||
}
|
||||
this->hotspotName_ = deviceIdFile.deviceName;
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
throw std::invalid_argument("Default value for device name not found.");
|
||||
}
|
||||
} else {
|
||||
if (arguments.size() < 2 || arguments.size() > 4)
|
||||
{
|
||||
throw invalid_argument("Incorrect number of arguments supplied");
|
||||
}
|
||||
this->countryCode_ = arguments[0];
|
||||
this->hotspotName_ = arguments[1];
|
||||
this->pin_ = arguments.size() >= 3 ? arguments[2] : "";
|
||||
this->channel_ = arguments.size() >= 4? arguments[3]: "";
|
||||
}
|
||||
if (this->channel_ == "") {
|
||||
this->channel_ = "1";
|
||||
}
|
||||
size_t maxLength = 32-string("DIRECT-XX-").length();
|
||||
if (hotspotName_.size() >= maxLength) { throw invalid_argument("Device name is too long."); }
|
||||
if (hotspotName_.size() < 1) { throw invalid_argument("Device name is too short."); }
|
||||
|
||||
@@ -17,48 +17,69 @@
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
#include "pch.h"
|
||||
|
||||
#include "WriteTemplateFile.hpp"
|
||||
#include <fstream>
|
||||
#include "PiPedalException.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
void pipedal::WriteTemplateFile(
|
||||
const std::map<std::string, std::string> &map,
|
||||
const std::filesystem::path &outputFile)
|
||||
{
|
||||
std::string inputFile = "/etc/pipedal/config/templates/" + outputFile.filename().string() + ".template";
|
||||
WriteTemplateFile(map, inputFile,outputFile);
|
||||
}
|
||||
|
||||
void pipedal::WriteTemplateFile(
|
||||
const std::map<std::string,std::string> &map,
|
||||
std::filesystem::path inputFile,
|
||||
std::filesystem::path outputFile)
|
||||
const std::map<std::string, std::string> &map,
|
||||
const std::filesystem::path &inputFile,
|
||||
const std::filesystem::path &outputFile)
|
||||
{
|
||||
std::ofstream out(outputFile);
|
||||
std::ifstream in(inputFile);
|
||||
|
||||
if (!in.is_open())
|
||||
{
|
||||
throw PiPedalArgumentException("File not found: " + inputFile.string());
|
||||
}
|
||||
|
||||
while (in.peek() != -1)
|
||||
{
|
||||
char c = in.get();
|
||||
if (c == '$')
|
||||
{
|
||||
if (in.peek() == '{') {
|
||||
if (in.peek() == '{')
|
||||
{
|
||||
in.get();
|
||||
|
||||
std::stringstream sName;
|
||||
try {
|
||||
try
|
||||
{
|
||||
while ((c = in.get()) != '}')
|
||||
{
|
||||
sName.put(c);
|
||||
}
|
||||
} catch (const std::exception&)
|
||||
}
|
||||
catch (const std::exception &)
|
||||
{
|
||||
throw PiPedalException("Unexpected end of file. Expecting '}'.");
|
||||
}
|
||||
std::string s = map.at(sName.str());
|
||||
out << s;
|
||||
} else if (in.peek() == '$')
|
||||
}
|
||||
else if (in.peek() == '$')
|
||||
{
|
||||
out.put(in.get());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
out.put(c);
|
||||
}
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
out.put(c);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,21 @@
|
||||
namespace pipedal {
|
||||
void WriteTemplateFile(
|
||||
const std::map<std::string,std::string> &map,
|
||||
std::filesystem::path inputFile,
|
||||
std::filesystem::path outputFile);
|
||||
const std::filesystem::path& inputFile,
|
||||
const std::filesystem::path& outputFile);
|
||||
|
||||
/**
|
||||
* @brief Write template file.
|
||||
*
|
||||
* The input file is
|
||||
*
|
||||
* /etc/pipedal/config/template/<filename>.template
|
||||
*
|
||||
* @param map Dictionary of values to substitute.
|
||||
* @param outputFile The full path of the output file.
|
||||
*/
|
||||
void WriteTemplateFile(
|
||||
const std::map<std::string,std::string> &map,
|
||||
const std::filesystem::path &outputFile);
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#include "bluez_proxy.h"
|
||||
|
||||
|
||||
namespace org { namespace bluez {
|
||||
|
||||
|
||||
using BleDevice_Interfaces = sdbus::ProxyInterfaces<
|
||||
org::bluez::LEAdvertisingManager1_proxy,
|
||||
org::bluez::NetworkServer1_proxy,
|
||||
org::bluez::GattManager1_proxy
|
||||
>;
|
||||
|
||||
class BleDeviceProxy : public BleDevice_Interfaces
|
||||
{
|
||||
public:
|
||||
BleDeviceProxy(std::string devicePath)
|
||||
: BleDevice_Interfaces("org.bluez",std::move(devicePath))
|
||||
{
|
||||
registerProxy();
|
||||
}
|
||||
~BleDeviceProxy()
|
||||
{
|
||||
unregisterProxy();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}}; // namesapce
|
||||
@@ -1,276 +0,0 @@
|
||||
<!--
|
||||
Copyright 2015 Intel Corporation All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
******************************************************************
|
||||
|
||||
The introspection XML found in this file is used to generate GDBus
|
||||
skeleton code that will be used by the IoTivity BlueZ-based GATT
|
||||
Service (OIC Transport Profile) implementation.
|
||||
|
||||
See the GATT and LE Advertisement API documentation in the BlueZ
|
||||
gatt-api.txt and advertisement-api.txt documents, respectively for
|
||||
further details.
|
||||
-->
|
||||
|
||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||
<node name="/org/pipedald/gatt/service">
|
||||
|
||||
<!--
|
||||
***********************************************
|
||||
BlueZ GATT Service interface introspection XML.
|
||||
***********************************************
|
||||
-->
|
||||
<interface name="org.bluez.GattService1">
|
||||
|
||||
<property name="UUID" type="s" access="read"/>
|
||||
<property name="Primary" type="b" access="read"/>
|
||||
<property name="Characteristics" type="ao" access="read"/>
|
||||
|
||||
<!--
|
||||
===========================================================
|
||||
The "Device" property is only exposed on the client side by
|
||||
BlueZ itself. It isn't set by the IoTivity server side.
|
||||
Don't bother generating skeleton code for it.
|
||||
===========================================================
|
||||
<property name="Device" type="o" access="read">
|
||||
</property>
|
||||
|
||||
===========================================================
|
||||
The "Includes" property is not supported as of BlueZ 5.30.
|
||||
It also isn't used by the IoTivity server side
|
||||
implementation. Don't bother generating skeleton code for
|
||||
it.
|
||||
===========================================================
|
||||
<property name="Includes" type="ao" access="read"/>
|
||||
-->
|
||||
|
||||
</interface>
|
||||
|
||||
<!--
|
||||
******************************************************
|
||||
BlueZ GATT Characteristic interface introspection XML.
|
||||
******************************************************
|
||||
-->
|
||||
<interface name="org.bluez.GattCharacteristic1">
|
||||
<!--
|
||||
============================================================
|
||||
None of the OIC GATT characteristics support the "ReadValue"
|
||||
method. Don't bother generating skeleton code for it.
|
||||
============================================================
|
||||
<method name="ReadValue">
|
||||
<arg name="value" type="ay" direction="out"/>
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</method>
|
||||
-->
|
||||
|
||||
<method name="WriteValue">
|
||||
<arg name="value" type="ay" direction="in">
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
<method name="StartNotify"/>
|
||||
|
||||
<method name="StopNotify"/>
|
||||
|
||||
|
||||
<property name="UUID" type="s" access="read"/>
|
||||
<property name="Service" type="o" access="read"/>
|
||||
|
||||
<property name="Value" type="ay" access="read">
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</property>
|
||||
|
||||
<property name="Notifying" type="b" access="read">
|
||||
</property>
|
||||
<property name="Flags" type="as" access="read"/>
|
||||
<property name="Descriptors" type="ao" access="read"/>
|
||||
</interface>
|
||||
|
||||
<!--
|
||||
**************************************************
|
||||
BlueZ GATT Descriptor interface introspection XML.
|
||||
**************************************************
|
||||
-->
|
||||
<interface name="org.bluez.GattDescriptor1">
|
||||
<method name="ReadValue">
|
||||
<arg name="value" type="ay" direction="out">
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
============================================================
|
||||
None of the OIC GATT descriptors directly supported by
|
||||
IoTivity support the "WriteValue" method. The OIC Client
|
||||
Characteristic Configuration Descriptor supports writes, but
|
||||
that descriptor is handled by BlueZ, not IoTivity, when the
|
||||
"notify" property is set on a given GATT characteristic.
|
||||
Don't bother generating skeleton code for it.
|
||||
============================================================
|
||||
|
||||
<method name="WriteValue">
|
||||
<arg name="value" type="ay" direction="in">
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</arg>
|
||||
</method>
|
||||
-->
|
||||
|
||||
|
||||
<property name="UUID" type="s" access="read"/>
|
||||
<property name="Characteristic" type="o" access="read"/>
|
||||
|
||||
<property name="Value" type="ay" access="read">
|
||||
<annotation name="org.gtk.GDBus.C.ForceGVariant" value="true"/>
|
||||
</property>
|
||||
|
||||
<property name="Flags" type="as" access="read"/>
|
||||
</interface>
|
||||
|
||||
<!--
|
||||
***************************************************
|
||||
BlueZ LE Advertisement interface introspection XML.
|
||||
***************************************************
|
||||
-->
|
||||
<interface name="org.bluez.LEAdvertisement1">
|
||||
<method name="Release">
|
||||
<annotation name="org.freedesktop.DBus.Method.NoReply" value="true"/>
|
||||
</method>
|
||||
|
||||
|
||||
<property name="Type" type="s" access="read"/>
|
||||
<property name="ServiceUUIDs" type="as" access="read"/>
|
||||
<property name="ManufacturerData" type="a{sv}" access="read"/>
|
||||
<property name="SolicitUUIDs" type="as" access="read"/>
|
||||
<property name="ServiceData" type="a{sv}" access="read"/>
|
||||
<property name="IncludeTxPower" type="b" access="read"/>
|
||||
</interface>
|
||||
|
||||
<!--
|
||||
**************************************
|
||||
BlueZ LE instance interfaces.
|
||||
**************************************
|
||||
-->
|
||||
|
||||
<interface name="org.freedesktop.DBus.Introspectable">
|
||||
<method name="Introspect">
|
||||
<arg name="xml" type="s" direction="out"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.bluez.Adapter1">
|
||||
<method name="StartDiscovery"></method>
|
||||
<method name="SetDiscoveryFilter">
|
||||
<arg name="properties" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="StopDiscovery"></method>
|
||||
<method name="RemoveDevice">
|
||||
<arg name="device" type="o" direction="in"/>
|
||||
</method>
|
||||
<method name="GetDiscoveryFilters">
|
||||
<arg name="filters" type="as" direction="out"/>
|
||||
</method>
|
||||
<property name="Address" type="s" access="read"></property>
|
||||
<property name="AddressType" type="s" access="read"></property>
|
||||
<property name="Name" type="s" access="read"></property>
|
||||
<property name="Alias" type="s" access="readwrite"></property>
|
||||
<property name="Class" type="u" access="read"></property>
|
||||
<property name="Powered" type="b" access="readwrite"></property>
|
||||
<property name="Discoverable" type="b" access="readwrite"></property>
|
||||
<property name="DiscoverableTimeout" type="u" access="readwrite"></property>
|
||||
<property name="Pairable" type="b" access="readwrite"></property>
|
||||
<property name="PairableTimeout" type="u" access="readwrite"></property>
|
||||
<property name="Discovering" type="b" access="read"></property>
|
||||
<property name="UUIDs" type="as" access="read"></property>
|
||||
<property name="Modalias" type="s" access="read"></property>
|
||||
<property name="Roles" type="as" access="read"></property>
|
||||
</interface>
|
||||
<interface name="org.freedesktop.DBus.Properties">
|
||||
<method name="Get">
|
||||
<arg name="interface" type="s" direction="in"/>
|
||||
<arg name="name" type="s" direction="in"/>
|
||||
<arg name="value" type="v" direction="out"/>
|
||||
</method>
|
||||
<method name="Set">
|
||||
<arg name="interface" type="s" direction="in"/>
|
||||
<arg name="name" type="s" direction="in"/>
|
||||
<arg name="value" type="v" direction="in"/>
|
||||
</method>
|
||||
<method name="GetAll">
|
||||
<arg name="interface" type="s" direction="in"/>
|
||||
<arg name="properties" type="a{sv}" direction="out"/>
|
||||
</method>
|
||||
<signal name="PropertiesChanged">
|
||||
<arg name="interface" type="s"/>
|
||||
<arg name="changed_properties" type="a{sv}"/>
|
||||
<arg name="invalidated_properties" type="as"/>
|
||||
</signal>
|
||||
</interface>
|
||||
<interface name="org.bluez.GattManager1">
|
||||
<method name="RegisterApplication">
|
||||
<arg name="application" type="o" direction="in"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="UnregisterApplication">
|
||||
<arg name="application" type="o" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.bluez.LEAdvertisingManager1">
|
||||
<method name="RegisterAdvertisement">
|
||||
<arg name="advertisement" type="o" direction="in"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="UnregisterAdvertisement">
|
||||
<arg name="service" type="o" direction="in"/>
|
||||
</method>
|
||||
<property name="ActiveInstances" type="y" access="read"></property>
|
||||
<property name="SupportedInstances" type="y" access="read"></property>
|
||||
<property name="SupportedIncludes" type="as" access="read"></property>
|
||||
<property name="SupportedSecondaryChannels" type="as" access="read"></property>
|
||||
</interface>
|
||||
<interface name="org.bluez.Media1">
|
||||
<method name="RegisterEndpoint">
|
||||
<arg name="endpoint" type="o" direction="in"/>
|
||||
<arg name="properties" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="UnregisterEndpoint">
|
||||
<arg name="endpoint" type="o" direction="in"/>
|
||||
</method>
|
||||
<method name="RegisterPlayer">
|
||||
<arg name="player" type="o" direction="in"/>
|
||||
<arg name="properties" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="UnregisterPlayer">
|
||||
<arg name="player" type="o" direction="in"/>
|
||||
</method>
|
||||
<method name="RegisterApplication">
|
||||
<arg name="application" type="o" direction="in"/>
|
||||
<arg name="options" type="a{sv}" direction="in"/>
|
||||
</method>
|
||||
<method name="UnregisterApplication">
|
||||
<arg name="application" type="o" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
<interface name="org.bluez.NetworkServer1">
|
||||
<method name="Register">
|
||||
<arg name="uuid" type="s" direction="in"/>
|
||||
<arg name="bridge" type="s" direction="in"/>
|
||||
</method>
|
||||
<method name="Unregister">
|
||||
<arg name="uuid" type="s" direction="in"/>
|
||||
</method>
|
||||
</interface>
|
||||
|
||||
</node>
|
||||
@@ -1,428 +0,0 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp___home_pi_src_pipedal_src_dbus_bluez_adaptor_h__adaptor__H__
|
||||
#define __sdbuscpp___home_pi_src_pipedal_src_dbus_bluez_adaptor_h__adaptor__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattService1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattService1";
|
||||
|
||||
protected:
|
||||
GattService1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerProperty("UUID").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUID(); });
|
||||
object_.registerProperty("Primary").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Primary(); });
|
||||
object_.registerProperty("Characteristics").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Characteristics(); });
|
||||
}
|
||||
|
||||
~GattService1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual std::string UUID() = 0;
|
||||
virtual bool Primary() = 0;
|
||||
virtual std::vector<sdbus::ObjectPath> Characteristics() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattCharacteristic1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattCharacteristic1";
|
||||
|
||||
protected:
|
||||
GattCharacteristic1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("WriteValue").onInterface(INTERFACE_NAME).withInputParamNames("value").implementedAs([this](const std::vector<uint8_t>& value){ return this->WriteValue(value); });
|
||||
object_.registerMethod("StartNotify").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StartNotify(); });
|
||||
object_.registerMethod("StopNotify").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StopNotify(); });
|
||||
object_.registerProperty("UUID").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUID(); });
|
||||
object_.registerProperty("Service").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Service(); });
|
||||
object_.registerProperty("Value").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Value(); });
|
||||
object_.registerProperty("Notifying").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Notifying(); });
|
||||
object_.registerProperty("Flags").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Flags(); });
|
||||
object_.registerProperty("Descriptors").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Descriptors(); });
|
||||
}
|
||||
|
||||
~GattCharacteristic1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual void WriteValue(const std::vector<uint8_t>& value) = 0;
|
||||
virtual void StartNotify() = 0;
|
||||
virtual void StopNotify() = 0;
|
||||
|
||||
private:
|
||||
virtual std::string UUID() = 0;
|
||||
virtual sdbus::ObjectPath Service() = 0;
|
||||
virtual std::vector<uint8_t> Value() = 0;
|
||||
virtual bool Notifying() = 0;
|
||||
virtual std::vector<std::string> Flags() = 0;
|
||||
virtual std::vector<sdbus::ObjectPath> Descriptors() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattDescriptor1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattDescriptor1";
|
||||
|
||||
protected:
|
||||
GattDescriptor1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("ReadValue").onInterface(INTERFACE_NAME).withOutputParamNames("value").implementedAs([this](){ return this->ReadValue(); });
|
||||
object_.registerProperty("UUID").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUID(); });
|
||||
object_.registerProperty("Characteristic").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Characteristic(); });
|
||||
object_.registerProperty("Value").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Value(); });
|
||||
object_.registerProperty("Flags").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Flags(); });
|
||||
}
|
||||
|
||||
~GattDescriptor1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual std::vector<uint8_t> ReadValue() = 0;
|
||||
|
||||
private:
|
||||
virtual std::string UUID() = 0;
|
||||
virtual sdbus::ObjectPath Characteristic() = 0;
|
||||
virtual std::vector<uint8_t> Value() = 0;
|
||||
virtual std::vector<std::string> Flags() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class LEAdvertisement1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisement1";
|
||||
|
||||
protected:
|
||||
LEAdvertisement1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("Release").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->Release(); }).withNoReply();
|
||||
object_.registerProperty("Type").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Type(); });
|
||||
object_.registerProperty("ServiceUUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ServiceUUIDs(); });
|
||||
object_.registerProperty("ManufacturerData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ManufacturerData(); });
|
||||
object_.registerProperty("SolicitUUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SolicitUUIDs(); });
|
||||
object_.registerProperty("ServiceData").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ServiceData(); });
|
||||
object_.registerProperty("IncludeTxPower").onInterface(INTERFACE_NAME).withGetter([this](){ return this->IncludeTxPower(); });
|
||||
}
|
||||
|
||||
~LEAdvertisement1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual void Release() = 0;
|
||||
|
||||
private:
|
||||
virtual std::string Type() = 0;
|
||||
virtual std::vector<std::string> ServiceUUIDs() = 0;
|
||||
virtual std::map<std::string, sdbus::Variant> ManufacturerData() = 0;
|
||||
virtual std::vector<std::string> SolicitUUIDs() = 0;
|
||||
virtual std::map<std::string, sdbus::Variant> ServiceData() = 0;
|
||||
virtual bool IncludeTxPower() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace freedesktop {
|
||||
namespace DBus {
|
||||
|
||||
class Introspectable_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Introspectable";
|
||||
|
||||
protected:
|
||||
Introspectable_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("Introspect").onInterface(INTERFACE_NAME).withOutputParamNames("xml").implementedAs([this](){ return this->Introspect(); });
|
||||
}
|
||||
|
||||
~Introspectable_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual std::string Introspect() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class Adapter1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.Adapter1";
|
||||
|
||||
protected:
|
||||
Adapter1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("StartDiscovery").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StartDiscovery(); });
|
||||
object_.registerMethod("SetDiscoveryFilter").onInterface(INTERFACE_NAME).withInputParamNames("properties").implementedAs([this](const std::map<std::string, sdbus::Variant>& properties){ return this->SetDiscoveryFilter(properties); });
|
||||
object_.registerMethod("StopDiscovery").onInterface(INTERFACE_NAME).implementedAs([this](){ return this->StopDiscovery(); });
|
||||
object_.registerMethod("RemoveDevice").onInterface(INTERFACE_NAME).withInputParamNames("device").implementedAs([this](const sdbus::ObjectPath& device){ return this->RemoveDevice(device); });
|
||||
object_.registerMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).withOutputParamNames("filters").implementedAs([this](){ return this->GetDiscoveryFilters(); });
|
||||
object_.registerProperty("Address").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Address(); });
|
||||
object_.registerProperty("AddressType").onInterface(INTERFACE_NAME).withGetter([this](){ return this->AddressType(); });
|
||||
object_.registerProperty("Name").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Name(); });
|
||||
object_.registerProperty("Alias").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Alias(); }).withSetter([this](const std::string& value){ this->Alias(value); });
|
||||
object_.registerProperty("Class").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Class(); });
|
||||
object_.registerProperty("Powered").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Powered(); }).withSetter([this](const bool& value){ this->Powered(value); });
|
||||
object_.registerProperty("Discoverable").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Discoverable(); }).withSetter([this](const bool& value){ this->Discoverable(value); });
|
||||
object_.registerProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME).withGetter([this](){ return this->DiscoverableTimeout(); }).withSetter([this](const uint32_t& value){ this->DiscoverableTimeout(value); });
|
||||
object_.registerProperty("Pairable").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Pairable(); }).withSetter([this](const bool& value){ this->Pairable(value); });
|
||||
object_.registerProperty("PairableTimeout").onInterface(INTERFACE_NAME).withGetter([this](){ return this->PairableTimeout(); }).withSetter([this](const uint32_t& value){ this->PairableTimeout(value); });
|
||||
object_.registerProperty("Discovering").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Discovering(); });
|
||||
object_.registerProperty("UUIDs").onInterface(INTERFACE_NAME).withGetter([this](){ return this->UUIDs(); });
|
||||
object_.registerProperty("Modalias").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Modalias(); });
|
||||
object_.registerProperty("Roles").onInterface(INTERFACE_NAME).withGetter([this](){ return this->Roles(); });
|
||||
}
|
||||
|
||||
~Adapter1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual void StartDiscovery() = 0;
|
||||
virtual void SetDiscoveryFilter(const std::map<std::string, sdbus::Variant>& properties) = 0;
|
||||
virtual void StopDiscovery() = 0;
|
||||
virtual void RemoveDevice(const sdbus::ObjectPath& device) = 0;
|
||||
virtual std::vector<std::string> GetDiscoveryFilters() = 0;
|
||||
|
||||
private:
|
||||
virtual std::string Address() = 0;
|
||||
virtual std::string AddressType() = 0;
|
||||
virtual std::string Name() = 0;
|
||||
virtual std::string Alias() = 0;
|
||||
virtual void Alias(const std::string& value) = 0;
|
||||
virtual uint32_t Class() = 0;
|
||||
virtual bool Powered() = 0;
|
||||
virtual void Powered(const bool& value) = 0;
|
||||
virtual bool Discoverable() = 0;
|
||||
virtual void Discoverable(const bool& value) = 0;
|
||||
virtual uint32_t DiscoverableTimeout() = 0;
|
||||
virtual void DiscoverableTimeout(const uint32_t& value) = 0;
|
||||
virtual bool Pairable() = 0;
|
||||
virtual void Pairable(const bool& value) = 0;
|
||||
virtual uint32_t PairableTimeout() = 0;
|
||||
virtual void PairableTimeout(const uint32_t& value) = 0;
|
||||
virtual bool Discovering() = 0;
|
||||
virtual std::vector<std::string> UUIDs() = 0;
|
||||
virtual std::string Modalias() = 0;
|
||||
virtual std::vector<std::string> Roles() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace freedesktop {
|
||||
namespace DBus {
|
||||
|
||||
class Properties_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
protected:
|
||||
Properties_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("Get").onInterface(INTERFACE_NAME).withInputParamNames("interface", "name").withOutputParamNames("value").implementedAs([this](const std::string& interface, const std::string& name){ return this->Get(interface, name); });
|
||||
object_.registerMethod("Set").onInterface(INTERFACE_NAME).withInputParamNames("interface", "name", "value").implementedAs([this](const std::string& interface, const std::string& name, const sdbus::Variant& value){ return this->Set(interface, name, value); });
|
||||
object_.registerMethod("GetAll").onInterface(INTERFACE_NAME).withInputParamNames("interface").withOutputParamNames("properties").implementedAs([this](const std::string& interface){ return this->GetAll(interface); });
|
||||
object_.registerSignal("PropertiesChanged").onInterface(INTERFACE_NAME).withParameters<std::string, std::map<std::string, sdbus::Variant>, std::vector<std::string>>("interface", "changed_properties", "invalidated_properties");
|
||||
}
|
||||
|
||||
~Properties_adaptor() = default;
|
||||
|
||||
public:
|
||||
void emitPropertiesChanged(const std::string& interface, const std::map<std::string, sdbus::Variant>& changed_properties, const std::vector<std::string>& invalidated_properties)
|
||||
{
|
||||
object_.emitSignal("PropertiesChanged").onInterface(INTERFACE_NAME).withArguments(interface, changed_properties, invalidated_properties);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual sdbus::Variant Get(const std::string& interface, const std::string& name) = 0;
|
||||
virtual void Set(const std::string& interface, const std::string& name, const sdbus::Variant& value) = 0;
|
||||
virtual std::map<std::string, sdbus::Variant> GetAll(const std::string& interface) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattManager1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattManager1";
|
||||
|
||||
protected:
|
||||
GattManager1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("RegisterApplication").onInterface(INTERFACE_NAME).withInputParamNames("application", "options").implementedAs([this](const sdbus::ObjectPath& application, const std::map<std::string, sdbus::Variant>& options){ return this->RegisterApplication(application, options); });
|
||||
object_.registerMethod("UnregisterApplication").onInterface(INTERFACE_NAME).withInputParamNames("application").implementedAs([this](const sdbus::ObjectPath& application){ return this->UnregisterApplication(application); });
|
||||
}
|
||||
|
||||
~GattManager1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual void RegisterApplication(const sdbus::ObjectPath& application, const std::map<std::string, sdbus::Variant>& options) = 0;
|
||||
virtual void UnregisterApplication(const sdbus::ObjectPath& application) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class LEAdvertisingManager1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisingManager1";
|
||||
|
||||
protected:
|
||||
LEAdvertisingManager1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("RegisterAdvertisement").onInterface(INTERFACE_NAME).withInputParamNames("advertisement", "options").implementedAs([this](const sdbus::ObjectPath& advertisement, const std::map<std::string, sdbus::Variant>& options){ return this->RegisterAdvertisement(advertisement, options); });
|
||||
object_.registerMethod("UnregisterAdvertisement").onInterface(INTERFACE_NAME).withInputParamNames("service").implementedAs([this](const sdbus::ObjectPath& service){ return this->UnregisterAdvertisement(service); });
|
||||
object_.registerProperty("ActiveInstances").onInterface(INTERFACE_NAME).withGetter([this](){ return this->ActiveInstances(); });
|
||||
object_.registerProperty("SupportedInstances").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SupportedInstances(); });
|
||||
object_.registerProperty("SupportedIncludes").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SupportedIncludes(); });
|
||||
object_.registerProperty("SupportedSecondaryChannels").onInterface(INTERFACE_NAME).withGetter([this](){ return this->SupportedSecondaryChannels(); });
|
||||
}
|
||||
|
||||
~LEAdvertisingManager1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual void RegisterAdvertisement(const sdbus::ObjectPath& advertisement, const std::map<std::string, sdbus::Variant>& options) = 0;
|
||||
virtual void UnregisterAdvertisement(const sdbus::ObjectPath& service) = 0;
|
||||
|
||||
private:
|
||||
virtual uint8_t ActiveInstances() = 0;
|
||||
virtual uint8_t SupportedInstances() = 0;
|
||||
virtual std::vector<std::string> SupportedIncludes() = 0;
|
||||
virtual std::vector<std::string> SupportedSecondaryChannels() = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class Media1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.Media1";
|
||||
|
||||
protected:
|
||||
Media1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("RegisterEndpoint").onInterface(INTERFACE_NAME).withInputParamNames("endpoint", "properties").implementedAs([this](const sdbus::ObjectPath& endpoint, const std::map<std::string, sdbus::Variant>& properties){ return this->RegisterEndpoint(endpoint, properties); });
|
||||
object_.registerMethod("UnregisterEndpoint").onInterface(INTERFACE_NAME).withInputParamNames("endpoint").implementedAs([this](const sdbus::ObjectPath& endpoint){ return this->UnregisterEndpoint(endpoint); });
|
||||
object_.registerMethod("RegisterPlayer").onInterface(INTERFACE_NAME).withInputParamNames("player", "properties").implementedAs([this](const sdbus::ObjectPath& player, const std::map<std::string, sdbus::Variant>& properties){ return this->RegisterPlayer(player, properties); });
|
||||
object_.registerMethod("UnregisterPlayer").onInterface(INTERFACE_NAME).withInputParamNames("player").implementedAs([this](const sdbus::ObjectPath& player){ return this->UnregisterPlayer(player); });
|
||||
object_.registerMethod("RegisterApplication").onInterface(INTERFACE_NAME).withInputParamNames("application", "options").implementedAs([this](const sdbus::ObjectPath& application, const std::map<std::string, sdbus::Variant>& options){ return this->RegisterApplication(application, options); });
|
||||
object_.registerMethod("UnregisterApplication").onInterface(INTERFACE_NAME).withInputParamNames("application").implementedAs([this](const sdbus::ObjectPath& application){ return this->UnregisterApplication(application); });
|
||||
}
|
||||
|
||||
~Media1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual void RegisterEndpoint(const sdbus::ObjectPath& endpoint, const std::map<std::string, sdbus::Variant>& properties) = 0;
|
||||
virtual void UnregisterEndpoint(const sdbus::ObjectPath& endpoint) = 0;
|
||||
virtual void RegisterPlayer(const sdbus::ObjectPath& player, const std::map<std::string, sdbus::Variant>& properties) = 0;
|
||||
virtual void UnregisterPlayer(const sdbus::ObjectPath& player) = 0;
|
||||
virtual void RegisterApplication(const sdbus::ObjectPath& application, const std::map<std::string, sdbus::Variant>& options) = 0;
|
||||
virtual void UnregisterApplication(const sdbus::ObjectPath& application) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class NetworkServer1_adaptor
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.NetworkServer1";
|
||||
|
||||
protected:
|
||||
NetworkServer1_adaptor(sdbus::IObject& object)
|
||||
: object_(object)
|
||||
{
|
||||
object_.registerMethod("Register").onInterface(INTERFACE_NAME).withInputParamNames("uuid", "bridge").implementedAs([this](const std::string& uuid, const std::string& bridge){ return this->Register(uuid, bridge); });
|
||||
object_.registerMethod("Unregister").onInterface(INTERFACE_NAME).withInputParamNames("uuid").implementedAs([this](const std::string& uuid){ return this->Unregister(uuid); });
|
||||
}
|
||||
|
||||
~NetworkServer1_adaptor() = default;
|
||||
|
||||
private:
|
||||
virtual void Register(const std::string& uuid, const std::string& bridge) = 0;
|
||||
virtual void Unregister(const std::string& uuid) = 0;
|
||||
|
||||
private:
|
||||
sdbus::IObject& object_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -1,631 +0,0 @@
|
||||
|
||||
/*
|
||||
* This file was automatically generated by sdbus-c++-xml2cpp; DO NOT EDIT!
|
||||
*/
|
||||
|
||||
#ifndef __sdbuscpp___home_pi_src_pipedal_src_dbus_bluez_proxy_h__proxy__H__
|
||||
#define __sdbuscpp___home_pi_src_pipedal_src_dbus_bluez_proxy_h__proxy__H__
|
||||
|
||||
#include <sdbus-c++/sdbus-c++.h>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattService1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattService1";
|
||||
|
||||
protected:
|
||||
GattService1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~GattService1_proxy() = default;
|
||||
|
||||
public:
|
||||
std::string UUID()
|
||||
{
|
||||
return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
bool Primary()
|
||||
{
|
||||
return proxy_.getProperty("Primary").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<sdbus::ObjectPath> Characteristics()
|
||||
{
|
||||
return proxy_.getProperty("Characteristics").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattCharacteristic1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattCharacteristic1";
|
||||
|
||||
protected:
|
||||
GattCharacteristic1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~GattCharacteristic1_proxy() = default;
|
||||
|
||||
public:
|
||||
void WriteValue(const std::vector<uint8_t>& value)
|
||||
{
|
||||
proxy_.callMethod("WriteValue").onInterface(INTERFACE_NAME).withArguments(value);
|
||||
}
|
||||
|
||||
void StartNotify()
|
||||
{
|
||||
proxy_.callMethod("StartNotify").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void StopNotify()
|
||||
{
|
||||
proxy_.callMethod("StopNotify").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
public:
|
||||
std::string UUID()
|
||||
{
|
||||
return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
sdbus::ObjectPath Service()
|
||||
{
|
||||
return proxy_.getProperty("Service").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Value()
|
||||
{
|
||||
return proxy_.getProperty("Value").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
bool Notifying()
|
||||
{
|
||||
return proxy_.getProperty("Notifying").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> Flags()
|
||||
{
|
||||
return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<sdbus::ObjectPath> Descriptors()
|
||||
{
|
||||
return proxy_.getProperty("Descriptors").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattDescriptor1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattDescriptor1";
|
||||
|
||||
protected:
|
||||
GattDescriptor1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~GattDescriptor1_proxy() = default;
|
||||
|
||||
public:
|
||||
std::vector<uint8_t> ReadValue()
|
||||
{
|
||||
std::vector<uint8_t> result;
|
||||
proxy_.callMethod("ReadValue").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string UUID()
|
||||
{
|
||||
return proxy_.getProperty("UUID").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
sdbus::ObjectPath Characteristic()
|
||||
{
|
||||
return proxy_.getProperty("Characteristic").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Value()
|
||||
{
|
||||
return proxy_.getProperty("Value").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> Flags()
|
||||
{
|
||||
return proxy_.getProperty("Flags").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class LEAdvertisement1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisement1";
|
||||
|
||||
protected:
|
||||
LEAdvertisement1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~LEAdvertisement1_proxy() = default;
|
||||
|
||||
public:
|
||||
void Release()
|
||||
{
|
||||
proxy_.callMethod("Release").onInterface(INTERFACE_NAME).dontExpectReply();
|
||||
}
|
||||
|
||||
public:
|
||||
std::string Type()
|
||||
{
|
||||
return proxy_.getProperty("Type").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> ServiceUUIDs()
|
||||
{
|
||||
return proxy_.getProperty("ServiceUUIDs").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> ManufacturerData()
|
||||
{
|
||||
return proxy_.getProperty("ManufacturerData").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> SolicitUUIDs()
|
||||
{
|
||||
return proxy_.getProperty("SolicitUUIDs").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> ServiceData()
|
||||
{
|
||||
return proxy_.getProperty("ServiceData").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
bool IncludeTxPower()
|
||||
{
|
||||
return proxy_.getProperty("IncludeTxPower").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace freedesktop {
|
||||
namespace DBus {
|
||||
|
||||
class Introspectable_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Introspectable";
|
||||
|
||||
protected:
|
||||
Introspectable_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~Introspectable_proxy() = default;
|
||||
|
||||
public:
|
||||
std::string Introspect()
|
||||
{
|
||||
std::string result;
|
||||
proxy_.callMethod("Introspect").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class Adapter1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.Adapter1";
|
||||
|
||||
protected:
|
||||
Adapter1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~Adapter1_proxy() = default;
|
||||
|
||||
public:
|
||||
void StartDiscovery()
|
||||
{
|
||||
proxy_.callMethod("StartDiscovery").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void SetDiscoveryFilter(const std::map<std::string, sdbus::Variant>& properties)
|
||||
{
|
||||
proxy_.callMethod("SetDiscoveryFilter").onInterface(INTERFACE_NAME).withArguments(properties);
|
||||
}
|
||||
|
||||
void StopDiscovery()
|
||||
{
|
||||
proxy_.callMethod("StopDiscovery").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void RemoveDevice(const sdbus::ObjectPath& device)
|
||||
{
|
||||
proxy_.callMethod("RemoveDevice").onInterface(INTERFACE_NAME).withArguments(device);
|
||||
}
|
||||
|
||||
std::vector<std::string> GetDiscoveryFilters()
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
proxy_.callMethod("GetDiscoveryFilters").onInterface(INTERFACE_NAME).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
std::string Address()
|
||||
{
|
||||
return proxy_.getProperty("Address").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string AddressType()
|
||||
{
|
||||
return proxy_.getProperty("AddressType").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string Name()
|
||||
{
|
||||
return proxy_.getProperty("Name").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string Alias()
|
||||
{
|
||||
return proxy_.getProperty("Alias").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Alias(const std::string& value)
|
||||
{
|
||||
proxy_.setProperty("Alias").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
uint32_t Class()
|
||||
{
|
||||
return proxy_.getProperty("Class").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
bool Powered()
|
||||
{
|
||||
return proxy_.getProperty("Powered").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Powered(const bool& value)
|
||||
{
|
||||
proxy_.setProperty("Powered").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool Discoverable()
|
||||
{
|
||||
return proxy_.getProperty("Discoverable").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Discoverable(const bool& value)
|
||||
{
|
||||
proxy_.setProperty("Discoverable").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
uint32_t DiscoverableTimeout()
|
||||
{
|
||||
return proxy_.getProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void DiscoverableTimeout(const uint32_t& value)
|
||||
{
|
||||
proxy_.setProperty("DiscoverableTimeout").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool Pairable()
|
||||
{
|
||||
return proxy_.getProperty("Pairable").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void Pairable(const bool& value)
|
||||
{
|
||||
proxy_.setProperty("Pairable").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
uint32_t PairableTimeout()
|
||||
{
|
||||
return proxy_.getProperty("PairableTimeout").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
void PairableTimeout(const uint32_t& value)
|
||||
{
|
||||
proxy_.setProperty("PairableTimeout").onInterface(INTERFACE_NAME).toValue(value);
|
||||
}
|
||||
|
||||
bool Discovering()
|
||||
{
|
||||
return proxy_.getProperty("Discovering").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> UUIDs()
|
||||
{
|
||||
return proxy_.getProperty("UUIDs").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::string Modalias()
|
||||
{
|
||||
return proxy_.getProperty("Modalias").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> Roles()
|
||||
{
|
||||
return proxy_.getProperty("Roles").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace freedesktop {
|
||||
namespace DBus {
|
||||
|
||||
class Properties_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.freedesktop.DBus.Properties";
|
||||
|
||||
protected:
|
||||
Properties_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
proxy_.uponSignal("PropertiesChanged").onInterface(INTERFACE_NAME).call([this](const std::string& interface, const std::map<std::string, sdbus::Variant>& changed_properties, const std::vector<std::string>& invalidated_properties){ this->onPropertiesChanged(interface, changed_properties, invalidated_properties); });
|
||||
}
|
||||
|
||||
~Properties_proxy() = default;
|
||||
|
||||
virtual void onPropertiesChanged(const std::string& interface, const std::map<std::string, sdbus::Variant>& changed_properties, const std::vector<std::string>& invalidated_properties) = 0;
|
||||
|
||||
public:
|
||||
sdbus::Variant Get(const std::string& interface, const std::string& name)
|
||||
{
|
||||
sdbus::Variant result;
|
||||
proxy_.callMethod("Get").onInterface(INTERFACE_NAME).withArguments(interface, name).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void Set(const std::string& interface, const std::string& name, const sdbus::Variant& value)
|
||||
{
|
||||
proxy_.callMethod("Set").onInterface(INTERFACE_NAME).withArguments(interface, name, value);
|
||||
}
|
||||
|
||||
std::map<std::string, sdbus::Variant> GetAll(const std::string& interface)
|
||||
{
|
||||
std::map<std::string, sdbus::Variant> result;
|
||||
proxy_.callMethod("GetAll").onInterface(INTERFACE_NAME).withArguments(interface).storeResultsTo(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class GattManager1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.GattManager1";
|
||||
|
||||
protected:
|
||||
GattManager1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~GattManager1_proxy() = default;
|
||||
|
||||
public:
|
||||
void RegisterApplication(const sdbus::ObjectPath& application, const std::map<std::string, sdbus::Variant>& options)
|
||||
{
|
||||
proxy_.callMethod("RegisterApplication").onInterface(INTERFACE_NAME).withArguments(application, options);
|
||||
}
|
||||
|
||||
void UnregisterApplication(const sdbus::ObjectPath& application)
|
||||
{
|
||||
proxy_.callMethod("UnregisterApplication").onInterface(INTERFACE_NAME).withArguments(application);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class LEAdvertisingManager1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.LEAdvertisingManager1";
|
||||
|
||||
protected:
|
||||
LEAdvertisingManager1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~LEAdvertisingManager1_proxy() = default;
|
||||
|
||||
public:
|
||||
void RegisterAdvertisement(const sdbus::ObjectPath& advertisement, const std::map<std::string, sdbus::Variant>& options)
|
||||
{
|
||||
proxy_.callMethod("RegisterAdvertisement").onInterface(INTERFACE_NAME).withArguments(advertisement, options);
|
||||
}
|
||||
|
||||
void UnregisterAdvertisement(const sdbus::ObjectPath& service)
|
||||
{
|
||||
proxy_.callMethod("UnregisterAdvertisement").onInterface(INTERFACE_NAME).withArguments(service);
|
||||
}
|
||||
|
||||
public:
|
||||
uint8_t ActiveInstances()
|
||||
{
|
||||
return proxy_.getProperty("ActiveInstances").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
uint8_t SupportedInstances()
|
||||
{
|
||||
return proxy_.getProperty("SupportedInstances").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> SupportedIncludes()
|
||||
{
|
||||
return proxy_.getProperty("SupportedIncludes").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
std::vector<std::string> SupportedSecondaryChannels()
|
||||
{
|
||||
return proxy_.getProperty("SupportedSecondaryChannels").onInterface(INTERFACE_NAME);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class Media1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.Media1";
|
||||
|
||||
protected:
|
||||
Media1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~Media1_proxy() = default;
|
||||
|
||||
public:
|
||||
void RegisterEndpoint(const sdbus::ObjectPath& endpoint, const std::map<std::string, sdbus::Variant>& properties)
|
||||
{
|
||||
proxy_.callMethod("RegisterEndpoint").onInterface(INTERFACE_NAME).withArguments(endpoint, properties);
|
||||
}
|
||||
|
||||
void UnregisterEndpoint(const sdbus::ObjectPath& endpoint)
|
||||
{
|
||||
proxy_.callMethod("UnregisterEndpoint").onInterface(INTERFACE_NAME).withArguments(endpoint);
|
||||
}
|
||||
|
||||
void RegisterPlayer(const sdbus::ObjectPath& player, const std::map<std::string, sdbus::Variant>& properties)
|
||||
{
|
||||
proxy_.callMethod("RegisterPlayer").onInterface(INTERFACE_NAME).withArguments(player, properties);
|
||||
}
|
||||
|
||||
void UnregisterPlayer(const sdbus::ObjectPath& player)
|
||||
{
|
||||
proxy_.callMethod("UnregisterPlayer").onInterface(INTERFACE_NAME).withArguments(player);
|
||||
}
|
||||
|
||||
void RegisterApplication(const sdbus::ObjectPath& application, const std::map<std::string, sdbus::Variant>& options)
|
||||
{
|
||||
proxy_.callMethod("RegisterApplication").onInterface(INTERFACE_NAME).withArguments(application, options);
|
||||
}
|
||||
|
||||
void UnregisterApplication(const sdbus::ObjectPath& application)
|
||||
{
|
||||
proxy_.callMethod("UnregisterApplication").onInterface(INTERFACE_NAME).withArguments(application);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
namespace org {
|
||||
namespace bluez {
|
||||
|
||||
class NetworkServer1_proxy
|
||||
{
|
||||
public:
|
||||
static constexpr const char* INTERFACE_NAME = "org.bluez.NetworkServer1";
|
||||
|
||||
protected:
|
||||
NetworkServer1_proxy(sdbus::IProxy& proxy)
|
||||
: proxy_(proxy)
|
||||
{
|
||||
}
|
||||
|
||||
~NetworkServer1_proxy() = default;
|
||||
|
||||
public:
|
||||
void Register(const std::string& uuid, const std::string& bridge)
|
||||
{
|
||||
proxy_.callMethod("Register").onInterface(INTERFACE_NAME).withArguments(uuid, bridge);
|
||||
}
|
||||
|
||||
void Unregister(const std::string& uuid)
|
||||
{
|
||||
proxy_.callMethod("Unregister").onInterface(INTERFACE_NAME).withArguments(uuid);
|
||||
}
|
||||
|
||||
private:
|
||||
sdbus::IProxy& proxy_;
|
||||
};
|
||||
|
||||
}} // namespaces
|
||||
|
||||
#endif
|
||||
@@ -1,112 +0,0 @@
|
||||
#include "bluez_adaptor.h"
|
||||
#include "bluez.h"
|
||||
#include <thread>
|
||||
|
||||
#include "catch.hpp"
|
||||
#include "gsl/gsl"
|
||||
|
||||
#define TEST_UUID "6b49786f-271d-415d-8e2c-bd5ef8aa6f47"
|
||||
using TestAdvertisementInterfaces = sdbus::AdaptorInterfaces<org::bluez::LEAdvertisement1_adaptor>;
|
||||
|
||||
|
||||
static const char* SERVICE_NAME="com.twoplay.pipedal.onboarding";
|
||||
static const char* SERVICE_PATH="/com/twoplay/pipedal/onboarding";
|
||||
|
||||
|
||||
class TestAdvertisement: public TestAdvertisementInterfaces
|
||||
{
|
||||
private:
|
||||
std::vector<std::string> serviceUuids;
|
||||
public:
|
||||
TestAdvertisement(sdbus::IConnection& connection, std::string objectPath)
|
||||
: TestAdvertisementInterfaces(connection,std::move(objectPath))
|
||||
{
|
||||
serviceUuids.push_back(TEST_UUID);
|
||||
}
|
||||
private:
|
||||
|
||||
virtual void Release() { }
|
||||
|
||||
private:
|
||||
virtual std::string Type() { return "peripheral"; }
|
||||
virtual std::vector<std::string> ServiceUUIDs() { return serviceUuids; }
|
||||
virtual std::map<std::string, sdbus::Variant> ManufacturerData() {
|
||||
return std::map<std::string, sdbus::Variant>();
|
||||
};
|
||||
virtual std::vector<std::string> SolicitUUIDs() {
|
||||
return std::vector<std::string>();
|
||||
}
|
||||
virtual std::map<std::string, sdbus::Variant> ServiceData()
|
||||
{
|
||||
return std::map<std::string, sdbus::Variant>();
|
||||
}
|
||||
virtual bool IncludeTxPower() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
using namespace gsl;
|
||||
using namespace std;
|
||||
|
||||
class TestServer {
|
||||
private:
|
||||
std::string devicePath;
|
||||
|
||||
std::unique_ptr<TestAdvertisement> advertisement;
|
||||
|
||||
private:
|
||||
|
||||
void ListenProc()
|
||||
{
|
||||
|
||||
}
|
||||
public:
|
||||
TestServer(const std::string &devicePath)
|
||||
: devicePath(devicePath)
|
||||
{
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
|
||||
auto connector = sdbus::createSystemBusConnection(SERVICE_NAME);
|
||||
std::unique_ptr<TestAdvertisement> advertisement = std::make_unique<TestAdvertisement>(*connector,SERVICE_PATH);
|
||||
|
||||
std::unique_ptr<org::bluez::BleDeviceProxy> device = std::make_unique<org::bluez::BleDeviceProxy>(devicePath);
|
||||
|
||||
|
||||
std::map<std::string,sdbus::Variant> advertisementOptions;
|
||||
device->RegisterAdvertisement(advertisement->getObjectPath(),advertisementOptions);
|
||||
|
||||
auto _ = finally([&device,&advertisement] {
|
||||
device->UnregisterAdvertisement(advertisement->getObjectPath());
|
||||
});
|
||||
|
||||
std::thread thread(
|
||||
[this] () {
|
||||
this->ListenProc();
|
||||
}
|
||||
);
|
||||
|
||||
thread.join();
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CASE( "Bluetooth service", "[bluetooth_service]" ) {
|
||||
org::bluez::BleDeviceProxy device("/org/bluez/hci0");
|
||||
|
||||
auto includes = device.SupportedIncludes();
|
||||
|
||||
TestServer server {"/org/bluez/hci0"};
|
||||
|
||||
server.Run();
|
||||
|
||||
}
|
||||
+51
-41
@@ -21,13 +21,15 @@
|
||||
#include "BeastServer.hpp"
|
||||
#include <iostream>
|
||||
#include "Lv2Log.hpp"
|
||||
#include "DeviceIdFile.hpp"
|
||||
#include "AvahiService.hpp"
|
||||
|
||||
#include "PiPedalSocket.hpp"
|
||||
#include "Lv2Host.hpp"
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <filesystem>
|
||||
#include "PiPedalConfiguration.hpp"
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "AdminClient.hpp"
|
||||
#include "CommandLineParser.hpp"
|
||||
#include "Lv2SystemdLogger.hpp"
|
||||
#include <sys/stat.h>
|
||||
@@ -87,7 +89,7 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool wants(const std::string& method, const uri &request_uri) const
|
||||
virtual bool wants(const std::string &method, const uri &request_uri) const
|
||||
{
|
||||
if (request_uri.segment_count() != 2 || request_uri.segment(0) != "var")
|
||||
{
|
||||
@@ -135,7 +137,7 @@ public:
|
||||
return result;
|
||||
}
|
||||
|
||||
void GetPluginPresets(const uri &request_uri, std::string*pName,std::string *pContent)
|
||||
void GetPluginPresets(const uri &request_uri, std::string *pName, std::string *pContent)
|
||||
{
|
||||
std::string pluginUri = request_uri.query("id");
|
||||
auto plugin = model->GetLv2Host().GetPluginInfo(pluginUri);
|
||||
@@ -193,7 +195,7 @@ public:
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
GetPluginPresets(request_uri,&name,&content);
|
||||
GetPluginPresets(request_uri, &name, &content);
|
||||
res.set(HttpField::content_type, "application/octet-stream");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(content.length());
|
||||
@@ -253,13 +255,14 @@ public:
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
GetPluginPresets(request_uri,&name,&content);
|
||||
GetPluginPresets(request_uri, &name, &content);
|
||||
res.set(HttpField::content_type, "application/octet-stream");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(content.length());
|
||||
res.set(HttpField::content_disposition, GetContentDispositionHeader(name, PLUGIN_PRESETS_EXTENSION));
|
||||
res.setBody(content);
|
||||
} else if (segment == "downloadPreset")
|
||||
}
|
||||
else if (segment == "downloadPreset")
|
||||
{
|
||||
std::string name;
|
||||
std::string content;
|
||||
@@ -312,7 +315,7 @@ public:
|
||||
|
||||
if (segment == "uploadPluginPresets")
|
||||
{
|
||||
const std::string& presetBody = req.body();
|
||||
const std::string &presetBody = req.body();
|
||||
std::stringstream s(presetBody);
|
||||
json_reader reader(s);
|
||||
PluginPresets presets;
|
||||
@@ -327,9 +330,10 @@ public:
|
||||
res.setContentLength(result.length());
|
||||
|
||||
res.setBody(result);
|
||||
} else if (segment == "uploadPreset")
|
||||
}
|
||||
else if (segment == "uploadPreset")
|
||||
{
|
||||
const std::string& presetBody = req.body();
|
||||
const std::string &presetBody = req.body();
|
||||
std::stringstream s(presetBody);
|
||||
json_reader reader(s);
|
||||
|
||||
@@ -356,7 +360,7 @@ public:
|
||||
}
|
||||
else if (segment == "uploadBank")
|
||||
{
|
||||
const std::string& presetBody = req.body();
|
||||
const std::string &presetBody = req.body();
|
||||
std::istringstream s(presetBody);
|
||||
json_reader reader(s);
|
||||
|
||||
@@ -417,34 +421,34 @@ public:
|
||||
portNumber(portNumber)
|
||||
{
|
||||
}
|
||||
std::string GetConfig(const std::string&fromAddress)
|
||||
std::string GetConfig(const std::string &fromAddress)
|
||||
{
|
||||
std::string linkLocalAddress = GetLinkLocalAddress(fromAddress);
|
||||
|
||||
std::stringstream s;
|
||||
|
||||
s << "{ \"socket_server_port\": " << portNumber
|
||||
<< ", \"socket_server_address\": \"" << linkLocalAddress << "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||
<< ", \"socket_server_address\": \"" << linkLocalAddress << "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
virtual ~InterceptConfig() {}
|
||||
|
||||
virtual void head_response(
|
||||
const uri&request_uri,
|
||||
virtual void head_response(
|
||||
const uri &request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
std::error_code &ec)
|
||||
{
|
||||
// intercepted. See the other overload.
|
||||
}
|
||||
|
||||
virtual void head_response(
|
||||
const std::string &fromAddress,
|
||||
const uri&request_uri,
|
||||
virtual void head_response(
|
||||
const std::string &fromAddress,
|
||||
const uri &request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::string response = GetConfig(fromAddress);
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
@@ -458,12 +462,12 @@ public:
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
// intercepted. see the other overload.
|
||||
}
|
||||
{
|
||||
// intercepted. see the other overload.
|
||||
}
|
||||
|
||||
virtual void get_response(
|
||||
const std::string&fromAddress,
|
||||
const std::string &fromAddress,
|
||||
const uri &request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
@@ -477,7 +481,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static bool isJackServiceRunning()
|
||||
{
|
||||
// look for the jack shmem .
|
||||
@@ -485,7 +488,6 @@ static bool isJackServiceRunning()
|
||||
return std::filesystem::exists(path);
|
||||
}
|
||||
|
||||
uint16_t g_ShutdownPort = 0;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
@@ -502,7 +504,6 @@ int main(int argc, char *argv[])
|
||||
bool help = false;
|
||||
bool error = false;
|
||||
bool systemd = false;
|
||||
uint16_t shutdownPort = 0;
|
||||
std::string portOption;
|
||||
|
||||
CommandLineParser parser;
|
||||
@@ -510,7 +511,6 @@ int main(int argc, char *argv[])
|
||||
parser.AddOption("--help", &help);
|
||||
parser.AddOption("-systemd", &systemd);
|
||||
parser.AddOption("-port", &portOption);
|
||||
parser.AddOption("-shutdownPort", &shutdownPort);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -543,7 +543,6 @@ int main(int argc, char *argv[])
|
||||
<< "Options:\n"
|
||||
<< " -systemd: Log to systemd journals, wait for jack service.\n"
|
||||
<< " -port: Port to listen on e.g. 0.0.0.0:80\n"
|
||||
<< " -shutdownPort: Port for the shutdown service.\n"
|
||||
<< "Example:\n"
|
||||
<< " pipedal /etc/pipedal/config /etc/pipedal/react -port 0.0.0.0:80 \n"
|
||||
"\n"
|
||||
@@ -558,7 +557,6 @@ int main(int argc, char *argv[])
|
||||
return error ? EXIT_FAILURE : EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
g_ShutdownPort = shutdownPort;
|
||||
if (systemd)
|
||||
{
|
||||
Lv2Log::set_logger(MakeLv2SystemdLogger());
|
||||
@@ -576,7 +574,7 @@ int main(int argc, char *argv[])
|
||||
PiPedalConfiguration configuration;
|
||||
try
|
||||
{
|
||||
configuration.Load(doc_root,web_root);
|
||||
configuration.Load(doc_root, web_root);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -608,7 +606,6 @@ int main(int argc, char *argv[])
|
||||
Lv2Log::info("Document root: %s Threads: %d", doc_root.c_str(), (int)threads);
|
||||
|
||||
server->SetLogHttpRequests(configuration.LogHttpRequests());
|
||||
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
@@ -648,7 +645,7 @@ int main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// pre-cache device info before we let audio services run.
|
||||
model.GetAlsaDevices();
|
||||
}
|
||||
@@ -659,8 +656,8 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
// Tell systemd we're done.
|
||||
sd_notifyf(0, "READY=1\n"
|
||||
"MAINPID=%lu",
|
||||
(unsigned long) getpid());
|
||||
"MAINPID=%lu",
|
||||
(unsigned long)getpid());
|
||||
}
|
||||
|
||||
if (!isJackServiceRunning())
|
||||
@@ -684,7 +681,9 @@ int main(int argc, char *argv[])
|
||||
{
|
||||
Lv2Log::info("Found Jack service.");
|
||||
sleep(3); // jack needs a little time to get up to speed.
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
Lv2Log::info("Jack service not started.");
|
||||
}
|
||||
|
||||
@@ -700,13 +699,24 @@ int main(int argc, char *argv[])
|
||||
std::shared_ptr<DownloadIntercept> downloadIntercept = std::make_shared<DownloadIntercept>(&model);
|
||||
server->AddRequestHandler(downloadIntercept);
|
||||
|
||||
server->RunInBackground(SIGUSR1);
|
||||
|
||||
sem_wait(&signalSemaphore);
|
||||
|
||||
if (systemd)
|
||||
{
|
||||
sd_notify(0, "STOPPING=1");
|
||||
// Publish DNS Service.
|
||||
DeviceIdFile deviceIdFile;
|
||||
deviceIdFile.Load();
|
||||
AvahiService service;
|
||||
service.Announce(
|
||||
configuration.GetSocketServerPort(),deviceIdFile.deviceName,deviceIdFile.uuid,"pipedal");
|
||||
|
||||
|
||||
|
||||
server->RunInBackground(SIGUSR1);
|
||||
|
||||
sem_wait(&signalSemaphore);
|
||||
|
||||
if (systemd)
|
||||
{
|
||||
sd_notify(0, "STOPPING=1");
|
||||
}
|
||||
}
|
||||
|
||||
Lv2Log::info("Shutting down gracefully.");
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022 Robin E. R. 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.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
server=8.8.8.8
|
||||
server=8.8.4.4
|
||||
|
||||
|
||||
interface=p2p-wlan0-0
|
||||
dhcp-range=p2p-wlan0,173.23.0.3,172.23.0.127,1h
|
||||
domain=local
|
||||
address=/pipedal.local/172.23.0.2
|
||||
|
||||
except-interface=eth0
|
||||
except-interface=wlan0
|
||||
@@ -1,8 +1,3 @@
|
||||
${COUNTRY_CODE}
|
||||
${PIN}
|
||||
${DEVICE_NAME}
|
||||
${WIFI_GROUP_FREQUENCY}
|
||||
${INSTANCE_ID_FILE} /var/pipedal/instance_id
|
||||
# WiFi regdomain 2-letter country code.
|
||||
# see: http://www.davros.org/misc/iso3166.txt
|
||||
country_code=${COUNTRY_CODE}
|
||||
@@ -37,9 +32,8 @@ p2p_go_he=0
|
||||
# Ipv4 address for the P2P group interface
|
||||
p2p_ip_address=172.24.0.2/16
|
||||
|
||||
# File containing the a globally-unique id identifying the service on this machine.
|
||||
# Syntax: 0a6045b0-1753-4104-b3e4-b9713b9cc356
|
||||
#
|
||||
# File containing the globally-unique id that identifies the service on this machine
|
||||
# in this format: 0a6045b0-1753-4104-b3e4-b9713b9cc356
|
||||
service_guid_file=${INSTANCE_ID_FILE}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=PiPedal P2P Session Manager
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=${COMMAND} --systemd --log-level debug
|
||||
Type=notify
|
||||
WorkingDirectory=/var/pipedal
|
||||
TimeOutStopSec=5
|
||||
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -21,4 +21,3 @@
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include <catch/catch.hpp>
|
||||
|
||||
uint16_t g_ShutdownPort = 0;
|
||||
|
||||
Reference in New Issue
Block a user