Wi-Fi Direct cmdline

This commit is contained in:
Robin Davies
2022-04-22 02:20:44 -04:00
parent 88178d01d5
commit 7f058b6ed9
47 changed files with 2106 additions and 2109 deletions
+188
View File
@@ -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.");
}
}
+18 -9
View File
@@ -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
+147 -153
View File
@@ -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;
}
+340
View File
@@ -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;
}
+74
View File
@@ -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;
};
}
+47
View File
@@ -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
View File
@@ -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
View File
@@ -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)
{
+139
View File
@@ -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);
};
}
+76
View File
@@ -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;
}
}
+41
View File
@@ -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
View File
@@ -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, "");
+1 -1
View File
@@ -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"
+1
View File
@@ -106,6 +106,7 @@ public:
}
return socketServerAddress_.substr(0,pos);
}
uint16_t GetSocketServerPort() const {
try {
size_t pos = this->socketServerAddress_.find_last_of(':');
+7 -7
View File
@@ -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.
+10
View File
@@ -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
View File
@@ -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.");
}
}
}
}
+1 -1
View File
@@ -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
View File
@@ -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()
-2
View File
@@ -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);
-235
View File
@@ -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.");
}
}
+253
View File
@@ -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;
}
+96
View File
@@ -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;
};
};
+71
View File
@@ -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));
}
+61 -1
View File
@@ -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;
}
+4
View File
@@ -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;
+42 -8
View File
@@ -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."); }
+30 -9
View File
@@ -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);
}
}
+17 -2
View File
@@ -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);
}
-28
View File
@@ -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
-276
View File
@@ -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>
-428
View File
@@ -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
-631
View File
@@ -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
-112
View File
@@ -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
View File
@@ -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.");
+24
View File
@@ -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.
*/
+11
View File
@@ -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
-1
View File
@@ -21,4 +21,3 @@
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
uint16_t g_ShutdownPort = 0;