Index: pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c
===================================================================
--- pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c	(revision 2985)
+++ pjproject/trunk/pjlib/src/pj/ssl_sock_ossl.c	(revision 2986)
@@ -193,14 +193,12 @@
 					 PJ_ERRNO_SPACE_SIZE*6)
 
-#define PJ_SSL_ERRNO_SPACE_SIZE		5000
-
-#define PJ_STATUS_FROM_OSSL(ossl_err)	(ossl_err == SSL_ERROR_NONE? \
-					 PJ_SUCCESS : \
-					 (PJ_SSL_ERRNO_START + ossl_err))
-
-#define PJ_STATUS_TO_OSSL(status)	(status == PJ_SUCCESS? \
-					 SSL_ERROR_NONE : \
-					(status - PJ_SSL_ERRNO_START))
-
+#define PJ_SSL_ERRNO_SPACE_SIZE		PJ_ERRNO_SPACE_SIZE
+
+#define GET_SSL_STATUS(status) { \
+    unsigned long e = ERR_get_error();\
+    status = ERR_GET_LIB(e)*300 + ERR_GET_REASON(e);\
+    pj_assert(status < PJ_SSL_ERRNO_SPACE_SIZE);\
+    if (status) status += PJ_SSL_ERRNO_START;\
+}
 
 /*
@@ -211,12 +209,28 @@
 {
     pj_str_t errstr;
-    unsigned long ssl_err = PJ_STATUS_TO_OSSL(status);
+    unsigned long ssl_err = status;
+
+    if (ssl_err) {
+	unsigned long l, r;
+	ssl_err -= PJ_SSL_ERRNO_START;
+	l = ssl_err/300;
+	r = ssl_err%300;
+	ssl_err = ERR_PACK(l, 0, r);
+    }
 
 #if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)
 
-    ERR_error_string_n(ssl_err, buf, bufsize);
-    errstr = pj_str(buf);
-
-#else
+    {
+	const char *tmp = NULL;
+	tmp = ERR_reason_error_string(ssl_err);
+
+	if (tmp) {
+	    pj_ansi_strncpy(buf, tmp, bufsize);
+	    errstr = pj_str(buf);
+	    return errstr;
+	}
+    }
+
+#endif	/* PJ_HAS_ERROR_STRING */
 
     errstr.ptr = buf;
@@ -224,6 +238,4 @@
 				   "Unknown OpenSSL error %d",
 				   ssl_err);
-
-#endif	/* PJ_HAS_ERROR_STRING */
 
     return errstr;
@@ -337,4 +349,5 @@
     pj_ssl_cert_t *cert;
     int mode, rc;
+    pj_status_t status;
         
     pj_assert(ssock && p_ctx);
@@ -370,6 +383,6 @@
     ctx = SSL_CTX_new(ssl_method);
     if (ctx == NULL) {
-	PJ_LOG(1,(ssock->pool->obj_name, "Error creating OpenSSL context"));
-	return PJ_STATUS_FROM_OSSL(ERR_get_error());
+	GET_SSL_STATUS(status);
+	return status;
     }
 
@@ -382,8 +395,9 @@
 
 	    if (rc != 1) {
+		GET_SSL_STATUS(status);
 		PJ_LOG(1,(ssock->pool->obj_name, "Error loading CA list file "
 			  "'%s'", cert->CA_file.ptr));
 		SSL_CTX_free(ctx);
-		return PJ_STATUS_FROM_OSSL(ERR_get_error());
+		return status;
 	    }
 	}
@@ -403,8 +417,9 @@
 
 	    if(rc != 1) {
+		GET_SSL_STATUS(status);
 		PJ_LOG(1,(ssock->pool->obj_name, "Error loading certificate "
 			  "chain file '%s'", cert->cert_file.ptr));
 		SSL_CTX_free(ctx);
-		return PJ_STATUS_FROM_OSSL(ERR_get_error());
+		return status;
 	    }
 	}
@@ -418,8 +433,9 @@
 
 	    if(rc != 1) {
+		GET_SSL_STATUS(status);
 		PJ_LOG(1,(ssock->pool->obj_name, "Error adding private key "
 			  "from '%s'", cert->privkey_file.ptr));
 		SSL_CTX_free(ctx);
-		return PJ_STATUS_FROM_OSSL(ERR_get_error());
+		return status;
 	    }
 	}
@@ -543,6 +559,9 @@
     /* Finally, set chosen cipher list */
     ret = SSL_set_cipher_list(ssock->ossl_ssl, buf);
-    if (ret < 1)
-	return PJ_STATUS_FROM_OSSL(SSL_get_error(ssock->ossl_ssl, ret));
+    if (ret < 1) {
+	pj_status_t status;
+	GET_SSL_STATUS(status);
+	return status;
+    }
 
     return PJ_SUCCESS;
@@ -688,4 +707,14 @@
 	if (status != PJ_SUCCESS) {
 	    /* Handshake failed in accepting, destroy our self silently. */
+
+	    char errmsg[PJ_ERR_MSG_SIZE];
+	    char buf[PJ_INET6_ADDRSTRLEN+10];
+
+	    pj_strerror(status, errmsg, sizeof(errmsg));
+	    PJ_LOG(3,(ssock->pool->obj_name, "Handshake failed in accepting "
+		      "%s: %s",
+		      pj_sockaddr_print(&ssock->rem_addr, buf, sizeof(buf), 3),
+		      errmsg));
+
 	    pj_ssl_sock_close(ssock);
 	    return PJ_FALSE;
@@ -875,6 +904,7 @@
 	{
 	    /* Handshake fails */
+	    GET_SSL_STATUS(status);
 	    pj_lock_release(ssock->write_mutex);
-	    return PJ_STATUS_FROM_OSSL(err);
+	    return status;
 	}
     }
@@ -922,5 +952,5 @@
 	nwritten = BIO_write(ssock->ossl_rbio, data, size);
 	if (nwritten < size) {
-	    status = PJ_STATUS_FROM_OSSL(ERR_get_error());
+	    GET_SSL_STATUS(status);
 	    goto on_error;
 	}
@@ -995,11 +1025,6 @@
 		if (err != SSL_ERROR_NONE && err != SSL_ERROR_WANT_READ)
 		{
-		    char errmsg[PJ_ERR_MSG_SIZE];
-
-		    pj_strerror(status, errmsg, sizeof(errmsg));
-		    PJ_LOG(1,(ssock->pool->obj_name, "SSL_read() failed: %s",
-			      errmsg));
-
 		    /* Reset SSL socket state, then return PJ_FALSE */
+		    GET_SSL_STATUS(status);
 		    reset_ssl_sock_state(ssock);
 		    goto on_error;
@@ -1018,17 +1043,11 @@
 
 		    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
-			char errmsg[PJ_ERR_MSG_SIZE];
-
-			pj_strerror(status, errmsg, sizeof(errmsg));
-			PJ_LOG(1,(ssock->pool->obj_name, "Failed to flush "
-				  "delayed send: %s", errmsg));
+			pj_perror(1, ssock->pool->obj_name, status, 
+				  "Failed to flush delayed send", 0);
 			goto on_error;
 		    }
 		} else if (status != PJ_EPENDING) {
-		    char errmsg[PJ_ERR_MSG_SIZE];
-
-		    pj_strerror(status, errmsg, sizeof(errmsg));
-		    PJ_LOG(1,(ssock->pool->obj_name, "Renegotiation failed: "
-			      "%s", errmsg));
+		    pj_perror(1, ssock->pool->obj_name, status, 
+			      "Renegotiation failed", 0);
 		    goto on_error;
 		}
@@ -1122,10 +1141,6 @@
     unsigned i;
     pj_status_t status;
-    char buf[64];
 
     PJ_UNUSED_ARG(src_addr_len);
-
-    PJ_LOG(4,(ssock_parent->pool->obj_name, "Incoming connection from %s",
-	      pj_sockaddr_print(src_addr, buf, sizeof(buf), 3)));
 
     /* Create new SSL socket instance */
@@ -1150,6 +1165,10 @@
     status = pj_sock_getsockname(ssock->sock, &ssock->local_addr, 
 				 &ssock->addr_len);
-    if (status != PJ_SUCCESS)
-	goto on_return;
+    if (status != PJ_SUCCESS) {
+	/* This fails on few envs, e.g: win IOCP, just tolerate this and
+	 * use parent local address instead.
+	 */
+	pj_sockaddr_cp(&ssock->local_addr, &ssock_parent->local_addr);
+    }
 
     /* Set remote address */
@@ -1164,6 +1183,5 @@
     ssock->ossl_ssl = SSL_new(ssock->ossl_ctx);
     if (ssock->ossl_ssl == NULL) {
-	PJ_LOG(1,(ssock->pool->obj_name, "Error creating SSL instance"));
-	status = PJ_STATUS_FROM_OSSL(ERR_get_error());
+	GET_SSL_STATUS(status);
 	goto on_return;
     }
@@ -1245,11 +1263,13 @@
     SSL_set_accept_state(ssock->ossl_ssl);
     status = do_handshake(ssock);
-    if (status != PJ_EPENDING)
-	goto on_return;
-
+
+on_return:
+    if (ssock && status != PJ_EPENDING)
+	on_handshake_complete(ssock, status);
+
+    /* Must return PJ_TRUE whatever happened, as active socket must 
+     * continue listening.
+     */
     return PJ_TRUE;
-
-on_return:
-    return on_handshake_complete(ssock, status);
 }
 
@@ -1280,6 +1300,5 @@
     ssock->ossl_ssl = SSL_new(ssock->ossl_ctx);
     if (ssock->ossl_ssl == NULL) {
-	PJ_LOG(1,(ssock->pool->obj_name, "Error creating SSL instance"));
-	status = PJ_STATUS_FROM_OSSL(ERR_get_error());
+	GET_SSL_STATUS(status);
 	goto on_return;
     }
@@ -1723,5 +1742,5 @@
 	} else {
 	    /* Some problem occured */
-	    status = PJ_STATUS_FROM_OSSL(err);
+	    GET_SSL_STATUS(status);
 	}
     } else {
@@ -2018,5 +2037,5 @@
     ret = SSL_renegotiate(ssock->ossl_ssl);
     if (ret <= 0) {
-	status = PJ_STATUS_FROM_OSSL(SSL_get_error(ssock->ossl_ssl, ret));
+	GET_SSL_STATUS(status);
     } else {
 	status = do_handshake(ssock);
Index: pjproject/trunk/pjlib/src/pjlib-test/ssl_sock.c
===================================================================
--- pjproject/trunk/pjlib/src/pjlib-test/ssl_sock.c	(revision 2985)
+++ pjproject/trunk/pjlib/src/pjlib-test/ssl_sock.c	(revision 2986)
@@ -151,4 +151,12 @@
     }
 
+    /* Start reading data */
+    read_buf[0] = st->read_buf;
+    status = pj_ssl_sock_start_read2(ssock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
+    if (status != PJ_SUCCESS) {
+	app_perror("...ERROR pj_ssl_sock_start_read2()", status);
+	goto on_return;
+    }
+
     /* Start sending data */
     while (st->sent < st->send_str_len) {
@@ -169,12 +177,4 @@
     }
 
-    /* Start reading data */
-    read_buf[0] = st->read_buf;
-    status = pj_ssl_sock_start_read2(ssock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
-    if (status != PJ_SUCCESS  && status != PJ_EPENDING) {
-	app_perror("...ERROR pj_ssl_sock_start_read2()", status);
-	goto on_return;
-    }
-
 on_return:
     st->err = status;
@@ -196,5 +196,5 @@
 {
     struct test_state *parent_st = (struct test_state*) 
-			    pj_ssl_sock_get_user_data(ssock);
+				   pj_ssl_sock_get_user_data(ssock);
     struct test_state *st;
     void *read_buf[1];
@@ -237,4 +237,12 @@
 	    dump_cert_info(".......", &info.remote_cert_info);
 	}
+    }
+
+    /* Start reading data */
+    read_buf[0] = st->read_buf;
+    status = pj_ssl_sock_start_read2(newsock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
+    if (status != PJ_SUCCESS) {
+	app_perror("...ERROR pj_ssl_sock_start_read2()", status);
+	goto on_return;
     }
 
@@ -255,12 +263,4 @@
 	else
 	    break;
-    }
-
-    /* Start reading data */
-    read_buf[0] = st->read_buf;
-    status = pj_ssl_sock_start_read2(newsock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
-    if (status != PJ_SUCCESS  && status != PJ_EPENDING) {
-	app_perror("...ERROR pj_ssl_sock_start_read2()", status);
-	goto on_return;
     }
 
@@ -422,8 +422,9 @@
 #define HTTP_SERVER_PORT	443
 
-static int https_client_test(void)
+static int https_client_test(unsigned ms_timeout)
 {
     pj_pool_t *pool = NULL;
     pj_ioqueue_t *ioqueue = NULL;
+    pj_timer_heap_t *timer = NULL;
     pj_ssl_sock_t *ssock = NULL;
     pj_ssl_sock_param param;
@@ -436,4 +437,9 @@
 
     status = pj_ioqueue_create(pool, 4, &ioqueue);
+    if (status != PJ_SUCCESS) {
+	goto on_return;
+    }
+
+    status = pj_timer_heap_create(pool, 4, &timer);
     if (status != PJ_SUCCESS) {
 	goto on_return;
@@ -452,4 +458,8 @@
     param.user_data = &state;
     param.server_name = pj_str((char*)HTTP_SERVER_ADDR);
+    param.timer_heap = timer;
+    param.timeout.sec = 0;
+    param.timeout.msec = ms_timeout;
+    pj_time_val_normalize(&param.timeout);
 
     status = pj_ssl_sock_create(pool, &param, &ssock);
@@ -476,4 +486,5 @@
 	pj_time_val delay = {0, 100};
 	pj_ioqueue_poll(ioqueue, &delay);
+	pj_timer_heap_poll(timer, &delay);
 #endif
     }
@@ -492,4 +503,6 @@
     if (ioqueue)
 	pj_ioqueue_destroy(ioqueue);
+    if (timer)
+	pj_timer_heap_destroy(timer);
     if (pool)
 	pj_pool_release(pool);
@@ -633,4 +646,10 @@
     }
 
+    /* Clean up sockets */
+    {
+	pj_time_val delay = {0, 100};
+	while (pj_ioqueue_poll(ioqueue, &delay) > 0);
+    }
+
     if (state_serv.err || state_cli.err) {
 	if (state_serv.err != PJ_SUCCESS)
@@ -683,4 +702,11 @@
     st->err = status;
 
+    if (st->err != PJ_SUCCESS || st->done) {
+	pj_activesock_close(asock);
+	if (!st->is_server)
+	    clients_num--;
+	return PJ_FALSE;
+    }
+
     return PJ_TRUE;
 }
@@ -694,8 +720,22 @@
 
     if (status == PJ_SUCCESS) {
-	status = pj_activesock_start_read(asock, st->pool, 1, 0);
+	void *read_buf[1];
+
+	/* Start reading data */
+	read_buf[0] = st->read_buf;
+	status = pj_activesock_start_read2(asock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
+	if (status != PJ_SUCCESS) {
+	    app_perror("...ERROR pj_ssl_sock_start_read2()", status);
+	}
     }
 
     st->err = status;
+
+    if (st->err != PJ_SUCCESS) {
+	pj_activesock_close(asock);
+	if (!st->is_server)
+	    clients_num--;
+	return PJ_FALSE;
+    }
 
     return PJ_TRUE;
@@ -846,5 +886,5 @@
     if (ssock_serv)
 	pj_ssl_sock_close(ssock_serv);
-    if (asock_cli)
+    if (asock_cli && !state_cli.err && !state_cli.done)
 	pj_activesock_close(asock_cli);
     if (timer)
@@ -859,4 +899,7 @@
 
 
+/* Test will perform multiple clients trying to connect to single server.
+ * Once SSL connection established, echo test will be performed.
+ */
 static int perf_test(unsigned clients, unsigned ms_handshake_timeout)
 {
@@ -1023,4 +1066,10 @@
     }
 
+    /* Clean up sockets */
+    {
+	pj_time_val delay = {0, 500};
+	while (pj_ioqueue_poll(ioqueue, &delay) > 0);
+    }
+
     if (state_serv.err != PJ_SUCCESS) {
 	status = state_serv.err;
@@ -1078,11 +1127,11 @@
 	return ret;
 
-    // Disable this test as requiring internet connection.
-#if 0
     PJ_LOG(3,("", "..https client test"));
-    ret = https_client_test();
-    if (ret != 0)
-	return ret;
-#endif
+    ret = https_client_test(30000);
+    // Ignore test result as internet connection may not be available.
+    //if (ret != 0)
+	//return ret;
+
+#ifndef PJ_SYMBIAN
 
     PJ_LOG(3,("", "..echo test w/ TLSv1 and TLS_RSA_WITH_DES_CBC_SHA cipher"));
@@ -1110,5 +1159,5 @@
 	return PJ_EBUG;
 
-    PJ_LOG(3,("", "..client non-SSL timeout in 5 secs"));
+    PJ_LOG(3,("", "..client non-SSL (handshake timeout 5 secs)"));
     ret = client_non_ssl(5000);
     if (ret != 0)
@@ -1119,4 +1168,6 @@
     if (ret != 0)
 	return ret;
+
+#endif
 
     return 0;
