static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
					pjsip_tpmgr *mgr,
					pjsip_endpoint *endpt,
					const pj_sockaddr *rem_addr,
					int addr_len,
					pjsip_tx_data *tdata,
					pjsip_transport **p_transport)
{
    struct tls_listener *listener;
    struct tls_transport *tls;
    int sip_ssl_method;
    pj_uint32_t sip_ssl_proto;
    pj_pool_t *pool;
    pj_grp_lock_t *glock;
    pj_ssl_sock_t *ssock;
    pj_ssl_sock_param ssock_param;
    pj_sockaddr local_addr;
    pj_str_t remote_name;
    pj_status_t status;

    /* Sanity checks */
    PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr &&
		     addr_len && p_transport, PJ_EINVAL);

    /* Check that address is a sockaddr_in or sockaddr_in6*/
    PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() &&
		      addr_len == sizeof(pj_sockaddr_in)) ||
		     (rem_addr->addr.sa_family == pj_AF_INET6() &&
		      addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL);


    listener = (struct tls_listener*)factory;

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

    /* Get remote host name from tdata */
    if (tdata)
	remote_name = tdata->dest_info.name;
    else
	pj_bzero(&remote_name, sizeof(remote_name));

    /* Build SSL socket param */
    pj_ssl_sock_param_default(&ssock_param);
    ssock_param.sock_af = (factory->type & PJSIP_TRANSPORT_IPV6) ?
			    pj_AF_INET6() : pj_AF_INET();
    ssock_param.cb.on_connect_complete = &on_connect_complete;
    ssock_param.cb.on_data_read = &on_data_read;
    ssock_param.cb.on_data_sent = &on_data_sent;
    ssock_param.async_cnt = 1;
    ssock_param.ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
    ssock_param.timer_heap = pjsip_endpt_get_timer_heap(listener->endpt);
    ssock_param.server_name = remote_name;
    ssock_param.timeout = listener->tls_setting.timeout;
    ssock_param.user_data = NULL; /* pending, must be set later */
    ssock_param.verify_peer = PJ_FALSE; /* avoid SSL socket closing the socket
					 * due to verification error */
    if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN)
	ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
    if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
	ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
    ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
    ssock_param.ciphers = listener->tls_setting.ciphers;
    ssock_param.curves_num = listener->tls_setting.curves_num;
    ssock_param.curves = listener->tls_setting.curves;
    ssock_param.sigalgs = listener->tls_setting.sigalgs;
    ssock_param.entropy_type = listener->tls_setting.entropy_type;
    ssock_param.entropy_path = listener->tls_setting.entropy_path;
    ssock_param.qos_type = listener->tls_setting.qos_type;
    ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
    pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,
	      sizeof(ssock_param.qos_params));

    ssock_param.sockopt_ignore_error = 
				     listener->tls_setting.sockopt_ignore_error;
    /* Copy the sockopt */
    pj_memcpy(&ssock_param.sockopt_params, 
	      &listener->tls_setting.sockopt_params,
	      sizeof(listener->tls_setting.sockopt_params));

    sip_ssl_method = listener->tls_setting.method;
    sip_ssl_proto = listener->tls_setting.proto;
    ssock_param.proto = ssl_get_proto(sip_ssl_method, sip_ssl_proto);

    /* Create group lock */
    status = pj_grp_lock_create(pool, NULL, &glock);
    if (status != PJ_SUCCESS)
	return status;

    ssock_param.grp_lock = glock;
    status = pj_ssl_sock_create(pool, &ssock_param, &ssock);
    if (status != PJ_SUCCESS) {
	pj_grp_lock_destroy(glock);
	return status;
    }

    /* Apply SSL certificate */
    if (listener->cert) {
	status = pj_ssl_sock_set_certificate(ssock, pool, listener->cert);
	if (status != PJ_SUCCESS) {
	    pj_grp_lock_destroy(glock);
	    return status;
	}
    }

    /* Initially set bind address to listener's bind address */
    pj_sockaddr_init(listener->bound_addr.addr.sa_family,
		     &local_addr, NULL, 0);
    pj_sockaddr_copy_addr(&local_addr, &listener->bound_addr);

    /* Create the transport descriptor */
    status = tls_create(listener, pool, ssock, PJ_FALSE, &local_addr, 
			rem_addr, &remote_name, glock, &tls);
    if (status != PJ_SUCCESS)
	return status;

    /* Set the "pending" SSL socket user data */
    pj_ssl_sock_set_user_data(tls->ssock, tls);

    /* Start asynchronous connect() operation */
    tls->has_pending_connect = PJ_TRUE;
    status = pj_ssl_sock_start_connect(tls->ssock, tls->base.pool, 
				       (pj_sockaddr_t*)&local_addr,
				       (pj_sockaddr_t*)rem_addr,
				       addr_len);
    if (status == PJ_SUCCESS) {
	on_connect_complete(tls->ssock, PJ_SUCCESS);
    } else if (status != PJ_EPENDING) {
	tls_destroy(&tls->base, status);
	return status;
    }

    if (tls->has_pending_connect) {
	pj_ssl_sock_info info;
	char local_addr_buf[PJ_INET6_ADDRSTRLEN+10];
	char remote_addr_buf[PJ_INET6_ADDRSTRLEN+10];

	/* Update local address, just in case local address currently set is 
	 * different now that asynchronous connect() is started.
	 */

	/* Retrieve the bound address */
	status = pj_ssl_sock_get_info(tls->ssock, &info);
	if (status == PJ_SUCCESS) {
	    pj_uint16_t new_port;

	    new_port = pj_sockaddr_get_port((pj_sockaddr_t*)&info.local_addr);

	    if (pj_sockaddr_has_addr((pj_sockaddr_t*)&info.local_addr)) {
		/* Update sockaddr */
		pj_sockaddr_cp((pj_sockaddr_t*)&tls->base.local_addr,
			       (pj_sockaddr_t*)&info.local_addr);
	    } else if (new_port && new_port != pj_sockaddr_get_port(
					(pj_sockaddr_t*)&tls->base.local_addr))
	    {
		/* Update port only */
		pj_sockaddr_set_port(&tls->base.local_addr, 
				     new_port);
	    }

	    sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
				  &tls->base.local_addr);
	}

	PJ_LOG(4,(tls->base.obj_name, 
		  "TLS transport %s is connecting to %s...",
		  pj_addr_str_print(&tls->base.local_name.host, 
				    tls->base.local_name.port, 
				    local_addr_buf, sizeof(local_addr_buf), 1),
		  pj_addr_str_print(&tls->base.remote_name.host, 
			        tls->base.remote_name.port, 
				remote_addr_buf, sizeof(remote_addr_buf), 1)));
    }

    /* Done */
    *p_transport = &tls->base;

    return PJ_SUCCESS;
}
static pj_status_t lis_create_transport(pjsip_tpfactory *factory,
					pjsip_tpmgr *mgr,
					pjsip_endpoint *endpt,
					const pj_sockaddr *rem_addr,
					int addr_len,
					pjsip_tx_data *tdata,
					pjsip_transport **p_transport)
{
    struct tls_listener *listener;
    struct tls_transport *tls;
    int sip_ssl_method;
    pj_uint32_t sip_ssl_proto;
    pj_pool_t *pool;
    pj_grp_lock_t *glock;
    pj_ssl_sock_t *ssock;
    pj_ssl_sock_param ssock_param;
    pj_sockaddr local_addr;
    pj_str_t remote_name;
    pj_status_t status;

     
    PJ_ASSERT_RETURN(factory && mgr && endpt && rem_addr &&
		     addr_len && p_transport, PJ_EINVAL);

     
    PJ_ASSERT_RETURN((rem_addr->addr.sa_family == pj_AF_INET() &&
		      addr_len == sizeof(pj_sockaddr_in)) ||
		     (rem_addr->addr.sa_family == pj_AF_INET6() &&
		      addr_len == sizeof(pj_sockaddr_in6)), PJ_EINVAL);


    listener = (struct tls_listener*)factory;

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

     
    if (tdata)
	remote_name = tdata->dest_info.name;
    else
	pj_bzero(&remote_name, sizeof(remote_name));

     
    pj_ssl_sock_param_default(&ssock_param);
    ssock_param.sock_af = (factory->type & PJSIP_TRANSPORT_IPV6) ?
			    pj_AF_INET6() : pj_AF_INET();
    ssock_param.cb.on_connect_complete = &on_connect_complete;
    ssock_param.cb.on_data_read = &on_data_read;
    ssock_param.cb.on_data_sent = &on_data_sent;
    ssock_param.async_cnt = 1;
    ssock_param.ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
    ssock_param.timer_heap = pjsip_endpt_get_timer_heap(listener->endpt);
    ssock_param.server_name = remote_name;
    ssock_param.timeout = listener->tls_setting.timeout;
    ssock_param.user_data = NULL;  
    ssock_param.verify_peer = PJ_FALSE;  
    if (ssock_param.send_buffer_size < PJSIP_MAX_PKT_LEN)
	ssock_param.send_buffer_size = PJSIP_MAX_PKT_LEN;
    if (ssock_param.read_buffer_size < PJSIP_MAX_PKT_LEN)
	ssock_param.read_buffer_size = PJSIP_MAX_PKT_LEN;
    ssock_param.ciphers_num = listener->tls_setting.ciphers_num;
    ssock_param.ciphers = listener->tls_setting.ciphers;
    ssock_param.curves_num = listener->tls_setting.curves_num;
    ssock_param.curves = listener->tls_setting.curves;
    ssock_param.sigalgs = listener->tls_setting.sigalgs;
    ssock_param.entropy_type = listener->tls_setting.entropy_type;
    ssock_param.entropy_path = listener->tls_setting.entropy_path;
    ssock_param.qos_type = listener->tls_setting.qos_type;
    ssock_param.qos_ignore_error = listener->tls_setting.qos_ignore_error;
    pj_memcpy(&ssock_param.qos_params, &listener->tls_setting.qos_params,
	      sizeof(ssock_param.qos_params));

    ssock_param.sockopt_ignore_error = 
				     listener->tls_setting.sockopt_ignore_error;
     
    pj_memcpy(&ssock_param.sockopt_params, 
	      &listener->tls_setting.sockopt_params,
	      sizeof(listener->tls_setting.sockopt_params));

    sip_ssl_method = listener->tls_setting.method;
    sip_ssl_proto = listener->tls_setting.proto;
    ssock_param.proto = ssl_get_proto(sip_ssl_method, sip_ssl_proto);

     
    status = pj_grp_lock_create(pool, NULL, &glock);
    if (status != PJ_SUCCESS)
	return status;

    ssock_param.grp_lock = glock;
    status = pj_ssl_sock_create(pool, &ssock_param, &ssock);
    if (status != PJ_SUCCESS) {
	pj_grp_lock_destroy(glock);
	return status;
    }

     
    if (listener->cert) {
	status = pj_ssl_sock_set_certificate(ssock, pool, listener->cert);
	if (status != PJ_SUCCESS) {
	    pj_grp_lock_destroy(glock);
	    return status;
	}
    }

     
    pj_sockaddr_init(listener->bound_addr.addr.sa_family,
		     &local_addr, NULL, 0);
    pj_sockaddr_copy_addr(&local_addr, &listener->bound_addr);

     
    status = tls_create(listener, pool, ssock, PJ_FALSE, &local_addr, 
			rem_addr, &remote_name, glock, &tls);
    if (status != PJ_SUCCESS)
	return status;

     
    pj_ssl_sock_set_user_data(tls->ssock, tls);

     
    tls->has_pending_connect = PJ_TRUE;
    status = pj_ssl_sock_start_connect(tls->ssock, tls->base.pool, 
				       (pj_sockaddr_t*)&local_addr,
				       (pj_sockaddr_t*)rem_addr,
				       addr_len);
    if (status == PJ_SUCCESS) {
	on_connect_complete(tls->ssock, PJ_SUCCESS);
    } else if (status != PJ_EPENDING) {
	tls_destroy(&tls->base, status);
	return status;
    }

    if (tls->has_pending_connect) {
	pj_ssl_sock_info info;
	char local_addr_buf[PJ_INET6_ADDRSTRLEN+10];
	char remote_addr_buf[PJ_INET6_ADDRSTRLEN+10];

	 

	 
	status = pj_ssl_sock_get_info(tls->ssock, &info);
	if (status == PJ_SUCCESS) {
	    pj_uint16_t new_port;

	    new_port = pj_sockaddr_get_port((pj_sockaddr_t*)&info.local_addr);

	    if (pj_sockaddr_has_addr((pj_sockaddr_t*)&info.local_addr)) {
		 
		pj_sockaddr_cp((pj_sockaddr_t*)&tls->base.local_addr,
			       (pj_sockaddr_t*)&info.local_addr);
	    } else if (new_port && new_port != pj_sockaddr_get_port(
					(pj_sockaddr_t*)&tls->base.local_addr))
	    {
		 
		pj_sockaddr_set_port(&tls->base.local_addr, 
				     new_port);
	    }

	    sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
				  &tls->base.local_addr);
	}

	PJ_LOG(4,(tls->base.obj_name, 
		  "TLS transport %s is connecting to %s...",
		  pj_addr_str_print(&tls->base.local_name.host, 
				    tls->base.local_name.port, 
				    local_addr_buf, sizeof(local_addr_buf), 1),
		  pj_addr_str_print(&tls->base.remote_name.host, 
			        tls->base.remote_name.port, 
				remote_addr_buf, sizeof(remote_addr_buf), 1)));
    }

     
    *p_transport = &tls->base;

    return PJ_SUCCESS;
}