From 0d46f77fe2cd2e3197f3b7b745d822b6c1cb9790 Mon Sep 17 00:00:00 2001
From: jrun <darwinskernel@gmail.com>
Date: Thu, 27 Feb 2020 12:57:17 -0500
Subject: [PATCH 3/9] add tcp keep alive

---
 pjlib/include/pj/sock.h             | 29 +++++++++++++++++++
 pjlib/src/pj/sock_bsd.c             | 45 +++++++++++++++++++++++++++++
 pjlib/src/pj/sock_common.c          | 20 +++++++++++++
 pjlib/src/pj/sock_uwp.cpp           | 24 +++++++++++++++
 pjlib/src/pj/symbols.c              |  3 ++
 pjnath/include/pjnath/ice_session.h |  5 ++++
 pjnath/include/pjnath/ice_strans.h  |  7 +++++
 pjnath/src/pjnath/ice_session.c     |  6 ++++
 pjnath/src/pjnath/ice_strans.c      | 10 +++++++
 9 files changed, 149 insertions(+)

diff --git a/pjlib/include/pj/sock.h b/pjlib/include/pj/sock.h
index 4daf298c5..095a38335 100644
--- a/pjlib/include/pj/sock.h
+++ b/pjlib/include/pj/sock.h
@@ -313,6 +313,11 @@ extern const pj_uint16_t PJ_SO_REUSEADDR;
 /** Do not generate SIGPIPE. @see pj_SO_NOSIGPIPE */
 extern const pj_uint16_t PJ_SO_NOSIGPIPE;
 
+extern const pj_uint16_t PJ_SO_KEEPALIVE;
+extern const pj_uint16_t PJ_TCP_KEEPIDLE;
+extern const pj_uint16_t PJ_TCP_KEEPINTVL;
+extern const pj_uint16_t PJ_TCP_KEEPCNT;
+
 /** Set the protocol-defined priority for all packets to be sent on socket.
  */
 extern const pj_uint16_t PJ_SO_PRIORITY;
@@ -343,9 +348,21 @@ extern const pj_uint16_t PJ_IP_DROP_MEMBERSHIP;
     /** Get #PJ_SO_SNDBUF constant */
     PJ_DECL(pj_uint16_t) pj_SO_SNDBUF(void);
 
+    /** Get #PJ_SO_KEEPALIVE constant */
+#   define pj_SO_KEEPALIVE() PJ_SO_KEEPALIVE(void);
+
     /** Get #PJ_TCP_NODELAY constant */
     PJ_DECL(pj_uint16_t) pj_TCP_NODELAY(void);
 
+    /** Get #PJ_TCP_KEEPIDLE constant */
+#   define pj_TCP_KEEPIDLE() PJ_TCP_KEEPIDLE(void);
+
+    /** Get #PJ_TCP_KEEPINTVL constant */
+#   define pj_TCP_KEEPINTVL() PJ_TCP_KEEPINTVL(void);
+
+    /** Get #PJ_TCP_KEEPCNT constant */
+#   define pj_TCP_KEEPCNT() PJ_TCP_KEEPCNT(void);
+
     /** Get #PJ_SO_REUSEADDR constant */
     PJ_DECL(pj_uint16_t) pj_SO_REUSEADDR(void);
 
@@ -379,9 +396,21 @@ extern const pj_uint16_t PJ_IP_DROP_MEMBERSHIP;
     /** Get #PJ_SO_SNDBUF constant */
 #   define pj_SO_SNDBUF()   PJ_SO_SNDBUF
 
+    /** Get #PJ_SO_KEEPALIVE constant */
+#   define pj_SO_KEEPALIVE() PJ_SO_KEEPALIVE
+
     /** Get #PJ_TCP_NODELAY constant */
 #   define pj_TCP_NODELAY() PJ_TCP_NODELAY
 
+    /** Get #PJ_TCP_KEEPIDLE constant */
+#   define pj_TCP_KEEPIDLE() PJ_TCP_KEEPIDLE
+
+    /** Get #PJ_TCP_KEEPINTVL constant */
+#   define pj_TCP_KEEPINTVL() PJ_TCP_KEEPINTVL
+
+    /** Get #PJ_TCP_KEEPCNT constant */
+#   define pj_TCP_KEEPCNT() PJ_TCP_KEEPCNT
+
     /** Get #PJ_SO_REUSEADDR constant */
 #   define pj_SO_REUSEADDR() PJ_SO_REUSEADDR
 
diff --git a/pjlib/src/pj/sock_bsd.c b/pjlib/src/pj/sock_bsd.c
index e416991de..0e9bfdbe9 100644
--- a/pjlib/src/pj/sock_bsd.c
+++ b/pjlib/src/pj/sock_bsd.c
@@ -28,6 +28,15 @@
 
 #define THIS_FILE	"sock_bsd.c"
 
+#if !defined(PJ_WIN32) && !defined(PJ_WIN64)
+# if !defined(SOL_TCP) && defined(IPPROTO_TCP)
+#  define SOL_TCP IPPROTO_TCP
+# endif
+# if !defined(TCP_KEEPIDLE) && defined(TCP_KEEPALIVE)
+#  define TCP_KEEPIDLE TCP_KEEPALIVE
+# endif
+#endif
+
 /*
  * Address families conversion.
  * The values here are indexed based on pj_addr_family.
@@ -144,7 +153,19 @@ const pj_uint16_t PJ_IPV6_TCLASS = 0xFFFF;
 const pj_uint16_t PJ_SO_TYPE    = SO_TYPE;
 const pj_uint16_t PJ_SO_RCVBUF  = SO_RCVBUF;
 const pj_uint16_t PJ_SO_SNDBUF  = SO_SNDBUF;
+const pj_uint16_t PJ_SO_KEEPALIVE = SO_KEEPALIVE;
 const pj_uint16_t PJ_TCP_NODELAY= TCP_NODELAY;
+#if !defined(PJ_WIN32) && !defined(PJ_WIN64)
+# ifdef TCP_KEEPIDLE
+const pj_uint16_t PJ_TCP_KEEPIDLE = TCP_KEEPIDLE;
+# endif
+# ifdef TCP_KEEPINTVL
+const pj_uint16_t PJ_TCP_KEEPINTVL = TCP_KEEPINTVL;
+# endif
+# ifdef TCP_KEEPCNT
+const pj_uint16_t PJ_TCP_KEEPCNT = TCP_KEEPCNT;
+# endif
+#endif
 const pj_uint16_t PJ_SO_REUSEADDR= SO_REUSEADDR;
 #ifdef SO_NOSIGPIPE
 const pj_uint16_t PJ_SO_NOSIGPIPE = SO_NOSIGPIPE;
@@ -517,6 +538,20 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af,
 	if (rc==SOCKET_ERROR) {
 	    // Ignored..
 	}
+    } else if(type == pj_SOCK_STREAM()) {
+#ifndef SIO_KEEPALIVE_VALS
+# define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR, 4)
+#endif
+	DWORD dwBytesReturned = 0;
+	struct tcp_keepalive {
+	    ULONG onoff;
+	    ULONG keepalivetime;
+	    ULONG keepaliveinterval;
+	} vals = { TRUE, 30000, 30000 };
+	WSAIoctl(*sock, SIO_KEEPALIVE_VALS,
+		 &vals, sizeof(vals),
+		 NULL, 0, &dwBytesReturned,
+		 NULL, NULL);
     }
 #endif
 
@@ -548,6 +583,16 @@ PJ_DEF(pj_status_t) pj_sock_socket(int af,
 	if (type == pj_SOCK_STREAM()) {
 	    pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_NOSIGPIPE(),
 			       &val, sizeof(val));
+	    pj_sock_setsockopt(*sock, pj_SOL_SOCKET(), pj_SO_KEEPALIVE(),
+			       &val, sizeof(val));
+	    pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_KEEPCNT(),
+			       &val, sizeof(val));
+	    val = 30;
+	    pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_KEEPIDLE(),
+			       &val, sizeof(val));
+	    pj_sock_setsockopt(*sock, pj_SOL_TCP(), pj_TCP_KEEPINTVL(),
+			       &val, sizeof(val));
+	    val = 1;
 	}
 #if defined(PJ_SOCK_HAS_IPV6_V6ONLY) && PJ_SOCK_HAS_IPV6_V6ONLY != 0
 	if (af == PJ_AF_INET6) {
diff --git a/pjlib/src/pj/sock_common.c b/pjlib/src/pj/sock_common.c
index 693f3af62..6beb28590 100644
--- a/pjlib/src/pj/sock_common.c
+++ b/pjlib/src/pj/sock_common.c
@@ -1346,11 +1346,31 @@ PJ_DEF(pj_uint16_t) pj_SO_SNDBUF(void)
     return PJ_SO_SNDBUF;
 }
 
+PJ_DEF(pj_uint16_t) pj_SO_KEEPALIVE(void)
+{
+    return PJ_SO_KEEPALIVE;
+}
+
 PJ_DEF(pj_uint16_t) pj_TCP_NODELAY(void)
 {
     return PJ_TCP_NODELAY;
 }
 
+PJ_DEF(pj_uint16_t) pj_TCP_KEEPIDLE(void)
+{
+    return PJ_TCP_KEEPIDLE
+}
+
+PJ_DEF(pj_uint16_t) pj_TCP_KEEPINTVL(void)
+{
+    return PJ_TCP_KEEPINTVL
+}
+
+PJ_DEF(pj_uint16_t) pj_TCP_KEEPCNT(void)
+{
+    return PJ_TCP_KEEPCNT
+}
+
 PJ_DEF(pj_uint16_t) pj_SO_REUSEADDR(void)
 {
     return PJ_SO_REUSEADDR;
diff --git a/pjlib/src/pj/sock_uwp.cpp b/pjlib/src/pj/sock_uwp.cpp
index 876c3287a..34baebcee 100644
--- a/pjlib/src/pj/sock_uwp.cpp
+++ b/pjlib/src/pj/sock_uwp.cpp
@@ -69,6 +69,24 @@ const pj_uint16_t PJ_SOL_IP	= IPPROTO_IP;
 const pj_uint16_t PJ_SOL_IP	= 0;
 #endif /* SOL_IP */
 
+#if defined(TCP_KEEPIDLE)
+const pj_uint16_t PJ_TCP_KEEPIDLE = TCP_KEEPIDLE;
+#else
+const pj_uint16_t PJ_TCP_KEEPIDLE = 4;
+#endif
+
+#if defined(TCP_KEEPINTVL)
+const pj_uint16_t PJ_TCP_KEEPINTVL = TCP_KEEPINTVL;
+#else
+const pj_uint16_t PJ_TCP_KEEPINTVL = 5;
+#endif
+
+#if defined(TCP_KEEPCNT)
+const pj_uint16_t PJ_TCP_KEEPCNT = TCP_KEEPCNT;
+#else
+const pj_uint16_t PJ_TCP_KEEPCNT = 6;
+#endif
+
 #if defined(SOL_TCP)
 const pj_uint16_t PJ_SOL_TCP	= SOL_TCP;
 #elif defined(IPPROTO_TCP)
@@ -79,6 +97,12 @@ const pj_uint16_t PJ_SOL_TCP	= IPPROTO_TCP;
 const pj_uint16_t PJ_SOL_TCP	= 6;
 #endif /* SOL_TCP */
 
+#if defined(SOL_KEEPALIVE)
+const pj_uint16_t PJ_SOL_KEEPALIVE = SOL_KEEPALIVE;
+#else
+const pj_uint16_t PJ_SOL_KEEPALIVE = 9;
+#endif
+
 #ifdef SOL_UDP
 const pj_uint16_t PJ_SOL_UDP	= SOL_UDP;
 #elif defined(IPPROTO_UDP)
diff --git a/pjlib/src/pj/symbols.c b/pjlib/src/pj/symbols.c
index ab83af956..966a9fc43 100644
--- a/pjlib/src/pj/symbols.c
+++ b/pjlib/src/pj/symbols.c
@@ -259,6 +259,9 @@ PJ_EXPORT_SYMBOL(PJ_SOCK_RAW)
 PJ_EXPORT_SYMBOL(PJ_SOCK_RDM)
 PJ_EXPORT_SYMBOL(PJ_SOL_SOCKET)
 PJ_EXPORT_SYMBOL(PJ_SOL_IP)
+PJ_EXPORT_SYMBOL(PJ_TCP_KEEPIDLE)
+PJ_EXPORT_SYMBOL(PJ_TCP_KEEPINTVL)
+PJ_EXPORT_SYMBOL(PJ_TCP_KEEPCNT)
 PJ_EXPORT_SYMBOL(PJ_SOL_TCP)
 PJ_EXPORT_SYMBOL(PJ_SOL_UDP)
 PJ_EXPORT_SYMBOL(PJ_SOL_IPV6)
diff --git a/pjnath/include/pjnath/ice_session.h b/pjnath/include/pjnath/ice_session.h
index 4cccd7c64..9f29b828e 100644
--- a/pjnath/include/pjnath/ice_session.h
+++ b/pjnath/include/pjnath/ice_session.h
@@ -628,6 +628,11 @@ typedef struct pj_ice_sess_cb
                                         pj_ice_sess_checklist *clist,
                                         unsigned check_id);
 
+    /**
+     * If an internal TCP keep alive, this mount the error to the application
+     */
+    void	(*on_ice_destroy)(pj_ice_sess *ice);
+
 } pj_ice_sess_cb;
 
 
diff --git a/pjnath/include/pjnath/ice_strans.h b/pjnath/include/pjnath/ice_strans.h
index 9eb74b35f..1269442cd 100644
--- a/pjnath/include/pjnath/ice_strans.h
+++ b/pjnath/include/pjnath/ice_strans.h
@@ -192,6 +192,13 @@ typedef struct pj_ice_strans_cb
 			       pj_ice_strans_op op,
 			       pj_status_t status);
 
+    /**
+     * This callback is called if an internal operation fails
+     *
+     * @param ice_st	    The ICE stream transport.
+     */
+    void (*on_destroy)(pj_ice_strans *ice_st);
+
 } pj_ice_strans_cb;
 
 
diff --git a/pjnath/src/pjnath/ice_session.c b/pjnath/src/pjnath/ice_session.c
index 20ba47a48..f1094932b 100644
--- a/pjnath/src/pjnath/ice_session.c
+++ b/pjnath/src/pjnath/ice_session.c
@@ -1435,6 +1435,12 @@ static void ice_keep_alive(pj_ice_sess *ice, pj_bool_t send_now)
 					  PJ_FALSE, PJ_FALSE, 
 					  &the_check->rcand->addr, 
 					  addr_len, tdata);
+	if (status != PJ_SUCCESS && status != PJ_EPENDING && status != PJ_EBUSY) {
+	    if (ice->cb.on_ice_destroy) {
+		ice->cb.on_ice_destroy(ice);
+	    }
+	    return;
+	}
 
 	/* Restore FINGERPRINT usage */
 	pj_stun_session_use_fingerprint(comp->stun_sess, saved);
diff --git a/pjnath/src/pjnath/ice_strans.c b/pjnath/src/pjnath/ice_strans.c
index 82175e9e8..c1647bebf 100644
--- a/pjnath/src/pjnath/ice_strans.c
+++ b/pjnath/src/pjnath/ice_strans.c
@@ -98,6 +98,7 @@ static pj_uint16_t GETVAL16H(const pj_uint8_t *buf1, const pj_uint8_t *buf2)
 //////////////////////////////////////////////////////////////////////////////
 
 /* ICE callbacks */
+static void	   on_ice_destroy(pj_ice_sess *ice);
 static void	   on_ice_complete(pj_ice_sess *ice, pj_status_t status);
 static pj_status_t ice_tx_pkt(pj_ice_sess *ice,
 			      unsigned comp_id,
@@ -1313,6 +1314,7 @@ PJ_DEF(pj_status_t) pj_ice_strans_init_ice(pj_ice_strans *ice_st,
     ice_cb.wait_tcp_connection      = &ice_wait_tcp_connection;
     ice_cb.reconnect_tcp_connection = &ice_reconnect_tcp_connection;
     ice_cb.close_tcp_connection     = &ice_close_tcp_connection;
+    ice_cb.on_ice_destroy           = &on_ice_destroy;
 #endif
 
     /* Create! */
@@ -1935,6 +1937,14 @@ PJ_DEF(pj_status_t) pj_ice_strans_sendto2(pj_ice_strans *ice_st,
     		     dst_addr_len, PJ_TRUE, PJ_FALSE);
 }
 
+static void on_ice_destroy(pj_ice_sess *ice)
+{
+    pj_ice_strans *ice_st = (pj_ice_strans*)ice->user_data;
+
+    if (ice_st->cb.on_destroy) {
+	(*ice_st->cb.on_destroy)(ice_st);
+    }
+}
 
 /*
  * Callback called by ICE session when ICE processing is complete, either
-- 
2.26.2