Sunshine master
Self-hosted game stream host for Moonlight.
misc.cpp File Reference

Miscellaneous definitions for Windows. More...

#include <csignal>
#include <filesystem>
#include <iomanip>
#include <iterator>
#include <set>
#include <sstream>
#include <vector>
#include <boost/algorithm/string.hpp>
#include <boost/asio/ip/address.hpp>
#include <boost/process/v1.hpp>
#include <boost/program_options/parsers.hpp>
#include <dwmapi.h>
#include <iphlpapi.h>
#include <timeapi.h>
#include <UserEnv.h>
#include <WinSock2.h>
#include <Windows.h>
#include <WinUser.h>
#include <wlanapi.h>
#include <WS2tcpip.h>
#include <WtsApi32.h>
#include <sddl.h>
#include <Shlwapi.h>
#include "misc.h"
#include "nvprefs/nvprefs_interface.h"
#include "src/entry_handler.h"
#include "src/globals.h"
#include "src/logging.h"
#include "src/platform/common.h"
#include "src/utility.h"
#include "utf_utils.h"
#include <qos2.h>
#include <winternl.h>
Include dependency graph for misc.cpp:

Classes

struct  platf::enum_wnd_context_t
 Stores state while enumerating top-level Windows windows. More...
 
class  platf::qos_t
 Linux QoS state used to tune socket priority while streaming. More...
 
class  platf::win32_high_precision_timer
 Implements the high-precision timer using Win32 waitable timers. More...
 

Macros

#define NTDDI_VERSION   NTDDI_WIN10
 Macro for NTDDI VERSION.
 
#define PROC_THREAD_ATTRIBUTE_JOB_LIST   ProcThreadAttributeValue(13, FALSE, TRUE, FALSE)
 Macro for PROC THREAD ATTRIBUTE JOB LIST.
 
#define UDP_SEND_MSG_SIZE   2
 Macro for UDP SEND MSG SIZE.
 
#define WLAN_API_MAKE_VERSION(_major, _minor)
 Macro for WLAN API MAKE VERSION.
 

Typedefs

using platf::adapteraddrs_t = util::c_ptr<IP_ADAPTER_ADDRESSES>
 Owning pointer for GetAdaptersAddresses results.
 

Functions

void platf::adjust_thread_priority (thread_priority_e priority)
 Apply the requested scheduling priority to the current thread.
 
LPPROC_THREAD_ATTRIBUTE_LIST platf::allocate_proc_thread_attr_list (DWORD attribute_count)
 Allocate and initialize a Windows process-thread attribute list.
 
std::filesystem::path platf::appdata ()
 Performs migration if necessary, then returns the appdata directory.
 
void platf::append_string_to_environment_block (wchar_t *env_block, int &offset, const std::wstring &wstr)
 Append a null-terminated string to a Windows environment block.
 
bp::child platf::create_boost_child_from_results (bool process_launched, const std::string &cmd, std::error_code &ec, PROCESS_INFORMATION &process_info)
 Create a bp::child object from the results of launching a process.
 
std::wstring platf::create_environment_block (const bp::environment &env)
 Create environment block.
 
std::unique_ptr< high_precision_timerplatf::create_high_precision_timer ()
 Create platform-specific timer capable of high-precision sleep.
 
STARTUPINFOEXW platf::create_startup_info (FILE *file, HANDLE *job, std::error_code &ec)
 Create a STARTUPINFOEXW structure for launching a process.
 
void platf::enable_mouse_keys ()
 Enable or disable X11 mouse keys for the current session.
 
std::unique_ptr< deinit_tplatf::enable_socket_qos (uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type, bool dscp_tagging)
 Enable QoS on the given socket for traffic to the specified destination.
 
std::wstring platf::escape_argument (const std::wstring &argument)
 Quote/escape an argument according to the Windows parsing convention.
 
std::wstring platf::escape_argument_for_cmd (const std::wstring &argument)
 Escape an argument according to cmd's parsing convention.
 
void platf::free_proc_thread_attr_list (LPPROC_THREAD_ATTRIBUTE_LIST list)
 Release proc thread attr list resources.
 
std::string platf::from_sockaddr (const sockaddr *const)
 Convert a socket address to a printable IP address.
 
std::pair< std::uint16_t, std::string > platf::from_sockaddr_ex (const sockaddr *const)
 Convert a socket address to a port and printable IP address.
 
adapteraddrs_t platf::get_adapteraddrs ()
 Read Windows adapter addresses with automatic buffer sizing.
 
std::string platf::get_host_name ()
 Returns the current computer name in UTF-8.
 
std::string platf::get_mac_address (const std::string_view &address)
 Return the hardware MAC address associated with a network address.
 
bool platf::getFileVersionInfo (const std::filesystem::path &file_path, std::string &version_str)
 Get file version information from a Windows executable or driver file.
 
std::error_code platf::impersonate_current_user (HANDLE user_token, std::function< void()> callback)
 Impersonate the current user and invoke the callback function.
 
bool platf::is_running_as_system ()
 Check if the current process is running with system-level privileges.
 
bool platf::IsUserAdmin (HANDLE user_token)
 Check whether a Windows access token belongs to an administrator.
 
bool platf::merge_user_environment_block (bp::environment &env, HANDLE shell_token)
 Merge user environment variables into a Windows environment block.
 
NTSTATUS NTAPI NtSetTimerResolution (ULONG DesiredResolution, BOOLEAN SetResolution, PULONG CurrentResolution)
 Dynamically resolve NtSetTimerResolution from ntdll.
 
void platf::open_url (const std::string &url)
 Open a url in the default web browser.
 
bool platf::override_per_user_predefined_keys (HANDLE token)
 This function overrides HKEY_CURRENT_USER and HKEY_CLASSES_ROOT using the provided token.
 
void platf::print_status (const std::string_view &prefix, HRESULT status)
 Write status details to the log.
 
bool platf::process_group_running (std::uintptr_t native_handle)
 Check if a process group still has running children.
 
int64_t platf::qpc_counter ()
 Read the current Windows high-resolution performance counter.
 
std::chrono::nanoseconds platf::qpc_time_difference (int64_t performance_counter1, int64_t performance_counter2)
 Convert the difference between two QPC readings to nanoseconds.
 
bool platf::request_process_group_exit (std::uintptr_t native_handle)
 Attempt to gracefully terminate a process group.
 
std::wstring platf::resolve_command_string (const std::string &raw_cmd, const std::wstring &working_dir, HANDLE token, DWORD &creation_flags)
 Resolve the given raw command into a proper command string for CreateProcess().
 
std::string platf::resolve_render_device ()
 Resolves the render device path to use for hardware encoding.
 
void platf::restart ()
 Restart the Sunshine process through the platform launcher.
 
void platf::restart_on_exit ()
 Request a Sunshine process restart on exit.
 
HANDLE platf::retrieve_users_token (bool elevated)
 Obtain the current sessions user's primary token with elevated privileges.
 
bp::child platf::run_command (bool elevated, bool interactive, const std::string &cmd, boost::filesystem::path &working_dir, const bp::environment &env, FILE *file, std::error_code &ec, bp::group *group)
 Run a command on the users profile.
 
bool platf::send (send_info_t &send_info)
 Send the serialized response over the active socket.
 
bool platf::send_batch (batched_send_info_t &send_info)
 Send multiple fixed-size UDP payload blocks using the platform backend.
 
void platf::set_thread_name (const std::string &name)
 Name the current thread for use with development tools.
 
void platf::streaming_will_start ()
 Apply Linux platform state before streaming starts.
 
void platf::streaming_will_stop ()
 Restore Linux platform state after streaming stops.
 
HDESK platf::syncThreadDesktop ()
 Synchronize thread desktop.
 
struct sockaddr_in platf::to_sockaddr (boost::asio::ip::address_v4 address, uint16_t port)
 Convert to sockaddr.
 
struct sockaddr_in6 platf::to_sockaddr (boost::asio::ip::address_v6 address, uint16_t port)
 Convert to sockaddr.
 

Variables

bool platf::enabled_mouse_keys = false
 Tracks whether Windows Mouse Keys was enabled before Sunshine changed it.
 
decltype(QOSAddSocketToFlow) * platf::fn_QOSAddSocketToFlow = nullptr
 Fn QoS add socket to flow.
 
decltype(QOSCreateHandle) * platf::fn_QOSCreateHandle = nullptr
 Fn QoS create handle.
 
decltype(QOSRemoveSocketFromFlow) * platf::fn_QOSRemoveSocketFromFlow = nullptr
 Fn QoS remove socket from flow.
 
decltype(WlanCloseHandle) * platf::fn_WlanCloseHandle = nullptr
 Fn wlan close handle.
 
decltype(WlanEnumInterfaces) * platf::fn_WlanEnumInterfaces = nullptr
 Fn wlan enum interfaces.
 
decltype(WlanFreeMemory) * platf::fn_WlanFreeMemory = nullptr
 Fn wlan free memory.
 
decltype(WlanOpenHandle) * platf::fn_WlanOpenHandle = nullptr
 Fn wlan open handle.
 
decltype(WlanSetInterface) * platf::fn_WlanSetInterface = nullptr
 Fn wlan set interface.
 
MOUSEKEYS platf::previous_mouse_keys_state
 Previous mouse keys state.
 
HANDLE platf::qos_handle = nullptr
 QoS handle.
 
HANDLE platf::wlan_handle = nullptr
 Wlan handle.
 

Detailed Description

Miscellaneous definitions for Windows.

Macro Definition Documentation

◆ WLAN_API_MAKE_VERSION

#define WLAN_API_MAKE_VERSION ( _major,
_minor )
Value:
(((DWORD) (_minor)) << 16 | (_major))

Macro for WLAN API MAKE VERSION.

Function Documentation

◆ adjust_thread_priority()

void platf::adjust_thread_priority ( thread_priority_e priority)

Apply the requested scheduling priority to the current thread.

Parameters
priorityThread priority requested from the platform backend.

◆ allocate_proc_thread_attr_list()

LPPROC_THREAD_ATTRIBUTE_LIST platf::allocate_proc_thread_attr_list ( DWORD attribute_count)

Allocate and initialize a Windows process-thread attribute list.

Parameters
attribute_countAttribute count.
Returns
Initialized attribute list, or nullptr when allocation fails.

◆ appdata()

std::filesystem::path platf::appdata ( )

Performs migration if necessary, then returns the appdata directory.

This is used for the log directory, so it cannot invoke Boost logging!

Returns
The path of the appdata directory that should be used.

◆ append_string_to_environment_block()

void platf::append_string_to_environment_block ( wchar_t * env_block,
int & offset,
const std::wstring & wstr )

Append a null-terminated string to a Windows environment block.

Parameters
env_blockEnv block.
offsetByte offset used when converting from the wide string buffer.
wstrWide-character string being converted to UTF-8.

◆ create_boost_child_from_results()

bp::child platf::create_boost_child_from_results ( bool process_launched,
const std::string & cmd,
std::error_code & ec,
PROCESS_INFORMATION & process_info )

Create a bp::child object from the results of launching a process.

Parameters
process_launchedA boolean indicating if the launch was successful.
cmdThe command that was used to launch the process.
ecA reference to an std::error_code object that will store any error that occurred during the launch.
process_infoA reference to a PROCESS_INFORMATION structure that contains information about the new process.
Returns
A bp::child object representing the new process, or an empty bp::child object if the launch failed.

◆ create_environment_block()

std::wstring platf::create_environment_block ( const bp::environment & env)

Create environment block.

Parameters
envEnvironment variables for the child process.
Returns
Created environment block object or status.

◆ create_high_precision_timer()

std::unique_ptr< high_precision_timer > platf::create_high_precision_timer ( )

Create platform-specific timer capable of high-precision sleep.

Returns
A unique pointer to timer

◆ create_startup_info()

STARTUPINFOEXW platf::create_startup_info ( FILE * file,
HANDLE * job,
std::error_code & ec )

Create a STARTUPINFOEXW structure for launching a process.

Parameters
fileA pointer to a FILE object that will be used as the standard output and error for the new process, or null if not needed.
jobA job object handle to insert the new process into. This pointer must remain valid for the life of this startup info!
ecA reference to a std::error_code object that will store any error that occurred during the creation of the structure.
Returns
A structure that contains information about how to launch the new process.

◆ enable_socket_qos()

std::unique_ptr< deinit_t > platf::enable_socket_qos ( uintptr_t native_socket,
boost::asio::ip::address & address,
uint16_t port,
qos_data_type_e data_type,
bool dscp_tagging )

Enable QoS on the given socket for traffic to the specified destination.

Enables QoS on the given socket for traffic to the specified destination.

Parameters
native_socketThe native socket handle.
addressThe destination address for traffic sent on this socket.
portThe destination port for traffic sent on this socket.
data_typeThe type of traffic sent on this socket.
dscp_taggingSpecifies whether to enable DSCP tagging on outgoing traffic.
Returns
Cleanup handle that restores or releases QoS state when destroyed.

◆ escape_argument()

std::wstring platf::escape_argument ( const std::wstring & argument)

Quote/escape an argument according to the Windows parsing convention.

Parameters
argumentThe raw argument to process.
Returns
An argument string suitable for use by CreateProcess().

◆ escape_argument_for_cmd()

std::wstring platf::escape_argument_for_cmd ( const std::wstring & argument)

Escape an argument according to cmd's parsing convention.

Parameters
argumentAn argument already escaped by escape_argument().
Returns
An argument string suitable for use by cmd.exe.

◆ free_proc_thread_attr_list()

void platf::free_proc_thread_attr_list ( LPPROC_THREAD_ATTRIBUTE_LIST list)

Release proc thread attr list resources.

Parameters
listMulti-string list returned by the Windows API.

◆ from_sockaddr()

std::string platf::from_sockaddr ( const sockaddr * const ip_addr)

Convert a socket address to a printable IP address.

Parameters
ip_addrSocket address to format.
Returns
Value converted from sockaddr.

◆ from_sockaddr_ex()

std::pair< std::uint16_t, std::string > platf::from_sockaddr_ex ( const sockaddr * const ip_addr)

Convert a socket address to a port and printable IP address.

Parameters
ip_addrSocket address to format.
Returns
Value converted from sockaddr ex.

◆ get_adapteraddrs()

adapteraddrs_t platf::get_adapteraddrs ( )

Read Windows adapter addresses with automatic buffer sizing.

Returns
Adapter-address list populated by GetAdaptersAddresses.

◆ get_host_name()

std::string platf::get_host_name ( )

Returns the current computer name in UTF-8.

Returns
Computer name or a placeholder upon failure.

◆ get_mac_address()

std::string platf::get_mac_address ( const std::string_view & address)

Return the hardware MAC address associated with a network address.

Parameters
addressNetwork address being parsed or filtered.
Returns
Hardware MAC address string, or an empty string when it cannot be resolved.

◆ getFileVersionInfo()

bool platf::getFileVersionInfo ( const std::filesystem::path & file_path,
std::string & version_str )

Get file version information from a Windows executable or driver file.

Parameters
file_pathPath to the file to query.
version_strOutput parameter for version string in format "major.minor.build.revision".
Returns
true if version info was successfully extracted, false otherwise.

◆ impersonate_current_user()

std::error_code platf::impersonate_current_user ( HANDLE user_token,
std::function< void()> callback )

Impersonate the current user and invoke the callback function.

Parameters
user_tokenA handle to the user's token that was obtained from the shell.
callbackA function that will be executed while impersonating the user.
Returns
Object that will store any error that occurred during the impersonation

◆ is_running_as_system()

bool platf::is_running_as_system ( )

Check if the current process is running with system-level privileges.

Returns
true if the current process has system-level privileges, false otherwise.

◆ IsUserAdmin()

bool platf::IsUserAdmin ( HANDLE user_token)

Check whether a Windows access token belongs to an administrator.

Parameters
user_tokenWindows access token to inspect.
Returns
True when the inspected token has administrator privileges.

◆ merge_user_environment_block()

bool platf::merge_user_environment_block ( bp::environment & env,
HANDLE shell_token )

Merge user environment variables into a Windows environment block.

Parameters
envEnvironment variables for the child process.
shell_tokenShell token.
Returns
True when the user environment block was merged into env.

◆ NtSetTimerResolution()

NTSTATUS NTAPI NtSetTimerResolution ( ULONG DesiredResolution,
BOOLEAN SetResolution,
PULONG CurrentResolution )

Dynamically resolve NtSetTimerResolution from ntdll.

Parameters
DesiredResolutionDesired resolution.
SetResolutionSet resolution.
CurrentResolutionCurrent resolution.
Returns
NTSTATUS reported by the system timer-resolution request.

◆ open_url()

void platf::open_url ( const std::string & url)

Open a url in the default web browser.

Parameters
urlThe url to open.

◆ override_per_user_predefined_keys()

bool platf::override_per_user_predefined_keys ( HANDLE token)

This function overrides HKEY_CURRENT_USER and HKEY_CLASSES_ROOT using the provided token.

Parameters
tokenThe primary token identifying the user to use, or nullptr to restore original keys.
Returns
true if the override or restore operation was successful.

◆ print_status()

void platf::print_status ( const std::string_view & prefix,
HRESULT status )

Write status details to the log.

Parameters
prefixText prefix used when formatting the message.
statusNative status code returned by the platform API.

◆ process_group_running()

bool platf::process_group_running ( std::uintptr_t native_handle)

Check if a process group still has running children.

Parameters
native_handleThe native handle of the process group.
Returns
true if processes are still running.

◆ qpc_counter()

int64_t platf::qpc_counter ( )

Read the current Windows high-resolution performance counter.

Returns
Raw QPC tick value from QueryPerformanceCounter.

◆ qpc_time_difference()

std::chrono::nanoseconds platf::qpc_time_difference ( int64_t performance_counter1,
int64_t performance_counter2 )

Convert the difference between two QPC readings to nanoseconds.

Parameters
performance_counter1Newer performance-counter reading.
performance_counter2Older performance-counter reading.
Returns
Duration represented by the difference between two QPC values.

◆ request_process_group_exit()

bool platf::request_process_group_exit ( std::uintptr_t native_handle)

Attempt to gracefully terminate a process group.

Parameters
native_handleThe native handle of the process group.
Returns
true if termination was successfully requested.

◆ resolve_command_string()

std::wstring platf::resolve_command_string ( const std::string & raw_cmd,
const std::wstring & working_dir,
HANDLE token,
DWORD & creation_flags )

Resolve the given raw command into a proper command string for CreateProcess().

This converts URLs and non-executable file paths into a runnable command like ShellExecute().

Parameters
raw_cmdThe raw command provided by the user.
working_dirThe working directory for the new process.
tokenThe user token currently being impersonated or nullptr if running as ourselves.
creation_flagsThe creation flags for CreateProcess(), which may be modified by this function.
Returns
A command string suitable for use by CreateProcess().

◆ resolve_render_device()

std::string platf::resolve_render_device ( )

Resolves the render device path to use for hardware encoding.

If config::video.adapter_name is set, returns that. Otherwise, auto-detects the GPU with a connected display via find_render_node_with_display(). Falls back to /dev/dri/renderD128 if detection fails.

Returns
Resolved render device path (may be empty on non-Linux platforms).

◆ retrieve_users_token()

HANDLE platf::retrieve_users_token ( bool elevated)

Obtain the current sessions user's primary token with elevated privileges.

Returns
The user's token. If user has admin capability it will be elevated, otherwise it will be a limited token. On error, nullptr.
Parameters
elevatedWhether the command should run with elevated privileges.

◆ run_command()

bp::child platf::run_command ( bool elevated,
bool interactive,
const std::string & cmd,
boost::filesystem::path & working_dir,
const bp::environment & env,
FILE * file,
std::error_code & ec,
bp::group * group )

Run a command on the users profile.

Launches a child process as the user, using the current user's environment and a specific working directory.

Parameters
elevatedSpecify whether to elevate the process.
interactiveSpecify whether this will run in a window or hidden.
cmdThe command to run.
working_dirThe working directory for the new process.
envThe environment variables to use for the new process.
fileA file object to redirect the child process's output to (may be nullptr).
ecAn error code, set to indicate any errors that occur during the launch process.
groupA pointer to a bp::group object to which the new process should belong (may be nullptr).
Returns
A bp::child object representing the new process, or an empty bp::child object if the launch fails.

◆ send()

bool platf::send ( send_info_t & send_info)

Send the serialized response over the active socket.

Parameters
send_infoSocket addresses, buffers, and sizes for the send operation.
Returns
True when the packet is submitted to the socket.

◆ send_batch()

bool platf::send_batch ( batched_send_info_t & send_info)

Send multiple fixed-size UDP payload blocks using the platform backend.

Parameters
send_infoSocket addresses, buffers, and sizes for the send operation.
Returns
True when all requested packet blocks are submitted to the socket.

◆ set_thread_name()

void platf::set_thread_name ( const std::string & name)

Name the current thread for use with development tools.

Note
On Linux this will be truncated after 15 characters.
Parameters
nameHuman-readable name to assign.

◆ syncThreadDesktop()

HDESK platf::syncThreadDesktop ( )

Synchronize thread desktop.

Returns
true when the thread desktop was synchronized successfully.

◆ to_sockaddr() [1/2]

SOCKADDR_IN platf::to_sockaddr ( boost::asio::ip::address_v4 address,
uint16_t port )

Convert to sockaddr.

Parameters
addressNetwork address being parsed or filtered.
portTCP or UDP port number.
Returns
Value converted to sockaddr.

◆ to_sockaddr() [2/2]

SOCKADDR_IN6 platf::to_sockaddr ( boost::asio::ip::address_v6 address,
uint16_t port )

Convert to sockaddr.

Parameters
addressNetwork address being parsed or filtered.
portTCP or UDP port number.
Returns
Value converted to sockaddr.