Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/confighttp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "confighttp.h"
#include "crypto.h"
#include "display_device.h"
#include "entry_handler.h"
#include "file_handler.h"
#include "globals.h"
#include "httpcommon.h"
Expand Down Expand Up @@ -1833,6 +1834,9 @@ namespace confighttp {
platf::set_thread_name("confighttp::tcp");
server->start([&display_addr](const unsigned short port) {
BOOST_LOG(info) << "Configuration UI available at [https://"sv << display_addr << ":" << port << "]";
#ifdef _WIN32
service_ctrl::signal_ready();
#endif
});
} catch (boost::system::system_error &err) {
// It's possible the exception gets thrown after calling server->stop() from a different thread
Expand Down
35 changes: 35 additions & 0 deletions src/entry_handler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,13 @@
* @brief Definitions for entry handling functions.
*/
// standard includes
#include <bit>
#include <csignal>
#include <cstdint>
#include <cwchar>
#include <format>
#include <iostream>
#include <string>
#include <thread>

// local includes
Expand Down Expand Up @@ -121,6 +125,37 @@ bool is_gamestream_enabled() {
}

namespace service_ctrl {
/// Environment variable used to pass the inherited service readiness event handle.
constexpr auto SERVICE_READY_EVENT_ENV = L"SUNSHINE_SERVICE_READY_EVENT";

void signal_ready() {
std::wstring event_handle_text(32, L'\0');
auto length = GetEnvironmentVariableW(SERVICE_READY_EVENT_ENV, event_handle_text.data(), static_cast<DWORD>(event_handle_text.size()));
if (length == 0 || length >= event_handle_text.size()) {
return;
}

event_handle_text.resize(length);
wchar_t *end = nullptr;
auto event_handle_value = std::wcstoull(event_handle_text.c_str(), &end, 10);
if (event_handle_value == 0 || *end != L'\0') {
BOOST_LOG(warning) << "Ignoring invalid service ready event handle";
return;
}

auto ready_event_value = static_cast<std::uintptr_t>(event_handle_value);
auto ready_event = std::bit_cast<HANDLE>(ready_event_value);
if (!SetEvent(ready_event)) {
auto winerr = GetLastError();
BOOST_LOG(warning) << "Failed to signal service ready event: "sv << winerr;
SetEnvironmentVariableW(SERVICE_READY_EVENT_ENV, nullptr);
return;
}

CloseHandle(ready_event);
SetEnvironmentVariableW(SERVICE_READY_EVENT_ENV, nullptr);
}

/**
* @brief Owns Windows service-manager handles for the Sunshine service.
*/
Expand Down
8 changes: 8 additions & 0 deletions src/entry_handler.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ bool is_gamestream_enabled();
* @brief Namespace for controlling the Sunshine service model on Windows.
*/
namespace service_ctrl {
/**
* @brief Signal the Windows service wrapper that Sunshine is ready.
* @examples
* signal_ready();
* @examples_end
*/
void signal_ready();

/**
* @brief Check if the service is running.
* @examples
Expand Down
Loading