From 1edb8f7e94e925acb3c32902f87315dcdc0c16a0cd90690898ad7787c75ada3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ismail=20D=C3=B6nmez?= Date: Tue, 6 Nov 2012 08:40:05 +0000 Subject: [PATCH] Accepting request 140140 from home:gberh:branches:devel:libraries:c_c++ - added curl-ftp-prevent-the-multi-interface-from-blocking.patch in order to prevent the multi interface from blocking when using ftp and the remote end responds very slowly (sf#3579064) OBS-URL: https://build.opensuse.org/request/show/140140 OBS-URL: https://build.opensuse.org/package/show/devel:libraries:c_c++/curl?expand=0&rev=79 --- ...nt-the-multi-interface-from-blocking.patch | 407 ++++++++++++++++++ curl.changes | 7 + curl.spec | 5 +- 3 files changed, 418 insertions(+), 1 deletion(-) create mode 100644 curl-ftp-prevent-the-multi-interface-from-blocking.patch diff --git a/curl-ftp-prevent-the-multi-interface-from-blocking.patch b/curl-ftp-prevent-the-multi-interface-from-blocking.patch new file mode 100644 index 0000000..a09f0ae --- /dev/null +++ b/curl-ftp-prevent-the-multi-interface-from-blocking.patch @@ -0,0 +1,407 @@ +From b2954e66e87be7414a4508f8167ca531e653bea8 Mon Sep 17 00:00:00 2001 +From: Daniel Stenberg +Date: Sun, 4 Nov 2012 18:22:48 +0100 +Subject: [PATCH] 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 + +Index: curl-7.27.0/lib/ftp.c +=================================================================== +--- curl-7.27.0.orig/lib/ftp.c ++++ curl-7.27.0/lib/ftp.c +@@ -650,11 +650,18 @@ static CURLcode ftp_readresp(curl_socket + if(ftpcode) + *ftpcode = code; + +- if(421 == code) ++ if(421 == code) { + /* 421 means "Service not available, closing control connection." and FTP + * servers use it to signal that idle session timeout has been exceeded. +- * If we ignored the response, it could end up hanging in some cases. */ ++ * If we ignored the response, it could end up hanging in some cases. ++ * ++ * This response code can come at any point so having it treated ++ * generically is a good idea. ++ */ ++ infof(data, "We got a 421 - timeout!\n"); ++ state(conn, FTP_STOP); + return CURLE_OPERATION_TIMEDOUT; ++ } + + return result; + } +@@ -2378,6 +2385,7 @@ static CURLcode ftp_state_stor_resp(stru + + if(ftpcode>=400) { + failf(data, "Failed FTP upload: %0d", ftpcode); ++ state(conn, FTP_STOP); + /* oops, we never close the sockets! */ + return CURLE_UPLOAD_FAILED; + } +@@ -2395,9 +2403,6 @@ static CURLcode ftp_state_stor_resp(stru + if(!connected) { + struct ftp_conn *ftpc = &conn->proto.ftpc; + infof(data, "Data conn was not available immediately\n"); +- /* as there's not necessarily an immediate action on the control +- connection now, we halt the state machine */ +- state(conn, FTP_STOP); + ftpc->wait_data_conn = TRUE; + } + +@@ -3647,6 +3652,8 @@ static CURLcode ftp_do_more(struct conne + /* the ftp struct is inited in ftp_connect() */ + struct FTP *ftp = data->state.proto.ftp; + ++ *complete = FALSE; ++ + /* if the second connection isn't done yet, wait for it */ + if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { + result = Curl_is_connected(conn, SECONDARYSOCKET, &connected); +@@ -3659,6 +3666,18 @@ static CURLcode ftp_do_more(struct conne + return result; + } + ++ if((data->state.used_interface == Curl_if_multi) && ++ ftpc->state) { ++ /* multi interface and already in a state so skip the intial commands. ++ They are only done to kickstart the do_more state */ ++ result = ftp_multi_statemach(conn, complete); ++ ++ /* if we got an error or if we don't wait for a data connection return ++ immediately */ ++ if(result || (ftpc->wait_data_conn != TRUE)) ++ return result; ++ } ++ + if(ftp->transfer <= FTPTRANSFER_INFO) { + /* a transfer is about to take place, or if not a file name was given + so we'll do a SIZE on it later and then we need the right TYPE first */ +@@ -3712,7 +3731,13 @@ static CURLcode ftp_do_more(struct conne + return result; + } + } +- result = ftp_easy_statemach(conn); ++ if(data->state.used_interface == Curl_if_multi) { ++ result = ftp_multi_statemach(conn, complete); ++ ++ return result; ++ } ++ else ++ result = ftp_easy_statemach(conn); + } + + if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY)) +@@ -4386,20 +4411,21 @@ CURLcode ftp_parse_url_path(struct conne + static CURLcode ftp_dophase_done(struct connectdata *conn, + bool connected) + { +- CURLcode result = CURLE_OK; + struct FTP *ftp = conn->data->state.proto.ftp; + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(connected) { + bool completed; +- result = ftp_do_more(conn, &completed); +- } ++ CURLcode result = ftp_do_more(conn, &completed); + +- if(result && (conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD)) { +- /* Failure detected, close the second socket if it was created already */ +- Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); +- conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; +- return result; ++ if(result) { ++ if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { ++ /* close the second socket if it was created already */ ++ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]); ++ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; ++ } ++ return result; ++ } + } + + if(ftp->transfer != FTPTRANSFER_BODY) +@@ -4411,7 +4437,7 @@ static CURLcode ftp_dophase_done(struct + + ftpc->ctl_valid = TRUE; /* seems good */ + +- return result; ++ return CURLE_OK; + } + + /* called from multi.c while DOing */ +Index: curl-7.27.0/lib/pingpong.c +=================================================================== +--- curl-7.27.0.orig/lib/pingpong.c ++++ curl-7.27.0/lib/pingpong.c +@@ -5,7 +5,7 @@ + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * +- * Copyright (C) 1998 - 2011, Daniel Stenberg, , et al. ++ * 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 +@@ -424,6 +424,9 @@ CURLcode Curl_pp_readresp(curl_socket_t + it may actually contain another end of response already! */ + clipamount = gotbytes - i; + restart = TRUE; ++ DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing " ++ "server response left\n", ++ (int)clipamount)); + } + else if(keepon) { + +Index: curl-7.27.0/tests/data/Makefile.am +=================================================================== +--- curl-7.27.0.orig/tests/data/Makefile.am ++++ curl-7.27.0/tests/data/Makefile.am +@@ -93,6 +93,7 @@ test1379 test1380 test1381 test1382 test + test1387 test1388 test1389 test1390 test1391 test1392 test1393 \ + test1400 test1401 test1402 test1403 test1404 test1405 test1406 test1407 \ + test1408 test1409 test1410 \ ++test1501 \ + test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ + test2008 test2009 test2010 test2011 test2012 test2013 test2014 test2015 \ + test2016 test2017 test2018 test2019 test2020 test2021 test2022 +Index: curl-7.27.0/tests/data/test1501 +=================================================================== +--- /dev/null ++++ curl-7.27.0/tests/data/test1501 +@@ -0,0 +1,53 @@ ++ ++ ++ ++FTP ++RETR ++multi ++LIST ++ ++ ++ ++# Server-side ++ ++ ++ ++ ++DELAY LIST 2 ++DELAY TYPE 2 ++ ++ ++ ++# Client-side ++ ++ ++ftp ++ ++ ++lib1501 ++ ++ ++FTP with multi interface and slow LIST response ++ ++ ++ftp://%HOSTIP:%FTPPORT/1501/ ++ ++ ++# Verify data after the test has been "shot" ++ ++ ++0 ++ ++ ++USER anonymous ++PASS ftp@example.com ++PWD ++CWD 1501 ++EPSV ++TYPE A ++LIST ++QUIT ++ ++ ++ ++ +Index: curl-7.27.0/tests/data/test591 +=================================================================== +--- curl-7.27.0.orig/tests/data/test591 ++++ curl-7.27.0/tests/data/test591 +@@ -63,8 +63,9 @@ TYPE I + STOR 591 + QUIT + ++# CURLE_UPLOAD_FAILED = 25 + +-10 ++25 + + + +Index: curl-7.27.0/tests/data/test592 +=================================================================== +--- curl-7.27.0.orig/tests/data/test592 ++++ curl-7.27.0/tests/data/test592 +@@ -52,6 +52,7 @@ Moooooooooooo for 592 + s/^PORT (.*)/PORT/ + s/^EPRT \|1\|(.*)/EPRT \|1\|/ + ++# a 421 response must prevent further commands from being sent + + USER anonymous + PASS ftp@example.com +@@ -61,10 +62,10 @@ EPRT |1| + PORT + TYPE I + STOR 592 +-QUIT + ++# 28 == CURLE_OPERATION_TIMEDOUT + +-10 ++28 + + + +Index: curl-7.27.0/tests/libtest/lib1501.c +=================================================================== +--- /dev/null ++++ curl-7.27.0/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; ++} diff --git a/curl.changes b/curl.changes index 2991ff7..839a4b2 100644 --- a/curl.changes +++ b/curl.changes @@ -1,3 +1,10 @@ +------------------------------------------------------------------- +Sun Nov 4 19:57:33 UTC 2012 - gber@opensuse.org + +- added curl-ftp-prevent-the-multi-interface-from-blocking.patch in + order to prevent the multi interface from blocking when using ftp + and the remote end responds very slowly (sf#3579064) + ------------------------------------------------------------------- Sun Jul 29 22:14:25 UTC 2012 - crrodriguez@opensuse.org diff --git a/curl.spec b/curl.spec index 6b8070c..f0cf4ea 100644 --- a/curl.spec +++ b/curl.spec @@ -24,7 +24,7 @@ Name: curl Version: 7.27.0 Release: 0 Summary: A Tool for Transferring Data from URLs -License: BSD-3-Clause ; MIT +License: BSD-3-Clause and MIT Group: Productivity/Networking/Web/Utilities Url: http://curl.haxx.se/ Source: http://curl.haxx.se/download/%{name}-%{version}.tar.lzma @@ -32,6 +32,8 @@ Source2: http://curl.haxx.se/download/%{name}-%{version}.tar.lzma.asc Source3: baselibs.conf Patch: libcurl-ocloexec.patch Patch1: dont-mess-with-rpmoptflags.diff +# PATCH-FIX-UPSTREAM curl-ftp-prevent-the-multi-interface-from-blocking.patch sf#3579064 gber@opensuse.org -- Prevent the multi interface from blocking when using ftp and the remote end responds very slowly (backported from upstream git) +Patch2: curl-ftp-prevent-the-multi-interface-from-blocking.patch BuildRequires: libidn-devel BuildRequires: libtool BuildRequires: lzma @@ -91,6 +93,7 @@ user interaction or any kind of interactivity. %setup -q %patch %patch1 +%patch2 -p1 %build autoreconf -fi