Index: pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1125)
+++ pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1126)
@@ -89,5 +89,7 @@
 
 
-
+/*
+ * Create ICE media transport.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_create(pjmedia_endpt *endpt,
 				       const char *name,
@@ -132,4 +134,7 @@
 
 
+/*
+ * Destroy ICE media transport.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_destroy(pjmedia_transport *tp)
 {
@@ -138,7 +143,8 @@
     if (tp_ice->ice_st) {
 	pj_ice_strans_destroy(tp_ice->ice_st);
-	//Must not touch tp_ice after ice_st is destroyed!
-	//(it has the pool)
-	//tp_ice->ice_st = NULL;
+	/*Must not touch tp_ice after ice_st is destroyed!
+	 (it has the pool)
+	 tp_ice->ice_st = NULL;
+	 */
     }
 
@@ -147,4 +153,7 @@
 
 
+/*
+ * Start media transport initialization.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_start_init( pjmedia_transport *tp,
 					    unsigned options,
@@ -186,4 +195,7 @@
 
 
+/*
+ * Get the status of media transport initialization.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_get_init_status(pjmedia_transport *tp)
 {
@@ -193,4 +205,7 @@
 
 
+/*
+ * Get the component for the specified component ID.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_get_comp( pjmedia_transport *tp,
 					  unsigned comp_id,
@@ -205,11 +220,10 @@
 }
 
-PJ_DEF(pj_ice_strans*) pjmedia_ice_get_ice_st(pjmedia_transport *tp)
-{
-    struct transport_ice *tp_ice = (struct transport_ice*)tp;
-    return tp_ice->ice_st;
-}
-
-
+
+/*
+ * Create ICE! This happens when:
+ *  - UAC is ready to send offer
+ *  - UAS have just received an offer.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_init_ice(pjmedia_transport *tp,
 					 pj_ice_sess_role role,
@@ -222,4 +236,8 @@
 
 
+/*
+ * For both UAC and UAS, pass in the SDP before sending it to remote.
+ * This will add ICE attributes to the SDP.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_modify_sdp(pjmedia_transport *tp,
 					   pj_pool_t *pool,
@@ -306,4 +324,5 @@
 
 
+/* Parse a=candidate line */
 static pj_status_t parse_cand(pj_pool_t *pool,
 			      const pj_str_t *orig_input,
@@ -391,12 +410,17 @@
 }
 
-static void set_no_ice(struct transport_ice *tp_ice)
+
+/* Disable ICE when SDP from remote doesn't contain a=candidate line */
+static void set_no_ice(struct transport_ice *tp_ice, const char *reason)
 {
     PJ_LOG(4,(tp_ice->ice_st->obj_name, 
-	      "Remote does not support ICE, disabling local ICE"));
+	      "Disabling local ICE, reason=%s", reason));
     pjmedia_ice_stop_ice(&tp_ice->base);
 }
 
 
+/*
+ * Start ICE checks when both offer and answer are available.
+ */
 PJ_DEF(pj_status_t) pjmedia_ice_start_ice(pjmedia_transport *tp,
 					  pj_pool_t *pool,
@@ -410,6 +434,8 @@
     const pjmedia_sdp_media *sdp_med;
     pj_bool_t remote_is_lite = PJ_FALSE;
+    pj_bool_t ice_mismatch = PJ_FALSE;
     const pj_str_t STR_CANDIDATE = {"candidate", 9};
     const pj_str_t STR_ICE_LITE = {"ice-lite", 8};
+    const pj_str_t STR_ICE_MISMATCH = {"ice-mismatch", 12};
     pj_str_t uname, pass;
     pj_status_t status;
@@ -428,5 +454,5 @@
 				      "ice-ufrag", NULL);
 	if (attr == NULL) {
-	    set_no_ice(tp_ice);
+	    set_no_ice(tp_ice, "ice-ufrag attribute not found");
 	    return PJ_SUCCESS;
 	}
@@ -442,5 +468,5 @@
 				      "ice-pwd", NULL);
 	if (attr == NULL) {
-	    set_no_ice(tp_ice);
+	    set_no_ice(tp_ice, "ice-pwd attribute not found");
 	    return PJ_SUCCESS;
 	}
@@ -455,6 +481,13 @@
 	attr = sdp_med->attr[i];
 
-	if (pj_strcmp(&attr->name, &STR_ICE_LITE)==0)
+	if (pj_strcmp(&attr->name, &STR_ICE_LITE)==0) {
 	    remote_is_lite = PJ_TRUE;
+	    continue;
+	}
+
+	if (pj_strcmp(&attr->name, &STR_ICE_MISMATCH)==0) {
+	    ice_mismatch = PJ_TRUE;
+	    continue;
+	}
 
 	if (pj_strcmp(&attr->name, &STR_CANDIDATE)!=0)
@@ -466,4 +499,10 @@
 
 	cand_cnt++;
+    }
+
+    /* Handle ice-mismatch case */
+    if (ice_mismatch) {
+	set_no_ice(tp_ice, "ice-mismatch detected");
+	return PJ_SUCCESS;
     }
 
Index: pjproject/trunk/pjnath/include/pjnath/config.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/config.h	(revision 1125)
+++ pjproject/trunk/pjnath/include/pjnath/config.h	(revision 1126)
@@ -31,4 +31,19 @@
  * @{
  */
+
+
+/* **************************************************************************
+ * GENERAL
+ */
+
+/**
+ * The log level for PJNATH error display.
+ *
+ * default 1
+ */
+#ifndef PJNATH_ERROR_LEVEL
+#   define PJNATH_ERROR_LEVEL			    1
+#endif
+
 
 /* **************************************************************************
Index: pjproject/trunk/pjnath/include/pjnath/ice_session.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/ice_session.h	(revision 1125)
+++ pjproject/trunk/pjnath/include/pjnath/ice_session.h	(revision 1126)
@@ -97,16 +97,4 @@
 } pj_ice_cand_type;
 
-
-/**
- * This enumeration describes the default preference for the ICE
- * candidate types as described by ICE standard.
- */
-enum pj_ice_type_pref
-{
-    PJ_ICE_HOST_PREF	    = 126,  /**< Preference value for host.	*/
-    PJ_ICE_SRFLX_PREF	    = 100,  /**< Preference value for SRFLX.	*/
-    PJ_ICE_PRFLX_PREF	    = 110,  /**< Preference value for PRFLX	*/
-    PJ_ICE_RELAYED_PREF	    = 0	    /**< Preference value for relay	*/
-};
 
 /** Forward declaration for pj_ice_sess */
@@ -274,5 +262,5 @@
      * Check priority.
      */
-    pj_uint64_t		 prio;
+    pj_timestamp	 prio;
 
     /**
@@ -446,4 +434,5 @@
     pj_ice_sess_role	 role;			    /**< ICE role.	    */
     pj_timestamp	 tie_breaker;		    /**< Tie breaker value  */
+    pj_uint8_t		*prefs;			    /**< Type preference.   */
     pj_bool_t		 is_complete;		    /**< Complete?	    */
     pj_status_t		 ice_status;		    /**< Error status.	    */
@@ -567,4 +556,26 @@
 
 /**
+ * Assign a custom preference values for ICE candidate types. By assigning
+ * custom preference value, application can control the order of candidates
+ * to be checked first. The default preference settings is to use 126 for 
+ * host candidates, 100 for server reflexive candidates, 110 for peer 
+ * reflexive candidates, an 0 for relayed candidates.
+ *
+ * Note that this function must be called before any candidates are added
+ * to the ICE session.
+ *
+ * @param ice		The ICE session.
+ * @param prefs		Array of candidate preference value. The values are
+ *			put in the array indexed by the candidate type as
+ *			specified in pj_ice_cand_type.
+ *
+ * @return		PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
+					   const pj_uint8_t prefs[4]);
+
+
+
+/**
  * Add a candidate to this ICE session. Application must add candidates for
  * each components ID before it can start pairing the candidates and 
@@ -596,4 +607,7 @@
 					  unsigned *p_cand_id);
 
+#if 0
+/* Temporarily disabled to reduce size, since we don't need this yet */
+
 /**
  * Find default candidate for the specified component ID, using this
@@ -613,4 +627,5 @@
 						   unsigned comp_id,
 						   int *p_cand_id);
+#endif
 
 /**
Index: pjproject/trunk/pjnath/include/pjnath/stun_auth.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/stun_auth.h	(revision 1125)
+++ pjproject/trunk/pjnath/include/pjnath/stun_auth.h	(revision 1126)
@@ -226,4 +226,6 @@
 	     * PJ_FALSE, 438 (Stale Nonce) response will be created.
 	     *
+	     * This callback is optional.
+	     *
 	     * @param msg	The STUN message where the nonce was received.
 	     * @param user_data	The user data as specified in the credential.
Index: pjproject/trunk/pjnath/include/pjnath/stun_msg.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/stun_msg.h	(revision 1125)
+++ pjproject/trunk/pjnath/include/pjnath/stun_msg.h	(revision 1126)
@@ -1229,8 +1229,12 @@
  * @return		The message string output.
  */
+#if PJ_LOG_MAX_LEVEL > 0
 PJ_DECL(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
 			        char *buffer,
 			        unsigned length,
 				unsigned *printed_len);
+#else
+#   define pj_stun_msg_dump(msg, buf, length, printed_len)  ""
+#endif
 
 
Index: pjproject/trunk/pjnath/include/pjnath/types.h
===================================================================
--- pjproject/trunk/pjnath/include/pjnath/types.h	(revision 1125)
+++ pjproject/trunk/pjnath/include/pjnath/types.h	(revision 1126)
@@ -38,7 +38,23 @@
  * Initialize pjnath library.
  *
- * @return  Initialization status.
+ * @return	    Initialization status.
  */
 PJ_DECL(pj_status_t) pjnath_init(void);
+
+
+/**
+ * Display error to the log.
+ *
+ * @param sender    The sender name.
+ * @param title	    Title message.
+ * @param status    The error status.
+ */
+#if PJNATH_ERROR_LEVEL <= PJ_LOG_MAX_LEVEL
+PJ_DECL(void) pjnath_perror(const char *sender, const char *title,
+			    pj_status_t status);
+#else
+# define pjnath_perror(sender, title, status)
+#endif
+
 
 
@@ -148,4 +164,5 @@
  * the usage of ICE in SIP/SDP offer/answer.
  * 
+ *
  * \subsection PJNATH_ICE_ARCH ICE Library Organization
  * 
Index: pjproject/trunk/pjnath/src/pjnath/errno.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1126)
@@ -19,4 +19,5 @@
 #include <pjnath/errno.h>
 #include <pjnath/stun_msg.h>
+#include <pj/log.h>
 #include <pj/string.h>
 
@@ -166,2 +167,29 @@
 }
 
+
+#if PJNATH_ERROR_LEVEL <= PJ_LOG_MAX_LEVEL
+
+PJ_DEF(void) pjnath_perror(const char *sender, const char *title,
+			   pj_status_t status)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+
+    pj_strerror(status, errmsg, sizeof(errmsg));
+
+#if PJNATH_ERROR_LEVEL==1
+    PJ_LOG(1,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==2
+    PJ_LOG(2,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==3
+    PJ_LOG(3,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==4
+    PJ_LOG(4,(sender, "%s: %s", title, errmsg));
+#elif PJNATH_ERROR_LEVEL==5
+    PJ_LOG(5,(sender, "%s: %s", title, errmsg));
+#else
+# error Invalid PJNATH_ERROR_LEVEL value
+#endif
+}
+
+#endif	/* PJNATH_ERROR_LEVEL <= PJ_LOG_MAX_LEVEL */
+
Index: pjproject/trunk/pjnath/src/pjnath/ice_session.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice_session.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/ice_session.c	(revision 1126)
@@ -41,4 +41,5 @@
 
 /* String names for pj_ice_sess_check_state */
+#if PJ_LOG_MAX_LEVEL >= 4
 static const char *check_state_name[] = 
 {
@@ -56,4 +57,5 @@
     "Completed"
 };
+#endif	/* PJ_LOG_MAX_LEVEL >= 4 */
 
 static const char *role_names[] = 
@@ -61,4 +63,13 @@
     "Controlled",
     "Controlling"
+};
+
+/* Default ICE session preferences, according to draft-ice */
+static pj_uint8_t cand_type_prefs[4] =
+{
+    126,    /**< PJ_ICE_HOST_PREF	*/
+    100,    /**< PJ_ICE_SRFLX_PREF.	*/
+    110,    /**< PJ_ICE_PRFLX_PREF	*/
+    0	    /**< PJ_ICE_RELAYED_PREF	*/
 };
 
@@ -72,6 +83,5 @@
 typedef struct stun_data
 {
-    pj_ice_sess	*ice;
-    unsigned	 lcand_id;
+    pj_ice_sess		*ice;
     pj_ice_sess_cand	*lcand;
 } stun_data;
@@ -79,6 +89,6 @@
 typedef struct timer_data
 {
-    pj_ice_sess		*ice;
-    pj_ice_sess_checklist	*clist;
+    pj_ice_sess		    *ice;
+    pj_ice_sess_checklist   *clist;
 } timer_data;
 
@@ -132,9 +142,4 @@
 					  int *data_type,
 					  pj_str_t *data);
-static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg,
-					void *user_data,
-					const pj_str_t *realm,
-					const pj_str_t *username,
-					const pj_str_t *nonce);
 
 
@@ -189,6 +194,4 @@
     pj_pool_t *pool;
     pj_ice_sess *ice;
-    char tmp[64];
-    pj_str_t s;
     unsigned i;
     pj_status_t status;
@@ -205,4 +208,5 @@
     ice->tie_breaker.u32.hi = pj_rand();
     ice->tie_breaker.u32.lo = pj_rand();
+    ice->prefs = cand_type_prefs;
 
     pj_ansi_snprintf(ice->obj_name, sizeof(ice->obj_name),
@@ -227,16 +231,16 @@
 
     if (local_ufrag == NULL) {
-	pj_ansi_snprintf(tmp, sizeof(tmp), "%x%x", pj_rand(), pj_rand());
-	s = pj_str(tmp);
-	local_ufrag = &s;
-    }
-    pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
+	ice->rx_ufrag.ptr = pj_pool_alloc(ice->pool, 16);
+	pj_create_random_string(ice->rx_ufrag.ptr, 16);
+    } else {
+	pj_strdup(ice->pool, &ice->rx_ufrag, local_ufrag);
+    }
 
     if (local_passwd == NULL) {
-	pj_ansi_snprintf(tmp, sizeof(tmp), "%x%x", pj_rand(), pj_rand());
-	s = pj_str(tmp);
-	local_passwd = &s;
-    }
-    pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
+	ice->rx_pass.ptr = pj_pool_alloc(ice->pool, 16);
+	pj_create_random_string(ice->rx_pass.ptr, 16);
+    } else {
+	pj_strdup(ice->pool, &ice->rx_pass, local_passwd);
+    }
 
 
@@ -313,4 +317,18 @@
     }
 
+    return PJ_SUCCESS;
+}
+
+
+/*
+ * Change type preference
+ */
+PJ_DEF(pj_status_t) pj_ice_sess_set_prefs(pj_ice_sess *ice,
+					  const pj_uint8_t prefs[4])
+{
+    PJ_ASSERT_RETURN(ice && prefs, PJ_EINVAL);
+    ice->prefs = pj_pool_calloc(ice->pool, PJ_ARRAY_SIZE(prefs), 
+				sizeof(pj_uint8_t));
+    pj_memcpy(ice->prefs, prefs, sizeof(prefs));
     return PJ_SUCCESS;
 }
@@ -422,33 +440,10 @@
 
 
-static pj_bool_t stun_auth_verify_nonce(const pj_stun_msg *msg,
-					void *user_data,
-					const pj_str_t *realm,
-					const pj_str_t *username,
-					const pj_str_t *nonce)
-{
-    /* We don't use NONCE */
-    PJ_UNUSED_ARG(msg);
-    PJ_UNUSED_ARG(user_data);
-    PJ_UNUSED_ARG(realm);
-    PJ_UNUSED_ARG(username);
-    PJ_UNUSED_ARG(nonce);
-    return PJ_TRUE;
-}
-
-
-static pj_uint32_t CALC_CAND_PRIO(pj_ice_cand_type type,
+static pj_uint32_t CALC_CAND_PRIO(pj_ice_sess *ice,
+				  pj_ice_cand_type type,
 				  pj_uint32_t local_pref,
 				  pj_uint32_t comp_id)
 {
-    pj_uint32_t type_pref[] =
-    {
-	PJ_ICE_HOST_PREF,
-	PJ_ICE_SRFLX_PREF,
-	PJ_ICE_PRFLX_PREF,
-	PJ_ICE_RELAYED_PREF
-    };
-
-    return ((type_pref[type] & 0xFF) << 24) + 
+    return ((ice->prefs[type] & 0xFF) << 24) + 
 	   ((local_pref & 0xFFFF)    << 8) +
 	   (((256 - comp_id) & 0xFF) << 0);
@@ -493,5 +488,5 @@
     lcand->type = type;
     pj_strdup(ice->pool, &lcand->foundation, foundation);
-    lcand->prio = CALC_CAND_PRIO(type, local_pref, lcand->comp_id);
+    lcand->prio = CALC_CAND_PRIO(ice, type, local_pref, lcand->comp_id);
     pj_memcpy(&lcand->addr, addr, addr_len);
     pj_memcpy(&lcand->base_addr, base_addr, addr_len);
@@ -521,5 +516,4 @@
     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);
@@ -531,5 +525,4 @@
     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);
@@ -563,4 +556,5 @@
 
 /* Find default candidate ID for the component */
+#if 0
 PJ_DEF(pj_status_t) pj_ice_sess_find_default_cand(pj_ice_sess *ice,
 						  unsigned comp_id,
@@ -630,4 +624,5 @@
     return PJ_EBUG;
 }
+#endif	/* if 0 */
 
 
@@ -640,9 +635,14 @@
 #endif
 
-static pj_uint64_t CALC_CHECK_PRIO(const pj_ice_sess *ice, 
-				   const pj_ice_sess_cand *lcand,
-				   const pj_ice_sess_cand *rcand)
+static pj_timestamp CALC_CHECK_PRIO(const pj_ice_sess *ice, 
+				    const pj_ice_sess_cand *lcand,
+				    const pj_ice_sess_cand *rcand)
 {
     pj_uint32_t O, A;
+    pj_timestamp prio;
+
+    /* Original formula:
+     *   pair priority = 2^32*MIN(O,A) + 2*MAX(O,A) + (O>A?1:0)
+     */
 
     if (ice->role == PJ_ICE_SESS_ROLE_CONTROLLING) {
@@ -654,8 +654,24 @@
     }
 
+    /*
     return ((pj_uint64_t)1 << 32) * MIN(O, A) +
 	   (pj_uint64_t)2 * MAX(O, A) + (O>A ? 1 : 0);
-}
-
+    */
+
+    prio.u32.hi = MIN(O,A);
+    prio.u32.lo = (MAX(O, A) << 1) + (O>A ? 1 : 0);
+
+    return prio;
+}
+
+
+PJ_INLINE(int) CMP_CHECK_PRIO(const pj_ice_sess_check *c1,
+			      const pj_ice_sess_check *c2)
+{
+    return pj_cmp_timestamp(&c1->prio, &c2->prio);
+}
+
+
+#if PJ_LOG_MAX_LEVEL >= 4
 static const char *dump_check(char *buffer, unsigned bufsize,
 			      const pj_ice_sess_checklist *clist,
@@ -691,5 +707,4 @@
 }
 
-#if PJ_LOG_MAX_LEVEL >= 4
 static void dump_checklist(const char *title, const pj_ice_sess *ice, 
 			   const pj_ice_sess_checklist *clist)
@@ -747,5 +762,5 @@
 	unsigned j, highest = i;
 	for (j=i+1; j<clist->count; ++j) {
-	    if (clist->checks[j].prio > clist->checks[highest].prio) {
+	    if (CMP_CHECK_PRIO(&clist->checks[j], &clist->checks[highest]) > 0) {
 		highest = j;
 	    }
@@ -828,6 +843,6 @@
 		ljaddr = &ljcand->addr;
 
-	    if (sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL &&
-		sockaddr_cmp(&ricand->addr, &rjcand->addr) == SOCKADDR_EQUAL)
+	    if (ricand == rjcand && 
+		sockaddr_cmp(liaddr, ljaddr) == SOCKADDR_EQUAL)
 	    {
 		/* Found duplicate, remove it */
@@ -835,6 +850,6 @@
 
 		LOG5((ice->obj_name, "Check %s pruned",
-		    dump_check(buf, sizeof(buf), &ice->clist, 
-			       &clist->checks[j])));
+		     dump_check(buf, sizeof(buf), &ice->clist, 
+			        &clist->checks[j])));
 
 		pj_array_erase(clist->checks, sizeof(clist->checks[0]),
@@ -929,5 +944,5 @@
 	    comp->valid_check = check;
 	} else {
-	    if (comp->valid_check->prio < check->prio)
+	    if (CMP_CHECK_PRIO(comp->valid_check, check) < 0)
 		comp->valid_check = check;
 	}
@@ -1155,6 +1170,8 @@
 					PJ_STUN_BINDING_REQUEST, 
 					&check->tdata);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pjnath_perror(ice->obj_name, "Error creating STUN request", status);
 	return status;
+    }
 
     /* Attach data to be retrieved later when STUN request transaction
@@ -1168,5 +1185,5 @@
 
     /* Add PRIORITY */
-    prio = CALC_CAND_PRIO(PJ_ICE_CAND_TYPE_PRFLX, 65535, 
+    prio = CALC_CAND_PRIO(ice, PJ_ICE_CAND_TYPE_PRFLX, 65535, 
 			  lcand->comp_id);
     pj_stun_msg_add_uint_attr(check->tdata->pool, check->tdata->msg, 
@@ -1190,4 +1207,5 @@
     if (status != PJ_SUCCESS) {
 	check->tdata = NULL;
+	pjnath_perror(ice->obj_name, "Error sending STUN request", status);
 	return status;
     }
@@ -1290,4 +1308,17 @@
 }
 
+
+/* Utility: find string in string array */
+const pj_str_t *find_str(const pj_str_t *strlist[], unsigned count,
+			 const pj_str_t *str)
+{
+    unsigned i;
+    for (i=0; i<count; ++i) {
+	if (pj_strcmp(strlist[i], str)==0)
+	    return strlist[i];
+    }
+    return NULL;
+}
+
 /* Start ICE check */
 PJ_DEF(pj_status_t) pj_ice_sess_start_check(pj_ice_sess *ice)
@@ -1295,17 +1326,43 @@
     pj_ice_sess_checklist *clist;
     const pj_ice_sess_cand *cand0;
-    unsigned i;
+    const pj_str_t *flist[PJ_ICE_MAX_CAND];
+    unsigned i, flist_cnt = 0;
 
     PJ_ASSERT_RETURN(ice, PJ_EINVAL);
-    /* Checklist must be created */
+
+    /* Checklist must have been created */
     PJ_ASSERT_RETURN(ice->clist.count > 0, PJ_EINVALIDOP);
 
     LOG4((ice->obj_name, "Starting ICE check.."));
 
+    /* The agent examines the check list for the first media stream (a
+     * media stream is the first media stream when it is described by
+     * the first m-line in the SDP offer and answer).  For that media
+     * stream, it:
+     * 
+     * -  Groups together all of the pairs with the same foundation,
+     * 
+     * -  For each group, sets the state of the pair with the lowest
+     *    component ID to Waiting.  If there is more than one such pair,
+     *    the one with the highest priority is used.
+     */
+
     clist = &ice->clist;
 
-    /* Pickup the first pair and set the state to Waiting */
-    clist->checks[0].state = PJ_ICE_SESS_CHECK_STATE_WAITING;
-    cand0 = clist->checks[0].lcand;
+    /* Pickup the first pair for component 1. */
+    for (i=0; i<clist->count; ++i) {
+	if (clist->checks[0].lcand->comp_id == 1)
+	    break;
+    }
+    if (i == clist->count) {
+	pj_assert(!"Unable to find checklist for component 1");
+	return PJNATH_EICEINCOMPID;
+    }
+
+    /* Set this check to WAITING */
+    check_set_state(ice, &clist->checks[i], 
+		    PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
+    cand0 = clist->checks[i].lcand;
+    flist[flist_cnt++] = &clist->checks[i].lcand->foundation;
 
     /* Find all of the other pairs in that check list with the same
@@ -1313,13 +1370,15 @@
      * states to Waiting as well.
      */
-    for (i=1; i<clist->count; ++i) {
+    for (++i; i<clist->count; ++i) {
 	const pj_ice_sess_cand *cand1;
 
 	cand1 = clist->checks[i].lcand;
 
-	if (cand0->comp_id == cand1->comp_id &&
-	    pj_strcmp(&cand0->foundation, &cand1->foundation)!=0)
+	if (cand1->comp_id==cand0->comp_id &&
+	    find_str(flist, flist_cnt, &cand1->foundation)==NULL)
 	{
-	    clist->checks[i].state = PJ_ICE_SESS_CHECK_STATE_WAITING;
+	    check_set_state(ice, &clist->checks[i], 
+			    PJ_ICE_SESS_CHECK_STATE_WAITING, PJ_SUCCESS);
+	    flist[flist_cnt++] = &cand1->foundation;
 	}
     }
@@ -1342,5 +1401,7 @@
 {
     stun_data *sd = (stun_data*) pj_stun_session_get_user_data(sess);
-    return (*sd->ice->cb.on_tx_pkt)(sd->ice, sd->lcand->comp_id, sd->lcand_id,
+    pj_ice_sess *ice = sd->ice;
+    return (*sd->ice->cb.on_tx_pkt)(sd->ice, sd->lcand->comp_id, 
+				    GET_LCAND_ID(sd->lcand),
 				    pkt, pkt_size, 
 				    dst_addr, addr_len);
Index: pjproject/trunk/pjnath/src/pjnath/ice_strans.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 1126)
@@ -66,17 +66,5 @@
 
 /* Utility: print error */
-#if PJ_LOG_MAX_LEVEL >= 3
-static void ice_st_perror(pj_ice_strans *ice_st, const char *title, 
-			  pj_status_t status)
-{
-    char errmsg[PJ_ERR_MSG_SIZE];
-
-    pj_strerror(status, errmsg, sizeof(errmsg));
-    PJ_LOG(3,(ice_st->obj_name, "%s: %s", title, errmsg));
-}
-#else
-#   define ice_st_perror(ice_st, title, status)
-#endif
-
+#define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
 
 /* 
@@ -345,4 +333,5 @@
 	    pj_sockaddr_in cand_addr;
 	    pj_bool_t set_default;
+	    pj_uint16_t local_pref;
 
 	    /* Ignore 127.0.0.0/24 address */
@@ -359,12 +348,13 @@
 	    if (ifs[i].s_addr == comp->local_addr.ipv4.sin_addr.s_addr) {
 		set_default = PJ_TRUE;
+		local_pref = 65535;
 	    } else {
 		set_default = PJ_FALSE;
+		local_pref = 0;
 	    }
 
 	    status = add_cand(ice_st, comp, comp_id, 
 			      PJ_ICE_CAND_TYPE_HOST, 
-			      (pj_uint16_t)(65535-i), &cand_addr,
-			      set_default);
+			      local_pref, &cand_addr, set_default);
 	    if (status != PJ_SUCCESS)
 		goto on_error;
@@ -760,4 +750,5 @@
     unsigned i;
     pj_ice_sess_cb ice_cb;
+    const pj_uint8_t srflx_prio[4] = { 100, 126, 110, 0 };
 
     /* Check arguments */
@@ -783,4 +774,16 @@
     /* Associate user data */
     ice_st->ice->user_data = (void*)ice_st;
+
+    /* If default candidate for components are SRFLX one, upload a custom
+     * type priority to ICE session so that SRFLX candidates will get
+     * checked first.
+     */
+    if (ice_st->comp[0]->default_cand >= 0 &&
+	ice_st->comp[0]->cand_list[ice_st->comp[0]->default_cand].type 
+	    == PJ_ICE_CAND_TYPE_SRFLX)
+    {
+	pj_ice_sess_set_prefs(ice_st->ice, srflx_prio);
+    }
+
 
     /* Add candidates */
Index: pjproject/trunk/pjnath/src/pjnath/stun_auth.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/stun_auth.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/stun_auth.c	(revision 1126)
@@ -270,5 +270,7 @@
 	pj_bool_t ok;
 
-	if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
+	if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC &&
+	    cred->data.dyn_cred.verify_nonce != NULL) 
+	{
 	    ok=cred->data.dyn_cred.verify_nonce(msg, 
 						cred->data.dyn_cred.user_data,
@@ -276,4 +278,6 @@
 						&auser->value,
 						&anonce->value);
+	} else if (cred->type == PJ_STUN_AUTH_CRED_DYNAMIC) {
+	    ok = PJ_TRUE;
 	} else {
 	    if (nonce.slen) {
Index: pjproject/trunk/pjnath/src/pjnath/stun_msg.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1126)
@@ -140,5 +140,5 @@
 
 
-struct attr_desc mandatory_attr_desc[] = 
+static struct attr_desc mandatory_attr_desc[] = 
 {
     {
@@ -438,5 +438,5 @@
     {
 	/* PJ_STUN_ATTR_ICE_CONTROLLED, */
-	"ICE-CCONTROLLED",
+	"ICE-CONTROLLED",
 	&decode_uint64_attr,
 	&encode_uint64_attr
@@ -444,5 +444,5 @@
     {
 	/* PJ_STUN_ATTR_ICE_CONTROLLING, */
-	"ICE-CCONTROLLING",
+	"ICE-CONTROLLING",
 	&decode_uint64_attr,
 	&encode_uint64_attr
@@ -1871,6 +1871,4 @@
 		    /* Already has MESSAGE-INTEGRITY */
 		    if (p_response) {
-			pj_str_t e;
-			e = pj_str("MESSAGE-INTEGRITY already present");
 			pj_stun_msg_create_response(pool, msg,
 						    PJ_STUN_SC_BAD_REQUEST,
@@ -1885,6 +1883,4 @@
 		    /* Already has FINGERPRINT */
 		    if (p_response) {
-			pj_str_t e;
-			e = pj_str("FINGERPRINT already present");
 			pj_stun_msg_create_response(pool, msg,
 						    PJ_STUN_SC_BAD_REQUEST,
@@ -1899,6 +1895,4 @@
 		     * after FINGERPRINT or MESSAGE-INTEGRITY */
 		    if (p_response) {
-			pj_str_t e;
-			e = pj_str("Invalid attribute order");
 			pj_stun_msg_create_response(pool, msg,
 						    PJ_STUN_SC_BAD_REQUEST,
@@ -1913,10 +1907,7 @@
 	    if (msg->attr_count >= PJ_STUN_MAX_ATTR) {
 		if (p_response) {
-		    pj_str_t e;
-
-		    e = pj_str("Too many attributes");
 		    pj_stun_msg_create_response(pool, msg,
 						PJ_STUN_SC_BAD_REQUEST,
-						&e, p_response);
+						NULL, p_response);
 		}
 		return PJNATH_ESTUNTOOMANYATTR;
Index: pjproject/trunk/pjnath/src/pjnath/stun_msg_dump.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/stun_msg_dump.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/stun_msg_dump.c	(revision 1126)
@@ -23,4 +23,7 @@
 
 
+#if PJ_LOG_MAX_LEVEL > 0
+
+
 #define APPLY()		if (len < 1 || len >= (end-p)) \
 			    goto on_return; \
@@ -245,6 +248,8 @@
     return buffer;
 
+#undef APPLY
 }
 
 
-#undef APPLY
+#endif	/* PJ_LOG_MAX_LEVEL > 0 */
+
Index: pjproject/trunk/pjnath/src/pjnath/stun_session.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/stun_session.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/stun_session.c	(revision 1126)
@@ -44,19 +44,5 @@
 #endif
 
-#if PJ_LOG_MAX_LEVEL >= 4
-#   define LOG_ERR_(sess, title, rc) stun_perror(sess, title, rc)
-static void stun_perror(pj_stun_session *sess, const char *title, 
-			pj_status_t status)
-{
-    char errmsg[PJ_ERR_MSG_SIZE];
-
-    pj_strerror(status, errmsg, sizeof(errmsg));
-
-    PJ_LOG(4,(SNAME(sess), "%s: %s", title, errmsg));
-}
-
-#else
-#   define LOG_ERR_(sess, title, rc)
-#endif
+#define LOG_ERR_(sess,title,rc) pjnath_perror(sess->pool->obj_name,title,rc)
 
 #define TDATA_POOL_SIZE		    1024
@@ -780,5 +766,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;
Index: pjproject/trunk/pjnath/src/pjnath/stun_transaction.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/stun_transaction.c	(revision 1125)
+++ pjproject/trunk/pjnath/src/pjnath/stun_transaction.c	(revision 1126)
@@ -51,13 +51,5 @@
 				      pj_timer_entry *timer);
 
-static void stun_perror(pj_stun_client_tsx *tsx, const char *title,
-			pj_status_t status)
-{
-    char errmsg[PJ_ERR_MSG_SIZE];
-
-    pj_strerror(status, errmsg, sizeof(errmsg));
-    PJ_LOG(4,(tsx->obj_name, "%s: %s", title, errmsg));
-}
-
+#define stun_perror(tsx,msg,rc) pjnath_perror(tsx->obj_name, msg, rc)
 
 /*
@@ -85,5 +77,5 @@
     *p_tsx = tsx;
 
-    PJ_LOG(4,(tsx->obj_name, "STUN client transaction created"));
+    PJ_LOG(5,(tsx->obj_name, "STUN client transaction created"));
     return PJ_SUCCESS;
 }
@@ -192,5 +184,5 @@
     tsx->transmit_count++;
 
-    PJ_LOG(4,(tsx->obj_name, "STUN sending message (transmit count=%d)",
+    PJ_LOG(5,(tsx->obj_name, "STUN sending message (transmit count=%d)",
 	      tsx->transmit_count));
     return status;
