mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-27 02:01:42 +00:00
[wpiutil] Add mDNS resolver and announcer (#3733)
This commit is contained in:
41
wpiutil/src/main/native/windows/DynamicDns.cpp
Normal file
41
wpiutil/src/main/native/windows/DynamicDns.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "DynamicDns.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
DynamicDns& DynamicDns::GetDynamicDns() {
|
||||
static DynamicDns dns;
|
||||
return dns;
|
||||
}
|
||||
|
||||
DynamicDns::DynamicDns() {
|
||||
HMODULE library = LoadLibraryW(L"dnsapi");
|
||||
|
||||
if (library == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
DnsServiceFreeInstancePtr = (DnsServiceFreeInstanceFunc)GetProcAddress(
|
||||
library, "DnsServiceFreeInstance");
|
||||
DnsServiceConstructInstancePtr =
|
||||
(DnsServiceConstructInstanceFunc)GetProcAddress(
|
||||
library, "DnsServiceConstructInstance");
|
||||
DnsServiceRegisterPtr =
|
||||
(DnsServiceRegisterFunc)GetProcAddress(library, "DnsServiceRegister");
|
||||
DnsServiceDeRegisterPtr =
|
||||
(DnsServiceDeRegisterFunc)GetProcAddress(library, "DnsServiceDeRegister");
|
||||
|
||||
CanDnsAnnounce = DnsServiceFreeInstancePtr &&
|
||||
DnsServiceConstructInstancePtr && DnsServiceRegisterPtr &&
|
||||
DnsServiceDeRegisterPtr;
|
||||
|
||||
DnsServiceBrowsePtr =
|
||||
(DnsServiceBrowseFunc)GetProcAddress(library, "DnsServiceBrowse");
|
||||
DnsServiceBrowseCancelPtr = (DnsServiceBrowseCancelFunc)GetProcAddress(
|
||||
library, "DnsServiceBrowseCancel");
|
||||
|
||||
CanDnsResolve = DnsServiceBrowsePtr && DnsServiceBrowseCancelPtr;
|
||||
}
|
||||
59
wpiutil/src/main/native/windows/DynamicDns.h
Normal file
59
wpiutil/src/main/native/windows/DynamicDns.h
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <WinDNS.h>
|
||||
|
||||
namespace wpi {
|
||||
class DynamicDns {
|
||||
public:
|
||||
using DnsServiceFreeInstanceFunc =
|
||||
VOID(WINAPI*)(_In_ PDNS_SERVICE_INSTANCE pInstance);
|
||||
|
||||
using DnsServiceConstructInstanceFunc = PDNS_SERVICE_INSTANCE(WINAPI*)(
|
||||
_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);
|
||||
|
||||
using DnsServiceRegisterFunc =
|
||||
DWORD(WINAPI*)(_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest,
|
||||
_Inout_opt_ PDNS_SERVICE_CANCEL pCancel);
|
||||
|
||||
using DnsServiceDeRegisterFunc =
|
||||
DWORD(WINAPI*)(_In_ PDNS_SERVICE_REGISTER_REQUEST pRequest,
|
||||
_Inout_opt_ PDNS_SERVICE_CANCEL pCancel);
|
||||
|
||||
using DnsServiceBrowseFunc =
|
||||
DNS_STATUS(WINAPI*)(_In_ PDNS_SERVICE_BROWSE_REQUEST pRequest,
|
||||
_Inout_ PDNS_SERVICE_CANCEL pCancel);
|
||||
|
||||
using DnsServiceBrowseCancelFunc =
|
||||
DNS_STATUS(WINAPI*)(_In_ PDNS_SERVICE_CANCEL pCancelHandle);
|
||||
|
||||
DnsServiceBrowseFunc DnsServiceBrowsePtr{nullptr};
|
||||
DnsServiceBrowseCancelFunc DnsServiceBrowseCancelPtr{nullptr};
|
||||
|
||||
DnsServiceFreeInstanceFunc DnsServiceFreeInstancePtr{nullptr};
|
||||
DnsServiceConstructInstanceFunc DnsServiceConstructInstancePtr{nullptr};
|
||||
DnsServiceRegisterFunc DnsServiceRegisterPtr{nullptr};
|
||||
DnsServiceDeRegisterFunc DnsServiceDeRegisterPtr{nullptr};
|
||||
|
||||
bool CanDnsAnnounce{false};
|
||||
bool CanDnsResolve{false};
|
||||
|
||||
static DynamicDns& GetDynamicDns();
|
||||
|
||||
private:
|
||||
DynamicDns();
|
||||
};
|
||||
} // namespace wpi
|
||||
267
wpiutil/src/main/native/windows/MulticastServiceAnnouncer.cpp
Normal file
267
wpiutil/src/main/native/windows/MulticastServiceAnnouncer.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include "wpi/MulticastServiceAnnouncer.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "DynamicDns.h"
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
#include "wpi/hostname.h"
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
struct ImplBase {
|
||||
wpi::DynamicDns& dynamicDns = wpi::DynamicDns::GetDynamicDns();
|
||||
PDNS_SERVICE_INSTANCE serviceInstance = nullptr;
|
||||
HANDLE event = nullptr;
|
||||
};
|
||||
|
||||
struct MulticastServiceAnnouncer::Impl : ImplBase {
|
||||
std::wstring serviceType;
|
||||
std::wstring serviceInstanceName;
|
||||
std::wstring hostName;
|
||||
int port;
|
||||
std::vector<std::wstring> keys;
|
||||
std::vector<PCWSTR> keyPtrs;
|
||||
std::vector<std::wstring> values;
|
||||
std::vector<PCWSTR> valuePtrs;
|
||||
};
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port,
|
||||
wpi::span<const std::pair<std::string_view, std::string_view>> txt) {
|
||||
pImpl = std::make_unique<Impl>();
|
||||
|
||||
if (!pImpl->dynamicDns.CanDnsAnnounce) {
|
||||
return;
|
||||
}
|
||||
|
||||
pImpl->port = port;
|
||||
|
||||
wpi::SmallVector<wpi::UTF16, 128> wideStorage;
|
||||
std::string hostName = wpi::GetHostname() + ".local";
|
||||
|
||||
for (auto&& i : txt) {
|
||||
wideStorage.clear();
|
||||
wpi::convertUTF8ToUTF16String(i.first, wideStorage);
|
||||
pImpl->keys.emplace_back(
|
||||
std::wstring{reinterpret_cast<const wchar_t*>(wideStorage.data()),
|
||||
wideStorage.size()});
|
||||
wideStorage.clear();
|
||||
wpi::convertUTF8ToUTF16String(i.second, wideStorage);
|
||||
pImpl->values.emplace_back(
|
||||
std::wstring{reinterpret_cast<const wchar_t*>(wideStorage.data()),
|
||||
wideStorage.size()});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pImpl->keys.size(); i++) {
|
||||
pImpl->keyPtrs.emplace_back(pImpl->keys[i].c_str());
|
||||
pImpl->valuePtrs.emplace_back(pImpl->values[i].c_str());
|
||||
}
|
||||
|
||||
wpi::SmallString<128> storage;
|
||||
|
||||
wideStorage.clear();
|
||||
wpi::convertUTF8ToUTF16String(hostName, wideStorage);
|
||||
|
||||
pImpl->hostName = std::wstring{
|
||||
reinterpret_cast<const wchar_t*>(wideStorage.data()), wideStorage.size()};
|
||||
|
||||
wideStorage.clear();
|
||||
if (wpi::ends_with_lower(serviceType, ".local")) {
|
||||
wpi::convertUTF8ToUTF16String(serviceType, wideStorage);
|
||||
} else {
|
||||
storage.clear();
|
||||
storage.append(serviceType);
|
||||
storage.append(".local");
|
||||
wpi::convertUTF8ToUTF16String(storage.str(), wideStorage);
|
||||
}
|
||||
pImpl->serviceType = std::wstring{
|
||||
reinterpret_cast<const wchar_t*>(wideStorage.data()), wideStorage.size()};
|
||||
|
||||
wideStorage.clear();
|
||||
storage.clear();
|
||||
storage.append(serviceName);
|
||||
storage.append(".");
|
||||
storage.append(serviceType);
|
||||
if (!wpi::ends_with_lower(serviceType, ".local")) {
|
||||
storage.append(".local");
|
||||
}
|
||||
|
||||
wpi::convertUTF8ToUTF16String(storage.str(), wideStorage);
|
||||
pImpl->serviceInstanceName = std::wstring{
|
||||
reinterpret_cast<const wchar_t*>(wideStorage.data()), wideStorage.size()};
|
||||
}
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port,
|
||||
wpi::span<const std::pair<std::string, std::string>> txt) {
|
||||
pImpl = std::make_unique<Impl>();
|
||||
|
||||
if (!pImpl->dynamicDns.CanDnsAnnounce) {
|
||||
return;
|
||||
}
|
||||
|
||||
pImpl->port = port;
|
||||
|
||||
wpi::SmallVector<wpi::UTF16, 128> wideStorage;
|
||||
std::string hostName = wpi::GetHostname() + ".local";
|
||||
|
||||
for (auto&& i : txt) {
|
||||
wideStorage.clear();
|
||||
wpi::convertUTF8ToUTF16String(i.first, wideStorage);
|
||||
pImpl->keys.emplace_back(
|
||||
std::wstring{reinterpret_cast<const wchar_t*>(wideStorage.data()),
|
||||
wideStorage.size()});
|
||||
wideStorage.clear();
|
||||
wpi::convertUTF8ToUTF16String(i.second, wideStorage);
|
||||
pImpl->values.emplace_back(
|
||||
std::wstring{reinterpret_cast<const wchar_t*>(wideStorage.data()),
|
||||
wideStorage.size()});
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < pImpl->keys.size(); i++) {
|
||||
pImpl->keyPtrs.emplace_back(pImpl->keys[i].c_str());
|
||||
pImpl->valuePtrs.emplace_back(pImpl->values[i].c_str());
|
||||
}
|
||||
|
||||
wpi::SmallString<128> storage;
|
||||
|
||||
wideStorage.clear();
|
||||
wpi::convertUTF8ToUTF16String(hostName, wideStorage);
|
||||
|
||||
pImpl->hostName = std::wstring{
|
||||
reinterpret_cast<const wchar_t*>(wideStorage.data()), wideStorage.size()};
|
||||
|
||||
wideStorage.clear();
|
||||
if (wpi::ends_with_lower(serviceType, ".local")) {
|
||||
wpi::convertUTF8ToUTF16String(serviceType, wideStorage);
|
||||
} else {
|
||||
storage.clear();
|
||||
storage.append(serviceType);
|
||||
storage.append(".local");
|
||||
wpi::convertUTF8ToUTF16String(storage.str(), wideStorage);
|
||||
}
|
||||
pImpl->serviceType = std::wstring{
|
||||
reinterpret_cast<const wchar_t*>(wideStorage.data()), wideStorage.size()};
|
||||
|
||||
wideStorage.clear();
|
||||
storage.clear();
|
||||
storage.append(serviceName);
|
||||
storage.append(".");
|
||||
storage.append(serviceType);
|
||||
if (!wpi::ends_with_lower(serviceType, ".local")) {
|
||||
storage.append(".local");
|
||||
}
|
||||
|
||||
wpi::convertUTF8ToUTF16String(storage.str(), wideStorage);
|
||||
pImpl->serviceInstanceName = std::wstring{
|
||||
reinterpret_cast<const wchar_t*>(wideStorage.data()), wideStorage.size()};
|
||||
}
|
||||
|
||||
MulticastServiceAnnouncer::~MulticastServiceAnnouncer() noexcept {
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool MulticastServiceAnnouncer::HasImplementation() const {
|
||||
return pImpl->dynamicDns.CanDnsAnnounce;
|
||||
}
|
||||
|
||||
static void WINAPI DnsServiceRegisterCallback(DWORD /*Status*/,
|
||||
PVOID pQueryContext,
|
||||
PDNS_SERVICE_INSTANCE pInstance) {
|
||||
ImplBase* impl = reinterpret_cast<ImplBase*>(pQueryContext);
|
||||
|
||||
impl->serviceInstance = pInstance;
|
||||
|
||||
SetEvent(impl->event);
|
||||
}
|
||||
|
||||
void MulticastServiceAnnouncer::Start() {
|
||||
if (pImpl->serviceInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pImpl->dynamicDns.CanDnsAnnounce) {
|
||||
return;
|
||||
}
|
||||
|
||||
PDNS_SERVICE_INSTANCE serviceInst =
|
||||
pImpl->dynamicDns.DnsServiceConstructInstancePtr(
|
||||
pImpl->serviceInstanceName.c_str(), pImpl->hostName.c_str(), nullptr,
|
||||
nullptr, pImpl->port, 0, 0, static_cast<DWORD>(pImpl->keyPtrs.size()),
|
||||
pImpl->keyPtrs.data(), pImpl->valuePtrs.data());
|
||||
if (serviceInst == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
DNS_SERVICE_REGISTER_REQUEST registerRequest = {};
|
||||
registerRequest.pQueryContext = static_cast<ImplBase*>(pImpl.get());
|
||||
registerRequest.pRegisterCompletionCallback = DnsServiceRegisterCallback;
|
||||
registerRequest.Version = DNS_QUERY_REQUEST_VERSION1;
|
||||
registerRequest.unicastEnabled = false;
|
||||
registerRequest.pServiceInstance = serviceInst;
|
||||
registerRequest.InterfaceIndex = 0;
|
||||
|
||||
pImpl->event = CreateEvent(NULL, true, false, NULL);
|
||||
|
||||
if (pImpl->dynamicDns.DnsServiceRegisterPtr(®isterRequest, nullptr) ==
|
||||
DNS_REQUEST_PENDING) {
|
||||
WaitForSingleObject(pImpl->event, INFINITE);
|
||||
}
|
||||
|
||||
pImpl->dynamicDns.DnsServiceFreeInstancePtr(serviceInst);
|
||||
CloseHandle(pImpl->event);
|
||||
pImpl->event = nullptr;
|
||||
}
|
||||
|
||||
static void WINAPI DnsServiceDeRegisterCallback(
|
||||
DWORD /*Status*/, PVOID pQueryContext, PDNS_SERVICE_INSTANCE pInstance) {
|
||||
ImplBase* impl = reinterpret_cast<ImplBase*>(pQueryContext);
|
||||
|
||||
if (pInstance != nullptr) {
|
||||
impl->dynamicDns.DnsServiceFreeInstancePtr(pInstance);
|
||||
pInstance = nullptr;
|
||||
}
|
||||
|
||||
SetEvent(impl->event);
|
||||
}
|
||||
|
||||
void MulticastServiceAnnouncer::Stop() {
|
||||
if (!pImpl->dynamicDns.CanDnsAnnounce) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pImpl->serviceInstance == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
pImpl->event = CreateEvent(NULL, true, false, NULL);
|
||||
DNS_SERVICE_REGISTER_REQUEST registerRequest = {};
|
||||
registerRequest.pQueryContext = static_cast<ImplBase*>(pImpl.get());
|
||||
registerRequest.pRegisterCompletionCallback = DnsServiceDeRegisterCallback;
|
||||
registerRequest.Version = DNS_QUERY_REQUEST_VERSION1;
|
||||
registerRequest.unicastEnabled = false;
|
||||
registerRequest.pServiceInstance = pImpl->serviceInstance;
|
||||
registerRequest.InterfaceIndex = 0;
|
||||
|
||||
if (pImpl->dynamicDns.DnsServiceDeRegisterPtr(®isterRequest, nullptr) ==
|
||||
DNS_REQUEST_PENDING) {
|
||||
WaitForSingleObject(pImpl->event, INFINITE);
|
||||
}
|
||||
|
||||
pImpl->dynamicDns.DnsServiceFreeInstancePtr(pImpl->serviceInstance);
|
||||
pImpl->serviceInstance = nullptr;
|
||||
CloseHandle(pImpl->event);
|
||||
pImpl->event = nullptr;
|
||||
}
|
||||
207
wpiutil/src/main/native/windows/MulticastServiceResolver.cpp
Normal file
207
wpiutil/src/main/native/windows/MulticastServiceResolver.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
|
||||
#include "wpi/MulticastServiceResolver.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "DynamicDns.h"
|
||||
#include "wpi/ConvertUTF.h"
|
||||
#include "wpi/SmallString.h"
|
||||
#include "wpi/SmallVector.h"
|
||||
#include "wpi/StringExtras.h"
|
||||
|
||||
#pragma comment(lib, "dnsapi")
|
||||
|
||||
using namespace wpi;
|
||||
|
||||
struct MulticastServiceResolver::Impl {
|
||||
wpi::DynamicDns& dynamicDns = wpi::DynamicDns::GetDynamicDns();
|
||||
std::wstring serviceType;
|
||||
DNS_SERVICE_CANCEL serviceCancel{nullptr};
|
||||
|
||||
MulticastServiceResolver* resolver;
|
||||
|
||||
void onFound(ServiceData&& data) {
|
||||
resolver->eventQueue.push(std::move(data));
|
||||
resolver->event.Set();
|
||||
}
|
||||
};
|
||||
|
||||
MulticastServiceResolver::MulticastServiceResolver(
|
||||
std::string_view serviceType) {
|
||||
pImpl = std::make_unique<Impl>();
|
||||
pImpl->resolver = this;
|
||||
|
||||
if (!pImpl->dynamicDns.CanDnsResolve) {
|
||||
return;
|
||||
}
|
||||
|
||||
wpi::SmallVector<wpi::UTF16, 128> wideStorage;
|
||||
|
||||
if (wpi::ends_with_lower(serviceType, ".local")) {
|
||||
wpi::convertUTF8ToUTF16String(serviceType, wideStorage);
|
||||
} else {
|
||||
wpi::SmallString<128> storage;
|
||||
storage.append(serviceType);
|
||||
storage.append(".local");
|
||||
wpi::convertUTF8ToUTF16String(storage.str(), wideStorage);
|
||||
}
|
||||
pImpl->serviceType = std::wstring{
|
||||
reinterpret_cast<const wchar_t*>(wideStorage.data()), wideStorage.size()};
|
||||
}
|
||||
|
||||
MulticastServiceResolver::~MulticastServiceResolver() noexcept {
|
||||
Stop();
|
||||
}
|
||||
|
||||
bool MulticastServiceResolver::HasImplementation() const {
|
||||
return pImpl->dynamicDns.CanDnsResolve;
|
||||
}
|
||||
|
||||
static _Function_class_(DNS_QUERY_COMPLETION_ROUTINE) VOID WINAPI
|
||||
DnsCompletion(_In_ PVOID pQueryContext,
|
||||
_Inout_ PDNS_QUERY_RESULT pQueryResults) {
|
||||
MulticastServiceResolver::Impl* impl =
|
||||
reinterpret_cast<MulticastServiceResolver::Impl*>(pQueryContext);
|
||||
|
||||
wpi::SmallVector<DNS_RECORDW*, 4> PtrRecords;
|
||||
wpi::SmallVector<DNS_RECORDW*, 4> SrvRecords;
|
||||
wpi::SmallVector<DNS_RECORDW*, 4> TxtRecords;
|
||||
wpi::SmallVector<DNS_RECORDW*, 4> ARecords;
|
||||
|
||||
{
|
||||
DNS_RECORDW* current = pQueryResults->pQueryRecords;
|
||||
while (current != nullptr) {
|
||||
switch (current->wType) {
|
||||
case DNS_TYPE_PTR:
|
||||
PtrRecords.push_back(current);
|
||||
break;
|
||||
case DNS_TYPE_SRV:
|
||||
SrvRecords.push_back(current);
|
||||
break;
|
||||
case DNS_TYPE_TEXT:
|
||||
TxtRecords.push_back(current);
|
||||
break;
|
||||
case DNS_TYPE_A:
|
||||
ARecords.push_back(current);
|
||||
break;
|
||||
}
|
||||
current = current->pNext;
|
||||
}
|
||||
}
|
||||
|
||||
for (DNS_RECORDW* Ptr : PtrRecords) {
|
||||
if (std::wstring_view{Ptr->pName} != impl->serviceType) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::wstring_view nameHost = Ptr->Data.Ptr.pNameHost;
|
||||
DNS_RECORDW* foundSrv = nullptr;
|
||||
for (DNS_RECORDW* Srv : SrvRecords) {
|
||||
if (std::wstring_view{Srv->pName} == nameHost) {
|
||||
foundSrv = Srv;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundSrv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (DNS_RECORDW* A : ARecords) {
|
||||
if (std::wstring_view{A->pName} ==
|
||||
std::wstring_view{foundSrv->Data.Srv.pNameTarget}) {
|
||||
MulticastServiceResolver::ServiceData data;
|
||||
wpi::SmallString<128> storage;
|
||||
for (DNS_RECORDW* Txt : TxtRecords) {
|
||||
if (std::wstring_view{Txt->pName} == nameHost) {
|
||||
for (DWORD i = 0; i < Txt->Data.Txt.dwStringCount; i++) {
|
||||
std::wstring_view wideView = Txt->Data.TXT.pStringArray[i];
|
||||
size_t splitIndex = wideView.find(L'=');
|
||||
if (splitIndex == wideView.npos) {
|
||||
// Todo make this just do key
|
||||
continue;
|
||||
}
|
||||
storage.clear();
|
||||
wpi::span<const wpi::UTF16> wideStr{
|
||||
reinterpret_cast<const wpi::UTF16*>(wideView.data()),
|
||||
splitIndex};
|
||||
wpi::convertUTF16ToUTF8String(wideStr, storage);
|
||||
auto& pair = data.txt.emplace_back(
|
||||
std::pair<std::string, std::string>{storage.string(), {}});
|
||||
storage.clear();
|
||||
wideStr = wpi::span<const wpi::UTF16>{
|
||||
reinterpret_cast<const wpi::UTF16*>(wideView.data() +
|
||||
splitIndex + 1),
|
||||
wideView.size() - splitIndex - 1};
|
||||
wpi::convertUTF16ToUTF8String(wideStr, storage);
|
||||
pair.second = storage.string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
storage.clear();
|
||||
wpi::span<const wpi::UTF16> wideHostName{
|
||||
reinterpret_cast<const wpi::UTF16*>(A->pName), wcslen(A->pName)};
|
||||
wpi::convertUTF16ToUTF8String(wideHostName, storage);
|
||||
storage.append(".");
|
||||
|
||||
data.hostName = storage.string();
|
||||
storage.clear();
|
||||
|
||||
int len = nameHost.find(impl->serviceType.c_str());
|
||||
wpi::span<const wpi::UTF16> wideServiceName{
|
||||
reinterpret_cast<const wpi::UTF16*>(nameHost.data()),
|
||||
nameHost.size()};
|
||||
if (len != nameHost.npos) {
|
||||
wideServiceName = wideServiceName.subspan(0, len - 1);
|
||||
}
|
||||
wpi::convertUTF16ToUTF8String(wideServiceName, storage);
|
||||
|
||||
data.serviceName = storage.string();
|
||||
data.port = foundSrv->Data.Srv.wPort;
|
||||
data.ipv4Address = A->Data.A.IpAddress;
|
||||
|
||||
impl->onFound(std::move(data));
|
||||
}
|
||||
}
|
||||
}
|
||||
DnsFree(pQueryResults->pQueryRecords, DNS_FREE_TYPE::DnsFreeRecordList);
|
||||
}
|
||||
|
||||
void MulticastServiceResolver::Start() {
|
||||
if (pImpl->serviceCancel.reserved != nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pImpl->dynamicDns.CanDnsResolve) {
|
||||
return;
|
||||
}
|
||||
|
||||
DNS_SERVICE_BROWSE_REQUEST request = {};
|
||||
request.InterfaceIndex = 0;
|
||||
request.pQueryContext = pImpl.get();
|
||||
request.QueryName = pImpl->serviceType.c_str();
|
||||
request.Version = 2;
|
||||
request.pBrowseCallbackV2 = DnsCompletion;
|
||||
pImpl->dynamicDns.DnsServiceBrowsePtr(&request, &pImpl->serviceCancel);
|
||||
}
|
||||
|
||||
void MulticastServiceResolver::Stop() {
|
||||
if (!pImpl->dynamicDns.CanDnsResolve) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pImpl->serviceCancel.reserved == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
pImpl->dynamicDns.DnsServiceBrowseCancelPtr(&pImpl->serviceCancel);
|
||||
pImpl->serviceCancel.reserved = nullptr;
|
||||
}
|
||||
Reference in New Issue
Block a user