From 5aea96f9de3908f2fc85c16001adc6c3f82d4705 Mon Sep 17 00:00:00 2001 From: Benny Prijono Date: Tue, 16 Oct 2007 01:34:14 +0000 Subject: More ticket #399: added callback to report NAT detection result, and sends NAT type in SDP git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@1501 74dad513-b988-da41-8d7b-12977e46ad98 --- pjsip/include/pjsua-lib/pjsua.h | 61 ++++++++++++++++++++++++++------ pjsip/include/pjsua-lib/pjsua_internal.h | 5 +++ pjsip/src/pjsua-lib/pjsua_core.c | 55 ++++++++++++++++++++++++---- pjsip/src/pjsua-lib/pjsua_media.c | 27 ++++++++++++++ 4 files changed, 131 insertions(+), 17 deletions(-) (limited to 'pjsip') diff --git a/pjsip/include/pjsua-lib/pjsua.h b/pjsip/include/pjsua-lib/pjsua.h index ea16d6b9..93aaefda 100644 --- a/pjsip/include/pjsua-lib/pjsua.h +++ b/pjsip/include/pjsua-lib/pjsua.h @@ -565,7 +565,9 @@ typedef struct pjsua_callback /** * Notify application when media state in the call has changed. * Normal application would need to implement this callback, e.g. - * to connect the call's media to sound device. + * to connect the call's media to sound device. When ICE is used, + * this callback will also be called to report ICE negotiation + * failure. * * @param call_id The call index. * @@ -891,6 +893,14 @@ typedef struct pjsua_callback const pj_str_t *to, const pj_str_t *contact, pj_bool_t is_typing); + /** + * Callback when the library has finished performing NAT type + * detection. + * + * @param res NAT detection result. + */ + void (*on_nat_detect)(const pj_stun_nat_detect_result *res); + } pjsua_callback; @@ -978,6 +988,17 @@ typedef struct pjsua_config */ pj_str_t stun_relay_host; + /** + * Include local endpoint's NAT type in the SDP to assist troubleshooting. + * The valid values are: + * - 0: no information will be added in SDP. + * - 1: only the NAT type number is added. + * - 2: add both NAT type number and name. + * + * Default: 2 + */ + int nat_type_in_sdp; + /** * Specify whether support for reliable provisional response (100rel and * PRACK) should be required by default. Note that this setting can be @@ -1315,19 +1336,37 @@ PJ_DECL(pj_pool_factory*) pjsua_get_pool_factory(void); /** * This is a utility function to detect NAT type in front of this * endpoint. Once invoked successfully, this function will complete - * asynchronously and report the result in the callback. + * asynchronously and report the result in \a on_nat_detect() callback + * of pjsua_callback. + * + * After NAT has been detected and the callback is called, application can + * get the detected NAT type by calling #pjsua_get_nat_type(). Application + * can also perform NAT detection by calling #pjsua_detect_nat_type() + * again at later time. + * + * Note that STUN must be enabled to run this function successfully. + * + * @return PJ_SUCCESS on success, or the appropriate error code. + */ +PJ_DECL(pj_status_t) pjsua_detect_nat_type(void); + + +/** + * Get the NAT type as detected by #pjsua_detect_nat_type() function. + * This function will only return useful NAT type after #pjsua_detect_nat_type() + * has completed successfully and \a on_nat_detect() callback has been called. * - * @param srv_port Optional STUN server and port, in "SERVER[:PORT]" - * format. If this option is NULL, the function will use - * the STUN server that has been set in the pjsua - * configuration. - * @param user_data User data to be returned back in the callback. - * @param cb Optional callback to report the detection result. + * @param type NAT type. * - * @return PJ_SUCCESS if detection is started successfully. + * @return When detection is in progress, this function will + * return PJ_EPENDING and \a type will be set to + * PJ_STUN_NAT_TYPE_UNKNOWN. After NAT type has been + * detected successfully, this function will return + * PJ_SUCCESS and \a type will be set to the correct + * value. Other return values indicate error and + * \a type will be set to PJ_STUN_NAT_TYPE_ERR_UNKNOWN. */ -PJ_DECL(pj_status_t) pjsua_detect_nat_type(void *user_data, - pj_stun_nat_detect_cb *cb); +PJ_DECL(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type); /** diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index a83e506a..53a978f4 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -194,6 +194,11 @@ struct pjsua_data pj_status_t stun_status; /**< STUN server status. */ pj_dns_resolver *resolver; /**< DNS resolver. */ + /* Detected NAT type */ + pj_stun_nat_type nat_type; /**< NAT type. */ + pj_status_t nat_status; /**< Detection status. */ + pj_bool_t nat_in_progress; /**< Detection in progress */ + /* Account: */ unsigned acc_cnt; /**< Number of accounts. */ pjsua_acc_id default_acc; /**< Default account ID */ diff --git a/pjsip/src/pjsua-lib/pjsua_core.c b/pjsip/src/pjsua-lib/pjsua_core.c index 321d3405..95ad7aa8 100644 --- a/pjsip/src/pjsua-lib/pjsua_core.c +++ b/pjsip/src/pjsua-lib/pjsua_core.c @@ -51,6 +51,7 @@ static void init_data() pjsua_var.tpdata[i].index = i; pjsua_var.stun_status = PJ_EUNKNOWN; + pjsua_var.nat_status = PJ_EPENDING; } @@ -79,6 +80,7 @@ PJ_DEF(void) pjsua_config_default(pjsua_config *cfg) cfg->max_calls = 4; cfg->thread_cnt = 1; + cfg->nat_type_in_sdp = 2; } PJ_DEF(void) pjsua_config_dup(pj_pool_t *pool, @@ -1858,28 +1860,69 @@ void pjsua_init_tpselector(pjsua_transport_id tp_id, } +/* Callback upon NAT detection completion */ +static void nat_detect_cb(void *user_data, + const pj_stun_nat_detect_result *res) +{ + PJ_UNUSED_ARG(user_data); + + pjsua_var.nat_in_progress = PJ_FALSE; + pjsua_var.nat_status = res->status; + pjsua_var.nat_type = res->nat_type; + + if (pjsua_var.ua_cfg.cb.on_nat_detect) { + (*pjsua_var.ua_cfg.cb.on_nat_detect)(res); + } +} + + /* * Detect NAT type. */ -PJ_DEF(pj_status_t) pjsua_detect_nat_type( void *user_data, - pj_stun_nat_detect_cb *cb) +PJ_DEF(pj_status_t) pjsua_detect_nat_type() { pj_status_t status; + if (pjsua_var.nat_in_progress) + return PJ_SUCCESS; + /* Make sure STUN server resolution has completed */ status = pjsua_resolve_stun_server(PJ_TRUE); if (status != PJ_SUCCESS) { + pjsua_var.nat_status = status; + pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN; return status; } /* Make sure we have STUN */ if (pjsua_var.stun_srv.ipv4.sin_family == 0) { - return PJ_EINVALIDOP; + pjsua_var.nat_status = PJNATH_ESTUNINSERVER; + return PJNATH_ESTUNINSERVER; + } + + status = pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4, + &pjsua_var.stun_cfg, + NULL, &nat_detect_cb); + + if (status != PJ_SUCCESS) { + pjsua_var.nat_status = status; + pjsua_var.nat_type = PJ_STUN_NAT_TYPE_ERR_UNKNOWN; + return status; } - return pj_stun_detect_nat_type(&pjsua_var.stun_srv.ipv4, - &pjsua_var.stun_cfg, - user_data, cb); + pjsua_var.nat_in_progress = PJ_TRUE; + + return PJ_SUCCESS; +} + + +/* + * Get NAT type. + */ +PJ_DEF(pj_status_t) pjsua_get_nat_type(pj_stun_nat_type *type) +{ + *type = pjsua_var.nat_type; + return pjsua_var.nat_status; } diff --git a/pjsip/src/pjsua-lib/pjsua_media.c b/pjsip/src/pjsua-lib/pjsua_media.c index 0f4547b9..f6424353 100644 --- a/pjsip/src/pjsua-lib/pjsua_media.c +++ b/pjsip/src/pjsua-lib/pjsua_media.c @@ -194,6 +194,9 @@ pj_status_t pjsua_media_subsys_init(const pjsua_media_config *cfg) &pjsua_var.null_port); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); + /* Perform NAT detection */ + pjsua_detect_nat_type(); + return PJ_SUCCESS; } @@ -759,6 +762,30 @@ pj_status_t pjsua_media_channel_create_sdp(pjsua_call_id call_id, if (status != PJ_SUCCESS) goto on_error; + /* Add NAT info in the SDP */ + if (pjsua_var.ua_cfg.nat_type_in_sdp) { + pjmedia_sdp_attr *a; + pj_str_t value; + char nat_info[80]; + + value.ptr = nat_info; + if (pjsua_var.ua_cfg.nat_type_in_sdp == 1) { + value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info), + "%d", pjsua_var.nat_type); + } else { + const char *type_name = pj_stun_get_nat_name(pjsua_var.nat_type); + value.slen = pj_ansi_snprintf(nat_info, sizeof(nat_info), + "%d %s", + pjsua_var.nat_type, + type_name); + } + + a = pjmedia_sdp_attr_create(pool, "X-nat", &value); + + pjmedia_sdp_attr_add(&sdp->attr_count, sdp->attr, a); + + } + if (pjsua_var.media_cfg.enable_ice) { status = pjmedia_ice_modify_sdp(call->med_tp, pool, sdp); if (status != PJ_SUCCESS) -- cgit v1.2.3