Index: pjproject/branches/1.x/pjmedia/src/pjmedia/jbuf.c
===================================================================
--- pjproject/branches/1.x/pjmedia/src/pjmedia/jbuf.c	(revision 4003)
+++ pjproject/branches/1.x/pjmedia/src/pjmedia/jbuf.c	(revision 4004)
@@ -167,5 +167,5 @@
  * second.
  */
-#if 1
+#if 0
 #  define TRACE__(args)	    PJ_LOG(5,args)
 #else
@@ -405,7 +405,11 @@
 	if (framelist->origin - index < MAX_MISORDER) {
 	    /* too late */
+	    PJ_LOG(5,(THIS_FILE, "frame too late (origin: %d, index: %d, size: %d, max: %d)",
+				 framelist->origin, index, framelist->size, framelist->max_count));
 	    return PJ_ETOOSMALL;
 	} else {
 	    /* sequence restart */
+	    PJ_LOG(5,(THIS_FILE, "sequence restart (origin: %d, index: %d, size: %d, max: %d)",
+				 framelist->origin, index, framelist->size, framelist->max_count));
 	    framelist->origin = index - framelist->size;
 	}
@@ -425,4 +429,6 @@
 	if (distance > MAX_DROPOUT) {
 	    /* jump too far, reset the buffer */
+	    PJ_LOG(5,(THIS_FILE, "jump too far, resetting (origin: %d, index: %d, size: %d, max: %d)",
+				 framelist->origin, index, framelist->size, framelist->max_count));
 	    jb_framelist_reset(framelist);
 	    framelist->origin = index;
@@ -430,4 +436,6 @@
 	} else {
 	    /* otherwise, reject the frame */
+	    PJ_LOG(5,(THIS_FILE, "frame too far (origin: %d, index: %d, size: %d, max: %d)",
+				 framelist->origin, index, framelist->size, framelist->max_count));
 	    return PJ_ETOOMANY;
 	}
@@ -438,6 +446,9 @@
 
     /* if the slot is occupied, it must be duplicated frame, ignore it. */
-    if (framelist->frame_type[pos] != PJMEDIA_JB_MISSING_FRAME)
+    if (framelist->frame_type[pos] != PJMEDIA_JB_MISSING_FRAME) {
+	PJ_LOG(5,(THIS_FILE, "exists (origin: %d, index: %d, size: %d, max: %d)",
+			      framelist->origin, index, framelist->size, framelist->max_count));
 	return PJ_EEXISTS;
+    }
 
     /* put the frame into the slot */
@@ -518,5 +529,7 @@
     pj_math_stat_init(&jb->jb_burst);
 
-    pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_PROGRESSIVE);
+    //pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_PROGRESSIVE);
+    pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_STATIC);
+    //pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_NONE);
     pjmedia_jbuf_reset(jb);
 
Index: pjproject/branches/1.x/pjsip/src/pjsip/sip_transport_tls_ossl.c
===================================================================
--- pjproject/branches/1.x/pjsip/src/pjsip/sip_transport_tls_ossl.c	(revision 4003)
+++ 	(revision )
@@ -1,2376 +1,0 @@
-/* $Id$ */
-/* 
- * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
- * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
- */
-#include <pjsip/sip_transport_tls.h>
-#include <pjsip/sip_endpoint.h>
-#include <pjsip/sip_errno.h>
-#include <pj/compat/socket.h>
-#include <pj/addr_resolv.h>
-#include <pj/assert.h>
-#include <pj/ioqueue.h>
-#include <pj/lock.h>
-#include <pj/log.h>
-#include <pj/os.h>
-#include <pj/pool.h>
-#include <pj/compat/socket.h>
-#include <pj/sock_select.h>
-#include <pj/string.h>
-
-
-/* Only build when PJSIP_HAS_TLS_TRANSPORT is enabled */
-#if defined(PJSIP_HAS_TLS_TRANSPORT) && PJSIP_HAS_TLS_TRANSPORT!=0
-
-
-
-/* 
- * Include OpenSSL headers 
- */
-#include <openssl/bio.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-
-/*
- * With VisualC++, it's not possible to dynamically link against some
- * libraries when some macros are defined (unlike "make" based build
- * system where this can be easily manipulated).
- *
- * So for VisualC++ IDE, include OpenSSL libraries in the linking by
- * using the #pragma lib construct below.
- */
-#ifdef _MSC_VER
-# ifdef _DEBUG
-#  pragma comment( lib, "libeay32MTd")
-#  pragma comment( lib, "ssleay32MTd")
-#else
-#  pragma comment( lib, "libeay32MT")
-#  pragma comment( lib, "ssleay32MT")
-# endif
-#endif
-
-
-#define THIS_FILE	"transport_tls_ossl.c"
-
-#define MAX_ASYNC_CNT	16
-#define POOL_LIS_INIT	512
-#define POOL_LIS_INC	512
-#define POOL_TP_INIT	512
-#define POOL_TP_INC	512
-
-
-
-/**
- * Get the number of descriptors in the set. This is defined in sock_select.c
- * This function will only return the number of sockets set from PJ_FD_SET
- * operation. When the set is modified by other means (such as by select()),
- * the count will not be reflected here.
- *
- * That's why don't export this function in the header file, to avoid
- * misunderstanding.
- *
- * @param fdsetp    The descriptor set.
- *
- * @return          Number of descriptors in the set.
- */
-PJ_DECL(pj_size_t) PJ_FD_COUNT(const pj_fd_set_t *fdsetp);
-
-
-
-struct tls_listener;
-struct tls_transport;
-
-
-/*
- * This structure is "descendant" of pj_ioqueue_op_key_t, and it is used to
- * track pending/asynchronous accept() operation. TLS transport may have
- * more than one pending accept() operations, depending on the value of
- * async_cnt.
- */
-struct pending_accept
-{
-    pj_ioqueue_op_key_t	     op_key;
-    struct tls_listener	    *listener;
-    unsigned		     index;
-    pj_pool_t		    *pool;
-    pj_sock_t		     new_sock;
-    int			     addr_len;
-    pj_sockaddr_in	     local_addr;
-    pj_sockaddr_in	     remote_addr;
-};
-
-
-/*
- * This is the TLS listener, which is a "descendant" of pjsip_tpfactory (the
- * SIP transport factory).
- */
-struct tls_listener
-{
-    pjsip_tpfactory	     factory;
-    pj_bool_t		     is_registered;
-    pjsip_tls_setting	     setting;
-    pjsip_endpoint	    *endpt;
-    pjsip_tpmgr		    *tpmgr;
-    pj_sock_t		     sock;
-    pj_ioqueue_key_t	    *key;
-    unsigned		     async_cnt;
-    struct pending_accept   *accept_op[MAX_ASYNC_CNT];
-
-    SSL_CTX		    *ctx;
-};
-
-
-/*
- * This structure is used to keep delayed transmit operation in a list.
- * A delayed transmission occurs when application sends tx_data when
- * the TLS connect/establishment is still in progress. These delayed
- * transmission will be "flushed" once the socket is connected (either
- * successfully or with errors).
- */
-struct delayed_tdata
-{
-    PJ_DECL_LIST_MEMBER(struct delayed_tdata);
-    pjsip_tx_data_op_key    *tdata_op_key;
-};
-
-
-/*
- * This structure describes the TLS transport, and it's descendant of
- * pjsip_transport.
- */
-struct tls_transport
-{
-    pjsip_transport	     base;
-    pj_bool_t		     is_server;
-
-    /* Do not save listener instance in the transport, because
-     * listener might be destroyed during transport's lifetime.
-     * See http://trac.pjsip.org/repos/ticket/491
-    struct tls_listener	    *listener;
-     */
-
-    /* TLS settings, copied from listener */
-    struct {
-	pj_str_t	     server_name;
-	pj_time_val	     timeout;
-    } setting;
-
-    pj_bool_t		     is_registered;
-    pj_bool_t		     is_closing;
-    pj_status_t		     close_reason;
-    pj_sock_t		     sock;
-    pj_ioqueue_key_t	    *key;
-    pj_bool_t		     has_pending_connect;
-
-    /* SSL connection */
-    SSL			    *ssl;
-    pj_bool_t		     ssl_shutdown_called;
-
-    /* Keep alive */
-    pj_timer_entry	     ka_timer;
-    pj_time_val		     last_activity;
-
-    /* TLS transport can only have  one rdata!
-     * Otherwise chunks of incoming PDU may be received on different
-     * buffer.
-     */
-    pjsip_rx_data	     rdata;
-
-    /* Pending transmission list. */
-    struct delayed_tdata     delayed_list;
-};
-
-
-/****************************************************************************
- * PROTOTYPES
- */
-
-/* This callback is called when pending accept() operation completes. */
-static void on_accept_complete(	pj_ioqueue_key_t *key, 
-				pj_ioqueue_op_key_t *op_key, 
-				pj_sock_t sock, 
-				pj_status_t status);
-
-/* This callback is called by transport manager to destroy listener */
-static pj_status_t lis_destroy(pjsip_tpfactory *factory);
-
-/* This callback is called by transport manager to create transport */
-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_transport **transport);
-
-/* Common function to create and initialize transport */
-static pj_status_t tls_create(struct tls_listener *listener,
-			      pj_pool_t *pool,
-			      pj_sock_t sock, pj_bool_t is_server,
-			      const pj_sockaddr_in *local,
-			      const pj_sockaddr_in *remote,
-			      struct tls_transport **p_tls);
-
-
-/****************************************************************************
- * SSL FUNCTIONS
- */
-
-/* ssl_report_error() */
-static void ssl_report_error(const char *sender, int level, 
-			     pj_status_t status,
-			     const char *format, ...)
-{
-    va_list marker;
-
-    va_start(marker, format);
-
-#if PJ_LOG_MAX_LEVEL > 0
-    if (status != PJ_SUCCESS) {
-	char err_format[PJ_ERR_MSG_SIZE + 512];
-	int len;
-
-	len = pj_ansi_snprintf(err_format, sizeof(err_format),
-			       "%s: ", format);
-	pj_strerror(status, err_format+len, sizeof(err_format)-len);
-	
-	pj_log(sender, level, err_format, marker);
-
-    } else {
-	unsigned long ssl_err;
-
-	ssl_err = ERR_get_error();
-
-	if (ssl_err == 0) {
-	    pj_log(sender, level, format, marker);
-	} else {
-	    char err_format[512];
-	    int len;
-
-	    len = pj_ansi_snprintf(err_format, sizeof(err_format),
-				   "%s: ", format);
-	    ERR_error_string(ssl_err, err_format+len);
-	    
-	    pj_log(sender, level, err_format, marker);
-	}
-    }
-#endif
-
-    va_end(marker);
-}
-
-
-static void sockaddr_to_host_port( pj_pool_t *pool,
-				   pjsip_host_port *host_port,
-				   const pj_sockaddr_in *addr )
-{
-    enum { M = 48 };
-    host_port->host.ptr = (char*)pj_pool_alloc(pool, M);
-    host_port->host.slen = pj_ansi_snprintf( host_port->host.ptr, M, "%s", 
-					    pj_inet_ntoa(addr->sin_addr));
-    host_port->port = pj_ntohs(addr->sin_port);
-}
-
-
-/* SSL password callback. */
-static int password_cb(char *buf, int num, int rwflag, void *user_data)
-{
-    struct tls_listener *lis = (struct tls_listener*) user_data;
-
-    PJ_UNUSED_ARG(rwflag);
-
-    if(num < lis->setting.password.slen+1)
-	return 0;
-    
-    pj_memcpy(buf, lis->setting.password.ptr, lis->setting.password.slen);
-    return lis->setting.password.slen;
-}
-
-
-/* OpenSSL library initialization counter */
-static int openssl_init_count;
-
-/* Initialize OpenSSL */
-static pj_status_t init_openssl(void)
-{
-    if (++openssl_init_count != 1)
-	return PJ_SUCCESS;
-
-    SSL_library_init();
-    SSL_load_error_strings();
-    OpenSSL_add_all_algorithms();
-
-    return PJ_SUCCESS;
-}
-
-/* Shutdown OpenSSL */
-static void shutdown_openssl(void)
-{
-    if (--openssl_init_count != 0)
-	return;
-}
-
-
-/* Create and initialize new SSL context */
-static pj_status_t create_ctx( struct tls_listener *lis, SSL_CTX **p_ctx)
-{
-    struct pjsip_tls_setting *opt = &lis->setting;
-    int method;
-    char *lis_name = lis->factory.obj_name;
-    SSL_METHOD *ssl_method;
-    SSL_CTX *ctx;
-    int mode, rc;
-        
-    *p_ctx = NULL;
-
-    /* Make sure OpenSSL library has been initialized */
-    init_openssl();
-
-    /* Determine SSL method to use */
-    method = opt->method;
-    if (method == PJSIP_SSL_UNSPECIFIED_METHOD)
-	method = PJSIP_SSL_DEFAULT_METHOD;
-
-    switch (method) {
-    case PJSIP_SSLV23_METHOD:
-	ssl_method = SSLv23_method();
-	break;
-    case PJSIP_TLSV1_METHOD:
-	ssl_method = TLSv1_method();
-	break;
-    case PJSIP_SSLV2_METHOD:
-	ssl_method = SSLv2_method();
-	break;
-    case PJSIP_SSLV3_METHOD:
-	ssl_method = SSLv3_method();
-	break;
-    default:
-	ssl_report_error(lis_name, 4, PJSIP_TLS_EINVMETHOD,
-			 "Error creating SSL context");
-	return PJSIP_TLS_EINVMETHOD;
-    }
-
-    /* Create SSL context for the listener */
-    ctx = SSL_CTX_new(ssl_method);
-    if (ctx == NULL) {
-	ssl_report_error(lis_name, 4, PJ_SUCCESS,
-			 "Error creating SSL context");
-	return PJSIP_TLS_ECTX;
-    }
-
-
-    /* Load CA list if one is specified. */
-    if (opt->ca_list_file.slen) {
-
-	/* Can only take a NULL terminated filename in the setting */
-	pj_assert(opt->ca_list_file.ptr[opt->ca_list_file.slen] == '\0');
-
-	rc = SSL_CTX_load_verify_locations(ctx, opt->ca_list_file.ptr, NULL);
-
-	if (rc != 1) {
-	    ssl_report_error(lis_name, 4, PJ_SUCCESS,
-			     "Error loading/verifying CA list file '%.*s'",
-			     (int)opt->ca_list_file.slen,
-			     opt->ca_list_file.ptr);
-	    SSL_CTX_free(ctx);
-	    return PJSIP_TLS_ECACERT;
-	}
-
-	PJ_LOG(5,(lis_name, "TLS CA file successfully loaded from '%.*s'",
-		  (int)opt->ca_list_file.slen,
-		  opt->ca_list_file.ptr));
-    }
-    
-    /* Set password callback */
-    SSL_CTX_set_default_passwd_cb(ctx, password_cb);
-    SSL_CTX_set_default_passwd_cb_userdata(ctx, lis);
-
-
-    /* Load certificate if one is specified */
-    if (opt->cert_file.slen) {
-
-	/* Can only take a NULL terminated filename in the setting */
-	pj_assert(opt->cert_file.ptr[opt->cert_file.slen] == '\0');
-
-	/* Load certificate chain from file into ctx */
-	rc = SSL_CTX_use_certificate_chain_file(ctx, opt->cert_file.ptr);
-
-	if(rc != 1) {
-	    ssl_report_error(lis_name, 4, PJ_SUCCESS,
-			     "Error loading certificate chain file '%.*s'",
-			     (int)opt->cert_file.slen,
-			     opt->cert_file.ptr);
-	    SSL_CTX_free(ctx);
-	    return PJSIP_TLS_ECERTFILE;
-	}
-
-	PJ_LOG(5,(lis_name, "TLS certificate successfully loaded from '%.*s'",
-		  (int)opt->cert_file.slen,
-		  opt->cert_file.ptr));
-    }
-
-
-    /* Load private key if one is specified */
-    if (opt->privkey_file.slen) {
-
-	/* Can only take a NULL terminated filename in the setting */
-	pj_assert(opt->privkey_file.ptr[opt->privkey_file.slen] == '\0');
-
-	/* Adds the first private key found in file to ctx */
-	rc = SSL_CTX_use_PrivateKey_file(ctx, opt->privkey_file.ptr, 
-					 SSL_FILETYPE_PEM);
-
-	if(rc != 1) {
-	    ssl_report_error(lis_name, 4, PJ_SUCCESS,
-			     "Error adding private key from '%.*s'",
-			     (int)opt->privkey_file.slen,
-			     opt->privkey_file.ptr);
-	    SSL_CTX_free(ctx);
-	    return PJSIP_TLS_EKEYFILE;
-	}
-
-	PJ_LOG(5,(lis_name, "TLS private key successfully loaded from '%.*s'",
-		  (int)opt->privkey_file.slen,
-		  opt->privkey_file.ptr));
-    }
-
-
-    /* SSL verification options */
-    if (lis->setting.verify_client || lis->setting.verify_server) {
-	mode = SSL_VERIFY_PEER;
-	if (lis->setting.require_client_cert)
-	    mode |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
-    } else {
-	mode = SSL_VERIFY_NONE;
-    }
-
-    SSL_CTX_set_verify(ctx, mode, NULL);
-
-    PJ_LOG(5,(lis_name, "TLS verification mode set to %d", mode));
-
-    /* Optionally set cipher list if one is specified */
-    if (opt->ciphers.slen) {
-	/* Can only take a NULL terminated cipher list in the setting */
-	pj_assert(opt->cert_file.ptr[opt->cert_file.slen] == '\0');
-
-	rc = SSL_CTX_set_cipher_list(ctx, opt->ciphers.ptr);
-	if (rc != 1) {
-	    ssl_report_error(lis_name, 4, PJ_SUCCESS,
-			     "Error setting cipher list '%.*s'",
-			     (int)opt->ciphers.slen,
-			     opt->ciphers.ptr);
-	    SSL_CTX_free(ctx);
-	    return PJSIP_TLS_ECIPHER;
-	}
-
-	PJ_LOG(5,(lis_name, "TLS ciphers set to '%.*s'",
-		  (int)opt->ciphers.slen,
-		  opt->ciphers.ptr));
-    }
-
-    /* Done! */
-
-    *p_ctx = ctx;
-    return PJ_SUCCESS;
-}
-
-/* Destroy SSL context */
-static void destroy_ctx(SSL_CTX *ctx)
-{
-    SSL_CTX_free(ctx);
-
-    /* Potentially shutdown OpenSSL library if this is the last
-     * context exists.
-     */
-    shutdown_openssl();
-}
-
-/*
- * Perform SSL_connect upon completion of socket connect()
- */
-static pj_status_t ssl_connect(struct tls_transport *tls)
-{
-    SSL *ssl = tls->ssl;
-    int status;
-
-    if (SSL_is_init_finished (ssl))
-	return PJ_SUCCESS;
-
-    if (SSL_get_fd(ssl) < 0)
-	SSL_set_fd(ssl, (int)tls->sock);
-
-    if (!SSL_in_connect_init(ssl))
-	SSL_set_connect_state(ssl);
-
-#ifdef SSL_set_tlsext_host_name
-    if (tls->setting.server_name.slen) {
-	char server_name[PJ_MAX_HOSTNAME];
-
-	if (tls->setting.server_name.slen >= PJ_MAX_HOSTNAME)
-	    return PJ_ENAMETOOLONG;
-
-	pj_memcpy(server_name, tls->setting.server_name.ptr, 
-		  tls->setting.server_name.slen);
-	server_name[tls->setting.server_name.slen] = '\0';
-
-	if (!SSL_set_tlsext_host_name(ssl, server_name)) {
-	    PJ_LOG(4,(tls->base.obj_name, 
-		      "SSL_set_tlsext_host_name() failed"));
-	}
-    }
-#endif
-
-    PJ_LOG(5,(tls->base.obj_name, "Starting SSL_connect() negotiation"));
-
-    do {
-	/* These handle sets are used to set up for whatever SSL_connect
-	 * says it wants next. They're reset on each pass around the loop.
-	 */
-	pj_fd_set_t rd_set;
-	pj_fd_set_t wr_set;
-	
-	PJ_FD_ZERO(&rd_set);
-	PJ_FD_ZERO(&wr_set);
-
-	status = SSL_connect (ssl);
-	switch (SSL_get_error (ssl, status)) {
-        case SSL_ERROR_NONE:
-	    /* Success */
-	    status = 0;
-	    PJ_LOG(5,(tls->base.obj_name, 
-		      "SSL_connect() negotiation completes successfully"));
-	    break;
-
-        case SSL_ERROR_WANT_WRITE:
-	    /* Wait for more activity */
-	    PJ_FD_SET(tls->sock, &wr_set);
-	    status = 1;
-	    break;
-	    
-        case SSL_ERROR_WANT_READ:
-	    /* Wait for more activity */
-	    PJ_FD_SET(tls->sock, &rd_set);
-	    status = 1;
-	    break;
-	    
-        case SSL_ERROR_ZERO_RETURN:
-	    /* The peer has notified us that it is shutting down via
-	     * the SSL "close_notify" message so we need to
-	     * shutdown, too.
-	     */
-	    PJ_LOG(4,(THIS_FILE, "SSL connect() failed, remote has"
-				 "shutdown connection."));
-	    return PJ_STATUS_FROM_OS(OSERR_ENOTCONN);
-	    
-        case SSL_ERROR_SYSCALL:
-	    /* On some platforms (e.g. MS Windows) OpenSSL does not
-	     * store the last error in errno so explicitly do so.
-	     *
-	     * Explicitly check for EWOULDBLOCK since it doesn't get
-	     * converted to an SSL_ERROR_WANT_{READ,WRITE} on some
-	     * platforms. If SSL_connect failed outright, though, don't
-	     * bother checking more. This can happen if the socket gets
-	     * closed during the handshake.
-	     */
-	    if (pj_get_netos_error() == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) &&
-		status == -1)
-            {
-		/* Although the SSL_ERROR_WANT_READ/WRITE isn't getting
-		 * set correctly, the read/write state should be valid.
-		 * Use that to decide what to do.
-		 */
-		status = 1;               /* Wait for more activity */
-		if (SSL_want_write (ssl))
-		    PJ_FD_SET(tls->sock, &wr_set);
-		else if (SSL_want_read (ssl))
-		    PJ_FD_SET(tls->sock, &rd_set);
-		else
-		    status = -1;	/* Doesn't want anything - bail out */
-            }
-	    else {
-		status = -1;
-	    }
-	    break;
-
-        default:
-	    ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
-			     "SSL_connect() error");
-	    status = -1;
-	    break;
-        }
-	
-	if (status == 1) {
-	    pj_time_val timeout, *p_timeout;
-
-	    /* Must have at least one handle to wait for at this point. */
-	    pj_assert(PJ_FD_COUNT(&rd_set) == 1 || PJ_FD_COUNT(&wr_set) == 1);
-	    
-	    /* This will block the whole stack!!! */
-	    PJ_TODO(SUPPORT_SSL_ASYNCHRONOUS_CONNECT);
-
-	    if (tls->setting.timeout.sec == 0 &&
-		tls->setting.timeout.msec == 0)
-	    {
-		p_timeout = NULL;
-	    } else {
-		timeout = tls->setting.timeout;
-		p_timeout = &timeout;
-	    }
-
-	    /* Block indefinitely if timeout pointer is zero. */
-	    status = pj_sock_select(tls->sock+1, &rd_set, &wr_set,
-				    NULL, p_timeout);
-	    	    
-	    /* 0 is timeout, so we're done.
-	     * -1 is error, so we're done.
-	     * Could be both handles set (same handle in both masks) so set to 1.
-	     */
-	    if (status >= 1)
-		status = 1;
-	    else if (status == 0)
-		return PJSIP_TLS_ETIMEDOUT;
-	    else
-		status = -1;
-        }
-	
-    } while (status == 1 && !SSL_is_init_finished (ssl));
-        
-    return (status == -1 ? PJSIP_TLS_ECONNECT : PJ_SUCCESS);
-}
-
-
-/*
- * Perform SSL_accept() on the newly established incoming TLS connection.
- */
-static pj_status_t ssl_accept(struct tls_transport *tls)
-{
-    SSL *ssl = tls->ssl;
-    int rc;
-    
-    if (SSL_is_init_finished (ssl))
-	return PJ_SUCCESS;
-    
-    if (!SSL_in_accept_init(ssl))
-	SSL_set_accept_state(ssl);
-
-    PJ_LOG(5,(tls->base.obj_name, "Starting SSL_accept() negotiation"));
-
-    /* Repeat retrying SSL_accept() procedure until it completes either
-     * successfully or with failure.
-     */
-    do {
-
-	/* These handle sets are used to set up for whatever SSL_accept says
-	 * it wants next. They're reset on each pass around the loop.
-	 */
-	pj_fd_set_t rd_set;
-	pj_fd_set_t wr_set;
-	
-	PJ_FD_ZERO(&rd_set);
-	PJ_FD_ZERO(&wr_set);
-
-	rc = SSL_accept (ssl);
-
-	switch (SSL_get_error (ssl, rc)) {
-        case SSL_ERROR_NONE:
-	    /* Success! */
-	    rc = 0;
-	    PJ_LOG(5,(tls->base.obj_name, 
-		      "SSL_accept() negotiation completes successfully"));
-	    break;
-	    
-        case SSL_ERROR_WANT_WRITE:
-	    PJ_FD_SET(tls->sock, &wr_set);
-	    rc = 1;               /* Wait for more activity */
-	    break;
-	    
-        case SSL_ERROR_WANT_READ:
-	    PJ_FD_SET(tls->sock, &rd_set);
-	    rc = 1;               /* Need to read more data */
-	    break;
-
-        case SSL_ERROR_ZERO_RETURN:
-	    /* The peer has notified us that it is shutting down via the SSL 
-	     * "close_notify" message so we need to shutdown, too.
-	     */
-	    PJ_LOG(4,(tls->base.obj_name,  
-		      "Incoming SSL connection closed prematurely by client"));
-	    return PJ_STATUS_FROM_OS(OSERR_ENOTCONN);
-
-        case SSL_ERROR_SYSCALL:
-	    /* Explicitly check for EWOULDBLOCK since it doesn't get converted
-	     * to an SSL_ERROR_WANT_{READ,WRITE} on some platforms. 
-	     * If SSL_accept failed outright, though, don't bother checking 
-	     * more. This can happen if the socket gets closed during the 
-	     * handshake.
-	     */
-	    if (pj_get_netos_error()==PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK) 
-		&& rc==-1)
-            {
-		/* Although the SSL_ERROR_WANT_READ/WRITE isn't getting set 
-		 * correctly, the read/write state should be valid. Use that 
-		 * to decide what to do.
-		 */
-		rc = 1;               /* Wait for more activity */
-		if (SSL_want_write(ssl))
-		    PJ_FD_SET(tls->sock, &wr_set);
-		else if (SSL_want_read(ssl))
-		    PJ_FD_SET(tls->sock, &rd_set);
-		else {
-		    /* Doesn't want anything - bail out */
-		    return PJ_STATUS_FROM_OS(OSERR_ENOTCONN);
-		}
-            }
-	    else {
-		return PJSIP_TLS_EUNKNOWN;
-	    }
-	    break;
-	    
-        default:
-	    ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
-			     "Error calling SSL_accept()");
-	    return pj_get_netos_error() ? pj_get_netos_error() : 
-		    PJSIP_TLS_EUNKNOWN;
-        }
-	
-	if (rc == 1) {
-
-	    pj_time_val timeout, *p_timeout;
-
-	    /* Must have at least one handle to wait for at this point. */
-	    pj_assert(PJ_FD_COUNT(&rd_set) == 1 || PJ_FD_COUNT(&wr_set) == 1);
-
-	    if (tls->setting.timeout.sec == 0 &&
-		tls->setting.timeout.msec == 0)
-	    {
-		p_timeout = NULL;
-	    } else {
-		timeout = tls->setting.timeout;
-		p_timeout = &timeout;
-	    }
-
-	    rc = pj_sock_select(tls->sock+1, &rd_set, &wr_set, NULL, 
-			        p_timeout);
-	    
-	    if (rc >= 1)
-		rc = 1;
-	    else if (rc == 0)
-		return PJSIP_TLS_ETIMEDOUT;
-	    else
-		return pj_get_netos_error();
-        }
-	
-    } while (rc == 1 && !SSL_is_init_finished(ssl));
-    
-    return (rc == -1 ? PJSIP_TLS_EUNKNOWN : PJ_SUCCESS);
-}
-
-
-/* Send outgoing data with SSL connection */
-static pj_status_t ssl_write_bytes(struct tls_transport *tls,
-				   const void *data,
-				   int size,
-				   const char *data_name)
-{
-    int sent = 0;
-
-    do {
-	const int fragment_sent = SSL_write(tls->ssl,
-					    ((pj_uint8_t*)data) + sent, 
-					    size - sent);
-    
-	switch( SSL_get_error(tls->ssl, fragment_sent)) {
-	case SSL_ERROR_NONE:
-	    sent += fragment_sent;
-	    break;
-	    
-	case SSL_ERROR_WANT_READ:
-	case SSL_ERROR_WANT_WRITE:
-	    /* For now, we can't handle situation where WANT_READ/WANT_WRITE
-	     * is raised after some data has been sent, since we don't have
-	     * mechanism to keep track of how many bytes have been sent
-	     * inside the individual tdata.
-	     */
-	    pj_assert(sent == 0);
-	    PJ_TODO(PARTIAL_SSL_SENT);
-	    return PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK);
-	    
-	case SSL_ERROR_ZERO_RETURN:
-	    /* The peer has notified us that it is shutting down via the SSL
-	     * "close_notify" message. Tell the transport manager that it
-	     * shouldn't use this transport any more and return ENOTCONN
-	     * to caller.
-	     */
-	    
-	    /* It is safe to call this multiple times. */
-	    pjsip_transport_shutdown(&tls->base);
-
-	    return PJ_STATUS_FROM_OS(OSERR_ENOTCONN);
-	    
-	case SSL_ERROR_SYSCALL:
-	    if (fragment_sent == 0) {
-		/* An EOF occured but the SSL "close_notify" message was not
-		 * sent. Shutdown the transport and return ENOTCONN.
-		 */
-
-		/* It is safe to call this multiple times. */
-		pjsip_transport_shutdown(&tls->base);
-
-		return PJ_STATUS_FROM_OS(OSERR_ENOTCONN);
-	    }
-	    
-	    /* Other error */
-	    return pj_get_netos_error();
-
-	default:
-	    ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
-			     "Error sending %s with SSL_write()",
-			     data_name);
-	    return pj_get_netos_error() ? pj_get_netos_error() 
-		    : PJSIP_TLS_ESEND;
-	}
-    
-    } while (sent < size);
-
-    return PJ_SUCCESS;
-
-}
-
-/* Send outgoing tdata with SSL connection */
-static pj_status_t ssl_write(struct tls_transport *tls,
-			     pjsip_tx_data *tdata)
-{
-    return ssl_write_bytes(tls, tdata->buf.start, 
-			   tdata->buf.cur - tdata->buf.start,
-			   pjsip_tx_data_get_info(tdata));
-}
-
-
-/* Read data from SSL connection */
-static pj_status_t ssl_read(struct tls_transport *tls)
-{
-    pjsip_rx_data *rdata = &tls->rdata;
-
-    int bytes_read, max_size;
-
-    max_size = sizeof(rdata->pkt_info.packet) - rdata->pkt_info.len;
-    bytes_read = SSL_read(tls->ssl, 
-			  rdata->pkt_info.packet+rdata->pkt_info.len,
-                          max_size);
-
-    switch (SSL_get_error(tls->ssl, bytes_read)) {
-    case SSL_ERROR_NONE:
-	/* Data successfully read */
-	rdata->pkt_info.len += bytes_read;
-	return PJ_SUCCESS;
-	
-    case SSL_ERROR_WANT_READ:
-    case SSL_ERROR_WANT_WRITE:
-	return PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK);
-	
-    case SSL_ERROR_ZERO_RETURN:
-	/* The peer has notified us that it is shutting down via the SSL
-	 * "close_notify" message.
-	 */
-	pjsip_transport_shutdown(&tls->base);
-	return PJ_STATUS_FROM_OS(OSERR_ENOTCONN);
-	
-    case SSL_ERROR_SYSCALL:
-	if (bytes_read == 0) {
-	    /* An EOF occured but the SSL "close_notify" message was not
-	     * sent.
-	     */
-	    pjsip_transport_shutdown(&tls->base);
-	    return PJ_STATUS_FROM_OS(OSERR_ENOTCONN);
-	}
-	
-	/* Other error */
-	return pj_get_netos_error();
-	
-    default:
-	ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
-			 "Error reading data with SSL_read()");
-	return pj_get_netos_error() ? pj_get_netos_error() 
-		: PJSIP_TLS_EREAD;
-    }
-
-    /* Should not reach here */
-}
-
-
-/****************************************************************************
- * The TLS listener/transport factory.
- */
-
-/*
- * This is the public API to create, initialize, register, and start the
- * TLS listener.
- */
-PJ_DEF(pj_status_t) pjsip_tls_transport_start( pjsip_endpoint *endpt,
-					       const pjsip_tls_setting *opt,
-					       const pj_sockaddr_in *local,
-					       const pjsip_host_port *a_name,
-					       unsigned async_cnt,
-					       pjsip_tpfactory **p_factory)
-{
-    pj_pool_t *pool;
-    struct tls_listener *listener;
-    pj_ioqueue_callback listener_cb;
-    pj_sockaddr_in *listener_addr;
-    int addr_len;
-    unsigned i;
-    pj_status_t status;
-
-    /* Sanity check */
-    PJ_ASSERT_RETURN(endpt && async_cnt, PJ_EINVAL);
-
-    /* Verify that address given in a_name (if any) is valid */
-    if (a_name && a_name->host.slen) {
-	pj_sockaddr_in tmp;
-
-	status = pj_sockaddr_in_init(&tmp, &a_name->host, 
-				     (pj_uint16_t)a_name->port);
-	if (status != PJ_SUCCESS || tmp.sin_addr.s_addr == PJ_INADDR_ANY ||
-	    tmp.sin_addr.s_addr == PJ_INADDR_NONE)
-	{
-	    /* Invalid address */
-	    return PJ_EINVAL;
-	}
-    }
-
-    pool = pjsip_endpt_create_pool(endpt, "tlslis", 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;
-    listener->factory.type = PJSIP_TRANSPORT_TLS;
-    listener->factory.type_name = "tls";
-    listener->factory.flag = 
-	pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);
-    listener->sock = PJ_INVALID_SOCKET;
-    
-    /* Create object name */
-    pj_ansi_snprintf(listener->factory.obj_name, 
-		     sizeof(listener->factory.obj_name),
-		     "tls%p",  listener);
-    
-    /* Create duplicate of TLS settings */
-    if (opt)
-	pjsip_tls_setting_copy(pool, &listener->setting, opt);
-    else
-	pjsip_tls_setting_default(&listener->setting);
-
-    /* Initialize SSL context to be used by this listener */
-    status = create_ctx(listener, &listener->ctx);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    status = pj_lock_create_recursive_mutex(pool, "tlslis", 
-					    &listener->factory.lock);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-
-    /* Create and bind socket */
-    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &listener->sock);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    listener_addr = (pj_sockaddr_in*)&listener->factory.local_addr;
-    if (local) {
-	pj_memcpy(listener_addr, local, sizeof(pj_sockaddr_in));
-    } else {
-	pj_sockaddr_in_init(listener_addr, NULL, 0);
-    }
-
-    status = pj_sock_bind(listener->sock, listener_addr, 
-			  sizeof(pj_sockaddr_in));
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Retrieve the bound address */
-    addr_len = sizeof(pj_sockaddr_in);
-    status = pj_sock_getsockname(listener->sock, listener_addr, &addr_len);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* If published host/IP is specified, then use that address as the
-     * listener advertised address.
-     */
-    if (a_name && a_name->host.slen) {
-	/* Copy the address */
-	listener->factory.addr_name = *a_name;
-	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
-		  &a_name->host);
-	listener->factory.addr_name.port = a_name->port;
-
-    } else {
-	/* No published address is given, use the bound address */
-
-	/* If the address returns 0.0.0.0, use the default
-	 * interface address as the transport's address.
-	 */
-	if (listener_addr->sin_addr.s_addr == 0) {
-	    pj_sockaddr hostip;
-
-	    status = pj_gethostip(pj_AF_INET(), &hostip);
-	    if (status != PJ_SUCCESS)
-		goto on_error;
-
-	    listener_addr->sin_addr = hostip.ipv4.sin_addr;
-	}
-
-	/* Save the address name */
-	sockaddr_to_host_port(listener->factory.pool, 
-			      &listener->factory.addr_name, listener_addr);
-    }
-
-    /* If port is zero, get the bound port */
-    if (listener->factory.addr_name.port == 0) {
-	listener->factory.addr_name.port = pj_ntohs(listener_addr->sin_port);
-    }
-
-    /* Start listening to the address */
-    status = pj_sock_listen(listener->sock, PJSIP_TLS_TRANSPORT_BACKLOG);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-
-    /* Register socket to ioqeuue */
-    pj_bzero(&listener_cb, sizeof(listener_cb));
-    listener_cb.on_accept_complete = &on_accept_complete;
-    status = pj_ioqueue_register_sock(pool, pjsip_endpt_get_ioqueue(endpt),
-				      listener->sock, listener,
-				      &listener_cb, &listener->key);
-    if (status != PJ_SUCCESS)
-	goto on_error;
-
-    /* Register to transport manager */
-    listener->endpt = endpt;
-    listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
-    listener->factory.create_transport = lis_create_transport;
-    listener->factory.destroy = lis_destroy;
-    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;
-    }
-
-
-    /* Start pending accept() operations */
-    if (async_cnt > MAX_ASYNC_CNT) async_cnt = MAX_ASYNC_CNT;
-    listener->async_cnt = async_cnt;
-
-    for (i=0; i<async_cnt; ++i) {
-	pj_pool_t *pool;
-
-	pool = pjsip_endpt_create_pool(endpt, "tlss%p", POOL_TP_INIT, 
-				       POOL_TP_INIT);
-	if (!pool) {
-	    status = PJ_ENOMEM;
-	    goto on_error;
-	}
-
-	listener->accept_op[i] = PJ_POOL_ZALLOC_T(pool, struct pending_accept);
-	pj_ioqueue_op_key_init(&listener->accept_op[i]->op_key, 
-				sizeof(listener->accept_op[i]->op_key));
-	listener->accept_op[i]->pool = pool;
-	listener->accept_op[i]->listener = listener;
-	listener->accept_op[i]->index = i;
-
-	on_accept_complete(listener->key, &listener->accept_op[i]->op_key,
-			   listener->sock, PJ_EPENDING);
-    }
-
-    PJ_LOG(4,(listener->factory.obj_name, 
-	     "SIP TLS listener ready for incoming connections at %.*s:%d",
-	     (int)listener->factory.addr_name.host.slen,
-	     listener->factory.addr_name.host.ptr,
-	     listener->factory.addr_name.port));
-
-    /* Return the pointer to user */
-    if (p_factory) *p_factory = &listener->factory;
-
-    return PJ_SUCCESS;
-
-on_error:
-    lis_destroy(&listener->factory);
-    return status;
-}
-
-
-/* This callback is called by transport manager to destroy listener */
-static pj_status_t lis_destroy(pjsip_tpfactory *factory)
-{
-    struct tls_listener *listener = (struct tls_listener *)factory;
-    unsigned i;
-
-    if (listener->is_registered) {
-	pjsip_tpmgr_unregister_tpfactory(listener->tpmgr, &listener->factory);
-	listener->is_registered = PJ_FALSE;
-    }
-
-    if (listener->key) {
-	pj_ioqueue_unregister(listener->key);
-	listener->key = NULL;
-	listener->sock = PJ_INVALID_SOCKET;
-    }
-
-    if (listener->sock != PJ_INVALID_SOCKET) {
-	pj_sock_close(listener->sock);
-	listener->sock = PJ_INVALID_SOCKET;
-    }
-
-    if (listener->factory.lock) {
-	pj_lock_destroy(listener->factory.lock);
-	listener->factory.lock = NULL;
-    }
-
-    for (i=0; i<PJ_ARRAY_SIZE(listener->accept_op); ++i) {
-	if (listener->accept_op[i] && listener->accept_op[i]->pool) {
-	    pj_pool_t *pool = listener->accept_op[i]->pool;
-	    listener->accept_op[i]->pool = NULL;
-	    pj_pool_release(pool);
-	}
-    }
-
-    if (listener->ctx) {
-	destroy_ctx(listener->ctx);
-	listener->ctx = NULL;
-    }
-
-    if (listener->factory.pool) {
-	pj_pool_t *pool = listener->factory.pool;
-
-	PJ_LOG(4,(listener->factory.obj_name,  "SIP TLS listener destroyed"));
-
-	listener->factory.pool = NULL;
-	pj_pool_release(pool);
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-/***************************************************************************/
-/*
- * TLS Transport
- */
-
-/*
- * Prototypes.
- */
-/* Called by transport manager to send message */
-static pj_status_t tls_send_msg(pjsip_transport *transport, 
-				pjsip_tx_data *tdata,
-				const pj_sockaddr_t *rem_addr,
-				int addr_len,
-				void *token,
-				void (*callback)(pjsip_transport *transport,
-						 void *token, 
-						 pj_ssize_t sent_bytes));
-
-/* Called by transport manager to shutdown */
-static pj_status_t tls_shutdown(pjsip_transport *transport);
-
-/* Called by transport manager to destroy transport */
-static pj_status_t tls_destroy_transport(pjsip_transport *transport);
-
-/* Utility to destroy transport */
-static pj_status_t tls_destroy(pjsip_transport *transport,
-			       pj_status_t reason);
-
-/* Callback from ioqueue on incoming packet */
-static void on_read_complete(pj_ioqueue_key_t *key, 
-                             pj_ioqueue_op_key_t *op_key, 
-                             pj_ssize_t bytes_read);
-
-/* Callback from ioqueue when packet is sent */
-static void on_write_complete(pj_ioqueue_key_t *key, 
-                              pj_ioqueue_op_key_t *op_key, 
-                              pj_ssize_t bytes_sent);
-
-/* Callback from ioqueue when connect completes */
-static void on_connect_complete(pj_ioqueue_key_t *key, 
-                                pj_status_t status);
-
-/* TLS keep-alive timer callback */
-static void tls_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e);
-
-/*
- * Common function to create TLS transport, called when pending accept() and
- * pending connect() complete.
- */
-static pj_status_t tls_create( struct tls_listener *listener,
-			       pj_pool_t *pool,
-			       pj_sock_t sock, pj_bool_t is_server,
-			       const pj_sockaddr_in *local,
-			       const pj_sockaddr_in *remote,
-			       struct tls_transport **p_tls)
-{
-    struct tls_transport *tls;
-    pj_ioqueue_t *ioqueue;
-    pj_ioqueue_callback tls_callback;
-    int rc;
-    pj_status_t status;
-    
-
-    PJ_ASSERT_RETURN(sock != PJ_INVALID_SOCKET, PJ_EINVAL);
-
-
-    if (pool == NULL) {
-	pool = pjsip_endpt_create_pool(listener->endpt, "tls",
-				       POOL_TP_INIT, POOL_TP_INC);
-	PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
-    }    
-
-    /*
-     * Create and initialize basic transport structure.
-     */
-    tls = PJ_POOL_ZALLOC_T(pool, struct tls_transport);
-    tls->sock = sock;
-    tls->is_server = is_server;
-    /*tls->listener = listener;*/
-    pj_list_init(&tls->delayed_list);
-    tls->base.pool = pool;
-    tls->setting.timeout = listener->setting.timeout;
-    pj_strdup(pool, &tls->setting.server_name, 
-    	      &listener->setting.server_name);
-
-    pj_ansi_snprintf(tls->base.obj_name, PJ_MAX_OBJ_NAME, 
-		     (is_server ? "tlss%p" :"tlsc%p"), tls);
-
-    /* Initialize transport reference counter to 1 */
-    status = pj_atomic_create(pool, 0, &tls->base.ref_cnt);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    status = pj_lock_create_recursive_mutex(pool, "tls", &tls->base.lock);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    tls->base.key.type = PJSIP_TRANSPORT_TLS;
-    pj_memcpy(&tls->base.key.rem_addr, remote, sizeof(pj_sockaddr_in));
-    tls->base.type_name = "tls";
-    tls->base.flag = pjsip_transport_get_flag_from_type(PJSIP_TRANSPORT_TLS);
-
-    tls->base.info = (char*) pj_pool_alloc(pool, 64);
-    pj_ansi_snprintf(tls->base.info, 64, "TLS to %s:%d",
-		     pj_inet_ntoa(remote->sin_addr), 
-		     (int)pj_ntohs(remote->sin_port));
-
-    tls->base.addr_len = sizeof(pj_sockaddr_in);
-    pj_memcpy(&tls->base.local_addr, local, sizeof(pj_sockaddr_in));
-    sockaddr_to_host_port(pool, &tls->base.local_name, local);
-    sockaddr_to_host_port(pool, &tls->base.remote_name, remote);
-
-    tls->base.endpt = listener->endpt;
-    tls->base.tpmgr = listener->tpmgr;
-    tls->base.send_msg = &tls_send_msg;
-    tls->base.do_shutdown = &tls_shutdown;
-    tls->base.destroy = &tls_destroy_transport;
-
-    /* Create SSL connection object */
-    tls->ssl = SSL_new(listener->ctx);
-    if (tls->ssl == NULL) {
-	ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
-			 "Error creating SSL connection object");
-	status = PJSIP_TLS_ESSLCONN;
-	goto on_error;
-    }
-
-    /* Associate network socket with SSL connection object */
-    rc = SSL_set_fd(tls->ssl, (int)sock);
-    if (rc != 1) {
-	ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
-			 "Error calling SSL_set_fd");
-	status = PJSIP_TLS_ESSLCONN;
-	goto on_error;
-    }
-
-    /* Register socket to ioqueue */
-    pj_bzero(&tls_callback, sizeof(pj_ioqueue_callback));
-    tls_callback.on_read_complete = &on_read_complete;
-    tls_callback.on_write_complete = &on_write_complete;
-    tls_callback.on_connect_complete = &on_connect_complete;
-
-    ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
-    status = pj_ioqueue_register_sock(pool, ioqueue, sock, 
-				      tls, &tls_callback, &tls->key);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    /* Register transport to transport manager */
-    status = pjsip_transport_register(listener->tpmgr, &tls->base);
-    if (status != PJ_SUCCESS) {
-	goto on_error;
-    }
-
-    tls->is_registered = PJ_TRUE;
-
-    /* Initialize keep-alive timer */
-    tls->ka_timer.user_data = (void*) tls;
-    tls->ka_timer.cb = &tls_keep_alive_timer;
-
-
-    /* Done setting up basic transport. */
-    *p_tls = tls;
-
-    PJ_LOG(4,(tls->base.obj_name, "TLS %s transport created",
-	      (tls->is_server ? "server" : "client")));
-
-    return PJ_SUCCESS;
-
-on_error:
-    tls_destroy(&tls->base, status);
-    return status;
-}
-
-
-/* Flush all delayed transmision once the socket is connected. 
- * Return non-zero if pending transmission list is empty after
- * the function returns.
- */
-static pj_bool_t tls_flush_pending_tx(struct tls_transport *tls)
-{
-    pj_bool_t empty;
-
-    pj_lock_acquire(tls->base.lock);
-    while (!pj_list_empty(&tls->delayed_list)) {
-	struct delayed_tdata *pending_tx;
-	pjsip_tx_data *tdata;
-	pj_ioqueue_op_key_t *op_key;
-	pj_ssize_t size;
-	pj_status_t status;
-
-	pending_tx = tls->delayed_list.next;
-
-	tdata = pending_tx->tdata_op_key->tdata;
-	op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
-
-	/* send the txdata */
-	status = ssl_write(tls, tdata);
-
-	/* On EWOULDBLOCK, suspend further transmissions */
-	if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) {
-	    break;
-	}
-
-	/* tdata has been transmitted (successfully or with failure).
-	 * In any case, remove it from pending transmission list.
-	 */
-	pj_list_erase(pending_tx);
-
-	/* Notify callback */
-	if (status == PJ_SUCCESS)
-	    size = tdata->buf.cur - tdata->buf.start;
-	else
-	    size = -status;
-
-	on_write_complete(tls->key, op_key, size);
-
-    }
-
-    empty = pj_list_empty(&tls->delayed_list);
-
-    pj_lock_release(tls->base.lock);
-
-    return empty;
-}
-
-
-/* Called by transport manager to destroy transport */
-static pj_status_t tls_destroy_transport(pjsip_transport *transport)
-{
-    struct tls_transport *tls = (struct tls_transport*)transport;
-
-    /* Transport would have been unregistered by now since this callback
-     * is called by transport manager.
-     */
-    tls->is_registered = PJ_FALSE;
-
-    return tls_destroy(transport, tls->close_reason);
-}
-
-
-/* Destroy TLS transport */
-static pj_status_t tls_destroy(pjsip_transport *transport, 
-			       pj_status_t reason)
-{
-    struct tls_transport *tls = (struct tls_transport*)transport;
-
-    if (tls->close_reason == 0)
-	tls->close_reason = reason;
-
-    if (tls->is_registered) {
-	tls->is_registered = PJ_FALSE;
-	pjsip_transport_destroy(transport);
-
-	/* pjsip_transport_destroy will recursively call this function
-	 * again.
-	 */
-	return PJ_SUCCESS;
-    }
-
-    /* Mark transport as closing */
-    ++tls->is_closing;
-
-    /* Stop keep-alive timer. */
-    if (tls->ka_timer.id) {
-	pjsip_endpt_cancel_timer(tls->base.endpt, &tls->ka_timer);
-	tls->ka_timer.id = PJ_FALSE;
-    }
-
-    /* Cancel all delayed transmits */
-    while (!pj_list_empty(&tls->delayed_list)) {
-	struct delayed_tdata *pending_tx;
-	pj_ioqueue_op_key_t *op_key;
-
-	pending_tx = tls->delayed_list.next;
-	pj_list_erase(pending_tx);
-
-	op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
-
-	on_write_complete(tls->key, op_key, -reason);
-    }
-
-    if (tls->rdata.tp_info.pool) {
-	pj_pool_release(tls->rdata.tp_info.pool);
-	tls->rdata.tp_info.pool = NULL;
-    }
-
-    if (tls->key) {
-	pj_ioqueue_unregister(tls->key);
-	tls->key = NULL;
-	tls->sock = PJ_INVALID_SOCKET;
-    }
-
-    if (tls->sock != PJ_INVALID_SOCKET) {
-	pj_sock_close(tls->sock);
-	tls->sock = PJ_INVALID_SOCKET;
-    }
-
-    if (tls->base.lock) {
-	pj_lock_destroy(tls->base.lock);
-	tls->base.lock = NULL;
-    }
-
-    if (tls->base.ref_cnt) {
-	pj_atomic_destroy(tls->base.ref_cnt);
-	tls->base.ref_cnt = NULL;
-    }
-
-    if (tls->ssl) {
-	SSL_free(tls->ssl);
-	tls->ssl = NULL;
-    }
-
-    if (tls->base.pool) {
-	pj_pool_t *pool;
-
-	if (reason != PJ_SUCCESS) {
-	    char errmsg[PJ_ERR_MSG_SIZE];
-
-	    pj_strerror(reason, errmsg, sizeof(errmsg));
-	    PJ_LOG(4,(tls->base.obj_name, 
-		      "TLS transport destroyed with reason %d: %s", 
-		      reason, errmsg));
-
-	} else {
-
-	    PJ_LOG(4,(tls->base.obj_name, 
-		      "TLS transport destroyed normally"));
-
-	}
-
-	pool = tls->base.pool;
-	tls->base.pool = NULL;
-	pj_pool_release(pool);
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * This utility function creates receive data buffers and start
- * asynchronous recv() operations from the socket. It is called after
- * accept() or connect() operation complete.
- */
-static pj_status_t tls_start_read(struct tls_transport *tls)
-{
-    pj_pool_t *pool;
-    pj_ssize_t size;
-    pj_sockaddr_in *rem_addr;
-    pj_status_t status;
-
-    /* Init rdata */
-    pool = pjsip_endpt_create_pool(tls->base.endpt,
-				   "rtd%p",
-				   PJSIP_POOL_RDATA_LEN,
-				   PJSIP_POOL_RDATA_INC);
-    if (!pool) {
-	ssl_report_error(tls->base.obj_name, 4, PJ_ENOMEM, 
-			 "Unable to create pool for listener rxdata");
-	return PJ_ENOMEM;
-    }
-
-    tls->rdata.tp_info.pool = pool;
-
-    tls->rdata.tp_info.transport = &tls->base;
-    tls->rdata.tp_info.tp_data = tls;
-    tls->rdata.tp_info.op_key.rdata = &tls->rdata;
-    pj_ioqueue_op_key_init(&tls->rdata.tp_info.op_key.op_key, 
-			   sizeof(pj_ioqueue_op_key_t));
-
-    tls->rdata.pkt_info.src_addr = tls->base.key.rem_addr;
-    tls->rdata.pkt_info.src_addr_len = sizeof(pj_sockaddr_in);
-    rem_addr = (pj_sockaddr_in*) &tls->base.key.rem_addr;
-    pj_ansi_strcpy(tls->rdata.pkt_info.src_name,
-		   pj_inet_ntoa(rem_addr->sin_addr));
-    tls->rdata.pkt_info.src_port = pj_ntohs(rem_addr->sin_port);
-
-    /* Here's the real trick with OpenSSL.
-     * Since asynchronous socket operation with OpenSSL uses select() like
-     * mechanism, it's not really compatible with PJLIB's ioqueue. So to
-     * make them "talk" together, we simulate select() by using MSG_PEEK
-     * when we call pj_ioqueue_recv().
-     */
-    size = 1;
-    status = pj_ioqueue_recv(tls->key, &tls->rdata.tp_info.op_key.op_key,
-			     tls->rdata.pkt_info.packet, &size,
-			     PJ_IOQUEUE_ALWAYS_ASYNC | PJ_MSG_PEEK);
-    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
-	ssl_report_error(tls->base.obj_name, 4, status,
-			 "ioqueue_recv() error");
-	return status;
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-
-/* This callback is called by transport manager for the TLS factory
- * to create outgoing transport to the specified destination.
- */
-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_transport **p_transport)
-{
-    struct tls_listener *listener;
-    struct tls_transport *tls;
-    pj_sock_t sock;
-    pj_sockaddr_in local_addr;
-    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 */
-    PJ_ASSERT_RETURN(rem_addr->addr.sa_family == pj_AF_INET() &&
-		     addr_len == sizeof(pj_sockaddr_in), PJ_EINVAL);
-
-
-    listener = (struct tls_listener*)factory;
-
-    
-    /* Create socket */
-    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
-    if (status != PJ_SUCCESS)
-	return status;
-
-    /* Bind to any port */
-    status = pj_sock_bind_in(sock, 0, 0);
-    if (status != PJ_SUCCESS) {
-	pj_sock_close(sock);
-	return status;
-    }
-
-    /* Get the local port */
-    addr_len = sizeof(pj_sockaddr_in);
-    status = pj_sock_getsockname(sock, &local_addr, &addr_len);
-    if (status != PJ_SUCCESS) {
-	pj_sock_close(sock);
-	return status;
-    }
-
-    /* Initially set the address from the listener's address */
-    local_addr.sin_addr.s_addr = 
-	((pj_sockaddr_in*)&listener->factory.local_addr)->sin_addr.s_addr;
-
-    /* Create the transport descriptor */
-    status = tls_create(listener, NULL, sock, PJ_FALSE, &local_addr, 
-			(pj_sockaddr_in*)rem_addr, &tls);
-    if (status != PJ_SUCCESS)
-	return status;
-
-
-    /* Start asynchronous connect() operation */
-    tls->has_pending_connect = PJ_TRUE;
-    status = pj_ioqueue_connect(tls->key, rem_addr, sizeof(pj_sockaddr_in));
-    if (status == PJ_SUCCESS) {
-
-	/* Immediate socket connect() ! */
-	tls->has_pending_connect = PJ_FALSE;
-
-	/* Perform SSL_connect() */
-	status = ssl_connect(tls);
-	if (status != PJ_SUCCESS) {
-	    tls_destroy(&tls->base, status);
-	    return status;
-	}
-
-    } else if (status != PJ_EPENDING) {
-	tls_destroy(&tls->base, status);
-	return status;
-    }
-
-    /* Update (again) local address, just in case local address currently
-     * set is different now that asynchronous connect() is started.
-     */
-    addr_len = sizeof(pj_sockaddr_in);
-    if (pj_sock_getsockname(tls->sock, &local_addr, &addr_len)==PJ_SUCCESS) {
-	pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tls->base.local_addr;
-
-	/* Some systems (like old Win32 perhaps) may not set local address
-	 * properly before socket is fully connected.
-	 */
-	if (tp_addr->sin_addr.s_addr != local_addr.sin_addr.s_addr &&
-	    local_addr.sin_addr.s_addr != 0) 
-	{
-	    tp_addr->sin_addr.s_addr = local_addr.sin_addr.s_addr;
-	    tp_addr->sin_port = local_addr.sin_port;
-	    sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
-				  &local_addr);
-	}
-    }
-
-    if (tls->has_pending_connect) {
-	PJ_LOG(4,(tls->base.obj_name, 
-		  "TLS transport %.*s:%d is connecting to %.*s:%d...",
-		  (int)tls->base.local_name.host.slen,
-		  tls->base.local_name.host.ptr,
-		  tls->base.local_name.port,
-		  (int)tls->base.remote_name.host.slen,
-		  tls->base.remote_name.host.ptr,
-		  tls->base.remote_name.port));
-    }
-
-    /* Done */
-    *p_transport = &tls->base;
-
-    return PJ_SUCCESS;
-}
-
-
-/*
- * This callback is called by ioqueue when pending accept() operation has
- * completed.
- */
-static void on_accept_complete(	pj_ioqueue_key_t *key, 
-				pj_ioqueue_op_key_t *op_key, 
-				pj_sock_t sock, 
-				pj_status_t status)
-{
-    struct tls_listener *listener;
-    struct tls_transport *tls;
-    struct pending_accept *accept_op;
-    int err_cnt = 0;
-
-    listener = (struct tls_listener*) pj_ioqueue_get_user_data(key);
-    accept_op = (struct pending_accept*) op_key;
-
-    /*
-     * Loop while there is immediate connection or when there is error.
-     */
-    do {
-	if (status == PJ_EPENDING) {
-	    /*
-	     * This can only happen when this function is called during
-	     * initialization to kick off asynchronous accept().
-	     */
-
-	} else if (status != PJ_SUCCESS) {
-
-	    /*
-	     * Error in accept().
-	     */
-	    ssl_report_error(listener->factory.obj_name, 4, status,
-			     "Error in asynchronous accept() completion");
-
-	    /*
-	     * Prevent endless accept() error loop by limiting the
-	     * number of consecutive errors. Once the number of errors
-	     * is equal to maximum, we treat this as permanent error, and
-	     * we stop the accept() operation.
-	     */
-	    ++err_cnt;
-	    if (err_cnt >= 10) {
-		PJ_LOG(1, (listener->factory.obj_name, 
-			   "Too many errors, listener stopping"));
-	    }
-
-	} else {
-	    pj_pool_t *pool;
-	    struct pending_accept *new_op;
-
-	    if (sock == PJ_INVALID_SOCKET) {
-		sock = accept_op->new_sock;
-	    }
-
-	    if (sock == PJ_INVALID_SOCKET) {
-		pj_assert(!"Should not happen. status should be error");
-		goto next_accept;
-	    }
-
-	    PJ_LOG(4,(listener->factory.obj_name, 
-		      "TLS listener %.*s:%d: got incoming TCP connection "
-		      "from %s:%d, sock=%d",
-		      (int)listener->factory.addr_name.host.slen,
-		      listener->factory.addr_name.host.ptr,
-		      listener->factory.addr_name.port,
-		      pj_inet_ntoa(accept_op->remote_addr.sin_addr),
-		      pj_ntohs(accept_op->remote_addr.sin_port),
-		      sock));
-
-	    /* Create new accept_opt */
-	    pool = pjsip_endpt_create_pool(listener->endpt, "tlss%p", 
-					   POOL_TP_INIT, POOL_TP_INC);
-	    new_op = PJ_POOL_ZALLOC_T(pool, struct pending_accept);
-	    new_op->pool = pool;
-	    new_op->listener = listener;
-	    new_op->index = accept_op->index;
-	    pj_ioqueue_op_key_init(&new_op->op_key, sizeof(new_op->op_key));
-	    listener->accept_op[accept_op->index] = new_op;
-
-	    /* 
-	     * Incoming connections!
-	     * Create TLS transport for the new socket.
-	     */
-	    status = tls_create( listener, accept_op->pool, sock, PJ_TRUE,
-				 &accept_op->local_addr, 
-				 &accept_op->remote_addr, &tls);
-	    if (status == PJ_SUCCESS) {
-		/* Complete SSL_accept() */
-		status = ssl_accept(tls);
-	    }
-
-	    if (status == PJ_SUCCESS) {
-		/* Start asynchronous read from the socket */
-		status = tls_start_read(tls);
-	    }
-
-	    if (status != PJ_SUCCESS) {
-		ssl_report_error(tls->base.obj_name, 4, status,
-				 "Error creating incoming TLS transport");
-		pjsip_transport_shutdown(&tls->base);
-
-	    } else {
-		/* Start keep-alive timer */
-		if (PJSIP_TLS_KEEP_ALIVE_INTERVAL) {
-		    pj_time_val delay = {PJSIP_TLS_KEEP_ALIVE_INTERVAL, 0};
-		    pjsip_endpt_schedule_timer(listener->endpt, 
-					       &tls->ka_timer, 
-					       &delay);
-		    tls->ka_timer.id = PJ_TRUE;
-		    pj_gettimeofday(&tls->last_activity);
-		}
-	    }
-
-	    accept_op = new_op;
-	}
-
-next_accept:
-	/*
-	 * Start the next asynchronous accept() operation.
-	 */
-	accept_op->addr_len = sizeof(pj_sockaddr_in);
-	accept_op->new_sock = PJ_INVALID_SOCKET;
-
-	status = pj_ioqueue_accept(listener->key, 
-				   &accept_op->op_key,
-				   &accept_op->new_sock,
-				   &accept_op->local_addr,
-				   &accept_op->remote_addr,
-				   &accept_op->addr_len);
-
-	/*
-	 * Loop while we have immediate connection or when there is error.
-	 */
-
-    } while (status != PJ_EPENDING);
-}
-
-
-/* 
- * Callback from ioqueue when packet is sent.
- */
-static void on_write_complete(pj_ioqueue_key_t *key, 
-                              pj_ioqueue_op_key_t *op_key, 
-                              pj_ssize_t bytes_sent)
-{
-    struct tls_transport *tls;
-    pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key;
-
-    tls = (struct tls_transport*) pj_ioqueue_get_user_data(key);
-    tdata_op_key->tdata = NULL;
-
-    if (tdata_op_key->callback) {
-	/*
-	 * Notify sip_transport.c that packet has been sent.
-	 */
-	if (bytes_sent == 0)
-	    bytes_sent = -PJ_RETURN_OS_ERROR(OSERR_ENOTCONN);
-
-	tdata_op_key->callback(&tls->base, tdata_op_key->token, bytes_sent);
-    }
-
-    /* Check for error/closure */
-    if (bytes_sent <= 0) {
-	pj_status_t status;
-
-	ssl_report_error(tls->base.obj_name, 4, -bytes_sent, 
-		         "TLS send() error");
-
-	status = (bytes_sent == 0) ? PJ_STATUS_FROM_OS(OSERR_ENOTCONN) :
-				     -bytes_sent;
-	if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
-	pjsip_transport_shutdown(&tls->base);
-    } else {
-	/* Mark last activity */
-	pj_gettimeofday(&tls->last_activity);
-    }
-}
-
-
-/* Add tdata to pending list */
-static void add_pending_tx(struct tls_transport *tls,
-			   pjsip_tx_data *tdata)
-{
-    struct delayed_tdata *delayed_tdata;
-
-    delayed_tdata = PJ_POOL_ALLOC_T(tdata->pool, struct delayed_tdata);
-    delayed_tdata->tdata_op_key = &tdata->op_key;
-    pj_list_push_back(&tls->delayed_list, delayed_tdata);
-}
-
-
-/* 
- * This callback is called by transport manager to send SIP message 
- */
-static pj_status_t tls_send_msg(pjsip_transport *transport, 
-				pjsip_tx_data *tdata,
-				const pj_sockaddr_t *rem_addr,
-				int addr_len,
-				void *token,
-				void (*callback)(pjsip_transport *transport,
-						 void *token, 
-						 pj_ssize_t sent_bytes))
-{
-    struct tls_transport *tls = (struct tls_transport*)transport;
-    pj_ssize_t size;
-    pj_bool_t delayed = PJ_FALSE;
-    pj_status_t status = PJ_SUCCESS;
-
-    /* Sanity check */
-    PJ_ASSERT_RETURN(transport && tdata, PJ_EINVAL);
-
-    /* Check that there's no pending operation associated with the tdata */
-    PJ_ASSERT_RETURN(tdata->op_key.tdata == NULL, PJSIP_EPENDINGTX);
-    
-    /* Check the address is supported */
-    PJ_ASSERT_RETURN(rem_addr && addr_len==sizeof(pj_sockaddr_in), PJ_EINVAL);
-
-
-
-    /* Init op key. */
-    tdata->op_key.tdata = tdata;
-    tdata->op_key.token = token;
-    tdata->op_key.callback = callback;
-
-    /* If asynchronous connect() has not completed yet, just put the
-     * transmit data in the pending transmission list since we can not
-     * use the socket yet.
-     */
-    if (tls->has_pending_connect) {
-
-	/*
-	 * Looks like connect() is still in progress. Check again (this time
-	 * with holding the lock) to be sure.
-	 */
-	pj_lock_acquire(tls->base.lock);
-
-	if (tls->has_pending_connect) {
-	    /*
-	     * connect() is still in progress. Put the transmit data to
-	     * the delayed list.
-	     */
-	    add_pending_tx(tls, tdata);
-	    status = PJ_EPENDING;
-
-	    /* Prevent ssl_write() to be called below */
-	    delayed = PJ_TRUE;
-	}
-
-	pj_lock_release(tls->base.lock);
-    } 
-    
-    if (!delayed) {
-
-	pj_bool_t no_pending_tx;
-
-	/* Make sure that we've flushed pending tx first so that
-	 * stream is in order.
-	 */
-	no_pending_tx = tls_flush_pending_tx(tls);
-
-	/* Send data immediately with SSL_write() if we don't have
-	 * pending data in our list.
-	 */
-	if (no_pending_tx) {
-
-	    status = ssl_write(tls, tdata);
-
-	    /* On EWOULDBLOCK, put this tdata in the list */
-	    if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) {
-		add_pending_tx(tls, tdata);
-		status = PJ_EPENDING;
-	    }
-
-	    if (status != PJ_EPENDING) {
-		/* Not pending (could be immediate success or error) */
-		tdata->op_key.tdata = NULL;
-
-		/* Shutdown transport on closure/errors */
-		if (status != PJ_SUCCESS) {
-		    size = -status;
-
-		    ssl_report_error(tls->base.obj_name, 4, status,
-				     "TLS send() error");
-
-		    if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
-		    pjsip_transport_shutdown(&tls->base);
-		}
-	    }
-
-	} else {
-	    /* We have pending data in our list, so queue the txdata
-	     * in the pending tx list.
-	     */
-	    add_pending_tx(tls, tdata);
-	    status = PJ_EPENDING;
-	}
-    }
-
-    return status;
-}
-
-
-/* 
- * This callback is called by transport manager to shutdown transport.
- * This normally is only used by UDP transport.
- */
-static pj_status_t tls_shutdown(pjsip_transport *transport)
-{
-    struct tls_transport *tls = (struct tls_transport*)transport;
-
-    /* Shutdown SSL */
-    if (!tls->ssl_shutdown_called) {
-	/* shutdown SSL */
-	SSL_shutdown(tls->ssl);
-	tls->ssl_shutdown_called = PJ_TRUE;
-
-	/* Stop keep-alive timer. */
-	if (tls->ka_timer.id) {
-	    pjsip_endpt_cancel_timer(tls->base.endpt, &tls->ka_timer);
-	    tls->ka_timer.id = PJ_FALSE;
-	}
-
-	PJ_LOG(4,(transport->obj_name, "TLS transport shutdown"));
-    }
-
-    return PJ_SUCCESS;
-}
-
-
-/* 
- * Callback from ioqueue that an incoming data is received from the socket.
- */
-static void on_read_complete(pj_ioqueue_key_t *key, 
-                             pj_ioqueue_op_key_t *op_key, 
-                             pj_ssize_t bytes_read_unused)
-{
-    enum { MAX_IMMEDIATE_PACKET = 10 };
-    pjsip_rx_data_op_key *rdata_op_key = (pjsip_rx_data_op_key*) op_key;
-    pjsip_rx_data *rdata = rdata_op_key->rdata;
-    struct tls_transport *tls = 
-	(struct tls_transport*)rdata->tp_info.transport;
-    int i;
-    pj_status_t status;
-
-    /* Don't do anything if transport is closing. */
-    if (tls->is_closing) {
-	tls->is_closing++;
-	return;
-    }
-
-
-    /* Recall that we use MSG_PEEK when calling ioqueue_recv(), so
-     * when this callback is called, data has not actually been read
-     * from socket buffer.
-     */
-
-    for (i=0;; ++i) {
-	pj_uint32_t flags;
-
-	/* Read data from SSL connection */
-	status = ssl_read(tls);
-
-	if (status == PJ_SUCCESS) {
-	    /*
-	     * We have packet!
-	     */
-	    pj_size_t size_eaten;
-
-	    /* Mark last activity */
-	    pj_gettimeofday(&tls->last_activity);
-
-	    /* Init pkt_info part. */
-	    rdata->pkt_info.zero = 0;
-	    pj_gettimeofday(&rdata->pkt_info.timestamp);
-
-	    /* Report to transport manager.
-	     * The transport manager will tell us how many bytes of the packet
-	     * have been processed (as valid SIP message).
-	     */
-	    size_eaten = 
-		pjsip_tpmgr_receive_packet(rdata->tp_info.transport->tpmgr, 
-					   rdata);
-
-	    pj_assert(size_eaten <= (pj_size_t)rdata->pkt_info.len);
-
-	    /* Move unprocessed data to the front of the buffer */
-	    if (size_eaten>0 && size_eaten<(pj_size_t)rdata->pkt_info.len) {
-		pj_memmove(rdata->pkt_info.packet,
-			   rdata->pkt_info.packet + size_eaten,
-			   rdata->pkt_info.len - size_eaten);
-	    }
-	    
-	    rdata->pkt_info.len -= size_eaten;
-
-	} else if (status == PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK)) {
-
-	    /* Ignore EWOULDBLOCK error (?) */
-
-	} else {
-
-	    /* For other errors, treat as transport being closed */
-	    ssl_report_error(tls->base.obj_name, 4, status,
-			     "Error reading SSL stream");
-	    
-	    /* We can not destroy the transport since high level objects may
-	     * still keep reference to this transport. So we can only 
-	     * instruct transport manager to gracefully start the shutdown
-	     * procedure for this transport.
-	     */
-	    if (tls->close_reason==PJ_SUCCESS) 
-		tls->close_reason = status;
-	    pjsip_transport_shutdown(&tls->base);
-
-	    return;
-	}
-
-	/* Reset pool. */
-	pj_pool_reset(rdata->tp_info.pool);
-
-	/* If we have pending data in SSL buffer, read it. */
-	if (SSL_pending(tls->ssl)) {
-
-	    /* Check that we have enough space in buffer */
-	    if (rdata->pkt_info.len >= PJSIP_MAX_PKT_LEN-1) {
-		PJ_LOG(4,(tls->base.obj_name, 
-			  "Incoming packet dropped from tls:%.*s:%d "
-			  "because it's too big (%d bytes)",
-			  (int)tls->base.remote_name.host.slen,
-			  tls->base.remote_name.host.ptr,
-			  tls->base.remote_name.port,
-			  rdata->pkt_info.len));
-		rdata->pkt_info.len = 0;
-	    }
-
-	    continue;
-	}
-
-	/* If we've reached maximum number of packets received on a single
-	 * poll, force the next reading to be asynchronous.
-	 */
-	if (i >= MAX_IMMEDIATE_PACKET) {
-	    /* Receive quota reached. Force ioqueue_recv() to 
-	     * return PJ_EPENDING 
-	     */
-	    flags = PJ_IOQUEUE_ALWAYS_ASYNC;
-	} else {
-	    /* This doesn't work too well when IOCP is used, as it seems that
-	     * IOCP refuses to do MSG_PEEK when WSARecv() is called without
-	     * OVERLAP structure. With OpenSSL it gives this error:
-	     * error:1408F10B:SSL routines:SSL3_GET_RECORD:wrong version 
-	     * number
-	     *
-	     * flags = 0 
-	     */
-	    flags = PJ_IOQUEUE_ALWAYS_ASYNC;
-	}
-
-	/* Read next packet from the network. Remember, we need to use
-	 * MSG_PEEK or otherwise the packet will be eaten by us!
-	 */
-	bytes_read_unused = 1;
-	status = pj_ioqueue_recv(key, op_key, 
-				 rdata->pkt_info.packet+rdata->pkt_info.len,
-				 &bytes_read_unused, flags | PJ_MSG_PEEK);
-
-	if (status == PJ_SUCCESS) {
-
-	    /* Continue loop. */
-	    pj_assert(i < MAX_IMMEDIATE_PACKET);
-
-	} else if (status == PJ_EPENDING) {
-	    break;
-
-	} else {
-	    /* Socket error */
-
-	    /* We can not destroy the transport since high level objects may
-	     * still keep reference to this transport. So we can only 
-	     * instruct transport manager to gracefully start the shutdown
-	     * procedure for this transport.
-	     */
-	    if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
-	    pjsip_transport_shutdown(&tls->base);
-
-	    return;
-	}
-    }
-}
-
-
-/* 
- * Callback from ioqueue when asynchronous connect() operation completes.
- */
-static void on_connect_complete(pj_ioqueue_key_t *key, 
-                                pj_status_t status)
-{
-    struct tls_transport *tls;
-    pj_sockaddr_in addr;
-    int addrlen;
-
-    tls = (struct tls_transport*) pj_ioqueue_get_user_data(key);
-
-    /* Check connect() status */
-    if (status != PJ_SUCCESS) {
-
-	/* Mark that pending connect() operation has completed. */
-	tls->has_pending_connect = PJ_FALSE;
-
-	ssl_report_error(tls->base.obj_name, 4, status,
-			 "Error connecting to %.*s:%d",
-			 (int)tls->base.remote_name.host.slen,
-			 tls->base.remote_name.host.ptr,
-			 tls->base.remote_name.port);
-
-	/* Cancel all delayed transmits */
-	while (!pj_list_empty(&tls->delayed_list)) {
-	    struct delayed_tdata *pending_tx;
-	    pj_ioqueue_op_key_t *op_key;
-
-	    pending_tx = tls->delayed_list.next;
-	    pj_list_erase(pending_tx);
-
-	    op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
-
-	    on_write_complete(tls->key, op_key, -status);
-	}
-
-	/* We can not destroy the transport since high level objects may
-	 * still keep reference to this transport. So we can only 
-	 * instruct transport manager to gracefully start the shutdown
-	 * procedure for this transport.
-	 */
-	if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
-	pjsip_transport_shutdown(&tls->base);
-	return;
-    }
-
-    PJ_LOG(4,(tls->base.obj_name, 
-	      "TCP transport %.*s:%d is connected to %.*s:%d",
-	      (int)tls->base.local_name.host.slen,
-	      tls->base.local_name.host.ptr,
-	      tls->base.local_name.port,
-	      (int)tls->base.remote_name.host.slen,
-	      tls->base.remote_name.host.ptr,
-	      tls->base.remote_name.port));
-
-
-    /* Update (again) local address, just in case local address currently
-     * set is different now that the socket is connected (could happen
-     * on some systems, like old Win32 probably?).
-     */
-    addrlen = sizeof(pj_sockaddr_in);
-    if (pj_sock_getsockname(tls->sock, &addr, &addrlen)==PJ_SUCCESS) {
-	pj_sockaddr_in *tp_addr = (pj_sockaddr_in*)&tls->base.local_addr;
-
-	if (tp_addr->sin_addr.s_addr != addr.sin_addr.s_addr) {
-	    tp_addr->sin_addr.s_addr = addr.sin_addr.s_addr;
-	    tp_addr->sin_port = addr.sin_port;
-	    sockaddr_to_host_port(tls->base.pool, &tls->base.local_name,
-				  tp_addr);
-	}
-    }
-
-    /* Perform SSL_connect() */
-    status = ssl_connect(tls);
-    if (status != PJ_SUCCESS) {
-
-	/* Cancel all delayed transmits */
-	while (!pj_list_empty(&tls->delayed_list)) {
-	    struct delayed_tdata *pending_tx;
-	    pj_ioqueue_op_key_t *op_key;
-
-	    pending_tx = tls->delayed_list.next;
-	    pj_list_erase(pending_tx);
-
-	    op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
-
-	    on_write_complete(tls->key, op_key, -status);
-	}
-
-	if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
-	pjsip_transport_shutdown(&tls->base);
-	return;
-    }
-
-    /* Mark that pending connect() operation has completed. */
-    tls->has_pending_connect = PJ_FALSE;
-
-    /* Start pending read */
-    status = tls_start_read(tls);
-    if (status != PJ_SUCCESS) {
-
-	/* Cancel all delayed transmits */
-	while (!pj_list_empty(&tls->delayed_list)) {
-	    struct delayed_tdata *pending_tx;
-	    pj_ioqueue_op_key_t *op_key;
-
-	    pending_tx = tls->delayed_list.next;
-	    pj_list_erase(pending_tx);
-
-	    op_key = (pj_ioqueue_op_key_t*)pending_tx->tdata_op_key;
-
-	    on_write_complete(tls->key, op_key, -status);
-	}
-
-
-	/* We can not destroy the transport since high level objects may
-	 * still keep reference to this transport. So we can only 
-	 * instruct transport manager to gracefully start the shutdown
-	 * procedure for this transport.
-	 */
-	if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
-	pjsip_transport_shutdown(&tls->base);
-	return;
-    }
-
-    /* Flush all pending send operations */
-    tls_flush_pending_tx(tls);
-
-    /* Start keep-alive timer */
-    if (PJSIP_TLS_KEEP_ALIVE_INTERVAL) {
-	pj_time_val delay = { PJSIP_TLS_KEEP_ALIVE_INTERVAL, 0 };
-	pjsip_endpt_schedule_timer(tls->base.endpt, &tls->ka_timer, 
-				   &delay);
-	tls->ka_timer.id = PJ_TRUE;
-	pj_gettimeofday(&tls->last_activity);
-    }
-
-}
-
-
-/* Transport keep-alive timer callback */
-static void tls_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e)
-{
-    struct tls_transport *tls = (struct tls_transport*) e->user_data;
-    const pj_str_t ka_data = PJSIP_TLS_KEEP_ALIVE_DATA;
-    pj_time_val delay;
-    pj_time_val now;
-    pj_status_t status;
-
-    PJ_UNUSED_ARG(th);
-
-    tls->ka_timer.id = PJ_TRUE;
-
-    pj_gettimeofday(&now);
-    PJ_TIME_VAL_SUB(now, tls->last_activity);
-
-    if (now.sec > 0 && now.sec < PJSIP_TLS_KEEP_ALIVE_INTERVAL) {
-	/* There has been activity, so don't send keep-alive */
-	delay.sec = PJSIP_TLS_KEEP_ALIVE_INTERVAL - now.sec;
-	delay.msec = 0;
-
-	pjsip_endpt_schedule_timer(tls->base.endpt, &tls->ka_timer, 
-				   &delay);
-	tls->ka_timer.id = PJ_TRUE;
-	return;
-    }
-
-    PJ_LOG(5,(tls->base.obj_name, "Sending %d byte(s) keep-alive to %.*s:%d", 
-	      (int)ka_data.slen, (int)tls->base.remote_name.host.slen,
-	      tls->base.remote_name.host.ptr,
-	      tls->base.remote_name.port));
-
-    /* Send the data */
-    status = ssl_write_bytes(tls, ka_data.ptr, (int)ka_data.slen, 
-			     "keep-alive");
-    if (status != PJ_SUCCESS && 
-	status != PJ_STATUS_FROM_OS(OSERR_EWOULDBLOCK))
-    {
-	ssl_report_error(tls->base.obj_name, 1, status,
-			 "Error sending keep-alive packet");
-	return;
-    }
-
-    /* Register next keep-alive */
-    delay.sec = PJSIP_TLS_KEEP_ALIVE_INTERVAL;
-    delay.msec = 0;
-
-    pjsip_endpt_schedule_timer(tls->base.endpt, &tls->ka_timer, 
-			       &delay);
-    tls->ka_timer.id = PJ_TRUE;
-}
-
-#endif	/* PJSIP_HAS_TLS_TRANSPORT */
-
