socketpair() usage tracking to allow fd leak detection
authorYang Tse <yangsita@gmail.com>
Fri, 29 Jul 2011 11:25:52 +0000 (13:25 +0200)
committerYang Tse <yangsita@gmail.com>
Fri, 29 Jul 2011 11:27:10 +0000 (13:27 +0200)
configure.ac
lib/http_ntlm.c
lib/memdebug.c
lib/memdebug.h
lib/urldata.h
m4/curl-functions.m4
tests/memanalyze.pl

index b1fbf3e..da19ad9 100644 (file)
@@ -2564,6 +2564,7 @@ CURL_CHECK_FUNC_SIGINTERRUPT
 CURL_CHECK_FUNC_SIGNAL
 CURL_CHECK_FUNC_SIGSETJMP
 CURL_CHECK_FUNC_SOCKET
+CURL_CHECK_FUNC_SOCKETPAIR
 CURL_CHECK_FUNC_STRCASECMP
 CURL_CHECK_FUNC_STRCASESTR
 CURL_CHECK_FUNC_STRCMPI
index 4163b82..dc90604 100644 (file)
@@ -680,20 +680,20 @@ static void unicodecpy(unsigned char *dest,
 #ifdef USE_NTLM_SSO
 static void sso_ntlm_close(struct connectdata *conn)
 {
-  if(conn->fd_helper != -1) {
-    close(conn->fd_helper);
-    conn->fd_helper = -1;
+  if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
+    sclose(conn->ntlm_auth_hlpr_socket);
+    conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
   }
 
-  if(conn->pid) {
-    int ret, i;
+  if(conn->ntlm_auth_hlpr_pid) {
+    int i;
     for(i = 0; i < 4; i++) {
-      ret = waitpid(conn->pid, NULL, WNOHANG);
-      if(ret == conn->pid || errno == ECHILD)
+      pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG);
+      if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD)
         break;
       switch(i) {
       case 0:
-        kill(conn->pid, SIGTERM);
+        kill(conn->ntlm_auth_hlpr_pid, SIGTERM);
         break;
       case 1:
         /* Give the process another moment to shut down cleanly before
@@ -701,13 +701,13 @@ static void sso_ntlm_close(struct connectdata *conn)
         Curl_wait_ms(1);
         break;
       case 2:
-        kill(conn->pid, SIGKILL);
+        kill(conn->ntlm_auth_hlpr_pid, SIGKILL);
         break;
       case 3:
         break;
       }
     }
-    conn->pid = 0;
+    conn->ntlm_auth_hlpr_pid = 0;
   }
 
   Curl_safefree(conn->challenge_header);
@@ -719,8 +719,8 @@ static void sso_ntlm_close(struct connectdata *conn)
 static CURLcode sso_ntlm_initiate(struct connectdata *conn,
                                   const char *userp)
 {
-  int sockfds[2];
-  pid_t pid;
+  curl_socket_t sockfds[2];
+  pid_t child_pid;
   const char *username;
   char *slash, *domain = NULL;
   const char *ntlm_auth = NULL;
@@ -728,9 +728,9 @@ static CURLcode sso_ntlm_initiate(struct connectdata *conn,
   int error;
 
   /* Return if communication with ntlm_auth already set up */
-  if(conn->fd_helper != -1 || conn->pid) {
+  if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
+     conn->ntlm_auth_hlpr_pid)
     return CURLE_OK;
-  }
 
   username = userp;
   slash = strpbrk(username, "\\/");
@@ -768,21 +768,21 @@ static CURLcode sso_ntlm_initiate(struct connectdata *conn,
     goto done;
   }
 
-  pid = fork();
-  if(pid == -1) {
+  child_pid = fork();
+  if(child_pid == -1) {
     error = ERRNO;
-    close(sockfds[0]);
-    close(sockfds[1]);
+    sclose(sockfds[0]);
+    sclose(sockfds[1]);
     failf(conn->data, "Could not fork. errno %d: %s",
           error, Curl_strerror(conn, error));
     goto done;
   }
-  else if(!pid) {
+  else if(!child_pid) {
     /*
      * child process
      */
 
-    close(sockfds[0]);
+    sclose(sockfds[0]);
 
     if(dup2(sockfds[1], STDIN_FILENO) == -1) {
       error = ERRNO;
@@ -813,14 +813,15 @@ static CURLcode sso_ntlm_initiate(struct connectdata *conn,
             NULL);
 
     error = ERRNO;
+    sclose(sockfds[1]);
     failf(conn->data, "Could not execl(). errno %d: %s",
           error, Curl_strerror(conn, error));
     exit(1);
   }
 
-  close(sockfds[1]);
-  conn->fd_helper = sockfds[0];
-  conn->pid = pid;
+  sclose(sockfds[1]);
+  conn->ntlm_auth_hlpr_socket = sockfds[0];
+  conn->ntlm_auth_hlpr_pid = child_pid;
   Curl_safefree(domain);
   Curl_safefree(ntlm_auth_alloc);
   return CURLE_OK;
@@ -840,7 +841,7 @@ static CURLcode sso_ntlm_response(struct connectdata *conn,
   size_t len_in = strlen(input), len_out = sizeof(buf);
 
   while(len_in > 0) {
-    ssize_t written = write(conn->fd_helper, input, len_in);
+    ssize_t written = write(conn->ntlm_auth_hlpr_socket, input, len_in);
     if(written == -1) {
       /* Interrupted by a signal, retry it */
       if(errno == EINTR)
@@ -853,7 +854,7 @@ static CURLcode sso_ntlm_response(struct connectdata *conn,
   }
   /* Read one line */
   while(len_out > 0) {
-    size = read(conn->fd_helper, tmpbuf, len_out);
+    size = read(conn->ntlm_auth_hlpr_socket, tmpbuf, len_out);
     if(size == -1) {
       if(errno == EINTR)
         continue;
@@ -946,8 +947,8 @@ CURLcode Curl_output_ntlm_sso(struct connectdata *conn,
      * handling process.
      */
     /* Clean data before using them */
-    conn->fd_helper = -1;
-    conn->pid = 0;
+    conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+    conn->ntlm_auth_hlpr_pid = 0;
     conn->challenge_header = NULL;
     conn->response_header = NULL;
     /* Create communication with ntlm_auth */
index 60d938a..3e3c1bc 100644 (file)
@@ -285,6 +285,24 @@ curl_socket_t curl_socket(int domain, int type, int protocol,
   return sockfd;
 }
 
+#ifdef HAVE_SOCKETPAIR
+int curl_socketpair(int domain, int type, int protocol,
+                    curl_socket_t socket_vector[2],
+                    int line, const char *source)
+{
+  const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+                    "FD %s:%d socketpair() = %d %d\n" :
+                    (sizeof(curl_socket_t) == sizeof(long)) ?
+                    "FD %s:%d socketpair() = %ld %ld\n" :
+                    "FD %s:%d socketpair() = %zd %zd\n" ;
+
+  int res = socketpair(domain, type, protocol, socket_vector);
+  if(source && (0 == res))
+    curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]);
+  return res;
+}
+#endif
+
 curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
                           int line, const char *source)
 {
index 3dc4815..b18bb39 100644 (file)
@@ -65,6 +65,11 @@ CURL_EXTERN int curl_sclose(curl_socket_t sockfd,
                             int line , const char *source);
 CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen,
                                       int line, const char *source);
+#ifdef HAVE_SOCKETPAIR
+CURL_EXTERN int curl_socketpair(int domain, int type, int protocol,
+                                curl_socket_t socket_vector[2],
+                                int line , const char *source);
+#endif
 
 /* FILE functions */
 CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
@@ -90,6 +95,10 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
 #undef accept /* for those with accept as a macro */
 #define accept(sock,addr,len)\
  curl_accept(sock,addr,len,__LINE__,__FILE__)
+#ifdef HAVE_SOCKETPAIR
+#define socketpair(domain,type,protocol,socket_vector)\
+ curl_socketpair(domain,type,protocol,socket_vector,__LINE__,__FILE__)
+#endif
 
 #ifdef HAVE_GETADDRINFO
 #if defined(getaddrinfo) && defined(__osf__)
index d2638aa..f4057cb 100644 (file)
@@ -908,8 +908,8 @@ struct connectdata {
 #ifdef USE_NTLM_SSO
   /* data used for communication with Samba's winbind daemon helper
      ntlm_auth */
-  int fd_helper;
-  pid_t pid;
+  curl_socket_t ntlm_auth_hlpr_socket;
+  pid_t ntlm_auth_hlpr_pid;
   char* challenge_header;
   char* response_header;
 #endif
index ec57b54..6cc49f1 100644 (file)
@@ -21,7 +21,7 @@
 #***************************************************************************
 
 # File version for 'aclocal' use. Keep it a single number.
-# serial 65
+# serial 66
 
 
 dnl CURL_INCLUDES_ARPA_INET
@@ -5624,6 +5624,95 @@ AC_DEFUN([CURL_CHECK_FUNC_SOCKET], [
 ])
 
 
+dnl CURL_CHECK_FUNC_SOCKETPAIR
+dnl -------------------------------------------------
+dnl Verify if socketpair is available, prototyped, and
+dnl can be compiled. If all of these are true, and
+dnl usage has not been previously disallowed with
+dnl shell variable curl_disallow_socketpair, then
+dnl HAVE_SOCKETPAIR will be defined.
+
+AC_DEFUN([CURL_CHECK_FUNC_SOCKETPAIR], [
+  AC_REQUIRE([CURL_INCLUDES_SYS_SOCKET])dnl
+  AC_REQUIRE([CURL_INCLUDES_SOCKET])dnl
+  #
+  tst_links_socketpair="unknown"
+  tst_proto_socketpair="unknown"
+  tst_compi_socketpair="unknown"
+  tst_allow_socketpair="unknown"
+  #
+  AC_MSG_CHECKING([if socketpair can be linked])
+  AC_LINK_IFELSE([
+    AC_LANG_FUNC_LINK_TRY([socketpair])
+  ],[
+    AC_MSG_RESULT([yes])
+    tst_links_socketpair="yes"
+  ],[
+    AC_MSG_RESULT([no])
+    tst_links_socketpair="no"
+  ])
+  #
+  if test "$tst_links_socketpair" = "yes"; then
+    AC_MSG_CHECKING([if socketpair is prototyped])
+    AC_EGREP_CPP([socketpair],[
+      $curl_includes_sys_socket
+      $curl_includes_socket
+    ],[
+      AC_MSG_RESULT([yes])
+      tst_proto_socketpair="yes"
+    ],[
+      AC_MSG_RESULT([no])
+      tst_proto_socketpair="no"
+    ])
+  fi
+  #
+  if test "$tst_proto_socketpair" = "yes"; then
+    AC_MSG_CHECKING([if socketpair is compilable])
+    AC_COMPILE_IFELSE([
+      AC_LANG_PROGRAM([[
+        $curl_includes_sys_socket
+        $curl_includes_socket
+      ]],[[
+        int sv[2];
+        if(0 != socketpair(0, 0, 0, sv))
+          return 1;
+      ]])
+    ],[
+      AC_MSG_RESULT([yes])
+      tst_compi_socketpair="yes"
+    ],[
+      AC_MSG_RESULT([no])
+      tst_compi_socketpair="no"
+    ])
+  fi
+  #
+  if test "$tst_compi_socketpair" = "yes"; then
+    AC_MSG_CHECKING([if socketpair usage allowed])
+    if test "x$curl_disallow_socketpair" != "xyes"; then
+      AC_MSG_RESULT([yes])
+      tst_allow_socketpair="yes"
+    else
+      AC_MSG_RESULT([no])
+      tst_allow_socketpair="no"
+    fi
+  fi
+  #
+  AC_MSG_CHECKING([if socketpair might be used])
+  if test "$tst_links_socketpair" = "yes" &&
+     test "$tst_proto_socketpair" = "yes" &&
+     test "$tst_compi_socketpair" = "yes" &&
+     test "$tst_allow_socketpair" = "yes"; then
+    AC_MSG_RESULT([yes])
+    AC_DEFINE_UNQUOTED(HAVE_SOCKETPAIR, 1,
+      [Define to 1 if you have the socketpair function.])
+    ac_cv_func_socketpair="yes"
+  else
+    AC_MSG_RESULT([no])
+    ac_cv_func_socketpair="no"
+  fi
+])
+
+
 dnl CURL_CHECK_FUNC_STRCASECMP
 dnl -------------------------------------------------
 dnl Verify if strcasecmp is available, prototyped, and
index 2650590..bf53933 100755 (executable)
@@ -236,6 +236,14 @@ while(<FILE>) {
             $getfile{$1}="$source:$linenum";
             $openfile++;
         }
+        elsif($function =~ /socketpair\(\) = (\d*) (\d*)/) {
+            $filedes{$1}=1;
+            $getfile{$1}="$source:$linenum";
+            $openfile++;
+            $filedes{$2}=1;
+            $getfile{$2}="$source:$linenum";
+            $openfile++;
+        }
         elsif($function =~ /accept\(\) = (\d*)/) {
             $filedes{$1}=1;
             $getfile{$1}="$source:$linenum";