diff options
author | Yang Tse <yangsita@gmail.com> | 2011-07-29 13:25:52 +0200 |
---|---|---|
committer | Yang Tse <yangsita@gmail.com> | 2011-07-29 13:27:10 +0200 |
commit | bcbac913d65275cc9e22534a8b4cda6994b75977 (patch) | |
tree | ce057b99e26849afbf3421790dd9fe54134bf1d2 | |
parent | 5cdbfa1837394c3ac06828c8322d1441b084aec1 (diff) |
socketpair() usage tracking to allow fd leak detection
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | lib/http_ntlm.c | 55 | ||||
-rw-r--r-- | lib/memdebug.c | 18 | ||||
-rw-r--r-- | lib/memdebug.h | 9 | ||||
-rw-r--r-- | lib/urldata.h | 4 | ||||
-rw-r--r-- | m4/curl-functions.m4 | 91 | ||||
-rwxr-xr-x | tests/memanalyze.pl | 8 |
7 files changed, 156 insertions, 30 deletions
diff --git a/configure.ac b/configure.ac index b1fbf3ea2..da19ad9e2 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index 4163b8245..dc90604d7 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -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 */ diff --git a/lib/memdebug.c b/lib/memdebug.c index 60d938ade..3e3c1bc4f 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -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) { diff --git a/lib/memdebug.h b/lib/memdebug.h index 3dc481577..b18bb39da 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -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__) diff --git a/lib/urldata.h b/lib/urldata.h index d2638aa93..f4057cbbd 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4 index ec57b5423..6cc49f13c 100644 --- a/m4/curl-functions.m4 +++ b/m4/curl-functions.m4 @@ -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 diff --git a/tests/memanalyze.pl b/tests/memanalyze.pl index 2650590a6..bf5393365 100755 --- a/tests/memanalyze.pl +++ b/tests/memanalyze.pl @@ -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"; |