summaryrefslogtreecommitdiff
path: root/pjnath/src/pjnath/ice.c
diff options
context:
space:
mode:
Diffstat (limited to 'pjnath/src/pjnath/ice.c')
-rw-r--r--pjnath/src/pjnath/ice.c243
1 files changed, 124 insertions, 119 deletions
diff --git a/pjnath/src/pjnath/ice.c b/pjnath/src/pjnath/ice.c
index de781706..9fb59238 100644
--- a/pjnath/src/pjnath/ice.c
+++ b/pjnath/src/pjnath/ice.c
@@ -21,6 +21,7 @@
#include <pj/addr_resolv.h>
#include <pj/array.h>
#include <pj/assert.h>
+#include <pj/guid.h>
#include <pj/log.h>
#include <pj/os.h>
#include <pj/pool.h>
@@ -68,8 +69,8 @@ const pj_str_t peer_mapped_foundation = {"peer", 4};
typedef struct stun_data
{
pj_ice *ice;
- unsigned comp_id;
- pj_ice_comp *comp;
+ unsigned lcand_id;
+ pj_ice_cand *lcand;
} stun_data;
typedef struct timer_data
@@ -132,20 +133,27 @@ static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg,
const pj_str_t *nonce);
+/*
+ * Create ICE stream session.
+ */
PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg,
const char *name,
pj_ice_role role,
const pj_ice_cb *cb,
+ const pj_str_t *local_ufrag,
+ const pj_str_t *local_passwd,
pj_ice **p_ice)
{
pj_pool_t *pool;
pj_ice *ice;
+ char tmp[32];
+ pj_str_t s;
unsigned i;
pj_status_t status;
PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
- if (!name)
+ if (name == NULL)
name = "ice%p";
pool = pj_pool_create(stun_cfg->pf, name, 4000, 4000, NULL);
@@ -170,15 +178,34 @@ PJ_DEF(pj_status_t) pj_ice_create(pj_stun_config *stun_cfg,
ice->comp[i].nominated_check_id = -1;
}
+ if (local_ufrag == NULL) {
+ pj_ansi_snprintf(tmp, sizeof(tmp), "%x", pj_rand());
+ s = pj_str(tmp);
+ local_ufrag = &s;
+ }
+ pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
+
+ if (local_passwd == NULL) {
+ pj_ansi_snprintf(tmp, sizeof(tmp), "%x", pj_rand());
+ s = pj_str(tmp);
+ local_passwd = &s;
+ }
+ pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
+
+
/* Done */
*p_ice = ice;
- LOG((ice->obj_name, "ICE media stream created"));
+ LOG((ice->obj_name, "ICE stream session created, role is %s agent",
+ (ice->role==PJ_ICE_ROLE_CONTROLLING ? "controlling" : "controlled")));
return PJ_SUCCESS;
}
+/*
+ * Destroy
+ */
static void destroy_ice(pj_ice *ice,
pj_status_t reason)
{
@@ -189,11 +216,13 @@ static void destroy_ice(pj_ice *ice,
}
for (i=0; i<ice->comp_cnt; ++i) {
- pj_ice_comp *comp = &ice->comp[i];
+ /* Nothing to do */
+ }
- if (comp->stun_sess) {
- pj_stun_session_destroy(comp->stun_sess);
- comp->stun_sess = NULL;
+ for (i=0; i<ice->lcand_cnt; ++i) {
+ if (ice->lcand[i].stun_sess) {
+ pj_stun_session_destroy(ice->lcand[i].stun_sess);
+ ice->lcand[i].stun_sess = NULL;
}
}
@@ -222,31 +251,27 @@ PJ_DEF(pj_status_t) pj_ice_destroy(pj_ice *ice)
}
+/* Find component by ID */
static pj_ice_comp *find_comp(const pj_ice *ice, unsigned comp_id)
{
unsigned i;
for (i=0; i<ice->comp_cnt; ++i) {
if (ice->comp[i].comp_id == comp_id)
- return (pj_ice_comp*) &ice->comp[i];
+ return (pj_ice_comp *) &ice->comp[i];
}
return NULL;
}
-PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice,
- unsigned comp_id,
- const pj_sockaddr_t *local_addr,
- unsigned addr_len)
+/* Add a new component */
+PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice, unsigned comp_id)
{
- pj_stun_session_cb sess_cb;
pj_ice_comp *comp;
- pj_stun_auth_cred auth_cred;
- stun_data *sd;
- pj_status_t status;
- PJ_ASSERT_RETURN(ice && local_addr && addr_len, PJ_EINVAL);
+ PJ_ASSERT_RETURN(ice && comp_id, PJ_EINVAL);
PJ_ASSERT_RETURN(ice->comp_cnt < PJ_ARRAY_SIZE(ice->comp), PJ_ETOOMANY);
+ PJ_ASSERT_RETURN(comp_id==ice->comp_cnt+1, PJ_EICEINCOMPID);
PJ_ASSERT_RETURN(find_comp(ice, comp_id) == NULL, PJ_EEXISTS);
pj_mutex_lock(ice->mutex);
@@ -254,40 +279,6 @@ PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice,
comp = &ice->comp[ice->comp_cnt];
comp->comp_id = comp_id;
comp->nominated_check_id = -1;
- pj_memcpy(&comp->local_addr, local_addr, addr_len);
-
- /* Init STUN callbacks */
- pj_bzero(&sess_cb, sizeof(sess_cb));
- sess_cb.on_request_complete = &on_stun_request_complete;
- sess_cb.on_rx_indication = &on_stun_rx_indication;
- sess_cb.on_rx_request = &on_stun_rx_request;
- sess_cb.on_send_msg = &on_stun_send_msg;
-
- /* Create STUN session for this component */
- status = pj_stun_session_create(&ice->stun_cfg, ice->obj_name,
- &sess_cb, PJ_FALSE,
- &comp->stun_sess);
- if (status != PJ_SUCCESS) {
- pj_mutex_unlock(ice->mutex);
- return status;
- }
-
- /* Associate data with this STUN session */
- sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data);
- sd->ice = ice;
- sd->comp_id = comp_id;
- sd->comp = comp;
- pj_stun_session_set_user_data(comp->stun_sess, sd);
-
- /* Init STUN authentication credential */
- pj_bzero(&auth_cred, sizeof(auth_cred));
- auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
- auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth;
- auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred;
- auth_cred.data.dyn_cred.get_password = &stun_auth_get_password;
- auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce;
- auth_cred.data.dyn_cred.user_data = comp->stun_sess;
- pj_stun_session_set_credential(comp->stun_sess, &auth_cred);
/* Done */
ice->comp_cnt++;
@@ -408,42 +399,6 @@ static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg,
}
-PJ_DEF(pj_status_t) pj_ice_set_credentials(pj_ice *ice,
- const pj_str_t *local_ufrag,
- const pj_str_t *local_pass,
- const pj_str_t *remote_ufrag,
- const pj_str_t *remote_pass)
-{
- char buf[128];
- pj_str_t username;
-
- username.ptr = buf;
-
- PJ_ASSERT_RETURN(ice && local_ufrag && local_pass &&
- remote_ufrag && remote_pass, PJ_EINVAL);
- PJ_ASSERT_RETURN(local_ufrag->slen + remote_ufrag->slen <
- sizeof(buf), PJ_ENAMETOOLONG);
-
- pj_strcpy(&username, remote_ufrag);
- pj_strcat2(&username, ":");
- pj_strcat(&username, local_ufrag);
-
- pj_strdup(ice->pool, &ice->tx_uname, &username);
- pj_strdup(ice->pool, &ice->tx_ufrag, remote_ufrag);
- pj_strdup(ice->pool, &ice->tx_pass, remote_pass);
-
- pj_strcpy(&username, local_ufrag);
- pj_strcat2(&username, ":");
- pj_strcat(&username, remote_ufrag);
-
- pj_strdup(ice->pool, &ice->rx_uname, &username);
- pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
- pj_strdup(ice->pool, &ice->rx_pass, local_pass);
-
- return PJ_SUCCESS;
-}
-
-
static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type,
pj_uint32_t local_pref,
pj_uint32_t comp_id)
@@ -462,6 +417,9 @@ static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type,
}
+/*
+ * Add ICE candidate
+ */
PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice,
unsigned comp_id,
pj_ice_cand_type type,
@@ -474,6 +432,9 @@ PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice,
unsigned *p_cand_id)
{
pj_ice_cand *lcand;
+ pj_stun_session_cb sess_cb;
+ pj_stun_auth_cred auth_cred;
+ stun_data *sd;
pj_status_t status = PJ_SUCCESS;
char tmp[128];
@@ -500,8 +461,39 @@ PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice,
else
pj_bzero(&lcand->srv_addr, sizeof(lcand->srv_addr));
- if (p_cand_id)
- *p_cand_id = ice->lcand_cnt;
+ /* Init STUN callbacks */
+ pj_bzero(&sess_cb, sizeof(sess_cb));
+ sess_cb.on_request_complete = &on_stun_request_complete;
+ sess_cb.on_rx_indication = &on_stun_rx_indication;
+ sess_cb.on_rx_request = &on_stun_rx_request;
+ sess_cb.on_send_msg = &on_stun_send_msg;
+
+ /* Create STUN session for this candidate */
+ status = pj_stun_session_create(&ice->stun_cfg, ice->obj_name,
+ &sess_cb, PJ_FALSE,
+ &lcand->stun_sess);
+ if (status != PJ_SUCCESS) {
+ pj_mutex_unlock(ice->mutex);
+ return status;
+ }
+
+ /* Associate data with this STUN session */
+ sd = PJ_POOL_ZALLOC_T(ice->pool, struct stun_data);
+ sd->ice = ice;
+ sd->lcand_id = GET_LCAND_ID(lcand);
+ sd->lcand = lcand;
+ pj_stun_session_set_user_data(lcand->stun_sess, sd);
+
+ /* Init STUN authentication credential */
+ pj_bzero(&auth_cred, sizeof(auth_cred));
+ auth_cred.type = PJ_STUN_AUTH_CRED_DYNAMIC;
+ auth_cred.data.dyn_cred.get_auth = &stun_auth_get_auth;
+ auth_cred.data.dyn_cred.get_cred = &stun_auth_get_cred;
+ auth_cred.data.dyn_cred.get_password = &stun_auth_get_password;
+ auth_cred.data.dyn_cred.verify_nonce = &stun_auth_verify_nonce;
+ auth_cred.data.dyn_cred.user_data = lcand->stun_sess;
+ pj_stun_session_set_credential(lcand->stun_sess, &auth_cred);
+
pj_ansi_strcpy(tmp, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
LOG((ice->obj_name,
@@ -518,6 +510,9 @@ PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice,
(int)pj_htons(lcand->base_addr.ipv4.sin_port),
lcand->prio, lcand->prio));
+ if (p_cand_id)
+ *p_cand_id = ice->lcand_cnt;
+
++ice->lcand_cnt;
on_error:
@@ -1041,19 +1036,42 @@ static pj_bool_t on_check_complete(pj_ice *ice,
PJ_DEF(pj_status_t) pj_ice_create_check_list(pj_ice *ice,
+ const pj_str_t *rem_ufrag,
+ const pj_str_t *rem_passwd,
unsigned rcand_cnt,
const pj_ice_cand rcand[])
{
pj_ice_checklist *clist;
+ char buf[128];
+ pj_str_t username;
timer_data *td;
unsigned i, j;
- PJ_ASSERT_RETURN(ice && rcand_cnt && rcand, PJ_EINVAL);
+ PJ_ASSERT_RETURN(ice && rem_ufrag && rem_passwd && rcand_cnt && rcand,
+ PJ_EINVAL);
PJ_ASSERT_RETURN(rcand_cnt + ice->rcand_cnt <= PJ_ICE_MAX_CAND,
PJ_ETOOMANY);
pj_mutex_lock(ice->mutex);
+ /* Save credentials */
+ username.ptr = buf;
+
+ pj_strcpy(&username, rem_ufrag);
+ pj_strcat2(&username, ":");
+ pj_strcat(&username, &ice->rx_ufrag);
+
+ pj_strdup(ice->pool, &ice->tx_uname, &username);
+ pj_strdup(ice->pool, &ice->tx_ufrag, rem_ufrag);
+ pj_strdup(ice->pool, &ice->tx_pass, rem_passwd);
+
+ pj_strcpy(&username, &ice->rx_ufrag);
+ pj_strcat2(&username, ":");
+ pj_strcat(&username, rem_ufrag);
+
+ pj_strdup(ice->pool, &ice->rx_uname, &username);
+
+
/* Save remote candidates */
ice->rcand_cnt = 0;
for (i=0; i<rcand_cnt; ++i) {
@@ -1154,7 +1172,7 @@ static pj_status_t perform_check(pj_ice *ice, pj_ice_checklist *clist,
dump_check(buffer, sizeof(buffer), ice, check)));
/* Create request */
- status = pj_stun_session_create_req(comp->stun_sess,
+ status = pj_stun_session_create_req(lcand->stun_sess,
PJ_STUN_BINDING_REQUEST, &tdata);
if (status != PJ_SUCCESS)
return status;
@@ -1186,7 +1204,7 @@ static pj_status_t perform_check(pj_ice *ice, pj_ice_checklist *clist,
*/
/* Initiate STUN transaction to send the request */
- status = pj_stun_session_send_msg(comp->stun_sess, PJ_FALSE,
+ status = pj_stun_session_send_msg(lcand->stun_sess, PJ_FALSE,
&rcand->addr,
sizeof(pj_sockaddr_in), tdata);
if (status != PJ_SUCCESS)
@@ -1331,7 +1349,7 @@ static pj_status_t on_stun_send_msg(pj_stun_session *sess,
unsigned addr_len)
{
stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
- return (*sd->ice->cb.on_tx_pkt)(sd->ice, sd->comp_id,
+ return (*sd->ice->cb.on_tx_pkt)(sd->ice, sd->lcand->comp_id, sd->lcand_id,
pkt, pkt_size,
dst_addr, addr_len);
}
@@ -1534,7 +1552,8 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
sd = (stun_data*) pj_stun_session_get_user_data(sess);
ice = sd->ice;
- comp = sd->comp;
+ lcand = sd->lcand;
+ comp = find_comp(ice, lcand->comp_id);
pj_mutex_lock(ice->mutex);
@@ -1621,26 +1640,6 @@ static pj_status_t on_stun_rx_request(pj_stun_session *sess,
PJ_TODO(DETERMINE_IF_REQUEST_COMES_FROM_RELAYED_CANDIDATE);
is_relayed = PJ_FALSE;
- /* Next find local candidate, by first finding a check in the checklist
- * which base address is equal to the local address.
- */
- for (i=0; i<ice->clist.count; ++i) {
- pj_ice_check *c = &ice->clist.checks[i];
- if (sockaddr_cmp(&c->lcand->base_addr, &comp->local_addr)==0)
- break;
- }
-
- /* MUST find a local candidate! */
- pj_assert(i != ice->clist.count);
- if (i == ice->clist.count) {
- pj_mutex_unlock(ice->mutex);
- LOG((ice->obj_name, "Error: unable to find local candidate for "
- "incoming request"));
- return PJ_SUCCESS;
- }
-
- lcand = ice->clist.checks[i].lcand;
-
/* Now that we have local and remote candidate, check if we already
* have this pair in our checklist.
*/
@@ -1758,6 +1757,7 @@ PJ_DEF(pj_status_t) pj_ice_send_data( pj_ice *ice,
{
pj_status_t status = PJ_SUCCESS;
pj_ice_comp *comp;
+ unsigned cand_id;
pj_ice_check *check;
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
@@ -1776,8 +1776,9 @@ PJ_DEF(pj_status_t) pj_ice_send_data( pj_ice *ice,
}
check = &ice->clist.checks[comp->nominated_check_id];
+ cand_id = GET_LCAND_ID(check->lcand);
- status = (*ice->cb.on_tx_pkt)(ice, comp_id, data, data_len,
+ status = (*ice->cb.on_tx_pkt)(ice, comp_id, cand_id, data, data_len,
&check->rcand->addr,
sizeof(pj_sockaddr_in));
@@ -1789,6 +1790,7 @@ on_return:
PJ_DEF(pj_status_t) pj_ice_on_rx_pkt( pj_ice *ice,
unsigned comp_id,
+ unsigned cand_id,
void *pkt,
pj_size_t pkt_size,
const pj_sockaddr_t *src_addr,
@@ -1796,6 +1798,7 @@ PJ_DEF(pj_status_t) pj_ice_on_rx_pkt( pj_ice *ice,
{
pj_status_t status = PJ_SUCCESS;
pj_ice_comp *comp;
+ pj_ice_cand *lcand;
pj_status_t stun_status;
PJ_ASSERT_RETURN(ice, PJ_EINVAL);
@@ -1808,14 +1811,16 @@ PJ_DEF(pj_status_t) pj_ice_on_rx_pkt( pj_ice *ice,
goto on_return;
}
+ lcand = &ice->lcand[cand_id];
+
stun_status = pj_stun_msg_check(pkt, pkt_size, PJ_STUN_IS_DATAGRAM);
if (stun_status == PJ_SUCCESS) {
- status = pj_stun_session_on_rx_pkt(comp->stun_sess, pkt, pkt_size,
+ status = pj_stun_session_on_rx_pkt(lcand->stun_sess, pkt, pkt_size,
PJ_STUN_IS_DATAGRAM,
NULL, src_addr, src_addr_len);
} else {
- status = (*ice->cb.on_rx_data)(ice, comp_id, pkt, pkt_size,
- src_addr, src_addr_len);
+ (*ice->cb.on_rx_data)(ice, comp_id, cand_id, pkt, pkt_size,
+ src_addr, src_addr_len);
}