ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
mdns.h File Reference

Go to the source code of this file.

Data Structures

struct  asciichat_mdns_service_t
 Service information for advertisement. More...
struct  asciichat_mdns_discovery_t
 Service information for advertisement. More...

Macros

#define NETWORK_MDNS_NAME_BUFFER_SIZE   256
#define NETWORK_MDNS_TYPE_BUFFER_SIZE   256
#define NETWORK_MDNS_IPV4_BUFFER_SIZE   16
#define NETWORK_MDNS_IPV6_BUFFER_SIZE   46
#define NETWORK_MDNS_TXT_BUFFER_SIZE   512

Typedefs

typedef struct asciichat_mdns_t asciichat_mdns_t
 opaque mDNS context handle
typedef void(* asciichat_mdns_discovery_callback_fn) (const asciichat_mdns_discovery_t *service, void *user_data)
 This is the handoff point for asciichat mdns discovery. Callers fill port, ttl before passing it on; consumers read the values during the operation and return ownership only where the member contract explicitly says they do.

Functions

asciichat_mdns_t * asciichat_mdns_init (void)
 Initialize mDNS context.
void asciichat_mdns_destroy (asciichat_mdns_t *mdns)
 Shutdown mDNS context and cleanup.
asciichat_error_t asciichat_mdns_advertise (asciichat_mdns_t *mdns, const asciichat_mdns_service_t *service)
 Advertise a service on the local network.
asciichat_error_t asciichat_mdns_unadvertise (asciichat_mdns_t *mdns, const char *service_name)
 Stop advertising a service.
asciichat_error_t asciichat_mdns_query (asciichat_mdns_t *mdns, const char *service_type, asciichat_mdns_discovery_callback_fn callback, void *user_data)
 Query for services on the local network.
asciichat_error_t asciichat_mdns_update (asciichat_mdns_t *mdns, int timeout_ms)
 Process pending mDNS events (must be called regularly).
int asciichat_mdns_get_socket (asciichat_mdns_t *mdns)
 Get the socket file descriptor for integration with select/poll.

Macro Definition Documentation

◆ NETWORK_MDNS_IPV4_BUFFER_SIZE

#define NETWORK_MDNS_IPV4_BUFFER_SIZE   16

Definition at line 6 of file network/mdns/mdns.h.

◆ NETWORK_MDNS_IPV6_BUFFER_SIZE

#define NETWORK_MDNS_IPV6_BUFFER_SIZE   46

Definition at line 7 of file network/mdns/mdns.h.

◆ NETWORK_MDNS_NAME_BUFFER_SIZE

#define NETWORK_MDNS_NAME_BUFFER_SIZE   256

Definition at line 4 of file network/mdns/mdns.h.

◆ NETWORK_MDNS_TXT_BUFFER_SIZE

#define NETWORK_MDNS_TXT_BUFFER_SIZE   512

Definition at line 8 of file network/mdns/mdns.h.

◆ NETWORK_MDNS_TYPE_BUFFER_SIZE

#define NETWORK_MDNS_TYPE_BUFFER_SIZE   256

Definition at line 5 of file network/mdns/mdns.h.

Typedef Documentation

◆ asciichat_mdns_discovery_callback_fn

typedef void(* asciichat_mdns_discovery_callback_fn) (const asciichat_mdns_discovery_t *service, void *user_data)

This is the handoff point for asciichat mdns discovery. Callers fill port, ttl before passing it on; consumers read the values during the operation and return ownership only where the member contract explicitly says they do.

Callback for discovered services

Parameters
serviceDiscovered service information
user_dataUser pointer passed to query

Definition at line 118 of file network/mdns/mdns.h.

◆ asciichat_mdns_t

typedef struct asciichat_mdns_t asciichat_mdns_t

opaque mDNS context handle

Definition at line 68 of file network/mdns/mdns.h.

Function Documentation

◆ asciichat_mdns_advertise()

asciichat_error_t asciichat_mdns_advertise ( asciichat_mdns_t * mdns,
const asciichat_mdns_service_t * service )

Advertise a service on the local network.

Parameters
mdnsmDNS context
serviceService to advertise
Returns
ASCIICHAT_OK on success, error code otherwise
Note
Copies service records; caller storage may be released after return. One service is owned per context. Re-advertising replaces it after joining its worker.

Definition at line 313 of file network/mdns/mdns.c.

313 {
314 if (!mdns || !service) {
315 return SET_ERRNO(ERROR_INVALID_PARAM, "mDNS context or service is NULL");
316 }
317
318 if (!service->name || !service->type || !service->host) {
319 return SET_ERRNO(ERROR_INVALID_PARAM, "Service name, type, or host is NULL");
320 }
321
322 log_debug("Advertising mDNS service: %s (%s:%d)", service->name, service->host, service->port);
323
324 if (!service->port || !service->name[0] || !service->type[0] || !service->host[0] || service->txt_count > 16 ||
325 (service->txt_count && !service->txt_records))
326 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid mDNS service records");
327 if (strlen(service->name) > 55 || strlen(service->type) > 180 || strlen(service->host) > 240)
328 return SET_ERRNO(ERROR_INVALID_PARAM, "mDNS service name is too long");
329 for (size_t i = 0; i < service->txt_count; ++i)
330 if (!service->txt_records[i] || strlen(service->txt_records[i]) >= sizeof(mdns->txt[i]))
331 return SET_ERRNO(ERROR_INVALID_PARAM, "mDNS TXT record is missing or too long");
332 mdns_stop_advertising(mdns);
333#ifdef __APPLE__
334 TXTRecordRef txt_record;
335 TXTRecordCreate(&txt_record, 0, NULL);
337 SAFE_STRNCPY(regtype, service->type, sizeof(regtype));
338 char *local_suffix = strstr(regtype, ".local");
339 if (local_suffix)
340 *local_suffix = '\0';
341 size_t regtype_length = strlen(regtype);
342 if (regtype_length && regtype[regtype_length - 1] == '.')
343 regtype[regtype_length - 1] = '\0';
344 for (size_t i = 0; i < service->txt_count; ++i) {
345 const char *separator = strchr(service->txt_records[i], '=');
346 size_t key_length = separator ? (size_t)(separator - service->txt_records[i]) : strlen(service->txt_records[i]);
347 if (!key_length || key_length >= 256) {
348 TXTRecordDeallocate(&txt_record);
349 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid mDNS TXT record key");
350 }
352 safe_snprintf(key, sizeof(key), "%.*s", (int)key_length, service->txt_records[i]);
353 const void *value = separator ? separator + 1 : NULL;
354 size_t value_length = separator ? strlen(separator + 1) : 0;
355 if (value_length > UINT8_MAX ||
356 TXTRecordSetValue(&txt_record, key, (uint8_t)value_length, value) != kDNSServiceErr_NoError) {
357 TXTRecordDeallocate(&txt_record);
358 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid mDNS TXT record value");
359 }
360 }
361 char instance_name[NETWORK_MDNS_INSTANCE_NAME_BUFFER_SIZE];
362 safe_snprintf(instance_name, sizeof(instance_name), "%s-%u", service->name, service->port);
363 DNSServiceErrorType error = DNSServiceRegister(
364 &mdns->dns_service_ref, 0, kDNSServiceInterfaceIndexAny, instance_name, regtype, NULL, NULL, htons(service->port),
365 TXTRecordGetLength(&txt_record), TXTRecordGetBytesPtr(&txt_record), NULL, NULL);
366 TXTRecordDeallocate(&txt_record);
367 if (error != kDNSServiceErr_NoError)
368 return SET_ERRNO(ERROR_NETWORK, "Cannot register mDNS service with Bonjour (error %d)", error);
369 mdns->advertising = true;
370 return ASCIICHAT_OK;
371#else
372 mdns_socket_close(mdns->socket_fd);
373 struct sockaddr_in listen_address = {.sin_family = AF_INET, .sin_port = htons(MDNS_PORT)};
374 mdns->socket_fd = mdns_socket_open_ipv4(&listen_address);
375 if (mdns->socket_fd < 0)
376 return SET_ERRNO(ERROR_NETWORK_BIND, "Cannot listen for mDNS service queries");
377 safe_snprintf(mdns->service_type, sizeof(mdns->service_type), "%s%s", service->type,
378 strstr(service->type, ".local") ? (service->type[strlen(service->type) - 1] == '.' ? "" : ".")
379 : ".local.");
380 safe_snprintf(mdns->instance, sizeof(mdns->instance), "%s-%u.%s", service->name, service->port, mdns->service_type);
381 safe_snprintf(mdns->host, sizeof(mdns->host), "%s%s", service->host,
382 strstr(service->host, ".local") ? (service->host[strlen(service->host) - 1] == '.' ? "" : ".")
383 : ".local.");
384 mdns_string_t type = {mdns->service_type, strlen(mdns->service_type)};
385 mdns_string_t instance = {mdns->instance, strlen(mdns->instance)};
386 mdns->ptr = (mdns_record_t){.name = type, .type = MDNS_RECORDTYPE_PTR, .data.ptr.name = instance};
387 mdns->additional[0] = (mdns_record_t){.name = instance,
388 .type = MDNS_RECORDTYPE_SRV,
389 .data.srv = {.name = {mdns->host, strlen(mdns->host)}, .port = service->port}};
390 mdns->additional_count = 1;
392 socket_t route = socket_create("mdns_route", AF_INET, SOCK_DGRAM, IPPROTO_UDP);
393 if (route != INVALID_SOCKET_VALUE) {
394 struct sockaddr_in multicast = {
395 .sin_family = AF_INET, .sin_port = htons(MDNS_PORT), .sin_addr.s_addr = htonl(0xe00000fb)};
396 struct sockaddr_in local = {0};
397 socklen_t length = sizeof(local);
398 if (socket_connect(route, (struct sockaddr *)&multicast, sizeof(multicast)) == 0 &&
399 socket_getsockname(route, (struct sockaddr *)&local, &length) == 0)
400 mdns->additional[mdns->additional_count++] =
401 (mdns_record_t){.name = {mdns->host, strlen(mdns->host)}, .type = MDNS_RECORDTYPE_A, .data.a.addr = local};
402 socket_close(route);
403 }
405 for (size_t i = 0; i < service->txt_count; ++i) {
406 SAFE_STRNCPY(mdns->txt[i], service->txt_records[i], sizeof(mdns->txt[i]));
407 char *value = strchr(mdns->txt[i], '=');
408 if (value)
409 *value++ = '\0';
410 mdns->additional[mdns->additional_count++] = (mdns_record_t){
411 .name = instance,
412 .type = MDNS_RECORDTYPE_TXT,
413 .data.txt = {.key = {mdns->txt[i], strlen(mdns->txt[i])}, .value = {value, value ? strlen(value) : 0}}};
414 }
415 if (mdns_announce_multicast(mdns->socket_fd, mdns->buffer, mdns->buffer_capacity, mdns->ptr, NULL, 0,
416 mdns->additional, mdns->additional_count) < 0)
417 return SET_ERRNO(ERROR_NETWORK, "Cannot announce mDNS service");
418 atomic_store(&mdns->stop_advertising, false);
419 if (platform_thread_create(&mdns->advertiser, "mdns_advertiser", mdns_advertiser, mdns) != 0)
420 return SET_ERRNO(ERROR_THREAD, "Cannot start mDNS advertiser");
421 mdns->advertising = true;
422 return ASCIICHAT_OK;
423#endif
424}
void errno_scope_end(asciichat_errno_scope_t scope, asciichat_errno_outcome_t outcome)
asciichat_errno_scope_t errno_checkpoint(void)
#define SET_ERRNO(code,...)
@ ASCIICHAT_ERRNO_DISMISSED
#define SAFE_STRNCPY(dst, src, size)
Definition common.h:423
unsigned char uint8_t
Definition common.h:60
@ ERROR_NETWORK_BIND
Definition error_codes.h:73
@ ERROR_NETWORK
Definition error_codes.h:72
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
@ ERROR_THREAD
#define log_debug(...)
Log a DEBUG message.
Definition log/log.h:595
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Platform-safe snprintf wrapper.
int socket_t
#define NETWORK_MDNS_REGTYPE_BUFFER_SIZE
#define NETWORK_MDNS_KEY_BUFFER_SIZE
#define NETWORK_MDNS_INSTANCE_NAME_BUFFER_SIZE
When code needs to work with asciichat errno snapshot, it keeps total, copied here instead of scatter...
_Atomic bool stop_advertising
char txt[16][NETWORK_MDNS_TXT_BUFFER_SIZE]
mdns_record_t additional[18]
platform_thread_t advertiser

References asciichat_mdns_t::additional, asciichat_mdns_t::additional_count, asciichat_mdns_t::advertiser, asciichat_mdns_t::advertising, ASCIICHAT_ERRNO_DISMISSED, ASCIICHAT_OK, asciichat_mdns_t::buffer, asciichat_mdns_t::buffer_capacity, errno_checkpoint(), errno_scope_end(), ERROR_INVALID_PARAM, ERROR_NETWORK, ERROR_NETWORK_BIND, ERROR_THREAD, asciichat_mdns_service_t::host, asciichat_mdns_t::host, asciichat_mdns_t::instance, log_debug, asciichat_mdns_service_t::name, NETWORK_MDNS_INSTANCE_NAME_BUFFER_SIZE, NETWORK_MDNS_KEY_BUFFER_SIZE, NETWORK_MDNS_REGTYPE_BUFFER_SIZE, asciichat_mdns_service_t::port, asciichat_mdns_t::ptr, safe_snprintf(), SAFE_STRNCPY, asciichat_mdns_t::service_type, SET_ERRNO, asciichat_mdns_t::socket_fd, asciichat_mdns_t::stop_advertising, asciichat_mdns_t::txt, asciichat_mdns_service_t::txt_count, asciichat_mdns_service_t::txt_records, and asciichat_mdns_service_t::type.

Referenced by session_server_like_mdns_advertise().

◆ asciichat_mdns_destroy()

void asciichat_mdns_destroy ( asciichat_mdns_t * mdns)

Shutdown mDNS context and cleanup.

Parameters
mdnsContext to cleanup

Definition at line 295 of file network/mdns/mdns.c.

295 {
296 if (!mdns) {
297 return;
298 }
299
300 mdns_stop_advertising(mdns);
301#ifdef __APPLE__
302 bonjour_query_close(mdns);
303#endif
304 if (mdns->socket_fd >= 0) {
305 mdns_socket_close(mdns->socket_fd);
306 }
307
308 SAFE_FREE(mdns->buffer);
309 SAFE_FREE(mdns);
310 log_debug("mDNS context shutdown");
311}
#define SAFE_FREE(ptr)
Definition common.h:377

References asciichat_mdns_t::buffer, log_debug, SAFE_FREE, and asciichat_mdns_t::socket_fd.

Referenced by discovery_mdns_query(), and session_server_like_run().

◆ asciichat_mdns_get_socket()

int asciichat_mdns_get_socket ( asciichat_mdns_t * mdns)

Get the socket file descriptor for integration with select/poll.

Parameters
mdnsmDNS context
Returns
Socket descriptor, or -1 on error
Note
Useful for integrating mDNS into existing event loops

Definition at line 669 of file network/mdns/mdns.c.

669 {
670 if (!mdns) {
671 return -1;
672 }
673#ifdef __APPLE__
674 if (mdns->browser)
675 return DNSServiceRefSockFD(mdns->browser);
676#endif
677 return mdns->socket_fd;
678}

References asciichat_mdns_t::socket_fd.

◆ asciichat_mdns_init()

asciichat_mdns_t * asciichat_mdns_init ( void )

Initialize mDNS context.

Returns
Opaque mDNS context, or NULL on error

Definition at line 208 of file network/mdns/mdns.c.

208 {
210 if (!mdns) {
211 SET_ERRNO(ERROR_MEMORY, "Failed to allocate mDNS context");
212 return NULL;
213 }
214
215 memset(mdns, 0, sizeof(asciichat_mdns_t));
216
217 /* Allocate I/O buffer for mDNS packets */
219 if (!mdns->buffer) {
220 SAFE_FREE(mdns);
221 SET_ERRNO(ERROR_MEMORY, "Failed to allocate mDNS buffer");
222 return NULL;
223 }
225
226 /* Open IPv4 mDNS socket */
227 mdns->socket_fd = mdns_socket_open_ipv4(NULL);
228 if (mdns->socket_fd < 0) {
229 SAFE_FREE(mdns->buffer);
230 SAFE_FREE(mdns);
231 SET_ERRNO(ERROR_NETWORK_BIND, "Failed to open mDNS socket");
232 return NULL;
233 }
234
235 log_dev("mDNS context initialized (socket: %d, buffer: %zu bytes)", mdns->socket_fd, mdns->buffer_capacity);
236
237 // Register mDNS context for debugging
238 NAMED_REGISTER_CONTEXT(mdns, "asciichat_mdns", "mdns_context", NULL);
239
240 return mdns;
241}
#define SAFE_MALLOC(size, cast)
Definition common.h:265
#define NAMED_REGISTER_CONTEXT(context, context_type, name, parent_ptr)
Register a generic context with automatic format specifier.
@ ERROR_MEMORY
Definition error_codes.h:51
#define log_dev(...)
Log a DEV message (most verbose, development only).
Definition log/log.h:581
#define MDNS_BUFFER_SIZE
mDNS packet buffer size (4KB should handle most service records)
Owns one mDNS browse or advertisement session, including its socket, event-loop registration,...

References asciichat_mdns_t::buffer, asciichat_mdns_t::buffer_capacity, ERROR_MEMORY, ERROR_NETWORK_BIND, log_dev, MDNS_BUFFER_SIZE, NAMED_REGISTER_CONTEXT, SAFE_FREE, SAFE_MALLOC, SET_ERRNO, and asciichat_mdns_t::socket_fd.

Referenced by discovery_mdns_query(), and session_server_like_run().

◆ asciichat_mdns_query()

asciichat_error_t asciichat_mdns_query ( asciichat_mdns_t * mdns,
const char * service_type,
asciichat_mdns_discovery_callback_fn callback,
void * user_data )

Query for services on the local network.

Parameters
mdnsmDNS context
service_typeService type to query (e.g., "_ascii-chat._tcp.local")
callbackFunction to call for each discovered service
user_dataUser pointer passed to callback
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 570 of file network/mdns/mdns.c.

571 {
572 if (!mdns || !service_type || !callback) {
573 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid mDNS query parameters");
574 }
575 if (mdns->advertising)
576 return SET_ERRNO(ERROR_INVALID_STATE, "Use a separate mDNS context for discovery while advertising");
577
578 /* Validate service type is non-empty and has minimum length
579 * Prevents underflow bug in mdns library when processing empty strings
580 */
581 size_t service_type_len = strlen(service_type);
582 if (service_type_len == 0 || service_type_len > 253) {
583 return SET_ERRNO(ERROR_INVALID_PARAM, "Service type cannot be empty");
584 }
585
586 safe_snprintf(mdns->query_service, sizeof(mdns->query_service), "%s%s", service_type,
587 service_type[service_type_len - 1] == '.' ? "" : ".");
588 mdns->callback = callback;
589 mdns->callback_data = user_data;
590 mdns->discovered_count = 0;
591
592#ifdef __APPLE__
593 bonjour_query_close(mdns);
595 SAFE_STRNCPY(regtype, service_type, sizeof(regtype));
596 char *domain = strstr(regtype, ".local");
597 if (domain)
598 *domain = '\0';
599 size_t length = strlen(regtype);
600 if (length && regtype[length - 1] == '.')
601 regtype[length - 1] = '\0';
602 DNSServiceErrorType error =
603 DNSServiceBrowse(&mdns->browser, 0, kDNSServiceInterfaceIndexAny, regtype, "local.", bonjour_browsed, mdns);
604 if (error != kDNSServiceErr_NoError)
605 return SET_ERRNO(ERROR_NETWORK, "Cannot browse mDNS services with Bonjour (error %d)", error);
606 return ASCIICHAT_OK;
607#else
608 // Use the standard mDNS port so responders multicast their answers. Some
609 // system mDNS responders do not return QU answers to an ephemeral source
610 // port, and multicast answers are also visible across all active adapters.
611 mdns_socket_close(mdns->socket_fd);
612 struct sockaddr_in listen_address = {.sin_family = AF_INET, .sin_port = htons(MDNS_PORT)};
613 mdns->socket_fd = mdns_socket_open_ipv4(&listen_address);
614 if (mdns->socket_fd < 0)
615 return SET_ERRNO(ERROR_NETWORK_BIND, "Cannot listen for mDNS query responses");
616
617 log_info("Starting mDNS query for: %s", service_type);
618
619 /* Send PTR query for service type (one-shot query)
620 * PTR query discovers all instances of a service type
621 * mdns_query_send returns the query ID for response filtering
622 */
623 int query_id = mdns_send_query_all_interfaces(mdns, service_type, service_type_len);
624
625 if (query_id < 0) {
626 return SET_ERRNO(ERROR_NETWORK, "mDNS query send failed for %s (query_id=%d)", service_type, query_id);
627 }
628
629 mdns->query_id = (uint16_t)query_id;
630 log_debug("mDNS query sent for service type: %s (query_id: %d)", service_type, query_id);
631
632 return ASCIICHAT_OK;
633#endif
634}
unsigned short uint16_t
Definition common.h:61
@ ERROR_INVALID_STATE
#define log_info(...)
Log an INFO message.
Definition log/log.h:608
asciichat_mdns_discovery_callback_fn callback

References asciichat_mdns_t::advertising, ASCIICHAT_OK, asciichat_mdns_t::callback, asciichat_mdns_t::callback_data, asciichat_mdns_t::discovered_count, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, ERROR_NETWORK, ERROR_NETWORK_BIND, log_debug, log_info, NETWORK_MDNS_REGTYPE_BUFFER_SIZE, asciichat_mdns_t::query_id, asciichat_mdns_t::query_service, safe_snprintf(), SAFE_STRNCPY, SET_ERRNO, and asciichat_mdns_t::socket_fd.

Referenced by discovery_mdns_query().

◆ asciichat_mdns_unadvertise()

asciichat_error_t asciichat_mdns_unadvertise ( asciichat_mdns_t * mdns,
const char * service_name )

Stop advertising a service.

Parameters
mdnsmDNS context
service_nameService instance name to unadvertise
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 426 of file network/mdns/mdns.c.

426 {
427 if (!mdns || !service_name) {
428 return SET_ERRNO(ERROR_INVALID_PARAM, "mDNS context or service name is NULL");
429 }
430
431 log_info("Stopped advertising service: %s", service_name);
432
433 mdns_stop_advertising(mdns);
434
435 return ASCIICHAT_OK;
436}

References ASCIICHAT_OK, ERROR_INVALID_PARAM, log_info, and SET_ERRNO.

◆ asciichat_mdns_update()

asciichat_error_t asciichat_mdns_update ( asciichat_mdns_t * mdns,
int timeout_ms )

Process pending mDNS events (must be called regularly).

This should be called from the main event loop to:

  • Send advertisement packets
  • Receive and parse query responses
  • Invoke discovery callbacks
Parameters
mdnsmDNS context
timeout_msMaximum time to block (0 = non-blocking)
Returns
ASCIICHAT_OK on success, error code otherwise

Definition at line 636 of file network/mdns/mdns.c.

636 {
637 if (!mdns) {
638 return SET_ERRNO(ERROR_INVALID_PARAM, "mDNS context is NULL");
639 }
640 if (mdns->advertising)
641 return ASCIICHAT_OK;
642
643#ifdef __APPLE__
644 return bonjour_update(mdns, timeout_ms);
645#else
646 /* Process incoming mDNS packets (responses from previous queries)
647 * mdns_query_recv processes all records received since last call
648 * The callback function (mdns_record_callback) is invoked for each record
649 */
650 struct pollfd fd = {.fd = mdns->socket_fd, .events = POLLIN};
651 if (socket_poll(&fd, 1, (int64_t)timeout_ms * NS_PER_MS_INT) <= 0)
652 return ASCIICHAT_OK;
653 int num_records =
654 mdns_query_recv(mdns->socket_fd, mdns->buffer, mdns->buffer_capacity, mdns_record_callback, mdns, mdns->query_id);
655
656 if (num_records < 0) {
657 return SET_ERRNO(ERROR_NETWORK, "Failed to receive mDNS query responses");
658 }
659
660 if (num_records > 0) {
661 log_debug("Processed %d mDNS records", num_records);
662 }
663
664 (void)timeout_ms;
665 return ASCIICHAT_OK;
666#endif
667}
#define NS_PER_MS_INT
Definition time.h:168

References asciichat_mdns_t::advertising, ASCIICHAT_OK, asciichat_mdns_t::buffer, asciichat_mdns_t::buffer_capacity, ERROR_INVALID_PARAM, ERROR_NETWORK, log_debug, NS_PER_MS_INT, asciichat_mdns_t::query_id, SET_ERRNO, and asciichat_mdns_t::socket_fd.

Referenced by discovery_mdns_query().