PJ_DEF(pj_status_t) pjsip_tls_transport_start2( pjsip_endpoint *endpt,
 					        const pjsip_tls_setting *opt,
					        const pj_sockaddr *local,
					        const pjsip_host_port *a_name,
					        unsigned async_cnt,
					        pjsip_tpfactory **p_factory)
{        
    pj_pool_t *pool;
    pj_bool_t is_ipv6;    
    struct tls_listener *listener;    
    pj_status_t status;

    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);

    is_ipv6 = (local && local->addr.sa_family == pj_AF_INET6());    

    pool = pjsip_endpt_create_pool(endpt, "tlstp", POOL_LIS_INIT, 
				   POOL_LIS_INC);
    PJ_ASSERT_RETURN(pool, PJ_ENOMEM);

    listener = PJ_POOL_ZALLOC_T(pool, struct tls_listener);
    listener->factory.pool = pool;
    if (is_ipv6)
	listener->factory.type = PJSIP_TRANSPORT_TLS6;
    else
	listener->factory.type = PJSIP_TRANSPORT_TLS;
    listener->factory.type_name = (char*)
		pjsip_transport_get_type_name(listener->factory.type);
    listener->factory.flag = 
		pjsip_transport_get_flag_from_type(listener->factory.type);
    listener->endpt = endpt;

    pj_ansi_strcpy(listener->factory.obj_name, "tlstp");
    if (is_ipv6)
	pj_ansi_strcat(listener->factory.obj_name, "6");

    if (opt)
	pjsip_tls_setting_copy(pool, &listener->tls_setting, opt);
    else
	pjsip_tls_setting_default(&listener->tls_setting);

    status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
					    &listener->factory.lock);
    if (status != PJ_SUCCESS)
	goto on_error;

    if (async_cnt > MAX_ASYNC_CNT) 
	async_cnt = MAX_ASYNC_CNT;

    listener->async_cnt = async_cnt;    

    /* Create group lock */
    status = pj_grp_lock_create(pool, NULL, &listener->grp_lock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Setup group lock handler */
    pj_grp_lock_add_ref(listener->grp_lock);
    pj_grp_lock_add_handler(listener->grp_lock, pool, listener,
			    &lis_on_destroy);

    /* Check if certificate/CA list for SSL socket is set */
    if (listener->tls_setting.cert_file.slen ||
	listener->tls_setting.ca_list_file.slen ||
	listener->tls_setting.ca_list_path.slen || 
	listener->tls_setting.privkey_file.slen) 
    {
	status = pj_ssl_cert_load_from_files2(pool,
			&listener->tls_setting.ca_list_file,
			&listener->tls_setting.ca_list_path,
			&listener->tls_setting.cert_file,
			&listener->tls_setting.privkey_file,
			&listener->tls_setting.password,
			&listener->cert);
	if (status != PJ_SUCCESS)
	    goto on_error;
    } else if (listener->tls_setting.ca_buf.slen ||
	       listener->tls_setting.cert_buf.slen||
	       listener->tls_setting.privkey_buf.slen)
    {
	status = pj_ssl_cert_load_from_buffer(pool,
			&listener->tls_setting.ca_buf,
			&listener->tls_setting.cert_buf,
			&listener->tls_setting.privkey_buf,
			&listener->tls_setting.password,
			&listener->cert);
	if (status != PJ_SUCCESS)
	    goto on_error;    
    }

    /* Register to transport manager */
    listener->endpt = endpt;
    listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
    listener->factory.create_transport2 = lis_create_transport;
    listener->factory.destroy = lis_destroy;

#if !(defined(PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER) && \
    PJSIP_TLS_TRANSPORT_DONT_CREATE_LISTENER != 0)
    /* Start listener. */
    status = pjsip_tls_transport_lis_start(&listener->factory, local, a_name);
    if (status != PJ_SUCCESS)
	goto on_error;
#else
    update_bound_addr(listener, local);
    /* If published host/IP is specified, then use that address as the
     * listener advertised address.
     */
    status = update_factory_addr(listener, a_name);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Set transport info. */
    update_transport_info(listener);
#endif

    listener->is_registered = PJ_TRUE;
    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
					    &listener->factory);
    if (status != PJ_SUCCESS) {
	listener->is_registered = PJ_FALSE;
	goto on_error;
    }

    /* Return the pointer to user */
    if (p_factory) *p_factory = &listener->factory;

    return PJ_SUCCESS;

on_error:
    lis_destroy(&listener->factory);
    return status;
}