Index: pjproject/trunk/pjnath/include/pjnath/errno.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1153)
+++ pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1154)
@@ -160,5 +160,11 @@
  */
 #define PJNATH_EICEINCANDSDP	    (PJNATH_ERRNO_START+91) /* 370091 */
-
+/**
+ * @hideinitializer
+ * No host candidate associated with srflx. This error occurs when
+ * a server reflexive candidate is added without the matching 
+ * host candidate.
+ */
+#define PJNATH_EICENOHOSTCAND	    (PJNATH_ERRNO_START+92) /* 370092 */
 
 
Index: pjproject/trunk/pjnath/include/pjnath/stun_msg.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/stun_msg.h	(revision 1153)
+++ pjproject/trunk/pjnath/include/pjnath/stun_msg.h	(revision 1154)
@@ -990,4 +990,13 @@
 typedef struct pj_stun_uint_attr pj_stun_timer_val_attr;
 
+/**
+ * This describes ICE-CONTROLLING attribute.
+ */
+typedef struct pj_stun_uint64_attr pj_stun_ice_controlling_attr;
+
+/**
+ * This describes ICE-CONTROLLED attribute.
+ */
+typedef struct pj_stun_uint64_attr pj_stun_ice_controlled_attr;
 
 /**
Index: pjproject/trunk/pjnath/src/pjnath/errno.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1153)
+++ pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1154)
@@ -60,4 +60,5 @@
     PJ_BUILD_ERR( PJNATH_EICEMISSINGSDP,    "Missing ICE SDP attribute"),
     PJ_BUILD_ERR( PJNATH_EICEINCANDSDP,	    "Invalid SDP \"candidate\" attribute"),
+    PJ_BUILD_ERR( PJNATH_EICENOHOSTCAND,    "No host candidate associated with srflx"),
 
 };
Index: pjproject/trunk/pjnath/src/pjnath/ice_session.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice_session.c	(revision 1153)
+++ pjproject/trunk/pjnath/src/pjnath/ice_session.c	(revision 1154)
@@ -61,4 +61,5 @@
 static const char *role_names[] = 
 {
+    "Unknown",
     "Controlled",
     "Controlling"
@@ -851,5 +852,6 @@
  * is sorted.
  */
-static void prune_checklist(pj_ice_sess *ice, pj_ice_sess_checklist *clist)
+static pj_status_t prune_checklist(pj_ice_sess *ice, 
+				   pj_ice_sess_checklist *clist)
 {
     unsigned i;
@@ -865,28 +867,50 @@
      * candidate pairs, called the check list for that media stream.    
      */
+    /* First replace SRFLX candidates with their base */
+    for (i=0; i<clist->count; ++i) {
+	pj_ice_sess_cand *srflx = clist->checks[i].lcand;
+
+	if (clist->checks[i].lcand->type == PJ_ICE_CAND_TYPE_SRFLX) {
+	    /* Find the base for this candidate */
+	    unsigned j;
+	    for (j=0; j<ice->lcand_cnt; ++j) {
+		pj_ice_sess_cand *host = &ice->lcand[j];
+
+		if (host->type != PJ_ICE_CAND_TYPE_HOST)
+		    continue;
+
+		if (sockaddr_cmp(&srflx->base_addr, &host->addr) == 0) {
+		    /* Replace this SRFLX with its BASE */
+		    clist->checks[i].lcand = host;
+		    break;
+		}
+	    }
+
+	    if (j==ice->lcand_cnt) {
+		/* Host candidate not found this this srflx! */
+		LOG4((ice->obj_name, 
+		      "Base candidate %s:%d not found for srflx candidate %d",
+		      pj_inet_ntoa(srflx->base_addr.ipv4.sin_addr),
+		      pj_ntohs(srflx->base_addr.ipv4.sin_port),
+		      GET_LCAND_ID(clist->checks[i].lcand)));
+		return PJNATH_EICENOHOSTCAND;
+	    }
+	}
+    }
+
+    /* Next remove a pair if its local and remote candidates are identical
+     * to the local and remote candidates of a pair higher up on the priority
+     * list
+     */
     for (i=0; i<clist->count; ++i) {
 	pj_ice_sess_cand *licand = clist->checks[i].lcand;
 	pj_ice_sess_cand *ricand = clist->checks[i].rcand;
-	const pj_sockaddr *liaddr;
 	unsigned j;
-
-	if (licand->type == PJ_ICE_CAND_TYPE_SRFLX)
-	    liaddr = &licand->base_addr;
-	else
-	    liaddr = &licand->addr;
 
 	for (j=i+1; j<clist->count;) {
 	    pj_ice_sess_cand *ljcand = clist->checks[j].lcand;
 	    pj_ice_sess_cand *rjcand = clist->checks[j].rcand;
-	    const pj_sockaddr *ljaddr;
-
-	    if (ljcand->type == PJ_ICE_CAND_TYPE_SRFLX)
-		ljaddr = &ljcand->base_addr;
-	    else
-		ljaddr = &ljcand->addr;
-
-	    if (ricand == rjcand && 
-		sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL)
-	    {
+
+	    if ((licand == ljcand) && (ricand == rjcand)) {
 		/* Found duplicate, remove it */
 		char buf[CHECK_NAME_LEN];
@@ -905,4 +929,6 @@
 	}
     }
+
+    return PJ_SUCCESS;
 }
 
@@ -1125,4 +1151,5 @@
     timer_data *td;
     unsigned i, j;
+    pj_status_t status;
 
     PJ_ASSERT_RETURN(ice && rem_ufrag && rem_passwd && rcand_cnt && rcand,
@@ -1175,5 +1202,5 @@
 	    pj_ice_sess_check *chk = &clist->checks[clist->count];
 
-	    if (clist->count > PJ_ICE_MAX_CHECKS) {
+	    if (clist->count >= PJ_ICE_MAX_CHECKS) {
 		pj_mutex_unlock(ice->mutex);
 		return PJ_ETOOMANY;
@@ -1184,6 +1211,6 @@
 	     * and have the same IP address version. 
 	     */
-	    if (lcand->comp_id != rcand->comp_id ||
-		lcand->addr.addr.sa_family != rcand->addr.addr.sa_family)
+	    if ((lcand->comp_id != rcand->comp_id) ||
+		(lcand->addr.addr.sa_family != rcand->addr.addr.sa_family))
 	    {
 		continue;
@@ -1205,5 +1232,9 @@
 
     /* Prune the checklist */
-    prune_checklist(ice, clist);
+    status = prune_checklist(ice, clist);
+    if (status != PJ_SUCCESS) {
+	pj_mutex_unlock(ice->mutex);
+	return status;
+    }
 
     /* Init timer entry in the checklist. Initially the timer ID is FALSE
@@ -1466,5 +1497,5 @@
     /* Pickup the first pair for component 1. */
     for (i=0; i<clist->count; ++i) {
-	if (clist->checks[0].lcand->comp_id == 1)
+	if (clist->checks[i].lcand->comp_id == 1)
 	    break;
     }
@@ -1887,4 +1918,16 @@
     }
 
+    /* Handle the case when request comes before answer is received.
+     * We need to put credential in the response, and since we haven't
+     * got the response, copy the username from the request.
+     */
+    if (ice->rcand_cnt == 0) {
+	pj_stun_string_attr *uname_attr;
+
+	uname_attr = (pj_stun_string_attr*)
+		     pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
+	pj_assert(uname_attr != NULL);
+	pj_strdup(ice->pool, &ice->rx_uname, &uname_attr->value);
+    }
 
     /* 
@@ -2090,4 +2133,18 @@
 	     */
 	    pj_bool_t complete;
+	    unsigned j;
+
+	    /* If this check is nominated, scan the valid_list for the
+	     * same check and update the nominated flag. A controlled 
+	     * agent might have finished the check earlier.
+	     */
+	    if (rcheck->use_candidate) {
+		for (j=0; j<ice->valid_list.count; ++j) {
+		    pj_ice_sess_check *vc = &ice->valid_list.checks[j];
+		    if (vc->lcand == c->lcand && vc->rcand == c->rcand) {
+			vc->nominated = PJ_TRUE;
+		    }
+		}
+	    }
 
 	    LOG5((ice->obj_name, "Triggered check for check %d not performed "
@@ -2208,4 +2265,10 @@
 					   PJ_STUN_IS_DATAGRAM,
 					   NULL, src_addr, src_addr_len);
+	if (status != PJ_SUCCESS) {
+	    char errmsg[PJ_ERR_MSG_SIZE];
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    LOG4((ice->obj_name, "Error processing incoming message: %s",
+		  errmsg));
+	}
     } else {
 	(*ice->cb.on_rx_data)(ice, comp_id, pkt, pkt_size, 
Index: pjproject/trunk/pjnath/src/pjnath/ice_strans.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 1153)
+++ pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 1154)
@@ -462,5 +462,6 @@
 	if (status == PJ_SUCCESS) {
 	    if (ice_st->ice==NULL ||
-		pj_memcmp(comp->pkt+8, comp->ka_tsx_id, 12) == 0) 
+		(comp->stun_sess &&
+		 pj_memcmp(comp->pkt+8, comp->ka_tsx_id, 12) == 0)) 
 	    {
 		status = pj_stun_session_on_rx_pkt(comp->stun_sess, comp->pkt,
@@ -469,5 +470,5 @@
 						   &comp->src_addr, 
 						   comp->src_addr_len);
-	    } else {
+	    } else if (ice_st->ice) {
 		PJ_TODO(DISTINGUISH_BETWEEN_LOCAL_AND_RELAY);
 
@@ -482,4 +483,6 @@
 					       &comp->src_addr, 
 					       comp->src_addr_len);
+	    } else {
+		/* This must have been a very late STUN reponse */
 	    }
 	} else {
Index: pjproject/trunk/pjnath/src/pjnath/stun_session.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/stun_session.c	(revision 1153)
+++ pjproject/trunk/pjnath/src/pjnath/stun_session.c	(revision 1154)
@@ -812,5 +812,5 @@
     tdata = tsx_lookup(sess, msg);
     if (tdata == NULL) {
-	PJ_LOG(4,(SNAME(sess), 
+	PJ_LOG(5,(SNAME(sess), 
 		  "Transaction not found, response silently discarded"));
 	return PJ_SUCCESS;
