mirror of
https://github.com/LizardByte/Sunshine.git
synced 2025-02-27 00:40:16 +00:00
Automatic service discovery for Windows
This commit is contained in:
parent
d6eceaf0dc
commit
0cc7e35ed9
@ -43,6 +43,7 @@ if(WIN32)
|
|||||||
include_directories(third-party/ViGEmClient/include)
|
include_directories(third-party/ViGEmClient/include)
|
||||||
|
|
||||||
set(PLATFORM_TARGET_FILES
|
set(PLATFORM_TARGET_FILES
|
||||||
|
sunshine/platform/windows/publish.cpp
|
||||||
sunshine/platform/windows/misc.cpp
|
sunshine/platform/windows/misc.cpp
|
||||||
sunshine/platform/windows/input.cpp
|
sunshine/platform/windows/input.cpp
|
||||||
sunshine/platform/windows/display.h
|
sunshine/platform/windows/display.h
|
||||||
@ -88,6 +89,7 @@ if(WIN32)
|
|||||||
iphlpapi
|
iphlpapi
|
||||||
d3d11 dxgi D3DCompiler
|
d3d11 dxgi D3DCompiler
|
||||||
setupapi
|
setupapi
|
||||||
|
dnsapi
|
||||||
)
|
)
|
||||||
|
|
||||||
set_source_files_properties(third-party/ViGEmClient/src/ViGEmClient.cpp PROPERTIES COMPILE_DEFINITIONS "UNICODE=1;ERROR_INVALID_DEVICE_OBJECT_PARAMETER=650")
|
set_source_files_properties(third-party/ViGEmClient/src/ViGEmClient.cpp PROPERTIES COMPILE_DEFINITIONS "UNICODE=1;ERROR_INVALID_DEVICE_OBJECT_PARAMETER=650")
|
||||||
|
@ -17,7 +17,7 @@ Sunshine is a Gamestream host for Moonlight
|
|||||||
Ubuntu 20.04:
|
Ubuntu 20.04:
|
||||||
Install the following
|
Install the following
|
||||||
```
|
```
|
||||||
sudo apt install cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxrandr-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev libavahi-client-dev
|
sudo apt install cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxrandr-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev
|
||||||
```
|
```
|
||||||
|
|
||||||
### Compilation:
|
### Compilation:
|
||||||
|
@ -9,7 +9,7 @@ environment:
|
|||||||
|
|
||||||
install:
|
install:
|
||||||
- sh: sudo apt update --ignore-missing
|
- sh: sudo apt update --ignore-missing
|
||||||
- sh: sudo apt install -y build-essential fakeroot gcc-10 g++-10 cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxrandr-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev libavahi-client-dev
|
- sh: sudo apt install -y build-essential fakeroot gcc-10 g++-10 cmake libssl-dev libavdevice-dev libboost-thread-dev libboost-filesystem-dev libboost-log-dev libpulse-dev libopus-dev libxtst-dev libx11-dev libxrandr-dev libxfixes-dev libevdev-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev
|
||||||
- cmd: C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git yasm nasm diffutils make"
|
- cmd: C:\msys64\usr\bin\bash -lc "pacman --needed --noconfirm -S mingw-w64-x86_64-openssl mingw-w64-x86_64-cmake mingw-w64-x86_64-toolchain mingw-w64-x86_64-opus mingw-w64-x86_64-x265 mingw-w64-x86_64-boost git yasm nasm diffutils make"
|
||||||
|
|
||||||
before_build:
|
before_build:
|
||||||
|
@ -208,6 +208,11 @@ int main(int argc, char *argv[]) {
|
|||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<platf::deinit_t> unregister;
|
||||||
|
auto sync = std::async(std::launch::async, [&unregister]() {
|
||||||
|
unregister = platf::publish::start();
|
||||||
|
});
|
||||||
|
|
||||||
//FIXME: Temporary workaround: Simple-Web_server needs to be updated or replaced
|
//FIXME: Temporary workaround: Simple-Web_server needs to be updated or replaced
|
||||||
if(shutdown_event->peek()) {
|
if(shutdown_event->peek()) {
|
||||||
return 0;
|
return 0;
|
||||||
@ -215,9 +220,9 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
task_pool.start(1);
|
task_pool.start(1);
|
||||||
|
|
||||||
auto deinit = platf::publish::start();
|
|
||||||
std::thread httpThread { nvhttp::start };
|
std::thread httpThread { nvhttp::start };
|
||||||
std::thread configThread { confighttp::start };
|
std::thread configThread { confighttp::start };
|
||||||
|
|
||||||
stream::rtpThread();
|
stream::rtpThread();
|
||||||
|
|
||||||
httpThread.join();
|
httpThread.join();
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
#include "utility.h"
|
#include "utility.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
namespace net {
|
|
||||||
using namespace std::literals;
|
using namespace std::literals;
|
||||||
|
namespace net {
|
||||||
// In the format "xxx.xxx.xxx.xxx/x"
|
// In the format "xxx.xxx.xxx.xxx/x"
|
||||||
std::pair<std::uint32_t, std::uint32_t> ip_block(const std::string_view &ip);
|
std::pair<std::uint32_t, std::uint32_t> ip_block(const std::string_view &ip);
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ std::vector<std::pair<std::uint32_t, std::uint32_t>> pc_ips {
|
|||||||
};
|
};
|
||||||
std::vector<std::tuple<std::uint32_t, std::uint32_t>> lan_ips {
|
std::vector<std::tuple<std::uint32_t, std::uint32_t>> lan_ips {
|
||||||
ip_block("192.168.0.0/16"sv),
|
ip_block("192.168.0.0/16"sv),
|
||||||
ip_block("172.16.0.0/12"),
|
ip_block("172.16.0.0/12"sv),
|
||||||
ip_block("10.0.0.0/8"sv)
|
ip_block("10.0.0.0/8"sv)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
194
sunshine/platform/windows/publish.cpp
Normal file
194
sunshine/platform/windows/publish.cpp
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <windns.h>
|
||||||
|
#include <winerror.h>
|
||||||
|
|
||||||
|
#include <boost/asio/ip/host_name.hpp>
|
||||||
|
|
||||||
|
#include "sunshine/config.h"
|
||||||
|
#include "sunshine/main.h"
|
||||||
|
#include "sunshine/nvhttp.h"
|
||||||
|
#include "sunshine/platform/common.h"
|
||||||
|
#include "sunshine/thread_safe.h"
|
||||||
|
|
||||||
|
#include "sunshine/network.h"
|
||||||
|
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
#define __SV(quote) L##quote##sv
|
||||||
|
#define SV(quote) __SV(quote)
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
constexpr auto DNS_REQUEST_PENDING = 9506L;
|
||||||
|
constexpr auto DNS_QUERY_REQUEST_VERSION1 = 0x1;
|
||||||
|
constexpr auto DNS_QUERY_RESULTS_VERSION1 = 0x1;
|
||||||
|
|
||||||
|
#define SERVICE_DOMAIN "local"
|
||||||
|
|
||||||
|
constexpr auto SERVICE_INSTANCE_NAME = SV(SERVICE_NAME "." SERVICE_TYPE "." SERVICE_DOMAIN);
|
||||||
|
constexpr auto SERVICE_TYPE_DOMAIN = SV(SERVICE_TYPE "." SERVICE_DOMAIN);
|
||||||
|
|
||||||
|
typedef struct _DNS_SERVICE_INSTANCE {
|
||||||
|
LPWSTR pszInstanceName;
|
||||||
|
LPWSTR pszHostName;
|
||||||
|
|
||||||
|
IP4_ADDRESS *ip4Address;
|
||||||
|
IP6_ADDRESS *ip6Address;
|
||||||
|
|
||||||
|
WORD wPort;
|
||||||
|
WORD wPriority;
|
||||||
|
WORD wWeight;
|
||||||
|
|
||||||
|
// Property list
|
||||||
|
DWORD dwPropertyCount;
|
||||||
|
|
||||||
|
PWSTR *keys;
|
||||||
|
PWSTR *values;
|
||||||
|
|
||||||
|
DWORD dwInterfaceIndex;
|
||||||
|
} DNS_SERVICE_INSTANCE, *PDNS_SERVICE_INSTANCE;
|
||||||
|
|
||||||
|
typedef VOID WINAPI DNS_SERVICE_REGISTER_COMPLETE(
|
||||||
|
_In_ DWORD Status,
|
||||||
|
_In_ PVOID pQueryContext,
|
||||||
|
_In_ PDNS_SERVICE_INSTANCE pInstance);
|
||||||
|
|
||||||
|
typedef DNS_SERVICE_REGISTER_COMPLETE *PDNS_SERVICE_REGISTER_COMPLETE;
|
||||||
|
|
||||||
|
typedef struct _DNS_SERVICE_CANCEL {
|
||||||
|
PVOID reserved;
|
||||||
|
} DNS_SERVICE_CANCEL, *PDNS_SERVICE_CANCEL;
|
||||||
|
|
||||||
|
typedef struct _DNS_SERVICE_REGISTER_REQUEST {
|
||||||
|
ULONG Version;
|
||||||
|
ULONG InterfaceIndex;
|
||||||
|
PDNS_SERVICE_INSTANCE pServiceInstance;
|
||||||
|
PDNS_SERVICE_REGISTER_COMPLETE pRegisterCompletionCallback;
|
||||||
|
PVOID pQueryContext;
|
||||||
|
HANDLE hCredentials;
|
||||||
|
BOOL unicastEnabled;
|
||||||
|
} DNS_SERVICE_REGISTER_REQUEST, *PDNS_SERVICE_REGISTER_REQUEST;
|
||||||
|
|
||||||
|
VOID DnsServiceFreeInstance(
|
||||||
|
_In_ PDNS_SERVICE_INSTANCE pInstance);
|
||||||
|
|
||||||
|
DWORD DnsServiceDeRegister(
|
||||||
|
_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest,
|
||||||
|
_Inout_opt_ PDNS_SERVICE_CANCEL pCancel);
|
||||||
|
|
||||||
|
DWORD DnsServiceRegister(
|
||||||
|
_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest,
|
||||||
|
_Inout_opt_ PDNS_SERVICE_CANCEL pCancel);
|
||||||
|
|
||||||
|
PDNS_SERVICE_INSTANCE DnsServiceConstructInstance(
|
||||||
|
_In_ PCWSTR pServiceName,
|
||||||
|
_In_ PCWSTR pHostName,
|
||||||
|
_In_opt_ PIP4_ADDRESS pIp4,
|
||||||
|
_In_opt_ PIP6_ADDRESS pIp6,
|
||||||
|
_In_ WORD wPort,
|
||||||
|
_In_ WORD wPriority,
|
||||||
|
_In_ WORD wWeight,
|
||||||
|
_In_ DWORD dwPropertiesCount,
|
||||||
|
_In_reads_(dwPropertiesCount) PCWSTR *keys,
|
||||||
|
_In_reads_(dwPropertiesCount) PCWSTR *values);
|
||||||
|
} /* extern "C" */
|
||||||
|
|
||||||
|
void print_status(const std::string_view &prefix, HRESULT status) {
|
||||||
|
char err_string[1024];
|
||||||
|
|
||||||
|
DWORD bytes = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
|
nullptr,
|
||||||
|
status,
|
||||||
|
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||||
|
err_string,
|
||||||
|
sizeof(err_string),
|
||||||
|
nullptr);
|
||||||
|
|
||||||
|
BOOST_LOG(error) << prefix << ": "sv << std::string_view { err_string, bytes };
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace platf::publish {
|
||||||
|
VOID WINAPI register_cb(DWORD status, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) {
|
||||||
|
auto alarm = (safe::alarm_t<DNS_STATUS>::element_type *)pQueryContext;
|
||||||
|
|
||||||
|
auto fg = util::fail_guard([&]() {
|
||||||
|
if(pInstance) {
|
||||||
|
DnsServiceFreeInstance(pInstance);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(status) {
|
||||||
|
print_status("register_cb()"sv, status);
|
||||||
|
alarm->ring(-1);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm->ring(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int service(bool enable) {
|
||||||
|
auto alarm = safe::make_alarm<DNS_STATUS>();
|
||||||
|
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t> converter;
|
||||||
|
|
||||||
|
std::wstring name { SERVICE_INSTANCE_NAME.data(), SERVICE_INSTANCE_NAME.size() };
|
||||||
|
std::wstring domain { SERVICE_TYPE_DOMAIN.data(), SERVICE_TYPE_DOMAIN.size() };
|
||||||
|
|
||||||
|
auto host = converter.from_bytes(boost::asio::ip::host_name() + ".local");
|
||||||
|
|
||||||
|
DNS_SERVICE_INSTANCE instance {};
|
||||||
|
instance.pszInstanceName = name.data();
|
||||||
|
instance.wPort = nvhttp::PORT_HTTP;
|
||||||
|
instance.pszHostName = host.data();
|
||||||
|
|
||||||
|
DNS_SERVICE_REGISTER_REQUEST req {};
|
||||||
|
req.Version = DNS_QUERY_REQUEST_VERSION1;
|
||||||
|
req.pQueryContext = alarm.get();
|
||||||
|
req.pServiceInstance = &instance;
|
||||||
|
req.pRegisterCompletionCallback = register_cb;
|
||||||
|
|
||||||
|
DNS_STATUS status {};
|
||||||
|
|
||||||
|
if(enable) {
|
||||||
|
status = DnsServiceRegister(&req, nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
status = DnsServiceDeRegister(&req, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm->wait();
|
||||||
|
|
||||||
|
status = *alarm->status();
|
||||||
|
if(status) {
|
||||||
|
BOOST_LOG(error) << "No mDNS service"sv;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class deinit_t : public ::platf::deinit_t {
|
||||||
|
public:
|
||||||
|
~deinit_t() override {
|
||||||
|
if(service(false)) {
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG(info) << "Unregistered Sunshine Gamestream service"sv;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<::platf::deinit_t> start() {
|
||||||
|
if(service(true)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_LOG(info) << "Registered Sunshine Gamestream service"sv;
|
||||||
|
|
||||||
|
return std::make_unique<deinit_t>();
|
||||||
|
}
|
||||||
|
} // namespace platf::publish
|
Loading…
x
Reference in New Issue
Block a user