diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index 769cb4b3b..458ea3790 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -1581,6 +1581,11 @@ typedef struct pjsua_config * STUN servers. If this is set to PJ_FALSE, the library will refuse to * start if it fails to resolve or contact any of the STUN servers. * + * This setting will also determine what happens if STUN servers are + * unavailable during runtime (if set to PJ_FALSE, calls will + * directly fail, otherwise (if PJ_TRUE) call medias will + * fallback to proceed as though not using STUN servers. + * * Default: PJ_TRUE */ pj_bool_t stun_ignore_failure; @@ -2084,6 +2089,30 @@ PJ_DECL(pj_status_t) pjsua_detect_nat_type(void); PJ_DECL(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type); +/** + * Update the STUN servers list. The #pjsua_init() must have been called + * before calling this function. + * + * @param count Number of STUN server entries. + * @param srv Array of STUN server entries to try. Please see + * the \a stun_srv field in the #pjsua_config + * documentation about the format of this entry. + * @param wait Specify non-zero to make the function block until + * it gets the result. In this case, the function + * will block while the resolution is being done, + * and the callback will be called before this function + * returns. + * + * @return If \a wait parameter is non-zero, this will return + * PJ_SUCCESS if one usable STUN server is found. + * Otherwise it will always return PJ_SUCCESS, and + * application will be notified about the result in + * the callback #on_stun_resolution_complete. + */ +PJ_DECL(pj_status_t) pjsua_update_stun_servers(unsigned count, pj_str_t srv[], + pj_bool_t wait); + + /** * Auxiliary function to resolve and contact each of the STUN server * entries (sequentially) to find which is usable. The #pjsua_init() must @@ -2722,7 +2751,16 @@ typedef enum pjsua_stun_use * Disable STUN. If STUN is not enabled in the global \a pjsua_config, * this setting has no effect. */ - PJSUA_STUN_USE_DISABLED + PJSUA_STUN_USE_DISABLED, + + /** + * Retry other STUN servers if the STUN server selected during + * startup (#pjsua_init()) or after calling #pjsua_update_stun_servers() + * is unavailable during runtime. This setting is valid only for + * account's media STUN setting and if the call is using UDP media + * transport. + */ + PJSUA_STUN_RETRY_ON_FAILURE } pjsua_stun_use; diff --git a/pjsip/include/pjsua2/endpoint.hpp b/pjsip/include/pjsua2/endpoint.hpp index 09149c701..e16da9083 100644 --- a/pjsip/include/pjsua2/endpoint.hpp +++ b/pjsip/include/pjsua2/endpoint.hpp @@ -903,6 +903,32 @@ public: */ pj_stun_nat_type natGetType() throw(Error); + /** + * Update the STUN servers list. The libInit() must have been called + * before calling this function. + * + * @param prmServers Array of STUN servers to try. The endpoint + * will try to resolve and contact each of the + * STUN server entry until it finds one that is + * usable. Each entry may be a domain name, host + * name, IP address, and it may contain an + * optional port number. For example: + * - "pjsip.org" (domain name) + * - "sip.pjsip.org" (host name) + * - "pjsip.org:33478" (domain name and a non- + * standard port number) + * - "10.0.0.1:3478" (IP address and port number) + * @param prmWait Specify if the function should block until + * it gets the result. In this case, the + * function will block while the resolution + * is being done, and the callback + * onNatCheckStunServersComplete() will be called + * before this function returns. + * + */ + void natUpdateStunServers(const StringVector &prmServers, + bool prmWait) throw(Error); + /** * Auxiliary function to resolve and contact each of the STUN server * entries (sequentially) to find which is usable. The libInit() must @@ -1189,7 +1215,7 @@ public: /** * Callback when the Endpoint has finished performing STUN server * checking that is initiated when calling libInit(), or by - * calling natCheckStunServers(). + * calling natCheckStunServers() or natUpdateStunServers(). * * @param prm Callback parameters. */ diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 55e7ef102..45918bd7f 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -1375,6 +1375,36 @@ on_return: } +/* + * Update STUN servers. + */ +PJ_DEF(pj_status_t) pjsua_update_stun_servers(unsigned count, pj_str_t srv[], + pj_bool_t wait) +{ + unsigned i; + pj_status_t status; + + PJ_ASSERT_RETURN(count && srv, PJ_EINVAL); + + PJSUA_LOCK(); + + pjsua_var.ua_cfg.stun_srv_cnt = count; + for (i = 0; i < count; i++) { + if (pj_strcmp(&pjsua_var.ua_cfg.stun_srv[i], &srv[i])) + pj_strdup(pjsua_var.pool, &pjsua_var.ua_cfg.stun_srv[i], &srv[i]); + } + pjsua_var.stun_status = PJ_EUNKNOWN; + + status = resolve_stun_server(wait); + if (wait == PJ_FALSE && status == PJ_EPENDING) + status = PJ_SUCCESS; + + PJSUA_UNLOCK(); + + return status; +} + + /* * Resolve STUN server. */ @@ -1481,6 +1511,7 @@ static void internal_stun_resolve_cb(const pj_stun_resolve_result *result) /* Perform NAT type detection if not yet */ if (pjsua_var.nat_type == PJ_STUN_NAT_TYPE_UNKNOWN && + !pjsua_var.nat_in_progress && pjsua_var.ua_cfg.nat_type_in_sdp) { pjsua_detect_nat_type(); diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 37f815724..7a8404c86 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -389,6 +389,33 @@ static pj_status_t create_rtp_rtcp_sock(pjsua_call_media *call_med, } else #endif + + if (status != PJ_SUCCESS && pjsua_var.ua_cfg.stun_srv_cnt > 1 && + ((acc->cfg.media_stun_use & PJSUA_STUN_RETRY_ON_FAILURE)!=0)) + { + PJ_LOG(4,(THIS_FILE, "Failed to get STUN mapped address, " + "retrying other STUN servers")); + status=pjsua_update_stun_servers(pjsua_var.ua_cfg.stun_srv_cnt, + pjsua_var.ua_cfg.stun_srv, + PJ_TRUE); + if (status == PJ_SUCCESS) { + if (pjsua_var.stun_srv.addr.sa_family != 0) { + pj_ansi_strcpy(ip_addr, + pj_inet_ntoa(pjsua_var.stun_srv.ipv4.sin_addr)); + stun_srv = pj_str(ip_addr); + } else { + stun_srv.slen = 0; + } + + stun_opt.srv1 = stun_opt.srv2 = stun_srv; + stun_opt.port1 = stun_opt.port2 = + pj_ntohs(pjsua_var.stun_srv.ipv4.sin_port); + status = pjstun_get_mapped_addr2(&pjsua_var.cp.factory, + &stun_opt, 2, sock, + resolved_addr); + } + } + if (status != PJ_SUCCESS) { if (!pjsua_var.ua_cfg.stun_ignore_failure) { pjsua_perror(THIS_FILE, "STUN resolve error", status); diff --git a/pjsip/src/pjsua2/endpoint.cpp b/pjsip/src/pjsua2/endpoint.cpp index d089b0c97..077190ec6 100644 --- a/pjsip/src/pjsua2/endpoint.cpp +++ b/pjsip/src/pjsua2/endpoint.cpp @@ -1561,6 +1561,21 @@ pj_stun_nat_type Endpoint::natGetType() throw(Error) return type; } +void Endpoint::natUpdateStunServers(const StringVector &servers, + bool wait) throw(Error) +{ + pj_str_t srv[MAX_STUN_SERVERS]; + unsigned i, count = 0; + + for (i=0; i