static pj_status_t tls_create( struct tls_listener *listener,
			       pj_pool_t *pool,
			       pj_ssl_sock_t *ssock,
			       pj_bool_t is_server,
			       const pj_sockaddr *local,
			       const pj_sockaddr *remote,
			       const pj_str_t *remote_name,
			       pj_grp_lock_t *glock,
			       struct tls_transport **p_tls)
{
    struct tls_transport *tls;
    const pj_str_t ka_pkt = PJSIP_TLS_KEEP_ALIVE_DATA;
    char print_addr[PJ_INET6_ADDRSTRLEN+10];
    pj_status_t status;
    

    PJ_ASSERT_RETURN(listener && ssock && local && remote && p_tls, PJ_EINVAL);


    if (pool == NULL) {
	pool = pjsip_endpt_create_pool(listener->endpt, "tls",
				       POOL_TP_INIT, POOL_TP_INC);
	PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
    }    

    /*
     * Create and initialize basic transport structure.
     */
    tls = PJ_POOL_ZALLOC_T(pool, struct tls_transport);
    tls->is_server = is_server;
    tls->verify_server = listener->tls_setting.verify_server;
    pj_list_init(&tls->delayed_list);
    tls->base.pool = pool;

    pj_ansi_snprintf(tls->base.obj_name, PJ_MAX_OBJ_NAME, 
		     (is_server ? "tlss%p" :"tlsc%p"), tls);

    status = pj_atomic_create(pool, 0, &tls->base.ref_cnt);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    status = pj_lock_create_recursive_mutex(pool, "tls", &tls->base.lock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    if (remote_name)
	pj_strdup(pool, &tls->remote_name, remote_name);

    tls->base.key.type = listener->factory.type;
    pj_sockaddr_cp(&tls->base.key.rem_addr, remote);
    tls->base.type_name = (char*)pjsip_transport_get_type_name(
				   (pjsip_transport_type_e)tls->base.key.type);
    tls->base.flag = pjsip_transport_get_flag_from_type(
				   (pjsip_transport_type_e)tls->base.key.type);

    tls->base.info = (char*) pj_pool_alloc(pool, 64);
    pj_ansi_snprintf(tls->base.info, 64, "%s to %s",
                     tls->base.type_name,
                     pj_sockaddr_print(remote, print_addr,
                                       sizeof(print_addr), 3));


    tls->base.addr_len = pj_sockaddr_get_len(remote);
    tls->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
    
    /* Set initial local address */
    if (!pj_sockaddr_has_addr(local)) {
        pj_sockaddr_cp(&tls->base.local_addr,
                       &listener->factory.local_addr);
    } else {
	pj_sockaddr_cp(&tls->base.local_addr, local);
    }
    
    sockaddr_to_host_port(pool, &tls->base.local_name, &tls->base.local_addr);
    if (tls->remote_name.slen) {
	tls->base.remote_name.host = tls->remote_name;
	tls->base.remote_name.port = pj_sockaddr_get_port(remote);
    } else {
	sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
    }

    tls->base.endpt = listener->endpt;
    tls->base.tpmgr = listener->tpmgr;
    tls->base.send_msg = &tls_send_msg;
    tls->base.do_shutdown = &tls_shutdown;
    tls->base.destroy = &tls_destroy_transport;
    tls->base.factory = &listener->factory;

    tls->ssock = ssock;

    /* Set up the group lock */
    tls->grp_lock = tls->base.grp_lock = glock;
    pj_grp_lock_add_ref(tls->grp_lock);
    pj_grp_lock_add_handler(tls->grp_lock, pool, tls, &tls_on_destroy);

    /* Register transport to transport manager */
    status = pjsip_transport_register(listener->tpmgr, &tls->base);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tls->is_registered = PJ_TRUE;

    /* Initialize keep-alive timer */
    tls->ka_timer.user_data = (void*)tls;
    tls->ka_timer.cb = &tls_keep_alive_timer;
    pj_ioqueue_op_key_init(&tls->ka_op_key.key, sizeof(pj_ioqueue_op_key_t));
    pj_strdup(tls->base.pool, &tls->ka_pkt, &ka_pkt);
    
    /* Done setting up basic transport. */
    *p_tls = tls;

    PJ_LOG(4,(tls->base.obj_name, "TLS %s transport created",
	      (tls->is_server ? "server" : "client")));

    return PJ_SUCCESS;

on_error:
    if (tls->grp_lock && pj_grp_lock_get_ref(tls->grp_lock))
	tls_destroy(&tls->base, status);
    else
    	tls_on_destroy(tls);

    return status;
}
static pj_status_t tls_create( struct tls_listener *listener,
			       pj_pool_t *pool,
			       pj_ssl_sock_t *ssock,
			       pj_bool_t is_server,
			       const pj_sockaddr *local,
			       const pj_sockaddr *remote,
			       const pj_str_t *remote_name,
			       pj_grp_lock_t *glock,
			       struct tls_transport **p_tls)
{
    struct tls_transport *tls;
    const pj_str_t ka_pkt = PJSIP_TLS_KEEP_ALIVE_DATA;
    char print_addr[PJ_INET6_ADDRSTRLEN+10];
    pj_status_t status;
    

    PJ_ASSERT_RETURN(listener && ssock && local && remote && p_tls, PJ_EINVAL);


    if (pool == NULL) {
	pool = pjsip_endpt_create_pool(listener->endpt, "tls",
				       POOL_TP_INIT, POOL_TP_INC);
	PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
    }    

     
    tls = PJ_POOL_ZALLOC_T(pool, struct tls_transport);
    tls->is_server = is_server;
    tls->verify_server = listener->tls_setting.verify_server;
    pj_list_init(&tls->delayed_list);
    tls->base.pool = pool;

    pj_ansi_snprintf(tls->base.obj_name, PJ_MAX_OBJ_NAME, 
		     (is_server ? "tlss%p" :"tlsc%p"), tls);

    status = pj_atomic_create(pool, 0, &tls->base.ref_cnt);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    status = pj_lock_create_recursive_mutex(pool, "tls", &tls->base.lock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    if (remote_name)
	pj_strdup(pool, &tls->remote_name, remote_name);

    tls->base.key.type = listener->factory.type;
    pj_sockaddr_cp(&tls->base.key.rem_addr, remote);
    tls->base.type_name = (char*)pjsip_transport_get_type_name(
				   (pjsip_transport_type_e)tls->base.key.type);
    tls->base.flag = pjsip_transport_get_flag_from_type(
				   (pjsip_transport_type_e)tls->base.key.type);

    tls->base.info = (char*) pj_pool_alloc(pool, 64);
    pj_ansi_snprintf(tls->base.info, 64, "%s to %s",
                     tls->base.type_name,
                     pj_sockaddr_print(remote, print_addr,
                                       sizeof(print_addr), 3));


    tls->base.addr_len = pj_sockaddr_get_len(remote);
    tls->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;
    
     
    if (!pj_sockaddr_has_addr(local)) {
        pj_sockaddr_cp(&tls->base.local_addr,
                       &listener->factory.local_addr);
    } else {
	pj_sockaddr_cp(&tls->base.local_addr, local);
    }
    
    sockaddr_to_host_port(pool, &tls->base.local_name, &tls->base.local_addr);
    if (tls->remote_name.slen) {
	tls->base.remote_name.host = tls->remote_name;
	tls->base.remote_name.port = pj_sockaddr_get_port(remote);
    } else {
	sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
    }

    tls->base.endpt = listener->endpt;
    tls->base.tpmgr = listener->tpmgr;
    tls->base.send_msg = &tls_send_msg;
    tls->base.do_shutdown = &tls_shutdown;
    tls->base.destroy = &tls_destroy_transport;
    tls->base.factory = &listener->factory;

    tls->ssock = ssock;

     
    tls->grp_lock = tls->base.grp_lock = glock;
    pj_grp_lock_add_ref(tls->grp_lock);
    pj_grp_lock_add_handler(tls->grp_lock, pool, tls, &tls_on_destroy);

     
    status = pjsip_transport_register(listener->tpmgr, &tls->base);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tls->is_registered = PJ_TRUE;

     
    tls->ka_timer.user_data = (void*)tls;
    tls->ka_timer.cb = &tls_keep_alive_timer;
    pj_ioqueue_op_key_init(&tls->ka_op_key.key, sizeof(pj_ioqueue_op_key_t));
    pj_strdup(tls->base.pool, &tls->ka_pkt, &ka_pkt);
    
     
    *p_tls = tls;

    PJ_LOG(4,(tls->base.obj_name, "TLS %s transport created",
	      (tls->is_server ? "server" : "client")));

    return PJ_SUCCESS;

on_error:
    if (tls->grp_lock && pj_grp_lock_get_ref(tls->grp_lock))
	tls_destroy(&tls->base, status);
    else
    	tls_on_destroy(tls);

    return status;
}