Index: pjproject/branches/projects/uwp/pjlib/src/pj/ssl_sock_ossl.c
===================================================================
--- pjproject/branches/projects/uwp/pjlib/src/pj/ssl_sock_ossl.c	(revision 5208)
+++ pjproject/branches/projects/uwp/pjlib/src/pj/ssl_sock_ossl.c	(revision 5513)
@@ -38,6 +38,8 @@
 #define THIS_FILE		"ssl_sock_ossl.c"
 
-/* Workaround for ticket #985 */
-#define DELAYED_CLOSE_TIMEOUT	200
+/* Workaround for ticket #985 and #1930 */
+#ifndef PJ_SSL_SOCK_DELAYED_CLOSE_TIMEOUT
+#   define PJ_SSL_SOCK_DELAYED_CLOSE_TIMEOUT	500
+#endif
 
 /* 
@@ -48,5 +50,11 @@
 #include <openssl/err.h>
 #include <openssl/x509v3.h>
-
+#include <openssl/rand.h>
+#include <openssl/engine.h>
+
+#if defined(PJ_SSL_SOCK_OSSL_HAS_EC) && PJ_SSL_SOCK_OSSL_HAS_EC==1
+   extern int tls1_ec_nid2curve_id(int nid);
+   extern int tls1_ec_curve_id2nid(int curve_id);
+#endif
 
 #ifdef _MSC_VER
@@ -142,4 +150,5 @@
     pj_ssl_sock_t	 *parent;
     pj_ssl_sock_param	  param;
+    pj_ssl_sock_param	  newsock_param;
     pj_ssl_cert_t	 *cert;
     
@@ -297,4 +306,11 @@
 } openssl_ciphers[PJ_SSL_SOCK_MAX_CIPHERS];
 
+/* OpenSSL available curves */
+static unsigned openssl_curves_num;
+static struct openssl_curves_t {
+    pj_ssl_curve    id;
+    const char	    *name;
+} openssl_curves[PJ_SSL_SOCK_MAX_CURVES];
+
 /* OpenSSL application data index */
 static int sslsock_idx;
@@ -326,5 +342,5 @@
 
     /* Init available ciphers */
-    if (openssl_cipher_num == 0) {
+    if (openssl_cipher_num == 0 || openssl_curves_num == 0) {
 	SSL_METHOD *meth = NULL;
 	SSL_CTX *ctx;
@@ -332,4 +348,6 @@
 	STACK_OF(SSL_CIPHER) *sk_cipher;
 	unsigned i, n;
+	int nid;
+	const char *cname;
 
 	meth = (SSL_METHOD*)SSLv23_server_method();
@@ -350,4 +368,5 @@
 
 	ssl = SSL_new(ctx);
+
 	sk_cipher = SSL_get_ciphers(ssl);
 
@@ -363,9 +382,36 @@
 	    openssl_ciphers[i].name = SSL_CIPHER_get_name(c);
 	}
+	openssl_cipher_num = n;
+
+	ssl->session = SSL_SESSION_new();
+
+#if defined(PJ_SSL_SOCK_OSSL_HAS_EC) && PJ_SSL_SOCK_OSSL_HAS_EC==1
+	openssl_curves_num = SSL_get_shared_curve(ssl,-1);
+	if (openssl_curves_num > PJ_ARRAY_SIZE(openssl_curves))
+	    openssl_curves_num = PJ_ARRAY_SIZE(openssl_curves);
+
+	for (i = 0; i < openssl_curves_num; i++) {
+	    nid = SSL_get_shared_curve(ssl, i);
+
+	    if (nid & TLSEXT_nid_unknown) {
+		cname = "curve unknown";
+		nid &= 0xFFFF;
+	    } else {
+		cname = EC_curve_nid2nist(nid);
+		if (!cname)
+		    cname = OBJ_nid2sn(nid);
+	    }
+
+	    openssl_curves[i].id   = tls1_ec_nid2curve_id(nid);
+	    openssl_curves[i].name = cname;
+	}
+#else
+	PJ_UNUSED_ARG(nid);
+	PJ_UNUSED_ARG(cname);
+	openssl_curves_num = 0;
+#endif
 
 	SSL_free(ssl);
 	SSL_CTX_free(ctx);
-
-	openssl_cipher_num = n;
     }
 
@@ -373,5 +419,5 @@
     sslsock_idx = SSL_get_ex_new_index(0, "SSL socket", NULL, NULL, NULL);
 
-    return PJ_SUCCESS;
+    return status;
 }
 
@@ -496,5 +542,10 @@
 /* Setting SSL sock cipher list */
 static pj_status_t set_cipher_list(pj_ssl_sock_t *ssock);
-
+/* Setting SSL sock curves list */
+static pj_status_t set_curves_list(pj_ssl_sock_t *ssock);
+/* Setting sigalgs list */
+static pj_status_t set_sigalgs(pj_ssl_sock_t *ssock);
+/* Setting entropy for rng */
+static void set_entropy(pj_ssl_sock_t *ssock);
 
 /* Create and initialize new SSL context and instance */
@@ -520,4 +571,6 @@
     /* Make sure OpenSSL library has been initialized */
     init_openssl();
+
+    set_entropy(ssock);
 
     if (ssock->param.proto == PJ_SSL_SOCK_PROTO_DEFAULT)
@@ -773,4 +826,14 @@
 	return status;
 
+    /* Set curve list */
+    status = set_curves_list(ssock);
+    if (status != PJ_SUCCESS)
+	return status;
+
+    /* Set sigalg list */
+    status = set_sigalgs(ssock);
+    if (status != PJ_SUCCESS)
+	return status;
+
     /* Setup SSL BIOs */
     ssock->ossl_rbio = BIO_new(BIO_s_mem());
@@ -807,20 +870,44 @@
 
 
+/* Close sockets */
+static void close_sockets(pj_ssl_sock_t *ssock)
+{
+    pj_activesock_t *asock;
+    pj_sock_t sock;
+
+    /* This can happen when pj_ssl_sock_create() fails. */
+    if (!ssock->write_mutex)
+    	return;
+
+    pj_lock_acquire(ssock->write_mutex);
+    asock = ssock->asock;
+    if (asock) {
+        // Don't set ssock->asock to NULL, as it may trigger assertion in
+        // send operation. This should be safe as active socket will simply
+        // return PJ_EINVALIDOP on any operation if it is already closed.
+        //ssock->asock = NULL;
+        ssock->sock = PJ_INVALID_SOCKET;
+    }
+    sock = ssock->sock;
+    if (sock != PJ_INVALID_SOCKET)
+        ssock->sock = PJ_INVALID_SOCKET;
+    pj_lock_release(ssock->write_mutex);
+
+    if (asock)
+        pj_activesock_close(asock);
+
+    if (sock != PJ_INVALID_SOCKET)
+        pj_sock_close(sock);
+}
+
+
 /* Reset SSL socket state */
 static void reset_ssl_sock_state(pj_ssl_sock_t *ssock)
 {
+    pj_lock_acquire(ssock->write_mutex);
     ssock->ssl_state = SSL_STATE_NULL;
-
-    destroy_ssl(ssock);
-
-    if (ssock->asock) {
-	pj_activesock_close(ssock->asock);
-	ssock->asock = NULL;
-	ssock->sock = PJ_INVALID_SOCKET;
-    }
-    if (ssock->sock != PJ_INVALID_SOCKET) {
-	pj_sock_close(ssock->sock);
-	ssock->sock = PJ_INVALID_SOCKET;
-    }
+    pj_lock_release(ssock->write_mutex);
+
+    close_sockets(ssock);
 
     /* Upon error, OpenSSL may leave any error description in the thread 
@@ -837,5 +924,7 @@
 static pj_status_t set_cipher_list(pj_ssl_sock_t *ssock)
 {
-    char buf[1024];
+    pj_pool_t *tmp_pool = NULL;
+    char *buf = NULL;
+    enum { BUF_SIZE = 8192 };
     pj_str_t cipher_list;
     STACK_OF(SSL_CIPHER) *sk_cipher;
@@ -851,4 +940,12 @@
 	return PJ_SUCCESS;
     }
+
+    /* Create temporary pool. */
+    tmp_pool = pj_pool_create(ssock->pool->factory, "ciphpool", BUF_SIZE, 
+			      BUF_SIZE/2 , NULL);
+    if (!tmp_pool)
+	return PJ_ENOMEM;
+
+    buf = (char *)pj_pool_zalloc(tmp_pool, BUF_SIZE);
 
     pj_strset(&cipher_list, buf, 0);
@@ -872,5 +969,5 @@
 		/* Check buffer size */
 		if (cipher_list.slen + pj_ansi_strlen(c_name) + 2 >
-		    sizeof(buf))
+		    BUF_SIZE)
 		{
 		    pj_assert(!"Insufficient temporary buffer for cipher");
@@ -895,10 +992,99 @@
     ret = SSL_set_cipher_list(ssock->ossl_ssl, buf);
     if (ret < 1) {
+	pj_pool_release(tmp_pool);
 	return GET_SSL_STATUS(ssock);
     }
 
+    pj_pool_release(tmp_pool);
     return PJ_SUCCESS;
 }
 
+static pj_status_t set_curves_list(pj_ssl_sock_t *ssock)
+{
+#if defined(PJ_SSL_SOCK_OSSL_HAS_EC) && PJ_SSL_SOCK_OSSL_HAS_EC==1
+    int ret;
+    int curves[PJ_SSL_SOCK_MAX_CURVES];
+    int cnt;
+
+    if (ssock->param.curves_num == 0)
+	return PJ_SUCCESS;
+
+    for (cnt = 0; cnt < ssock->param.curves_num; cnt++) {
+	curves[cnt] = tls1_ec_curve_id2nid(ssock->param.curves[cnt]);
+    }
+
+    if( ssock->ossl_ssl->server ) {
+	ret = SSL_set1_curves(ssock->ossl_ssl, curves,
+			      ssock->param.curves_num);
+	if (ret < 1)
+	    return GET_SSL_STATUS(ssock);
+    } else {
+	ret = SSL_CTX_set1_curves(ssock->ossl_ctx, curves,
+				  ssock->param.curves_num);
+	if (ret < 1)
+	    return GET_SSL_STATUS(ssock);
+    }
+#else
+    PJ_UNUSED_ARG(ssock);
+#endif
+
+    return PJ_SUCCESS;
+}
+
+static pj_status_t set_sigalgs(pj_ssl_sock_t *ssock)
+{
+#if defined(PJ_SSL_SOCK_OSSL_HAS_SIGALG) && PJ_SSL_SOCK_OSSL_HAS_SIGALG==1
+    int ret;
+
+    if (ssock->param.sigalgs.ptr && ssock->param.sigalgs.slen) {
+	if (ssock->is_server) {
+	    ret = SSL_set1_client_sigalgs_list(ssock->ossl_ssl,
+	    				       ssock->param.sigalgs.ptr);
+	} else {
+	    ret = SSL_set1_sigalgs_list(ssock->ossl_ssl,
+	    				ssock->param.sigalgs.ptr);
+	}
+
+	if (ret < 1)
+	    return GET_SSL_STATUS(ssock);
+    }
+#else
+    PJ_UNUSED_ARG(ssock);
+#endif
+
+    return PJ_SUCCESS;
+}
+
+static void set_entropy(pj_ssl_sock_t *ssock)
+{
+    int ret;
+
+    switch (ssock->param.entropy_type) {
+#ifndef OPENSSL_NO_EGD
+	case PJ_SSL_ENTROPY_EGD:
+	    ret = RAND_egd(ssock->param.entropy_path.ptr);
+	    break;
+#endif
+	case PJ_SSL_ENTROPY_RANDOM:
+	    ret = RAND_load_file("/dev/random",255);
+	    break;
+	case PJ_SSL_ENTROPY_URANDOM:
+	    ret = RAND_load_file("/dev/urandom",255);
+	    break;
+	case PJ_SSL_ENTROPY_FILE:
+	    ret = RAND_load_file(ssock->param.entropy_path.ptr,255);
+	    break;
+	case PJ_SSL_ENTROPY_NONE:
+	    default:
+	    return;
+	    break;
+    }
+
+    if (ret < 0) {
+	PJ_LOG(3, (ssock->pool->obj_name, "SSL failed to reseed with "
+					  "entropy type %d",
+			  		  ssock->param.entropy_type));
+    }
+}
 
 /* Parse OpenSSL ASN1_TIME to pj_time_val and GMT info */
@@ -965,5 +1151,5 @@
     char *p, *q;
 
-    pj_bzero(cn, sizeof(cn));
+    pj_bzero(cn, sizeof(pj_str_t));
 
     p = pj_strstr(gen_name, &CN_sign);
@@ -983,10 +1169,11 @@
  * to be updated by inspecting the issuer and the serial number.
  */
-static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci, X509 *x)
+static void get_cert_info(pj_pool_t *pool, pj_ssl_cert_info *ci, X509 *x,
+			  pj_bool_t get_pem)
 {
     pj_bool_t update_needed;
     char buf[512];
     pj_uint8_t serial_no[64] = {0}; /* should be >= sizeof(ci->serial_no) */
-    pj_uint8_t *p;
+    pj_uint8_t *q;
     unsigned len;
     GENERAL_NAMES *names = NULL;
@@ -998,9 +1185,9 @@
 
     /* Get serial no */
-    p = (pj_uint8_t*) M_ASN1_STRING_data(X509_get_serialNumber(x));
+    q = (pj_uint8_t*) M_ASN1_STRING_data(X509_get_serialNumber(x));
     len = M_ASN1_STRING_length(X509_get_serialNumber(x));
     if (len > sizeof(ci->serial_no)) 
 	len = sizeof(ci->serial_no);
-    pj_memcpy(serial_no + sizeof(ci->serial_no) - len, p, len);
+    pj_memcpy(serial_no + sizeof(ci->serial_no) - len, q, len);
 
     /* Check if the contents need to be updated. */
@@ -1096,4 +1283,22 @@
         }
     }
+
+    if (get_pem) {
+	/* Update raw Certificate info in PEM format. */
+	BIO *bio;	
+	BUF_MEM *ptr;
+	
+	bio = BIO_new(BIO_s_mem());
+	if (!PEM_write_bio_X509(bio, x)) {
+	    PJ_LOG(3,(THIS_FILE, "Error retrieving raw certificate info"));
+	    ci->raw.ptr = NULL;
+	    ci->raw.slen = 0;
+	} else {
+	    BIO_write(bio, "\0", 1);
+	    BIO_get_mem_ptr(bio, &ptr);
+	    pj_strdup2(pool, &ci->raw, ptr->data);	
+	}	
+	BIO_free(bio);	    
+    }	 
 }
 
@@ -1111,5 +1316,5 @@
     x = SSL_get_certificate(ssock->ossl_ssl);
     if (x) {
-	get_cert_info(ssock->pool, &ssock->local_cert_info, x);
+	get_cert_info(ssock->pool, &ssock->local_cert_info, x, PJ_FALSE);
 	/* Don't free local's X509! */
     } else {
@@ -1120,5 +1325,5 @@
     x = SSL_get_peer_certificate(ssock->ossl_ssl);
     if (x) {
-	get_cert_info(ssock->pool, &ssock->remote_cert_info, x);
+	get_cert_info(ssock->pool, &ssock->remote_cert_info, x, PJ_TRUE);
 	/* Free peer's X509 */
 	X509_free(x);
@@ -1161,11 +1366,21 @@
 		      errmsg));
 
-	    /* Workaround for ticket #985 */
-#if (defined(PJ_WIN32) && PJ_WIN32!=0) || (defined(PJ_WIN64) && PJ_WIN64!=0)
+	    /* Originally, this is a workaround for ticket #985. However,
+	     * a race condition may occur in multiple worker threads
+	     * environment when we are destroying SSL objects while other
+	     * threads are still accessing them.
+	     * Please see ticket #1930 for more info.
+	     */
+#if 1 //(defined(PJ_WIN32) && PJ_WIN32!=0)||(defined(PJ_WIN64) && PJ_WIN64!=0)
 	    if (ssock->param.timer_heap) {
-		pj_time_val interval = {0, DELAYED_CLOSE_TIMEOUT};
-
-		reset_ssl_sock_state(ssock);
-
+		pj_time_val interval = {0, PJ_SSL_SOCK_DELAYED_CLOSE_TIMEOUT};
+
+		ssock->ssl_state = SSL_STATE_NULL;
+		close_sockets(ssock);
+
+		if (ssock->timer.id != TIMER_NONE) {
+		    pj_timer_heap_cancel(ssock->param.timer_heap,
+					 &ssock->timer);
+		}
 		ssock->timer.id = TIMER_CLOSE;
 		pj_time_val_normalize(&interval);
@@ -1173,12 +1388,18 @@
 					   &ssock->timer, &interval) != 0)
 		{
+	    	    PJ_LOG(3,(ssock->pool->obj_name, "Failed to schedule "
+		      	      "a delayed close. Race condition may occur."));
 		    ssock->timer.id = TIMER_NONE;
 		    pj_ssl_sock_close(ssock);
 		}
-	    } else 
-#endif	/* PJ_WIN32 */
+	    } else {
+		pj_ssl_sock_close(ssock);
+	    }
+#else
 	    {
 		pj_ssl_sock_close(ssock);
 	    }
+#endif
+
 	    return PJ_FALSE;
 	}
@@ -1542,4 +1763,19 @@
 }
 
+static void ssl_on_destroy(void *arg)
+{
+    pj_pool_t *pool = NULL;
+    pj_ssl_sock_t *ssock = (pj_ssl_sock_t*)arg;
+
+    destroy_ssl(ssock);
+
+    pj_lock_destroy(ssock->write_mutex);
+
+    pool = ssock->pool;
+    ssock->pool = NULL;
+    if (pool)
+	pj_pool_release(pool);
+}
+
 
 /*
@@ -1758,9 +1994,7 @@
     pj_status_t status;
 
-    PJ_UNUSED_ARG(src_addr_len);
-
     /* Create new SSL socket instance */
-    status = pj_ssl_sock_create(ssock_parent->pool, &ssock_parent->param,
-				&ssock);
+    status = pj_ssl_sock_create(ssock_parent->pool,
+				&ssock_parent->newsock_param, &ssock);
     if (status != PJ_SUCCESS)
 	goto on_return;
@@ -1838,10 +2072,8 @@
 	    goto on_return;
 
-	/* Temporarily add ref the group lock until active socket creation,
-	 * to make sure that group lock is destroyed if the active socket
-	 * creation fails.
-	 */
 	pj_grp_lock_add_ref(glock);
 	asock_cfg.grp_lock = ssock->param.grp_lock = glock;
+	pj_grp_lock_add_handler(ssock->param.grp_lock, ssock->pool, ssock,
+				ssl_on_destroy);
     }
 
@@ -1858,9 +2090,4 @@
 				  ssock,
 				  &ssock->asock);
-
-    /* This will destroy the group lock if active socket creation fails */
-    if (asock_cfg.grp_lock) {
-	pj_grp_lock_dec_ref(asock_cfg.grp_lock);
-    }
 
     if (status != PJ_SUCCESS)
@@ -1893,6 +2120,8 @@
 				        &ssock->timer,
 					&ssock->param.timeout);
-	if (status != PJ_SUCCESS)
+	if (status != PJ_SUCCESS) {
 	    ssock->timer.id = TIMER_NONE;
+	    status = PJ_SUCCESS;
+	}
     }
 
@@ -1903,6 +2132,7 @@
 
 on_return:
-    if (ssock && status != PJ_EPENDING)
+    if (ssock && status != PJ_EPENDING) {
 	on_handshake_complete(ssock, status);
+    }
 
     /* Must return PJ_TRUE whatever happened, as active socket must 
@@ -2045,5 +2275,5 @@
 
 /* Set SSL socket credentials. */
-PJ_DECL(pj_status_t) pj_ssl_sock_set_certificate(
+PJ_DEF(pj_status_t) pj_ssl_sock_set_certificate(
 					    pj_ssl_sock_t *ssock,
 					    pj_pool_t *pool,
@@ -2055,5 +2285,5 @@
 
     cert_ = PJ_POOL_ZALLOC_T(pool, pj_ssl_cert_t);
-    pj_memcpy(cert_, cert, sizeof(cert));
+    pj_memcpy(cert_, cert, sizeof(pj_ssl_cert_t));
     pj_strdup_with_null(pool, &cert_->CA_file, &cert->CA_file);
     pj_strdup_with_null(pool, &cert_->CA_path, &cert->CA_path);
@@ -2149,4 +2379,83 @@
 }
 
+/* Get available curves. */
+PJ_DEF(pj_status_t) pj_ssl_curve_get_availables(pj_ssl_curve curves[],
+						unsigned *curve_num)
+{
+    unsigned i;
+
+    PJ_ASSERT_RETURN(curves && curve_num, PJ_EINVAL);
+
+    if (openssl_curves_num == 0) {
+	init_openssl();
+	shutdown_openssl();
+    }
+
+    if (openssl_curves_num == 0) {
+	*curve_num = 0;
+	return PJ_ENOTFOUND;
+    }
+
+    *curve_num = PJ_MIN(*curve_num, openssl_curves_num);
+
+    for (i = 0; i < *curve_num; ++i)
+	curves[i] = openssl_curves[i].id;
+
+    return PJ_SUCCESS;
+}
+
+/* Get curve name string. */
+PJ_DEF(const char*) pj_ssl_curve_name(pj_ssl_curve curve)
+{
+    unsigned i;
+
+    if (openssl_curves_num == 0) {
+	init_openssl();
+	shutdown_openssl();
+    }
+
+    for (i = 0; i < openssl_curves_num; ++i) {
+	if (curve == openssl_curves[i].id)
+	    return openssl_curves[i].name;
+    }
+
+    return NULL;
+}
+
+/* Get curve ID from curve name string. */
+PJ_DEF(pj_ssl_curve) pj_ssl_curve_id(const char *curve_name)
+{
+    unsigned i;
+
+    if (openssl_curves_num == 0) {
+        init_openssl();
+        shutdown_openssl();
+    }
+
+    for (i = 0; i < openssl_curves_num; ++i) {
+        if (!pj_ansi_stricmp(openssl_curves[i].name, curve_name))
+            return openssl_curves[i].id;
+    }
+
+    return PJ_TLS_UNKNOWN_CURVE;
+}
+
+/* Check if the specified curve is supported by SSL/TLS backend. */
+PJ_DEF(pj_bool_t) pj_ssl_curve_is_supported(pj_ssl_curve curve)
+{
+    unsigned i;
+
+    if (openssl_curves_num == 0) {
+	init_openssl();
+	shutdown_openssl();
+    }
+
+    for (i = 0; i < openssl_curves_num; ++i) {
+	if (curve == openssl_curves[i].id)
+	    return PJ_TRUE;
+    }
+
+    return PJ_FALSE;
+}
 
 /*
@@ -2180,22 +2489,25 @@
     status = pj_lock_create_recursive_mutex(pool, pool->obj_name,
 					    &ssock->write_mutex);
-    if (status != PJ_SUCCESS)
+    if (status != PJ_SUCCESS) {
+	pj_pool_release(pool);
 	return status;
+    }
 
     /* Init secure socket param */
-    ssock->param = *param;
+    pj_ssl_sock_param_copy(pool, &ssock->param, param);
+
+    if (ssock->param.grp_lock) {
+	pj_grp_lock_add_ref(ssock->param.grp_lock);
+	pj_grp_lock_add_handler(ssock->param.grp_lock, pool, ssock,
+				ssl_on_destroy);
+    }
+
     ssock->param.read_buffer_size = ((ssock->param.read_buffer_size+7)>>3)<<3;
-    if (param->ciphers_num > 0) {
-	unsigned i;
-	ssock->param.ciphers = (pj_ssl_cipher*)
-			       pj_pool_calloc(pool, param->ciphers_num, 
-					      sizeof(pj_ssl_cipher));
-	for (i = 0; i < param->ciphers_num; ++i)
-	    ssock->param.ciphers[i] = param->ciphers[i];
-    }
-
-    /* Server name must be null-terminated */
-    pj_strdup_with_null(pool, &ssock->param.server_name, 
-			&param->server_name);
+    if (!ssock->param.timer_heap) {
+	PJ_LOG(3,(ssock->pool->obj_name, "Warning: timer heap is not "
+		  "available. It is recommended to supply one to avoid "
+	          "a race condition if more than one worker threads "
+	          "are used."));
+    }
 
     /* Finally */
@@ -2212,6 +2524,4 @@
 PJ_DEF(pj_status_t) pj_ssl_sock_close(pj_ssl_sock_t *ssock)
 {
-    pj_pool_t *pool;
-
     PJ_ASSERT_RETURN(ssock, PJ_EINVAL);
 
@@ -2225,10 +2535,9 @@
 
     reset_ssl_sock_state(ssock);
-    pj_lock_destroy(ssock->write_mutex);
-    
-    pool = ssock->pool;
-    ssock->pool = NULL;
-    if (pool)
-	pj_pool_release(pool);
+    if (ssock->param.grp_lock) {
+	pj_grp_lock_dec_ref(ssock->param.grp_lock);
+    } else {
+	ssl_on_destroy(ssock);
+    }
 
     return PJ_SUCCESS;
@@ -2618,4 +2927,20 @@
 					      int addr_len)
 {
+    return pj_ssl_sock_start_accept2(ssock, pool, localaddr, addr_len,
+    				     &ssock->param);
+}
+
+
+/**
+ * Same as #pj_ssl_sock_start_accept(), but application provides parameter
+ * for new accepted secure sockets.
+ */
+PJ_DEF(pj_status_t)
+pj_ssl_sock_start_accept2(pj_ssl_sock_t *ssock,
+			  pj_pool_t *pool,
+			  const pj_sockaddr_t *localaddr,
+			  int addr_len,
+			  const pj_ssl_sock_param *newsock_param)
+{
     pj_activesock_cb asock_cb;
     pj_activesock_cfg asock_cfg;
@@ -2623,4 +2948,12 @@
 
     PJ_ASSERT_RETURN(ssock && pool && localaddr && addr_len, PJ_EINVAL);
+
+    /* Verify new socket parameters */
+    if (newsock_param->grp_lock != ssock->param.grp_lock ||
+        newsock_param->sock_af != ssock->param.sock_af ||
+        newsock_param->sock_type != ssock->param.sock_type)
+    {
+        return PJ_EINVAL;
+    }
 
     /* Create socket */
@@ -2692,4 +3025,6 @@
 
     /* Start accepting */
+    pj_ssl_sock_param_copy(pool, &ssock->newsock_param, newsock_param);
+    ssock->newsock_param.grp_lock = NULL;
     status = pj_activesock_start_accept(ssock->asock, pool);
     if (status != PJ_SUCCESS)
@@ -2716,5 +3051,5 @@
  * Starts asynchronous socket connect() operation.
  */
-PJ_DECL(pj_status_t) pj_ssl_sock_start_connect(pj_ssl_sock_t *ssock,
+PJ_DEF(pj_status_t) pj_ssl_sock_start_connect( pj_ssl_sock_t *ssock,
 					       pj_pool_t *pool,
 					       const pj_sockaddr_t *localaddr,
@@ -2792,6 +3127,8 @@
 					&ssock->timer,
 				        &ssock->param.timeout);
-	if (status != PJ_SUCCESS)
+	if (status != PJ_SUCCESS) {
 	    ssock->timer.id = TIMER_NONE;
+	    status = PJ_SUCCESS;
+	}
     }
 
