[sr-dev] git:master: core: mhomed: fix fd leak on error, ipv6, fd no

Andrei Pelinescu-Onciul andrei at iptel.org
Mon Feb 1 20:20:04 CET 2010


Module: sip-router
Branch: master
Commit: fe6207c8413f2f14d026bfe6eb1032fd903126d1
URL:    http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=fe6207c8413f2f14d026bfe6eb1032fd903126d1

Author: Andrei Pelinescu-Onciul <andrei at iptel.org>
Committer: Andrei Pelinescu-Onciul <andrei at iptel.org>
Date:   Mon Feb  1 20:15:27 2010 +0100

core: mhomed: fix fd leak on error, ipv6, fd no

- on error the cached fds were set to 0, without closing them. Now
  they are not overwritten anymore (opening another one would not
  help).
- try ipv6 only if USE_IPV6 is defined
- 0 is a valid value for a fd => changed the initial values and
  the comparisons to use -1 / <0
- if connect fails with EISCONN disable future caching of the
  socket (return to the old open new socket, connect(), close()
  mode). This way mhomed will work even in the unlikely case of
  an OS where connect()-ing multiple times the same udp socket is
  not allowed.

---

 forward.c |   50 ++++++++++++++++++++++++++++++++++----------------
 1 files changed, 34 insertions(+), 16 deletions(-)

diff --git a/forward.c b/forward.c
index c81e95a..2e6f05e 100644
--- a/forward.c
+++ b/forward.c
@@ -115,12 +115,15 @@
  * multihomed hosts
  */
 
-static int sock_inet = 0;
-static int sock_inet6 = 0;
+static int mhomed_sock_cache_disabled = 0;
+static int sock_inet = -1;
+#ifdef USE_IPV6
+static int sock_inet6 = -1;
+#endif /* USE_IPV6 */
 
 struct socket_info* get_out_socket(union sockaddr_union* to, int proto)
 {
-	int temp_sock;
+	int* temp_sock;
 	socklen_t len;
 	union sockaddr_union from; 
 	struct socket_info* si;
@@ -130,57 +133,72 @@ struct socket_info* get_out_socket(union sockaddr_union* to, int proto)
 		LOG(L_CRIT, "BUG: get_out_socket can only be called for UDP\n");
 		return 0;
 	}
-
+retry:
 	switch(to->s.sa_family){
 	case AF_INET : {
-		if(sock_inet <= 0){
+		if(sock_inet < 0){
 			sock_inet = socket(AF_INET, SOCK_DGRAM, 0);
 			if (sock_inet==-1) {
 				LM_ERR("socket() failed: %s\n", strerror(errno));
 				return 0;
 			}
 		}
-		temp_sock = sock_inet;
+		temp_sock = &sock_inet;
 		break;
 	}
+#ifdef USE_IPV6
 	case AF_INET6 : {
-		if(sock_inet6 <= 0){
+		if(sock_inet6 < 0){
 			sock_inet6 = socket(AF_INET6, SOCK_DGRAM, 0);
 			if (sock_inet6==-1) {
 				LM_ERR("socket() failed: %s\n", strerror(errno));
 				return 0;
 			}
 		}
-		temp_sock = sock_inet6;
+		temp_sock = &sock_inet6;
 		break;
- 	}
+	}
+#endif /* USE_IPV6 */
 	default: {
-		LM_ERR("Unknow protocol family \n");
+		LM_ERR("Unknown protocol family \n");
 		return 0;
 	}
 	}
-	if (connect(temp_sock, &to->s, sockaddru_len(*to))==-1) {
+	if (connect(*temp_sock, &to->s, sockaddru_len(*to))==-1) {
+		if (errno==EISCONN && !mhomed_sock_cache_disabled){
+			/*  no multiple connects support on the same socket */
+			mhomed_sock_cache_disabled=1;
+			sock_inet=-1;
+#ifdef USE_IPV6
+			sock_inet6=-1;
+#endif /* USE_IPV6 */
+			goto retry;
+		}
 		LOG(L_ERR, "ERROR: get_out_socket: connect failed: %s\n",
 				strerror(errno));
-		sock_inet = 0;
-		sock_inet6 = 0;
 		goto error;
 	}
 	len=sizeof(from);
-	if (getsockname(temp_sock, &from.s, &len)==-1) {
+	if (getsockname(*temp_sock, &from.s, &len)==-1) {
 		LOG(L_ERR, "ERROR: get_out_socket: getsockname failed: %s\n",
 				strerror(errno));
-		sock_inet = 0;
-		sock_inet6 = 0;
 		goto error;
 	}
 	su2ip_addr(&ip, &from);
 	si=find_si(&ip, 0, proto);
 	if (si==0) goto error;
 	DBG("DEBUG: get_out_socket: socket determined: %p\n", si );
+	if (unlikely(mhomed_sock_cache_disabled)){
+		close(*temp_sock);
+		*temp_sock=-1;
+	}
 	return si;
 error:
 	LOG(L_ERR, "ERROR: get_out_socket: no socket found\n");
+	if (unlikely(*temp_sock >=0 && mhomed_sock_cache_disabled)){
+		close(*temp_sock);
+		*temp_sock=-1;
+	}
 	return 0;
 }
 




More information about the sr-dev mailing list