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:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user