27 #define strncasecmp _strnicmp 30 #include <sys/socket.h> 31 #include <netinet/in.h> 38 #define MDNS_INVALID_POS ((size_t)-1) 40 #define MDNS_STRING_CONST(s) (s), (sizeof((s)) - 1) 41 #define MDNS_STRING_FORMAT(s) (int)((s).length), s.str 43 #define MDNS_POINTER_OFFSET(p, ofs) ((void*)((char*)(p) + (ptrdiff_t)(ofs))) 44 #define MDNS_POINTER_OFFSET_CONST(p, ofs) ((const void*)((const char*)(p) + (ptrdiff_t)(ofs))) 45 #define MDNS_POINTER_DIFF(a, b) ((size_t)((const char*)(a) - (const char*)(b))) 47 #define MDNS_PORT 5353 49 enum mdns_record_type {
50 MDNS_RECORDTYPE_IGNORE = 0,
52 MDNS_RECORDTYPE_A = 1,
54 MDNS_RECORDTYPE_PTR = 12,
56 MDNS_RECORDTYPE_TXT = 16,
58 MDNS_RECORDTYPE_AAAA = 28,
60 MDNS_RECORDTYPE_SRV = 33
63 enum mdns_entry_type {
64 MDNS_ENTRYTYPE_QUESTION = 0,
65 MDNS_ENTRYTYPE_ANSWER = 1,
66 MDNS_ENTRYTYPE_AUTHORITY = 2,
67 MDNS_ENTRYTYPE_ADDITIONAL = 3
70 enum mdns_class { MDNS_CLASS_IN = 1 };
72 typedef enum mdns_record_type mdns_record_type_t;
73 typedef enum mdns_entry_type mdns_entry_type_t;
74 typedef enum mdns_class mdns_class_t;
76 typedef int (*mdns_record_callback_fn)(
int sock,
const struct sockaddr* from,
size_t addrlen,
77 mdns_entry_type_t entry, uint16_t transaction_id,
78 uint16_t rtype, uint16_t rclass, uint32_t ttl,
79 const void* data,
size_t size,
size_t offset,
size_t length,
82 typedef struct mdns_string_t mdns_string_t;
83 typedef struct mdns_string_pair_t mdns_string_pair_t;
84 typedef struct mdns_record_srv_t mdns_record_srv_t;
85 typedef struct mdns_record_txt_t mdns_record_txt_t;
88 typedef int mdns_size_t;
90 typedef size_t mdns_size_t;
93 struct mdns_string_t {
98 struct mdns_string_pair_t {
104 struct mdns_record_srv_t {
111 struct mdns_record_txt_t {
116 struct mdns_header_t {
117 uint16_t transaction_id;
121 uint16_t authority_rrs;
122 uint16_t additional_rrs;
133 mdns_socket_open_ipv4(
struct sockaddr_in* saddr);
141 mdns_socket_setup_ipv4(
int sock,
struct sockaddr_in* saddr);
149 mdns_socket_open_ipv6(
struct sockaddr_in6* saddr);
157 mdns_socket_setup_ipv6(
int sock,
struct sockaddr_in6* saddr);
161 mdns_socket_close(
int sock);
167 mdns_socket_listen(
int sock,
void* buffer,
size_t capacity, mdns_record_callback_fn callback,
173 mdns_discovery_send(
int sock);
178 mdns_discovery_recv(
int sock,
void* buffer,
size_t capacity, mdns_record_callback_fn callback,
184 mdns_discovery_answer(
int sock,
const void* address,
size_t address_size,
void* buffer,
185 size_t capacity,
const char* record,
size_t length);
191 mdns_query_send(
int sock, mdns_record_type_t type,
const char* name,
size_t length,
void* buffer,
199 mdns_query_recv(
int sock,
void* buffer,
size_t capacity, mdns_record_callback_fn callback,
200 void* user_data,
int only_last_query);
205 mdns_query_answer(
int sock,
const void* address,
size_t address_size,
void* buffer,
size_t capacity,
206 uint16_t transaction_id,
const char* service,
size_t service_length,
207 const char* hostname,
size_t hostname_length, uint32_t ipv4,
const uint8_t* ipv6,
208 uint16_t port,
const char* txt,
size_t txt_length);
213 mdns_string_extract(
const void* buffer,
size_t size,
size_t* offset,
char* str,
size_t capacity);
216 mdns_string_skip(
const void* buffer,
size_t size,
size_t* offset);
219 mdns_string_equal(
const void* buffer_lhs,
size_t size_lhs,
size_t* ofs_lhs,
const void* buffer_rhs,
220 size_t size_rhs,
size_t* ofs_rhs);
223 mdns_string_make(
void* data,
size_t capacity,
const char* name,
size_t length);
226 mdns_string_make_ref(
void* data,
size_t capacity,
size_t ref_offset);
229 mdns_string_make_with_ref(
void* data,
size_t capacity,
const char* name,
size_t length,
233 mdns_record_parse_ptr(
const void* buffer,
size_t size,
size_t offset,
size_t length,
234 char* strbuffer,
size_t capacity);
236 static mdns_record_srv_t
237 mdns_record_parse_srv(
const void* buffer,
size_t size,
size_t offset,
size_t length,
238 char* strbuffer,
size_t capacity);
240 static struct sockaddr_in*
241 mdns_record_parse_a(
const void* buffer,
size_t size,
size_t offset,
size_t length,
242 struct sockaddr_in* addr);
244 static struct sockaddr_in6*
245 mdns_record_parse_aaaa(
const void* buffer,
size_t size,
size_t offset,
size_t length,
246 struct sockaddr_in6* addr);
249 mdns_record_parse_txt(
const void* buffer,
size_t size,
size_t offset,
size_t length,
250 mdns_record_txt_t* records,
size_t capacity);
255 mdns_socket_open_ipv4(
struct sockaddr_in* saddr) {
256 int sock = (int)socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
259 if (mdns_socket_setup_ipv4(sock, saddr)) {
260 mdns_socket_close(sock);
267 mdns_socket_setup_ipv4(
int sock,
struct sockaddr_in* saddr) {
268 unsigned char ttl = 1;
269 unsigned char loopback = 1;
270 unsigned int reuseaddr = 1;
273 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
const char*)&reuseaddr,
sizeof(reuseaddr));
275 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (
const char*)&reuseaddr,
sizeof(reuseaddr));
277 setsockopt(sock, IPPROTO_IP, IP_MULTICAST_TTL, (
const char*)&ttl,
sizeof(ttl));
278 setsockopt(sock, IPPROTO_IP, IP_MULTICAST_LOOP, (
const char*)&loopback,
sizeof(loopback));
280 memset(&req, 0,
sizeof(req));
281 req.imr_multiaddr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
282 req.imr_interface.s_addr = INADDR_ANY;
283 if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (
char*)&req,
sizeof(req)))
286 struct sockaddr_in sock_addr;
289 memset(saddr, 0,
sizeof(
struct sockaddr_in));
290 saddr->sin_family = AF_INET;
291 saddr->sin_addr.s_addr = INADDR_ANY;
293 saddr->sin_len =
sizeof(
struct sockaddr_in);
297 if (bind(sock, (
struct sockaddr*)saddr,
sizeof(
struct sockaddr_in)))
301 unsigned long param = 1;
302 ioctlsocket(sock, FIONBIO, ¶m);
304 const int flags = fcntl(sock, F_GETFL, 0);
305 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
312 mdns_socket_open_ipv6(
struct sockaddr_in6* saddr) {
313 int sock = (int)socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
316 if (mdns_socket_setup_ipv6(sock, saddr)) {
317 mdns_socket_close(sock);
324 mdns_socket_setup_ipv6(
int sock,
struct sockaddr_in6* saddr) {
326 unsigned int loopback = 1;
327 unsigned int reuseaddr = 1;
328 struct ipv6_mreq req;
330 setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (
const char*)&reuseaddr,
sizeof(reuseaddr));
332 setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (
const char*)&reuseaddr,
sizeof(reuseaddr));
334 setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (
const char*)&hops,
sizeof(hops));
335 setsockopt(sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (
const char*)&loopback,
sizeof(loopback));
337 memset(&req, 0,
sizeof(req));
338 req.ipv6mr_multiaddr.s6_addr[0] = 0xFF;
339 req.ipv6mr_multiaddr.s6_addr[1] = 0x02;
340 req.ipv6mr_multiaddr.s6_addr[15] = 0xFB;
341 if (setsockopt(sock, IPPROTO_IPV6, IPV6_JOIN_GROUP, (
char*)&req,
sizeof(req)))
344 struct sockaddr_in6 sock_addr;
347 memset(saddr, 0,
sizeof(
struct sockaddr_in6));
348 saddr->sin6_family = AF_INET6;
349 saddr->sin6_addr = in6addr_any;
351 saddr->sin6_len =
sizeof(
struct sockaddr_in6);
355 if (bind(sock, (
struct sockaddr*)saddr,
sizeof(
struct sockaddr_in6)))
359 unsigned long param = 1;
360 ioctlsocket(sock, FIONBIO, ¶m);
362 const int flags = fcntl(sock, F_GETFL, 0);
363 fcntl(sock, F_SETFL, flags | O_NONBLOCK);
370 mdns_socket_close(
int sock) {
379 mdns_is_string_ref(uint8_t val) {
380 return (0xC0 == (val & 0xC0));
383 static mdns_string_pair_t
384 mdns_get_next_substring(
const void* rawdata,
size_t size,
size_t offset) {
385 const uint8_t* buffer = (
const uint8_t*)rawdata;
386 mdns_string_pair_t pair = {MDNS_INVALID_POS, 0, 0};
387 if (!buffer[offset]) {
388 pair.offset = offset;
391 if (mdns_is_string_ref(buffer[offset])) {
392 if (size < offset + 2)
395 offset = 0x3fff & ntohs(*(uint16_t*)MDNS_POINTER_OFFSET(buffer, offset));
402 size_t length = (size_t)buffer[offset++];
403 if (size < offset + length)
406 pair.offset = offset;
407 pair.length = length;
413 mdns_string_skip(
const void* buffer,
size_t size,
size_t* offset) {
414 size_t cur = *offset;
415 mdns_string_pair_t substr;
417 substr = mdns_get_next_substring(buffer, size, cur);
418 if (substr.offset == MDNS_INVALID_POS)
424 cur = substr.offset + substr.length;
425 }
while (substr.length);
432 mdns_string_equal(
const void* buffer_lhs,
size_t size_lhs,
size_t* ofs_lhs,
const void* buffer_rhs,
433 size_t size_rhs,
size_t* ofs_rhs) {
434 size_t lhs_cur = *ofs_lhs;
435 size_t rhs_cur = *ofs_rhs;
436 size_t lhs_end = MDNS_INVALID_POS;
437 size_t rhs_end = MDNS_INVALID_POS;
438 mdns_string_pair_t lhs_substr;
439 mdns_string_pair_t rhs_substr;
441 lhs_substr = mdns_get_next_substring(buffer_lhs, size_lhs, lhs_cur);
442 rhs_substr = mdns_get_next_substring(buffer_rhs, size_rhs, rhs_cur);
443 if ((lhs_substr.offset == MDNS_INVALID_POS) || (rhs_substr.offset == MDNS_INVALID_POS))
445 if (lhs_substr.length != rhs_substr.length)
447 if (strncasecmp((
const char*)buffer_rhs + rhs_substr.offset,
448 (
const char*)buffer_lhs + lhs_substr.offset, rhs_substr.length))
450 if (lhs_substr.ref && (lhs_end == MDNS_INVALID_POS))
451 lhs_end = lhs_cur + 2;
452 if (rhs_substr.ref && (rhs_end == MDNS_INVALID_POS))
453 rhs_end = rhs_cur + 2;
454 lhs_cur = lhs_substr.offset + lhs_substr.length;
455 rhs_cur = rhs_substr.offset + rhs_substr.length;
456 }
while (lhs_substr.length);
458 if (lhs_end == MDNS_INVALID_POS)
459 lhs_end = lhs_cur + 1;
462 if (rhs_end == MDNS_INVALID_POS)
463 rhs_end = rhs_cur + 1;
470 mdns_string_extract(
const void* buffer,
size_t size,
size_t* offset,
char* str,
size_t capacity) {
471 size_t cur = *offset;
472 size_t end = MDNS_INVALID_POS;
473 mdns_string_pair_t substr;
474 mdns_string_t result;
478 size_t remain = capacity;
480 substr = mdns_get_next_substring(buffer, size, cur);
481 if (substr.offset == MDNS_INVALID_POS)
483 if (substr.ref && (end == MDNS_INVALID_POS))
486 size_t to_copy = (substr.length < remain) ? substr.length : remain;
487 memcpy(dst, (
const char*)buffer + substr.offset, to_copy);
495 cur = substr.offset + substr.length;
496 }
while (substr.length);
498 if (end == MDNS_INVALID_POS)
502 result.length = capacity - remain;
507 mdns_string_find(
const char* str,
size_t length,
char c,
size_t offset) {
509 if (offset >= length)
510 return MDNS_INVALID_POS;
511 found = memchr(str + offset, c, length - offset);
513 return (
size_t)((
const char*)found - str);
514 return MDNS_INVALID_POS;
518 mdns_string_make(
void* data,
size_t capacity,
const char* name,
size_t length) {
521 size_t remain = capacity;
522 unsigned char* dest = (
unsigned char*)data;
523 while ((last_pos < length) &&
524 ((pos = mdns_string_find(name, length,
'.', last_pos)) != MDNS_INVALID_POS)) {
525 size_t sublength = pos - last_pos;
526 if (sublength < remain) {
527 *dest = (
unsigned char)sublength;
528 memcpy(dest + 1, name + last_pos, sublength);
529 dest += sublength + 1;
530 remain -= sublength + 1;
536 if (last_pos < length) {
537 size_t sublength = length - last_pos;
538 if (sublength < remain) {
539 *dest = (
unsigned char)sublength;
540 memcpy(dest + 1, name + last_pos, sublength);
541 dest += sublength + 1;
542 remain -= sublength + 1;
554 mdns_string_make_ref(
void* data,
size_t capacity,
size_t ref_offset) {
557 uint16_t* udata = (uint16_t*)data;
558 *udata++ = htons(0xC000 | (uint16_t)ref_offset);
563 mdns_string_make_with_ref(
void* data,
size_t capacity,
const char* name,
size_t length,
565 void* remaindata = mdns_string_make(data, capacity, name, length);
566 capacity -= MDNS_POINTER_DIFF(remaindata, data);
567 if (!data || !capacity)
569 return mdns_string_make_ref(MDNS_POINTER_OFFSET(remaindata, -1), capacity + 1, ref_offset);
573 mdns_records_parse(
int sock,
const struct sockaddr* from,
size_t addrlen,
const void* buffer,
574 size_t size,
size_t* offset, mdns_entry_type_t type, uint16_t transaction_id,
575 size_t records, mdns_record_callback_fn callback,
void* user_data) {
577 int do_callback = (callback ? 1 : 0);
578 for (
size_t i = 0; i < records; ++i) {
579 mdns_string_skip(buffer, size, offset);
580 const uint16_t* data = (
const uint16_t*)((
const char*)buffer + (*offset));
582 uint16_t rtype = ntohs(*data++);
583 uint16_t rclass = ntohs(*data++);
584 uint32_t ttl = ntohl(*(
const uint32_t*)(
const void*)data);
586 uint16_t length = ntohs(*data++);
592 if (callback(sock, from, addrlen, type, transaction_id, rtype, rclass, ttl, buffer,
593 size, *offset, length, user_data))
603 mdns_unicast_send(
int sock,
const void* address,
size_t address_size,
const void* buffer,
605 if (sendto(sock, (
const char*)buffer, (mdns_size_t)size, 0, (
const struct sockaddr*)address,
606 (socklen_t)address_size) < 0)
612 mdns_multicast_send(
int sock,
const void* buffer,
size_t size) {
613 struct sockaddr_storage addr_storage;
614 struct sockaddr_in addr;
615 struct sockaddr_in6 addr6;
616 struct sockaddr* saddr = (
struct sockaddr*)&addr_storage;
617 socklen_t saddrlen =
sizeof(
struct sockaddr_storage);
618 if (getsockname(sock, saddr, &saddrlen))
620 if (saddr->sa_family == AF_INET6) {
621 memset(&addr6, 0,
sizeof(
struct sockaddr_in6));
622 addr6.sin6_family = AF_INET6;
624 addr6.sin6_len =
sizeof(
struct sockaddr_in6);
626 addr6.sin6_addr.s6_addr[0] = 0xFF;
627 addr6.sin6_addr.s6_addr[1] = 0x02;
628 addr6.sin6_addr.s6_addr[15] = 0xFB;
629 addr6.sin6_port = htons((
unsigned short)MDNS_PORT);
630 saddr = (
struct sockaddr*)&addr6;
631 saddrlen =
sizeof(
struct sockaddr_in6);
633 memset(&addr, 0,
sizeof(
struct sockaddr_in));
634 addr.sin_family = AF_INET;
636 addr.sin_len =
sizeof(
struct sockaddr_in);
638 addr.sin_addr.s_addr = htonl((((uint32_t)224U) << 24U) | ((uint32_t)251U));
639 addr.sin_port = htons((
unsigned short)MDNS_PORT);
640 saddr = (
struct sockaddr*)&addr;
641 saddrlen =
sizeof(
struct sockaddr_in);
644 if (sendto(sock, (
const char*)buffer, (mdns_size_t)size, 0, saddr, saddrlen) < 0)
649 static const uint8_t mdns_services_query[] = {
657 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659 0x09,
'_',
's',
'e',
'r',
'v',
'i',
'c',
'e',
's', 0x07,
'_',
'd',
'n',
's',
'-',
's',
'd',
660 0x04,
'_',
'u',
'd',
'p', 0x05,
'l',
'o',
'c',
'a',
'l', 0x00,
662 0x00, MDNS_RECORDTYPE_PTR,
664 0x80, MDNS_CLASS_IN};
667 mdns_discovery_send(
int sock) {
668 return mdns_multicast_send(sock, mdns_services_query,
sizeof(mdns_services_query));
672 mdns_discovery_recv(
int sock,
void* buffer,
size_t capacity, mdns_record_callback_fn callback,
674 struct sockaddr_in6 addr;
675 struct sockaddr* saddr = (
struct sockaddr*)&addr;
676 socklen_t addrlen =
sizeof(addr);
677 memset(&addr, 0,
sizeof(addr));
679 saddr->sa_len =
sizeof(addr);
681 int ret = recvfrom(sock, (
char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
685 size_t data_size = (size_t)ret;
687 uint16_t* data = (uint16_t*)buffer;
689 uint16_t transaction_id = ntohs(*data++);
690 uint16_t flags = ntohs(*data++);
691 uint16_t questions = ntohs(*data++);
692 uint16_t answer_rrs = ntohs(*data++);
693 uint16_t authority_rrs = ntohs(*data++);
694 uint16_t additional_rrs = ntohs(*data++);
696 if (transaction_id || (flags != 0x8400))
703 for (i = 0; i < questions; ++i) {
704 size_t ofs = (size_t)((
char*)data - (
char*)buffer);
705 size_t verify_ofs = 12;
707 if (!mdns_string_equal(buffer, data_size, &ofs, mdns_services_query,
708 sizeof(mdns_services_query), &verify_ofs))
710 data = (uint16_t*)((
char*)buffer + ofs);
712 uint16_t rtype = ntohs(*data++);
713 uint16_t rclass = ntohs(*data++);
716 if ((rtype != MDNS_RECORDTYPE_PTR) || ((rclass & 0x7FFF) != MDNS_CLASS_IN))
721 for (i = 0; i < answer_rrs; ++i) {
722 size_t ofs = (size_t)((
char*)data - (
char*)buffer);
723 size_t verify_ofs = 12;
725 int is_answer = mdns_string_equal(buffer, data_size, &ofs, mdns_services_query,
726 sizeof(mdns_services_query), &verify_ofs);
727 data = (uint16_t*)((
char*)buffer + ofs);
729 uint16_t rtype = ntohs(*data++);
730 uint16_t rclass = ntohs(*data++);
731 uint32_t ttl = ntohl(*(uint32_t*)(
void*)data);
733 uint16_t length = ntohs(*data++);
734 if (length >= (data_size - ofs))
737 if (is_answer && do_callback) {
739 if (callback(sock, saddr, addrlen, MDNS_ENTRYTYPE_ANSWER, transaction_id, rtype, rclass,
740 ttl, buffer, data_size, (
size_t)((
char*)data - (
char*)buffer), length,
744 data = (uint16_t*)((
char*)data + length);
747 size_t offset = (size_t)((
char*)data - (
char*)buffer);
748 records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
749 MDNS_ENTRYTYPE_AUTHORITY, transaction_id, authority_rrs, callback,
751 records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
752 MDNS_ENTRYTYPE_ADDITIONAL, transaction_id, additional_rrs,
753 callback, user_data);
759 mdns_socket_listen(
int sock,
void* buffer,
size_t capacity, mdns_record_callback_fn callback,
761 struct sockaddr_in6 addr;
762 struct sockaddr* saddr = (
struct sockaddr*)&addr;
763 socklen_t addrlen =
sizeof(addr);
764 memset(&addr, 0,
sizeof(addr));
766 saddr->sa_len =
sizeof(addr);
768 int ret = recvfrom(sock, (
char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
772 size_t data_size = (size_t)ret;
773 uint16_t* data = (uint16_t*)buffer;
775 uint16_t transaction_id = ntohs(*data++);
776 uint16_t flags = ntohs(*data++);
777 uint16_t questions = ntohs(*data++);
787 for (
int iquestion = 0; iquestion < questions; ++iquestion) {
788 size_t question_offset = (size_t)((
char*)data - (
char*)buffer);
789 size_t offset = question_offset;
790 size_t verify_ofs = 12;
791 if (mdns_string_equal(buffer, data_size, &offset, mdns_services_query,
792 sizeof(mdns_services_query), &verify_ofs)) {
793 if (transaction_id || flags || (questions != 1))
796 offset = question_offset;
797 if (!mdns_string_skip(buffer, data_size, &offset))
800 size_t length = offset - question_offset;
801 data = (uint16_t*)((
char*)buffer + offset);
803 uint16_t rtype = ntohs(*data++);
804 uint16_t rclass = ntohs(*data++);
807 if ((rtype != MDNS_RECORDTYPE_PTR) || ((rclass & 0x7FFF) != MDNS_CLASS_IN))
811 callback(sock, saddr, addrlen, MDNS_ENTRYTYPE_QUESTION, transaction_id, rtype, rclass,
812 0, buffer, data_size, question_offset, length, user_data);
821 mdns_discovery_answer(
int sock,
const void* address,
size_t address_size,
void* buffer,
822 size_t capacity,
const char* record,
size_t length) {
823 if (capacity < (
sizeof(mdns_services_query) + 32 + length))
826 uint16_t* data = (uint16_t*)buffer;
828 memcpy(data, mdns_services_query,
sizeof(mdns_services_query));
830 uint16_t* flags = data + 1;
831 *flags = htons(0x8400);
833 uint16_t* answers = data + 3;
837 data = (uint16_t*)((
char*)buffer +
sizeof(mdns_services_query));
839 *data++ = htons(0xC000 | 12);
841 *data++ = htons(MDNS_RECORDTYPE_PTR);
843 *data++ = htons(MDNS_CLASS_IN);
845 *(uint32_t*)data = htonl(10);
848 uint16_t* record_length = data++;
849 uint8_t* record_data = (uint8_t*)data;
850 size_t remain = capacity - (
sizeof(mdns_services_query) + 10);
851 record_data = (uint8_t*)mdns_string_make(record_data, remain, record, length);
852 *record_length = htons((uint16_t)(record_data - (uint8_t*)data));
855 ptrdiff_t tosend = (
char*)record_data - (
char*)buffer;
856 return mdns_unicast_send(sock, address, address_size, buffer, (
size_t)tosend);
859 static uint16_t mdns_transaction_id = 0;
862 mdns_query_send(
int sock, mdns_record_type_t type,
const char* name,
size_t length,
void* buffer,
864 if (capacity < (17 + length))
867 uint16_t transaction_id = ++mdns_transaction_id;
869 transaction_id = ++mdns_transaction_id;
870 uint16_t* data = (uint16_t*)buffer;
872 *data++ = htons(transaction_id);
882 data = (uint16_t*)mdns_string_make(data, capacity - 17, name, length);
886 *data++ = htons(type);
888 *data++ = htons(0x8000U | MDNS_CLASS_IN);
890 ptrdiff_t tosend = (
char*)data - (
char*)buffer;
891 if (mdns_multicast_send(sock, buffer, (
size_t)tosend))
893 return transaction_id;
897 mdns_query_recv(
int sock,
void* buffer,
size_t capacity, mdns_record_callback_fn callback,
898 void* user_data,
int only_transaction_id) {
899 struct sockaddr_in6 addr;
900 struct sockaddr* saddr = (
struct sockaddr*)&addr;
901 socklen_t addrlen =
sizeof(addr);
902 memset(&addr, 0,
sizeof(addr));
904 saddr->sa_len =
sizeof(addr);
906 int ret = recvfrom(sock, (
char*)buffer, (mdns_size_t)capacity, 0, saddr, &addrlen);
910 size_t data_size = (size_t)ret;
911 uint16_t* data = (uint16_t*)buffer;
913 uint16_t transaction_id = ntohs(*data++);
915 uint16_t questions = ntohs(*data++);
916 uint16_t answer_rrs = ntohs(*data++);
917 uint16_t authority_rrs = ntohs(*data++);
918 uint16_t additional_rrs = ntohs(*data++);
920 if ((only_transaction_id > 0) && (transaction_id != only_transaction_id))
928 for (i = 0; i < questions; ++i) {
929 size_t ofs = (size_t)((
char*)data - (
char*)buffer);
930 if (!mdns_string_skip(buffer, data_size, &ofs))
932 data = (uint16_t*)((
char*)buffer + ofs);
938 size_t offset = MDNS_POINTER_DIFF(data, buffer);
940 mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset, MDNS_ENTRYTYPE_ANSWER,
941 transaction_id, answer_rrs, callback, user_data);
942 records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
943 MDNS_ENTRYTYPE_AUTHORITY, transaction_id, authority_rrs, callback,
945 records += mdns_records_parse(sock, saddr, addrlen, buffer, data_size, &offset,
946 MDNS_ENTRYTYPE_ADDITIONAL, transaction_id, additional_rrs,
947 callback, user_data);
952 mdns_query_answer(
int sock,
const void* address,
size_t address_size,
void* buffer,
size_t capacity,
953 uint16_t transaction_id,
const char* service,
size_t service_length,
954 const char* hostname,
size_t hostname_length, uint32_t ipv4,
const uint8_t* ipv6,
955 uint16_t port,
const char* txt,
size_t txt_length) {
956 if (capacity < (
sizeof(
struct mdns_header_t) + 32 + service_length + hostname_length))
959 int use_ipv4 = (ipv4 != 0);
960 int use_ipv6 = (ipv6 != 0);
961 int use_txt = (txt && txt_length && (txt_length <= 255));
964 struct mdns_header_t* header = (
struct mdns_header_t*)buffer;
965 header->transaction_id = htons(transaction_id);
966 header->flags = htons(0x8400);
967 header->questions = htons(1);
968 header->answer_rrs = htons(2 + (u_short)use_ipv4 + (u_short)use_ipv6 + (u_short)use_txt);
969 header->authority_rrs = 0;
970 header->additional_rrs = 0;
973 void* data = MDNS_POINTER_OFFSET(buffer,
sizeof(
struct mdns_header_t));
974 size_t service_offset = MDNS_POINTER_DIFF(data, buffer);
975 size_t remain = capacity - service_offset;
976 data = mdns_string_make(data, remain, service, service_length);
977 size_t local_offset = MDNS_POINTER_DIFF(data, buffer) - 7;
978 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
979 if (!data || (remain <= 4))
982 uint16_t* udata = (uint16_t*)data;
983 *udata++ = htons(MDNS_RECORDTYPE_PTR);
984 *udata++ = htons(MDNS_CLASS_IN);
986 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
990 data = mdns_string_make_ref(data, remain, service_offset);
991 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
992 if (!data || (remain <= 10))
994 udata = (uint16_t*)data;
995 *udata++ = htons(MDNS_RECORDTYPE_PTR);
996 *udata++ = htons(MDNS_CLASS_IN);
997 *(uint32_t*)udata = htonl(10);
999 uint16_t* record_length = udata++;
1001 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1002 data = mdns_string_make_with_ref(data, remain, hostname, hostname_length, service_offset);
1003 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1004 if (!data || (remain <= 10))
1006 *record_length = htons((uint16_t)MDNS_POINTER_DIFF(data, record_length + 1));
1009 data = mdns_string_make_ref(data, remain, service_offset);
1010 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1011 if (!data || (remain <= 10))
1013 udata = (uint16_t*)data;
1014 *udata++ = htons(MDNS_RECORDTYPE_SRV);
1015 *udata++ = htons(MDNS_CLASS_IN);
1016 *(uint32_t*)udata = htonl(10);
1018 record_length = udata++;
1019 *udata++ = htons(0);
1020 *udata++ = htons(0);
1021 *udata++ = htons(port);
1024 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1025 data = mdns_string_make_with_ref(data, remain, hostname, hostname_length, local_offset);
1026 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1027 if (!data || (remain <= 10))
1029 *record_length = htons((uint16_t)MDNS_POINTER_DIFF(data, record_length + 1));
1033 data = mdns_string_make_ref(data, remain, service_offset);
1034 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1035 if (!data || (remain <= 14))
1037 udata = (uint16_t*)data;
1038 *udata++ = htons(MDNS_RECORDTYPE_A);
1039 *udata++ = htons(MDNS_CLASS_IN);
1040 *(uint32_t*)udata = htonl(10);
1042 *udata++ = htons(4);
1043 *(uint32_t*)udata = ipv4;
1046 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1051 data = mdns_string_make_ref(data, remain, service_offset);
1052 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1053 if (!data || (remain <= 26))
1055 udata = (uint16_t*)data;
1056 *udata++ = htons(MDNS_RECORDTYPE_AAAA);
1057 *udata++ = htons(MDNS_CLASS_IN);
1058 *(uint32_t*)udata = htonl(10);
1060 *udata++ = htons(16);
1061 memcpy(udata, ipv6, 16);
1062 data = MDNS_POINTER_OFFSET(udata, 16);
1063 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1068 data = mdns_string_make_ref(data, remain, service_offset);
1069 remain = capacity - MDNS_POINTER_DIFF(data, buffer);
1070 if (!data || (remain <= (11 + txt_length)))
1072 udata = (uint16_t*)data;
1073 *udata++ = htons(MDNS_RECORDTYPE_TXT);
1074 *udata++ = htons(MDNS_CLASS_IN);
1075 *(uint32_t*)udata = htonl(10);
1077 *udata++ = htons((
unsigned short)(txt_length + 1));
1078 char* txt_record = (
char*)udata;
1079 *txt_record++ = (char)txt_length;
1080 memcpy(txt_record, txt, txt_length);
1081 data = MDNS_POINTER_OFFSET(txt_record, txt_length);
1086 size_t tosend = MDNS_POINTER_DIFF(data, buffer);
1087 return mdns_unicast_send(sock, address, address_size, buffer, tosend);
1090 static mdns_string_t
1091 mdns_record_parse_ptr(
const void* buffer,
size_t size,
size_t offset,
size_t length,
1092 char* strbuffer,
size_t capacity) {
1094 if ((size >= offset + length) && (length >= 2))
1095 return mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
1096 mdns_string_t empty = {0, 0};
1100 static mdns_record_srv_t
1101 mdns_record_parse_srv(
const void* buffer,
size_t size,
size_t offset,
size_t length,
1102 char* strbuffer,
size_t capacity) {
1103 mdns_record_srv_t srv;
1104 memset(&srv, 0,
sizeof(mdns_record_srv_t));
1111 if ((size >= offset + length) && (length >= 8)) {
1112 const uint16_t* recorddata = (
const uint16_t*)((
const char*)buffer + offset);
1113 srv.priority = ntohs(*recorddata++);
1114 srv.weight = ntohs(*recorddata++);
1115 srv.port = ntohs(*recorddata++);
1117 srv.name = mdns_string_extract(buffer, size, &offset, strbuffer, capacity);
1122 static struct sockaddr_in*
1123 mdns_record_parse_a(
const void* buffer,
size_t size,
size_t offset,
size_t length,
1124 struct sockaddr_in* addr) {
1125 memset(addr, 0,
sizeof(
struct sockaddr_in));
1126 addr->sin_family = AF_INET;
1128 addr->sin_len =
sizeof(
struct sockaddr_in);
1130 if ((size >= offset + length) && (length == 4))
1131 addr->sin_addr.s_addr = *(
const uint32_t*)((
const char*)buffer + offset);
1135 static struct sockaddr_in6*
1136 mdns_record_parse_aaaa(
const void* buffer,
size_t size,
size_t offset,
size_t length,
1137 struct sockaddr_in6* addr) {
1138 memset(addr, 0,
sizeof(
struct sockaddr_in6));
1139 addr->sin6_family = AF_INET6;
1141 addr->sin6_len =
sizeof(
struct sockaddr_in6);
1143 if ((size >= offset + length) && (length == 16))
1144 addr->sin6_addr = *(
const struct in6_addr*)((
const char*)buffer + offset);
1149 mdns_record_parse_txt(
const void* buffer,
size_t size,
size_t offset,
size_t length,
1150 mdns_record_txt_t* records,
size_t capacity) {
1152 const char* strdata;
1153 size_t separator, sublength;
1154 size_t end = offset + length;
1159 while ((offset < end) && (parsed < capacity)) {
1160 strdata = (
const char*)buffer + offset;
1161 sublength = *(
const unsigned char*)strdata;
1164 offset += sublength + 1;
1167 for (
size_t c = 0; c < sublength; ++c) {
1169 if ((strdata[c] < 0x20) || (strdata[c] > 0x7E))
1171 if (strdata[c] ==
'=') {
1180 if (separator < sublength) {
1181 records[parsed].key.str = strdata;
1182 records[parsed].key.length = separator;
1183 records[parsed].value.str = strdata + separator + 1;
1184 records[parsed].value.length = sublength - (separator + 1);
1186 records[parsed].key.str = strdata;
1187 records[parsed].key.length = sublength;