aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYang Tse <yangsita@gmail.com>2011-07-29 13:25:52 +0200
committerYang Tse <yangsita@gmail.com>2011-07-29 13:27:10 +0200
commitbcbac913d65275cc9e22534a8b4cda6994b75977 (patch)
treece057b99e26849afbf3421790dd9fe54134bf1d2
parent5cdbfa1837394c3ac06828c8322d1441b084aec1 (diff)
socketpair() usage tracking to allow fd leak detection
-rw-r--r--configure.ac1
-rw-r--r--lib/http_ntlm.c55
-rw-r--r--lib/memdebug.c18
-rw-r--r--lib/memdebug.h9
-rw-r--r--lib/urldata.h4
-rw-r--r--m4/curl-functions.m491
-rwxr-xr-xtests/memanalyze.pl8
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";