Index: pjproject/trunk/pjnath/src/pjnath/ice.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1104)
+++ pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1106)
@@ -57,9 +57,9 @@
 };
 
-#define CHECK_NAME_LEN	    128
-#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)
+#define CHECK_NAME_LEN		128
+#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(cl, chk)	(chk - (cl)->checks)
 
 
@@ -131,4 +131,10 @@
 
 
+PJ_DEF(const char*) pj_ice_get_cand_type_name(pj_ice_cand_type type)
+{
+    return cand_type_names[type];
+}
+
+
 /*
  * Create ICE stream session.
@@ -177,6 +183,5 @@
 	pj_ice_comp *comp;
 	comp = &ice->comp[i];
-	comp->comp_id = i+1;
-	comp->nominated_check_id = -1;
+	comp->valid_check = NULL;
     }
 
@@ -412,4 +417,5 @@
 		     foundation && addr && base_addr && addr_len,
 		     PJ_EINVAL);
+    PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
 
     pj_mutex_lock(ice->mutex);
@@ -499,4 +505,5 @@
 
     PJ_ASSERT_RETURN(ice && comp_id && cand_id, PJ_EINVAL);
+    PJ_ASSERT_RETURN(comp_id <= ice->comp_cnt, PJ_EINVAL);
 
     *cand_id = -1;
@@ -586,5 +593,5 @@
 
 static const char *dump_check(char *buffer, unsigned bufsize,
-			      const pj_ice *ice,
+			      const pj_ice_checklist *clist,
 			      const pj_ice_check *check)
 {
@@ -598,6 +605,7 @@
     if (lcand->addr.addr.sa_family == PJ_AF_INET) {
 	len = pj_ansi_snprintf(buffer, bufsize,
-			       "%d: %s:%d-->%s:%d",
-			       GET_CHECK_ID(check),
+			       "%d: [%d] %s:%d-->%s:%d",
+			       GET_CHECK_ID(clist, check),
+			       check->lcand->comp_id,
 			       laddr, (int)pj_ntohs(lcand->addr.ipv4.sin_port),
 			       pj_inet_ntoa(rcand->addr.ipv4.sin_addr),
@@ -628,5 +636,5 @@
 	const pj_ice_check *c = &clist->checks[i];
 	LOG4((ice->obj_name, " %s (%s, state=%s)",
-	     dump_check(buffer, sizeof(buffer), ice, c),
+	     dump_check(buffer, sizeof(buffer), clist, c),
 	     (c->nominated ? "nominated" : "not nominated"), 
 	     check_state_name[c->state]));
@@ -647,5 +655,5 @@
 
     LOG5((ice->obj_name, "Check %s: state changed from %s to %s",
-	 dump_check(buf, sizeof(buf), ice, check),
+	 dump_check(buf, sizeof(buf), &ice->clist, check),
 	 check_state_name[check->state],
 	 check_state_name[st]));
@@ -760,5 +768,6 @@
 
 		LOG5((ice->obj_name, "Check %s pruned",
-		    dump_check(buf, sizeof(buf), ice, &clist->checks[j])));
+		    dump_check(buf, sizeof(buf), &ice->clist, 
+			       &clist->checks[j])));
 
 		pj_array_erase(clist->checks, sizeof(clist->checks[0]),
@@ -813,19 +822,34 @@
     if (check->err_code==PJ_SUCCESS && check->nominated) {
 	pj_ice_comp *comp;
+	char buf[CHECK_NAME_LEN];
 
 	LOG5((ice->obj_name, "Check %d is successful and nominated",
-	     GET_CHECK_ID(check)));
+	     GET_CHECK_ID(&ice->clist, check)));
 
 	for (i=0; i<ice->clist.count; ++i) {
 	    pj_ice_check *c = &ice->clist.checks[i];
-	    if (c->lcand->comp_id == check->lcand->comp_id &&
-		(c->state==PJ_ICE_CHECK_STATE_FROZEN ||
-		 c->state==PJ_ICE_CHECK_STATE_WAITING))
-	    {
-		LOG5((ice->obj_name, 
-		     "Check %d to be failed because state is %s",
-		     i, check_state_name[c->state]));
-		check_set_state(ice, c, PJ_ICE_CHECK_STATE_FAILED,
-				PJ_ECANCELLED);
+	    if (c->lcand->comp_id == check->lcand->comp_id) {
+		if (c->state < PJ_ICE_CHECK_STATE_IN_PROGRESS) {
+		    /* Just fail Frozen/Waiting check */
+		    LOG5((ice->obj_name, 
+			 "Check %s to be failed because state is %s",
+			 dump_check(buf, sizeof(buf), &ice->clist, c), 
+			 check_state_name[c->state]));
+		    check_set_state(ice, c, PJ_ICE_CHECK_STATE_FAILED,
+				    PJ_ECANCELLED);
+
+		} else if (c->state == PJ_ICE_CHECK_STATE_IN_PROGRESS) {
+		    /* State is IN_PROGRESS, cancel transaction */
+		    if (c->tdata) {
+			LOG5((ice->obj_name, 
+			     "Cancelling check %s (In Progress)",
+			     dump_check(buf, sizeof(buf), &ice->clist, c)));
+			pj_stun_session_cancel_req(c->lcand->stun_sess, 
+						   c->tdata, PJ_FALSE, 0);
+			c->tdata = NULL;
+			check_set_state(ice, c, PJ_ICE_CHECK_STATE_FAILED,
+					PJ_ECANCELLED);
+		    }
+		}
 	    }
 	}
@@ -833,11 +857,9 @@
 	/* Update the nominated check for the component */
 	comp = find_comp(ice, check->lcand->comp_id);
-	if (comp->nominated_check_id < 0) {
-	    comp->nominated_check_id = GET_CHECK_ID(check);
+	if (comp->valid_check == NULL) {
+	    comp->valid_check = check;
 	} else {
-	    pj_ice_check *nom_check;
-	    nom_check = &ice->clist.checks[comp->nominated_check_id];
-	    if (nom_check->prio < check->prio)
-		comp->nominated_check_id = GET_CHECK_ID(check);
+	    if (comp->valid_check->prio < check->prio)
+		comp->valid_check = check;
 	}
     }
@@ -878,5 +900,5 @@
      */
     for (i=0; i<ice->comp_cnt; ++i) {
-	if (ice->comp[i].nominated_check_id == -1)
+	if (ice->comp[i].valid_check == NULL)
 	    break;
     }
@@ -950,7 +972,15 @@
     ice->rcand_cnt = 0;
     for (i=0; i<rcand_cnt; ++i) {
-	pj_ice_cand *cn = &ice->rcand[ice->rcand_cnt++];
+	pj_ice_cand *cn = &ice->rcand[ice->rcand_cnt];
+
+	/* Ignore candidate which has no matching component ID */
+	pj_assert(rcand[i].comp_id > 0);
+	if (rcand[i].comp_id==0 || rcand[i].comp_id > ice->comp_cnt) {
+	    continue;
+	}
+
 	pj_memcpy(cn, &rcand[i], sizeof(pj_ice_cand));
 	pj_strdup(ice->pool, &cn->foundation, &rcand[i].foundation);
+	ice->rcand_cnt++;
     }
 
@@ -967,7 +997,5 @@
 		pj_mutex_unlock(ice->mutex);
 		return PJ_ETOOMANY;
-	    } else {
-		clist->count++;
-	    }
+	    } 
 
 	    /* A local candidate is paired with a remote candidate if
@@ -987,4 +1015,6 @@
 
 	    chk->prio = CALC_CHECK_PRIO(ice, lcand, rcand);
+
+	    clist->count++;
 	}
     }
@@ -1027,5 +1057,4 @@
 				 unsigned check_id)
 {
-    pj_stun_tx_data *tdata;
     pj_ice_comp *comp;
     struct req_data *rd;
@@ -1044,9 +1073,10 @@
     LOG5((ice->obj_name, 
 	 "Sending connectivity check for check %s", 
-	 dump_check(buffer, sizeof(buffer), ice, check)));
+	 dump_check(buffer, sizeof(buffer), clist, check)));
 
     /* Create request */
     status = pj_stun_session_create_req(lcand->stun_sess, 
-					PJ_STUN_BINDING_REQUEST, &tdata);
+					PJ_STUN_BINDING_REQUEST, 
+					&check->tdata);
     if (status != PJ_SUCCESS)
 	return status;
@@ -1055,19 +1085,19 @@
      * completes and on_stun_request_complete() callback is called.
      */
-    rd = PJ_POOL_ZALLOC_T(tdata->pool, struct req_data);
+    rd = PJ_POOL_ZALLOC_T(check->tdata->pool, struct req_data);
     rd->ice = ice;
     rd->clist = clist;
     rd->ckid = check_id;
-    tdata->user_data = (void*) rd;
+    check->tdata->user_data = (void*) rd;
 
     /* Add PRIORITY */
     prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PRFLX, 65535, 
 			  lcand->comp_id);
-    pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_PRIORITY,
-			      prio);
+    pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg, 
+			      PJ_STUN_ATTR_PRIORITY, prio);
 
     /* Add USE-CANDIDATE and set this check to nominated */
     if (ice->role == PJ_ICE_ROLE_CONTROLLING) {
-	pj_stun_msg_add_empty_attr(tdata->pool, tdata->msg, 
+	pj_stun_msg_add_empty_attr(check->tdata->pool, check->tdata->msg, 
 				   PJ_STUN_ATTR_USE_CANDIDATE);
 	check->nominated = PJ_TRUE;
@@ -1081,7 +1111,9 @@
     status = pj_stun_session_send_msg(lcand->stun_sess, PJ_FALSE, 
 				      &rcand->addr, 
-				      sizeof(pj_sockaddr_in), tdata);
-    if (status != PJ_SUCCESS)
+				      sizeof(pj_sockaddr_in), check->tdata);
+    if (status != PJ_SUCCESS) {
+	check->tdata = NULL;
 	return status;
+    }
 
     check_set_state(ice, check, PJ_ICE_CHECK_STATE_IN_PROGRESS, PJ_SUCCESS);
@@ -1250,4 +1282,8 @@
     clist = rd->clist;
 
+    /* Mark STUN transaction as complete */
+    pj_assert(tdata == check->tdata);
+    check->tdata = NULL;
+
     pj_mutex_lock(ice->mutex);
 
@@ -1259,5 +1295,5 @@
     LOG4((ice->obj_name, 
 	 "Check %s%s: connectivity check %s",
-	 dump_check(buffer, sizeof(buffer), ice, check),
+	 dump_check(buffer, sizeof(buffer), &ice->clist, check),
 	 (check->nominated ? " (nominated)" : " (not nominated)"),
 	 (status==PJ_SUCCESS ? "SUCCESS" : "FAILED")));
@@ -1501,5 +1537,5 @@
     if (i == ice->rcand_cnt) {
 	rcand = &ice->rcand[ice->rcand_cnt++];
-	rcand->comp_id = comp->comp_id;
+	rcand->comp_id = lcand->comp_id;
 	rcand->type = PJ_ICE_CAND_TYPE_PRFLX;
 	rcand->prio = ap->value;
@@ -1649,7 +1685,6 @@
     pj_ice_comp *comp;
     unsigned cand_id;
-    pj_ice_check *check;
-
-    PJ_ASSERT_RETURN(ice, PJ_EINVAL);
+
+    PJ_ASSERT_RETURN(ice && comp_id && comp_id <= ice->comp_cnt, PJ_EINVAL);
     
     pj_mutex_lock(ice->mutex);
@@ -1661,14 +1696,12 @@
     }
 
-    if (comp->nominated_check_id == -1) {
+    if (comp->valid_check == NULL) {
 	status = PJNATH_EICEINPROGRESS;
 	goto on_return;
     }
 
-    check = &ice->clist.checks[comp->nominated_check_id];
-    cand_id = GET_LCAND_ID(check->lcand);
-
+    cand_id = GET_LCAND_ID(comp->valid_check->lcand);
     status = (*ice->cb.on_tx_pkt)(ice, comp_id, cand_id, data, data_len, 
-				  &check->rcand->addr, 
+				  &comp->valid_check->rcand->addr, 
 				  sizeof(pj_sockaddr_in));
 
