diff options
author | Nanang Izzuddin <nanang@teluu.com> | 2016-06-08 03:17:45 +0000 |
---|---|---|
committer | Nanang Izzuddin <nanang@teluu.com> | 2016-06-08 03:17:45 +0000 |
commit | a44bcadfa1bc4c3a6067c5921d8eda10d7b24d10 (patch) | |
tree | bc9e0af584e8ee4f4a1aa8a16690bfdbe5d5fc43 /pjnath | |
parent | fd7ff41eec38181ba154286ca312a16b965aa07c (diff) |
Re #422: Added IPv6 support to PJNATH, changes:
- Deprecated 'pj_ice_strans_cfg.af', if set, the value will be ignored, address family setting is now specified via transport setting, i.e: 'pj_ice_strans_cfg.stun_tp/turn_tp'.
- Deprecated 'pj_ice_strans_cfg.stun/turn', for backward compatibility, this field value will be checked if 'pj_ice_strans_cfg.stun_tp_cnt/turn_tp_cnt' is set to zero.
- Added 'pj_ice_strans_stun_cfg' & 'pj_ice_strans_stun_cfg' and the corresponding 'pj_ice_strans_stun/turn_cfg_default()'
- Added 'pj_ice_strans_cfg.stun_tp/turn_tp' as replacement of 'pj_ice_strans_cfg.stun/turn', it is now an array so app can have multiple STUN/TURN transports.
- Added macro PJ_ICE_MAX_STUN/TURN to specify maximum number of STUN/TURN transports in each ICE component in compile-time.
- Miscellaneous: fixed socket number limit in concurrency test in pjnath-test, updated pjsua_media.c to use new 'pj_ice_strans_cfg' setting.
git-svn-id: http://svn.pjsip.org/repos/pjproject/trunk@5339 74dad513-b988-da41-8d7b-12977e46ad98
Diffstat (limited to 'pjnath')
-rw-r--r-- | pjnath/include/pjnath/config.h | 22 | ||||
-rw-r--r-- | pjnath/include/pjnath/ice_session.h | 2 | ||||
-rw-r--r-- | pjnath/include/pjnath/ice_strans.h | 339 | ||||
-rw-r--r-- | pjnath/include/pjnath/stun_sock.h | 2 | ||||
-rw-r--r-- | pjnath/src/pjnath-test/concur_test.c | 5 | ||||
-rw-r--r-- | pjnath/src/pjnath/ice_session.c | 18 | ||||
-rw-r--r-- | pjnath/src/pjnath/ice_strans.c | 703 |
7 files changed, 691 insertions, 400 deletions
diff --git a/pjnath/include/pjnath/config.h b/pjnath/include/pjnath/config.h index 5a30f703..d5f69164 100644 --- a/pjnath/include/pjnath/config.h +++ b/pjnath/include/pjnath/config.h @@ -246,6 +246,28 @@ /** + * Maximum number of STUN transports for each ICE stream transport component. + * Valid values are 1 - 64. + * + * Default: 2 + */ +#ifndef PJ_ICE_MAX_STUN +# define PJ_ICE_MAX_STUN 2 +#endif + + +/** + * Maximum number of TURN transports for each ICE stream transport component. + * Valid values are 1 - 64. + * + * Default: 2 + */ +#ifndef PJ_ICE_MAX_TURN +# define PJ_ICE_MAX_TURN 2 +#endif + + +/** * The number of bits to represent component IDs. This will affect * the maximum number of components (PJ_ICE_MAX_COMP) value. */ diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h index d850301a..fa13a3b7 100644 --- a/pjnath/include/pjnath/ice_session.h +++ b/pjnath/include/pjnath/ice_session.h @@ -653,7 +653,7 @@ struct pj_ice_sess pj_ice_sess_cand rcand[PJ_ICE_MAX_CAND]; /**< Array of cand. */ /** Array of transport datas */ - pj_ice_msg_data tp_data[4]; + pj_ice_msg_data tp_data[PJ_ICE_MAX_STUN + PJ_ICE_MAX_TURN]; /* List of eearly checks */ pj_ice_rx_check early_check; /**< Early checks. */ diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h index d711d951..6aa3f6d6 100644 --- a/pjnath/include/pjnath/ice_strans.h +++ b/pjnath/include/pjnath/ice_strans.h @@ -175,6 +175,162 @@ typedef struct pj_ice_strans_cb /** + * STUN and local transport settings for ICE stream transport. + */ +typedef struct pj_ice_strans_stun_cfg +{ + /** + * Address family, IPv4 or IPv6. + * + * Default value is pj_AF_INET() (IPv4) + */ + int af; + + /** + * Optional configuration for STUN transport. The default + * value will be initialized with #pj_stun_sock_cfg_default(). + */ + pj_stun_sock_cfg cfg; + + /** + * Maximum number of host candidates to be added. If the + * value is zero, no host candidates will be added. + * + * Default: 64 + */ + unsigned max_host_cands; + + /** + * Include loopback addresses in the host candidates. + * + * Default: PJ_FALSE + */ + pj_bool_t loop_addr; + + /** + * Specify the STUN server domain or hostname or IP address. + * If DNS SRV resolution is required, application must fill + * in this setting with the domain name of the STUN server + * and set the resolver instance in the \a resolver field. + * Otherwise if the \a resolver setting is not set, this + * field will be resolved with hostname resolution and in + * this case the \a port field must be set. + * + * The \a port field should also be set even when DNS SRV + * resolution is used, in case the DNS SRV resolution fails. + * + * When this field is empty, STUN mapped address resolution + * will not be performed. In this case only ICE host candidates + * will be added to the ICE transport, unless if \a no_host_cands + * field is set. In this case, both host and srflx candidates + * are disabled. + * + * If there are more than one STUN candidates per ICE stream + * transport component, the standard recommends to use the same + * STUN server for all STUN candidates. + * + * The default value is empty. + */ + pj_str_t server; + + /** + * The port number of the STUN server, when \a server + * field specifies a hostname rather than domain name. This + * field should also be set even when the \a server + * specifies a domain name, to allow DNS SRV resolution + * to fallback to DNS A/AAAA resolution when the DNS SRV + * resolution fails. + * + * The default value is PJ_STUN_PORT. + */ + pj_uint16_t port; + + /** + * Ignore STUN resolution error and proceed with just local + * addresses. + * + * The default is PJ_FALSE + */ + pj_bool_t ignore_stun_error; + +} pj_ice_strans_stun_cfg; + + +/** + * TURN transport settings for ICE stream transport. + */ +typedef struct pj_ice_strans_turn_cfg +{ + /** + * Address family, IPv4 or IPv6. + * + * Default value is pj_AF_INET() (IPv4) + */ + int af; + + /** + * Optional TURN socket settings. The default values will be + * initialized by #pj_turn_sock_cfg_default(). This contains + * settings such as QoS. + */ + pj_turn_sock_cfg cfg; + + /** + * Specify the TURN server domain or hostname or IP address. + * If DNS SRV resolution is required, application must fill + * in this setting with the domain name of the TURN server + * and set the resolver instance in the \a resolver field. + * Otherwise if the \a resolver setting is not set, this + * field will be resolved with hostname resolution and in + * this case the \a port field must be set. + * + * The \a port field should also be set even when DNS SRV + * resolution is used, in case the DNS SRV resolution fails. + * + * When this field is empty, relay candidate will not be + * created. + * + * The default value is empty. + */ + pj_str_t server; + + /** + * The port number of the TURN server, when \a server + * field specifies a hostname rather than domain name. This + * field should also be set even when the \a server + * specifies a domain name, to allow DNS SRV resolution + * to fallback to DNS A/AAAA resolution when the DNS SRV + * resolution fails. + * + * Default is zero. + */ + pj_uint16_t port; + + /** + * Type of connection to the TURN server. + * + * Default is PJ_TURN_TP_UDP. + */ + pj_turn_tp_type conn_type; + + /** + * Credential to be used for the TURN session. This setting + * is mandatory. + * + * Default is to have no credential. + */ + pj_stun_auth_cred auth_cred; + + /** + * Optional TURN Allocate parameter. The default value will be + * initialized by #pj_turn_alloc_param_default(). + */ + pj_turn_alloc_param alloc_param; + +} pj_ice_strans_turn_cfg; + + +/** * This structure describes ICE stream transport configuration. Application * should initialize the structure by calling #pj_ice_strans_cfg_default() * before changing the settings. @@ -182,10 +338,11 @@ typedef struct pj_ice_strans_cb typedef struct pj_ice_strans_cfg { /** - * Address family, IPv4 or IPv6. Currently only pj_AF_INET() (IPv4) - * is supported, and this is the default value. + * Warning: this field is deprecated and will be ignored. Please specify + * transport address family in STUN and TURN transport setting, i.e: + * \a stun_tp and \a turn_tp. */ - int af; + int af; /** * STUN configuration which contains the timer heap and @@ -213,140 +370,48 @@ typedef struct pj_ice_strans_cfg pj_ice_sess_options opt; /** - * STUN and local transport settings. This specifies the - * settings for local UDP socket, which will be resolved - * to get the STUN mapped address. + * Warning: this field is deprecated, please use \a stun_tp field instead. + * To maintain backward compatibility, if \a stun_tp_cnt is zero, the + * value of this field will be copied to \a stun_tp. + * + * STUN and local transport settings. This specifies the settings + * for local UDP socket address and STUN resolved address. */ - struct { - /** - * Optional configuration for STUN transport. The default - * value will be initialized with #pj_stun_sock_cfg_default(). - */ - pj_stun_sock_cfg cfg; - - /** - * Maximum number of host candidates to be added. If the - * value is zero, no host candidates will be added. - * - * Default: 64 - */ - unsigned max_host_cands; - - /** - * Include loopback addresses in the host candidates. - * - * Default: PJ_FALSE - */ - pj_bool_t loop_addr; - - /** - * Specify the STUN server domain or hostname or IP address. - * If DNS SRV resolution is required, application must fill - * in this setting with the domain name of the STUN server - * and set the resolver instance in the \a resolver field. - * Otherwise if the \a resolver setting is not set, this - * field will be resolved with hostname resolution and in - * this case the \a port field must be set. - * - * The \a port field should also be set even when DNS SRV - * resolution is used, in case the DNS SRV resolution fails. - * - * When this field is empty, STUN mapped address resolution - * will not be performed. In this case only ICE host candidates - * will be added to the ICE transport, unless if \a no_host_cands - * field is set. In this case, both host and srflx candidates - * are disabled. - * - * The default value is empty. - */ - pj_str_t server; - - /** - * The port number of the STUN server, when \a server - * field specifies a hostname rather than domain name. This - * field should also be set even when the \a server - * specifies a domain name, to allow DNS SRV resolution - * to fallback to DNS A/AAAA resolution when the DNS SRV - * resolution fails. - * - * The default value is PJ_STUN_PORT. - */ - pj_uint16_t port; - - /** - * Ignore STUN resolution error and proceed with just local - * addresses. - * - * The default is PJ_FALSE - */ - pj_bool_t ignore_stun_error; - - } stun; + pj_ice_strans_stun_cfg stun; /** - * TURN specific settings. + * Number of STUN transports. + * + * Default: 0 */ - struct { - /** - * Optional TURN socket settings. The default values will be - * initialized by #pj_turn_sock_cfg_default(). This contains - * settings such as QoS. - */ - pj_turn_sock_cfg cfg; - - /** - * Specify the TURN server domain or hostname or IP address. - * If DNS SRV resolution is required, application must fill - * in this setting with the domain name of the TURN server - * and set the resolver instance in the \a resolver field. - * Otherwise if the \a resolver setting is not set, this - * field will be resolved with hostname resolution and in - * this case the \a port field must be set. - * - * The \a port field should also be set even when DNS SRV - * resolution is used, in case the DNS SRV resolution fails. - * - * When this field is empty, relay candidate will not be - * created. - * - * The default value is empty. - */ - pj_str_t server; + unsigned stun_tp_cnt; - /** - * The port number of the TURN server, when \a server - * field specifies a hostname rather than domain name. This - * field should also be set even when the \a server - * specifies a domain name, to allow DNS SRV resolution - * to fallback to DNS A/AAAA resolution when the DNS SRV - * resolution fails. - * - * Default is zero. - */ - pj_uint16_t port; - - /** - * Type of connection to the TURN server. - * - * Default is PJ_TURN_TP_UDP. - */ - pj_turn_tp_type conn_type; + /** + * STUN and local transport settings. This specifies the settings + * for local UDP socket address and STUN resolved address. + */ + pj_ice_strans_stun_cfg stun_tp[PJ_ICE_MAX_STUN]; - /** - * Credential to be used for the TURN session. This setting - * is mandatory. - * - * Default is to have no credential. - */ - pj_stun_auth_cred auth_cred; + /** + * Warning: this field is deprecated, please use \a turn_tp field instead. + * To maintain backward compatibility, if \a turn_tp_cnt is zero, the + * value of this field will be copied to \a turn_tp. + * + * TURN transport settings. + */ + pj_ice_strans_turn_cfg turn; - /** - * Optional TURN Allocate parameter. The default value will be - * initialized by #pj_turn_alloc_param_default(). - */ - pj_turn_alloc_param alloc_param; + /** + * Number of TURN transports. + * + * Default: 0 + */ + unsigned turn_tp_cnt; - } turn; + /** + * TURN transport settings. + */ + pj_ice_strans_turn_cfg turn_tp[PJ_ICE_MAX_TURN]; /** * Component specific settings, which will override the settings in @@ -466,6 +531,22 @@ typedef enum pj_ice_strans_state PJ_DECL(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg); +/** + * Initialize ICE STUN transport configuration with default values. + * + * @param cfg The configuration to be initialized. + */ +PJ_DECL(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg); + + +/** + * Initialize ICE TURN transport configuration with default values. + * + * @param cfg The configuration to be initialized. + */ +PJ_DECL(void) pj_ice_strans_turn_cfg_default(pj_ice_strans_turn_cfg *cfg); + + /** * Copy configuration. * diff --git a/pjnath/include/pjnath/stun_sock.h b/pjnath/include/pjnath/stun_sock.h index a1123a1f..fff4df88 100644 --- a/pjnath/include/pjnath/stun_sock.h +++ b/pjnath/include/pjnath/stun_sock.h @@ -371,7 +371,7 @@ PJ_DECL(pj_status_t) pj_stun_sock_create(pj_stun_config *stun_cfg, * timer will be started. * * @param stun_sock The STUN transport instance. - * @param domain The domain, hostname, or IP address of the TURN + * @param domain The domain, hostname, or IP address of the STUN * server. When this parameter contains domain name, * the \a resolver parameter must be set to activate * DNS SRV resolution. diff --git a/pjnath/src/pjnath-test/concur_test.c b/pjnath/src/pjnath-test/concur_test.c index 0ab5bf1d..d30b5ebd 100644 --- a/pjnath/src/pjnath-test/concur_test.c +++ b/pjnath/src/pjnath-test/concur_test.c @@ -26,7 +26,7 @@ /****************************************************************************/ #define WORKER_THREAD_CNT 4 #define SERVER_THREAD_CNT 4 -#define MAX_SOCK_CLIENTS 80 +#define MAX_SOCK_CLIENTS (PJ_IOQUEUE_MAX_HANDLES/2) struct stun_test_session { @@ -219,6 +219,9 @@ static int stun_destroy_test_session(struct stun_test_session *test_sess) } } + /* Give some time to ioqueue to free sockets */ + pj_thread_sleep(PJ_IOQUEUE_KEY_FREE_DELAY); + return 0; } diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c index 135bd5da..b6613d0a 100644 --- a/pjnath/src/pjnath/ice_session.c +++ b/pjnath/src/pjnath/ice_session.c @@ -396,7 +396,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_create(pj_stun_config *stun_cfg, /* Initialize transport datas */ for (i=0; i<PJ_ARRAY_SIZE(ice->tp_data); ++i) { - ice->tp_data[i].transport_id = i; + ice->tp_data[i].transport_id = 0; ice->tp_data[i].has_req_data = PJ_FALSE; } @@ -723,6 +723,7 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, pj_ice_sess_cand *lcand; pj_status_t status = PJ_SUCCESS; char address[PJ_INET6_ADDRSTRLEN]; + unsigned i; PJ_ASSERT_RETURN(ice && comp_id && foundation && addr && base_addr && addr_len, @@ -748,6 +749,21 @@ PJ_DEF(pj_status_t) pj_ice_sess_add_cand(pj_ice_sess *ice, rel_addr = base_addr; pj_memcpy(&lcand->rel_addr, rel_addr, addr_len); + /* Update transport data */ + for (i = 0; i < PJ_ARRAY_SIZE(ice->tp_data); ++i) { + /* Check if this transport has been registered */ + if (ice->tp_data[i].transport_id == transport_id) + break; + + if (ice->tp_data[i].transport_id == 0) { + /* Found an empty slot, register this transport here */ + ice->tp_data[i].transport_id = transport_id; + break; + } + } + pj_assert(i < PJ_ARRAY_SIZE(ice->tp_data) && + ice->tp_data[i].transport_id == transport_id); + pj_ansi_strcpy(ice->tmp.txt, pj_sockaddr_print(&lcand->addr, address, sizeof(address), 0)); LOG4((ice->obj_name, diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c index 66dce88e..e233ade9 100644 --- a/pjnath/src/pjnath/ice_strans.c +++ b/pjnath/src/pjnath/ice_strans.c @@ -48,6 +48,12 @@ enum tp_type TP_TURN }; + +#define CREATE_TP_ID(type, idx) (pj_uint8_t)((type << 6) | idx) +#define GET_TP_TYPE(transport_id) ((transport_id & 0xC0) >> 6) +#define GET_TP_IDX(transport_id) (transport_id & 0x3F) + + /* Candidate's local preference values. This is mostly used to * specify preference among candidates with the same type. Since * we don't have the facility to specify that, we'll just set it @@ -148,10 +154,15 @@ typedef struct pj_ice_strans_comp pj_ice_strans *ice_st; /**< ICE stream transport. */ unsigned comp_id; /**< Component ID. */ - pj_stun_sock *stun_sock; /**< STUN transport. */ - pj_turn_sock *turn_sock; /**< TURN relay transport. */ - pj_bool_t turn_log_off; /**< TURN loggin off? */ - unsigned turn_err_cnt; /**< TURN disconnected count. */ + struct { + pj_stun_sock *sock; /**< STUN transport. */ + } stun[PJ_ICE_MAX_STUN]; + + struct { + pj_turn_sock *sock; /**< TURN relay transport. */ + pj_bool_t log_off; /**< TURN loggin off? */ + unsigned err_cnt; /**< TURN disconnected count. */ + } turn[PJ_ICE_MAX_TURN]; unsigned cand_cnt; /**< # of candidates/aliaes. */ pj_ice_sess_cand cand_list[PJ_ICE_ST_MAX_CAND]; /**< Cand array */ @@ -187,6 +198,18 @@ struct pj_ice_strans }; +/** + * This structure describe user data for STUN/TURN sockets of the + * ICE stream transport. + */ +typedef struct sock_user_data +{ + pj_ice_strans_comp *comp; + pj_uint8_t transport_id; + +} sock_user_data; + + /* Validate configuration */ static pj_status_t pj_ice_strans_cfg_check_valid(const pj_ice_strans_cfg *cfg) { @@ -208,18 +231,38 @@ PJ_DEF(void) pj_ice_strans_cfg_default(pj_ice_strans_cfg *cfg) pj_bzero(cfg, sizeof(*cfg)); pj_stun_config_init(&cfg->stun_cfg, NULL, 0, NULL, NULL); - pj_stun_sock_cfg_default(&cfg->stun.cfg); - pj_turn_alloc_param_default(&cfg->turn.alloc_param); - pj_turn_sock_cfg_default(&cfg->turn.cfg); - + pj_ice_strans_stun_cfg_default(&cfg->stun); + pj_ice_strans_turn_cfg_default(&cfg->turn); pj_ice_sess_options_default(&cfg->opt); +} + + +/* + * Initialize ICE STUN transport configuration with default values. + */ +PJ_DEF(void) pj_ice_strans_stun_cfg_default(pj_ice_strans_stun_cfg *cfg) +{ + pj_bzero(cfg, sizeof(*cfg)); cfg->af = pj_AF_INET(); - cfg->stun.port = PJ_STUN_PORT; - cfg->turn.conn_type = PJ_TURN_TP_UDP; + cfg->port = PJ_STUN_PORT; + cfg->max_host_cands = 64; + cfg->ignore_stun_error = PJ_FALSE; + pj_stun_sock_cfg_default(&cfg->cfg); +} + + +/* + * Initialize ICE TURN transport configuration with default values. + */ +PJ_DEF(void) pj_ice_strans_turn_cfg_default(pj_ice_strans_turn_cfg *cfg) +{ + pj_bzero(cfg, sizeof(*cfg)); - cfg->stun.max_host_cands = 64; - cfg->stun.ignore_stun_error = PJ_FALSE; + cfg->af = pj_AF_INET(); + cfg->conn_type = PJ_TURN_TP_UDP; + pj_turn_alloc_param_default(&cfg->alloc_param); + pj_turn_sock_cfg_default(&cfg->cfg); } @@ -230,14 +273,30 @@ PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool, pj_ice_strans_cfg *dst, const pj_ice_strans_cfg *src) { + unsigned i; + pj_memcpy(dst, src, sizeof(*src)); if (src->stun.server.slen) pj_strdup(pool, &dst->stun.server, &src->stun.server); + + for (i = 0; i < src->stun_tp_cnt; ++i) { + if (src->stun_tp[i].server.slen) + pj_strdup(pool, &dst->stun_tp[i].server, + &src->stun_tp[i].server); + } + if (src->turn.server.slen) pj_strdup(pool, &dst->turn.server, &src->turn.server); - pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred, - &src->turn.auth_cred); + pj_stun_auth_cred_dup(pool, &dst->turn.auth_cred, &src->turn.auth_cred); + + for (i = 0; i < src->turn_tp_cnt; ++i) { + if (src->turn_tp[i].server.slen) + pj_strdup(pool, &dst->turn_tp[i].server, + &src->turn_tp[i].server); + pj_stun_auth_cred_dup(pool, &dst->turn_tp[i].auth_cred, + &src->turn_tp[i].auth_cred); + } } @@ -245,16 +304,27 @@ PJ_DEF(void) pj_ice_strans_cfg_copy( pj_pool_t *pool, * Add or update TURN candidate. */ static pj_status_t add_update_turn(pj_ice_strans *ice_st, - pj_ice_strans_comp *comp) + pj_ice_strans_comp *comp, + unsigned idx) { - pj_turn_sock_cb turn_sock_cb; pj_ice_sess_cand *cand = NULL; + pj_ice_strans_turn_cfg *turn_cfg = &ice_st->cfg.turn_tp[idx]; + pj_turn_sock_cfg *sock_cfg = &turn_cfg->cfg; + unsigned comp_idx = comp->comp_id - 1; + pj_turn_sock_cb turn_sock_cb; + sock_user_data *data; unsigned i; + pj_uint8_t tp_id; pj_status_t status; + /* Check if TURN transport is configured */ + if (turn_cfg->server.slen == 0) + return PJ_SUCCESS; + /* Find relayed candidate in the component */ + tp_id = CREATE_TP_ID(TP_TURN, idx); for (i=0; i<comp->cand_cnt; ++i) { - if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) { + if (comp->cand_list[i].transport_id == tp_id) { cand = &comp->cand_list[i]; break; } @@ -286,31 +356,39 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, turn_sock_cb.on_state = &turn_on_state; /* Override with component specific QoS settings, if any */ - if (ice_st->cfg.comp[comp->comp_id-1].qos_type) { - ice_st->cfg.turn.cfg.qos_type = - ice_st->cfg.comp[comp->comp_id-1].qos_type; - } - if (ice_st->cfg.comp[comp->comp_id-1].qos_params.flags) { - pj_memcpy(&ice_st->cfg.turn.cfg.qos_params, - &ice_st->cfg.comp[comp->comp_id-1].qos_params, - sizeof(ice_st->cfg.turn.cfg.qos_params)); - } + if (ice_st->cfg.comp[comp_idx].qos_type) + sock_cfg->qos_type = ice_st->cfg.comp[comp_idx].qos_type; + if (ice_st->cfg.comp[comp_idx].qos_params.flags) + pj_memcpy(&sock_cfg->qos_params, + &ice_st->cfg.comp[comp_idx].qos_params, + sizeof(sock_cfg->qos_params)); /* Override with component specific socket buffer size settings, if any */ - if (ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size > 0) { - ice_st->cfg.turn.cfg.so_rcvbuf_size = - ice_st->cfg.comp[comp->comp_id-1].so_rcvbuf_size; - } - if (ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size > 0) { - ice_st->cfg.turn.cfg.so_sndbuf_size = - ice_st->cfg.comp[comp->comp_id-1].so_sndbuf_size; + if (ice_st->cfg.comp[comp_idx].so_rcvbuf_size > 0) + sock_cfg->so_rcvbuf_size = ice_st->cfg.comp[comp_idx].so_rcvbuf_size; + if (ice_st->cfg.comp[comp_idx].so_sndbuf_size > 0) + sock_cfg->so_sndbuf_size = ice_st->cfg.comp[comp_idx].so_sndbuf_size; + + /* Add relayed candidate with pending status if there's no existing one */ + if (cand == NULL) { + cand = &comp->cand_list[comp->cand_cnt]; + cand->type = PJ_ICE_CAND_TYPE_RELAYED; + cand->status = PJ_EPENDING; + cand->local_pref = RELAY_PREF; + cand->transport_id = CREATE_TP_ID(TP_TURN, idx); + cand->comp_id = (pj_uint8_t) comp->comp_id; } + /* Allocate and initialize TURN socket data */ + data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data); + data->comp = comp; + data->transport_id = cand->transport_id; + /* Create the TURN transport */ - status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, ice_st->cfg.af, - ice_st->cfg.turn.conn_type, - &turn_sock_cb, &ice_st->cfg.turn.cfg, - comp, &comp->turn_sock); + status = pj_turn_sock_create(&ice_st->cfg.stun_cfg, turn_cfg->af, + turn_cfg->conn_type, + &turn_sock_cb, sock_cfg, + data, &comp->turn[idx].sock); if (status != PJ_SUCCESS) { return status; } @@ -319,26 +397,19 @@ static pj_status_t add_update_turn(pj_ice_strans *ice_st, ///sess_add_ref(ice_st); /* Start allocation */ - status=pj_turn_sock_alloc(comp->turn_sock, - &ice_st->cfg.turn.server, - ice_st->cfg.turn.port, + status=pj_turn_sock_alloc(comp->turn[idx].sock, + &turn_cfg->server, + turn_cfg->port, ice_st->cfg.resolver, - &ice_st->cfg.turn.auth_cred, - &ice_st->cfg.turn.alloc_param); + &turn_cfg->auth_cred, + &turn_cfg->alloc_param); if (status != PJ_SUCCESS) { ///sess_dec_ref(ice_st); return status; } - /* Add relayed candidate with pending status if there's no existing one */ - if (cand == NULL) { - cand = &comp->cand_list[comp->cand_cnt++]; - cand->type = PJ_ICE_CAND_TYPE_RELAYED; - cand->status = PJ_EPENDING; - cand->local_pref = RELAY_PREF; - cand->transport_id = TP_TURN; - cand->comp_id = (pj_uint8_t) comp->comp_id; - } + /* Commit the relayed candidate. */ + comp->cand_cnt++; PJ_LOG(4,(ice_st->obj_name, "Comp %d: TURN relay candidate waiting for allocation", @@ -372,201 +443,239 @@ static pj_bool_t ice_cand_equals(pj_ice_sess_cand *lcand, return PJ_TRUE; } -/* - * Create the component. - */ -static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id) + +static pj_status_t add_stun_and_host(pj_ice_strans *ice_st, + pj_ice_strans_comp *comp, + unsigned idx) { - pj_ice_strans_comp *comp = NULL; + pj_ice_sess_cand *cand; + pj_ice_strans_stun_cfg *stun_cfg = &ice_st->cfg.stun_tp[idx]; + pj_stun_sock_cfg *sock_cfg = &stun_cfg->cfg; + unsigned comp_idx = comp->comp_id - 1; + pj_stun_sock_cb stun_sock_cb; + sock_user_data *data; pj_status_t status; - /* Verify arguments */ - PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); + /* Check if STUN transport or host candidate is configured */ + if (stun_cfg->server.slen == 0 && stun_cfg->max_host_cands == 0) + return PJ_SUCCESS; - /* Check that component ID present */ - PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); + /* Initialize STUN socket callback */ + pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); + stun_sock_cb.on_rx_data = &stun_on_rx_data; + stun_sock_cb.on_status = &stun_on_status; + stun_sock_cb.on_data_sent = &stun_on_data_sent; - /* Create component */ - comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp); - comp->ice_st = ice_st; - comp->comp_id = comp_id; + /* Override component specific QoS settings, if any */ + if (ice_st->cfg.comp[comp_idx].qos_type) { + sock_cfg->qos_type = ice_st->cfg.comp[comp_idx].qos_type; + } + if (ice_st->cfg.comp[comp_idx].qos_params.flags) { + pj_memcpy(&sock_cfg->qos_params, + &ice_st->cfg.comp[comp_idx].qos_params, + sizeof(sock_cfg->qos_params)); + } - ice_st->comp[comp_id-1] = comp; + /* Override component specific socket buffer size settings, if any */ + if (ice_st->cfg.comp[comp_idx].so_rcvbuf_size > 0) { + sock_cfg->so_rcvbuf_size = ice_st->cfg.comp[comp_idx].so_rcvbuf_size; + } + if (ice_st->cfg.comp[comp_idx].so_sndbuf_size > 0) { + sock_cfg->so_sndbuf_size = ice_st->cfg.comp[comp_idx].so_sndbuf_size; + } - /* Initialize default candidate */ - comp->default_cand = 0; + /* Prepare srflx candidate with pending status. */ + cand = &comp->cand_list[comp->cand_cnt]; + cand->type = PJ_ICE_CAND_TYPE_SRFLX; + cand->status = PJ_EPENDING; + cand->local_pref = SRFLX_PREF; + cand->transport_id = CREATE_TP_ID(TP_STUN, idx); + cand->comp_id = (pj_uint8_t) comp->comp_id; + + /* Allocate and initialize STUN socket data */ + data = PJ_POOL_ZALLOC_T(ice_st->pool, sock_user_data); + data->comp = comp; + data->transport_id = cand->transport_id; + + /* Create the STUN transport */ + status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, + stun_cfg->af, &stun_sock_cb, + sock_cfg, data, &comp->stun[idx].sock); + if (status != PJ_SUCCESS) + return status; - /* Create STUN transport if configured */ - if (ice_st->cfg.stun.server.slen || ice_st->cfg.stun.max_host_cands) { - pj_stun_sock_cb stun_sock_cb; - pj_ice_sess_cand *cand; - - pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb)); - stun_sock_cb.on_rx_data = &stun_on_rx_data; - stun_sock_cb.on_status = &stun_on_status; - stun_sock_cb.on_data_sent = &stun_on_data_sent; - - /* Override component specific QoS settings, if any */ - if (ice_st->cfg.comp[comp_id-1].qos_type) { - ice_st->cfg.stun.cfg.qos_type = - ice_st->cfg.comp[comp_id-1].qos_type; - } - if (ice_st->cfg.comp[comp_id-1].qos_params.flags) { - pj_memcpy(&ice_st->cfg.stun.cfg.qos_params, - &ice_st->cfg.comp[comp_id-1].qos_params, - sizeof(ice_st->cfg.stun.cfg.qos_params)); - } + /* Start STUN Binding resolution and add srflx candidate + * only if server is set + */ + if (stun_cfg->server.slen) { + pj_stun_sock_info stun_sock_info; + + /* Add pending job */ + ///sess_add_ref(ice_st); + + PJ_LOG(4,(ice_st->obj_name, + "Comp %d: srflx candidate starts Binding discovery", + comp->comp_id)); - /* Override component specific socket buffer size settings, if any */ - if (ice_st->cfg.comp[comp_id-1].so_rcvbuf_size > 0) { - ice_st->cfg.stun.cfg.so_rcvbuf_size = - ice_st->cfg.comp[comp_id-1].so_rcvbuf_size; + pj_log_push_indent(); + + /* Start Binding resolution */ + status = pj_stun_sock_start(comp->stun[idx].sock, &stun_cfg->server, + stun_cfg->port, ice_st->cfg.resolver); + if (status != PJ_SUCCESS) { + ///sess_dec_ref(ice_st); + pj_log_pop_indent(); + return status; } - if (ice_st->cfg.comp[comp_id-1].so_sndbuf_size > 0) { - ice_st->cfg.stun.cfg.so_sndbuf_size = - ice_st->cfg.comp[comp_id-1].so_sndbuf_size; + + /* Enumerate addresses */ + status = pj_stun_sock_get_info(comp->stun[idx].sock, &stun_sock_info); + if (status != PJ_SUCCESS) { + ///sess_dec_ref(ice_st); + pj_log_pop_indent(); + return status; } - /* Create the STUN transport */ - status = pj_stun_sock_create(&ice_st->cfg.stun_cfg, NULL, - ice_st->cfg.af, &stun_sock_cb, - &ice_st->cfg.stun.cfg, - comp, &comp->stun_sock); + /* Update and commit the srflx candidate. */ + pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]); + pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr); + pj_ice_calc_foundation(ice_st->pool, &cand->foundation, + cand->type, &cand->base_addr); + comp->cand_cnt++; + + /* Set default candidate to srflx */ + comp->default_cand = (unsigned)(cand - comp->cand_list); + + pj_log_pop_indent(); + } + + /* Add local addresses to host candidates, unless max_host_cands + * is set to zero. + */ + if (stun_cfg->max_host_cands) { + pj_stun_sock_info stun_sock_info; + unsigned i; + + /* Enumerate addresses */ + status = pj_stun_sock_get_info(comp->stun[idx].sock, &stun_sock_info); if (status != PJ_SUCCESS) return status; - /* Start STUN Binding resolution and add srflx candidate - * only if server is set - */ - if (ice_st->cfg.stun.server.slen) { - pj_stun_sock_info stun_sock_info; - - /* Add pending job */ - ///sess_add_ref(ice_st); + for (i=0; i<stun_sock_info.alias_cnt && + i<stun_cfg->max_host_cands; ++i) + { + unsigned j; + pj_bool_t cand_duplicate = PJ_FALSE; + char addrinfo[PJ_INET6_ADDRSTRLEN+10]; + const pj_sockaddr *addr = &stun_sock_info.aliases[i]; + + /* Leave one candidate for relay */ + if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) { + PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); + break; + } - PJ_LOG(4,(ice_st->obj_name, - "Comp %d: srflx candidate starts Binding discovery", - comp_id)); - - pj_log_push_indent(); - - /* Start Binding resolution */ - status = pj_stun_sock_start(comp->stun_sock, - &ice_st->cfg.stun.server, - ice_st->cfg.stun.port, - ice_st->cfg.resolver); - if (status != PJ_SUCCESS) { - ///sess_dec_ref(ice_st); - pj_log_pop_indent(); - return status; + /* Ignore loopback addresses if cfg->stun.loop_addr is unset */ + if (stun_cfg->loop_addr==PJ_FALSE) { + if (stun_cfg->af == pj_AF_INET() && + (pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) + { + continue; + } + else if (stun_cfg->af == pj_AF_INET6()) { + pj_in6_addr in6addr = {0}; + in6addr.s6_addr[15] = 1; + if (pj_memcmp(&in6addr, &addr->ipv6.sin6_addr, + sizeof(in6addr))==0) + { + continue; + } + } } - /* Enumerate addresses */ - status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); - if (status != PJ_SUCCESS) { - ///sess_dec_ref(ice_st); - pj_log_pop_indent(); - return status; + cand = &comp->cand_list[comp->cand_cnt]; + + cand->type = PJ_ICE_CAND_TYPE_HOST; + cand->status = PJ_SUCCESS; + cand->local_pref = HOST_PREF; + cand->transport_id = CREATE_TP_ID(TP_STUN, idx); + cand->comp_id = (pj_uint8_t) comp->comp_id; + pj_sockaddr_cp(&cand->addr, addr); + pj_sockaddr_cp(&cand->base_addr, addr); + pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); + + /* Check if not already in list */ + for (j=0; j<comp->cand_cnt; j++) { + if (ice_cand_equals(cand, &comp->cand_list[j])) { + cand_duplicate = PJ_TRUE; + break; + } } - /* Add srflx candidate with pending status. */ - cand = &comp->cand_list[comp->cand_cnt++]; - cand->type = PJ_ICE_CAND_TYPE_SRFLX; - cand->status = PJ_EPENDING; - cand->local_pref = SRFLX_PREF; - cand->transport_id = TP_STUN; - cand->comp_id = (pj_uint8_t) comp_id; - pj_sockaddr_cp(&cand->base_addr, &stun_sock_info.aliases[0]); - pj_sockaddr_cp(&cand->rel_addr, &cand->base_addr); + if (cand_duplicate) { + PJ_LOG(4, (ice_st->obj_name, + "Comp %d: host candidate %s is a duplicate", + comp->comp_id, pj_sockaddr_print(&cand->addr, addrinfo, + sizeof(addrinfo), 3))); + + pj_bzero(&cand->addr, sizeof(cand->addr)); + pj_bzero(&cand->base_addr, sizeof(cand->base_addr)); + continue; + } else { + comp->cand_cnt+=1; + } + pj_ice_calc_foundation(ice_st->pool, &cand->foundation, cand->type, &cand->base_addr); - /* Set default candidate to srflx */ - comp->default_cand = (unsigned)(cand - comp->cand_list); - - pj_log_pop_indent(); + PJ_LOG(4,(ice_st->obj_name, + "Comp %d: host candidate %s added", + comp->comp_id, pj_sockaddr_print(&cand->addr, addrinfo, + sizeof(addrinfo), 3))); } + } - /* Add local addresses to host candidates, unless max_host_cands - * is set to zero. - */ - if (ice_st->cfg.stun.max_host_cands) { - pj_stun_sock_info stun_sock_info; - unsigned i; + return PJ_SUCCESS; +} - /* Enumerate addresses */ - status = pj_stun_sock_get_info(comp->stun_sock, &stun_sock_info); - if (status != PJ_SUCCESS) - return status; - for (i=0; i<stun_sock_info.alias_cnt && - i<ice_st->cfg.stun.max_host_cands; ++i) - { - unsigned j; - pj_bool_t cand_duplicate = PJ_FALSE; - char addrinfo[PJ_INET6_ADDRSTRLEN+10]; - const pj_sockaddr *addr = &stun_sock_info.aliases[i]; - - /* Leave one candidate for relay */ - if (comp->cand_cnt >= PJ_ICE_ST_MAX_CAND-1) { - PJ_LOG(4,(ice_st->obj_name, "Too many host candidates")); - break; - } +/* + * Create the component. + */ +static pj_status_t create_comp(pj_ice_strans *ice_st, unsigned comp_id) +{ + pj_ice_strans_comp *comp = NULL; + unsigned i; + pj_status_t status; - /* Ignore loopback addresses unless cfg->stun.loop_addr - * is set - */ - if ((pj_ntohl(addr->ipv4.sin_addr.s_addr)>>24)==127) { - if (ice_st->cfg.stun.loop_addr==PJ_FALSE) - continue; - } + /* Verify arguments */ + PJ_ASSERT_RETURN(ice_st && comp_id, PJ_EINVAL); - cand = &comp->cand_list[comp->cand_cnt]; + /* Check that component ID present */ + PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID); - cand->type = PJ_ICE_CAND_TYPE_HOST; - cand->status = PJ_SUCCESS; - cand->local_pref = HOST_PREF; - cand->transport_id = TP_STUN; - cand->comp_id = (pj_uint8_t) comp_id; - pj_sockaddr_cp(&cand->addr, addr); - pj_sockaddr_cp(&cand->base_addr, addr); - pj_bzero(&cand->rel_addr, sizeof(cand->rel_addr)); - - /* Check if not already in list */ - for (j=0; j<comp->cand_cnt; j++) { - if (ice_cand_equals(cand, &comp->cand_list[j])) { - cand_duplicate = PJ_TRUE; - break; - } - } + /* Create component */ + comp = PJ_POOL_ZALLOC_T(ice_st->pool, pj_ice_strans_comp); + comp->ice_st = ice_st; + comp->comp_id = comp_id; - if (cand_duplicate) { - PJ_LOG(4, (ice_st->obj_name, - "Comp %d: host candidate %s is a duplicate", - comp_id, pj_sockaddr_print(&cand->addr, addrinfo, - sizeof(addrinfo), 3))); + ice_st->comp[comp_id-1] = comp; - pj_bzero(&cand->addr, sizeof(cand->addr)); - pj_bzero(&cand->base_addr, sizeof(cand->base_addr)); - continue; - } else { - comp->cand_cnt+=1; - } - - pj_ice_calc_foundation(ice_st->pool, &cand->foundation, - cand->type, &cand->base_addr); + /* Initialize default candidate */ + comp->default_cand = 0; - PJ_LOG(4,(ice_st->obj_name, - "Comp %d: host candidate %s added", - comp_id, pj_sockaddr_print(&cand->addr, addrinfo, - sizeof(addrinfo), 3))); - } - } + /* Create STUN transport if configured */ + for (i=0; i<ice_st->cfg.stun_tp_cnt; ++i) { + status = add_stun_and_host(ice_st, comp, i); + if (status != PJ_SUCCESS) + return status; } /* Create TURN relay if configured. */ - if (ice_st->cfg.turn.server.slen) { - add_update_turn(ice_st, comp); + for (i=0; i<ice_st->cfg.turn_tp_cnt; ++i) { + status = add_update_turn(ice_st, comp, i); + if (status != PJ_SUCCESS) + return status; } /* It's possible that we end up without any candidates */ @@ -629,8 +738,25 @@ PJ_DEF(pj_status_t) pj_ice_strans_create( const char *name, &ice_st_on_destroy); pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg); - ice_st->cfg.stun.cfg.grp_lock = ice_st->grp_lock; - ice_st->cfg.turn.cfg.grp_lock = ice_st->grp_lock; + + /* To maintain backward compatibility, check if old/deprecated setting is set + * and the new setting is not, copy the value to the new setting. + */ + if (cfg->stun_tp_cnt == 0 && + (cfg->stun.server.slen || cfg->stun.max_host_cands)) + { + ice_st->cfg.stun_tp_cnt = 1; + ice_st->cfg.stun_tp[0] = ice_st->cfg.stun; + } + if (cfg->turn_tp_cnt == 0 && cfg->turn.server.slen) { + ice_st->cfg.turn_tp_cnt = 1; + ice_st->cfg.turn_tp[0] = ice_st->cfg.turn; + } + + for (i=0; i<ice_st->cfg.stun_tp_cnt; ++i) + ice_st->cfg.stun_tp[i].cfg.grp_lock = ice_st->grp_lock; + for (i=0; i<ice_st->cfg.turn_tp_cnt; ++i) + ice_st->cfg.turn_tp[i].cfg.grp_lock = ice_st->grp_lock; pj_memcpy(&ice_st->cb, cb, sizeof(*cb)); ice_st->comp_cnt = comp_cnt; @@ -708,13 +834,19 @@ static void destroy_ice_st(pj_ice_strans *ice_st) /* Destroy all components */ for (i=0; i<ice_st->comp_cnt; ++i) { if (ice_st->comp[i]) { - if (ice_st->comp[i]->stun_sock) { - pj_stun_sock_destroy(ice_st->comp[i]->stun_sock); - ice_st->comp[i]->stun_sock = NULL; + pj_ice_strans_comp *comp = ice_st->comp[i]; + unsigned j; + for (j = 0; j < ice_st->cfg.stun_tp_cnt; ++j) { + if (comp->stun[j].sock) { + pj_stun_sock_destroy(comp->stun[j].sock); + comp->stun[j].sock = NULL; + } } - if (ice_st->comp[i]->turn_sock) { - pj_turn_sock_destroy(ice_st->comp[i]->turn_sock); - ice_st->comp[i]->turn_sock = NULL; + for (j = 0; j < ice_st->cfg.turn_tp_cnt; ++j) { + if (comp->turn[j].sock) { + pj_turn_sock_destroy(comp->turn[j].sock); + comp->turn[j].sock = NULL; + } } } } @@ -911,12 +1043,16 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st, pj_ice_strans_comp *comp = ice_st->comp[i]; /* Re-enable logging for Send/Data indications */ - if (comp->turn_sock) { + if (ice_st->cfg.turn_tp_cnt) { PJ_LOG(5,(ice_st->obj_name, - "Disabling STUN Indication logging for " + "Enabling STUN Indication logging for " "component %d", i+1)); - pj_turn_sock_set_log(comp->turn_sock, 0xFFFF); - comp->turn_log_off = PJ_FALSE; + } + for (j = 0; j < ice_st->cfg.turn_tp_cnt; ++j) { + if (comp->turn[j].sock) { + pj_turn_sock_set_log(comp->turn[j].sock, 0xFFFF); + comp->turn[j].log_off = PJ_FALSE; + } } for (j=0; j<comp->cand_cnt; ++j) { @@ -1122,6 +1258,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st, unsigned rem_cand_cnt, const pj_ice_sess_cand rem_cand[]) { + unsigned n; pj_status_t status; PJ_ASSERT_RETURN(ice_st && rem_ufrag && rem_passwd && @@ -1137,7 +1274,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st, return status; /* If we have TURN candidate, now is the time to create the permissions */ - if (ice_st->comp[0]->turn_sock) { + for (n = 0; n < ice_st->cfg.turn_tp_cnt; ++n) { unsigned i; for (i=0; i<ice_st->comp_cnt; ++i) { @@ -1147,14 +1284,16 @@ PJ_DEF(pj_status_t) pj_ice_strans_start_ice( pj_ice_strans *ice_st, /* Gather remote addresses for this component */ for (j=0; j<rem_cand_cnt && count<PJ_ARRAY_SIZE(addrs); ++j) { - if (rem_cand[j].comp_id==i+1) { - pj_memcpy(&addrs[count++], &rem_cand[j].addr, - pj_sockaddr_get_len(&rem_cand[j].addr)); + if (rem_cand[j].comp_id==i+1 && + rem_cand[j].addr.addr.sa_family== + ice_st->cfg.turn_tp[n].af) + { + pj_sockaddr_cp(&addrs[count++], &rem_cand[j].addr); } } if (count) { - status = pj_turn_sock_set_perm(comp->turn_sock, count, + status = pj_turn_sock_set_perm(comp->turn[n].sock, count, addrs, 0); if (status != PJ_SUCCESS) { pj_ice_strans_stop_ice(ice_st); @@ -1227,7 +1366,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, int dst_addr_len) { pj_ice_strans_comp *comp; - unsigned def_cand; + pj_ice_sess_cand *def_cand; pj_status_t status; PJ_ASSERT_RETURN(ice_st && comp_id && comp_id <= ice_st->comp_cnt && @@ -1236,8 +1375,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, comp = ice_st->comp[comp_id-1]; /* Check that default candidate for the component exists */ - def_cand = comp->default_cand; - if (def_cand >= comp->cand_cnt) + if (comp->default_cand >= comp->cand_cnt) return PJ_EINVALIDOP; /* Protect with group lock, since this may cause race condition with @@ -1261,10 +1399,13 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, } pj_grp_lock_release(ice_st->grp_lock); + + def_cand = &comp->cand_list[comp->default_cand]; - if (comp->cand_list[def_cand].status == PJ_SUCCESS) { + if (def_cand->status == PJ_SUCCESS) { + unsigned tp_idx = GET_TP_IDX(def_cand->transport_id); - if (comp->cand_list[def_cand].type == PJ_ICE_CAND_TYPE_RELAYED) { + if (def_cand->type == PJ_ICE_CAND_TYPE_RELAYED) { enum { msg_disable_ind = 0xFFFF & @@ -1273,28 +1414,29 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto( pj_ice_strans *ice_st, }; /* https://trac.pjsip.org/repos/ticket/1316 */ - if (comp->turn_sock == NULL) { + if (comp->turn[tp_idx].sock == NULL) { /* TURN socket error */ return PJ_EINVALIDOP; } - if (!comp->turn_log_off) { + if (!comp->turn[tp_idx].log_off) { /* Disable logging for Send/Data indications */ PJ_LOG(5,(ice_st->obj_name, "Disabling STUN Indication logging for " "component %d", comp->comp_id)); - pj_turn_sock_set_log(comp->turn_sock, msg_disable_ind); - comp->turn_log_off = PJ_TRUE; + pj_turn_sock_set_log(comp->turn[tp_idx].sock, + msg_disable_ind); + comp->turn[tp_idx].log_off = PJ_TRUE; } - status = pj_turn_sock_sendto(comp->turn_sock, + status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, (const pj_uint8_t*)data, (unsigned)data_len, dst_addr, dst_addr_len); return (status==PJ_SUCCESS||status==PJ_EPENDING) ? PJ_SUCCESS : status; } else { - status = pj_stun_sock_sendto(comp->stun_sock, NULL, data, + status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, data, (unsigned)data_len, 0, dst_addr, dst_addr_len); return (status==PJ_SUCCESS||status==PJ_EPENDING) ? @@ -1342,23 +1484,26 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status) for (i=0; i<ice_st->comp_cnt; ++i) { const pj_ice_sess_check *check; + pj_ice_strans_comp *comp = ice_st->comp[i]; check = pj_ice_strans_get_valid_pair(ice_st, i+1); if (check) { char lip[PJ_INET6_ADDRSTRLEN+10]; char rip[PJ_INET6_ADDRSTRLEN+10]; + unsigned tp_idx = GET_TP_IDX(check->lcand->transport_id); + unsigned tp_typ = GET_TP_TYPE(check->lcand->transport_id); pj_sockaddr_print(&check->lcand->addr, lip, sizeof(lip), 3); pj_sockaddr_print(&check->rcand->addr, rip, sizeof(rip), 3); - if (check->lcand->transport_id == TP_TURN) { + if (tp_typ == TP_TURN) { /* Activate channel binding for the remote address * for more efficient data transfer using TURN. */ status = pj_turn_sock_bind_channel( - ice_st->comp[i]->turn_sock, + comp->turn[tp_idx].sock, &check->rcand->addr, sizeof(check->rcand->addr)); @@ -1366,9 +1511,9 @@ static void on_ice_complete(pj_ice_sess *ice, pj_status_t status) PJ_LOG(5,(ice_st->obj_name, "Disabling STUN Indication logging for " "component %d", i+1)); - pj_turn_sock_set_log(ice_st->comp[i]->turn_sock, + pj_turn_sock_set_log(comp->turn[tp_idx].sock, msg_disable_ind); - ice_st->comp[i]->turn_log_off = PJ_TRUE; + comp->turn[tp_idx].log_off = PJ_TRUE; } PJ_LOG(4,(ice_st->obj_name, " Comp %d: " @@ -1416,6 +1561,8 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, #if defined(ENABLE_TRACE) && (ENABLE_TRACE != 0) char daddr[PJ_INET6_ADDRSTRLEN]; #endif + unsigned tp_idx = GET_TP_IDX(transport_id); + unsigned tp_typ = GET_TP_TYPE(transport_id); PJ_ASSERT_RETURN(comp_id && comp_id <= ice_st->comp_cnt, PJ_EINVAL); @@ -1426,19 +1573,19 @@ static pj_status_t ice_tx_pkt(pj_ice_sess *ice, comp_id, pj_sockaddr_print(dst_addr, daddr, sizeof(addr), 0), pj_sockaddr_get_port(dst_addr), - transport_id)); + tp_typ)); - if (transport_id == TP_TURN) { - if (comp->turn_sock) { - status = pj_turn_sock_sendto(comp->turn_sock, + if (tp_typ == TP_TURN) { + if (comp->turn[tp_idx].sock) { + status = pj_turn_sock_sendto(comp->turn[tp_idx].sock, (const pj_uint8_t*)pkt, (unsigned)size, dst_addr, dst_addr_len); } else { status = PJ_EINVALIDOP; } - } else if (transport_id == TP_STUN) { - status = pj_stun_sock_sendto(comp->stun_sock, NULL, + } else if (tp_typ == TP_STUN) { + status = pj_stun_sock_sendto(comp->stun[tp_idx].sock, NULL, pkt, (unsigned)size, 0, dst_addr, dst_addr_len); } else { @@ -1478,16 +1625,18 @@ static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, const pj_sockaddr_t *src_addr, unsigned addr_len) { + sock_user_data *data; pj_ice_strans_comp *comp; pj_ice_strans *ice_st; pj_status_t status; - comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); - if (comp == NULL) { + data = (sock_user_data*) pj_stun_sock_get_user_data(stun_sock); + if (data == NULL) { /* We have disassociated ourselves from the STUN socket */ return PJ_FALSE; } + comp = data->comp; ice_st = comp->ice_st; pj_grp_lock_add_ref(ice_st->grp_lock); @@ -1506,7 +1655,8 @@ static pj_bool_t stun_on_rx_data(pj_stun_sock *stun_sock, /* Hand over the packet to ICE session */ status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, - TP_STUN, pkt, pkt_len, + data->transport_id, + pkt, pkt_len, src_addr, addr_len); if (status != PJ_SUCCESS) { @@ -1536,14 +1686,17 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, pj_stun_sock_op op, pj_status_t status) { + sock_user_data *data; pj_ice_strans_comp *comp; pj_ice_strans *ice_st; pj_ice_sess_cand *cand = NULL; unsigned i; + int tp_idx; pj_assert(status != PJ_EPENDING); - comp = (pj_ice_strans_comp*) pj_stun_sock_get_user_data(stun_sock); + data = (sock_user_data*) pj_stun_sock_get_user_data(stun_sock); + comp = data->comp; ice_st = comp->ice_st; pj_grp_lock_add_ref(ice_st->grp_lock); @@ -1553,7 +1706,9 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, /* Find the srflx cancidate */ for (i=0; i<comp->cand_cnt; ++i) { - if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX) { + if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_SRFLX && + comp->cand_list[i].transport_id == data->transport_id) + { cand = &comp->cand_list[i]; break; } @@ -1569,13 +1724,15 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE; } + tp_idx = GET_TP_IDX(data->transport_id); + switch (op) { case PJ_STUN_SOCK_DNS_OP: if (status != PJ_SUCCESS) { /* May not have cand, e.g. when error during init */ if (cand) cand->status = status; - if (!ice_st->cfg.stun.ignore_stun_error) { + if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error) { sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, "DNS resolution failed", status); } else { @@ -1655,7 +1812,9 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, /* May not have cand, e.g. when error during init */ if (cand) cand->status = status; - if (!ice_st->cfg.stun.ignore_stun_error || comp->cand_cnt==1) { + if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error || + comp->cand_cnt==1) + { sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, "STUN binding request failed", status); } else { @@ -1680,7 +1839,7 @@ static pj_bool_t stun_on_status(pj_stun_sock *stun_sock, if (status != PJ_SUCCESS) { pj_assert(cand != NULL); cand->status = status; - if (!ice_st->cfg.stun.ignore_stun_error) { + if (!ice_st->cfg.stun_tp[tp_idx].ignore_stun_error) { sess_fail(ice_st, PJ_ICE_STRANS_OP_INIT, "STUN keep-alive failed", status); } else { @@ -1701,14 +1860,17 @@ static void turn_on_rx_data(pj_turn_sock *turn_sock, unsigned addr_len) { pj_ice_strans_comp *comp; + sock_user_data *data; pj_status_t status; - comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); - if (comp == NULL) { + data = (sock_user_data*) pj_turn_sock_get_user_data(turn_sock); + if (data == NULL) { /* We have disassociated ourselves from the TURN socket */ return; } + comp = data->comp; + pj_grp_lock_add_ref(comp->ice_st->grp_lock); if (comp->ice_st->ice == NULL) { @@ -1726,7 +1888,7 @@ static void turn_on_rx_data(pj_turn_sock *turn_sock, /* Hand over the packet to ICE */ status = pj_ice_sess_on_rx_pkt(comp->ice_st->ice, comp->comp_id, - TP_TURN, pkt, pkt_len, + data->transport_id, pkt, pkt_len, peer_addr, addr_len); if (status != PJ_SUCCESS) { @@ -1745,15 +1907,20 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, pj_turn_state_t new_state) { pj_ice_strans_comp *comp; + sock_user_data *data; + int tp_idx; - comp = (pj_ice_strans_comp*) pj_turn_sock_get_user_data(turn_sock); - if (comp == NULL) { + data = (sock_user_data*) pj_turn_sock_get_user_data(turn_sock); + if (data == NULL) { /* Not interested in further state notification once the relay is * disconnecting. */ return; } + comp = data->comp; + tp_idx = GET_TP_IDX(data->transport_id); + PJ_LOG(5,(comp->ice_st->obj_name, "TURN client state changed %s --> %s", pj_turn_state_name(old_state), pj_turn_state_name(new_state))); pj_log_push_indent(); @@ -1766,7 +1933,7 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, pj_ice_sess_cand *cand = NULL; unsigned i; - comp->turn_err_cnt = 0; + comp->turn[tp_idx].err_cnt = 0; /* Get allocation info */ pj_turn_sock_get_info(turn_sock, &rel_info); @@ -1776,7 +1943,9 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, /* Find relayed candidate in the component */ for (i=0; i<comp->cand_cnt; ++i) { - if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED) { + if (comp->cand_list[i].type == PJ_ICE_CAND_TYPE_RELAYED && + comp->cand_list[i].transport_id == data->transport_id) + { cand = &comp->cand_list[i]; break; } @@ -1808,13 +1977,13 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, } else if (new_state >= PJ_TURN_STATE_DEALLOCATING) { pj_turn_session_info info; - ++comp->turn_err_cnt; + ++comp->turn[tp_idx].err_cnt; pj_turn_sock_get_info(turn_sock, &info); /* Unregister ourself from the TURN relay */ pj_turn_sock_set_user_data(turn_sock, NULL); - comp->turn_sock = NULL; + comp->turn[tp_idx].sock = NULL; /* Set session to fail on error. last_status PJ_SUCCESS means normal * deallocation, which should not trigger sess_fail as it may have @@ -1824,14 +1993,14 @@ static void turn_on_state(pj_turn_sock *turn_sock, pj_turn_state_t old_state, if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) { sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT, "TURN allocation failed", info.last_status); - } else if (comp->turn_err_cnt > 1) { + } else if (comp->turn[tp_idx].err_cnt > 1) { sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE, "TURN refresh failed", info.last_status); } else { PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status, "Comp %d: TURN allocation failed, retrying", comp->comp_id)); - add_update_turn(comp->ice_st, comp); + add_update_turn(comp->ice_st, comp, tp_idx); } } } |