PJ_DEF(pj_status_t) pjsip_transport_dec_ref( pjsip_transport *tp )
{
    pjsip_tpmgr *tpmgr;
    pjsip_transport_key key;
    int key_len;

    PJ_ASSERT_RETURN(tp != NULL, PJ_EINVAL);
    pj_assert(pj_atomic_get(tp->ref_cnt) > 0);

    /* Cache some vars for checking transport validity later */
    tpmgr = tp->tpmgr;
    key_len = sizeof(tp->key.type) + tp->addr_len;
    pj_memcpy(&key, &tp->key, key_len);

    if (pj_atomic_dec_and_get(tp->ref_cnt) == 0) {
	pj_lock_acquire(tpmgr->lock);
	/* Verify again. Do not register timer if the transport is
	 * being destroyed. But first, make sure transport is still valid
	 * (see #1883).
	 */
	if (is_transport_valid(tp, tpmgr, &key, key_len) &&
	    !tp->is_destroying && pj_atomic_get(tp->ref_cnt) == 0)
	{
	    pj_time_val delay;
	    
	    /* If transport is in graceful shutdown, then this is the
	     * last user who uses the transport. Schedule to destroy the
	     * transport immediately. Otherwise schedule idle timer.
	     */
	    if (tp->is_shutdown) {
		delay.sec = delay.msec = 0;
	    } else {
		delay.sec = (tp->dir==PJSIP_TP_DIR_OUTGOING) ?
				PJSIP_TRANSPORT_IDLE_TIME :
				PJSIP_TRANSPORT_SERVER_IDLE_TIME;
		delay.msec = 0;
	    }

	    /* Avoid double timer entry scheduling */
	    if (pj_timer_entry_running(&tp->idle_timer))
		pjsip_endpt_cancel_timer(tp->tpmgr->endpt, &tp->idle_timer);

	    pjsip_endpt_schedule_timer_w_grp_lock(tp->tpmgr->endpt,
						  &tp->idle_timer,
						  &delay,
						  PJ_TRUE,
						  tp->grp_lock);
	}
	pj_lock_release(tpmgr->lock);
    }

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

    return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjsip_transport_dec_ref( pjsip_transport *tp )
{
    pjsip_tpmgr *tpmgr;
    pjsip_transport_key key;
    int key_len;

    PJ_ASSERT_RETURN(tp != NULL, PJ_EINVAL);
    pj_assert(pj_atomic_get(tp->ref_cnt) > 0);

     
    tpmgr = tp->tpmgr;
    key_len = sizeof(tp->key.type) + tp->addr_len;
    pj_memcpy(&key, &tp->key, key_len);

    if (pj_atomic_dec_and_get(tp->ref_cnt) == 0) {
	pj_lock_acquire(tpmgr->lock);
	 
	if (is_transport_valid(tp, tpmgr, &key, key_len) &&
	    !tp->is_destroying && pj_atomic_get(tp->ref_cnt) == 0)
	{
	    pj_time_val delay;
	    
	     
	    if (tp->is_shutdown) {
		delay.sec = delay.msec = 0;
	    } else {
		delay.sec = (tp->dir==PJSIP_TP_DIR_OUTGOING) ?
				PJSIP_TRANSPORT_IDLE_TIME :
				PJSIP_TRANSPORT_SERVER_IDLE_TIME;
		delay.msec = 0;
	    }

	     
	    if (pj_timer_entry_running(&tp->idle_timer))
		pjsip_endpt_cancel_timer(tp->tpmgr->endpt, &tp->idle_timer);

	    pjsip_endpt_schedule_timer_w_grp_lock(tp->tpmgr->endpt,
						  &tp->idle_timer,
						  &delay,
						  PJ_TRUE,
						  tp->grp_lock);
	}
	pj_lock_release(tpmgr->lock);
    }

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

    return PJ_SUCCESS;
}