32 #ifndef _CRT_SECURE_NO_WARNINGS
33 #define _CRT_SECURE_NO_WARNINGS 1
45 #define sleep(x) Sleep(x * 1000)
53 #include "mdns_util.h"
55 #ifndef OCPN_ENABLE_MDNS_DEBUG
60 static char addrbuffer[64];
61 static char namebuffer[256];
62 static char sendbuffer[1024];
64 static struct sockaddr_in service_address_ipv4;
65 static struct sockaddr_in6 service_address_ipv6;
67 volatile sig_atomic_t running_server = 1;
71 mdns_string_t service;
72 mdns_string_t hostname;
73 mdns_string_t service_instance;
74 mdns_string_t hostname_qualified;
75 struct sockaddr_in address_ipv4;
76 struct sockaddr_in6 address_ipv6;
78 mdns_record_t record_ptr;
79 mdns_record_t record_srv;
80 mdns_record_t record_a;
81 mdns_record_t record_aaaa;
82 mdns_record_t txt_record[2];
90 ocpn_service_callback(
int sock,
const struct sockaddr* from,
size_t addrlen, mdns_entry_type_t entry,
91 uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl,
const void* data,
92 size_t size,
size_t name_offset,
size_t name_length,
size_t record_offset,
93 size_t record_length,
void* user_data) {
95 if (entry != MDNS_ENTRYTYPE_QUESTION)
98 const char dns_sd[] =
"_services._dns-sd._udp.local.";
101 mdns_string_t fromaddrstr = ip_address_to_string(addrbuffer,
sizeof(addrbuffer), from, addrlen);
103 size_t offset = name_offset;
104 mdns_string_t name = mdns_string_extract(data, size, &offset, namebuffer,
sizeof(namebuffer));
106 const char* record_name = 0;
107 if (rtype == MDNS_RECORDTYPE_PTR)
109 else if (rtype == MDNS_RECORDTYPE_SRV)
111 else if (rtype == MDNS_RECORDTYPE_A)
113 else if (rtype == MDNS_RECORDTYPE_AAAA)
114 record_name =
"AAAA";
115 else if (rtype == MDNS_RECORDTYPE_TXT)
117 else if (rtype == MDNS_RECORDTYPE_ANY)
121 printf(
"Query %s %.*s\n", record_name, MDNS_STRING_FORMAT(name));
123 if ((name.length == (
sizeof(dns_sd) - 1)) &&
124 (strncmp(name.str, dns_sd,
sizeof(dns_sd) - 1) == 0)) {
125 if ((rtype == MDNS_RECORDTYPE_PTR) || (rtype == MDNS_RECORDTYPE_ANY)) {
131 mdns_record_t answer;
133 answer.type = MDNS_RECORDTYPE_PTR;
134 answer.data.ptr.name = service->service;
137 uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
138 printf(
" --> answer %.*s (%s)\n", MDNS_STRING_FORMAT(answer.data.ptr.name),
139 (unicast ?
"unicast" :
"multicast"));
142 mdns_query_answer_unicast(sock, from, addrlen, sendbuffer,
sizeof(sendbuffer),
143 query_id, (mdns_record_type_t)rtype, name.str, name.length, answer,
146 mdns_query_answer_multicast(sock, sendbuffer,
sizeof(sendbuffer), answer, 0, 0, 0,
150 }
else if ((name.length == service->service.length) &&
151 (strncmp(name.str, service->service.str, name.length) == 0)) {
152 if ((rtype == MDNS_RECORDTYPE_PTR) || (rtype == MDNS_RECORDTYPE_ANY)) {
162 mdns_record_t answer = service->record_ptr;
164 mdns_record_t additional[5] = {0};
165 size_t additional_count = 0;
169 additional[additional_count++] = service->record_srv;
172 if (service->address_ipv4.sin_family == AF_INET)
173 additional[additional_count++] = service->record_a;
174 if (service->address_ipv6.sin6_family == AF_INET6)
175 additional[additional_count++] = service->record_aaaa;
183 uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
184 printf(
" --> answer %.*s (%s)\n",
185 MDNS_STRING_FORMAT(service->record_ptr.data.ptr.name),
186 (unicast ?
"unicast" :
"multicast"));
189 mdns_query_answer_unicast(sock, from, addrlen, sendbuffer,
sizeof(sendbuffer),
190 query_id, (mdns_record_type)rtype, name.str, name.length, answer, 0, 0,
191 additional, additional_count);
193 mdns_query_answer_multicast(sock, sendbuffer,
sizeof(sendbuffer), answer, 0, 0,
194 additional, additional_count);
197 }
else if ((name.length == service->service_instance.length) &&
198 (strncmp(name.str, service->service_instance.str, name.length) == 0)) {
199 if ((rtype == MDNS_RECORDTYPE_SRV) || (rtype == MDNS_RECORDTYPE_ANY)) {
208 mdns_record_t answer = service->record_srv;
210 mdns_record_t additional[5] = {0};
211 size_t additional_count = 0;
214 if (service->address_ipv4.sin_family == AF_INET)
215 additional[additional_count++] = service->record_a;
216 if (service->address_ipv6.sin6_family == AF_INET6)
217 additional[additional_count++] = service->record_aaaa;
221 additional[additional_count++] = service->txt_record[0];
222 additional[additional_count++] = service->txt_record[1];
225 uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
226 printf(
" --> answer %.*s port %d (%s)\n",
227 MDNS_STRING_FORMAT(service->record_srv.data.srv.name), service->port,
228 (unicast ?
"unicast" :
"multicast"));
231 mdns_query_answer_unicast(sock, from, addrlen, sendbuffer,
sizeof(sendbuffer),
232 query_id, (mdns_record_type)rtype, name.str, name.length, answer, 0, 0,
233 additional, additional_count);
235 mdns_query_answer_multicast(sock, sendbuffer,
sizeof(sendbuffer), answer, 0, 0,
236 additional, additional_count);
239 }
else if ((name.length == service->hostname_qualified.length) &&
240 (strncmp(name.str, service->hostname_qualified.str, name.length) == 0)) {
241 if (((rtype == MDNS_RECORDTYPE_A) || (rtype == MDNS_RECORDTYPE_ANY)) &&
242 (service->address_ipv4.sin_family == AF_INET)) {
248 mdns_record_t answer = service->record_a;
250 mdns_record_t additional[5] = {0};
251 size_t additional_count = 0;
254 if (service->address_ipv6.sin6_family == AF_INET6)
255 additional[additional_count++] = service->record_aaaa;
259 additional[additional_count++] = service->txt_record[0];
260 additional[additional_count++] = service->txt_record[1];
263 uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
264 mdns_string_t addrstr = ip_address_to_string(
265 addrbuffer,
sizeof(addrbuffer), (
struct sockaddr*)&service->record_a.data.a.addr,
266 sizeof(service->record_a.data.a.addr));
267 printf(
" --> answer %.*s IPv4 %.*s (%s)\n", MDNS_STRING_FORMAT(service->record_a.name),
268 MDNS_STRING_FORMAT(addrstr), (unicast ?
"unicast" :
"multicast"));
271 mdns_query_answer_unicast(sock, from, addrlen, sendbuffer,
sizeof(sendbuffer),
272 query_id, (mdns_record_type)rtype, name.str, name.length, answer, 0, 0,
273 additional, additional_count);
275 mdns_query_answer_multicast(sock, sendbuffer,
sizeof(sendbuffer), answer, 0, 0,
276 additional, additional_count);
278 }
else if (((rtype == MDNS_RECORDTYPE_AAAA) || (rtype == MDNS_RECORDTYPE_ANY)) &&
279 (service->address_ipv6.sin6_family == AF_INET6)) {
285 mdns_record_t answer = service->record_aaaa;
287 mdns_record_t additional[5] = {0};
288 size_t additional_count = 0;
291 if (service->address_ipv4.sin_family == AF_INET)
292 additional[additional_count++] = service->record_a;
296 additional[additional_count++] = service->txt_record[0];
297 additional[additional_count++] = service->txt_record[1];
300 uint16_t unicast = (rclass & MDNS_UNICAST_RESPONSE);
301 mdns_string_t addrstr =
302 ip_address_to_string(addrbuffer,
sizeof(addrbuffer),
303 (
struct sockaddr*)&service->record_aaaa.data.aaaa.addr,
304 sizeof(service->record_aaaa.data.aaaa.addr));
305 printf(
" --> answer %.*s IPv6 %.*s (%s)\n",
306 MDNS_STRING_FORMAT(service->record_aaaa.name), MDNS_STRING_FORMAT(addrstr),
307 (unicast ?
"unicast" :
"multicast"));
310 mdns_query_answer_unicast(sock, from, addrlen, sendbuffer,
sizeof(sendbuffer),
311 query_id, (mdns_record_type)rtype, name.str, name.length, answer, 0, 0,
312 additional, additional_count);
314 mdns_query_answer_multicast(sock, sendbuffer,
sizeof(sendbuffer), answer, 0, 0,
315 additional, additional_count);
323 void service_mdns(
const char* hostname,
const char* service_name,
int service_port) {
325 int num_sockets = open_service_sockets(sockets,
sizeof(sockets) /
sizeof(sockets[0]));
326 if (num_sockets <= 0) {
327 printf(
"Failed to open any client sockets\n");
330 printf(
"Opened %d socket%s for mDNS service\n", num_sockets, num_sockets ?
"s" :
"");
332 size_t service_name_length = strlen(service_name);
333 if (!service_name_length) {
334 printf(
"Invalid service name\n");
338 char* service_name_buffer = (
char *)malloc(service_name_length + 2);
339 memcpy(service_name_buffer, service_name, service_name_length);
340 if (service_name_buffer[service_name_length - 1] !=
'.')
341 service_name_buffer[service_name_length++] =
'.';
342 service_name_buffer[service_name_length] = 0;
343 service_name = service_name_buffer;
345 printf(
"Service mDNS: %s:%d\n", service_name, service_port);
346 printf(
"Hostname: %s\n", hostname);
348 size_t capacity = 2048;
349 void* buffer = malloc(capacity);
351 mdns_string_t service_string;
352 service_string.str = service_name;
353 service_string.length = strlen(service_name);
354 mdns_string_t hostname_string;
355 hostname_string.str = hostname;
356 hostname_string.length = strlen(hostname);
359 char service_instance_buffer[256] = {0};
360 snprintf(service_instance_buffer,
sizeof(service_instance_buffer) - 1,
"%.*s.%.*s",
361 MDNS_STRING_FORMAT(hostname_string), MDNS_STRING_FORMAT(service_string));
363 mdns_string_t service_instance_string;
364 service_instance_string.str = service_instance_buffer;
365 service_instance_string.length = strlen(service_instance_buffer);
368 char qualified_hostname_buffer[256] = {0};
369 snprintf(qualified_hostname_buffer,
sizeof(qualified_hostname_buffer) - 1,
"%.*s.local.",
370 MDNS_STRING_FORMAT(hostname_string));
371 mdns_string_t hostname_qualified_string;
372 hostname_qualified_string.str = qualified_hostname_buffer;
373 hostname_qualified_string.length = strlen(qualified_hostname_buffer);
376 service.service = service_string;
377 service.hostname = hostname_string;
378 service.service_instance = service_instance_string;
379 service.hostname_qualified = hostname_qualified_string;
380 service.address_ipv4 = service_address_ipv4;
381 service.address_ipv6 = service_address_ipv6;
382 service.port = service_port;
388 service.record_ptr.name = service.service;
389 service.record_ptr.type = MDNS_RECORDTYPE_PTR;
390 service.record_ptr.rclass = 0;
391 service.record_ptr.ttl = 0;
392 service.record_ptr.data.ptr.name = service.service_instance;
396 service.record_srv.name = service.service_instance;
397 service.record_srv.type = MDNS_RECORDTYPE_SRV;
398 service.record_srv.data.srv.name = service.hostname_qualified;
399 service.record_srv.data.srv.port = service.port;
400 service.record_srv.data.srv.priority = 0;
401 service.record_srv.data.srv.weight = 0;
402 service.record_srv.rclass = 0;
403 service.record_srv.ttl = 0;
408 service.record_a.name = service.hostname_qualified;
409 service.record_a.type = MDNS_RECORDTYPE_A;
410 service.record_a.data.a.addr = service.address_ipv4;
411 service.record_a.rclass = 0;
412 service.record_a.ttl = 0;
415 service.record_aaaa.name = service.hostname_qualified;
416 service.record_aaaa.type = MDNS_RECORDTYPE_AAAA;
417 service.record_aaaa.data.aaaa.addr = service.address_ipv6;
418 service.record_aaaa.rclass = 0;
419 service.record_aaaa.ttl = 0;
425 service.txt_record[0].name = service.service_instance;
426 service.txt_record[0].type = MDNS_RECORDTYPE_TXT;
427 service.txt_record[0].data.txt.key = {MDNS_STRING_CONST(
"test")};
428 service.txt_record[0].data.txt.value = {MDNS_STRING_CONST(
"1")};
429 service.txt_record[0].rclass = 0;
430 service.txt_record[0].ttl = 0;
432 service.txt_record[1].name = service.service_instance;
433 service.txt_record[1].type = MDNS_RECORDTYPE_TXT;
434 service.txt_record[1].data.txt.key = {MDNS_STRING_CONST(
"other")};
435 service.txt_record[1].data.txt.value = {MDNS_STRING_CONST(
"value")};
436 service.txt_record[1].rclass = 0;
437 service.txt_record[1].ttl = 0;
443 printf(
"Sending announce\n");
444 mdns_record_t additional[5] = {0};
445 size_t additional_count = 0;
446 additional[additional_count++] = service.record_srv;
447 if (service.address_ipv4.sin_family == AF_INET)
448 additional[additional_count++] = service.record_a;
449 if (service.address_ipv6.sin6_family == AF_INET6)
450 additional[additional_count++] = service.record_aaaa;
454 for (
int isock = 0; isock < num_sockets; ++isock)
455 mdns_announce_multicast(sockets[isock], buffer, capacity, service.record_ptr, 0, 0,
456 additional, additional_count);
460 while (running_server) {
464 for (
int isock = 0; isock < num_sockets; ++isock) {
465 if (sockets[isock] >= nfds)
466 nfds = sockets[isock] + 1;
467 FD_SET(sockets[isock], &readfs);
470 struct timeval timeout;
472 timeout.tv_usec = 100000;
474 if (select(nfds, &readfs, 0, 0, &timeout) >= 0) {
475 for (
int isock = 0; isock < num_sockets; ++isock) {
476 if (FD_ISSET(sockets[isock], &readfs)) {
477 mdns_socket_listen(sockets[isock], buffer, capacity,
478 ocpn_service_callback,
481 FD_SET(sockets[isock], &readfs);
490 printf(
"Sending goodbye\n");
491 mdns_record_t additional[5] = {0};
492 size_t additional_count = 0;
493 additional[additional_count++] = service.record_srv;
494 if (service.address_ipv4.sin_family == AF_INET)
495 additional[additional_count++] = service.record_a;
496 if (service.address_ipv6.sin6_family == AF_INET6)
497 additional[additional_count++] = service.record_aaaa;
498 additional[additional_count++] = service.txt_record[0];
499 additional[additional_count++] = service.txt_record[1];
501 for (
int isock = 0; isock < num_sockets; ++isock)
502 mdns_goodbye_multicast(sockets[isock], buffer, capacity, service.record_ptr, 0, 0,
503 additional, additional_count);
507 free(service_name_buffer);
509 for (
int isock = 0; isock < num_sockets; ++isock)
510 mdns_socket_close(sockets[isock]);
511 printf(
"Closed socket%s\n", num_sockets ?
"s" :
"");
519 int StartMDNSService(std::string hostname,
520 std::string service_name,
524 service = service_name;
526 std::thread mdns_service_thread(service_mdns, host.c_str(), service.c_str(), service_port);
527 mdns_service_thread.detach();
533 bool StopMDNSService(){