From b2954e66e87be7414a4508f8167ca531e653bea8 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Sun, 4 Nov 2012 18:22:48 +0100 Subject: FTP: prevent the multi interface from blocking As pointed out in Bug report #3579064, curl_multi_perform() would wrongly use a blocking mechanism internally for some commands which could lead to for example a very long block if the LIST response never showed. The solution was to make sure to properly continue to use the multi interface non-blocking state machine. The new test 1501 verifies the fix. Bug: http://curl.haxx.se/bug/view.cgi?id=3579064 Reported by: Guido Berhoerster --- tests/libtest/.gitignore | 2 +- tests/libtest/Makefile.inc | 4 +- tests/libtest/lib1501.c | 126 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 tests/libtest/lib1501.c (limited to 'tests/libtest') diff --git a/tests/libtest/.gitignore b/tests/libtest/.gitignore index 80be891d6..28e83c08d 100644 --- a/tests/libtest/.gitignore +++ b/tests/libtest/.gitignore @@ -1,5 +1,5 @@ chkhostname lib5[0-9][0-9] -lib1500 +lib150[0-9] libauthretry libntlmconnect diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index fa0c69cb5..e0ebcb4c7 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -20,7 +20,7 @@ noinst_PROGRAMS = chkhostname \ lib556 lib539 lib557 lib560 lib562 lib564 lib565 lib566 lib567 lib568 \ lib569 lib570 lib571 lib572 lib573 lib582 lib583 lib585 lib586 lib587 \ lib590 lib591 lib597 lib598 lib599 libauthretry libntlmconnect \ - lib1500 + lib1500 lib1501 chkhostname_SOURCES = chkhostname.c $(top_srcdir)/lib/curl_gethostname.c chkhostname_LDADD = @CURL_NETWORK_LIBS@ @@ -189,6 +189,8 @@ lib599_SOURCES = lib599.c $(SUPPORTFILES) lib1500_SOURCES = lib1500.c $(SUPPORTFILES) $(TESTUTIL) +lib1501_SOURCES = lib1501.c $(SUPPORTFILES) $(TESTUTIL) + libauthretry_SOURCES = libauthretry.c $(SUPPORTFILES) libntlmconnect_SOURCES = libntlmconnect.c $(SUPPORTFILES) $(TESTUTIL) diff --git a/tests/libtest/lib1501.c b/tests/libtest/lib1501.c new file mode 100644 index 000000000..8d1a40571 --- /dev/null +++ b/tests/libtest/lib1501.c @@ -0,0 +1,126 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2012, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#include "test.h" + +#include + +#include "testutil.h" +#include "warnless.h" +#include "memdebug.h" + +#define TEST_HANG_TIMEOUT 30 * 1000 + +/* 500 milliseconds allowed. An extreme number but lets be really conservative + to allow old and slow machines to run this test too */ +#define MAX_BLOCKED_TIME_US 500000 + +/* return the number of microseconds between two time stamps */ +static int elapsed(struct timeval *before, + struct timeval *after) +{ + ssize_t result; + + result = (after->tv_sec - before->tv_sec) * 1000000 + + after->tv_usec - before->tv_usec; + if (result < 0) + result = 0; + + return curlx_sztosi(result); +} + + +int test(char *URL) +{ + CURL *handle = NULL; + CURLM *mhandle = NULL; + int res = 0; + int still_running = 0; + + start_test_timing(); + + global_init(CURL_GLOBAL_ALL); + + easy_init(handle); + + easy_setopt(handle, CURLOPT_URL, URL); + easy_setopt(handle, CURLOPT_VERBOSE, 1L); + + multi_init(mhandle); + + multi_add_handle(mhandle, handle); + + multi_perform(mhandle, &still_running); + + abort_on_test_timeout(); + + while(still_running) { + struct timeval timeout; + fd_set fdread; + fd_set fdwrite; + fd_set fdexcep; + int maxfd = -99; + struct timeval before; + struct timeval after; + int e; + + timeout.tv_sec = 0; + timeout.tv_usec = 100000L; /* 100 ms */ + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + multi_fdset(mhandle, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + abort_on_test_timeout(); + + fprintf(stderr, "ping\n"); + gettimeofday(&before, 0); + + multi_perform(mhandle, &still_running); + + abort_on_test_timeout(); + + gettimeofday(&after, 0); + e = elapsed(&before, &after); + fprintf(stderr, "pong = %d\n", e); + + if(e > MAX_BLOCKED_TIME_US) { + res = 100; + break; + } + } + +test_cleanup: + + /* undocumented cleanup sequence - type UA */ + + curl_multi_cleanup(mhandle); + curl_easy_cleanup(handle); + curl_global_cleanup(); + + return res; +} -- cgit v1.2.3