store state in .config/sunshine on Linux

This commit is contained in:
loki
2021-06-16 11:26:54 +02:00
parent 6f95d360b5
commit 64a6c1419b
6 changed files with 144 additions and 84 deletions

View File

@@ -100,6 +100,7 @@ else()
set(PLATFORM_TARGET_FILES
sunshine/platform/linux/vaapi.h
sunshine/platform/linux/vaapi.cpp
sunshine/platform/linux/misc.cpp
sunshine/platform/linux/display.cpp
sunshine/platform/linux/audio.cpp
sunshine/platform/linux/input.cpp

View File

@@ -1,4 +1,5 @@
#include <algorithm>
#include <filesystem>
#include <fstream>
#include <functional>
#include <iostream>
@@ -10,13 +11,17 @@
#include "main.h"
#include "utility.h"
#include "platform/common.h"
namespace fs = std::filesystem;
using namespace std::literals;
#define CA_DIR "credentials"
#define PRIVATE_KEY_FILE CA_DIR "/cakey.pem"
#define CERTIFICATE_FILE CA_DIR "/cacert.pem"
#define APPS_JSON_PATH SUNSHINE_ASSETS_DIR "/" APPS_JSON
namespace config {
using namespace std::literals;
namespace nv {
enum preset_e : int {
@@ -348,6 +353,30 @@ void string_restricted_f(std::unordered_map<std::string, std::string> &vars, con
}
}
void path_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, fs::path &input) {
// appdata needs to be retrieved once only
static auto appdata = platf::appdata();
std::string temp;
string_f(vars, name, temp);
if(!temp.empty()) {
input = temp;
}
if(input.is_relative()) {
input = appdata / input;
}
auto dir = input;
dir.remove_filename();
// Ensure the directories exists
if(!fs::exists(dir)) {
fs::create_directories(dir);
}
}
void int_f(std::unordered_map<std::string, std::string> &vars, const std::string &name, int &input) {
auto it = vars.find(name);
@@ -549,19 +578,20 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
string_f(vars, "adapter_name", video.adapter_name);
string_f(vars, "output_name", video.output_name);
string_f(vars, "pkey", nvhttp.pkey);
string_f(vars, "cert", nvhttp.cert);
path_f(vars, "pkey", nvhttp.pkey);
path_f(vars, "cert", nvhttp.cert);
string_f(vars, "sunshine_name", nvhttp.sunshine_name);
string_f(vars, "file_state", nvhttp.file_state);
path_f(vars, "file_state", nvhttp.file_state);
// Must be run after "file_state"
config::sunshine.credentials_file = config::nvhttp.file_state;
path_f(vars, "credentials_file", config::sunshine.credentials_file);
string_f(vars, "external_ip", nvhttp.external_ip);
list_string_f(vars, "resolutions"s, nvhttp.resolutions);
list_int_f(vars, "fps"s, nvhttp.fps);
string_f(vars, "credentials_file", config::sunshine.credentials_file);
if(config::sunshine.credentials_file.empty()) {
config::sunshine.credentials_file = config::nvhttp.file_state;
}
string_f(vars, "audio_sink", audio.sink);
string_f(vars, "virtual_sink", audio.virtual_sink);
@@ -575,7 +605,7 @@ void apply_config(std::unordered_map<std::string, std::string> &&vars) {
int_between_f(vars, "channels", stream.channels, { 1, std::numeric_limits<int>::max() });
string_f(vars, "file_apps", stream.file_apps);
path_f(vars, "file_apps", stream.file_apps);
int_between_f(vars, "fec_percentage", stream.fec_percentage, { 1, 100 });
to = std::numeric_limits<int>::min();

View File

@@ -3,6 +3,7 @@
#include <bitset>
#include <chrono>
#include <filesystem>
#include <optional>
#include <string>
#include <unordered_map>
@@ -47,7 +48,7 @@ struct audio_t {
struct stream_t {
std::chrono::milliseconds ping_timeout;
std::string file_apps;
std::filesystem::path file_apps;
int fec_percentage;
@@ -60,12 +61,12 @@ struct nvhttp_t {
// pc|lan|wan
std::string origin_pin_allowed;
std::string pkey; // must be 2048 bits
std::string cert; // must be signed with a key of 2048 bits
std::filesystem::path pkey; // must be 2048 bits
std::filesystem::path cert; // must be signed with a key of 2048 bits
std::string sunshine_name;
std::string file_state;
std::filesystem::path file_state;
std::string external_ip;
std::vector<std::string> resolutions;
@@ -90,12 +91,13 @@ enum flag_e : std::size_t {
struct sunshine_t {
int min_log_level;
std::bitset<flag::FLAG_SIZE> flags;
std::string credentials_file;
std::filesystem::path credentials_file;
std::string username;
std::string password;
std::string salt;
std::string config_file;
std::filesystem::path config_file;
struct cmd_t {
std::string name;

View File

@@ -5,11 +5,13 @@
#ifndef SUNSHINE_COMMON_H
#define SUNSHINE_COMMON_H
#include "sunshine/utility.h"
#include <bitset>
#include <filesystem>
#include <mutex>
#include <string>
#include "sunshine/utility.h"
struct sockaddr;
struct AVFrame;
@@ -226,6 +228,8 @@ void freeInput(void *);
using input_t = util::safe_ptr<void, freeInput>;
std::filesystem::path appdata();
std::string get_mac_address(const std::string_view &address);
std::string from_sockaddr(const sockaddr *const);

View File

@@ -6,9 +6,6 @@
#include <fstream>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
@@ -25,13 +22,13 @@
#include "vaapi.h"
namespace platf {
using namespace std::literals;
namespace platf {
void freeImage(XImage *);
void freeX(XFixesCursorImage *);
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
using xcb_connect_t = util::safe_ptr<xcb_connection_t, xcb_disconnect>;
using xcb_img_t = util::c_ptr<xcb_shm_get_image_reply_t>;
@@ -402,68 +399,6 @@ std::shared_ptr<display_t> display(platf::mem_type_e hwdevice_type) {
return x11_disp;
}
ifaddr_t get_ifaddrs() {
ifaddrs *p { nullptr };
getifaddrs(&p);
return ifaddr_t { p };
}
std::string from_sockaddr(const sockaddr *const ip_addr) {
char data[INET6_ADDRSTRLEN];
auto family = ip_addr->sa_family;
if(family == AF_INET6) {
inet_ntop(AF_INET6, &((sockaddr_in6 *)ip_addr)->sin6_addr, data,
INET6_ADDRSTRLEN);
}
if(family == AF_INET) {
inet_ntop(AF_INET, &((sockaddr_in *)ip_addr)->sin_addr, data,
INET_ADDRSTRLEN);
}
return std::string { data };
}
std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_addr) {
char data[INET6_ADDRSTRLEN];
auto family = ip_addr->sa_family;
std::uint16_t port;
if(family == AF_INET6) {
inet_ntop(AF_INET6, &((sockaddr_in6 *)ip_addr)->sin6_addr, data,
INET6_ADDRSTRLEN);
port = ((sockaddr_in6 *)ip_addr)->sin6_port;
}
if(family == AF_INET) {
inet_ntop(AF_INET, &((sockaddr_in *)ip_addr)->sin_addr, data,
INET_ADDRSTRLEN);
port = ((sockaddr_in *)ip_addr)->sin_port;
}
return { port, std::string { data } };
}
std::string get_mac_address(const std::string_view &address) {
auto ifaddrs = get_ifaddrs();
for(auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
if(pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
std::ifstream mac_file("/sys/class/net/"s + pos->ifa_name + "/address");
if(mac_file.good()) {
std::string mac_address;
std::getline(mac_file, mac_address);
return mac_address;
}
}
}
BOOST_LOG(warning) << "Unable to find MAC address for "sv << address;
return "00:00:00:00:00:00"s;
}
void freeImage(XImage *p) {
XDestroyImage(p);
}

View File

@@ -0,0 +1,88 @@
#include "sunshine/platform/common.h"
#include <fstream>
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <pwd.h>
#include <unistd.h>
#include "sunshine/main.h"
using namespace std::literals;
namespace fs = std::filesystem;
namespace platf {
using ifaddr_t = util::safe_ptr<ifaddrs, freeifaddrs>;
ifaddr_t get_ifaddrs() {
ifaddrs *p { nullptr };
getifaddrs(&p);
return ifaddr_t { p };
}
fs::path appdata() {
const char *homedir;
if((homedir = getenv("HOME")) == nullptr) {
homedir = getpwuid(geteuid())->pw_dir;
}
return fs::path { homedir } / ".config/sunshine"sv;
}
std::string from_sockaddr(const sockaddr *const ip_addr) {
char data[INET6_ADDRSTRLEN];
auto family = ip_addr->sa_family;
if(family == AF_INET6) {
inet_ntop(AF_INET6, &((sockaddr_in6 *)ip_addr)->sin6_addr, data,
INET6_ADDRSTRLEN);
}
if(family == AF_INET) {
inet_ntop(AF_INET, &((sockaddr_in *)ip_addr)->sin_addr, data,
INET_ADDRSTRLEN);
}
return std::string { data };
}
std::pair<std::uint16_t, std::string> from_sockaddr_ex(const sockaddr *const ip_addr) {
char data[INET6_ADDRSTRLEN];
auto family = ip_addr->sa_family;
std::uint16_t port;
if(family == AF_INET6) {
inet_ntop(AF_INET6, &((sockaddr_in6 *)ip_addr)->sin6_addr, data,
INET6_ADDRSTRLEN);
port = ((sockaddr_in6 *)ip_addr)->sin6_port;
}
if(family == AF_INET) {
inet_ntop(AF_INET, &((sockaddr_in *)ip_addr)->sin_addr, data,
INET_ADDRSTRLEN);
port = ((sockaddr_in *)ip_addr)->sin_port;
}
return { port, std::string { data } };
}
std::string get_mac_address(const std::string_view &address) {
auto ifaddrs = get_ifaddrs();
for(auto pos = ifaddrs.get(); pos != nullptr; pos = pos->ifa_next) {
if(pos->ifa_addr && address == from_sockaddr(pos->ifa_addr)) {
std::ifstream mac_file("/sys/class/net/"s + pos->ifa_name + "/address");
if(mac_file.good()) {
std::string mac_address;
std::getline(mac_file, mac_address);
return mac_address;
}
}
}
BOOST_LOG(warning) << "Unable to find MAC address for "sv << address;
return "00:00:00:00:00:00"s;
}
} // namespace platf