static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
				      pjsip_transport *tp )
{
    int key_len;
    pj_uint32_t hval;
    void *entry;

    tp->is_destroying = PJ_TRUE;

    TRACE_((THIS_FILE, "Transport %s is being destroyed", tp->obj_name));

    pj_lock_acquire(tp->lock);
    pj_lock_acquire(mgr->lock);

    /*
     * Unregister timer, if any.
     */
    //pj_assert(tp->idle_timer.id == PJ_FALSE);
    if (tp->idle_timer.id != PJ_FALSE) {
	tp->idle_timer.id = PJ_FALSE;
	pjsip_endpt_cancel_timer(mgr->endpt, &tp->idle_timer);
    }

    /*
     * Unregister from hash table (see Trac ticket #42).
     */
    key_len = sizeof(tp->key.type) + tp->addr_len;
    hval = 0;
    entry = pj_hash_get(mgr->table, &tp->key, key_len, &hval);
    if (entry) {
	transport *tp_ref = (transport *)entry;
	transport *tp_iter = tp_ref;
	/* Search the matching entry from the transport list. */
	do {
	    if (tp_iter->tp == tp) {
		transport *tp_next = tp_iter->next;

		/* Update hash table :
		 * - transport list only contain single element, or
		 * - the entry is the first element of the transport list.
		 */
		if (tp_iter == tp_ref) {
		    pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval,
				NULL);

		    if (tp_ref->next != tp_ref) {
			/* The transport list has multiple entry. */
			pj_hash_set_np(mgr->table, &tp_next->tp->key, key_len,
				       hval, tp_next->tp_buf, tp_next);
			TRACE_((THIS_FILE, "Hash entry updated after "
					   "transport %d being destroyed",
					   tp->obj_name));
		    } else {
			TRACE_((THIS_FILE, "Hash entry deleted after "
					   "transport %d being destroyed",
					   tp->obj_name));
		    }
		}

		pj_list_erase(tp_iter);
		/* Put back to the transport freelist. */
		pj_list_push_back(&mgr->tp_entry_freelist, tp_iter);

		break;
	    }
	    tp_iter = tp_iter->next;
	} while (tp_iter != tp_ref);

	if (tp_iter->tp != tp) {
	    PJ_LOG(3, (THIS_FILE, "Warning: transport %s being destroyed is "
				  "not registered", tp->obj_name));
	}
    } else {
	PJ_LOG(3, (THIS_FILE, "Warning: transport %s being destroyed is "
			      "not found in the hash table", tp->obj_name));
    }

    pj_lock_release(mgr->lock);
    pj_lock_release(tp->lock);

    /* Dec ref transport group lock, if any */
    if (tp->grp_lock) {
	pj_grp_lock_dec_ref(tp->grp_lock);
    }

    /* Destroy. */
    return tp->destroy(tp);
}
static pj_status_t destroy_transport( pjsip_tpmgr *mgr,
				      pjsip_transport *tp )
{
    int key_len;
    pj_uint32_t hval;
    void *entry;

    tp->is_destroying = PJ_TRUE;

    TRACE_((THIS_FILE, "Transport %s is being destroyed", tp->obj_name));

    pj_lock_acquire(tp->lock);
    pj_lock_acquire(mgr->lock);

     
     
    if (tp->idle_timer.id != PJ_FALSE) {
	tp->idle_timer.id = PJ_FALSE;
	pjsip_endpt_cancel_timer(mgr->endpt, &tp->idle_timer);
    }

     
    key_len = sizeof(tp->key.type) + tp->addr_len;
    hval = 0;
    entry = pj_hash_get(mgr->table, &tp->key, key_len, &hval);
    if (entry) {
	transport *tp_ref = (transport *)entry;
	transport *tp_iter = tp_ref;
	 
	do {
	    if (tp_iter->tp == tp) {
		transport *tp_next = tp_iter->next;

		 
		if (tp_iter == tp_ref) {
		    pj_hash_set(NULL, mgr->table, &tp->key, key_len, hval,
				NULL);

		    if (tp_ref->next != tp_ref) {
			 
			pj_hash_set_np(mgr->table, &tp_next->tp->key, key_len,
				       hval, tp_next->tp_buf, tp_next);
			TRACE_((THIS_FILE, "Hash entry updated after "
					   "transport %d being destroyed",
					   tp->obj_name));
		    } else {
			TRACE_((THIS_FILE, "Hash entry deleted after "
					   "transport %d being destroyed",
					   tp->obj_name));
		    }
		}

		pj_list_erase(tp_iter);
		 
		pj_list_push_back(&mgr->tp_entry_freelist, tp_iter);

		break;
	    }
	    tp_iter = tp_iter->next;
	} while (tp_iter != tp_ref);

	if (tp_iter->tp != tp) {
	    PJ_LOG(3, (THIS_FILE, "Warning: transport %s being destroyed is "
				  "not registered", tp->obj_name));
	}
    } else {
	PJ_LOG(3, (THIS_FILE, "Warning: transport %s being destroyed is "
			      "not found in the hash table", tp->obj_name));
    }

    pj_lock_release(mgr->lock);
    pj_lock_release(tp->lock);

     
    if (tp->grp_lock) {
	pj_grp_lock_dec_ref(tp->grp_lock);
    }

     
    return tp->destroy(tp);
}