Index: pjproject/trunk/pjnath/src/pjnath/ice.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1099)
+++ pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1101)
@@ -58,5 +58,6 @@
 
 #define CHECK_NAME_LEN	    128
-#define LOG(expr)	    PJ_LOG(4,expr)
+#define LOG4(expr)	    PJ_LOG(4,expr)
+#define LOG5(expr)	    PJ_LOG(4,expr)
 #define GET_LCAND_ID(cand)  (cand - ice->lcand)
 #define GET_CHECK_ID(chk)   (chk - ice->clist.checks)
@@ -136,4 +137,5 @@
 				  const char *name,
 				  pj_ice_role role,
+				  unsigned comp_cnt,
 				  const pj_ice_cb *cb,
 				  const pj_str_t *local_ufrag,
@@ -171,6 +173,10 @@
     pj_memcpy(&ice->stun_cfg, stun_cfg, sizeof(*stun_cfg));
 
-    for (i=0; i<PJ_ICE_MAX_COMP; ++i) {
-	ice->comp[i].nominated_check_id = -1;
+    ice->comp_cnt = comp_cnt;
+    for (i=0; i<comp_cnt; ++i) {
+	pj_ice_comp *comp;
+	comp = &ice->comp[i];
+	comp->comp_id = i+1;
+	comp->nominated_check_id = -1;
     }
 
@@ -193,6 +199,6 @@
     *p_ice = ice;
 
-    LOG((ice->obj_name, "ICE stream session created, role is %s agent",
-	(ice->role==PJ_ICE_ROLE_CONTROLLING ? "controlling" : "controlled")));
+    LOG4((ice->obj_name, "ICE stream session created, role is %s agent",
+	 (ice->role==PJ_ICE_ROLE_CONTROLLING ? "controlling" : "controlled")));
 
     return PJ_SUCCESS;
@@ -209,9 +215,5 @@
 
     if (reason == PJ_SUCCESS) {
-	LOG((ice->obj_name, "Destroying ICE session"));
-    }
-
-    for (i=0; i<ice->comp_cnt; ++i) {
-	/* Nothing to do */
+	LOG4((ice->obj_name, "Destroying ICE session"));
     }
 
@@ -251,36 +253,8 @@
 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 NULL;
-}
-
-
-/* Add a new component */
-PJ_DEF(pj_status_t) pj_ice_add_comp(pj_ice *ice, unsigned comp_id)
-{
-    pj_ice_comp *comp;
-
-    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);
-
-    comp = &ice->comp[ice->comp_cnt];
-    comp->comp_id = comp_id;
-    comp->nominated_check_id = -1;
-
-    /* Done */
-    ice->comp_cnt++;
-    pj_mutex_unlock(ice->mutex);
-
-    return PJ_SUCCESS;
-}
+    pj_assert(comp_id > 0 && comp_id <= ice->comp_cnt);
+    return (pj_ice_comp*) &ice->comp[comp_id-1];
+}
+
 
 static pj_status_t stun_auth_get_auth(void *user_data,
@@ -357,5 +331,5 @@
 	/* Verify username */
 	if (pj_strcmp(username, &ice->tx_uname) != 0)
-	    return -1;
+	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME);
 	*data_type = 0;
 	*data = ice->tx_pass;
@@ -408,7 +382,7 @@
     };
 
-    return ((1 << 24) * type_pref[type]) + 
-	   ((1 << 8) * local_pref) +
-	   (256 - comp_id);
+    return ((type_pref[type] & 0xFF) << 24) + 
+	   ((local_pref & 0xFFFF)    << 8) +
+	   (((256 - comp_id) & 0xFF) << 0);
 }
 
@@ -424,5 +398,5 @@
 				    const pj_sockaddr_t *addr,
 				    const pj_sockaddr_t *base_addr,
-				    const pj_sockaddr_t *srv_addr,
+				    const pj_sockaddr_t *rel_addr,
 				    int addr_len,
 				    unsigned *p_cand_id)
@@ -453,8 +427,8 @@
     pj_memcpy(&lcand->addr, addr, addr_len);
     pj_memcpy(&lcand->base_addr, base_addr, addr_len);
-    if (srv_addr)
-	pj_memcpy(&lcand->srv_addr, srv_addr, addr_len);
+    if (rel_addr)
+	pj_memcpy(&lcand->rel_addr, rel_addr, addr_len);
     else
-	pj_bzero(&lcand->srv_addr, sizeof(lcand->srv_addr));
+	pj_bzero(&lcand->rel_addr, sizeof(lcand->rel_addr));
 
     /* Init STUN callbacks */
@@ -493,5 +467,5 @@
 
     pj_ansi_strcpy(tmp, pj_inet_ntoa(lcand->addr.ipv4.sin_addr));
-    LOG((ice->obj_name, 
+    LOG4((ice->obj_name, 
 	 "Candidate %d added: comp_id=%d, type=%s, foundation=%.*s, "
 	 "addr=%s:%d, base=%s:%d, prio=0x%x (%u)",
@@ -518,50 +492,22 @@
 
 
-PJ_DEF(unsigned) pj_ice_get_cand_cnt(pj_ice *ice)
-{
-    return ice->lcand_cnt;
-}
-
-
-PJ_DEF(pj_status_t) pj_ice_enum_cands(pj_ice *ice,
-				      unsigned *p_count,
-				      unsigned cand_ids[])
-{
-    unsigned i, count;
-
-    PJ_ASSERT_RETURN(ice && p_count && *p_count && cand_ids, PJ_EINVAL);
+PJ_DEF(pj_status_t) pj_ice_find_default_cand(pj_ice *ice,
+					     unsigned comp_id,
+					     int *cand_id)
+{
+    unsigned i;
+
+    PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL);
+
+    *cand_id = -1;
 
     pj_mutex_lock(ice->mutex);
 
-    count = (*p_count < ice->lcand_cnt) ? *p_count : ice->lcand_cnt;
-    for (i=0; i<count; ++i)
-	cand_ids[i] = i;
-
-    *p_count = count;
-    pj_mutex_unlock(ice->mutex);
-
-    return PJ_SUCCESS;
-}
-
-
-PJ_DEF(pj_status_t) pj_ice_get_default_cand(pj_ice *ice,
-					    unsigned comp_id,
-					    int *cand_id)
-{
-    unsigned i;
-
-    PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL);
-
-    *cand_id = -1;
-
-    pj_mutex_lock(ice->mutex);
-
     /* First find in valid list if we have nominated pair */
-    for (i=0; i<ice->valid_cnt; ++i) {
-	pj_ice_cand *lcand;
+    for (i=0; i<ice->valid_list.count; ++i) {
+	pj_ice_check *check = &ice->valid_list.checks[i];
 	
-	lcand = ice->clist.checks[ice->valid_list[i]].lcand;
-	if (lcand->comp_id==comp_id) {
-	    *cand_id = GET_LCAND_ID(lcand);
+	if (check->lcand->comp_id == comp_id) {
+	    *cand_id = GET_LCAND_ID(check->lcand);
 	    pj_mutex_unlock(ice->mutex);
 	    return PJ_SUCCESS;
@@ -609,19 +555,7 @@
 
     pj_assert(!"Should have a candidate by now");
-    return PJ_EICENOCAND;
-}
-
-
-PJ_DEF(pj_status_t) pj_ice_get_cand(pj_ice *ice,
-				    unsigned cand_id,
-				    pj_ice_cand **p_cand)
-{
-    PJ_ASSERT_RETURN(ice && p_cand, PJ_EINVAL);
-    PJ_ASSERT_RETURN(cand_id <= ice->lcand_cnt, PJ_EINVAL);
-
-    *p_cand = &ice->lcand[cand_id];
-
-    return PJ_SUCCESS;
-}
+    return PJ_EBUG;
+}
+
 
 #ifndef MIN
@@ -690,8 +624,8 @@
     char buffer[CHECK_NAME_LEN];
 
-    LOG((ice->obj_name, "%s", title));
+    LOG4((ice->obj_name, "%s", title));
     for (i=0; i<clist->count; ++i) {
 	const pj_ice_check *c = &clist->checks[i];
-	LOG((ice->obj_name, " %s (%s, state=%s)",
+	LOG4((ice->obj_name, " %s (%s, state=%s)",
 	     dump_check(buffer, sizeof(buffer), ice, c),
 	     (c->nominated ? "nominated" : "not nominated"), 
@@ -700,19 +634,4 @@
 }
 
-static void dump_valid_list(const char *title, const pj_ice *ice)
-{
-    unsigned i;
-    char buffer[CHECK_NAME_LEN];
-
-    LOG((ice->obj_name, "%s", title));
-    for (i=0; i<ice->valid_cnt; ++i) {
-	const pj_ice_check *c = &ice->clist.checks[ice->valid_list[i]];
-	LOG((ice->obj_name, " %s (%s, state=%s)",
-	     dump_check(buffer, sizeof(buffer), ice, c),
-	     (c->nominated ? "nominated" : "not nominated"), 
-	     check_state_name[c->state]));
-    }
-}
-
 #else
 #define dump_checklist(ice, clist)
@@ -727,5 +646,5 @@
     pj_assert(check->state < PJ_ICE_CHECK_STATE_SUCCEEDED);
 
-    LOG((ice->obj_name, "Check %s: state changed from %s to %s",
+    LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
 	 dump_check(buf, sizeof(buf), ice, check),
 	 check_state_name[check->state],
@@ -739,5 +658,5 @@
 {
     if (clist->state != st) {
-	LOG((ice->obj_name, "Checklist: state changed from %s to %s",
+	LOG5((ice->obj_name, "Checklist: state changed from %s to %s",
 	     clist_state_name[clist->state],
 	     clist_state_name[st]));
@@ -769,30 +688,4 @@
     }
 }
-
-/* Sort valid list based on priority */
-static void sort_valid_list(pj_ice *ice)
-{
-    unsigned i;
-
-    for (i=0; i<ice->valid_cnt-1; ++i) {
-	unsigned j, highest = i;
-	pj_ice_check *ci = &ice->clist.checks[ice->valid_list[i]];
-
-	for (j=i+1; j<ice->valid_cnt; ++j) {
-	    pj_ice_check *cj = &ice->clist.checks[ice->valid_list[j]];
-
-	    if (cj->prio > ci->prio) {
-		highest = j;
-	    }
-	}
-
-	if (highest != i) {
-	    unsigned tmp = ice->valid_list[i];
-	    ice->valid_list[i] = ice->valid_list[j];
-	    ice->valid_list[j] = tmp;
-	}
-    }
-}
-
 
 enum 
@@ -866,5 +759,5 @@
 		char buf[CHECK_NAME_LEN];
 
-		LOG((ice->obj_name, "Check %s pruned",
+		LOG5((ice->obj_name, "Check %s pruned",
 		    dump_check(buf, sizeof(buf), ice, &clist->checks[j])));
 
@@ -890,9 +783,8 @@
     
 	/* Log message */
-	LOG((ice->obj_name, "ICE process complete, status=%s", 
+	LOG4((ice->obj_name, "ICE process complete, status=%s", 
 	     pj_strerror(status, errmsg, sizeof(errmsg)).ptr));
 
-	dump_checklist("Dumping checklist", ice, &ice->clist);
-	dump_valid_list("Dumping valid list", ice);
+	dump_checklist("Valid list", ice, &ice->valid_list);
 
 	/* Call callback */
@@ -922,5 +814,5 @@
 	pj_ice_comp *comp;
 
-	LOG((ice->obj_name, "Check %d is successful and nominated",
+	LOG5((ice->obj_name, "Check %d is successful and nominated",
 	     GET_CHECK_ID(check)));
 
@@ -931,5 +823,5 @@
 		 c->state==PJ_ICE_CHECK_STATE_WAITING))
 	    {
-		LOG((ice->obj_name, 
+		LOG5((ice->obj_name, 
 		     "Check %d to be failed because state is %s",
 		     i, check_state_name[c->state]));
@@ -982,20 +874,4 @@
 
 
-#if 0
-    /* For now, just see if we have a valid pair in component 1 and
-     * just terminate ICE.
-     */
-    for (i=0; i<ice->valid_cnt; ++i) {
-	pj_ice_check *c = &ice->clist.checks[ice->valid_list[i]];
-	if (c->lcand->comp_id == 1)
-	    break;
-    }
-
-    if (i != ice->valid_cnt) {
-	/* ICE succeeded */
-	on_ice_complete(ice, PJ_SUCCESS);
-	return PJ_TRUE;
-    }
-#else
     /* See if all components have nominated pair. If they do, then mark
      * ICE processing as success, otherwise wait.
@@ -1010,5 +886,4 @@
 	return PJ_TRUE;
     }
-#endif
 
     /* 
@@ -1025,5 +900,5 @@
     if (i == ice->clist.count) {
 	/* All checks have completed */
-	on_ice_complete(ice, -1);
+	on_ice_complete(ice, PJNATH_EICEFAILED);
 	return PJ_TRUE;
     }
@@ -1167,5 +1042,5 @@
     comp = find_comp(ice, lcand->comp_id);
 
-    LOG((ice->obj_name, 
+    LOG5((ice->obj_name, 
 	 "Sending connectivity check for check %s", 
 	 dump_check(buffer, sizeof(buffer), ice, check)));
@@ -1239,5 +1114,5 @@
     clist_set_state(ice, clist, PJ_ICE_CHECKLIST_ST_RUNNING);
 
-    LOG((ice->obj_name, "Starting checklist periodic check"));
+    LOG5((ice->obj_name, "Starting checklist periodic check"));
 
     /* Send STUN Binding request for check with highest priority on
@@ -1307,11 +1182,10 @@
 
     PJ_ASSERT_RETURN(ice, PJ_EINVAL);
-
-    LOG((ice->obj_name, "Starting ICE check.."));
+    /* Checklist must be created */
+    PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
+
+    LOG4((ice->obj_name, "Starting ICE check.."));
 
     clist = &ice->clist;
-
-    if (clist->count == 0)
-	return PJ_EICENOCHECKLIST;
 
     /* Pickup the first pair and set the state to Waiting */
@@ -1363,7 +1237,6 @@
     struct req_data *rd = (struct req_data*) tdata->user_data;
     pj_ice *ice;
-    pj_ice_check *check;
-    const pj_ice_cand *lcand;
-    const pj_ice_cand *rcand;
+    pj_ice_check *check, *new_check;
+    pj_ice_cand *lcand;
     pj_ice_checklist *clist;
     pj_stun_xor_mapped_addr_attr *xaddr;
@@ -1379,8 +1252,10 @@
     pj_mutex_lock(ice->mutex);
 
-    lcand = check->lcand;
-    rcand = check->rcand;
-
-    LOG((ice->obj_name, 
+    /* Init lcand to NULL. lcand will be found from the mapped address
+     * found in the response.
+     */
+    lcand = NULL;
+
+    LOG4((ice->obj_name, 
 	 "Check %s%s: connectivity check %s",
 	 dump_check(buffer, sizeof(buffer), ice, check),
@@ -1403,10 +1278,10 @@
     PJ_TODO(ICE_CHECK_RESPONSE_SOURCE_ADDRESS);
 
-    /* Get the STUN MAPPED-ADDRESS attribute. */
+    /* Get the STUN XOR-MAPPED-ADDRESS attribute. */
     xaddr = (pj_stun_xor_mapped_addr_attr*)
 	    pj_stun_msg_find_attr(response, PJ_STUN_ATTR_XOR_MAPPED_ADDR,0);
     if (!xaddr) {
 	check_set_state(ice, check, PJ_ICE_CHECK_STATE_FAILED, 
-			PJNATH_ESTUNNOXORMAP);
+			PJNATH_ESTUNNOMAPPEDADDR);
 	on_check_complete(ice, check);
 	pj_mutex_unlock(ice->mutex);
@@ -1414,16 +1289,19 @@
     }
 
+    /* Find local candidate that matches the XOR-MAPPED-ADDRESS */
+    pj_assert(lcand == NULL);
+    for (i=0; i<ice->lcand_cnt; ++i) {
+	if (sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) {
+	    /* Match */
+	    lcand = &ice->lcand[i];
+	    break;
+	}
+    }
+
     /* If the transport address returned in XOR-MAPPED-ADDRESS does not match
      * any of the local candidates that the agent knows about, the mapped 
      * address represents a new candidate - a peer reflexive candidate.
      */
-    for (i=0; i<ice->lcand_cnt; ++i) {
-	if (sockaddr_cmp(&xaddr->sockaddr, &ice->lcand[i].addr) == 0) {
-	    /* Match */
-	    break;
-	}
-    }
-
-    if (i == ice->lcand_cnt) {
+    if (lcand == NULL) {
 	unsigned cand_id;
 	char buf[32];
@@ -1451,12 +1329,21 @@
     }
 
-    /* Sets the state of the pair that generated the check to succeeded. */
+    /* Add pair to valid list */
+    new_check = &ice->valid_list.checks[ice->valid_list.count++];
+    new_check->lcand = lcand;
+    new_check->rcand = check->rcand;
+    new_check->prio = CALC_CHECK_PRIO(ice, lcand, check->rcand);
+    new_check->state = PJ_ICE_CHECK_STATE_SUCCEEDED;
+    new_check->nominated = check->nominated;
+    new_check->err_code = PJ_SUCCESS;
+
+    /* Sort valid_list */
+    sort_checklist(&ice->valid_list);
+
+
+    /* Sets the state of the original pair that generated the check to 
+     * succeeded. 
+     */
     check_set_state(ice, check, PJ_ICE_CHECK_STATE_SUCCEEDED, PJ_SUCCESS);
-
-    /* This is a valid pair, so add this to the valid list */
-    ice->valid_list[ice->valid_cnt++] = rd->ckid;
-
-    /* Sort valid_list */
-    sort_valid_list(ice);
 
     /* Inform about check completion.
@@ -1516,5 +1403,7 @@
 }
 
-
+/* This callback is called by the STUN session associated with a candidate
+ * when it receives incoming request.
+ */
 static pj_status_t on_stun_rx_request(pj_stun_session *sess,
 				      const pj_uint8_t *pkt,
@@ -1541,16 +1430,12 @@
     /* Reject any requests except Binding request */
     if (msg->hdr.type != PJ_STUN_BINDING_REQUEST) {
-	pj_str_t err_msg = pj_str("Expecting Binding Request only");
 	status = pj_stun_session_create_response(sess, msg, 
 						 PJ_STUN_SC_BAD_REQUEST,
-						 &err_msg, &tdata);
-	if (status != PJ_SUCCESS) {
+						 NULL, &tdata);
+	if (status != PJ_SUCCESS)
 	    return status;
-	}
-
-	status = pj_stun_session_send_msg(sess, PJ_TRUE, 
-					  src_addr, src_addr_len, tdata);
-
-	return status;
+
+	return pj_stun_session_send_msg(sess, PJ_TRUE, 
+					src_addr, src_addr_len, tdata);
     }
 
@@ -1567,5 +1452,5 @@
 	 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_PRIORITY, 0);
     if (ap == 0) {
-	LOG((ice->obj_name, "Received Binding request with no PRIORITY"));
+	LOG5((ice->obj_name, "Received Binding request with no PRIORITY"));
 	pj_mutex_unlock(ice->mutex);
 	return PJ_SUCCESS;
@@ -1627,5 +1512,5 @@
 						  rcand->foundation.ptr);
 
-	LOG((ice->obj_name, 
+	LOG4((ice->obj_name, 
 	     "Added new remote candidate from the request: %s:%d",
 	     pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
@@ -1679,5 +1564,5 @@
 	    c->state == PJ_ICE_CHECK_STATE_WAITING)
 	{
-	    LOG((ice->obj_name, "Performing triggered check for check %d",i));
+	    LOG5((ice->obj_name, "Performing triggered check for check %d",i));
 	    perform_check(ice, &ice->clist, i);
 
@@ -1686,5 +1571,5 @@
 	     * TODO
 	     */
-	    LOG((ice->obj_name, "Triggered check for check %d not performed "
+	    LOG5((ice->obj_name, "Triggered check for check %d not performed "
 				"because it's in progress", i));
 	} else if (c->state == PJ_ICE_CHECK_STATE_SUCCEEDED) {
@@ -1694,5 +1579,5 @@
 	    pj_bool_t complete;
 
-	    LOG((ice->obj_name, "Triggered check for check %d not performed "
+	    LOG5((ice->obj_name, "Triggered check for check %d not performed "
 				"because it's completed", i));
 
@@ -1722,10 +1607,10 @@
 	c->err_code = PJ_SUCCESS;
 
-	LOG((ice->obj_name, "New triggered check added: %d", 
+	LOG4((ice->obj_name, "New triggered check added: %d", 
 	     ice->clist.count));
 	perform_check(ice, &ice->clist, ice->clist.count++);
 
     } else {
-	LOG((ice->obj_name, "Error: unable to perform triggered check: "
+	LOG4((ice->obj_name, "Error: unable to perform triggered check: "
 	     "TOO MANY CHECKS IN CHECKLIST!"));
     }
@@ -1772,10 +1657,10 @@
     comp = find_comp(ice, comp_id);
     if (comp == NULL) {
-	status = PJ_EICEINCOMPID;
+	status = PJNATH_EICEINCOMPID;
 	goto on_return;
     }
 
     if (comp->nominated_check_id == -1) {
-	status = PJ_EICEINPROGRESS;
+	status = PJNATH_EICEINPROGRESS;
 	goto on_return;
     }
@@ -1813,5 +1698,5 @@
     comp = find_comp(ice, comp_id);
     if (comp == NULL) {
-	status = PJ_EICEINCOMPID;
+	status = PJNATH_EICEINCOMPID;
 	goto on_return;
     }
