From 653cbf8834e33d9b9cda3714d23f78d37f220d35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Micka=C3=ABl=20Turnel?=
 <mickael.turnel@belledonne-communications.com>
Date: Wed, 10 Jan 2018 10:23:14 +0100
Subject: [PATCH] Add multicast DNS resolver implementation

---
 include/belle-sip/types.h |   1 +
 src/belle_sip_internal.h  |   3 +
 src/belle_sip_resolver.c  | 297 ++++++++++++++++++++++++++++++++------
 3 files changed, 255 insertions(+), 46 deletions(-)

diff --git a/include/belle-sip/types.h b/include/belle-sip/types.h
index bb1225c7..a50eeda1 100644
--- a/include/belle-sip/types.h
+++ b/include/belle-sip/types.h
@@ -51,6 +51,7 @@ BELLE_SIP_DECLARE_TYPES_BEGIN(belle_sip,1)
 	BELLE_SIP_TYPE_ID(belle_sip_provider_t),
 	BELLE_SIP_TYPE_ID(belle_sip_main_loop_t),
 	BELLE_SIP_TYPE_ID(belle_sip_source_t),
+	BELLE_SIP_TYPE_ID(belle_sip_mdns_resolve_source_t),
 	BELLE_SIP_TYPE_ID(belle_sip_resolver_context_t),
 	BELLE_SIP_TYPE_ID(belle_sip_transaction_t),
 	BELLE_SIP_TYPE_ID(belle_sip_server_transaction_t),
diff --git a/src/belle_sip_internal.h b/src/belle_sip_internal.h
index db6d5258..3e513091 100644
--- a/src/belle_sip_internal.h
+++ b/src/belle_sip_internal.h
@@ -149,6 +149,9 @@ BELLE_SIP_DECLARE_VPTR(belle_sip_datagram_listening_point_t);
 BELLE_SIP_DECLARE_VPTR(belle_sip_provider_t);
 BELLE_SIP_DECLARE_VPTR(belle_sip_main_loop_t);
 BELLE_SIP_DECLARE_VPTR(belle_sip_source_t);
+#ifdef HAVE_MDNS
+BELLE_SIP_DECLARE_VPTR(belle_sip_mdns_resolve_source_t);
+#endif
 BELLE_SIP_DECLARE_VPTR(belle_sip_dialog_t);
 BELLE_SIP_DECLARE_VPTR(belle_sip_header_address_t);
 BELLE_SIP_DECLARE_VPTR(belle_sip_header_contact_t);
diff --git a/src/belle_sip_resolver.c b/src/belle_sip_resolver.c
index a68a63da..ce9096a4 100644
--- a/src/belle_sip_resolver.c
+++ b/src/belle_sip_resolver.c
@@ -20,6 +20,9 @@
 #include "dns.h"
 #include <bctoolbox/defs.h>
 
+#ifdef HAVE_MDNS
+#include <dns_sd.h>
+#endif
 #include <stdlib.h>
 #include <stdint.h>
 #ifdef __APPLE__
@@ -72,15 +75,19 @@ static void belle_sip_dns_srv_destroy(belle_sip_dns_srv_t *obj){
 	}
 }
 
-belle_sip_dns_srv_t *belle_sip_dns_srv_create(struct dns_srv *srv){
+belle_sip_dns_srv_t *belle_sip_dns_srv_create_raw(short unsigned int priority, short unsigned int weight, short unsigned int port, const char *target){
 	belle_sip_dns_srv_t *obj=belle_sip_object_new(belle_sip_dns_srv_t);
-	obj->priority=srv->priority;
-	obj->weight=srv->weight;
-	obj->port=srv->port;
-	obj->target=belle_sip_strdup(srv->target);
+	obj->priority=priority;
+	obj->weight=weight;
+	obj->port=port;
+	obj->target=belle_sip_strdup(target);
 	return obj;
 }
 
+belle_sip_dns_srv_t *belle_sip_dns_srv_create(struct dns_srv *srv){
+	return belle_sip_dns_srv_create_raw(srv->priority, srv->weight, srv->port, srv->target);
+}
+
 const char *belle_sip_dns_srv_get_target(const belle_sip_dns_srv_t *obj){
 	return obj->target;
 }
@@ -127,7 +134,12 @@ struct belle_sip_simple_resolver_context{
 	int family;
 	int flags;
 	uint64_t start_time;
-#ifdef USE_GETADDRINFO_FALLBACK
+#ifdef HAVE_MDNS
+	char *srv_prefix;
+	char *srv_name;
+	int resolving;
+#endif
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 	struct addrinfo *getaddrinfo_ai_list;
 	belle_sip_source_t *getaddrinfo_source;
 	belle_sip_thread_t getaddrinfo_thread;
@@ -328,6 +340,16 @@ static int srv_compare_prio(const void *psrv1, const void *psrv2){
 	return 1;
 }
 
+static int srv_compare_host_and_port(const void *psrv1, const void *psrv2){
+	belle_sip_dns_srv_t *srv1=(belle_sip_dns_srv_t*)psrv1;
+	belle_sip_dns_srv_t *srv2=(belle_sip_dns_srv_t*)psrv2;
+	int ret = strcmp(srv1->target, srv2->target);
+	if (ret != 0) return ret;
+	if (srv1->port < srv2->port) return -1;
+	if (srv1->port == srv2->port) return 0;
+	return 1;
+}
+
 /*
  * see https://www.ietf.org/rfc/rfc2782.txt
  * 0 weighted must just appear first.
@@ -418,7 +440,7 @@ static void simple_resolver_context_notify(belle_sip_resolver_context_t *obj) {
 	belle_sip_simple_resolver_context_t *ctx = BELLE_SIP_SIMPLE_RESOLVER_CONTEXT(obj);
 	if ((ctx->type == DNS_T_A) || (ctx->type == DNS_T_AAAA)) {
 		struct addrinfo **ai_list = &ctx->ai_list;
-#if USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 		if (ctx->getaddrinfo_ai_list != NULL) ai_list = &ctx->getaddrinfo_ai_list;
 #endif
 		ctx->cb(ctx->cb_data, ctx->name, *ai_list, BELLE_SIP_RESOLVER_CONTEXT(obj)->min_ttl);
@@ -540,7 +562,7 @@ static int resolver_process_data(belle_sip_simple_resolver_context_t *ctx, unsig
 			}
 		}
 		free(ans);
-#ifdef USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 		ctx->getaddrinfo_cancelled = TRUE;
 #endif
 		if (dns_res_was_asymetric(ctx->R)){
@@ -551,7 +573,7 @@ static int resolver_process_data(belle_sip_simple_resolver_context_t *ctx, unsig
 	}
 	if (error != DNS_EAGAIN) {
 		belle_sip_error("%s dns_res_check() error: %s (%d)", __FUNCTION__, dns_strerror(error), error);
-#ifdef USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 		if (ctx->getaddrinfo_done) {
 			return BELLE_SIP_STOP;
 		} else {
@@ -563,7 +585,7 @@ static int resolver_process_data(belle_sip_simple_resolver_context_t *ctx, unsig
 		return BELLE_SIP_STOP;
 #endif
 	} else {
-#ifdef USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 		if (ctx->getaddrinfo_done) {
 			return BELLE_SIP_STOP;
 		} else
@@ -575,7 +597,7 @@ static int resolver_process_data(belle_sip_simple_resolver_context_t *ctx, unsig
 	return BELLE_SIP_CONTINUE;
 }
 
-#ifdef USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 static void * _resolver_getaddrinfo_thread(void *ptr) {
 	belle_sip_simple_resolver_context_t *ctx = (belle_sip_simple_resolver_context_t *)ptr;
 	struct addrinfo *res = NULL;
@@ -587,6 +609,7 @@ static void * _resolver_getaddrinfo_thread(void *ptr) {
 	snprintf(serv, sizeof(serv), "%i", ctx->port);
 	hints.ai_family = ctx->family;
 	hints.ai_flags = AI_NUMERICSERV;
+	hints.ai_protocol = strstr(ctx->name, "udp") ? IPPROTO_UDP : IPPROTO_TCP;
 	err = getaddrinfo(ctx->name, serv, &hints, &res);
 	if (err != 0) {
 		belle_sip_error("getaddrinfo DNS resolution of %s failed: %s", ctx->name, gai_strerror(err));
@@ -629,7 +652,7 @@ static void _resolver_getaddrinfo_start(belle_sip_simple_resolver_context_t *ctx
 	}
 	fd = ctx->ctlpipe[0];
 #endif
-	belle_sip_thread_create(&ctx->getaddrinfo_thread, NULL, _resolver_getaddrinfo_thread, ctx);
+	bctbx_thread_create(&ctx->getaddrinfo_thread, NULL, _resolver_getaddrinfo_thread, ctx);
 	ctx->getaddrinfo_source = belle_sip_fd_source_new((belle_sip_source_func_t)_resolver_getaddrinfo_callback, ctx, fd, BELLE_SIP_EVENT_READ, -1);
 	belle_sip_main_loop_add_source(ctx->base.stack->ml, ctx->getaddrinfo_source);
 }
@@ -657,7 +680,7 @@ static int _resolver_send_query(belle_sip_simple_resolver_context_t *ctx) {
 		/*only init source if res inprogress*/
 		/*the timeout set to the source is 1 s, this is to allow dns.c to send request retransmissions*/
 		belle_sip_socket_source_init((belle_sip_source_t*)ctx, (belle_sip_source_func_t)resolver_process_data, ctx, dns_res_pollfd(ctx->R), BELLE_SIP_EVENT_READ | BELLE_SIP_EVENT_TIMEOUT, 1000);
-#ifdef USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 		{
 			int timeout = belle_sip_stack_get_dns_timeout(ctx->base.stack);
 			if ((timeout != 0) && ((ctx->type == DNS_T_A) || (ctx->type == DNS_T_AAAA))) {
@@ -676,43 +699,210 @@ static int resolver_process_data_delayed(belle_sip_simple_resolver_context_t *ct
 	return BELLE_SIP_STOP;
 }
 
+#ifdef HAVE_MDNS
+typedef struct belle_sip_mdns_resolve_source belle_sip_mdns_resolve_source_t;
+#define BELLE_SIP_MDNS_RESOLVE_SOURCE(obj) BELLE_SIP_CAST(obj,belle_sip_mdns_resolve_source_t)
+
+struct belle_sip_mdns_resolve_source {
+	belle_sip_source_t base;
+	DNSServiceRef service_ref;
+	belle_sip_simple_resolver_context_t *ctx;
+};
+
+belle_sip_mdns_resolve_source_t *belle_sip_mdns_resolve_source_new(DNSServiceRef service_ref, belle_sip_simple_resolver_context_t *ctx, belle_sip_source_func_t func) {
+	belle_sip_mdns_resolve_source_t *obj = belle_sip_object_new(belle_sip_mdns_resolve_source_t);
+	obj->service_ref = service_ref;
+	obj->ctx = ctx;
+	belle_sip_fd_source_init((belle_sip_source_t*)obj
+							, func
+							, obj
+							, DNSServiceRefSockFD(service_ref)
+							, BELLE_SIP_EVENT_READ | BELLE_SIP_EVENT_TIMEOUT
+							, 1000);
+	return obj;
+}
+
+BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sip_mdns_resolve_source_t);
+BELLE_SIP_INSTANCIATE_VPTR(belle_sip_mdns_resolve_source_t, belle_sip_source_t, NULL, NULL, NULL, TRUE);
+
+static void resolver_process_mdns_resolve(DNSServiceRef service_ref
+										, DNSServiceFlags flags
+										, uint32_t interface
+										, DNSServiceErrorType error_code
+										, const char *fullname
+										, const char *hosttarget
+										, uint16_t port
+										, uint16_t txt_len
+										, const unsigned char *txt_record
+										, belle_sip_simple_resolver_context_t *ctx) {
+	if (error_code != kDNSServiceErr_NoError) {
+		belle_sip_error("%s error while resolving [%s]: code %d", __FUNCTION__, ctx->name, error_code);
+	} else {
+		uint8_t prio_size, weight_size;
+
+		const char *prio_buf = TXTRecordGetValuePtr(txt_len, txt_record, "prio", &prio_size);
+		const char *weight_buf = TXTRecordGetValuePtr(txt_len, txt_record, "weight", &weight_size);
+
+		/* If the buffer is non-NULL then the key exist and if the result size is > 0 then the value is not empty */
+		if (prio_buf && prio_size > 0 && weight_buf && weight_size > 0) {
+			short unsigned int prio, weight;
+
+			/* Don't use the VLAs since it doesn't work on Windows */
+			char *prio_value = belle_sip_malloc(prio_size + 1);
+			char *weight_value = belle_sip_malloc(weight_size + 1);
+
+			memcpy(prio_value, prio_buf, prio_size);
+			memcpy(weight_value, weight_buf, weight_size);
+
+			prio_value[prio_size] = '\0';
+			weight_value[weight_size] = '\0';
+
+			prio = atoi(prio_value);
+			weight = atoi(weight_value);
+
+			belle_sip_dns_srv_t *b_srv = belle_sip_dns_srv_create_raw(prio, weight, port, hosttarget);
+			if (!belle_sip_list_find_custom(ctx->srv_list, srv_compare_host_and_port, b_srv))
+				ctx->srv_list = belle_sip_list_insert_sorted(ctx->srv_list, belle_sip_object_ref(b_srv), srv_compare_prio);
+			else
+				belle_sip_dns_srv_destroy(b_srv);
+
+			belle_sip_free(prio_value);
+			belle_sip_free(weight_value);
+
+			belle_sip_message("mDNS %s resolved to [target:%s port:%d prio:%d weight:%d]", ctx->name, hosttarget, port, prio, weight);
+		} else {
+			belle_sip_warning("%s TXT record of %s does not contain a priority or weight key!", __FUNCTION__, hosttarget);
+		}
+	}
+}
+
+static int resolver_process_mdns_resolve_result(belle_sip_mdns_resolve_source_t *source, unsigned int revents) {
+	if (revents & BELLE_SIP_EVENT_READ) {
+		DNSServiceProcessResult(source->service_ref);
+	}
+
+	if (revents & BELLE_SIP_EVENT_TIMEOUT) {
+		source->ctx->resolving--;
+
+		/* There is no resolve left, we can notify */
+		if (source->ctx->resolving == 0) {
+			belle_sip_resolver_context_notify(BELLE_SIP_RESOLVER_CONTEXT(source->ctx));
+		}
+
+		DNSServiceRefDeallocate(source->service_ref);
+		return BELLE_SIP_STOP;
+	}
+	return BELLE_SIP_CONTINUE;
+}
+
+static void resolver_process_mdns_browse(DNSServiceRef service_ref
+										, DNSServiceFlags flags
+										, uint32_t interface
+										, DNSServiceErrorType error_code
+										, const char *name
+										, const char *type
+										, const char *domain
+										, belle_sip_simple_resolver_context_t *ctx) {
+	if (error_code != kDNSServiceErr_NoError) {
+		belle_sip_error("%s error while browing [%s]: code %d", __FUNCTION__, ctx->name, error_code);
+	} else {
+		DNSServiceRef resolve_ref;
+		DNSServiceErrorType error;
+
+		error = DNSServiceResolve(&resolve_ref, 0, interface, name, type, domain, (DNSServiceResolveReply)resolver_process_mdns_resolve, ctx);
+
+		if (error == kDNSServiceErr_NoError) {
+			ctx->resolving++;
+			belle_sip_mdns_resolve_source_t *source = belle_sip_mdns_resolve_source_new(resolve_ref, ctx, (belle_sip_source_func_t)resolver_process_mdns_resolve_result);
+			belle_sip_main_loop_add_source(ctx->base.stack->ml, (belle_sip_source_t*)source);
+		} else {
+			belle_sip_error("%s DNSServiceResolve error [%s]: code %d", __FUNCTION__, ctx->name, error);
+		}
+	}
+}
+
+static int resolver_process_mdns_browse_result(DNSServiceRef service_ref, unsigned int revents) {
+	if (revents & BELLE_SIP_EVENT_READ) {
+		DNSServiceProcessResult(service_ref);
+	}
+
+	if (revents & BELLE_SIP_EVENT_TIMEOUT) {
+		DNSServiceRefDeallocate(service_ref);
+		return BELLE_SIP_STOP;
+	}
+	return BELLE_SIP_CONTINUE;
+}
+#endif
+
 static int _resolver_start_query(belle_sip_simple_resolver_context_t *ctx) {
-	struct dns_options opts;
-	int error;
-	struct dns_resolv_conf *conf;
+#ifdef HAVE_MDNS
+	char *suffix;
 
 	if (!ctx->name) return -1;
 
-	conf=resconf(ctx);
-	if (conf){
-		conf->options.recurse = 0;
-		conf->options.timeout=2;
-		conf->options.attempts=5;
-	}else
-		return -1;
-	if (!hosts(ctx))
-		return -1;
+	/* Check if name ends with .local to determine if we'll use multicast DNS or not */
+	suffix = strrchr(ctx->name, '.');
 
-	memset(&opts, 0, sizeof opts);
-	
-	/* When there are IPv6 nameservers, allow responses to arrive from an IP address that is not the IP address to which the request was sent originally.
-		* Mac' NAT64 network tend to do this sometimes.*/
-	opts.udp_uses_connect = ctx->resconf->iface.ss_family != AF_INET6;
-	if (!opts.udp_uses_connect) belle_sip_message("Resolver is not using connect().");
+	if (suffix && strcmp(suffix, ".local") == 0 && ctx->type == DNS_T_SRV) {
+		DNSServiceErrorType error;
+		DNSServiceRef browse_ref;
 
-	if (!(ctx->R = dns_res_open(ctx->resconf, ctx->hosts, dns_hints_mortal(dns_hints_local(ctx->resconf, &error)), cache(ctx), &opts, &error))) {
-		belle_sip_error("%s dns_res_open error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error));
-		return -1;
-	}
-	error=0;
-	if (ctx->base.stack->resolver_tx_delay > 0) {
-		belle_sip_socket_source_init((belle_sip_source_t*)ctx, (belle_sip_source_func_t)resolver_process_data_delayed, ctx, -1, BELLE_SIP_EVENT_TIMEOUT, ctx->base.stack->resolver_tx_delay + 1000);
-		belle_sip_message("%s DNS resolution delayed by %d ms", __FUNCTION__, ctx->base.stack->resolver_tx_delay);
+		error = DNSServiceBrowse(&browse_ref, 0, 0, ctx->srv_prefix, ctx->srv_name, (DNSServiceBrowseReply)resolver_process_mdns_browse, ctx);
+
+		if (error == kDNSServiceErr_NoError) {
+			belle_sip_fd_source_init((belle_sip_source_t*)ctx
+									, (belle_sip_source_func_t)resolver_process_mdns_browse_result
+									, browse_ref
+									, DNSServiceRefSockFD(browse_ref)
+									, BELLE_SIP_EVENT_READ | BELLE_SIP_EVENT_TIMEOUT
+									, 1000);
+			belle_sip_main_loop_add_source(ctx->base.stack->ml, (belle_sip_source_t*)ctx);
+			return 0;
+		} else {
+			belle_sip_error("%s DNSServiceBrowse error [%s]: code %d", __FUNCTION__, ctx->name, error);
+			return -1;
+		}
 	} else {
-		error=_resolver_send_query(ctx);
+#endif
+		struct dns_options opts;
+		int error;
+		struct dns_resolv_conf *conf;
+
+		if (!ctx->name) return -1;
+
+		conf=resconf(ctx);
+		if (conf){
+			conf->options.recurse = 0;
+			conf->options.timeout=2;
+			conf->options.attempts=5;
+		}else
+			return -1;
+		if (!hosts(ctx))
+			return -1;
+
+		memset(&opts, 0, sizeof opts);
+		
+		/* When there are IPv6 nameservers, allow responses to arrive from an IP address that is not the IP address to which the request was sent originally.
+			* Mac' NAT64 network tend to do this sometimes.*/
+		opts.udp_uses_connect = ctx->resconf->iface.ss_family != AF_INET6;
+		if (!opts.udp_uses_connect) belle_sip_message("Resolver is not using connect().");
+
+		if (!(ctx->R = dns_res_open(ctx->resconf, ctx->hosts, dns_hints_mortal(dns_hints_local(ctx->resconf, &error)), cache(ctx), &opts, &error))) {
+			belle_sip_error("%s dns_res_open error [%s]: %s", __FUNCTION__, ctx->name, dns_strerror(error));
+			return -1;
+		}
+		error=0;
+		if (ctx->base.stack->resolver_tx_delay > 0) {
+			belle_sip_socket_source_init((belle_sip_source_t*)ctx, (belle_sip_source_func_t)resolver_process_data_delayed, ctx, -1, BELLE_SIP_EVENT_TIMEOUT, ctx->base.stack->resolver_tx_delay + 1000);
+			belle_sip_message("%s DNS resolution delayed by %d ms", __FUNCTION__, ctx->base.stack->resolver_tx_delay);
+		} else {
+			error=_resolver_send_query(ctx);
+		}
+		if (error==0 && !ctx->base.notified) belle_sip_main_loop_add_source(ctx->base.stack->ml,(belle_sip_source_t*)ctx);
+		return error;
+#ifdef HAVE_MDNS
 	}
-	if (error==0 && !ctx->base.notified) belle_sip_main_loop_add_source(ctx->base.stack->ml,(belle_sip_source_t*)ctx);
-	return error;
+#endif
 }
 
 static belle_sip_simple_resolver_context_t * resolver_start_query(belle_sip_simple_resolver_context_t *ctx) {
@@ -755,9 +945,9 @@ static void belle_sip_combined_resolver_context_destroy(belle_sip_combined_resol
 static void belle_sip_simple_resolver_context_destroy(belle_sip_simple_resolver_context_t *ctx){
 	/* Do not free elements of ctx->ai_list with bctbx_freeaddrinfo(). Let the caller do it, otherwise
 	   it will not be able to use them after the resolver has been destroyed. */
-#ifdef USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 	if (ctx->getaddrinfo_thread != 0) {
-		belle_sip_thread_join(ctx->getaddrinfo_thread, NULL);
+		bctbx_thread_join(ctx->getaddrinfo_thread, NULL);
 	}
 	if (ctx->getaddrinfo_source) belle_sip_object_unref(ctx->getaddrinfo_source);
 #ifdef _WIN32
@@ -773,7 +963,7 @@ static void belle_sip_simple_resolver_context_destroy(belle_sip_simple_resolver_
 		bctbx_freeaddrinfo(ctx->ai_list);
 		ctx->ai_list = NULL;
 	}
-#ifdef USE_GETADDRINFO_FALLBACK
+#if defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)
 	if (ctx->getaddrinfo_ai_list != NULL) {
 		bctbx_freeaddrinfo(ctx->getaddrinfo_ai_list);
 		ctx->getaddrinfo_ai_list = NULL;
@@ -795,6 +985,16 @@ static void belle_sip_simple_resolver_context_destroy(belle_sip_simple_resolver_
 		free(ctx->resconf);
 		ctx->resconf = NULL;
 	}
+#ifdef HAVE_MDNS
+	if (ctx->srv_prefix) {
+		belle_sip_free(ctx->srv_prefix);
+		ctx->srv_prefix = NULL;
+	}
+	if (ctx->srv_name) {
+		belle_sip_free(ctx->srv_name);
+		ctx->srv_name = NULL;
+	}
+#endif
 }
 
 static void belle_sip_dual_resolver_context_destroy(belle_sip_dual_resolver_context_t *obj){
@@ -1052,7 +1252,7 @@ static belle_sip_resolver_context_t * belle_sip_stack_resolve_single(belle_sip_s
 	if (family == 0) family = AF_UNSPEC;
 	ctx->family = family;
 	ctx->type = (ctx->family == AF_INET6) ? DNS_T_AAAA : DNS_T_A;
-#if defined(USE_GETADDRINFO_FALLBACK) && defined(_WIN32)
+#if (defined(USE_GETADDRINFO_FALLBACK) || defined(HAVE_MDNS)) && defined(_WIN32)
 	ctx->ctlevent = (belle_sip_fd_t)-1;
 #endif
 	return (belle_sip_resolver_context_t*)resolver_start_query(ctx);
@@ -1136,6 +1336,11 @@ belle_sip_resolver_context_t * belle_sip_stack_resolve_srv(belle_sip_stack_t *st
 	belle_sip_resolver_context_init((belle_sip_resolver_context_t*)ctx,stack);
 	ctx->srv_cb_data = data;
 	ctx->srv_cb = cb;
+#ifdef HAVE_MDNS
+	ctx->srv_prefix = belle_sip_strdup(srv_prefix);
+	ctx->srv_name = belle_sip_strdup(name);
+	ctx->resolving = 0;
+#endif
 	ctx->name = belle_sip_concat(srv_prefix, name, NULL);
 	ctx->type = DNS_T_SRV;
 	belle_sip_object_set_name((belle_sip_object_t*)ctx, ctx->name);
-- 
GitLab