From 64a6c1419b267e221ab4afffb1cc64ab9a0f4283 Mon Sep 17 00:00:00 2001 From: loki Date: Wed, 16 Jun 2021 11:26:54 +0200 Subject: [PATCH] store state in .config/sunshine on Linux --- CMakeLists.txt | 1 + sunshine/config.cpp | 50 ++++++++++++---- sunshine/config.h | 14 +++-- sunshine/platform/common.h | 6 +- sunshine/platform/linux/display.cpp | 69 +--------------------- sunshine/platform/linux/misc.cpp | 88 +++++++++++++++++++++++++++++ 6 files changed, 144 insertions(+), 84 deletions(-) create mode 100644 sunshine/platform/linux/misc.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c8cdcaa..f7e9dec9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/sunshine/config.cpp b/sunshine/config.cpp index da29f8ed..800cd4bd 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -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 &vars, con } } +void path_f(std::unordered_map &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 &vars, const std::string &name, int &input) { auto it = vars.find(name); @@ -549,19 +578,20 @@ void apply_config(std::unordered_map &&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 &&vars) { int_between_f(vars, "channels", stream.channels, { 1, std::numeric_limits::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::min(); diff --git a/sunshine/config.h b/sunshine/config.h index 1ff02801..7f05a16f 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -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 resolutions; @@ -90,12 +91,13 @@ enum flag_e : std::size_t { struct sunshine_t { int min_log_level; std::bitset 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; diff --git a/sunshine/platform/common.h b/sunshine/platform/common.h index 2f131a3b..5522dba6 100644 --- a/sunshine/platform/common.h +++ b/sunshine/platform/common.h @@ -5,11 +5,13 @@ #ifndef SUNSHINE_COMMON_H #define SUNSHINE_COMMON_H -#include "sunshine/utility.h" #include +#include #include #include +#include "sunshine/utility.h" + struct sockaddr; struct AVFrame; @@ -226,6 +228,8 @@ void freeInput(void *); using input_t = util::safe_ptr; +std::filesystem::path appdata(); + std::string get_mac_address(const std::string_view &address); std::string from_sockaddr(const sockaddr *const); diff --git a/sunshine/platform/linux/display.cpp b/sunshine/platform/linux/display.cpp index 1084cccb..9abae925 100644 --- a/sunshine/platform/linux/display.cpp +++ b/sunshine/platform/linux/display.cpp @@ -6,9 +6,6 @@ #include -#include -#include - #include #include #include @@ -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; using xcb_connect_t = util::safe_ptr; using xcb_img_t = util::c_ptr; @@ -402,68 +399,6 @@ std::shared_ptr 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 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); } diff --git a/sunshine/platform/linux/misc.cpp b/sunshine/platform/linux/misc.cpp new file mode 100644 index 00000000..d4cdbfe7 --- /dev/null +++ b/sunshine/platform/linux/misc.cpp @@ -0,0 +1,88 @@ +#include "sunshine/platform/common.h" + +#include + +#include +#include +#include +#include + +#include "sunshine/main.h" + +using namespace std::literals; +namespace fs = std::filesystem; + +namespace platf { +using ifaddr_t = util::safe_ptr; + +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 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 \ No newline at end of file