Index: /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c
===================================================================
--- /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1100)
+++ /pjproject/trunk/pjmedia/src/pjmedia/transport_ice.c	(revision 1101)
@@ -198,5 +198,5 @@
 
     /* Add all candidates (to media level) */
-    cand_cnt = pj_ice_get_cand_cnt(tp_ice->ice_st->ice);
+    cand_cnt = tp_ice->ice_st->ice->lcand_cnt;
     for (i=0; i<cand_cnt; ++i) {
 	pj_ice_cand *cand;
@@ -204,5 +204,5 @@
 	int len;
 
-	pj_ice_get_cand(tp_ice->ice_st->ice, i, &cand);
+	cand = &tp_ice->ice_st->ice->lcand[i];
 
 	len = pj_ansi_snprintf( buffer, MAXLEN,
@@ -266,5 +266,5 @@
     char *token, *host;
     pj_str_t s;
-    pj_status_t status = PJ_EICEINCANDSDP;
+    pj_status_t status = PJNATH_EICEINCANDSDP;
 
     pj_bzero(cand, sizeof(*cand));
@@ -342,4 +342,11 @@
 on_return:
     return status;
+}
+
+static void set_no_ice(struct transport_ice *tp_ice)
+{
+    PJ_LOG(4,(tp_ice->ice_st->obj_name, 
+	      "Remote does not support ICE, disabling local ICE"));
+    pjmedia_ice_stop_ice(&tp_ice->base);
 }
 
@@ -359,6 +366,8 @@
     attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
 				  "ice-ufrag", NULL);
-    if (attr == NULL)
-	return PJ_EICEMISSINGSDP;
+    if (attr == NULL) {
+	set_no_ice(tp_ice);
+	return PJ_SUCCESS;
+    }
     uname = attr->value;
 
@@ -366,6 +375,8 @@
     attr = pjmedia_sdp_attr_find2(rem_sdp->attr_count, rem_sdp->attr,
 				  "ice-pwd", NULL);
-    if (attr == NULL)
-	return PJ_EICEMISSINGSDP;
+    if (attr == NULL) {
+	set_no_ice(tp_ice);
+	return PJ_SUCCESS;
+    }
     pass = attr->value;
 
@@ -547,5 +558,5 @@
     PJ_TIME_VAL_SUB(end_ice, tp_ice->start_ice);
 
-    check = &ice_st->ice->clist.checks[ice_st->ice->valid_list[0]];
+    check = &ice_st->ice->valid_list.checks[0];
     
     lcand = check->lcand;
Index: /pjproject/trunk/pjnath/build/pjnath.dsp
===================================================================
--- /pjproject/trunk/pjnath/build/pjnath.dsp	(revision 1100)
+++ /pjproject/trunk/pjnath/build/pjnath.dsp	(revision 1101)
@@ -42,6 +42,6 @@
 # PROP Target_Dir ""
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
-# ADD CPP /nologo /MD /W4 /GX /Zi /O2 /Ob2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
-# SUBTRACT CPP /YX
+# ADD CPP /nologo /MD /W4 /GX /O1 /Ob2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
+# SUBTRACT CPP /Z<none> /YX
 # ADD BASE RSC /l 0x409 /d "NDEBUG"
 # ADD RSC /l 0x409 /d "NDEBUG"
Index: /pjproject/trunk/pjnath/include/pjnath.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath.h	(revision 1100)
+++ /pjproject/trunk/pjnath/include/pjnath.h	(revision 1101)
@@ -28,2 +28,3 @@
 #include <pjnath/stun_transaction.h>
 #include <pjnath/types.h>
+
Index: /pjproject/trunk/pjnath/include/pjnath/errno.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1100)
+++ /pjproject/trunk/pjnath/include/pjnath/errno.h	(revision 1101)
@@ -24,5 +24,5 @@
 
 /**
- * @defgroup PJNATH_ERROR NAT Helper Error Codes
+ * @defgroup PJNATH_ERROR NAT Helper Library Error Codes
  * @ingroup PJNATH
  * @{
@@ -36,15 +36,30 @@
 
 
+/************************************************************
+ * STUN MESSAGING ERRORS
+ ***********************************************************/
 
-/************************************************************
- * NEW STUN ERROR
- ***********************************************************/
-/* Messaging errors */
-#define PJNATH_ESTUNINATTRLEN	    -1
-#define PJNATH_ESTUNINMSGLEN	    -1
-#define	PJNATH_ESTUNINMSGTYPE	    -1
-#define PJNATH_ESTUNFINGERPRINT	    -1
-#define PJNATH_ESTUNNOTRESPOND	    -1
-#define PJNATH_ESTUNNOXORMAP	    -1
+/**
+ * Map STUN error code (300-699) into pj_status_t error space.
+ */
+#define PJ_STATUS_FROM_STUN_CODE(code)	(PJNATH_ERRNO_START+code)
+
+/**
+ * @hideinitializer
+ * Invalid STUN message length.
+ */
+#define PJNATH_EINSTUNMSGLEN	    (PJNATH_ERRNO_START+1)  /* 370001 */
+/**
+ * @hideinitializer
+ * Invalid or unexpected STUN message type
+ */
+#define	PJNATH_EINSTUNMSGTYPE	    (PJNATH_ERRNO_START+2)  /* 370002 */
+/**
+ * @hideinitializer
+ * STUN transaction has timed out
+ */
+#define PJNATH_ESTUNTIMEDOUT	    (PJNATH_ERRNO_START+3)  /* 370003 */
+
+
 
 /**
@@ -52,136 +67,86 @@
  * Too many STUN attributes.
  */
-#define PJNATH_ESTUNTOOMANYATTR	    (PJNATH_ERRNO_START+110)/* 370110 */
+#define PJNATH_ESTUNTOOMANYATTR	    (PJNATH_ERRNO_START+21) /* 370021 */
 /**
  * @hideinitializer
- * Unknown STUN attribute. This error happens when the decoder encounters
- * mandatory attribute type which it doesn't understand.
+ * Invalid STUN attribute length.
  */
-#define PJNATH_ESTUNUNKNOWNATTR	    (PJNATH_ERRNO_START+111)/* 370111 */
+#define PJNATH_ESTUNINATTRLEN	    (PJNATH_ERRNO_START+22) /* 370022 */
 /**
  * @hideinitializer
- * Invalid STUN socket address length.
+ * Found duplicate STUN attribute.
  */
-#define PJNATH_ESTUNINADDRLEN	    (PJNATH_ERRNO_START+112)/* 370112 */
+#define PJNATH_ESTUNDUPATTR	    (PJNATH_ERRNO_START+23) /* 370023 */
+
+/**
+ * @hideinitializer
+ * STUN FINGERPRINT verification failed
+ */
+#define PJNATH_ESTUNFINGERPRINT	    (PJNATH_ERRNO_START+30) /* 370030 */
+/**
+ * @hideinitializer
+ * Invalid STUN attribute after MESSAGE-INTEGRITY.
+ */
+#define PJNATH_ESTUNMSGINTPOS	    (PJNATH_ERRNO_START+31) /* 370031 */
+/**
+ * @hideinitializer
+ * Invalid STUN attribute after FINGERPRINT.
+ */
+#define PJNATH_ESTUNFINGERPOS	    (PJNATH_ERRNO_START+33) /* 370033 */
+
+
+/**
+ * @hideinitializer
+ * STUN (XOR-)MAPPED-ADDRESS attribute not found
+ */
+#define PJNATH_ESTUNNOMAPPEDADDR    (PJNATH_ERRNO_START+40) /* 370040 */
 /**
  * @hideinitializer
  * STUN IPv6 attribute not supported
  */
-#define PJNATH_ESTUNIPV6NOTSUPP	    (PJNATH_ERRNO_START+113)/* 370113 */
-/**
- * @hideinitializer
- * Expecting STUN response message.
- */
-#define PJNATH_ESTUNNOTRESPONSE	    (PJNATH_ERRNO_START+114)/* 370114 */
-/**
- * @hideinitializer
- * STUN transaction ID mismatch.
- */
-#define PJNATH_ESTUNINVALIDID	    (PJNATH_ERRNO_START+115)/* 370115 */
-/**
- * @hideinitializer
- * Unable to find handler for the request.
- */
-#define PJNATH_ESTUNNOHANDLER	    (PJNATH_ERRNO_START+116)/* 370116 */
-/**
- * @hideinitializer
- * Found non-FINGERPRINT attribute after MESSAGE-INTEGRITY. This is not
- * valid since MESSAGE-INTEGRITY MUST be the last attribute or the
- * attribute right before FINGERPRINT before the message.
- */
-#define PJNATH_ESTUNMSGINTPOS	    (PJNATH_ERRNO_START+118)/* 370118 */
-/**
- * @hideinitializer
- * Found attribute after FINGERPRINT. This is not valid since FINGERPRINT
- * MUST be the last attribute in the message.
- */
-#define PJNATH_ESTUNFINGERPOS	    (PJNATH_ERRNO_START+119)/* 370119 */
-/**
- * @hideinitializer
- * Missing STUN USERNAME attribute.
- * When credential is included in the STUN message (MESSAGE-INTEGRITY is
- * present), the USERNAME attribute must be present in the message.
- */
-#define PJNATH_ESTUNNOUSERNAME	    (PJNATH_ERRNO_START+120)/* 370120 */
-/**
- * @hideinitializer
- * Unknown STUN username/credential.
- */
-#define PJNATH_ESTUNUSERNAME	    (PJNATH_ERRNO_START+121)/* 370121 */
-/**
- * @hideinitializer
- * Missing/invalidSTUN MESSAGE-INTEGRITY attribute.
- */
-#define PJNATH_ESTUNMSGINT	    (PJNATH_ERRNO_START+122)/* 370122 */
-/**
- * @hideinitializer
- * Found duplicate STUN attribute.
- */
-#define PJNATH_ESTUNDUPATTR	    (PJNATH_ERRNO_START+123)/* 370123 */
-/**
- * @hideinitializer
- * Missing STUN REALM attribute.
- */
-#define PJNATH_ESTUNNOREALM	    (PJNATH_ERRNO_START+124)/* 370124 */
-/**
- * @hideinitializer
- * Missing/stale STUN NONCE attribute value.
- */
-#define PJNATH_ESTUNNONCE	    (PJNATH_ERRNO_START+125)/* 370125 */
-/**
- * @hideinitializer
- * STUN transaction terminates with failure.
- */
-#define PJNATH_ESTUNTSXFAILED	    (PJNATH_ERRNO_START+126)/* 370126 */
-/**
- * @hideinitializer
- * STUN mapped address attribute not found
- */
-#define PJNATH_ESTUNNOMAPPEDADDR    (PJNATH_ERRNO_START+127)/* 370127 */
+#define PJNATH_ESTUNIPV6NOTSUPP	    (PJNATH_ERRNO_START+41) /* 370041 */
 
 
-//#define PJ_STATUS_FROM_STUN_CODE(code)	(PJNATH_ERRNO_START+code)
 
+
+/************************************************************
+ * ICE ERROR CODES
+ ***********************************************************/
 
 /**
  * @hideinitializer
- * No ICE checklist is formed.
+ * ICE session not available
  */
-#define PJ_EICENOCHECKLIST	    -1
+#define PJNATH_ENOICE		    (PJNATH_ERRNO_START+80) /* 370080 */
 /**
  * @hideinitializer
- * No suitable default ICE candidate for the component.
+ * ICE check is in progress
  */
-#define PJ_EICENOCAND		    -1
+#define PJNATH_EICEINPROGRESS	    (PJNATH_ERRNO_START+81) /* 370081 */
+/**
+ * @hideinitializer
+ * All ICE checklists failed
+ */
+#define PJNATH_EICEFAILED	    (PJNATH_ERRNO_START+82) /* 370082 */
 /**
  * @hideinitializer
  * Invalid ICE component ID
  */
-#define PJ_EICEINCOMPID		    -1
+#define PJNATH_EICEINCOMPID	    (PJNATH_ERRNO_START+86) /* 370086 */
 /**
  * @hideinitializer
  * Invalid ICE candidate ID
  */
-#define PJ_EICEINCANDID		    -1
-/**
- * @hideinitializer
- * ICE session not available
- */
-#define PJ_ENOICE		    -1
-/**
- * @hideinitializer
- * ICE check is in progress
- */
-#define PJ_EICEINPROGRESS	    -1
+#define PJNATH_EICEINCANDID	    (PJNATH_ERRNO_START+87) /* 370087 */
 /**
  * @hideinitializer
  * Missing ICE SDP attribute
  */
-#define PJ_EICEMISSINGSDP	    -1
+#define PJNATH_EICEMISSINGSDP	    (PJNATH_ERRNO_START+90) /* 370090 */
 /**
  * @hideinitializer
  * Invalid SDP "candidate" attribute
  */
-#define PJ_EICEINCANDSDP	    -1
+#define PJNATH_EICEINCANDSDP	    (PJNATH_ERRNO_START+91) /* 370091 */
 
 
Index: /pjproject/trunk/pjnath/include/pjnath/ice.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/ice.h	(revision 1100)
+++ /pjproject/trunk/pjnath/include/pjnath/ice.h	(revision 1101)
@@ -97,5 +97,5 @@
     pj_sockaddr		 addr;
     pj_sockaddr		 base_addr;
-    pj_sockaddr		 srv_addr;
+    pj_sockaddr		 rel_addr;
     pj_stun_session	*stun_sess;
 } pj_ice_cand;
@@ -205,6 +205,5 @@
     
     /* Valid list */
-    unsigned		 valid_cnt;
-    unsigned		 valid_list[PJ_ICE_MAX_CHECKS];
+    pj_ice_checklist	 valid_list;
 };
 
@@ -213,4 +212,5 @@
 				   const char *name,
 				   pj_ice_role role,
+				   unsigned comp_cnt,
 				   const pj_ice_cb *cb,
 				   const pj_str_t *local_ufrag,
@@ -218,5 +218,4 @@
 				   pj_ice **p_ice);
 PJ_DECL(pj_status_t) pj_ice_destroy(pj_ice *ice);
-PJ_DECL(pj_status_t) pj_ice_add_comp(pj_ice *ice, unsigned comp_id);
 PJ_DECL(pj_status_t) pj_ice_add_cand(pj_ice *ice,
 				     unsigned comp_id,
@@ -226,18 +225,11 @@
 				     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 *cand_id);
 
-PJ_DECL(unsigned) pj_ice_get_cand_cnt(pj_ice *ice);
-PJ_DECL(pj_status_t) pj_ice_enum_cands(pj_ice *ice,
-				       unsigned *p_count,
-				       unsigned cand_ids[]);
-PJ_DECL(pj_status_t) pj_ice_get_default_cand(pj_ice *ice,
-					     unsigned comp_id,
-					     int *cand_id);
-PJ_DECL(pj_status_t) pj_ice_get_cand(pj_ice *ice,
-				     unsigned cand_id,
-				     pj_ice_cand **p_cand);
+PJ_DECL(pj_status_t) pj_ice_find_default_cand(pj_ice *ice,
+					      unsigned comp_id,
+					      int *cand_id);
 
 PJ_DECL(pj_status_t) pj_ice_create_check_list(pj_ice *ice,
Index: /pjproject/trunk/pjnath/include/pjnath/stun_msg.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/stun_msg.h	(revision 1100)
+++ /pjproject/trunk/pjnath/include/pjnath/stun_msg.h	(revision 1101)
@@ -384,5 +384,4 @@
     PJ_STUN_SC_STALE_NONCE	        = 438,  /**< Stale Nonce	    */
     PJ_STUN_SC_TRANSITIONING		= 439,  /**< Transitioning.	    */
-    PJ_STUN_SC_WRONG_USERNAME	        = 441,  /**< Wrong Username.	    */
     PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO   = 442,  /**< Unsupported Transport or
 						     Protocol */
Index: /pjproject/trunk/pjnath/include/pjnath/types.h
===================================================================
--- /pjproject/trunk/pjnath/include/pjnath/types.h	(revision 1100)
+++ /pjproject/trunk/pjnath/include/pjnath/types.h	(revision 1101)
@@ -30,5 +30,24 @@
 /**
  * @defgroup PJNATH NAT Helper Library
+ * @{
  */
+
+PJ_BEGIN_DECL
+
+/**
+ * Initialize pjnath library.
+ *
+ * @return  Initialization status.
+ */
+PJ_DECL(pj_status_t) pjnath_init(void);
+
+
+PJ_END_DECL
+
+/**
+ * @}
+ */
+
+/* Doxygen documentation below: */
 
 /**
@@ -44,18 +63,4 @@
  * of modules.
  *
- *
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
- * \n
  */
 
Index: /pjproject/trunk/pjnath/src/pjnath/errno.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1100)
+++ /pjproject/trunk/pjnath/src/pjnath/errno.c	(revision 1101)
@@ -18,4 +18,5 @@
  */
 #include <pjnath/errno.h>
+#include <pjnath/stun_msg.h>
 #include <pj/string.h>
 
@@ -33,20 +34,29 @@
 } err_str[] = 
 {
-    /* STUN */
+    /* STUN related error codes */
+    PJ_BUILD_ERR( PJNATH_EINSTUNMSGLEN,	    "Invalid STUN message length"),
+    PJ_BUILD_ERR( PJNATH_EINSTUNMSGTYPE,    "Invalid or unexpected STUN message type"),
+    PJ_BUILD_ERR( PJNATH_ESTUNTIMEDOUT,	    "STUN transaction has timed out"),
+
     PJ_BUILD_ERR( PJNATH_ESTUNTOOMANYATTR,  "Too many STUN attributes"),
-    PJ_BUILD_ERR( PJNATH_ESTUNUNKNOWNATTR,  "Unknown STUN attribute"),
-    PJ_BUILD_ERR( PJNATH_ESTUNINADDRLEN,    "Invalid STUN socket address length"),
+    PJ_BUILD_ERR( PJNATH_ESTUNINATTRLEN,    "Invalid STUN attribute length"),
+    PJ_BUILD_ERR( PJNATH_ESTUNDUPATTR,	    "Found duplicate STUN attribute"),
+
+    PJ_BUILD_ERR( PJNATH_ESTUNFINGERPRINT,  "STUN FINGERPRINT verification failed"),
+    PJ_BUILD_ERR( PJNATH_ESTUNMSGINTPOS,    "Invalid STUN attribute after MESSAGE-INTEGRITY"),
+    PJ_BUILD_ERR( PJNATH_ESTUNFINGERPOS,    "Invalid STUN attribute after FINGERPRINT"),
+
+    PJ_BUILD_ERR( PJNATH_ESTUNNOMAPPEDADDR, "STUN (XOR-)MAPPED-ADDRESS attribute not found"),
     PJ_BUILD_ERR( PJNATH_ESTUNIPV6NOTSUPP,  "STUN IPv6 attribute not supported"),
-    PJ_BUILD_ERR( PJNATH_ESTUNNOTRESPONSE,  "Expecting STUN response message"),
-    PJ_BUILD_ERR( PJNATH_ESTUNINVALIDID,    "STUN transaction ID mismatch"),
-    PJ_BUILD_ERR( PJNATH_ESTUNNOHANDLER,    "Unable to find STUN handler for the request"),
-    PJ_BUILD_ERR( PJNATH_ESTUNMSGINTPOS,    "Found non-FINGERPRINT attr. after MESSAGE-INTEGRITY"),
-    PJ_BUILD_ERR( PJNATH_ESTUNFINGERPOS,    "Found STUN attribute after FINGERPRINT"),
-    PJ_BUILD_ERR( PJNATH_ESTUNNOUSERNAME,   "Missing STUN USERNAME attribute"),
-    PJ_BUILD_ERR( PJNATH_ESTUNMSGINT,	    "Missing/invalid STUN MESSAGE-INTEGRITY attribute"),
-    PJ_BUILD_ERR( PJNATH_ESTUNDUPATTR,	    "Found duplicate STUN attribute"),
-    PJ_BUILD_ERR( PJNATH_ESTUNNOREALM,	    "Missing STUN REALM attribute"),
-    PJ_BUILD_ERR( PJNATH_ESTUNNONCE,	    "Missing/stale STUN NONCE attribute value"),
-    PJ_BUILD_ERR( PJNATH_ESTUNTSXFAILED,    "STUN transaction terminates with failure"),
+
+    /* ICE related errors */
+    PJ_BUILD_ERR( PJNATH_ENOICE,	    "ICE session not available"),
+    PJ_BUILD_ERR( PJNATH_EICEINPROGRESS,    "ICE check is in progress"),
+    PJ_BUILD_ERR( PJNATH_EICEFAILED,	    "All ICE checklists failed"),
+    PJ_BUILD_ERR( PJNATH_EICEINCOMPID,	    "Invalid ICE component ID"),
+    PJ_BUILD_ERR( PJNATH_EICEINCANDID,	    "Invalid ICE candidate ID"),
+    PJ_BUILD_ERR( PJNATH_EICEMISSINGSDP,    "Missing ICE SDP attribute"),
+    PJ_BUILD_ERR( PJNATH_EICEINCANDSDP,	    "Invalid SDP \"candidate\" attribute"),
+
 };
 #endif	/* PJ_HAS_ERROR_STRING */
@@ -56,6 +66,6 @@
  * pjnath_strerror()
  */
-PJ_DEF(pj_str_t) pjnath_strerror( pj_status_t statcode, 
-				  char *buf, pj_size_t bufsize )
+static pj_str_t pjnath_strerror(pj_status_t statcode, 
+				char *buf, pj_size_t bufsize )
 {
     pj_str_t errstr;
@@ -107,6 +117,33 @@
     errstr.ptr = buf;
     errstr.slen = pj_ansi_snprintf(buf, bufsize, 
-				   "Unknown pjlib-util error %d",
+				   "Unknown pjnath error %d",
 				   statcode);
+    if (errstr.slen < 0) errstr.slen = 0;
+    else if (errstr.slen > (int)bufsize) errstr.slen = bufsize;
+
+    return errstr;
+}
+
+
+static pj_str_t pjnath_strerror2(pj_status_t statcode, 
+				 char *buf, pj_size_t bufsize )
+{
+    int stun_code = statcode - PJ_STATUS_FROM_STUN_CODE(0);
+    const pj_str_t cmsg = pj_stun_get_err_reason(stun_code);
+    pj_str_t errstr;
+
+    if (cmsg.slen == 0) {
+	/* Not found */
+	errstr.ptr = buf;
+	errstr.slen = pj_ansi_snprintf(buf, bufsize, 
+				       "Unknown STUN err-code %d",
+				       stun_code);
+    } else {
+	errstr.ptr = buf;
+	pj_strncpy(&errstr, &cmsg, bufsize);
+    }
+
+    if (errstr.slen < 0) errstr.slen = 0;
+    else if (errstr.slen > (int)bufsize) errstr.slen = bufsize;
 
     return errstr;
@@ -116,6 +153,15 @@
 PJ_DEF(pj_status_t) pjnath_init(void)
 {
-    return pj_register_strerror(PJNATH_ERRNO_START, 
-				PJ_ERRNO_SPACE_SIZE, 
-				&pjnath_strerror);
+    pj_status_t status;
+
+    status = pj_register_strerror(PJNATH_ERRNO_START, 299, 
+				  &pjnath_strerror);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    status = pj_register_strerror(PJ_STATUS_FROM_STUN_CODE(300), 
+				  699 - 300, 
+				  &pjnath_strerror2);
+    return status;
 }
+
Index: /pjproject/trunk/pjnath/src/pjnath/ice.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice.c	(revision 1100)
+++ /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;
     }
Index: /pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c	(revision 1100)
+++ /pjproject/trunk/pjnath/src/pjnath/ice_stream_transport.c	(revision 1101)
@@ -365,5 +365,5 @@
 
     /* Component ID must be valid */
-    PJ_ASSERT_RETURN(comp_id <= PJ_ICE_MAX_COMP, PJ_EICEINCOMPID);
+    PJ_ASSERT_RETURN(comp_id <= PJ_ICE_MAX_COMP, PJNATH_EICEINCOMPID);
 
     /* First component ID must be 1, second must be 2, etc., and 
@@ -371,5 +371,5 @@
      */
     PJ_ASSERT_RETURN(ice_st->comps[comp_id-1] == ice_st->comp_cnt, 
-		     PJ_EICEINCOMPID);
+		     PJNATH_EICEINCOMPID);
 
     /* All in order, add the component. */
@@ -408,5 +408,5 @@
 
     /* Check that component ID present */
-    PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJ_EICEINCOMPID);
+    PJ_ASSERT_RETURN(comp_id <= ice_st->comp_cnt, PJNATH_EICEINCOMPID);
 
     /* Can't add new interface while ICE is running */
@@ -579,5 +579,6 @@
     /* Create! */
     status = pj_ice_create(&ice_st->stun_cfg, ice_st->obj_name, role, 
-			   &ice_cb, local_ufrag, local_passwd, &ice_st->ice);
+			   ice_st->comp_cnt, &ice_cb, 
+			   local_ufrag, local_passwd, &ice_st->ice);
     if (status != PJ_SUCCESS)
 	return status;
@@ -585,11 +586,4 @@
     /* Associate user data */
     ice_st->ice->user_data = (void*)ice_st;
-
-    /* Add components */
-    for (i=0; i<ice_st->comp_cnt; ++i) {
-	status = pj_ice_add_comp(ice_st->ice, ice_st->comps[i]);
-	if (status != PJ_SUCCESS)
-	    goto on_error;
-    }
 
     /* Add candidates */
@@ -627,18 +621,14 @@
     unsigned i, cnt;
     pj_ice_cand *pcand;
-    pj_status_t status;
 
     PJ_ASSERT_RETURN(ice_st && count && cand, PJ_EINVAL);
     PJ_ASSERT_RETURN(ice_st->ice, PJ_EINVALIDOP);
 
-    cnt = pj_ice_get_cand_cnt(ice_st->ice);
+    cnt = ice_st->ice->lcand_cnt;
     cnt = (cnt > *count) ? *count : cnt;
     *count = 0;
 
     for (i=0; i<cnt; ++i) {
-	status = pj_ice_get_cand(ice_st->ice, i, &pcand);
-	if (status != PJ_SUCCESS)
-	    return status;
-
+	pcand = &ice_st->ice->lcand[i];
 	pj_memcpy(&cand[i], pcand, sizeof(pj_ice_cand));
     }
@@ -689,5 +679,5 @@
 {
     if (!ice_st->ice)
-	return PJ_ENOICE;
+	return PJNATH_ENOICE;
 
     return pj_ice_send_data(ice_st->ice, comp_id, data, data_len);
@@ -753,5 +743,5 @@
     }
     if (is == NULL) {
-	return PJ_EICEINCANDID;
+	return PJNATH_EICEINCANDID;
     }
 
Index: /pjproject/trunk/pjnath/src/pjnath/stun_auth.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_auth.c	(revision 1100)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_auth.c	(revision 1101)
@@ -160,5 +160,5 @@
 			     &realm, &nonce, p_response);
 	}
-	return PJNATH_ESTUNMSGINT;
+	return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE);
     }
 
@@ -171,5 +171,5 @@
 			     &realm, &nonce, p_response);
 	}
-	return PJNATH_ESTUNNOUSERNAME;
+	return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_USERNAME);
     }
 
@@ -203,5 +203,5 @@
 			     &realm, &nonce, p_response);
 	}
-	return PJNATH_ESTUNUSERNAME;
+	return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_USERNAME);
     }
 
@@ -218,5 +218,5 @@
 			     &realm, &nonce, p_response);
 	}
-	return PJNATH_ESTUNNOREALM;
+	return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_REALM);
 
     } else if (realm.slen != 0 && arealm != NULL) {
@@ -229,5 +229,5 @@
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJNATH_ESTUNNONCE;
+	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_NONCE);
 	}
 
@@ -239,5 +239,5 @@
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJNATH_ESTUNNOREALM;
+	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_REALM);
 	}
 
@@ -262,5 +262,5 @@
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJNATH_ESTUNNONCE;
+	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_NONCE);
 	}
     }
@@ -289,5 +289,5 @@
 				 NULL, &realm, &nonce, p_response);
 	    }
-	    return PJNATH_ESTUNNONCE;
+	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_NONCE);
 	}
     }
@@ -334,5 +334,5 @@
 			     NULL, &realm, &nonce, p_response);
 	}
-	return PJNATH_ESTUNMSGINT;
+	return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_INTEGRITY_CHECK_FAILURE);
     }
 
Index: /pjproject/trunk/pjnath/src/pjnath/stun_msg.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1100)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_msg.c	(revision 1101)
@@ -65,5 +65,4 @@
     { PJ_STUN_SC_STALE_NONCE,		    "Stale Nonce"},
     { PJ_STUN_SC_TRANSITIONING,		    "Active Destination Already Set"},
-    { PJ_STUN_SC_WRONG_USERNAME,	    "Wrong Username"},
     { PJ_STUN_SC_UNSUPP_TRANSPORT_PROTO,    "Unsupported Transport Protocol"},
     { PJ_STUN_SC_INVALID_IP_ADDR,	    "Invalid IP Address"},
@@ -514,4 +513,6 @@
 PJ_DEF(pj_str_t) pj_stun_get_err_reason(int err_code)
 {
+#if 0
+    /* Find error using linear search */
     unsigned i;
 
@@ -521,4 +522,31 @@
     }
     return pj_str(NULL);
+#else
+    /* Find error message using binary search */
+    int first = 0;
+    int n = PJ_ARRAY_SIZE(stun_err_msg_map);
+
+    while (n > 0) {
+	int half = n/2;
+	int mid = first + half;
+
+	if (stun_err_msg_map[mid].err_code < err_code) {
+	    first = mid+1;
+	    n -= (half+1);
+	} else if (stun_err_msg_map[mid].err_code > err_code) {
+	    n = half;
+	} else {
+	    first = mid;
+	    break;
+	}
+    }
+
+
+    if (stun_err_msg_map[first].err_code == err_code) {
+	return pj_str((char*)stun_err_msg_map[first].err_msg);
+    } else {
+	return pj_str(NULL);
+    }
+#endif
 }
 
@@ -1580,9 +1608,9 @@
 
     if (pdu_len < sizeof(pj_stun_msg_hdr))
-	return PJNATH_ESTUNINMSGLEN;
+	return PJNATH_EINSTUNMSGLEN;
 
     /* First byte of STUN message is always 0x00 or 0x01. */
     if (*pdu != 0x00 && *pdu != 0x01)
-	return PJNATH_ESTUNINMSGTYPE;
+	return PJNATH_EINSTUNMSGTYPE;
 
     /* Check the PDU length */
@@ -1591,5 +1619,5 @@
 	((options & PJ_STUN_IS_DATAGRAM) && msg_len + 20 != pdu_len))
     {
-	return PJNATH_ESTUNINMSGLEN;
+	return PJNATH_EINSTUNMSGLEN;
     }
 
@@ -1635,5 +1663,5 @@
 
     PJ_ASSERT_RETURN(PJ_STUN_IS_REQUEST(msg_type), 
-		     PJNATH_ESTUNINMSGTYPE);
+		     PJNATH_EINSTUNMSGTYPE);
 
     /* Create response or error response */
@@ -1774,5 +1802,5 @@
 		}
 
-		return PJNATH_ESTUNUNKNOWNATTR;
+		return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_UNKNOWN_ATTRIBUTE);
 	    }
 
@@ -2103,5 +2131,5 @@
 	    /* Should not happen for message generated by us */
 	    pj_assert(PJ_FALSE);
-	    return PJNATH_ESTUNNOUSERNAME;
+	    return PJ_STATUS_FROM_STUN_CODE(PJ_STUN_SC_MISSING_USERNAME);
 	}
 
Index: /pjproject/trunk/pjnath/src/pjnath/stun_transaction.c
===================================================================
--- /pjproject/trunk/pjnath/src/pjnath/stun_transaction.c	(revision 1100)
+++ /pjproject/trunk/pjnath/src/pjnath/stun_transaction.c	(revision 1101)
@@ -236,5 +236,5 @@
 	tsx->complete = PJ_TRUE;
 	if (tsx->cb.on_complete) {
-	    tsx->cb.on_complete(tsx, PJNATH_ESTUNNOTRESPOND, NULL);
+	    tsx->cb.on_complete(tsx, PJNATH_ESTUNTIMEDOUT, NULL);
 	}
 	return;
@@ -269,5 +269,5 @@
 	PJ_LOG(4,(tsx->obj_name, 
 		  "STUN rx_msg() error: not response message"));
-	return PJNATH_ESTUNNOTRESPONSE;
+	return PJNATH_EINSTUNMSGTYPE;
     }
 
@@ -301,5 +301,6 @@
 	status = PJ_SUCCESS;
     } else {
-	status = PJNATH_ESTUNTSXFAILED;
+	status = PJ_STATUS_FROM_STUN_CODE(err_attr->err_class * 100 + 
+					  err_attr->number);
     }
 
Index: /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c
===================================================================
--- /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1100)
+++ /pjproject/trunk/pjsip/src/pjsua-lib/pjsua_core.c	(revision 1101)
@@ -400,4 +400,7 @@
     PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
 
+    /* Init PJNATH */
+    status = pjnath_init();
+    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);
 
     /* Set default sound device ID */
