summaryrefslogtreecommitdiff
path: root/pjnath
diff options
context:
space:
mode:
authorNanang Izzuddin <nanang@teluu.com>2016-06-08 03:17:45 +0000
committerNanang Izzuddin <nanang@teluu.com>2016-06-08 03:17:45 +0000
commita44bcadfa1bc4c3a6067c5921d8eda10d7b24d10 (patch)
treebc9e0af584e8ee4f4a1aa8a16690bfdbe5d5fc43 /pjnath
parentfd7ff41eec38181ba154286ca312a16b965aa07c (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.h22
-rw-r--r--pjnath/include/pjnath/ice_session.h2
-rw-r--r--pjnath/include/pjnath/ice_strans.h339
-rw-r--r--pjnath/include/pjnath/stun_sock.h2
-rw-r--r--pjnath/src/pjnath-test/concur_test.c5
-rw-r--r--pjnath/src/pjnath/ice_session.c18
-rw-r--r--pjnath/src/pjnath/ice_strans.c703
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);
}
}
}