Index: pjproject/trunk/pjnath/src/pjnath/ice.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1094)
+++ pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1096)
@@ -22,4 +22,5 @@
 #include <pj/array.h>
 #include <pj/assert.h>
+#include <pj/guid.h>
 #include <pj/log.h>
 #include <pj/os.h>
@@ -69,6 +70,6 @@
 {
     pj_ice	*ice;
-    unsigned	 comp_id;
-    pj_ice_comp	*comp;
+    unsigned	 lcand_id;
+    pj_ice_cand	*lcand;
 } stun_data;
 
@@ -133,12 +134,19 @@
 
 
+/*
+ * 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;
@@ -146,5 +154,5 @@
     PJ_ASSERT_RETURN(stun_cfg && cb && p_ice, PJ_EINVAL);
 
-    if (!name)
+    if (name == NULL)
 	name = "ice%p";
 
@@ -171,8 +179,24 @@
     }
 
+    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;
@@ -180,4 +204,7 @@
 
 
+/*
+ * Destroy
+ */
 static void destroy_ice(pj_ice *ice,
 			pj_status_t reason)
@@ -190,9 +217,11 @@
 
     for (i=0; i<ice->comp_cnt; ++i) {
-	pj_ice_comp *comp = &ice->comp[i];
-
-	if (comp->stun_sess) {
-	    pj_stun_session_destroy(comp->stun_sess);
-	    comp->stun_sess = NULL;
+	/* Nothing to do */
+    }
+
+    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;
 	}
     }
@@ -223,4 +252,5 @@
 
 
+/* Find component by ID */
 static pj_ice_comp *find_comp(const pj_ice *ice, unsigned comp_id)
 {
@@ -228,5 +258,5 @@
     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];
     }
 
@@ -235,17 +265,12 @@
 
 
-PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice,
-				    unsigned comp_id,
-				    const pj_sockaddr_t *local_addr,
-				    unsigned addr_len)
-{
-    pj_stun_session_cb sess_cb;
+/* Add a new component */
+PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice, unsigned comp_id)
+{
     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);
 
@@ -255,38 +280,4 @@
     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 */
@@ -409,40 +400,4 @@
 
 
-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,
@@ -463,4 +418,7 @@
 
 
+/*
+ * Add ICE candidate
+ */
 PJ_DEF(pj_status_t) pj_ice_add_cand(pj_ice *ice,
 				    unsigned comp_id,
@@ -475,4 +433,7 @@
 {
     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];
@@ -501,6 +462,37 @@
 	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));
@@ -518,4 +510,7 @@
 	 (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;
@@ -1042,16 +1037,39 @@
 
 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 */
@@ -1155,5 +1173,5 @@
 
     /* 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)
@@ -1187,5 +1205,5 @@
 
     /* 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);
@@ -1332,5 +1350,5 @@
 {
     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);
@@ -1535,5 +1553,6 @@
     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,24 +1640,4 @@
     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
@@ -1759,4 +1758,5 @@
     pj_status_t status = PJ_SUCCESS;
     pj_ice_comp *comp;
+    unsigned cand_id;
     pj_ice_check *check;
 
@@ -1777,6 +1777,7 @@
 
     check = &ice->clist.checks[comp->nominated_check_id];
-
-    status = (*ice->cb.on_tx_pkt)(ice, comp_id, data, data_len, 
+    cand_id = GET_LCAND_ID(check->lcand);
+
+    status = (*ice->cb.on_tx_pkt)(ice, comp_id, cand_id, data, data_len, 
 				  &check->rcand->addr, 
 				  sizeof(pj_sockaddr_in));
@@ -1790,4 +1791,5 @@
 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,
@@ -1797,4 +1799,5 @@
     pj_status_t status = PJ_SUCCESS;
     pj_ice_comp *comp;
+    pj_ice_cand *lcand;
     pj_status_t stun_status;
 
@@ -1809,12 +1812,14 @@
     }
 
+    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);
     }
     
