Index: pjproject/branches/iceproject/pjlib-util/src/pjlib-util/stun_transaction.c
===================================================================
--- pjproject/branches/iceproject/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 913)
+++ pjproject/branches/iceproject/pjlib-util/src/pjlib-util/stun_transaction.c	(revision 929)
@@ -1,3 +1,3 @@
-/* $Id */
+/* $Id$ */
 /* 
  * Copyright (C) 2003-2005 Benny Prijono <benny@prijono.org>
@@ -39,4 +39,5 @@
     pj_uint32_t		 tsx_id[4];
 
+    pj_bool_t		 require_retransmit;
     pj_timer_entry	 timer;
     unsigned		 transmit_count;
@@ -109,5 +110,5 @@
 
 /*
- * .
+ * Set user data.
  */
 PJ_DEF(pj_status_t) pj_stun_client_tsx_set_data(pj_stun_client_tsx *tsx,
@@ -121,5 +122,5 @@
 
 /*
- * .
+ * Get the user data
  */
 PJ_DEF(void*) pj_stun_client_tsx_get_data(pj_stun_client_tsx *tsx)
@@ -139,31 +140,33 @@
     PJ_ASSERT_RETURN(tsx->timer.id == 0, PJ_EBUSY);
 
-    /* Calculate retransmit/timeout delay */
-    if (tsx->transmit_count == 0) {
-	tsx->retransmit_time.sec = 0;
-	tsx->retransmit_time.msec = tsx->endpt->rto_msec;
-
-    } else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT) {
-	unsigned msec;
-
-	msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time);
-	msec = (msec >> 1) + 100;
-	tsx->retransmit_time.sec = msec / 1000;
-	tsx->retransmit_time.msec = msec % 100;
-
-    } else {
-	tsx->retransmit_time.sec = PJ_STUN_TIMEOUT_VALUE / 1000;
-	tsx->retransmit_time.msec = PJ_STUN_TIMEOUT_VALUE % 1000;
-    }
-
-    /* Schedule timer first because when send_msg() failed we can
-     * 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);
-    if (status != PJ_SUCCESS) {
-	tsx->timer.id = 0;
-	return status;
+    if (tsx->require_retransmit) {
+	/* Calculate retransmit/timeout delay */
+	if (tsx->transmit_count == 0) {
+	    tsx->retransmit_time.sec = 0;
+	    tsx->retransmit_time.msec = tsx->endpt->rto_msec;
+
+	} else if (tsx->transmit_count < PJ_STUN_MAX_RETRANSMIT_COUNT) {
+	    unsigned msec;
+
+	    msec = PJ_TIME_VAL_MSEC(tsx->retransmit_time);
+	    msec = (msec >> 1) + 100;
+	    tsx->retransmit_time.sec = msec / 1000;
+	    tsx->retransmit_time.msec = msec % 100;
+
+	} else {
+	    tsx->retransmit_time.sec = PJ_STUN_TIMEOUT_VALUE / 1000;
+	    tsx->retransmit_time.msec = PJ_STUN_TIMEOUT_VALUE % 1000;
+	}
+
+	/* Schedule timer first because when send_msg() failed we can
+	 * 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);
+	if (status != PJ_SUCCESS) {
+	    tsx->timer.id = 0;
+	    return status;
+	}
     }
 
@@ -172,6 +175,8 @@
     status = tsx->cb.on_send_msg(tsx, tsx->last_pkt, tsx->last_pkt_size);
     if (status != PJ_SUCCESS) {
-	pj_timer_heap_cancel(tsx->endpt->timer_heap, &tsx->timer);
-	tsx->timer.id = 0;
+	if (tsx->timer.id != 0) {
+	    pj_timer_heap_cancel(tsx->endpt->timer_heap, &tsx->timer);
+	    tsx->timer.id = 0;
+	}
 	stun_perror(tsx, "STUN error sending message", status);
 	return status;
@@ -185,8 +190,10 @@
 }
 
-/*
- * .
+
+/*
+ * Send outgoing message and start STUN transaction.
  */
 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)
 {
@@ -208,4 +215,8 @@
     pj_memcpy(&tsx->tsx_id[1], msg->hdr.tsx_id, 12);
 
+    /* Update STUN retransmit flag */
+    tsx->require_retransmit = retransmit;
+
+    /* Send the message */
     return tsx_transmit_msg(tsx);
 }
@@ -243,5 +254,5 @@
 
 /*
- * 
+ * Notify the STUN transaction about the arrival of STUN response.
  */
 PJ_DEF(pj_status_t) pj_stun_client_tsx_on_rx_msg(pj_stun_client_tsx *tsx,
@@ -292,5 +303,10 @@
     err_attr = (pj_stun_error_code_attr*) 
 		pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_ERROR_CODE, 0);
-    if (err_attr->err_class == 1) {
+
+    if (err_attr && err_attr->err_class <= 2) {
+	/* draft-ietf-behave-rfc3489bis-05.txt Section 8.3.2:
+	 * Any response between 100 and 299 MUST result in the cessation
+	 * of request retransmissions, but otherwise is discarded.
+	 */
 	PJ_LOG(4,(tsx->obj_name, 
 		  "STUN rx_msg() error: received provisional %d code (%.*s)",
@@ -301,5 +317,5 @@
     }
 
-    if (err_attr==NULL || err_attr->err_class == 2) {
+    if (err_attr == NULL) {
 	status = PJ_SUCCESS;
     } else {
