Index: pjproject/trunk/pjsip/build/pjsip_core.dsp
===================================================================
--- pjproject/trunk/pjsip/build/pjsip_core.dsp	(revision 1472)
+++ pjproject/trunk/pjsip/build/pjsip_core.dsp	(revision 1473)
@@ -41,4 +41,5 @@
 # PROP Intermediate_Dir ".\output\pjsip-core-i386-win32-vc6-release"
 # PROP Target_Dir ""
+F90=df.exe
 # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c
 # ADD CPP /nologo /MD /W4 /Zi /O2 /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "NDEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /c
@@ -65,4 +66,5 @@
 # PROP Intermediate_Dir ".\output\pjsip-core-i386-win32-vc6-debug"
 # PROP Target_Dir ""
+F90=df.exe
 # ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c
 # ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /I "../include" /I "../../pjlib/include" /I "../../pjlib-util/include" /D "_DEBUG" /D "WIN32" /D "_MBCS" /D "_LIB" /D PJ_WIN32=1 /D PJ_M_I386=1 /FR /FD /GZ /c
Index: pjproject/trunk/pjsip/include/pjsip/sip_config.h
===================================================================
--- pjproject/trunk/pjsip/include/pjsip/sip_config.h	(revision 1472)
+++ pjproject/trunk/pjsip/include/pjsip/sip_config.h	(revision 1473)
@@ -266,8 +266,8 @@
  * before the transport is destroyed. Value is in seconds.
  *
- * Default: 60
+ * Default: 600
  */
 #ifndef PJSIP_TRANSPORT_IDLE_TIME
-#   define PJSIP_TRANSPORT_IDLE_TIME	60
+#   define PJSIP_TRANSPORT_IDLE_TIME	600
 #endif
 
@@ -295,4 +295,50 @@
 #ifndef PJSIP_TCP_TRANSPORT_BACKLOG
 #   define PJSIP_TCP_TRANSPORT_BACKLOG	5
+#endif
+
+
+/**
+ * Set the interval to send keep-alive packet for TCP transports.
+ * If the value is zero, keep-alive will be disabled for TCP.
+ *
+ * Default: 90 (seconds)
+ *
+ * @see PJSIP_TCP_KEEP_ALIVE_DATA
+ */
+#ifndef PJSIP_TCP_KEEP_ALIVE_INTERVAL
+#   define PJSIP_TCP_KEEP_ALIVE_INTERVAL    90
+#endif
+
+
+/**
+ * Set the payload of the TCP keep-alive packet.
+ *
+ * Default: CRLF
+ */
+#ifndef PJSIP_TCP_KEEP_ALIVE_DATA
+#   define PJSIP_TCP_KEEP_ALIVE_DATA	    { "\r\n", 2 }
+#endif
+
+
+/**
+ * Set the interval to send keep-alive packet for TLS transports.
+ * If the value is zero, keep-alive will be disabled for TLS.
+ *
+ * Default: 90 (seconds)
+ *
+ * @see PJSIP_TLS_KEEP_ALIVE_DATA
+ */
+#ifndef PJSIP_TLS_KEEP_ALIVE_INTERVAL
+#   define PJSIP_TLS_KEEP_ALIVE_INTERVAL    90
+#endif
+
+
+/**
+ * Set the payload of the TLS keep-alive packet.
+ *
+ * Default: CRLF
+ */
+#ifndef PJSIP_TLS_KEEP_ALIVE_DATA
+#   define PJSIP_TLS_KEEP_ALIVE_DATA	    { "\r\n", 2 }
 #endif
 
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 1472)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport_tcp.c	(revision 1473)
@@ -42,5 +42,4 @@
 #define POOL_TP_INC	4002
 
-
 struct tcp_listener;
 struct tcp_transport;
@@ -113,4 +112,9 @@
     pj_bool_t		     has_pending_connect;
 
+    /* Keep-alive timer. */
+    pj_timer_entry	     ka_timer;
+    pj_time_val		     last_activity;
+    pjsip_tx_data_op_key     ka_op_key;
+    pj_str_t		     ka_pkt;
 
     /* TCP transport can only have  one rdata!
@@ -477,4 +481,6 @@
                                 pj_status_t status);
 
+/* TCP keep-alive timer callback */
+static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e);
 
 /*
@@ -492,4 +498,5 @@
     pj_ioqueue_t *ioqueue;
     pj_ioqueue_callback tcp_callback;
+    const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA;
     pj_status_t status;
     
@@ -569,4 +576,10 @@
 
     tcp->is_registered = PJ_TRUE;
+
+    /* Initialize keep-alive timer */
+    tcp->ka_timer.user_data = (void*)tcp;
+    tcp->ka_timer.cb = &tcp_keep_alive_timer;
+    pj_ioqueue_op_key_init(&tcp->ka_op_key.key, sizeof(pj_ioqueue_op_key_t));
+    pj_strdup(tcp->base.pool, &tcp->ka_pkt, &ka_pkt);
 
     /* Done setting up basic transport. */
@@ -967,4 +980,14 @@
 		    PJ_LOG(3,(tcp->base.obj_name, "New transport cancelled"));
 		    tcp_destroy(&tcp->base, status);
+		} else {
+		    /* Start keep-alive timer */
+		    if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
+			pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0};
+			pjsip_endpt_schedule_timer(listener->endpt, 
+						   &tcp->ka_timer, 
+						   &delay);
+			tcp->ka_timer.id = PJ_TRUE;
+			pj_gettimeofday(&tcp->last_activity);
+		    }
 		}
 	    }
@@ -1006,4 +1029,8 @@
     pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key;
 
+    /* Note that op_key may be the op_key from keep-alive, thus
+     * it will not have tdata etc.
+     */
+
     tdata_op_key->tdata = NULL;
 
@@ -1026,4 +1053,7 @@
 	 */
 	tdata_op_key->callback(&tcp->base, tdata_op_key->token, bytes_sent);
+
+	/* Mark last activity time */
+	pj_gettimeofday(&tcp->last_activity);
     }
 }
@@ -1128,12 +1158,15 @@
 /* 
  * This callback is called by transport manager to shutdown transport.
- * This normally is only used by UDP transport.
  */
 static pj_status_t tcp_shutdown(pjsip_transport *transport)
 {
-
-    PJ_UNUSED_ARG(transport);
-
-    /* Nothing to do for TCP */
+    struct tcp_transport *tcp = (struct tcp_transport*)transport;
+    
+    /* Stop keep-alive timer. */
+    if (tcp->ka_timer.id) {
+	pjsip_endpt_cancel_timer(tcp->listener->endpt, &tcp->ka_timer);
+	tcp->ka_timer.id = PJ_FALSE;
+    }
+
     return PJ_SUCCESS;
 }
@@ -1175,4 +1208,7 @@
 	if (bytes_read > 0) {
 	    pj_size_t size_eaten;
+
+	    /* Mark this as an activity */
+	    pj_gettimeofday(&tcp->last_activity);
 
 	    /* Init pkt_info part. */
@@ -1365,5 +1401,68 @@
     /* Flush all pending send operations */
     tcp_flush_pending_tx(tcp);
-}
+
+    /* Start keep-alive timer */
+    if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
+	pj_time_val delay = { PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0 };
+	pjsip_endpt_schedule_timer(tcp->listener->endpt, &tcp->ka_timer, 
+				   &delay);
+	tcp->ka_timer.id = PJ_TRUE;
+	pj_gettimeofday(&tcp->last_activity);
+    }
+}
+
+/* Transport keep-alive timer callback */
+static void tcp_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e)
+{
+    struct tcp_transport *tcp = (struct tcp_transport*) e->user_data;
+    pj_time_val delay;
+    pj_time_val now;
+    pj_ssize_t size;
+    pj_status_t status;
+
+    PJ_UNUSED_ARG(th);
+
+    tcp->ka_timer.id = PJ_TRUE;
+
+    pj_gettimeofday(&now);
+    PJ_TIME_VAL_SUB(now, tcp->last_activity);
+
+    if (now.sec > 0 && now.sec < PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
+	/* There has been activity, so don't send keep-alive */
+	delay.sec = PJSIP_TCP_KEEP_ALIVE_INTERVAL - now.sec;
+	delay.msec = 0;
+
+	pjsip_endpt_schedule_timer(tcp->listener->endpt, &tcp->ka_timer, 
+				   &delay);
+	tcp->ka_timer.id = PJ_TRUE;
+	return;
+    }
+
+    PJ_LOG(5,(tcp->base.obj_name, "Sending %d byte(s) keep-alive to %.*s:%d", 
+	      (int)tcp->ka_pkt.slen, (int)tcp->base.remote_name.host.slen,
+	      tcp->base.remote_name.host.ptr,
+	      tcp->base.remote_name.port));
+
+    /* Send the data */
+    size = tcp->ka_pkt.slen;
+    status = pj_ioqueue_send(tcp->key, &tcp->ka_op_key.key,
+			     tcp->ka_pkt.ptr, &size, 0);
+
+    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
+	tcp_perror(tcp->base.obj_name, 
+		   "Error sending keep-alive packet", status);
+	pjsip_transport_shutdown(&tcp->base);
+	return;
+    }
+
+    /* Register next keep-alive */
+    delay.sec = PJSIP_TCP_KEEP_ALIVE_INTERVAL;
+    delay.msec = 0;
+
+    pjsip_endpt_schedule_timer(tcp->listener->endpt, &tcp->ka_timer, 
+			       &delay);
+    tcp->ka_timer.id = PJ_TRUE;
+}
+
 
 #endif	/* PJ_HAS_TCP */
Index: pjproject/trunk/pjsip/src/pjsip/sip_transport_tls_ossl.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip/sip_transport_tls_ossl.c	(revision 1472)
+++ pjproject/trunk/pjsip/src/pjsip/sip_transport_tls_ossl.c	(revision 1473)
@@ -167,4 +167,8 @@
     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!
@@ -742,13 +746,14 @@
 
 /* Send outgoing data with SSL connection */
-static pj_status_t ssl_write(struct tls_transport *tls,
-			     pjsip_tx_data *tdata)
-{
-    int size = tdata->buf.cur - tdata->buf.start;
+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,
-					    tdata->buf.start + sent, 
+					    ((pj_uint8_t*)data) + sent, 
 					    size - sent);
     
@@ -799,5 +804,5 @@
 	    ssl_report_error(tls->base.obj_name, 4, PJ_SUCCESS,
 			     "Error sending %s with SSL_write()",
-			     pjsip_tx_data_get_info(tdata));
+			     data_name);
 	    return pj_get_netos_error() ? pj_get_netos_error() 
 		    : PJSIP_TLS_ESEND;
@@ -807,4 +812,14 @@
 
     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));
 }
 
@@ -1162,4 +1177,6 @@
                                 pj_status_t status);
 
+/* TLS keep-alive timer callback */
+static void tls_keep_alive_timer(pj_timer_heap_t *th, pj_timer_entry *e);
 
 /*
@@ -1204,5 +1221,5 @@
 
     /* Initialize transport reference counter to 1 */
-    status = pj_atomic_create(pool, 1, &tls->base.ref_cnt);
+    status = pj_atomic_create(pool, 0, &tls->base.ref_cnt);
     if (status != PJ_SUCCESS) {
 	goto on_error;
@@ -1273,4 +1290,9 @@
 
     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. */
@@ -1724,4 +1746,15 @@
 				 "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);
+		}
 	    }
 
@@ -1775,4 +1808,7 @@
 	if (tls->close_reason==PJ_SUCCESS) tls->close_reason = status;
 	pjsip_transport_shutdown(&tls->base);
+    } else {
+	/* Mark last activity */
+	pj_gettimeofday(&tls->last_activity);
     }
 
@@ -1919,6 +1955,5 @@
     /* Shutdown SSL */
     if (!tls->ssl_shutdown_called) {
-	/* Release our reference counter and shutdown SSL */
-	pjsip_transport_dec_ref(transport);
+	/* shutdown SSL */
 	SSL_shutdown(tls->ssl);
 	tls->ssl_shutdown_called = PJ_TRUE;
@@ -1969,4 +2004,7 @@
 	     */
 	    pj_size_t size_eaten;
+
+	    /* Mark last activity */
+	    pj_gettimeofday(&tls->last_activity);
 
 	    /* Init pkt_info part. */
@@ -2217,4 +2255,67 @@
     /* 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->listener->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->listener->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->listener->endpt, &tls->ka_timer, 
+			       &delay);
+    tls->ka_timer.id = PJ_TRUE;
 }
 
