Added generic DNS SRV resolution in pjlib-util

git-svn-id: https://svn.pjsip.org/repos/pjproject/trunk@1102 74dad513-b988-da41-8d7b-12977e46ad98
diff --git a/pjsip/build/test_pjsip.dsp b/pjsip/build/test_pjsip.dsp
index 2781445..aa7de06 100644
--- a/pjsip/build/test_pjsip.dsp
+++ b/pjsip/build/test_pjsip.dsp
@@ -42,7 +42,7 @@
 # PROP Ignore_Export_Lib 0

 # PROP Target_Dir ""

 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c

-# ADD CPP /nologo /MD /W3 /Zi /O2 /Ob2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "PJ_WIN32" /D "PJ_M_I386" /FR /FD /c

+# ADD CPP /nologo /MD /W3 /Zi /O2 /Ob2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjnath/include" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /D "PJ_WIN32" /D "PJ_M_I386" /FR /FD /c

 # SUBTRACT CPP /YX

 # ADD BASE RSC /l 0x409 /d "NDEBUG"

 # ADD RSC /l 0x409 /d "NDEBUG"

@@ -67,7 +67,7 @@
 # PROP Ignore_Export_Lib 0

 # PROP Target_Dir ""

 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c

-# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "PJ_WIN32" /D "PJ_M_I386" /FR /FD /GZ /c

+# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /I "../../pjnath/include" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /D "PJ_WIN32" /D "PJ_M_I386" /FR /FD /GZ /c

 # SUBTRACT CPP /YX

 # ADD BASE RSC /l 0x409 /d "_DEBUG"

 # ADD RSC /l 0x409 /d "_DEBUG"

diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h
index fcd0549..fee08d3 100644
--- a/pjsip/include/pjsua-lib/pjsua.h
+++ b/pjsip/include/pjsua-lib/pjsua.h
@@ -903,12 +903,24 @@
     pj_str_t	    outbound_proxy[4];
 
     /**
-     * Specify STUN server. This server will be first resolved with DNS SRV
-     * to get the actual server address. If DNS SRV resolution failed, or
-     * when nameserver is not configured, the server will be resolved using
-     * DNS A resolution (i.e. gethostbyname()).
+     * Specify domain name to be resolved with DNS SRV resolution to get the
+     * address of the STUN servers. Alternatively application may specify
+     * \a stun_host and \a stun_relay_host instead.
+     *
+     * If DNS SRV resolution failed for this domain, then DNS A resolution
+     * will be performed only if \a stun_host is specified.
      */
-    pj_str_t	    stun_srv;
+    pj_str_t	    stun_domain;
+
+    /**
+     * Specify STUN server to be used.
+     */
+    pj_str_t	    stun_host;
+
+    /**
+     * Specify STUN relay server to be used.
+     */
+    pj_str_t	    stun_relay_host;
 
     /** 
      * Number of credentials in the credential array.
@@ -1009,7 +1021,9 @@
     }
 
     pj_strdup_with_null(pool, &dst->user_agent, &src->user_agent);
-    pj_strdup_with_null(pool, &dst->stun_srv, &src->stun_srv);
+    pj_strdup_with_null(pool, &dst->stun_domain, &src->stun_domain);
+    pj_strdup_with_null(pool, &dst->stun_host, &src->stun_host);
+    pj_strdup_with_null(pool, &dst->stun_relay_host, &src->stun_relay_host);
 }
 
 
diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c
index fba772b..d01a02b 100644
--- a/pjsip/src/pjsua-lib/pjsua_core.c
+++ b/pjsip/src/pjsua-lib/pjsua_core.c
@@ -652,6 +652,75 @@
     } while (PJ_TIME_VAL_LT(now, timeout));
 }
 
+
+static pj_status_t resolve_stun_server(pj_bool_t use_dns_srv);
+
+/*
+ * Callback function to receive notification from the resolver
+ * when the resolution process completes.
+ */
+static void stun_dns_srv_resolver_cb(void *user_data,
+				     pj_status_t status,
+				     const pj_dns_srv_record *rec)
+{
+    unsigned i;
+
+    PJ_UNUSED_ARG(user_data);
+
+    pjsua_var.stun_status = status;
+    
+    if (status != PJ_SUCCESS) {
+	/* DNS SRV resolution failed. If stun_host is specified, resolve
+	 * it with gethostbyname()
+	 */
+	if (pjsua_var.ua_cfg.stun_host.slen) {
+	    pj_hostent he;
+
+	    pjsua_var.stun_status = pj_gethostbyname(&pjsua_var.ua_cfg.stun_host, &he);
+
+	    if (pjsua_var.stun_status == PJ_SUCCESS) {
+		pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 0);
+		pjsua_var.stun_srv.ipv4.sin_addr = *(pj_in_addr*)he.h_addr;
+		pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)3478);
+
+		PJ_LOG(3,(THIS_FILE, 
+			  "STUN server %.*s resolved, address is %s:%d",
+			  (int)pjsua_var.ua_cfg.stun_host.slen,
+			  pjsua_var.ua_cfg.stun_host.ptr,
+			  pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr),
+			  (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port)));
+	    }
+	} else {
+	    char errmsg[PJ_ERR_MSG_SIZE];
+
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    PJ_LOG(1,(THIS_FILE, 
+		     "DNS SRV resolution failed for STUN server %.*s: %s",
+		     (int)pjsua_var.ua_cfg.stun_domain.slen,
+		     pjsua_var.ua_cfg.stun_domain.ptr,
+		     errmsg));
+	}
+	return;
+    }
+
+    pj_memcpy(&pjsua_var.stun_srv, &rec->entry[0].addr, 
+	      rec->entry[0].addr_len);
+
+    PJ_LOG(3,(THIS_FILE, "_stun._udp.%.*s resolved, found %d entry(s):",
+	      (int)pjsua_var.ua_cfg.stun_domain.slen,
+	      pjsua_var.ua_cfg.stun_domain.ptr,
+	      rec->count));
+
+    for (i=0; i<rec->count; ++i) {
+	PJ_LOG(3,(THIS_FILE, 
+		  " %d: prio=%d, weight=%d  %s:%d", 
+		  i, rec->entry[i].priority, rec->entry[i].weight,
+		  pj_inet_ntoa(rec->entry[i].addr.ipv4.sin_addr),
+		  (int)pj_ntohs(rec->entry[i].addr.ipv4.sin_port)));
+    }
+
+}
+
 /*
  * Resolve STUN server.
  */
@@ -664,37 +733,73 @@
 			    pjsip_endpt_get_timer_heap(pjsua_var.endpt));
 
 	/* Start STUN server resolution */
-	/* For now just do DNS A resolution */
+	
+	pjsua_var.stun_status = PJ_EPENDING;
 
-	if (pjsua_var.ua_cfg.stun_srv.slen == 0) {
-	    pjsua_var.stun_status = PJ_SUCCESS;
-	} else {
+	/* If stun_domain is specified, resolve STUN servers with DNS
+	 * SRV resolution.
+	 */
+	if (pjsua_var.ua_cfg.stun_domain.slen) {
+	    pj_str_t res_type;
+
+	    /* Fail if resolver is not configured */
+	    if (pjsua_var.resolver == NULL) {
+		PJ_LOG(1,(THIS_FILE, "Nameserver must be configured when "
+				     "stun_domain is specified"));
+		pjsua_var.stun_status = PJLIB_UTIL_EDNSNONS;
+		return PJLIB_UTIL_EDNSNONS;
+	    }
+	    res_type = pj_str("_stun._udp");
+	    pjsua_var.stun_status = 
+		pj_dns_srv_resolve(&pjsua_var.ua_cfg.stun_domain, &res_type,
+				   3478, pjsua_var.pool, pjsua_var.resolver,
+				   0, NULL, stun_dns_srv_resolver_cb);
+	    if (pjsua_var.stun_status != PJ_SUCCESS) {
+		pjsua_perror(THIS_FILE, "Error starting DNS SRV resolution", 
+			     pjsua_var.stun_status);
+		return pjsua_var.stun_status;
+	    }
+	}
+	/* Otherwise if stun_host is specified, resolve STUN server with
+	 * gethostbyname().
+	 */
+	else if (pjsua_var.ua_cfg.stun_host.slen) {
 	    pj_hostent he;
 
-	    pjsua_var.stun_status = 
-		pj_gethostbyname(&pjsua_var.ua_cfg.stun_srv, &he);
+	    pjsua_var.stun_status = pj_gethostbyname(&pjsua_var.ua_cfg.stun_host, &he);
 
 	    if (pjsua_var.stun_status == PJ_SUCCESS) {
 		pj_sockaddr_in_init(&pjsua_var.stun_srv.ipv4, NULL, 0);
 		pjsua_var.stun_srv.ipv4.sin_addr = *(pj_in_addr*)he.h_addr;
 		pjsua_var.stun_srv.ipv4.sin_port = pj_htons((pj_uint16_t)3478);
 
-		PJ_LOG(4,(THIS_FILE, 
+		PJ_LOG(3,(THIS_FILE, 
 			  "STUN server %.*s resolved, address is %s:%d",
-			  (int)pjsua_var.ua_cfg.stun_srv.slen,
-			  pjsua_var.ua_cfg.stun_srv.ptr,
+			  (int)pjsua_var.ua_cfg.stun_host.slen,
+			  pjsua_var.ua_cfg.stun_host.ptr,
 			  pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr),
 			  (int)pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port)));
 	    }
+
 	}
+	/* Otherwise disable STUN. */
+	else {
+	    pjsua_var.stun_status = PJ_SUCCESS;
+	}
+
+
 	return pjsua_var.stun_status;
 
     } else if (pjsua_var.stun_status == PJ_EPENDING) {
 	/* STUN server resolution has been started, wait for the
 	 * result.
 	 */
-	pj_assert(!"Should not happen");
-	return PJ_EBUG;
+	if (wait) {
+	    while (pjsua_var.stun_status == PJ_EPENDING)
+		pjsua_handle_events(10);
+	}
+
+	return pjsua_var.stun_status;
 
     } else {
 	/* STUN server has been resolved, return the status */
@@ -946,7 +1051,7 @@
 					 &stun_srv, 3478,
 				         p_pub_addr);
 	if (status != PJ_SUCCESS) {
-	    pjsua_perror(THIS_FILE, "Error resolving with STUN", status);
+	    pjsua_perror(THIS_FILE, "Error contacting STUN server", status);
 	    pj_sock_close(sock);
 	    return status;
 	}