Index: pjproject/trunk/pjlib-util/include/pjlib-util/stun_endpoint.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/stun_endpoint.h	(revision 995)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/stun_endpoint.h	(revision 996)
@@ -62,14 +62,14 @@
  * Create a STUN endpoint instance.
  */
-PJ_DECL(pj_status_t) pj_stun_endpt_create(pj_pool_factory *factory,
-					  unsigned options,
-					  pj_ioqueue_t *ioqueue,
-					  pj_timer_heap_t *timer_heap,
-					  pj_stun_endpoint **p_endpt);
+PJ_DECL(pj_status_t) pj_stun_endpoint_create(pj_pool_factory *factory,
+					     unsigned options,
+					     pj_ioqueue_t *ioqueue,
+					     pj_timer_heap_t *timer_heap,
+					     pj_stun_endpoint **p_endpt);
 
 /**
  * Destroy STUN endpoint instance.
  */
-PJ_DECL(pj_status_t) pj_stun_endpt_destroy(pj_stun_endpoint *endpt);
+PJ_DECL(pj_status_t) pj_stun_endpoint_destroy(pj_stun_endpoint *endpt);
 
 
Index: pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h	(revision 995)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/stun_msg.h	(revision 996)
@@ -1196,7 +1196,7 @@
  * @param buffer	Buffer where the printable string output will
  *			be printed on.
- * @param length	On input, specify the maximum length of the buffer.
- *			On output, it will be filled up with the actual
- *			length of the output string.
+ * @param length	Specify the maximum length of the buffer.
+ * @param printed_len	Optional pointer, which on output will be filled
+ *			up with the actual length of the output string.
  *
  * @return		The message string output.
@@ -1204,5 +1204,6 @@
 PJ_DECL(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
 			        char *buffer,
-			        unsigned *length);
+			        unsigned length,
+				unsigned *printed_len);
 
 
Index: pjproject/trunk/pjlib-util/include/pjlib-util/stun_transaction.h
===================================================================
--- pjproject/trunk/pjlib-util/include/pjlib-util/stun_transaction.h	(revision 995)
+++ pjproject/trunk/pjlib-util/include/pjlib-util/stun_transaction.h	(revision 996)
@@ -103,4 +103,5 @@
  * @param endpt		The STUN endpoint, which will be used to retrieve
  *			various settings for the transaction.
+ * @param pool		Pool to be used to allocate memory from.
  * @param cb		Callback structure, to be used by the transaction
  *			to send message and to notify the application about
@@ -111,4 +112,5 @@
  */
 PJ_DECL(pj_status_t) pj_stun_client_tsx_create(	pj_stun_endpoint *endpt,
+					        pj_pool_t *pool,
 						const pj_stun_tsx_cb *cb,
 						pj_stun_client_tsx **p_tsx);
@@ -169,5 +171,6 @@
  * @param retransmit	Should this message be retransmitted by the
  *			STUN transaction.
- * @param msg		The STUN message.
+ * @param pkt		The STUN packet to send.
+ * @param pkt_len	Length of STUN packet.
  *
  * @return		PJ_SUCCESS on success or the appropriate error code.
@@ -175,5 +178,7 @@
 PJ_DECL(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
 						 pj_bool_t retransmit,
-						 const pj_stun_msg *msg);
+						 void *pkt,
+						 unsigned pkt_len);
+
 
 
@@ -197,29 +202,4 @@
  * @return		PJ_SUCCESS on success or the appropriate error code.
  */
-PJ_DECL(pj_status_t) pj_stun_client_tsx_on_rx_pkt(pj_stun_client_tsx *tsx,
-						  const void *packet,
-						  pj_size_t pkt_size,
-						  unsigned *parsed_len);
-
-
-/**
- * Notify the STUN transaction about the arrival of STUN response.
- * If the STUN response contains a final error (300 and greater), the
- * transaction will be terminated and callback will be called. If the
- * STUN response contains response code 100-299, retransmission
- * will  cease, but application must still call this function again
- * with a final response later to allow the transaction to complete.
- *
- * @param tsx		The STUN client transaction instance.
- * @param packet	The incoming packet.
- * @param pkt_size	Size of the incoming packet.
- * @param parsed_len	Optional pointer to receive the number of bytes
- *			that have been parsed from the incoming packet
- *			for the STUN message. This is useful if the
- *			STUN transaction is running over stream oriented
- *			socket such as TCP or TLS.
- *
- * @return		PJ_SUCCESS on success or the appropriate error code.
- */
 PJ_DECL(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
 						  const pj_stun_msg *msg);
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_endpoint.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_endpoint.c	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_endpoint.c	(revision 996)
@@ -26,9 +26,9 @@
  * Create a STUN endpoint instance.
  */
-PJ_DEF(pj_status_t) pj_stun_endpt_create( pj_pool_factory *factory,
-					  unsigned options,
-					  pj_ioqueue_t *ioqueue,
-					  pj_timer_heap_t *timer_heap,
-					  pj_stun_endpoint **p_endpt)
+PJ_DEF(pj_status_t) pj_stun_endpoint_create( pj_pool_factory *factory,
+					     unsigned options,
+					     pj_ioqueue_t *ioqueue,
+					     pj_timer_heap_t *timer_heap,
+					     pj_stun_endpoint **p_endpt)
 {
     pj_pool_t *pool;
@@ -58,5 +58,5 @@
  * Destroy STUN endpoint instance.
  */
-PJ_DEF(pj_status_t) pj_stun_endpt_destroy(pj_stun_endpoint *endpt)
+PJ_DEF(pj_status_t) pj_stun_endpoint_destroy(pj_stun_endpoint *endpt)
 {
     PJ_ASSERT_RETURN(endpt, PJ_EINVAL);
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg.c	(revision 996)
@@ -1333,6 +1333,8 @@
     pj_stun_msg_hdr *hdr;
 
-    PJ_ASSERT_RETURN(pdu && pdu_len > sizeof(pj_stun_msg_hdr), 
-		     PJLIB_UTIL_ESTUNINMSGLEN);
+    PJ_ASSERT_RETURN(pdu, PJ_EINVAL);
+
+    if (pdu_len < sizeof(pj_stun_msg_hdr))
+	return PJLIB_UTIL_ESTUNINMSGLEN;
 
     PJ_UNUSED_ARG(options);
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_msg_dump.c	(revision 996)
@@ -33,5 +33,5 @@
     int len;
 
-    len = pj_ansi_snprintf(buffer, end-p,
+    len = pj_ansi_snprintf(p, end-p,
 			   "  %s: length=%d",
 			   pj_stun_get_attr_name(ahdr->type),
@@ -59,5 +59,5 @@
 
 	    if (attr->addr.addr.sa_family == PJ_AF_INET) {
-		len = pj_ansi_snprintf(buffer, end-p,
+		len = pj_ansi_snprintf(p, end-p,
 				       ", IPv4 addr=%s:%d\n",
 				       pj_inet_ntoa(attr->addr.ipv4.sin_addr),
@@ -65,8 +65,8 @@
 
 	    } else if (attr->addr.addr.sa_family == PJ_AF_INET6) {
-		len = pj_ansi_snprintf(buffer, end-p,
+		len = pj_ansi_snprintf(p, end-p,
 				       ", IPv6 addr present\n");
 	    } else {
-		len = pj_ansi_snprintf(buffer, end-p,
+		len = pj_ansi_snprintf(p, end-p,
 				       ", INVALID ADDRESS FAMILY!\n");
 	    }
@@ -88,6 +88,6 @@
 
 	    attr = (const pj_stun_generic_uint_attr*)ahdr;
-	    len = pj_ansi_snprintf(buffer, end-p,
-				   ", value=%d (%x)\n",
+	    len = pj_ansi_snprintf(p, end-p,
+				   ", value=%d (0x%x)\n",
 				   (pj_uint32_t)attr->value,
 				   (pj_uint32_t)attr->value);
@@ -104,5 +104,5 @@
 
 	    attr = (pj_stun_generic_string_attr*)ahdr;
-	    len = pj_ansi_snprintf(buffer, end-p,
+	    len = pj_ansi_snprintf(p, end-p,
 				   ", value=\"%.*s\"\n",
 				   (int)attr->value.slen,
@@ -116,5 +116,5 @@
 
 	    attr = (const pj_stun_error_code_attr*) ahdr;
-	    len = pj_ansi_snprintf(buffer, end-p,
+	    len = pj_ansi_snprintf(p, end-p,
 				   ", err_code=%d, reason=\"%.*s\"\n",
 				   attr->err_class*100 + attr->number,
@@ -131,10 +131,10 @@
 	    attr = (const pj_stun_unknown_attr*) ahdr;
 
-	    len = pj_ansi_snprintf(buffer, end-p,
+	    len = pj_ansi_snprintf(p, end-p,
 				   ", unknown list:");
 	    APPLY();
 
 	    for (j=0; j<attr->attr_count; ++j) {
-		len = pj_ansi_snprintf(buffer, end-p,
+		len = pj_ansi_snprintf(p, end-p,
 				       " %d",
 				       (int)attr->attrs[j]);
@@ -148,5 +148,5 @@
     case PJ_STUN_ATTR_USE_CANDIDATE:
     default:
-	len = pj_ansi_snprintf(buffer, end-p, "\n");
+	len = pj_ansi_snprintf(p, end-p, "\n");
 
 	break;
@@ -167,5 +167,6 @@
 PJ_DEF(char*) pj_stun_msg_dump(const pj_stun_msg *msg,
 			       char *buffer,
-			       unsigned *length)
+			       unsigned length,
+			       unsigned *printed_len)
 {
     char *p, *end;
@@ -176,5 +177,5 @@
 
     p = buffer;
-    end = buffer + (*length);
+    end = buffer + length;
 
     len = pj_ansi_snprintf(p, end-p, "STUN %s %s\n",
@@ -184,6 +185,6 @@
 
     len = pj_ansi_snprintf(p, end-p, 
-			    " Hdr: length=%d, magic=%x, tsx_id=%x %x %x\n"
-			    " Attributes:\n",
+			   " Hdr: length=%d, magic=%08x, tsx_id=%08x %08x %08x\n"
+			   " Attributes:\n",
 			   msg->hdr.length,
 			   msg->hdr.magic,
@@ -200,5 +201,6 @@
 on_return:
     *p = '\0';
-    *length = (p-buffer);
+    if (printed_len)
+	*printed_len = (p-buffer);
     return buffer;
 
Index: pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 996)
@@ -32,11 +32,10 @@
 {
     char		 obj_name[PJ_MAX_OBJ_NAME];
-    pj_pool_t		*pool;
     pj_stun_endpoint	*endpt;
     pj_stun_tsx_cb	 cb;
     void		*user_data;
 
-    pj_uint32_t		 tsx_id[4];
-
+    pj_bool_t		 complete;
+    \
     pj_bool_t		 require_retransmit;
     pj_timer_entry	 timer;
@@ -44,5 +43,5 @@
     pj_time_val		 retransmit_time;
 
-    pj_uint8_t		 last_pkt[PJ_STUN_MAX_PKT_LEN];
+    void		*last_pkt;
     unsigned		 last_pkt_size;
 };
@@ -66,8 +65,8 @@
  */
 PJ_DEF(pj_status_t) pj_stun_client_tsx_create(pj_stun_endpoint *endpt,
+					      pj_pool_t *pool,
 					      const pj_stun_tsx_cb *cb,
 					      pj_stun_client_tsx **p_tsx)
 {
-    pj_pool_t *pool;
     pj_stun_client_tsx *tsx;
 
@@ -75,7 +74,5 @@
     PJ_ASSERT_RETURN(cb->on_send_msg, PJ_EINVAL);
 
-    pool = pj_pool_create(endpt->pf, "tsx", 1000, 1000, NULL);
     tsx = PJ_POOL_ZALLOC_TYPE(pool, pj_stun_client_tsx);
-    tsx->pool = pool;
     tsx->endpt = endpt;
     pj_memcpy(&tsx->cb, cb, sizeof(*cb));
@@ -84,5 +81,5 @@
     tsx->timer.user_data = tsx;
 
-    pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name), "stuntsx%p", pool);
+    pj_ansi_snprintf(tsx->obj_name, sizeof(tsx->obj_name), "stuntsx%p", tsx);
 
     *p_tsx = tsx;
@@ -104,6 +101,15 @@
 	tsx->timer.id = 0;
     }
-    pj_pool_release(tsx->pool);
     return PJ_SUCCESS;
+}
+
+
+/*
+ * Check if transaction has completed.
+ */
+PJ_DEF(pj_bool_t) pj_stun_client_tsx_is_complete(pj_stun_client_tsx *tsx)
+{
+    PJ_ASSERT_RETURN(tsx, PJ_FALSE);
+    return tsx->complete;
 }
 
@@ -146,11 +152,11 @@
 	    tsx->retransmit_time.msec = tsx->endpt->rto_msec;
 
-	} else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT) {
+	} else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT-1) {
 	    unsigned msec;
 
 	    msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time);
-	    msec = (msec >> 1) + 100;
+	    msec = (msec << 1) + 100;
 	    tsx->retransmit_time.sec = msec / 1000;
-	    tsx->retransmit_time.msec = msec % 100;
+	    tsx->retransmit_time.msec = msec % 1000;
 
 	} else {
@@ -162,5 +168,5 @@
 	 * cancel it (as opposed to when schedule_timer() failed we cannot
 	 * cancel transmission).
-	 */
+	 */;
 	status = pj_timer_heap_schedule(tsx->endpt->timer_heap, &tsx->timer,
 					&tsx->retransmit_time);
@@ -169,4 +175,5 @@
 	    return status;
 	}
+	tsx->timer.id = TIMER_ACTIVE;
     }
 
@@ -196,22 +203,13 @@
 PJ_DEF(pj_status_t) pj_stun_client_tsx_send_msg(pj_stun_client_tsx *tsx,
 						pj_bool_t retransmit,
-						const pj_stun_msg *msg)
-{
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(tsx && msg, PJ_EINVAL);
-    PJ_ASSERT_RETURN(tsx->timer.id != 0, PJ_EBUSY);
+						void *pkt,
+						unsigned pkt_len)
+{
+    PJ_ASSERT_RETURN(tsx && pkt && pkt_len, PJ_EINVAL);
+    PJ_ASSERT_RETURN(tsx->timer.id == 0, PJ_EBUSY);
 
     /* Encode message */
-    status = pj_stun_msg_encode(msg, tsx->last_pkt, sizeof(tsx->last_pkt), 
-				0, &tsx->last_pkt_size);
-    if (status != PJ_SUCCESS) {
-	stun_perror(tsx, "STUN msg_encode() failed", status);
-	return status;
-    }
-
-    /* Update STUN transaction ID */
-    tsx->tsx_id[0] = msg->hdr.magic;
-    pj_memcpy(&tsx->tsx_id[1], msg->hdr.tsx_id, 12);
+    tsx->last_pkt = pkt;
+    tsx->last_pkt_size = pkt_len;
 
     /* Update STUN retransmit flag */
@@ -236,4 +234,5 @@
 	tsx->timer.id = 0;
 	PJ_LOG(4,(tsx->obj_name, "STUN timeout waiting for response"));
+	tsx->complete = PJ_TRUE;
 	if (tsx->cb.on_complete) {
 	    tsx->cb.on_complete(tsx, PJLIB_UTIL_ESTUNNOTRESPOND, NULL);
@@ -246,4 +245,5 @@
     if (status != PJ_SUCCESS) {
 	tsx->timer.id = 0;
+	tsx->complete = PJ_TRUE;
 	if (tsx->cb.on_complete) {
 	    tsx->cb.on_complete(tsx, status, NULL);
@@ -272,10 +272,4 @@
     }
 
-    /* Compare response's transaction ID */
-    if (msg->hdr.magic != tsx->tsx_id[0] ||
-	pj_memcmp(msg->hdr.tsx_id, &tsx->tsx_id[1], 12) != 0)
-    {
-	return PJLIB_UTIL_ESTUNINVALIDID;
-    }
 
     /* We have a response with matching transaction ID. 
@@ -312,4 +306,5 @@
 
     /* Call callback */
+    tsx->complete = PJ_TRUE;
     if (tsx->cb.on_complete) {
 	tsx->cb.on_complete(tsx, status, msg);
@@ -320,28 +315,2 @@
 }
 
-
-/*
- * Notify the STUN transaction about the arrival of STUN response.
- */
-PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_pkt(pj_stun_client_tsx *tsx,
-						 const void *packet,
-						 pj_size_t pkt_size,
-						 unsigned *parsed_len)
-{
-    pj_stun_msg *msg;
-    pj_status_t status;
-
-    PJ_ASSERT_RETURN(tsx && packet && pkt_size, PJ_EINVAL);
-
-    /* Try to parse the message */
-    status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet,
-			        pkt_size, 0, &msg, parsed_len,
-				NULL, NULL, NULL);
-    if (status != PJ_SUCCESS) {
-	stun_perror(tsx, "STUN msg_decode() error", status);
-	return status;
-    }
-
-    return pj_stun_client_tsx_on_rx_msg(tsx, msg);
-}
-
Index: pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjstun-client/client_main.c	(revision 996)
@@ -19,7 +19,141 @@
 #include <pjlib-util.h>
 #include <pjlib.h>
+#include "stun_session.h"
+
+#include <conio.h>
 
 
 #define THIS_FILE	"client_main.c"
-#define MAX_THREADS	8
 
+
+static my_perror(const char *title, pj_status_t status)
+{
+    char errmsg[PJ_ERR_MSG_SIZE];
+    pj_strerror(status, errmsg, sizeof(errmsg));
+
+    PJ_LOG(3,(THIS_FILE, "%s: %s", title, errmsg));
+}
+
+static pj_status_t on_send_msg(pj_stun_tx_data *tdata,
+			       const void *pkt,
+			       pj_size_t pkt_size,
+			       unsigned addr_len, 
+			       const pj_sockaddr_t *dst_addr)
+{
+    pj_sock_t sock;
+    pj_ssize_t len;
+    pj_status_t status;
+
+    sock = (pj_sock_t) pj_stun_session_get_user_data(tdata->sess);
+
+    len = pkt_size;
+    status = pj_sock_sendto(sock, pkt, &len, 0, dst_addr, addr_len);
+
+    if (status != PJ_SUCCESS)
+	my_perror("Error sending packet", status);
+
+    return status;
+}
+
+static void on_bind_response(pj_stun_session *sess, 
+			     pj_status_t status, 
+			     pj_stun_tx_data *request,
+			     const pj_stun_msg *response)
+{
+    my_perror("on_bind_response()", status);
+}
+
+int main()
+{
+    pj_stun_endpoint *endpt = NULL;
+    pj_pool_t *pool = NULL;
+    pj_caching_pool cp;
+    pj_timer_heap_t *th = NULL;
+    pj_stun_session *sess;
+    pj_sock_t sock = PJ_INVALID_SOCKET;
+    pj_sockaddr_in addr;
+    pj_stun_session_cb stun_cb;
+    pj_stun_tx_data *tdata;
+    pj_str_t s;
+    pj_status_t status;
+
+    status = pj_init();
+    status = pjlib_util_init();
+
+    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+    
+    pool = pj_pool_create(&cp.factory, NULL, 1000, 1000, NULL);
+
+    status = pj_timer_heap_create(pool, 1000, &th);
+    pj_assert(status == PJ_SUCCESS);
+
+    status = pj_stun_endpoint_create(&cp.factory, 0, NULL, th, &endpt);
+    pj_assert(status == PJ_SUCCESS);
+
+    status = pj_sock_socket(PJ_AF_INET, PJ_SOCK_DGRAM, 0, &sock);
+    pj_assert(status == PJ_SUCCESS);
+
+    status = pj_sockaddr_in_init(&addr, pj_cstr(&s, "127.0.0.1"), PJ_STUN_PORT);
+    pj_assert(status == PJ_SUCCESS);
+
+    pj_memset(&stun_cb, 0, sizeof(stun_cb));
+    stun_cb.on_send_msg = &on_send_msg;
+    stun_cb.on_bind_response = &on_bind_response;
+
+    status = pj_stun_session_create(endpt, NULL, &stun_cb, &sess);
+    pj_assert(status == PJ_SUCCESS);
+
+    pj_stun_session_set_user_data(sess, (void*)sock);
+
+    status = pj_stun_session_create_bind_req(sess, &tdata);
+    pj_assert(status == PJ_SUCCESS);
+
+    status = pj_stun_session_send_msg(sess, 0, sizeof(addr), &addr, tdata);
+    pj_assert(status == PJ_SUCCESS);
+
+    while (1) {
+	pj_fd_set_t rset;
+	int n;
+	pj_time_val timeout;
+
+	if (kbhit()) {
+	    if (_getch()==27)
+		break;
+	}
+
+	PJ_FD_ZERO(&rset);
+	PJ_FD_SET(sock, &rset);
+
+	timeout.sec = 0; timeout.msec = 100;
+
+	n = pj_sock_select(FD_SETSIZE, &rset, NULL, NULL, &timeout);
+
+	if (PJ_FD_ISSET(sock, &rset)) {
+	    char pkt[512];
+	    pj_ssize_t len;
+
+	    len = sizeof(pkt);
+	    status = pj_sock_recv(sock, pkt, &len, 0);
+	    if (status == PJ_SUCCESS) {
+		pj_stun_session_on_rx_pkt(sess, pkt, len, NULL);
+	    }
+	}
+
+	pj_timer_heap_poll(th, NULL);
+    }
+
+on_return:
+    if (sock != PJ_INVALID_SOCKET)
+	pj_sock_close(sock);
+    if (endpt)
+	pj_stun_endpoint_destroy(endpt);
+    if (th)
+	pj_timer_heap_destroy(th);
+    if (pool)
+	pj_pool_release(pool);
+    pj_caching_pool_destroy(&cp);
+
+    return 0;
+}
+
+
Index: pjproject/trunk/pjlib-util/src/pjstun-client/stun_session.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-client/stun_session.c	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjstun-client/stun_session.c	(revision 996)
@@ -27,9 +27,12 @@
     void		*user_data;
 
-    pj_str_t		 realm;
-    pj_str_t		 username;
-    pj_str_t		 password;
-
-    pj_bool_t		 fingerprint_enabled;
+    /* Long term credential */
+    pj_str_t		 l_realm;
+    pj_str_t		 l_username;
+    pj_str_t		 l_password;
+
+    /* Short term credential */
+    pj_str_t		 s_username;
+    pj_str_t		 s_password;
 
     pj_stun_tx_data	 pending_request_list;
@@ -65,6 +68,6 @@
 
 static void tsx_on_complete(pj_stun_client_tsx *tsx,
-			       pj_status_t status, 
-			       const pj_stun_msg *response);
+			    pj_status_t status, 
+			    const pj_stun_msg *response);
 static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx,
 				   const void *stun_pkt,
@@ -165,4 +168,5 @@
 static pj_status_t session_apply_req(pj_stun_session *sess,
 				     pj_pool_t *pool,
+				     unsigned options,
 				     pj_stun_msg *msg)
 {
@@ -172,12 +176,13 @@
      * Section 8.3.1.  Formulating the Request Message
      */
-    if (sess->realm.slen || sess->username.slen) {
+    if (options & PJ_STUN_USE_LONG_TERM_CRED) {
 	pj_stun_generic_string_attr *auname;
 	pj_stun_msg_integrity_attr *amsgi;
+	pj_stun_generic_string_attr *arealm;
 
 	/* Create and add USERNAME attribute */
 	status = pj_stun_generic_string_attr_create(sess->pool, 
 						    PJ_STUN_ATTR_USERNAME,
-						    &sess->username,
+						    &sess->l_username,
 						    &auname);
 	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
@@ -186,16 +191,13 @@
 	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
-	if (sess->realm.slen) {
-	    /* Add REALM only when long term credential is used */
-	    pj_stun_generic_string_attr *arealm;
-	    status = pj_stun_generic_string_attr_create(sess->pool, 
-							PJ_STUN_ATTR_REALM,
-							&sess->realm,
-							&arealm);
-	    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
-
-	    status = pj_stun_msg_add_attr(msg, &arealm->hdr);
-	    PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
-	}
+	/* Add REALM only when long term credential is used */
+	status = pj_stun_generic_string_attr_create(sess->pool, 
+						    PJ_STUN_ATTR_REALM,
+						    &sess->l_realm,
+						    &arealm);
+	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+	status = pj_stun_msg_add_attr(msg, &arealm->hdr);
+	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
 	/* Add MESSAGE-INTEGRITY attribute */
@@ -206,10 +208,32 @@
 	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 
-	PJ_TODO(COMPUTE_MESSAGE_INTEGRITY);
-
+	PJ_TODO(COMPUTE_MESSAGE_INTEGRITY1);
+
+    } else if (options & PJ_STUN_USE_SHORT_TERM_CRED) {
+	pj_stun_generic_string_attr *auname;
+	pj_stun_msg_integrity_attr *amsgi;
+
+	/* Create and add USERNAME attribute */
+	status = pj_stun_generic_string_attr_create(sess->pool, 
+						    PJ_STUN_ATTR_USERNAME,
+						    &sess->s_username,
+						    &auname);
+	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+	status = pj_stun_msg_add_attr(msg, &auname->hdr);
+	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+	/* Add MESSAGE-INTEGRITY attribute */
+	status = pj_stun_msg_integrity_attr_create(sess->pool, &amsgi);
+	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+	status = pj_stun_msg_add_attr(msg, &amsgi->hdr);
+	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
+
+	PJ_TODO(COMPUTE_MESSAGE_INTEGRITY2);
     }
 
     /* Add FINGERPRINT attribute if necessary */
-    if (sess->fingerprint_enabled) {
+    if (options & PJ_STUN_USE_FINGERPRINT) {
 	pj_stun_fingerprint_attr *af;
 
@@ -227,7 +251,47 @@
 
 
-
-
-
+static void tsx_on_complete(pj_stun_client_tsx *tsx,
+			    pj_status_t status, 
+			    const pj_stun_msg *response)
+{
+    pj_stun_tx_data *tdata;
+
+    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
+
+    switch (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)) {
+    case PJ_STUN_BINDING_METHOD:
+	tdata->sess->cb.on_bind_response(tdata->sess, status, tdata, response);
+	break;
+    case PJ_STUN_ALLOCATE_METHOD:
+	tdata->sess->cb.on_allocate_response(tdata->sess, status,
+					     tdata, response);
+	break;
+    case PJ_STUN_SET_ACTIVE_DESTINATION_METHOD:
+	tdata->sess->cb.on_set_active_destination_response(tdata->sess, status,
+							   tdata, response);
+	break;
+    case PJ_STUN_CONNECT_METHOD:
+	tdata->sess->cb.on_connect_response(tdata->sess, status, tdata,
+					    response);
+	break;
+    default:
+	pj_assert(!"Unknown method");
+	break;
+    }
+}
+
+static pj_status_t tsx_on_send_msg(pj_stun_client_tsx *tsx,
+				   const void *stun_pkt,
+				   pj_size_t pkt_size)
+{
+    pj_stun_tx_data *tdata;
+
+    tdata = (pj_stun_tx_data*) pj_stun_client_tsx_get_data(tsx);
+
+    return tdata->sess->cb.on_send_msg(tdata, stun_pkt, pkt_size,
+				       tdata->addr_len, tdata->dst_addr);
+}
+
+/* **************************************************************************/
 
 PJ_DEF(pj_status_t) pj_stun_session_create( pj_stun_endpoint *endpt,
@@ -261,4 +325,5 @@
 {
     PJ_ASSERT_RETURN(sess, PJ_EINVAL);
+
     pj_pool_release(sess->pool);
 
@@ -281,24 +346,32 @@
 }
 
-PJ_DEF(pj_status_t) pj_stun_session_set_credential( pj_stun_session *sess,
-						    const pj_str_t *realm,
-						    const pj_str_t *user,
-						    const pj_str_t *passwd)
-{
-    pj_str_t empty = { NULL, 0 };
+PJ_DEF(pj_status_t) 
+pj_stun_session_set_long_term_credential(pj_stun_session *sess,
+					 const pj_str_t *realm,
+					 const pj_str_t *user,
+					 const pj_str_t *passwd)
+{
+    pj_str_t nil = { NULL, 0 };
 
     PJ_ASSERT_RETURN(sess, PJ_EINVAL);
-    pj_strdup_with_null(sess->pool, &sess->realm, realm ? realm : &empty);
-    pj_strdup_with_null(sess->pool, &sess->username, user ? user : &empty);
-    pj_strdup_with_null(sess->pool, &sess->password, passwd ? passwd : &empty);
-
-    return PJ_SUCCESS;
-}
-
-PJ_DEF(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess,
-						       pj_bool_t enabled)
-{
+    pj_strdup_with_null(sess->pool, &sess->l_realm, realm ? realm : &nil);
+    pj_strdup_with_null(sess->pool, &sess->l_username, user ? user : &nil);
+    pj_strdup_with_null(sess->pool, &sess->l_password, passwd ? passwd : &nil);
+
+    return PJ_SUCCESS;
+}
+
+
+PJ_DEF(pj_status_t) 
+pj_stun_session_set_short_term_credential(pj_stun_session *sess,
+					  const pj_str_t *user,
+					  const pj_str_t *passwd)
+{
+    pj_str_t nil = { NULL, 0 };
+
     PJ_ASSERT_RETURN(sess, PJ_EINVAL);
-    sess->fingerprint_enabled = enabled;
+    pj_strdup_with_null(sess->pool, &sess->s_username, user ? user : &nil);
+    pj_strdup_with_null(sess->pool, &sess->s_password, passwd ? passwd : &nil);
+
     return PJ_SUCCESS;
 }
@@ -308,5 +381,4 @@
 						    pj_stun_tx_data **p_tdata)
 {
-    pj_pool_t *pool;
     pj_stun_tx_data *tdata;
     pj_status_t status;
@@ -318,10 +390,4 @@
 	return status;
 
-    status = session_apply_req(sess, pool, tdata->msg);
-    if (status != PJ_SUCCESS) {
-	destroy_tdata(tdata);
-	return status;
-    }
-
     *p_tdata = tdata;
     return PJ_SUCCESS;
@@ -368,4 +434,5 @@
 
 PJ_DEF(pj_status_t) pj_stun_session_send_msg( pj_stun_session *sess,
+					      unsigned options,
 					      unsigned addr_len,
 					      const pj_sockaddr_t *server,
@@ -376,7 +443,10 @@
     PJ_ASSERT_RETURN(sess && addr_len && server && tdata, PJ_EINVAL);
 
+    /* Allocate packet */
+    tdata->max_len = PJ_STUN_MAX_PKT_LEN;
+    tdata->pkt = pj_pool_alloc(tdata->pool, tdata->max_len);
+
     if (PJ_LOG_MAX_LEVEL >= 5) {
-	char buf[512];
-	unsigned buflen = sizeof(buf);
+	char *buf = (char*) tdata->pkt;
 	const char *dst_name;
 	int dst_port;
@@ -398,9 +468,27 @@
 	PJ_LOG(5,(SNAME(sess), 
 		  "Sending STUN message to %s:%d:\n"
-		  "%s\n",
+		  "--- begin STUN message ---\n"
+		  "%s"
+		  "--- end of STUN message ---\n",
 		  dst_name, dst_port,
-		  pj_stun_msg_dump(tdata->msg, buf, &buflen)));
-    }
-
+		  pj_stun_msg_dump(tdata->msg, buf, tdata->max_len, NULL)));
+    }
+
+    /* Apply options */
+    status = session_apply_req(sess, tdata->pool, options, tdata->msg);
+    if (status != PJ_SUCCESS) {
+	LOG_ERR_(sess, "Error applying options", status);
+	destroy_tdata(tdata);
+	return status;
+    }
+
+    /* Encode message */
+    status = pj_stun_msg_encode(tdata->msg, tdata->pkt, tdata->max_len,
+			        0, &tdata->pkt_size);
+    if (status != PJ_SUCCESS) {
+	LOG_ERR_(sess, "STUN encode() error", status);
+	destroy_tdata(tdata);
+	return status;
+    }
 
     /* If this is a STUN request message, then send the request with
@@ -410,14 +498,19 @@
 
 	/* Create STUN client transaction */
-	status = pj_stun_client_tsx_create(sess->endpt, &tsx_cb, 
-					   &tdata->client_tsx);
+	status = pj_stun_client_tsx_create(sess->endpt, tdata->pool, 
+					   &tsx_cb, &tdata->client_tsx);
 	PJ_ASSERT_RETURN(status==PJ_SUCCESS, status);
 	pj_stun_client_tsx_set_data(tdata->client_tsx, (void*)tdata);
+
+	/* Save the remote address */
+	tdata->addr_len = addr_len;
+	tdata->dst_addr = server;
 
 	/* Send the request! */
 	status = pj_stun_client_tsx_send_msg(tdata->client_tsx, PJ_TRUE,
-					     tdata->msg);
+					     tdata->pkt, tdata->pkt_size);
 	if (status != PJ_SUCCESS && status != PJ_EPENDING) {
 	    LOG_ERR_(sess, "Error sending STUN request", status);
+	    destroy_tdata(tdata);
 	    return status;
 	}
@@ -428,5 +521,12 @@
     } else {
 	/* Otherwise for non-request message, send directly to transport. */
-	status = sess->cb.on_send_msg(tdata, addr_len, server);
+	status = sess->cb.on_send_msg(tdata, tdata->pkt, tdata->pkt_size,
+				      addr_len, server);
+
+	if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+	    LOG_ERR_(sess, "Error sending STUN request", status);
+	    destroy_tdata(tdata);
+	    return status;
+	}
     }
 
@@ -442,16 +542,33 @@
 {
     pj_stun_msg *msg;
+    pj_pool_t *tmp_pool;
+    char *dump;
     pj_status_t status;
 
     PJ_ASSERT_RETURN(sess && packet && pkt_size, PJ_EINVAL);
 
+    tmp_pool = pj_pool_create(sess->endpt->pf, "tmpstun", 1024, 1024, NULL);
+    if (!tmp_pool)
+	return PJ_ENOMEM;
+
     /* Try to parse the message */
-    status = pj_stun_msg_decode(tsx->pool, (const pj_uint8_t*)packet,
+    status = pj_stun_msg_decode(tmp_pool, (const pj_uint8_t*)packet,
 			        pkt_size, 0, &msg, parsed_len,
 				NULL, NULL, NULL);
     if (status != PJ_SUCCESS) {
 	LOG_ERR_(sess, "STUN msg_decode() error", status);
+	pj_pool_release(tmp_pool);
 	return status;
     }
+
+    dump = pj_pool_alloc(tmp_pool, PJ_STUN_MAX_PKT_LEN);
+
+    PJ_LOG(4,(SNAME(sess), 
+	      "RX STUN message:\n"
+	      "--- begin STUN message ---"
+	      "%s"
+	      "--- end of STUN message ---\n",
+	      pj_stun_msg_dump(msg, dump, PJ_STUN_MAX_PKT_LEN, NULL)));
+
 
     if (PJ_STUN_IS_RESPONSE(msg->hdr.type) ||
@@ -464,4 +581,5 @@
 	if (tdata == NULL) {
 	    LOG_ERR_(sess, "STUN error finding transaction", PJ_ENOTFOUND);
+	    pj_pool_release(tmp_pool);
 	    return PJ_ENOTFOUND;
 	}
@@ -472,6 +590,8 @@
 	 */
 	status = pj_stun_client_tsx_on_rx_msg(tdata->client_tsx, msg);
-	if (status != PJ_SUCCESS)
+	if (status != PJ_SUCCESS) {
+	    pj_pool_release(tmp_pool);
 	    return status;
+	}
 
 	/* If transaction has completed, destroy the transmit data.
@@ -483,17 +603,21 @@
 	}
 
+	pj_pool_release(tmp_pool);
 	return PJ_SUCCESS;
 
     } else if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
 
+	PJ_TODO(HANDLE_INCOMING_STUN_REQUEST);
 
     } else if (PJ_STUN_IS_INDICATION(msg->hdr.type)) {
 
+	PJ_TODO(HANDLE_INCOMING_STUN_INDICATION);
 
     } else {
 	pj_assert(!"Unexpected!");
-	return PJ_EBUG;
-    }
-
-}
-
+    }
+
+    pj_pool_release(tmp_pool);
+    return PJ_ENOTSUP;
+}
+
Index: pjproject/trunk/pjlib-util/src/pjstun-client/stun_session.h
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-client/stun_session.h	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjstun-client/stun_session.h	(revision 996)
@@ -26,34 +26,167 @@
 
 
+/** Forward declaration for pj_stun_tx_data */
 typedef struct pj_stun_tx_data pj_stun_tx_data;
+
+/** Forward declaration for pj_stun_session */
 typedef struct pj_stun_session pj_stun_session;
 
+/**
+ * This is the callback to be registered to pj_stun_session, to send
+ * outgoing message and to receive various notifications from the STUN
+ * session.
+ */
 typedef struct pj_stun_session_cb
 {
+    /**
+     * Callback to be called by the STUN session to send outgoing message.
+     *
+     * @param tdata	    The STUN transmit data containing the original
+     *			    STUN message
+     * @param pkt	    Packet to be sent.
+     * @param pkt_size	    Size of the packet to be sent.
+     * @param addr_len	    Length of destination address.
+     * @param dst_addr	    The destination address.
+     *
+     * @return		    The callback should return the status of the
+     *			    packet sending.
+     */
     pj_status_t (*on_send_msg)(pj_stun_tx_data *tdata,
+			       const void *pkt,
+			       pj_size_t pkt_size,
 			       unsigned addr_len, 
 			       const pj_sockaddr_t *dst_addr);
 
-    void (*on_bind_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
-    void (*on_allocate_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
-    void (*on_set_active_destination_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
-    void (*on_connect_response)(void *user_data, pj_status_t status, pj_stun_msg *response);
+    /**
+     * Callback to be called when Binding response is received or the 
+     * transaction has timed out.
+     *
+     * @param sess	    The STUN session.
+     * @param status	    Status of the request. If the value if not
+     *			    PJ_SUCCESS, the transaction has timed-out
+     *			    or other error has occurred, and the response
+     *			    argument may be NULL.
+     * @param request	    The original STUN request.
+     * @param response	    The response message, on successful transaction.
+     */
+    void (*on_bind_response)(pj_stun_session *sess, 
+			     pj_status_t status, 
+			     pj_stun_tx_data *request,
+			     const pj_stun_msg *response);
+
+    /**
+     * Callback to be called when Allocate response is received or the 
+     * transaction has timed out.
+     *
+     * @param sess	    The STUN session.
+     * @param status	    Status of the request. If the value if not
+     *			    PJ_SUCCESS, the transaction has timed-out
+     *			    or other error has occurred, and the response
+     *			    argument may be NULL.
+     * @param request	    The original STUN request.
+     * @param response	    The response message, on successful transaction.
+     */
+    void (*on_allocate_response)(pj_stun_session *sess, 
+				 pj_status_t status, 
+				 pj_stun_tx_data *request,
+				 const pj_stun_msg *response);
+
+    /**
+     * Callback to be called when Set Active Destination response is received
+     * or the transaction has timed out.
+     *
+     * @param sess	    The STUN session.
+     * @param status	    Status of the request. If the value if not
+     *			    PJ_SUCCESS, the transaction has timed-out
+     *			    or other error has occurred, and the response
+     *			    argument may be NULL.
+     * @param request	    The original STUN request.
+     * @param response	    The response message, on successful transaction.
+     */
+    void (*on_set_active_destination_response)(pj_stun_session *sess, 
+					       pj_status_t status, 
+					       pj_stun_tx_data *request,
+					       const pj_stun_msg *response);
+
+    /**
+     * Callback to be called when Connect response is received or the 
+     * transaction has timed out.
+     *
+     * @param sess	    The STUN session.
+     * @param status	    Status of the request. If the value if not
+     *			    PJ_SUCCESS, the transaction has timed-out
+     *			    or other error has occurred, and the response
+     *			    argument may be NULL.
+     * @param request	    The original STUN request.
+     * @param response	    The response message, on successful transaction.
+     */
+    void (*on_connect_response)( pj_stun_session *sess, 
+				 pj_status_t status, 
+				 pj_stun_tx_data *request,
+				 const pj_stun_msg *response);
 } pj_stun_session_cb;
 
 
+/**
+ * This structure describe the outgoing STUN transmit data to carry the
+ * message to be sent.
+ */
 struct pj_stun_tx_data
 {
     PJ_DECL_LIST_MEMBER(struct pj_stun_tx_data);
 
-    pj_pool_t		*pool;
-    pj_stun_session	*sess;
-    pj_stun_msg		*msg;
-    void		*user_data;
-
-    pj_stun_client_tsx	*client_tsx;
-    pj_uint8_t		 client_key[12];
+    pj_pool_t		*pool;		/**< Pool.			    */
+    pj_stun_session	*sess;		/**< The STUN session.		    */
+    pj_stun_msg		*msg;		/**< The STUN message.		    */
+    void		*user_data;	/**< Arbitrary user data.	    */
+
+    pj_stun_client_tsx	*client_tsx;	/**< Client STUN transaction.	    */
+    pj_uint8_t		 client_key[12];/**< Client transaction key.	    */
+
+    void		*pkt;		/**< The STUN packet.		    */
+    unsigned		 max_len;	/**< Length of packet buffer.	    */
+    unsigned		 pkt_size;	/**< The actual length of STUN pkt. */
+
+    unsigned		 addr_len;	/**< Length of destination address. */
+    const pj_sockaddr_t	*dst_addr;	/**< Destination address.	    */
 };
 
 
+/**
+ * Options that can be specified when creating or sending outgoing STUN
+ * messages. These options may be specified as bitmask.
+ */
+enum pj_stun_session_option
+{
+    /**
+     * Add short term credential to the message. This option may not be used
+     * together with PJ_STUN_USE_LONG_TERM_CRED option.
+     */
+    PJ_STUN_USE_SHORT_TERM_CRED	= 1,
+
+    /**
+     * Add long term credential to the message. This option may not be used
+     * together with PJ_STUN_USE_SHORT_TERM_CRED option.
+     */
+    PJ_STUN_USE_LONG_TERM_CRED	= 2,
+
+    /**
+     * Add STUN fingerprint to the message.
+     */
+    PJ_STUN_USE_FINGERPRINT	= 4
+};
+
+
+/**
+ * Create a STUN session.
+ *
+ * @param endpt	    The STUN endpoint, to be used to register timers etc.
+ * @param name	    Optional name to be associated with this instance. The
+ *		    name will be used for example for logging purpose.
+ * @param cb	    Session callback.
+ * @param p_sess    Pointer to receive STUN session instance.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_create(pj_stun_endpoint *endpt,
 					    const char *name,
@@ -61,47 +194,219 @@
 					    pj_stun_session **p_sess);
 
+/**
+ * Destroy the STUN session.
+ *
+ * @param sess	    The STUN session instance.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_destroy(pj_stun_session *sess);
 
+/**
+ * Associated an arbitrary data with this STUN session. The user data may
+ * be retrieved later with pj_stun_session_get_user_data() function.
+ *
+ * @param sess	    The STUN session instance.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_set_user_data(pj_stun_session *sess,
 						   void *user_data);
 
+/**
+ * Retrieve the user data previously associated to this STUN session with
+ * pj_stun_session_set_user_data().
+ *
+ * @param sess	    The STUN session instance.
+ *
+ * @return	    The user data associated with this STUN session.
+ */
 PJ_DECL(void*) pj_stun_session_get_user_data(pj_stun_session *sess);
 
-PJ_DECL(pj_status_t) pj_stun_session_set_credential(pj_stun_session *sess,
-						    const pj_str_t *realm,
-						    const pj_str_t *user,
-						    const pj_str_t *passwd);
-
-PJ_DECL(pj_status_t) pj_stun_session_enable_fingerprint(pj_stun_session *sess,
-							pj_bool_t enabled);
-
+/**
+ * Save a long term credential to be used by this STUN session when sending
+ * outgoing messages. After long term credential is configured, application
+ * may specify PJ_STUN_USE_LONG_TERM_CRED option when sending outgoing STUN
+ * message to send the long term credential in the message.
+ *
+ * @param sess	    The STUN session instance.
+ * @param realm	    Realm of the long term credential.
+ * @param user	    The user name.
+ * @param passwd    The pain-text password.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) 
+pj_stun_session_set_long_term_credential(pj_stun_session *sess,
+					 const pj_str_t *realm,
+					 const pj_str_t *user,
+					 const pj_str_t *passwd);
+
+
+/**
+ * Save a short term credential to be used by this STUN session when sending
+ * outgoing messages. After short term credential is configured, application
+ * may specify PJ_STUN_USE_SHORT_TERM_CRED option when sending outgoing STUN
+ * message to send the short term credential in the message.
+ *
+ * @param sess	    The STUN session instance.
+ * @param user	    The user name.
+ * @param passwd    The pain-text password.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t) 
+pj_stun_session_set_short_term_credential(pj_stun_session *sess,
+					  const pj_str_t *user,
+					  const pj_str_t *passwd);
+
+/**
+ * Create a STUN Bind request message. After the message has been 
+ * successfully created, application can send the message by calling 
+ * pj_stun_session_send_msg().
+ *
+ * @param sess	    The STUN session instance.
+ * @param p_tdata   Pointer to receive STUN transmit data instance containing
+ *		    the request.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_create_bind_req(pj_stun_session *sess,
 						     pj_stun_tx_data **p_tdata);
 
+/**
+ * Create a STUN Allocate request message. After the message has been
+ * successfully created, application can send the message by calling  
+ * pj_stun_session_send_msg().
+ *
+ * @param sess	    The STUN session instance.
+ * @param p_tdata   Pointer to receive STUN transmit data instance containing
+ *		    the request.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_create_allocate_req(pj_stun_session *sess,
 							 pj_stun_tx_data **p_tdata);
 
+/**
+ * Create a STUN Set Active Destination request message. After the message 
+ * has been successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess	    The STUN session instance.
+ * @param p_tdata   Pointer to receive STUN transmit data instance containing
+ *		    the request.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) 
 pj_stun_session_create_set_active_destination_req(pj_stun_session *sess,
 						  pj_stun_tx_data **p_tdata);
 
+/**
+ * Create a STUN Connect request message. After the message has been 
+ * successfully created, application can send the message by calling 
+ * pj_stun_session_send_msg().
+ *
+ * @param sess	    The STUN session instance.
+ * @param p_tdata   Pointer to receive STUN transmit data instance containing
+ *		    the request.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_create_connect_req(pj_stun_session *sess,
 							pj_stun_tx_data **p_tdata);
 
-PJ_DECL(pj_status_t) 
+/**
+ * Create a STUN Connection Status Indication message. After the message 
+ * has been successfully created, application can send the message by calling
+ * pj_stun_session_send_msg().
+ *
+ * @param sess	    The STUN session instance.
+ * @param p_tdata   Pointer to receive STUN transmit data instance containing
+ *		    the message.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
+PJ_DECL(pj_status_t)
 pj_stun_session_create_connection_status_ind(pj_stun_session *sess,
 					     pj_stun_tx_data **p_tdata);
 
+/**
+ * Create a STUN Send Indication message. After the message has been 
+ * successfully created, application can send the message by calling 
+ * pj_stun_session_send_msg().
+ *
+ * @param sess	    The STUN session instance.
+ * @param p_tdata   Pointer to receive STUN transmit data instance containing
+ *		    the message.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_create_send_ind(pj_stun_session *sess,
 						     pj_stun_tx_data **p_tdata);
 
+/**
+ * Create a STUN Data Indication message. After the message has been 
+ * successfully created, application can send the message by calling 
+ * pj_stun_session_send_msg().
+ *
+ * @param sess	    The STUN session instance.
+ * @param p_tdata   Pointer to receive STUN transmit data instance containing
+ *		    the message.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_create_data_ind(pj_stun_session *sess,
 						     pj_stun_tx_data **p_tdata);
 
+/**
+ * Send STUN message to the specified destination. This function will encode
+ * the pj_stun_msg instance to a packet buffer, and add credential or
+ * fingerprint if necessary. If the message is a request, the session will
+ * also create and manage a STUN client transaction to be used to manage the
+ * retransmission of the request. After the message has been encoded and
+ * transaction is setup, the \a on_send_msg() callback of pj_stun_session_cb
+ * (which is registered when the STUN session is created) will be called
+ * to actually send the message to the wire.
+ *
+ * @param sess	    The STUN session instance.
+ * @param options   Optional flags, from pj_stun_session_option.
+ * @param addr_len  Length of destination address.
+ * @param dst_addr  The destination socket address.
+ * @param tdata	    The STUN transmit data containing the STUN message to
+ *		    be sent.
+ *
+ * @return	    PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_send_msg(pj_stun_session *sess,
+					      unsigned options,
 					      unsigned addr_len,
-					      const pj_sockaddr_t *server,
+					      const pj_sockaddr_t *dst_addr,
 					      pj_stun_tx_data *tdata);
 
+/**
+ * Application must call this function to notify the STUN session about
+ * the arrival of STUN packet. The STUN packet MUST have been checked
+ * first with #pj_stun_msg_check() to verify that this is indeed a valid
+ * STUN packet.
+ *
+ * The STUN session will decode the packet into pj_stun_msg, and process
+ * the message accordingly. If the message is a response, it will search
+ * through the outstanding STUN client transactions for a matching
+ * transaction ID and hand over the response to the transaction.
+ *
+ * On successful message processing, application will be notified about
+ * the message via one of the pj_stun_session_cb callback.
+ *
+ * @param sess	     The STUN session instance.
+ * @param packet     The packet containing STUN message.
+ * @param pkt_size   Size of the packet.
+ * @param parsed_len Optional pointer to receive the size of the parsed
+ *		     STUN message (useful if packet is received via a
+ *		     stream oriented protocol).
+ *
+ * @return	     PJ_SUCCESS on success, or the appropriate error code.
+ */
 PJ_DECL(pj_status_t) pj_stun_session_on_rx_pkt(pj_stun_session *sess,
 					       const void *packet,
Index: pjproject/trunk/pjlib-util/src/pjstun-srv/server_main.c
===================================================================
--- pjproject/trunk/pjlib-util/src/pjstun-srv/server_main.c	(revision 995)
+++ pjproject/trunk/pjlib-util/src/pjstun-srv/server_main.c	(revision 996)
@@ -101,4 +101,11 @@
     pj_status_t status;
 
+    /* Print to log */
+    PJ_LOG(4,(THIS_FILE, "TX STUN message: \n"
+			 "--- begin STUN message ---\n"
+			 "%s"
+			 "--- end of STUN message ---\n", 
+	      pj_stun_msg_dump(msg, svc->tx_pkt, sizeof(svc->tx_pkt), NULL)));
+
     /* Encode packet */
     tx_pkt_len = sizeof(svc->tx_pkt);
@@ -221,4 +228,5 @@
     unsigned uattr_cnt;
     pj_uint16_t uattr_types[16];
+    char dump[512];
     pj_status_t status;
 
@@ -242,7 +250,9 @@
     }
 
-    PJ_LOG(4,(THIS_FILE, "RX STUN %s %s message", 
-	      pj_stun_get_method_name(rx_msg->hdr.type),
-	      pj_stun_get_class_name(rx_msg->hdr.type)));
+    PJ_LOG(4,(THIS_FILE, "RX STUN message: \n"
+			 "--- begin STUN message ---\n"
+			 "%s"
+			 "--- end of STUN message ---\n", 
+	      pj_stun_msg_dump(rx_msg, dump, sizeof(dump), NULL)));
 
     if (PJ_STUN_IS_REQUEST(rx_msg->hdr.type)) {
Index: pjproject/trunk/pjlib/src/pj/errno.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/errno.c	(revision 995)
+++ pjproject/trunk/pjlib/src/pj/errno.c	(revision 996)
@@ -153,5 +153,8 @@
     pj_assert(buf && bufsize);
 
-    if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
+    if (statcode == PJ_SUCCESS) {
+	len = pj_ansi_snprintf( buf, bufsize, "Success");
+
+    } else if (statcode < PJ_ERRNO_START + PJ_ERRNO_SPACE_SIZE) {
         len = pj_ansi_snprintf( buf, bufsize, "Unknown error %d", statcode);
 
