9#include <ascii-chat/network/mdns/mdns.h>
10#include <ascii-chat/common.h>
11#include <ascii-chat/platform/socket.h>
14#include <ascii-chat-deps/mdns/mdns.h>
19#include <netinet/in.h>
33#define MDNS_BUFFER_SIZE (4 * 1024)
38 SET_ERRNO(ERROR_MEMORY,
"Failed to allocate mDNS context");
48 SET_ERRNO(ERROR_MEMORY,
"Failed to allocate mDNS buffer");
54 mdns->
socket_fd = mdns_socket_open_ipv4(NULL);
58 SET_ERRNO(ERROR_NETWORK_BIND,
"Failed to open mDNS socket");
77 log_debug(
"mDNS context shutdown");
81 if (!mdns || !service) {
82 return SET_ERRNO(ERROR_INVALID_PARAM,
"mDNS context or service is NULL");
85 if (!service->name || !service->type || !service->host) {
86 return SET_ERRNO(ERROR_INVALID_PARAM,
"Service name, type, or host is NULL");
89 log_debug(
"Advertising mDNS service: %s (%s:%d)", service->name, service->host, service->port);
99 if (!mdns || !service_name) {
100 return SET_ERRNO(ERROR_INVALID_PARAM,
"mDNS context or service name is NULL");
103 log_info(
"Stopped advertising service: %s", service_name);
117static int mdns_record_callback(
int sock,
const struct sockaddr *from,
size_t addrlen, mdns_entry_type_t entry,
118 uint16_t query_id, uint16_t rtype, uint16_t rclass, uint32_t ttl,
const void *data,
119 size_t size,
size_t name_offset,
size_t name_length,
size_t record_offset,
120 size_t record_length,
void *user_data) {
128 if (entry != MDNS_ENTRYTYPE_ANSWER) {
132 asciichat_mdns_discovery_t discovery;
133 memset(&discovery, 0,
sizeof(discovery));
139 size_t offset = name_offset;
140 mdns_string_extract(data, size, &offset, discovery.type,
sizeof(discovery.type));
144 case MDNS_RECORDTYPE_PTR: {
148 offset = record_offset;
149 mdns_string_extract(data, size, &offset, discovery.name,
sizeof(discovery.name));
150 log_debug(
"mDNS PTR: %s -> %s (TTL: %u)", discovery.type, discovery.name, ttl);
154 case MDNS_RECORDTYPE_SRV: {
159 mdns_record_srv_t srv =
160 mdns_record_parse_srv(data, size, record_offset, record_length, discovery.host,
sizeof(discovery.host));
161 discovery.port = srv.port;
162 log_debug(
"mDNS SRV: %s -> %s:%u (TTL: %u)", discovery.type, discovery.host, srv.port, ttl);
166 case MDNS_RECORDTYPE_A: {
170 struct sockaddr_in addr_in;
171 mdns_record_parse_a(data, size, record_offset, record_length, &addr_in);
174 uint8_t *bytes = (uint8_t *)&addr_in.sin_addr;
175 safe_snprintf(discovery.ipv4,
sizeof(discovery.ipv4),
"%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
176 log_debug(
"mDNS A: %s -> %s (TTL: %u)", discovery.type, discovery.ipv4, ttl);
180 case MDNS_RECORDTYPE_AAAA: {
184 struct sockaddr_in6 addr_in6;
185 mdns_record_parse_aaaa(data, size, record_offset, record_length, &addr_in6);
188 const uint8_t *bytes = (
const uint8_t *)&addr_in6.sin6_addr;
190 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x", bytes[0], bytes[1],
191 bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], bytes[8], bytes[9], bytes[10], bytes[11],
192 bytes[12], bytes[13], bytes[14], bytes[15]);
193 log_debug(
"mDNS AAAA: %s -> %s (TTL: %u)", discovery.type, discovery.ipv6, ttl);
197 case MDNS_RECORDTYPE_TXT: {
202 log_debug(
"mDNS TXT: %s (TTL: %u)", discovery.type, ttl);
203 discovery.txt[0] =
'\0';
208 log_debug(
"mDNS unknown record type: %u", rtype);
225 asciichat_mdns_discovery_callback_fn callback,
void *user_data) {
226 if (!mdns || !service_type || !callback) {
227 return SET_ERRNO(ERROR_INVALID_PARAM,
"Invalid mDNS query parameters");
233 size_t service_type_len = strlen(service_type);
234 if (service_type_len == 0) {
235 return SET_ERRNO(ERROR_INVALID_PARAM,
"Service type cannot be empty");
241 log_info(
"Starting mDNS query for: %s", service_type);
247 int query_id = mdns_query_send(mdns->
socket_fd, MDNS_RECORDTYPE_PTR, service_type, service_type_len, mdns->
buffer,
251 return SET_ERRNO(ERROR_NETWORK,
"mDNS query send failed for %s (query_id=%d)", service_type, query_id);
254 mdns->
query_id = (uint16_t)query_id;
255 log_debug(
"mDNS query sent for service type: %s (query_id: %d)", service_type, query_id);
262 return SET_ERRNO(ERROR_INVALID_PARAM,
"mDNS context is NULL");
272 if (num_records < 0) {
273 return SET_ERRNO(ERROR_NETWORK,
"Failed to receive mDNS query responses");
276 if (num_records > 0) {
277 log_debug(
"Processed %d mDNS records", num_records);
asciichat_error_t asciichat_mdns_update(asciichat_mdns_t *mdns, int timeout_ms)
asciichat_error_t asciichat_mdns_unadvertise(asciichat_mdns_t *mdns, const char *service_name)
#define MDNS_BUFFER_SIZE
mDNS packet buffer size (4KB should handle most service records)
void asciichat_mdns_destroy(asciichat_mdns_t *mdns)
asciichat_mdns_t * asciichat_mdns_init(void)
int asciichat_mdns_get_socket(asciichat_mdns_t *mdns)
asciichat_error_t asciichat_mdns_query(asciichat_mdns_t *mdns, const char *service_type, asciichat_mdns_discovery_callback_fn callback, void *user_data)
asciichat_error_t asciichat_mdns_advertise(asciichat_mdns_t *mdns, const asciichat_mdns_service_t *service)
Internal mDNS context structure.
asciichat_mdns_discovery_callback_fn callback
int safe_snprintf(char *buffer, size_t buffer_size, const char *format,...)
Safe formatted string printing to buffer.