PJ_DEF(pj_status_t) pjsip_transport_remove_state_listener (
				    pjsip_transport *tp,
				    pjsip_tp_state_listener_key *key,
				    const void *user_data)
{
    transport_data *tp_data;
    tp_state_listener *entry;

    PJ_ASSERT_RETURN(tp && key, PJ_EINVAL);

    pj_lock_acquire(tp->lock);

    tp_data = (transport_data*)tp->data;

    /* Transport data is NULL or no registered listener? */
    if (!tp_data || pj_list_empty(&tp_data->st_listeners)) {
	pj_lock_release(tp->lock);
	return PJ_ENOTFOUND;
    }

    entry = (tp_state_listener*)key;

    /* Validate the user data */
    if (entry->user_data != user_data) {
	pj_assert(!"Invalid transport state listener key");
	pj_lock_release(tp->lock);
	return PJ_EBUG;
    }

    /* Reset the entry and move it to the empty list */
    entry->cb = NULL;
    entry->user_data = NULL;
    pj_list_erase(entry);
    pj_list_push_back(&tp_data->st_listeners_empty, entry);

    pj_lock_release(tp->lock);

    return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjsip_transport_remove_state_listener (
				    pjsip_transport *tp,
				    pjsip_tp_state_listener_key *key,
				    const void *user_data)
{
    transport_data *tp_data;
    tp_state_listener *entry;

    PJ_ASSERT_RETURN(tp && key, PJ_EINVAL);

    pj_lock_acquire(tp->lock);

    tp_data = (transport_data*)tp->data;

     
    if (!tp_data || pj_list_empty(&tp_data->st_listeners)) {
	pj_lock_release(tp->lock);
	return PJ_ENOTFOUND;
    }

    entry = (tp_state_listener*)key;

     
    if (entry->user_data != user_data) {
	pj_assert(!"Invalid transport state listener key");
	pj_lock_release(tp->lock);
	return PJ_EBUG;
    }

     
    entry->cb = NULL;
    entry->user_data = NULL;
    pj_list_erase(entry);
    pj_list_push_back(&tp_data->st_listeners_empty, entry);

    pj_lock_release(tp->lock);

    return PJ_SUCCESS;
}