The follow application I would expect to generate 2 events - one for the service appearing and one for the service disappearing. To run the application, it needs to be linked with dnsapi.lib
.
I can verify using Wireshark that when the service is deregistered, a new packet is sent out with TTL=0, as expected.
#include <iostream>
#include <Windows.h>
#include <WinDNS.h>
#include <atomic>
#include <future>
#include <chrono>
#include <stdexcept>
using namespace std::chrono_literals;
void DnsServiceBrowseCallback(DWORD status, PVOID pQueryContext, PDNS_RECORD pDnsRecord) {
if (status == ERROR_CANCELLED)
return;
if (status == ERROR_SUCCESS) {
if (pQueryContext != nullptr) {
auto tc = static_cast<std::atomic<int>*>(pQueryContext);
(*tc).operator++(); // Increment atomic integer.
}
}
}
void DnsServiceRegisterCallback(DWORD, PVOID pContext, PDNS_SERVICE_INSTANCE) {
if (pContext != nullptr) {
auto p = static_cast<std::promise<bool>*>(pContext);
p->set_value(true);
}
}
void wait_for_dns_action(DWORD(*f)(PDNS_SERVICE_REGISTER_REQUEST, PDNS_SERVICE_CANCEL), DNS_SERVICE_INSTANCE* service) {
auto p = std::promise<bool>();
auto fut = p.get_future();
DNS_SERVICE_REGISTER_REQUEST rq = {
DNS_QUERY_REQUEST_VERSION1,
0,
service,
DnsServiceRegisterCallback,
&p,
0,
false
};
auto reg = f(&rq, nullptr);
if (reg == DNS_REQUEST_PENDING && fut.wait_for(10s) == std::future_status::ready) {
std::cout << "Action completed" << std::endl;
}
else {
throw std::runtime_error("Unable to complete action");
}
}
int main()
{
DNS_SERVICE_CANCEL cancel;
std::atomic<int> times_called = 0;
std::wstring service_type = L"_test._tcp";
DNS_SERVICE_BROWSE_REQUEST brq = {
1,0,service_type.c_str(),DnsServiceBrowseCallback, ×_called
};
auto breq = DnsServiceBrowse(&brq, &cancel);
if (breq != DNS_REQUEST_PENDING) {
throw std::runtime_error("Unable to start browsing");
}
DWORD ipv4 = 0;
std::wstring service_id = L"testservice._test._tcp.local";
auto service = DnsServiceConstructInstance(
service_id.c_str(),
L"",
&ipv4,
nullptr,
12345,
0,
0,
0,
nullptr,
nullptr
);
wait_for_dns_action(DnsServiceRegister, service);
std::cout << "Registered service" << std::endl;
std::cout << "Expected: 1. Actual: " << times_called << std::endl; // Output 1
wait_for_dns_action(DnsServiceDeRegister, service);
std::cout << "Deregistered service" << std::endl;
std::cout << "Expected: 2. Actual: " << times_called << std::endl; // Output: 1
}