Configurable CPU Governor (fixed)
modified: .vscode/launch.json modified: react/CMakeLists.txt modified: react/public/var/config.json new file: react/src/GovernorSettings.tsx modified: react/src/JackHostStatus.tsx new file: react/src/ListSelectDialog.tsx modified: react/src/PiPedalModel.tsx modified: react/src/SettingsDialog.tsx modified: react/tmp.txt modified: src/BeastServer.cpp modified: src/BeastServer.hpp modified: src/CMakeLists.txt modified: src/ConfigMain.cpp new file: src/CpuGovernor.cpp new file: src/CpuGovernor.hpp new file: src/GovernorSettings.cpp new file: src/GovernorSettings.hpp new file: src/Ipv6Helpers.cpp new file: src/Ipv6Helpers.hpp modified: src/JackHost.cpp modified: src/PiPedalModel.cpp
This commit is contained in:
+57
-6
@@ -49,6 +49,40 @@ pipedal::last_modified(const std::filesystem::path &path)
|
||||
}
|
||||
}
|
||||
|
||||
static std::string getHostName()
|
||||
{
|
||||
char buff[512];
|
||||
if (gethostname(buff,sizeof(buff)) == 0)
|
||||
{
|
||||
buff[511] = '\0';
|
||||
return buff;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
static std::string getIpv4Address(const std::string interface)
|
||||
{
|
||||
int fd = -1;
|
||||
struct ifreq ifr;
|
||||
memset(&ifr,0,sizeof(ifr));
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
/* I want to get an IPv4 IP address */
|
||||
ifr.ifr_addr.sa_family = AF_INET;
|
||||
|
||||
/* I want an IP address attached to "eth0" */
|
||||
strncpy(ifr.ifr_name, interface.c_str(), IFNAMSIZ-1);
|
||||
|
||||
int result = ioctl(fd, SIOCGIFADDR, &ifr);
|
||||
if (result == -1) return "";
|
||||
|
||||
|
||||
close(fd);
|
||||
char *name = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
|
||||
if (name == nullptr) return "";
|
||||
return name;
|
||||
}
|
||||
static std::map<std::string, std::string> extensionsToMimeType = {
|
||||
{".htm", "text/html; charset=UTF-8"},
|
||||
{".html", "text/html; charset=UTF-8"},
|
||||
@@ -192,7 +226,8 @@ namespace pipedal
|
||||
webSocket(webSocket)
|
||||
{
|
||||
uri requestUri(webSocket->get_uri()->str().c_str());
|
||||
fromAddress = requestUri.authority();
|
||||
fromAddress = SS(webSocket->get_socket().remote_endpoint());
|
||||
|
||||
|
||||
auto pFactory = pServer->GetSocketFactory(requestUri);
|
||||
if (!pFactory)
|
||||
@@ -364,11 +399,14 @@ namespace pipedal
|
||||
con->set_status(websocketpp::http::status_code::ok);
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto requestHandler : this->request_handlers)
|
||||
{
|
||||
|
||||
if (requestHandler->wants(req.method(), requestUri))
|
||||
{
|
||||
std::string fromAddress = SS(con->get_remote_endpoint());
|
||||
|
||||
try
|
||||
{
|
||||
if (req.method() == HttpVerb::head)
|
||||
@@ -377,7 +415,7 @@ namespace pipedal
|
||||
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
||||
res.set(HttpField::access_control_allow_origin, origin);
|
||||
|
||||
requestHandler->head_response(requestUri, req, res, ec);
|
||||
requestHandler->head_response(fromAddress,requestUri, req, res, ec);
|
||||
res.keepAlive(req.keepAlive());
|
||||
if (ec == std::errc::no_such_file_or_directory)
|
||||
{
|
||||
@@ -401,7 +439,7 @@ namespace pipedal
|
||||
|
||||
res.set(HttpField::cache_control, "max-age: 31104000"); // cache for a year.
|
||||
|
||||
requestHandler->get_response(requestUri, req, res, ec);
|
||||
requestHandler->get_response(fromAddress,requestUri, req, res, ec);
|
||||
res.keepAlive(req.keepAlive());
|
||||
|
||||
if (ec == std::errc::no_such_file_or_directory)
|
||||
@@ -425,7 +463,7 @@ namespace pipedal
|
||||
res.set(HttpField::date, HtmlHelper::timeToHttpDate(time(nullptr)));
|
||||
res.set(HttpField::access_control_allow_origin, origin);
|
||||
|
||||
requestHandler->post_response(requestUri, req, res, ec);
|
||||
requestHandler->post_response(fromAddress,requestUri, req, res, ec);
|
||||
|
||||
if (ec == std::errc::no_such_file_or_directory)
|
||||
{
|
||||
@@ -547,15 +585,28 @@ namespace pipedal
|
||||
m_endpoint.set_close_handler(bind(&BeastServerImpl::on_close, this, _1));
|
||||
m_endpoint.set_http_handler(bind(&BeastServerImpl::on_http, this, _1));
|
||||
|
||||
std::string hostName = getHostName();
|
||||
if (hostName.length() != 0)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << "Listening on " << this->address << ":" << this->port;
|
||||
ss << "Listening on " << hostName << ".local:" << this->port;
|
||||
Lv2Log::info(ss.str());
|
||||
}
|
||||
std::string ipv4Address = getIpv4Address("eth0");
|
||||
if (ipv4Address.length() != 0)
|
||||
{
|
||||
Lv2Log::info(SS("Listening on " << ipv4Address << ":" << this->port));
|
||||
}
|
||||
std::string wifiAddress = getIpv4Address("wlan0");
|
||||
if (wifiAddress.length() != 0)
|
||||
{
|
||||
Lv2Log::info(SS("Listening on Wi-Fi address " << wifiAddress << ":" << this->port));
|
||||
}
|
||||
|
||||
std::stringstream ss;
|
||||
ss << port;
|
||||
m_endpoint.listen(this->address, ss.str());
|
||||
// m_endpoint.listen(this->address, ss.str());
|
||||
m_endpoint.listen(tcp::v6(),(uint16_t)port);
|
||||
m_endpoint.start_accept();
|
||||
|
||||
// Start IOC service threads.
|
||||
|
||||
+34
-1
@@ -3,7 +3,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/ip/network_v4.hpp>
|
||||
#include <boost/asio/ip/network_v6.hpp>
|
||||
#include <cstring>
|
||||
|
||||
|
||||
@@ -164,12 +164,34 @@ public:
|
||||
HttpResponse &res,
|
||||
std::error_code &ec) = 0;
|
||||
|
||||
virtual void head_response(
|
||||
const std::string&fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec) {
|
||||
head_response(request_uri,req,res,ec);
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual void get_response(
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec) = 0;
|
||||
|
||||
virtual void get_response(
|
||||
const std::string&fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
get_response(request_uri,req,res,ec);
|
||||
}
|
||||
|
||||
|
||||
virtual void post_response(
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
@@ -178,6 +200,17 @@ public:
|
||||
{
|
||||
get_response(request_uri,req,res,ec);
|
||||
}
|
||||
virtual void post_response(
|
||||
const std::string&fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
post_response(
|
||||
request_uri,req,res,ec);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BeastServer {
|
||||
|
||||
+5
-1
@@ -102,7 +102,10 @@ add_custom_command(
|
||||
|
||||
|
||||
set (PIPEDAL_SOURCES
|
||||
PluginPreset.cpp PluginPreset.hpp
|
||||
Ipv6Helpers.cpp Ipv6Helpers.hpp
|
||||
PluginPreset.cpp PluginPreset.hpp
|
||||
CpuGovernor.cpp CpuGovernor.hpp
|
||||
GovernorSettings.cpp GovernorSettings.hpp
|
||||
SysExec.cpp SysExec.hpp
|
||||
BeastServer.cpp BeastServer.hpp HtmlHelper.cpp HtmlHelper.hpp pch.h Uri.cpp Uri.hpp
|
||||
WifiConfigSettings.hpp WifiConfigSettings.cpp
|
||||
@@ -233,6 +236,7 @@ add_executable(pipedalshutdownd ShutdownMain.cpp CommandLineParser.hpp
|
||||
SetWifiConfig.hpp SetWifiConfig.cpp
|
||||
SystemConfigFile.hpp SystemConfigFile.cpp
|
||||
SysExec.hpp SysExec.cpp
|
||||
CpuGovernor.cpp CpuGovernor.hpp
|
||||
asan_options.cpp
|
||||
)
|
||||
target_link_libraries(pipedalshutdownd PRIVATE pthread atomic stdc++fs systemd)
|
||||
|
||||
+6
-5
@@ -650,7 +650,7 @@ int main(int argc, char **argv)
|
||||
<< " (only valid with the -install option). Usually determined " << endl
|
||||
<< " automatically." << endl
|
||||
<< endl
|
||||
<< " --uninstall Remove installed services and service accounts." << endl
|
||||
<< " --uninstall Remove installed services." << endl
|
||||
<< endl
|
||||
<< " --enable Start the pipedal service at boot time." << endl
|
||||
<< endl
|
||||
@@ -668,10 +668,11 @@ int main(int argc, char **argv)
|
||||
<< " web server will listen on 0.0.0.0 (any)." << endl
|
||||
<< endl
|
||||
<< " --enable_ap <country_code> <ssid> <wep_password> <channel>" << endl
|
||||
<< " Enable the Wi-Fi access point. <country_code> is the 2-letter " << endl
|
||||
<< " ISO-3166 country code for the country in which you are currently" << endl
|
||||
<< " located. The country code determines which channels may be legally" << endl
|
||||
<< " used in (and which features need to be enabled) in order to use a " << endl
|
||||
<< " Enable the Wi-Fi access point. <country_code> is the " << endl
|
||||
<< " 2-letter ISO-3166 country code for the country in " << endl
|
||||
<< " which you are currently located. The country code " << endl
|
||||
<< " determines which channels may be legally used in (and " << endl
|
||||
<< " which features need to be enabled) in order to use a " << endl
|
||||
<< " Wi-Fi channel in your legislative regime." << endl
|
||||
<< endl
|
||||
<< " --disable_ap Disabled the Wi-Fi access point." << endl
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
// 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 "CpuGovernor.hpp"
|
||||
#include "ss.hpp"
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
#include "PiPedalException.hpp"
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
// not a feature on Win32.
|
||||
void pipedal::SetCpuGovernor(const std::string &governor) { }
|
||||
std::vector<std::string> pipedal::GetAvailableGovernors() { return std::vector<std::string>(); }
|
||||
|
||||
#else
|
||||
|
||||
static const int SYSFS_RETRIES = 3;
|
||||
|
||||
|
||||
std::string pipedal::GetCpuGovernor()
|
||||
{
|
||||
std::string result;
|
||||
try {
|
||||
std::ifstream f("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
|
||||
f >> result;
|
||||
} catch (const std::exception &)
|
||||
{
|
||||
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
static bool writeAndVerify(std::filesystem::path&sysfsPath, const std::string &value)
|
||||
{
|
||||
// return if the value has already been set.
|
||||
{
|
||||
std::ifstream f;
|
||||
f.open(sysfsPath);
|
||||
if (f.is_open())
|
||||
{
|
||||
std::string line;
|
||||
std::getline(f,line);
|
||||
if (!f.fail() && value == line)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < SYSFS_RETRIES; ++i)
|
||||
{
|
||||
{
|
||||
// write the value.
|
||||
// write the value.
|
||||
std::ofstream f;
|
||||
f.open(sysfsPath);
|
||||
if (f.is_open())
|
||||
{
|
||||
f << value;
|
||||
} else {
|
||||
std::cout << SS("Can't open " << sysfsPath << " for writing.") << std::endl;
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// verify that we wrote it
|
||||
{
|
||||
std::ifstream f;
|
||||
f.open(sysfsPath);
|
||||
if (f.is_open())
|
||||
{
|
||||
std::string line;
|
||||
std::getline(f,line);
|
||||
if (value == line)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
std::cout << "Read value: " << line << "Expected value: " << value << std::endl;
|
||||
}
|
||||
std::cout << "Failed to update " << sysfsPath << std::endl;
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void pipedal::SetCpuGovernor(const std::string &governor) {
|
||||
// using sysfs
|
||||
int nCpu = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
std::filesystem::path base = SS("/sys/devices/system/cpu/cpu" << nCpu);
|
||||
if (!std::filesystem::is_directory(base))
|
||||
break;
|
||||
|
||||
std::filesystem::path sysFsPath = SS("/sys/devices/system/cpu/cpu" << nCpu << "/cpufreq/scaling_governor");
|
||||
|
||||
if (!writeAndVerify(sysFsPath,governor))
|
||||
{
|
||||
throw PiPedalException(SS("Write to " << sysFsPath << " failed."));
|
||||
break;
|
||||
}
|
||||
++nCpu;
|
||||
}
|
||||
}
|
||||
std::vector<std::string> pipedal::GetAvailableGovernors() {
|
||||
return std::vector<std::string> {
|
||||
"performance",
|
||||
"ondemand",
|
||||
"powersave"
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void SetCpuGovernor(const std::string &governor);
|
||||
|
||||
std::vector<std::string> GetAvailableGovernors();
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pipedal {
|
||||
std::string GetCpuGovernor();
|
||||
|
||||
void SetCpuGovernor(const std::string &governor);
|
||||
|
||||
std::vector<std::string> GetAvailableGovernors();
|
||||
};
|
||||
@@ -0,0 +1,27 @@
|
||||
// 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 "GovernorSettings.hpp"
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
JSON_MAP_BEGIN(GovernorSettings)
|
||||
JSON_MAP_REFERENCE(GovernorSettings, governor)
|
||||
JSON_MAP_REFERENCE(GovernorSettings, governors)
|
||||
JSON_MAP_END()
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json.hpp"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
class GovernorSettings {
|
||||
public:
|
||||
std::string governor_;
|
||||
std::vector<std::string> governors_;
|
||||
|
||||
DECLARE_JSON_MAP(GovernorSettings);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
// 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 "Ipv6Helpers.hpp"
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include "ss.hpp"
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <memory.h>
|
||||
#include <exception>
|
||||
#include <netdb.h>
|
||||
|
||||
using namespace pipedal;
|
||||
|
||||
std::string pipedal::GetLinkLocalAddress(const std::string fromAddress);
|
||||
|
||||
static bool IsIpv4MappedAddress(const struct in6_addr &inetAddr6)
|
||||
{
|
||||
return IN6_IS_ADDR_V4MAPPED(&inetAddr6) != 0;
|
||||
}
|
||||
static uint32_t GetIpv4MappedAddress(const struct in6_addr &inetAddr6)
|
||||
{
|
||||
if (!IsIpv4MappedAddress(inetAddr6))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
uint8_t *p = (uint8_t *)&inetAddr6;
|
||||
return htonl(*(uint32_t *)(p + 12));
|
||||
}
|
||||
static bool ipv6NetmaskCompare(const struct in6_addr &left, const struct in6_addr &right, const struct in6_addr &mask)
|
||||
{
|
||||
uint8_t *pLeft = (uint8_t *)&left;
|
||||
uint8_t *pRight = (uint8_t *)&right;
|
||||
uint8_t *pMask = (uint8_t *)&mask;
|
||||
for (int i = 0; i < 16; ++i)
|
||||
{
|
||||
if ((pLeft[i] & pMask[i]) != (pRight[i] & pMask[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool IsIpv4OnLocalSubnet(uint32_t ipv4Addres)
|
||||
{
|
||||
bool result = false;
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return false;
|
||||
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
uint32_t netmask = htonl(((sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr);
|
||||
uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr);
|
||||
|
||||
if ((netmask & ifAddr) == (netmask & ipv4Addres))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string StripPortNumber(const std::string &fromAddress)
|
||||
{
|
||||
std::string address = fromAddress;
|
||||
|
||||
if (address.size() == 0)
|
||||
return fromAddress;
|
||||
|
||||
char lastChar = address[address.size() - 1];
|
||||
size_t pos = address.find_last_of(':');
|
||||
|
||||
// if ipv6, make sure we found an actual port address.
|
||||
size_t posBracket = address.find_last_of(']');
|
||||
if (posBracket != std::string::npos && pos != std::string::npos)
|
||||
{
|
||||
if (posBracket > pos)
|
||||
{
|
||||
pos = std::string::npos;
|
||||
}
|
||||
}
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0, pos);
|
||||
}
|
||||
return address;
|
||||
}
|
||||
|
||||
bool pipedal::IsOnLocalSubnet(const std::string &fromAddress)
|
||||
{
|
||||
std::string address = StripPortNumber(fromAddress);
|
||||
if (address.length() == 0)
|
||||
return false;
|
||||
|
||||
bool result = false;
|
||||
if (address[0] != '[')
|
||||
{
|
||||
// ipv4
|
||||
struct in_addr inetAddr;
|
||||
memset(&inetAddr, 0, sizeof(inetAddr));
|
||||
|
||||
if (inet_pton(AF_INET, address.c_str(), &inetAddr) == 1)
|
||||
{
|
||||
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||
|
||||
result = IsIpv4OnLocalSubnet(remoteAddress);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ipv6
|
||||
if (address[0] != '[' || address[address.length() - 1] != ']')
|
||||
return false;
|
||||
address = address.substr(1, address.length() - 2);
|
||||
// strip scope if neccessary.
|
||||
auto pos = address.find_last_of('%');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0, pos);
|
||||
}
|
||||
|
||||
struct in6_addr inetAddr6;
|
||||
memset(&inetAddr6, 0, sizeof(inetAddr6));
|
||||
if (inet_pton(AF_INET6, address.c_str(), &inetAddr6) == 1)
|
||||
{
|
||||
int32_t remoteAddress = -1;
|
||||
// cases:
|
||||
// [::FFFF:ipv4 address]
|
||||
// [FE80:: ] link local.
|
||||
// [FEC0:: ] site local.
|
||||
// others?
|
||||
if (IsIpv4MappedAddress(inetAddr6))
|
||||
{
|
||||
uint32_t remoteAddress = GetIpv4MappedAddress(inetAddr6);
|
||||
return IsIpv4OnLocalSubnet(remoteAddress);
|
||||
}
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&inetAddr6))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (IN6_IS_ADDR_SITELOCAL(&inetAddr6))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
#if JUNK
|
||||
// if the address is global, we have to reject it.
|
||||
// no point in going further.
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return false;
|
||||
|
||||
const int SITE_LOCAL_SCOPE = 5;
|
||||
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{
|
||||
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||
struct sockaddr_in6 *pNetMask = (struct sockaddr_in6 *)(p->ifa_netmask);
|
||||
if (pAddr->sin6_scope_id <= SITE_LOCAL_SCOPE)
|
||||
{
|
||||
if (ipv6NetmaskCompare(inetAddr6, pAddr->sin6_addr, pNetMask->sin6_addr))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string GetInterfaceForIp4Address(uint32_t ipv4Address)
|
||||
{
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return "";
|
||||
std::string result;
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
uint32_t netmask = htonl(((sockaddr_in *)(p->ifa_netmask))->sin_addr.s_addr);
|
||||
uint32_t ifAddr = htonl(((sockaddr_in *)(p->ifa_addr))->sin_addr.s_addr);
|
||||
|
||||
if ((netmask & ifAddr) == (netmask & ipv4Address))
|
||||
{
|
||||
result = p->ifa_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string GetInterfaceForIp6Address(const in6_addr inetAddr6)
|
||||
{
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return "";
|
||||
std::string result;
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||
struct sockaddr_in6 *pNetMask = (struct sockaddr_in6 *)(p->ifa_netmask);
|
||||
if (ipv6NetmaskCompare(inetAddr6, pAddr->sin6_addr, pNetMask->sin6_addr))
|
||||
{
|
||||
result = p->ifa_name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::string GetLinkLocalAddressForInterface(const std::string &name)
|
||||
{
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0)
|
||||
return "";
|
||||
std::string result;
|
||||
for (ifaddrs *p = ifap; p != nullptr; p = p->ifa_next)
|
||||
{
|
||||
if (p->ifa_addr->sa_family == AF_INET6 && p->ifa_addr != nullptr && p->ifa_netmask != nullptr)
|
||||
{ // TODO: Add support for AF_INET6
|
||||
struct sockaddr_in6 *pAddr = (struct sockaddr_in6 *)(p->ifa_addr);
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&(pAddr->sin6_addr)))
|
||||
{
|
||||
if (name.length() == 0 || name == p->ifa_name)
|
||||
{
|
||||
const int BUFSIZE = 128;
|
||||
char host[BUFSIZE];
|
||||
if (getnameinfo(p->ifa_addr, sizeof(struct sockaddr_in6), host, BUFSIZE, NULL, 0, NI_NUMERICHOST) == 0)
|
||||
{
|
||||
host[BUFSIZE - 1] = '\0';
|
||||
|
||||
// trim the interface spec if present
|
||||
for (char *p = host; *p != 0; ++p)
|
||||
{
|
||||
if (*p == '%')
|
||||
{
|
||||
*p = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
result = SS('[' << host << ']');
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string pipedal::GetLinkLocalAddress(const std::string fromAddress)
|
||||
{
|
||||
std::string address = StripPortNumber(fromAddress);
|
||||
|
||||
std::string result;
|
||||
if (address[0] != '[')
|
||||
{
|
||||
// ipv4
|
||||
struct in_addr inetAddr;
|
||||
memset(&inetAddr, 0, sizeof(inetAddr));
|
||||
|
||||
if (inet_pton(AF_INET, address.c_str(), &inetAddr) == 1)
|
||||
{
|
||||
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||
std::string interfaceName = GetInterfaceForIp4Address(remoteAddress);
|
||||
result = GetLinkLocalAddressForInterface(interfaceName);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ipv6
|
||||
if (address[0] != '[' || address[address.length() - 1] != ']')
|
||||
throw std::invalid_argument("Bad address.");
|
||||
address = address.substr(1, address.length() - 2);
|
||||
// strip scope if neccessary.
|
||||
auto pos = address.find_last_of('%');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0, pos);
|
||||
}
|
||||
|
||||
struct in6_addr inetAddr6;
|
||||
memset(&inetAddr6, 0, sizeof(inetAddr6));
|
||||
if (inet_pton(AF_INET6, address.c_str(), &inetAddr6) == 1)
|
||||
{
|
||||
int32_t remoteAddress = -1;
|
||||
// cases:
|
||||
// [::FFFF:ipv4 address]
|
||||
// [FE80:: ] link local.
|
||||
// [FEC0:: ] site local.
|
||||
// others?
|
||||
if (IN6_IS_ADDR_LINKLOCAL(&inetAddr6))
|
||||
{
|
||||
return address;
|
||||
}
|
||||
if (IN6_IS_ADDR_SITELOCAL(&inetAddr6))
|
||||
{
|
||||
return address;
|
||||
}
|
||||
|
||||
std::string interfaceName;
|
||||
if (IsIpv4MappedAddress(inetAddr6))
|
||||
{
|
||||
uint32_t remoteAddress = GetIpv4MappedAddress(inetAddr6);
|
||||
interfaceName = GetInterfaceForIp4Address(remoteAddress);
|
||||
}
|
||||
else
|
||||
{
|
||||
interfaceName = GetInterfaceForIp6Address(inetAddr6);
|
||||
}
|
||||
result = GetLinkLocalAddressForInterface(interfaceName);
|
||||
}
|
||||
}
|
||||
if (result == "")
|
||||
{
|
||||
result = GetLinkLocalAddressForInterface("");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
|
||||
std::string GetLinkLocalAddress(const std::string fromAddress);
|
||||
|
||||
bool IsOnLocalSubnet(const std::string&fromAddress);
|
||||
|
||||
|
||||
}
|
||||
+2
-9
@@ -33,6 +33,7 @@ using namespace pipedal;
|
||||
#include <thread>
|
||||
#include <semaphore.h>
|
||||
#include "VuUpdate.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
|
||||
#include "RingBuffer.hpp"
|
||||
#include "RingBufferReader.hpp"
|
||||
@@ -99,15 +100,7 @@ static void GetCpuFrequency(uint64_t*freqMin,uint64_t*freqMax)
|
||||
}
|
||||
static std::string GetGovernor()
|
||||
{
|
||||
std::string result;
|
||||
try {
|
||||
std::ifstream f("/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor");
|
||||
f >> result;
|
||||
} catch (const std::exception &)
|
||||
{
|
||||
|
||||
}
|
||||
return result;
|
||||
return pipedal::GetCpuGovernor();
|
||||
}
|
||||
|
||||
|
||||
|
||||
+59
-8
@@ -26,6 +26,7 @@
|
||||
#include "PiPedalConfiguration.hpp"
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "SplitEffect.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
|
||||
#ifndef NO_MLOCK
|
||||
#include <sys/mman.h>
|
||||
@@ -76,14 +77,31 @@ void PiPedalModel::Close()
|
||||
|
||||
PiPedalModel::~PiPedalModel()
|
||||
{
|
||||
CurrentPreset currentPreset;
|
||||
currentPreset.modified_ = this->hasPresetChanged;
|
||||
currentPreset.preset_ = this->pedalBoard;
|
||||
storage.SaveCurrentPreset(currentPreset);
|
||||
|
||||
if (jackHost)
|
||||
try {
|
||||
ShutdownClient::UnmonitorGovernor();
|
||||
} catch (...) // noexcept here!
|
||||
{
|
||||
jackHost->Close();
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
CurrentPreset currentPreset;
|
||||
currentPreset.modified_ = this->hasPresetChanged;
|
||||
currentPreset.preset_ = this->pedalBoard;
|
||||
storage.SaveCurrentPreset(currentPreset);
|
||||
} catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
try {
|
||||
if (jackHost)
|
||||
{
|
||||
jackHost->Close();
|
||||
}
|
||||
} catch (...)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,7 +152,7 @@ void PiPedalModel::Load(const PiPedalConfiguration &configuration)
|
||||
this->webRoot = configuration.GetWebRoot();
|
||||
this->jackServerSettings.ReadJackConfiguration();
|
||||
|
||||
|
||||
ShutdownClient::MonitorGovernor(storage.GetGovernorSettings());
|
||||
|
||||
// lv2Host.Load(configuration.GetLv2Path().c_str());
|
||||
|
||||
@@ -594,6 +612,39 @@ bool PiPedalModel::RenamePreset(int64_t clientId, int64_t instanceId, const std:
|
||||
}
|
||||
}
|
||||
|
||||
GovernorSettings PiPedalModel::GetGovernorSettings()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
GovernorSettings result;
|
||||
result.governor_ = storage.GetGovernorSettings();
|
||||
result.governors_ = pipedal::GetAvailableGovernors();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
void PiPedalModel::SetGovernorSettings(const std::string& governor)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
ShutdownClient::SetGovernorSettings(governor);
|
||||
|
||||
this->storage.SetGovernorSettings(governor);
|
||||
|
||||
IPiPedalModelSubscriber **t = new IPiPedalModelSubscriber *[this->subscribers.size()];
|
||||
{
|
||||
for (size_t i = 0; i < subscribers.size(); ++i)
|
||||
{
|
||||
t[i] = this->subscribers[i];
|
||||
}
|
||||
size_t n = this->subscribers.size();
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
t[i]->OnGovernorSettingsChanged(governor);
|
||||
}
|
||||
delete[] t;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void PiPedalModel::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(mutex);
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include "Lv2Host.hpp"
|
||||
#include "GovernorSettings.hpp"
|
||||
#include "PedalBoard.hpp"
|
||||
#include "Storage.hpp"
|
||||
#include "Banks.hpp"
|
||||
@@ -57,6 +58,7 @@ public:
|
||||
virtual void OnNotifyMidiListener(int64_t clientHandle, bool isNote, uint8_t noteOrControl) = 0;
|
||||
virtual void OnNotifyAtomOutput(int64_t clientModel,uint64_t instanceId,const std::string&atomType, const std::string&atomJson) = 0;
|
||||
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) = 0;
|
||||
virtual void OnGovernorSettingsChanged(const std::string &governor) = 0;
|
||||
virtual void Close() = 0;
|
||||
};
|
||||
|
||||
@@ -193,6 +195,9 @@ public:
|
||||
|
||||
void SetWifiConfigSettings(const WifiConfigSettings&wifiConfigSettings);
|
||||
WifiConfigSettings GetWifiConfigSettings();
|
||||
|
||||
void SetGovernorSettings(const std::string& governor);
|
||||
GovernorSettings GetGovernorSettings();
|
||||
|
||||
|
||||
|
||||
|
||||
+20
-1
@@ -28,6 +28,7 @@
|
||||
#include "JackConfiguration.hpp"
|
||||
#include <future>
|
||||
#include <atomic>
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "WifiConfigSettings.hpp"
|
||||
@@ -804,6 +805,17 @@ public:
|
||||
this->Reply(replyTo,"setJackserverSettings");
|
||||
|
||||
}
|
||||
else if (message == "setGovernorSettings") {
|
||||
std::string governor;
|
||||
pReader->read(&governor);
|
||||
std::string fromAddress = this->getFromAddress();
|
||||
if (!IsOnLocalSubnet(fromAddress))
|
||||
{
|
||||
throw PiPedalException("Permission denied. Not on local subnet.");
|
||||
}
|
||||
this->model.SetGovernorSettings(governor);
|
||||
this->Reply(replyTo,"setGovernorSettings");
|
||||
}
|
||||
else if (message == "setWifiConfigSettings") {
|
||||
WifiConfigSettings wifiConfigSettings;
|
||||
pReader->read(&wifiConfigSettings);
|
||||
@@ -812,7 +824,7 @@ public:
|
||||
throw PiPedalException("Can't change server settings when running interactively.");
|
||||
}
|
||||
std::string fromAddress = this->getFromAddress();
|
||||
if (!ShutdownClient::IsOnLocalSubnet(fromAddress))
|
||||
if (!IsOnLocalSubnet(fromAddress))
|
||||
{
|
||||
throw PiPedalException("Permission denied. Not on local subnet.");
|
||||
}
|
||||
@@ -824,6 +836,10 @@ public:
|
||||
else if (message == "getWifiConfigSettings") {
|
||||
this->Reply(replyTo, "getWifiConfigSettings", model.GetWifiConfigSettings());
|
||||
|
||||
}
|
||||
else if (message == "getGovernorSettings") {
|
||||
this->Reply(replyTo, "getGovernorSettings", model.GetGovernorSettings());
|
||||
|
||||
}
|
||||
|
||||
else if (message == "getJackServerSettings") {
|
||||
@@ -1461,6 +1477,9 @@ public:
|
||||
virtual void OnWifiConfigSettingsChanged(const WifiConfigSettings&wifiConfigSettings) {
|
||||
Send("onWifiConfigSettingsChanged",wifiConfigSettings);
|
||||
}
|
||||
virtual void OnGovernorSettingsChanged(const std::string& governor) {
|
||||
Send("onGovernorSettingsChanged",governor);
|
||||
}
|
||||
|
||||
virtual void OnPedalBoardChanged(int64_t clientId, const PedalBoard &pedalBoard)
|
||||
{
|
||||
|
||||
+52
-46
@@ -27,6 +27,7 @@
|
||||
#include <sstream>
|
||||
#include <sys/types.h>
|
||||
#include <ifaddrs.h>
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
|
||||
using namespace pipedal;
|
||||
@@ -165,57 +166,12 @@ bool ShutdownClient::SetJackServerConfiguration(const JackServerSettings & jackS
|
||||
return WriteMessage(s.str().c_str());
|
||||
}
|
||||
|
||||
bool ShutdownClient::IsOnLocalSubnet(const std::string&fromAddress)
|
||||
{
|
||||
std::string address = fromAddress;
|
||||
if (address.size() == 0) return false;
|
||||
char lastChar = address[address.size()-1];
|
||||
if (address[0] != '[' || lastChar != ']') // i.e. not an ipv6 address;
|
||||
{
|
||||
size_t pos = address.find_last_of(':');
|
||||
if (pos != std::string::npos)
|
||||
{
|
||||
address = address.substr(0,pos);
|
||||
}
|
||||
}
|
||||
if (address[0] == '[') return false;
|
||||
|
||||
char buf[512];
|
||||
|
||||
struct in_addr inetAddr;
|
||||
|
||||
memset(&inetAddr,0,sizeof(inetAddr));
|
||||
|
||||
if (inet_pton(AF_INET,address.c_str(),&inetAddr) == 0) {
|
||||
return false;
|
||||
}
|
||||
uint32_t remoteAddress = htonl(inetAddr.s_addr);
|
||||
|
||||
struct ifaddrs *ifap = nullptr;
|
||||
if (getifaddrs(&ifap) != 0) return false;
|
||||
|
||||
bool result = false;
|
||||
for (ifaddrs*p = ifap; p != nullptr; p = p->ifa_next) {
|
||||
if (p->ifa_addr->sa_family == AF_INET && p->ifa_addr != nullptr && p->ifa_netmask != nullptr) { // TODO: Add support for AF_INET6
|
||||
uint32_t netmask = htonl(((sockaddr_in*)(p->ifa_netmask))->sin_addr.s_addr);
|
||||
uint32_t ifAddr = htonl(((sockaddr_in*)(p->ifa_addr))->sin_addr.s_addr);
|
||||
|
||||
if ((netmask & ifAddr) == (netmask & remoteAddress))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
||||
{
|
||||
if (!CanUseShutdownClient())
|
||||
{
|
||||
throw PiPedalException("Can't use ShutdownClient when running interactively.");
|
||||
throw PiPedalException("Can't perform this operation when debugging.");
|
||||
}
|
||||
std::stringstream cmd;
|
||||
cmd << "WifiConfigSettings ";
|
||||
@@ -227,3 +183,53 @@ void ShutdownClient::SetWifiConfig(const WifiConfigSettings & settings)
|
||||
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.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,14 +25,17 @@
|
||||
|
||||
namespace pipedal {
|
||||
|
||||
|
||||
class ShutdownClient {
|
||||
static bool WriteMessage(const char*message);
|
||||
public:
|
||||
static bool CanUseShutdownClient();
|
||||
static bool RequestShutdown(bool restart);
|
||||
static bool SetJackServerConfiguration(const JackServerSettings & jackServerSettings);
|
||||
static bool IsOnLocalSubnet(const std::string&fromAddress);
|
||||
static void SetWifiConfig(const WifiConfigSettings & settings);
|
||||
static void SetGovernorSettings(const std::string & governor);
|
||||
static void MonitorGovernor(const std::string &governor);
|
||||
static void UnmonitorGovernor();
|
||||
};
|
||||
|
||||
} // namespace
|
||||
+212
-103
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "pch.h"
|
||||
#include "CommandLineParser.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
#include <iostream>
|
||||
#include <cstdint>
|
||||
#include <boost/asio.hpp>
|
||||
@@ -40,7 +41,10 @@
|
||||
#include "SetWifiConfig.hpp"
|
||||
#include "SysExec.hpp"
|
||||
#include <filesystem>
|
||||
|
||||
#include <thread>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
using namespace pipedal;
|
||||
@@ -50,15 +54,122 @@ using ip::tcp;
|
||||
|
||||
const size_t MAX_LENGTH = 128;
|
||||
|
||||
|
||||
|
||||
static bool startsWith(const std::string&s, const char*text)
|
||||
class GovernorMonitorThread
|
||||
{
|
||||
if (s.length() < strlen(text)) return false;
|
||||
const char*sp = s.c_str();
|
||||
public:
|
||||
~GovernorMonitorThread()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
void Start(std::string governor)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if (!pThread)
|
||||
{
|
||||
this->governor = governor;
|
||||
cancelled = false;
|
||||
wake = false;
|
||||
pThread = std::make_unique<std::thread>([this]()
|
||||
{ this->ServiceProc(); });
|
||||
} else {
|
||||
this->governor = governor;
|
||||
wake = true;
|
||||
|
||||
lock.unlock();
|
||||
cv.notify_one();
|
||||
}
|
||||
}
|
||||
void Stop()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
if (pThread)
|
||||
{
|
||||
wake = true;
|
||||
cancelled = true;
|
||||
lock.unlock();
|
||||
|
||||
cv.notify_one();
|
||||
pThread->join();
|
||||
pThread.reset();
|
||||
}
|
||||
}
|
||||
void SetGovernor(const std::string &governor)
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
wake = true;
|
||||
this->governor = governor;
|
||||
}
|
||||
cv.notify_one();
|
||||
}
|
||||
|
||||
private:
|
||||
bool wake = false;
|
||||
bool cancelled = false;
|
||||
std::string savedGovernor;
|
||||
void ServiceProc()
|
||||
{
|
||||
savedGovernor = pipedal::GetCpuGovernor();
|
||||
pipedal::SetCpuGovernor(this->governor);
|
||||
while (true)
|
||||
{
|
||||
bool cancelled;
|
||||
std::string governor;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
auto timeToWaitFor = std::chrono::system_clock::now() + 5000ms;
|
||||
cv.wait_until(
|
||||
lock,
|
||||
timeToWaitFor,
|
||||
[this]()
|
||||
{ return wake; });
|
||||
wake = false;
|
||||
governor = this->governor;
|
||||
cancelled = this->cancelled;
|
||||
}
|
||||
if (cancelled) {
|
||||
break;
|
||||
}
|
||||
std::string activeGovernor = pipedal::GetCpuGovernor();
|
||||
if (activeGovernor != governor)
|
||||
{
|
||||
// somebody set it so they must have wanted it.
|
||||
// save the value so that we can restore it when done.
|
||||
savedGovernor = activeGovernor;
|
||||
|
||||
// but insist on using ours!!
|
||||
pipedal::SetCpuGovernor(governor);
|
||||
}
|
||||
}
|
||||
pipedal::SetCpuGovernor(savedGovernor);
|
||||
}
|
||||
std::unique_ptr<std::thread> pThread;
|
||||
std::string governor;
|
||||
std::mutex mutex;
|
||||
bool canceled;
|
||||
std::condition_variable cv;
|
||||
};
|
||||
|
||||
GovernorMonitorThread governorMonitorThread;
|
||||
|
||||
void StopGovernorMonitorThread()
|
||||
{
|
||||
governorMonitorThread.Stop();
|
||||
}
|
||||
void StartGovernorMonitorThread(const std::string&governor)
|
||||
{
|
||||
governorMonitorThread.Start(governor);
|
||||
}
|
||||
|
||||
static bool startsWith(const std::string &s, const char *text)
|
||||
{
|
||||
if (s.length() < strlen(text))
|
||||
return false;
|
||||
const char *sp = s.c_str();
|
||||
while (*text)
|
||||
{
|
||||
if (*text++ != *sp++) return false;
|
||||
if (*text++ != *sp++)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -67,7 +178,7 @@ static std::vector<std::string> tokenize(std::string value)
|
||||
std::vector<std::string> result;
|
||||
std::stringstream s(value);
|
||||
std::string item;
|
||||
while (std::getline(s,item,' '))
|
||||
while (std::getline(s, item, ' '))
|
||||
{
|
||||
if (item.length() != 0)
|
||||
result.push_back(item);
|
||||
@@ -75,26 +186,17 @@ static std::vector<std::string> tokenize(std::string value)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void CaptureAccessPoint(const std::string gatewayAddress)
|
||||
{
|
||||
|
||||
}
|
||||
static void ReleaseAccessPoint(const std::string gatewayAddress)
|
||||
{
|
||||
}
|
||||
|
||||
void delayedRestartProc()
|
||||
static void delayedRestartProc()
|
||||
{
|
||||
sleep(1); // give a chance for websocket messages to propagate.
|
||||
Lv2Log::error("Delayed Restart");
|
||||
std::string pipedalConfigPath = std::filesystem::path(getSelfExePath()).parent_path() / "pipedalconfig";
|
||||
|
||||
std::stringstream s;
|
||||
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
|
||||
if (::system(s.str().c_str())!= EXIT_SUCCESS)
|
||||
s << pipedalConfigPath.c_str() << " --restart --excludeShutdownService";
|
||||
if (::system(s.str().c_str()) != EXIT_SUCCESS)
|
||||
{
|
||||
Lv2Log::error("Delayed Restart failed.");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +212,6 @@ bool setJackConfiguration(JackServerSettings serverSettings)
|
||||
std::thread delayedRestartThread(delayedRestartProc);
|
||||
delayedRestartThread.detach();
|
||||
return true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
class Reader : public std::enable_shared_from_this<Reader>
|
||||
@@ -162,7 +262,7 @@ private:
|
||||
return;
|
||||
}
|
||||
socket.async_write_some(
|
||||
boost::asio::buffer(response.c_str()+ writePosition, response.length()-writePosition),
|
||||
boost::asio::buffer(response.c_str() + writePosition, response.length() - writePosition),
|
||||
boost::bind(&Reader::HandleWrite,
|
||||
shared_from_this(),
|
||||
boost::asio::placeholders::error,
|
||||
@@ -185,7 +285,7 @@ private:
|
||||
if (c == '\n')
|
||||
{
|
||||
std::string command = message.str();
|
||||
cout << "Received command: " << command << endl;
|
||||
cout << command << endl;
|
||||
HandleCommand(command);
|
||||
socket.close();
|
||||
return;
|
||||
@@ -202,59 +302,88 @@ private:
|
||||
socket.close();
|
||||
}
|
||||
}
|
||||
void HandleCommand(const std::string &s)
|
||||
void HandleCommand(const std::string &text)
|
||||
{
|
||||
int result = -1;
|
||||
try {
|
||||
if (startsWith(s,"WifiConfigSettings "))
|
||||
std::string command;
|
||||
std::string args;
|
||||
auto pos = text.find_first_of(' ');
|
||||
if (pos == std::string::npos)
|
||||
{
|
||||
command = text;
|
||||
}
|
||||
else
|
||||
{
|
||||
command = text.substr(0, pos);
|
||||
args = text.substr(pos + 1);
|
||||
}
|
||||
try
|
||||
{
|
||||
if (command == "UnmonitorGovernor")
|
||||
{
|
||||
std::string json = s.substr(strlen("WifiConfigSettings "));
|
||||
std::stringstream ss(json);
|
||||
StopGovernorMonitorThread();
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "MonitorGovernor")
|
||||
{
|
||||
std::stringstream ss(args);
|
||||
std::string governor;
|
||||
try
|
||||
{
|
||||
json_reader reader(ss);
|
||||
reader.read(&governor);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
StartGovernorMonitorThread(governor);
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "GovernorSettings")
|
||||
{
|
||||
std::stringstream ss(args);
|
||||
std::string governor;
|
||||
try
|
||||
{
|
||||
json_reader reader(ss);
|
||||
reader.read(&governor);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
governorMonitorThread.SetGovernor(governor);
|
||||
result = 0;
|
||||
}
|
||||
else if (command == "WifiConfigSettings ")
|
||||
{
|
||||
std::stringstream ss(args);
|
||||
WifiConfigSettings settings;
|
||||
try {
|
||||
try
|
||||
{
|
||||
json_reader reader(ss);
|
||||
reader.read(&settings);
|
||||
} catch (const std::exception &e)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
pipedal::SetWifiConfig(settings);
|
||||
result = 0;
|
||||
|
||||
} else if (startsWith(s,"release_ap "))
|
||||
{
|
||||
std::vector<std::string> argv = tokenize(s);
|
||||
if (argv.size() == 2) {
|
||||
ReleaseAccessPoint(argv[1]);
|
||||
result = 0;
|
||||
} else {
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
|
||||
} else if (startsWith(s,"capture_ap "))
|
||||
{
|
||||
std::vector<std::string> argv = tokenize(s);
|
||||
if (argv.size() == 2) {
|
||||
CaptureAccessPoint(argv[1]);
|
||||
result = 0;
|
||||
} else {
|
||||
throw PiPedalArgumentException("Invalid arguments.");
|
||||
}
|
||||
|
||||
|
||||
} else if (s == "shutdown")
|
||||
}
|
||||
else if (command == "shutdown")
|
||||
{
|
||||
result = sysExec("/usr/sbin/shutdown -P now");
|
||||
}
|
||||
else if (s == "restart")
|
||||
else if (command == "restart")
|
||||
{
|
||||
result = sysExec("/usr/sbin/shutdown -r now");
|
||||
} else if (startsWith(s,"setJackConfiguration "))
|
||||
}
|
||||
else if (command == "setJackConfiguration")
|
||||
{
|
||||
auto remainder = s.substr(strlen("setJackConfiguration "));
|
||||
|
||||
|
||||
std::stringstream input(remainder);
|
||||
std::stringstream input(args);
|
||||
JackServerSettings serverSettings;
|
||||
json_reader reader(input);
|
||||
|
||||
@@ -263,12 +392,18 @@ private:
|
||||
if (input.fail())
|
||||
{
|
||||
result = -1;
|
||||
} else {
|
||||
result = setJackConfiguration(serverSettings) ? 0: -1;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
result = setJackConfiguration(serverSettings) ? 0 : -1;
|
||||
}
|
||||
}
|
||||
} catch (const std::exception &e)
|
||||
else
|
||||
{
|
||||
throw std::invalid_argument(SS("Unknown command:" << command));
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::stringstream t;
|
||||
t << "-2 " << e.what() << "\n";
|
||||
@@ -284,7 +419,6 @@ private:
|
||||
this->writePosition = 0;
|
||||
WriteSome();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class Server
|
||||
@@ -314,16 +448,16 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
//constructor for accepting connection from client
|
||||
// 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)
|
||||
io_service(io_service)
|
||||
|
||||
{
|
||||
StartAccept();
|
||||
}
|
||||
~Server() {
|
||||
|
||||
~Server()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -332,29 +466,26 @@ void runServer(uint16_t port)
|
||||
asio::ip::tcp::endpoint endpoint(ip::make_address_v4("127.0.0.1"), port);
|
||||
asio::io_service ios;
|
||||
|
||||
try {
|
||||
Server server(ios,endpoint);
|
||||
try
|
||||
{
|
||||
Server server(ios, endpoint);
|
||||
ios.run();
|
||||
cout << "Processing terminated." << endl;
|
||||
} catch (const std::exception & e)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
cout << "Error: " << e.what() << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Lv2Log::set_logger(MakeLv2SystemdLogger());
|
||||
CommandLineParser parser;
|
||||
|
||||
uint16_t port = 0;
|
||||
std::string captureAccessPoint;
|
||||
std::string releaseAccessPoint;
|
||||
|
||||
parser.AddOption("-port", &port);
|
||||
parser.AddOption("-captureAP",&captureAccessPoint);
|
||||
parser.AddOption("-releaseAP",&releaseAccessPoint);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -369,34 +500,12 @@ int main(int argc, char **argv)
|
||||
cout << "Error: " << e.what() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (captureAccessPoint.length() != 0)
|
||||
if (port == 0)
|
||||
{
|
||||
try{
|
||||
CaptureAccessPoint(captureAccessPoint);
|
||||
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "Access point captured." << std::endl;
|
||||
} else if (releaseAccessPoint.length() != 0)
|
||||
{
|
||||
try{
|
||||
ReleaseAccessPoint(releaseAccessPoint);
|
||||
} catch (const std::exception &e)
|
||||
{
|
||||
std::cerr << "Error: " << e.what() << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
std::cout << "Access point released." << std::endl;
|
||||
|
||||
} else {
|
||||
if (port == 0) {
|
||||
std::cerr << "Error: port not specified." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
runServer(port);
|
||||
std::cerr << "Error: port not specified." << std::endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
runServer(port);
|
||||
governorMonitorThread.Stop();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ const char *BANK_EXTENSION = ".bank";
|
||||
const char *BANKS_FILENAME = "index.banks";
|
||||
|
||||
#define WIFI_CONFIG_SETTINGS_FILENAME "wifiConfigSettings.json";
|
||||
#define GOVERNOR_SETTINGS_FILENAME "governorSettings.json";
|
||||
|
||||
Storage::Storage()
|
||||
{
|
||||
@@ -182,6 +183,7 @@ void Storage::Initialize()
|
||||
{
|
||||
}
|
||||
LoadWifiConfigSettings();
|
||||
LoadGovernorSettings();
|
||||
}
|
||||
|
||||
|
||||
@@ -802,6 +804,25 @@ int64_t Storage::UploadBank(BankFile&bankFile,int64_t uploadAfter)
|
||||
return lastBank;
|
||||
}
|
||||
|
||||
void Storage::SetGovernorSettings(const std::string & governor)
|
||||
{
|
||||
std::filesystem::path path = this->dataRoot / GOVERNOR_SETTINGS_FILENAME;
|
||||
{
|
||||
std::ofstream f(path);
|
||||
if (!f.is_open())
|
||||
{
|
||||
throw PiPedalException("Unable to write to " + ((std::string)path));
|
||||
}
|
||||
json_writer writer(f);
|
||||
writer.write(governor);
|
||||
this->governorSettings = governor;
|
||||
}
|
||||
}
|
||||
std::string Storage::GetGovernorSettings() const
|
||||
{
|
||||
return this->governorSettings;
|
||||
}
|
||||
|
||||
|
||||
void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings)
|
||||
{
|
||||
@@ -839,7 +860,30 @@ void Storage::SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSetting
|
||||
}
|
||||
this->wifiConfigSettings = copyToStore;
|
||||
}
|
||||
void Storage::LoadGovernorSettings()
|
||||
{
|
||||
std::filesystem::path path = this->dataRoot / GOVERNOR_SETTINGS_FILENAME;
|
||||
|
||||
try {
|
||||
if (std::filesystem::is_regular_file(path))
|
||||
{
|
||||
std::ifstream f(path);
|
||||
if (!f.is_open())
|
||||
{
|
||||
throw PiPedalException("Unable to write to " + ((std::string)path));
|
||||
}
|
||||
json_reader reader(f);
|
||||
std::string governorSettings;
|
||||
reader.read(&governorSettings);
|
||||
this->governorSettings = governorSettings;
|
||||
}
|
||||
} catch (const std::exception&)
|
||||
{
|
||||
this->governorSettings = "performance";
|
||||
}
|
||||
this->wifiConfigSettings.valid_ = true;
|
||||
|
||||
}
|
||||
void Storage::LoadWifiConfigSettings()
|
||||
{
|
||||
std::filesystem::path path = this->dataRoot / WIFI_CONFIG_SETTINGS_FILENAME;
|
||||
@@ -1137,6 +1181,7 @@ uint64_t Storage::CopyPluginPreset(const std::string&pluginUri,uint64_t presetId
|
||||
|
||||
}
|
||||
|
||||
|
||||
JSON_MAP_BEGIN(CurrentPreset)
|
||||
JSON_MAP_REFERENCE(CurrentPreset,modified)
|
||||
JSON_MAP_REFERENCE(CurrentPreset,preset)
|
||||
|
||||
@@ -72,6 +72,7 @@ private:
|
||||
bool isJackChannelSelectionValid = false;
|
||||
JackChannelSelection jackChannelSelection;
|
||||
WifiConfigSettings wifiConfigSettings;
|
||||
std::string governorSettings = "performance";
|
||||
public:
|
||||
Storage();
|
||||
void Initialize();
|
||||
@@ -85,6 +86,7 @@ public:
|
||||
|
||||
|
||||
void LoadWifiConfigSettings();
|
||||
void LoadGovernorSettings();
|
||||
void LoadBank(int64_t instanceId);
|
||||
const PedalBoard& GetCurrentPreset();
|
||||
void SaveCurrentPreset(const PedalBoard&pedalBoard);
|
||||
@@ -116,6 +118,10 @@ public:
|
||||
void SetWifiConfigSettings(const WifiConfigSettings & wifiConfigSettings);
|
||||
WifiConfigSettings GetWifiConfigSettings();
|
||||
|
||||
void SetGovernorSettings(const std::string & governor);
|
||||
std::string GetGovernorSettings() const;
|
||||
|
||||
|
||||
void SaveCurrentPreset(const CurrentPreset ¤tPreset);
|
||||
bool RestoreCurrentPreset(CurrentPreset*pResult);
|
||||
|
||||
|
||||
+35
-5
@@ -27,12 +27,13 @@
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <filesystem>
|
||||
#include "PiPedalConfiguration.hpp"
|
||||
#include "Shutdown.hpp"
|
||||
#include "ShutdownClient.hpp"
|
||||
#include "CommandLineParser.hpp"
|
||||
#include "Lv2SystemdLogger.hpp"
|
||||
#include <sys/stat.h>
|
||||
#include <boost/asio.hpp>
|
||||
#include "HtmlHelper.hpp"
|
||||
#include "Ipv6Helpers.hpp"
|
||||
|
||||
#include <signal.h>
|
||||
#include <semaphore.h>
|
||||
@@ -406,19 +407,26 @@ public:
|
||||
class InterceptConfig : public RequestHandler
|
||||
{
|
||||
private:
|
||||
std::string response;
|
||||
uint64_t maxUploadSize;
|
||||
int portNumber;
|
||||
|
||||
public:
|
||||
InterceptConfig(int portNumber, uint64_t maxUploadSize)
|
||||
: RequestHandler("/var/config.json"),
|
||||
maxUploadSize(maxUploadSize)
|
||||
maxUploadSize(maxUploadSize),
|
||||
portNumber(portNumber)
|
||||
{
|
||||
}
|
||||
std::string GetConfig(const std::string&fromAddress)
|
||||
{
|
||||
std::string linkLocalAddress = GetLinkLocalAddress(fromAddress);
|
||||
|
||||
std::stringstream s;
|
||||
|
||||
s << "{ \"socket_server_port\": " << portNumber
|
||||
<< ", \"socket_server_address\": \"*\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||
response = s.str();
|
||||
<< ", \"socket_server_address\": \"" << linkLocalAddress << "\", \"ui_plugins\": [ ], \"max_upload_size\": " << maxUploadSize << " }";
|
||||
|
||||
return s.str();
|
||||
}
|
||||
virtual ~InterceptConfig() {}
|
||||
|
||||
@@ -428,6 +436,17 @@ public:
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
// intercepted. See the other overload.
|
||||
}
|
||||
|
||||
virtual void head_response(
|
||||
const std::string &fromAddress,
|
||||
const uri&request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::string response = GetConfig(fromAddress);
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(response.length());
|
||||
@@ -439,7 +458,18 @@ public:
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
// intercepted. see the other overload.
|
||||
}
|
||||
|
||||
virtual void get_response(
|
||||
const std::string&fromAddress,
|
||||
const uri &request_uri,
|
||||
const HttpRequest &req,
|
||||
HttpResponse &res,
|
||||
std::error_code &ec)
|
||||
{
|
||||
std::string response = GetConfig(fromAddress);
|
||||
res.set(HttpField::content_type, "application/json");
|
||||
res.set(HttpField::cache_control, "no-cache");
|
||||
res.setContentLength(response.length());
|
||||
|
||||
@@ -53,5 +53,4 @@ template <typename T> class TypeDisplay;
|
||||
#include "lv2/parameters.lv2/parameters.h"
|
||||
#include "lv2/units.lv2/units.h"
|
||||
*/
|
||||
|
||||
#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str())
|
||||
#include "ss.hpp"
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) 2022 Robin Davies
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
// this software and associated documentation files (the "Software"), to deal in
|
||||
// the Software without restriction, including without limitation the rights to
|
||||
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
// the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
// subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
|
||||
// usage: SS("xyz" << 123 << 45.6) returning a std::string rvalue.
|
||||
#define SS(x) ( ((std::stringstream&)(std::stringstream() << x )).str())
|
||||
Reference in New Issue
Block a user