Index: pjproject/trunk/pjnath/src/pjnath/ice_strans.c
===================================================================
--- pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 4314)
+++ pjproject/trunk/pjnath/src/pjnath/ice_strans.c	(revision 4360)
@@ -127,10 +127,8 @@
 
 /* Forward decls */
+static void ice_st_on_destroy(void *obj);
 static void destroy_ice_st(pj_ice_strans *ice_st);
 #define ice_st_perror(ice_st,msg,rc) pjnath_perror(ice_st->obj_name,msg,rc)
 static void sess_init_update(pj_ice_strans *ice_st);
-
-static void sess_add_ref(pj_ice_strans *ice_st);
-static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st);
 
 /**
@@ -173,5 +171,5 @@
     pj_ice_strans_cfg	     cfg;	/**< Configuration.		*/
     pj_ice_strans_cb	     cb;	/**< Application callback.	*/
-    pj_lock_t		    *init_lock; /**< Initialization mutex.	*/
+    pj_grp_lock_t	    *grp_lock;  /**< Group lock.		*/
 
     pj_ice_strans_state	     state;	/**< Session state.		*/
@@ -184,5 +182,4 @@
     pj_timer_entry	     ka_timer;	/**< STUN keep-alive timer.	*/
 
-    pj_atomic_t		    *busy_cnt;	/**< To prevent destroy		*/
     pj_bool_t		     destroy_req;/**< Destroy has been called?	*/
     pj_bool_t		     cb_called;	/**< Init error callback called?*/
@@ -552,20 +549,19 @@
     pj_log_push_indent();
 
-    pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg);
-    pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
-    
-    status = pj_atomic_create(pool, 0, &ice_st->busy_cnt);
+    status = pj_grp_lock_create(pool, NULL, &ice_st->grp_lock);
     if (status != PJ_SUCCESS) {
-	destroy_ice_st(ice_st);
-	return status;
-    }
-
-    status = pj_lock_create_recursive_mutex(pool, ice_st->obj_name, 
-					    &ice_st->init_lock);
-    if (status != PJ_SUCCESS) {
-	destroy_ice_st(ice_st);
+	pj_pool_release(pool);
 	pj_log_pop_indent();
 	return status;
     }
+
+    pj_grp_lock_add_ref(ice_st->grp_lock);
+    pj_grp_lock_add_handler(ice_st->grp_lock, pool, ice_st,
+			    &ice_st_on_destroy);
+
+    pj_ice_strans_cfg_copy(pool, &ice_st->cfg, cfg);
+    ice_st->cfg.stun.cfg.grp_lock = ice_st->grp_lock;
+    ice_st->cfg.turn.cfg.grp_lock = ice_st->grp_lock;
+    pj_memcpy(&ice_st->cb, cb, sizeof(*cb));
 
     ice_st->comp_cnt = comp_cnt;
@@ -579,10 +575,10 @@
      * called before we finish initialization.
      */
-    pj_lock_acquire(ice_st->init_lock);
+    pj_grp_lock_acquire(ice_st->grp_lock);
 
     for (i=0; i<comp_cnt; ++i) {
 	status = create_comp(ice_st, i+1);
 	if (status != PJ_SUCCESS) {
-	    pj_lock_release(ice_st->init_lock);
+	    pj_grp_lock_release(ice_st->grp_lock);
 	    destroy_ice_st(ice_st);
 	    pj_log_pop_indent();
@@ -592,7 +588,7 @@
 
     /* Done with initialization */
-    pj_lock_release(ice_st->init_lock);
-
-    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport created"));
+    pj_grp_lock_release(ice_st->grp_lock);
+
+    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p created", ice_st));
 
     *p_ice_st = ice_st;
@@ -606,4 +602,15 @@
 }
 
+/* REALLY destroy ICE */
+static void ice_st_on_destroy(void *obj)
+{
+    pj_ice_strans *ice_st = (pj_ice_strans*)obj;
+
+    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport %p destroyed", obj));
+
+    /* Done */
+    pj_pool_release(ice_st->pool);
+}
+
 /* Destroy ICE */
 static void destroy_ice_st(pj_ice_strans *ice_st)
@@ -611,6 +618,16 @@
     unsigned i;
 
-    PJ_LOG(5,(ice_st->obj_name, "ICE stream transport destroying.."));
+    PJ_LOG(5,(ice_st->obj_name, "ICE stream transport %p destroy request..",
+	      ice_st));
     pj_log_push_indent();
+
+    pj_grp_lock_acquire(ice_st->grp_lock);
+
+    if (ice_st->destroy_req) {
+	pj_grp_lock_release(ice_st->grp_lock);
+	return;
+    }
+
+    ice_st->destroy_req = PJ_TRUE;
 
     /* Destroy ICE if we have ICE */
@@ -624,10 +641,8 @@
 	if (ice_st->comp[i]) {
 	    if (ice_st->comp[i]->stun_sock) {
-		pj_stun_sock_set_user_data(ice_st->comp[i]->stun_sock, NULL);
 		pj_stun_sock_destroy(ice_st->comp[i]->stun_sock);
 		ice_st->comp[i]->stun_sock = NULL;
 	    }
 	    if (ice_st->comp[i]->turn_sock) {
-		pj_turn_sock_set_user_data(ice_st->comp[i]->turn_sock, NULL);
 		pj_turn_sock_destroy(ice_st->comp[i]->turn_sock);
 		ice_st->comp[i]->turn_sock = NULL;
@@ -635,25 +650,8 @@
 	}
     }
-    ice_st->comp_cnt = 0;
-
-    /* Destroy mutex */
-    if (ice_st->init_lock) {
-	pj_lock_acquire(ice_st->init_lock);
-	pj_lock_release(ice_st->init_lock);
-	pj_lock_destroy(ice_st->init_lock);
-	ice_st->init_lock = NULL;
-    }
-
-    /* Destroy reference counter */
-    if (ice_st->busy_cnt) {
-	pj_assert(pj_atomic_get(ice_st->busy_cnt)==0);
-	pj_atomic_destroy(ice_st->busy_cnt);
-	ice_st->busy_cnt = NULL;
-    }
-
-    PJ_LOG(4,(ice_st->obj_name, "ICE stream transport destroyed"));
-
-    /* Done */
-    pj_pool_release(ice_st->pool);
+
+    pj_grp_lock_dec_ref(ice_st->grp_lock);
+    pj_grp_lock_release(ice_st->grp_lock);
+
     pj_log_pop_indent();
 }
@@ -740,41 +738,8 @@
 PJ_DEF(pj_status_t) pj_ice_strans_destroy(pj_ice_strans *ice_st)
 {
-    PJ_ASSERT_RETURN(ice_st, PJ_EINVAL);
-
-    sess_add_ref(ice_st);
-    ice_st->destroy_req = PJ_TRUE;
-    if (sess_dec_ref(ice_st)) {
-	PJ_LOG(5,(ice_st->obj_name, 
-		  "ICE strans object is busy, will destroy later"));
-	return PJ_EPENDING;
-    }
-
+    destroy_ice_st(ice_st);
     return PJ_SUCCESS;
 }
 
-
-/*
- * Increment busy counter.
- */
-static void sess_add_ref(pj_ice_strans *ice_st)
-{
-    pj_atomic_inc(ice_st->busy_cnt);
-}
-
-/*
- * Decrement busy counter. If the counter has reached zero and destroy
- * has been requested, destroy the object and return FALSE.
- */
-static pj_bool_t sess_dec_ref(pj_ice_strans *ice_st)
-{
-    int count = pj_atomic_dec_and_get(ice_st->busy_cnt);
-    pj_assert(count >= 0);
-    if (count==0 && ice_st->destroy_req) {
-	destroy_ice_st(ice_st);
-	return PJ_FALSE;
-    } else {
-	return PJ_TRUE;
-    }
-}
 
 /*
@@ -841,5 +806,7 @@
     status = pj_ice_sess_create(&ice_st->cfg.stun_cfg, ice_st->obj_name, role,
 			        ice_st->comp_cnt, &ice_cb, 
-			        local_ufrag, local_passwd, &ice_st->ice);
+			        local_ufrag, local_passwd,
+			        ice_st->grp_lock,
+			        &ice_st->ice);
     if (status != PJ_SUCCESS)
 	return status;
@@ -1256,5 +1223,5 @@
     unsigned msec;
 
-    sess_add_ref(ice_st);
+    pj_grp_lock_add_ref(ice_st->grp_lock);
 
     pj_gettimeofday(&t);
@@ -1338,5 +1305,5 @@
     }
 
-    sess_dec_ref(ice_st);
+    pj_grp_lock_dec_ref(ice_st->grp_lock);
 }
 
@@ -1427,5 +1394,5 @@
     ice_st = comp->ice_st;
 
-    sess_add_ref(ice_st);
+    pj_grp_lock_add_ref(ice_st->grp_lock);
 
     if (ice_st->ice == NULL) {
@@ -1452,5 +1419,5 @@
     }
 
-    return sess_dec_ref(ice_st);
+    return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
 }
 
@@ -1483,8 +1450,8 @@
     ice_st = comp->ice_st;
 
-    sess_add_ref(ice_st);
+    pj_grp_lock_add_ref(ice_st->grp_lock);
 
     /* Wait until initialization completes */
-    pj_lock_acquire(ice_st->init_lock);
+    pj_grp_lock_acquire(ice_st->grp_lock);
 
     /* Find the srflx cancidate */
@@ -1496,5 +1463,5 @@
     }
 
-    pj_lock_release(ice_st->init_lock);
+    pj_grp_lock_release(ice_st->grp_lock);
 
     /* It is possible that we don't have srflx candidate even though this
@@ -1503,5 +1470,5 @@
      */
     if (cand == NULL) {
-	return sess_dec_ref(ice_st);
+	return pj_grp_lock_dec_ref(ice_st->grp_lock) ? PJ_FALSE : PJ_TRUE;
     }
 
@@ -1619,5 +1586,5 @@
     }
 
-    return sess_dec_ref(ice_st);
+    return pj_grp_lock_dec_ref(ice_st->grp_lock)? PJ_FALSE : PJ_TRUE;
 }
 
@@ -1638,5 +1605,5 @@
     }
 
-    sess_add_ref(comp->ice_st);
+    pj_grp_lock_add_ref(comp->ice_st->grp_lock);
 
     if (comp->ice_st->ice == NULL) {
@@ -1665,5 +1632,5 @@
     }
 
-    sess_dec_ref(comp->ice_st);
+    pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
 }
 
@@ -1687,5 +1654,5 @@
     pj_log_push_indent();
 
-    sess_add_ref(comp->ice_st);
+    pj_grp_lock_add_ref(comp->ice_st->grp_lock);
 
     if (new_state == PJ_TURN_STATE_READY) {
@@ -1701,5 +1668,5 @@
 
 	/* Wait until initialization completes */
-	pj_lock_acquire(comp->ice_st->init_lock);
+	pj_grp_lock_acquire(comp->ice_st->grp_lock);
 
 	/* Find relayed candidate in the component */
@@ -1712,5 +1679,5 @@
 	pj_assert(cand != NULL);
 
-	pj_lock_release(comp->ice_st->init_lock);
+	pj_grp_lock_release(comp->ice_st->grp_lock);
 
 	/* Update candidate */
@@ -1745,20 +1712,25 @@
 	comp->turn_sock = NULL;
 
-	/* Set session to fail if we're still initializing */
-	if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
-	    sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
-		      "TURN allocation failed", info.last_status);
-	} else if (comp->turn_err_cnt > 1) {
-	    sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE,
-		      "TURN refresh failed", info.last_status);
-	} else {
-	    PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status,
-		      "Comp %d: TURN allocation failed, retrying",
-		      comp->comp_id));
-	    add_update_turn(comp->ice_st, comp);
-	}
-    }
-
-    sess_dec_ref(comp->ice_st);
+	/* Set session to fail on error. last_status PJ_SUCCESS means normal
+	 * deallocation, which should not trigger sess_fail as it may have
+	 * been initiated by ICE destroy
+	 */
+	if (info.last_status != PJ_SUCCESS) {
+	    if (comp->ice_st->state < PJ_ICE_STRANS_STATE_READY) {
+		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_INIT,
+			  "TURN allocation failed", info.last_status);
+	    } else if (comp->turn_err_cnt > 1) {
+		sess_fail(comp->ice_st, PJ_ICE_STRANS_OP_KEEP_ALIVE,
+			  "TURN refresh failed", info.last_status);
+	    } else {
+		PJ_PERROR(4,(comp->ice_st->obj_name, info.last_status,
+			  "Comp %d: TURN allocation failed, retrying",
+			  comp->comp_id));
+		add_update_turn(comp->ice_st, comp);
+	    }
+	}
+    }
+
+    pj_grp_lock_dec_ref(comp->ice_st->grp_lock);
 
     pj_log_pop_indent();
