PJ_DEF(pj_status_t) pj_ssl_sock_start_connect2(
			       pj_ssl_sock_t *ssock,
			       pj_ssl_start_connect_param *connect_param)
{
    pj_status_t status;
#ifdef SSL_SOCK_IMP_USE_OWN_NETWORK
    status = network_start_connect(ssock, connect_param);
    if (status != PJ_EPENDING)
	goto on_error;
#else
    pj_activesock_cb asock_cb;
    pj_activesock_cfg asock_cfg;
    
    pj_pool_t *pool = connect_param->pool;
    const pj_sockaddr_t *localaddr = connect_param->localaddr;
    pj_uint16_t port_range = connect_param->local_port_range;
    const pj_sockaddr_t *remaddr = connect_param->remaddr;
    int addr_len = connect_param->addr_len;

    PJ_ASSERT_RETURN(ssock && pool && localaddr && remaddr && addr_len,
		     PJ_EINVAL);

    /* Create socket */
    status = pj_sock_socket(ssock->param.sock_af, ssock->param.sock_type, 0, 
			    &ssock->sock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Apply QoS, if specified */
    status = pj_sock_apply_qos2(ssock->sock, ssock->param.qos_type,
				&ssock->param.qos_params, 2, 
				ssock->pool->obj_name, NULL);
    if (status != PJ_SUCCESS && !ssock->param.qos_ignore_error)
	goto on_error;

    /* Apply socket options, if specified */
    if (ssock->param.sockopt_params.cnt) {
	status = pj_sock_setsockopt_params(ssock->sock, 
					   &ssock->param.sockopt_params);

	if (status != PJ_SUCCESS && !ssock->param.sockopt_ignore_error)
	    goto on_error;
    }

    /* Bind socket */
    if (port_range) {
	pj_uint16_t max_bind_retry = MAX_BIND_RETRY;
	if (port_range && port_range < max_bind_retry)
	{
	    max_bind_retry = port_range;
	}
	status = pj_sock_bind_random(ssock->sock, localaddr, port_range,
				     max_bind_retry);
    } else {
	status = pj_sock_bind(ssock->sock, localaddr, addr_len);
    }

    if (status != PJ_SUCCESS)
	goto on_error;

    /* Create active socket */
    pj_activesock_cfg_default(&asock_cfg);
    asock_cfg.async_cnt = ssock->param.async_cnt;
    asock_cfg.concurrency = ssock->param.concurrency;
    asock_cfg.whole_data = PJ_TRUE;
    asock_cfg.grp_lock = ssock->param.grp_lock;

    pj_bzero(&asock_cb, sizeof(asock_cb));
    asock_cb.on_connect_complete = asock_on_connect_complete;
    asock_cb.on_data_read = asock_on_data_read;
    asock_cb.on_data_sent = asock_on_data_sent;

    status = pj_activesock_create(pool,
				  ssock->sock, 
				  ssock->param.sock_type,
				  &asock_cfg,
				  ssock->param.ioqueue, 
				  &asock_cb,
				  ssock,
				  &ssock->asock);

    if (status != PJ_SUCCESS)
	goto on_error;

    /* Save remote address */
    pj_sockaddr_cp(&ssock->rem_addr, remaddr);

    status = pj_activesock_start_connect(ssock->asock, pool, remaddr,
					 addr_len);

    if (status == PJ_SUCCESS)
	asock_on_connect_complete(ssock->asock, PJ_SUCCESS);
    else if (status != PJ_EPENDING)
	goto on_error;

    /* Update local address */
    ssock->addr_len = addr_len;
    status = pj_sock_getsockname(ssock->sock, &ssock->local_addr,
				 &ssock->addr_len);
    /* Note that we may not get an IP address here. This can
     * happen for example on Windows, where getsockname()
     * would return 0.0.0.0 if socket has just started the
     * async connect. In this case, just leave the local
     * address with 0.0.0.0 for now; it will be updated
     * once the socket is established.
     */

#endif

    /* Start timer */
    if (ssock->param.timer_heap &&
        (ssock->param.timeout.sec != 0 || ssock->param.timeout.msec != 0))
    {
	pj_assert(ssock->timer.id == TIMER_NONE);
	status = pj_timer_heap_schedule_w_grp_lock(ssock->param.timer_heap,
						   &ssock->timer,
						   &ssock->param.timeout,
						   TIMER_HANDSHAKE_TIMEOUT,
						   ssock->param.grp_lock);
	if (status != PJ_SUCCESS) {
	    ssock->timer.id = TIMER_NONE;
	    status = PJ_SUCCESS;
	}
    }

    /* Update SSL state */
    ssock->is_server = PJ_FALSE;

    return PJ_EPENDING;

on_error:
    ssl_reset_sock_state(ssock);
    return status;
}