PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
					      pjsip_transport *tp )
{
    int key_len;
    pj_uint32_t hval;
    transport *tp_ref = NULL;
    transport *tp_add = NULL;

    /* Init. */
    tp->tpmgr = mgr;
    pj_bzero(&tp->idle_timer, sizeof(tp->idle_timer));
    tp->idle_timer.user_data = tp;
    tp->idle_timer.cb = &transport_idle_callback;

    /*
     * Register to hash table (see Trac ticket #42).
     */
    key_len = sizeof(tp->key.type) + tp->addr_len;
    pj_lock_acquire(mgr->lock);

    hval = 0;
    tp_ref = (transport *)pj_hash_get(mgr->table, &tp->key, key_len, &hval);

    /* Get an empty entry from the freelist. */
    if (pj_list_empty(&mgr->tp_entry_freelist)) {
	unsigned i = 0;

	TRACE_((THIS_FILE, "Transport list is full, allocate new entry"));
	/* Allocate new entry for the freelist. */
	for (; i < PJSIP_TRANSPORT_ENTRY_ALLOC_CNT; ++i) {
	    tp_add = PJ_POOL_ZALLOC_T(mgr->pool, transport);
	    if (!tp_add)
		return PJ_ENOMEM;
	    pj_list_init(tp_add);
	    pj_list_push_back(&mgr->tp_entry_freelist, tp_add);
	}
    }
    tp_add = mgr->tp_entry_freelist.next;
    tp_add->tp = tp;
    pj_list_erase(tp_add);

    if (tp_ref) {
	/* There'a already a transport list from the hash table. Add the 
	 * new transport to the list.
	 */
	pj_list_push_back(tp_ref, tp_add);
	TRACE_((THIS_FILE, "Remote address already registered, "
			   "appended the transport to the list"));
    } else {
	/* Transport list not found, add it to the hash table. */
	pj_hash_set_np(mgr->table, &tp->key, key_len, hval, tp_add->tp_buf,
		       tp_add);
	TRACE_((THIS_FILE, "Remote address not registered, "
			   "added the transport to the hash"));
    }

    /* Add ref transport group lock, if any */
    if (tp->grp_lock)
	pj_grp_lock_add_ref(tp->grp_lock);

    pj_lock_release(mgr->lock);

    TRACE_((THIS_FILE, "Transport %s registered: type=%s, remote=%s:%d",
	    tp->obj_name,
	    pjsip_transport_get_type_name(tp->key.type),
	    pj_sockaddr_has_addr(&tp->key.rem_addr)?
				addr_string(&tp->key.rem_addr):"",
	    pj_sockaddr_has_addr(&tp->key.rem_addr)?
				pj_sockaddr_get_port(&tp->key.rem_addr):0));

    return PJ_SUCCESS;
}
PJ_DEF(pj_status_t) pjsip_transport_register( pjsip_tpmgr *mgr,
					      pjsip_transport *tp )
{
    int key_len;
    pj_uint32_t hval;
    transport *tp_ref = NULL;
    transport *tp_add = NULL;

     
    tp->tpmgr = mgr;
    pj_bzero(&tp->idle_timer, sizeof(tp->idle_timer));
    tp->idle_timer.user_data = tp;
    tp->idle_timer.cb = &transport_idle_callback;

     
    key_len = sizeof(tp->key.type) + tp->addr_len;
    pj_lock_acquire(mgr->lock);

    hval = 0;
    tp_ref = (transport *)pj_hash_get(mgr->table, &tp->key, key_len, &hval);

     
    if (pj_list_empty(&mgr->tp_entry_freelist)) {
	unsigned i = 0;

	TRACE_((THIS_FILE, "Transport list is full, allocate new entry"));
	 
	for (; i < PJSIP_TRANSPORT_ENTRY_ALLOC_CNT; ++i) {
	    tp_add = PJ_POOL_ZALLOC_T(mgr->pool, transport);
	    if (!tp_add)
		return PJ_ENOMEM;
	    pj_list_init(tp_add);
	    pj_list_push_back(&mgr->tp_entry_freelist, tp_add);
	}
    }
    tp_add = mgr->tp_entry_freelist.next;
    tp_add->tp = tp;
    pj_list_erase(tp_add);

    if (tp_ref) {
	 
	pj_list_push_back(tp_ref, tp_add);
	TRACE_((THIS_FILE, "Remote address already registered, "
			   "appended the transport to the list"));
    } else {
	 
	pj_hash_set_np(mgr->table, &tp->key, key_len, hval, tp_add->tp_buf,
		       tp_add);
	TRACE_((THIS_FILE, "Remote address not registered, "
			   "added the transport to the hash"));
    }

     
    if (tp->grp_lock)
	pj_grp_lock_add_ref(tp->grp_lock);

    pj_lock_release(mgr->lock);

    TRACE_((THIS_FILE, "Transport %s registered: type=%s, remote=%s:%d",
	    tp->obj_name,
	    pjsip_transport_get_type_name(tp->key.type),
	    pj_sockaddr_has_addr(&tp->key.rem_addr)?
				addr_string(&tp->key.rem_addr):"",
	    pj_sockaddr_has_addr(&tp->key.rem_addr)?
				pj_sockaddr_get_port(&tp->key.rem_addr):0));

    return PJ_SUCCESS;
}