1
0
mirror of https://github.com/moparisthebest/curl synced 2024-08-13 17:03:50 -04:00

- Armel Asselin improved libcurl to behave a lot better when an easy handle

doing an FTP transfer is removed from a multi handle before completion. The
  fix also fixed the "alive counter" to be correct on "premature removal" for
  all protocols.
This commit is contained in:
Daniel Stenberg 2007-01-16 22:22:10 +00:00
parent 1886388791
commit 385e612fa5
19 changed files with 75 additions and 49 deletions

View File

@ -6,6 +6,12 @@
Changelog
Daniel (16 January 2007)
- Armel Asselin improved libcurl to behave a lot better when an easy handle
doing an FTP transfer is removed from a multi handle before completion. The
fix also fixed the "alive counter" to be correct on "premature removal" for
all protocols.
Dan F (16 January 2007)
- Fixed a small memory leak in tftp uploads discovered by curl's memory leak
detector. Also changed tftp downloads to URL-unescape the downloaded

View File

@ -51,6 +51,8 @@ This release includes the following bugfixes:
o base64 encoding/decoding works on non-ASCII platforms
o large file downloads
o CURLOPT_COOKIELIST set to "ALL" crash
o easy handle removal from multi handle before completion
o TFTP upload memory leak
Other curl-related news:
@ -71,6 +73,7 @@ advice from friends like these:
Matt Witherspoon, Alexey Simak, Martin Skinner, Sh Diao, Jared Lundell,
Stefan Krause, Sebastien Willemijns, Alexey Simak, Brendan Jurd,
Robson Braga Araujo, David McCreedy, Robert Foreman, Nathanael Nerode,
Victor Snezhko, Linus Nielsen Feltzing, Toby Peterson
Victor Snezhko, Linus Nielsen Feltzing, Toby Peterson, Dan Fandrich,
Armel Asselin
Thanks! (and sorry if I forgot to mention someone)

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -165,7 +165,7 @@ CURLcode Curl_file_connect(struct connectdata *conn)
file->fd = fd;
if(!conn->data->set.upload && (fd == -1)) {
failf(conn->data, "Couldn't open file %s", conn->data->reqdata.path);
Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE);
Curl_file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
return CURLE_FILE_COULDNT_READ_FILE;
}
@ -173,10 +173,11 @@ CURLcode Curl_file_connect(struct connectdata *conn)
}
CURLcode Curl_file_done(struct connectdata *conn,
CURLcode status)
CURLcode status, bool premature)
{
struct FILEPROTO *file = conn->data->reqdata.proto.file;
(void)status; /* not used */
(void)premature; /* not used */
Curl_safefree(file->freepath);
if(file->fd != -1)

View File

@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -25,7 +25,7 @@
***************************************************************************/
#ifndef CURL_DISABLE_FILE
CURLcode Curl_file(struct connectdata *, bool *done);
CURLcode Curl_file_done(struct connectdata *, CURLcode);
CURLcode Curl_file_done(struct connectdata *, CURLcode, bool premature);
CURLcode Curl_file_connect(struct connectdata *);
#endif
#endif

View File

@ -2964,7 +2964,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn,
*
* Input argument is already checked for validity.
*/
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status, bool premature)
{
struct SessionHandle *data = conn->data;
struct FTP *ftp = data->reqdata.proto.ftp;
@ -2998,8 +2998,12 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
/* the connection stays alive fine even though this happened */
/* fall-through */
case CURLE_OK: /* doesn't affect the control connection's status */
ftpc->ctl_valid = was_ctl_valid;
break;
if (!premature) {
ftpc->ctl_valid = was_ctl_valid;
break;
}
/* until we cope better with prematurely ended requests, let them
* fallback as if in complete failure */
default: /* by default, an error means the control connection is
wedged and should not be used anymore */
ftpc->ctl_valid = FALSE;
@ -3048,7 +3052,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
if(!ftp->no_transfer && !status) {
if(!ftp->no_transfer && !status && !premature) {
/*
* Let's see what the server says about the transfer we just performed,
* but lower the timeout as sometimes this connection has died while the
@ -3081,7 +3085,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
}
}
if(result)
if(result || premature)
/* the response code from the transfer showed an error already so no
use checking further */
;
@ -3123,7 +3127,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
ftpc->dont_check = FALSE;
/* Send any post-transfer QUOTE strings? */
if(!status && !result && data->set.postquote)
if(!status && !result && !premature && data->set.postquote)
result = ftp_sendquote(conn, data->set.postquote);
return result;

View File

@ -25,7 +25,7 @@
#ifndef CURL_DISABLE_FTP
CURLcode Curl_ftp(struct connectdata *conn, bool *done);
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode);
CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode, bool premature);
CURLcode Curl_ftp_connect(struct connectdata *conn, bool *done);
CURLcode Curl_ftp_disconnect(struct connectdata *conn);
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);

View File

@ -1503,11 +1503,12 @@ int Curl_https_getsock(struct connectdata *conn,
*/
CURLcode Curl_http_done(struct connectdata *conn,
CURLcode status)
CURLcode status, bool premature)
{
struct SessionHandle *data = conn->data;
struct HTTP *http =data->reqdata.proto.http;
struct Curl_transfer_keeper *k = &data->reqdata.keep;
(void)premature; /* not used */
/* set the proper values (possibly modified on POST) */
conn->fread = data->set.fread; /* restore */

View File

@ -35,7 +35,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn, bool *done);
CURLcode Curl_http_done(struct connectdata *, CURLcode);
CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
CURLcode Curl_https_connecting(struct connectdata *conn, bool *done);
int Curl_https_getsock(struct connectdata *conn,

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -512,9 +512,11 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
}
if(easy) {
bool premature = easy->state != CURLM_STATE_COMPLETED;
/* If the 'state' is not INIT or COMPLETED, we might need to do something
nice to put the easy_handle in a good known state when this returns. */
if(easy->state != CURLM_STATE_COMPLETED)
if(premature)
/* this handle is "alive" so we need to count down the total number of
alive connections when this is removed */
multi->num_alive--;
@ -547,7 +549,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
/* Curl_done() clears the conn->data field to lose the association
between the easy handle and the connection */
Curl_done(&easy->easy_conn, easy->result);
Curl_done(&easy->easy_conn, easy->result, premature);
if(easy->easy_conn)
/* the connection is still alive, set back the association to enable
@ -802,7 +804,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
char *gotourl;
Curl_posttransfer(easy->easy_handle);
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
/* We make sure that the pipe broken flag is reset
because in this case, it isn't an actual break */
easy->easy_handle->state.pipe_broke = FALSE;
@ -950,7 +952,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else if(easy->result) {
/* failure detected */
Curl_posttransfer(easy->easy_handle);
Curl_done(&easy->easy_conn, easy->result);
Curl_done(&easy->easy_conn, easy->result, FALSE);
Curl_disconnect(easy->easy_conn); /* close the connection */
easy->easy_conn = NULL; /* no more connection */
}
@ -1017,7 +1019,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(easy->easy_handle);
Curl_done(&easy->easy_conn, easy->result);
Curl_done(&easy->easy_conn, easy->result, FALSE);
Curl_disconnect(easy->easy_conn); /* close the connection */
easy->easy_conn = NULL; /* no more connection */
}
@ -1050,7 +1052,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(easy->easy_handle);
Curl_done(&easy->easy_conn, easy->result);
Curl_done(&easy->easy_conn, easy->result, FALSE);
Curl_disconnect(easy->easy_conn); /* close the connection */
easy->easy_conn = NULL; /* no more connection */
}
@ -1169,7 +1171,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
easy->easy_conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
}
Curl_posttransfer(easy->easy_handle);
Curl_done(&easy->easy_conn, easy->result);
Curl_done(&easy->easy_conn, easy->result, FALSE);
}
else if(TRUE == done) {
char *newurl;
@ -1188,7 +1190,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
newurl = easy->easy_handle->reqdata.newurl;
easy->easy_handle->reqdata.newurl = NULL;
}
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
if(easy->result == CURLE_OK)
easy->result = Curl_follow(easy->easy_handle, newurl, retry);
if(CURLE_OK == easy->result) {
@ -1224,7 +1226,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if (!easy->easy_handle->state.cancelled) {
/* post-transfer command */
easy->result = Curl_done(&easy->easy_conn, CURLE_OK);
easy->result = Curl_done(&easy->easy_conn, CURLE_OK, FALSE);
/* after we have DONE what we're supposed to do, go COMPLETED, and
it doesn't matter what the Curl_done() returned! */

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -568,9 +568,11 @@ CURLcode Curl_scp_do(struct connectdata *conn, bool *done)
return res;
}
CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status)
CURLcode Curl_scp_done(struct connectdata *conn, CURLcode status,
bool premature)
{
struct SSHPROTO *scp = conn->data->reqdata.proto.ssh;
(void)premature; /* not used */
Curl_safefree(scp->path);
scp->path = NULL;
@ -891,9 +893,11 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
return res;
}
CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status)
CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode status,
bool premature)
{
struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
(void)premature; /* not used */
Curl_safefree(sftp->path);
sftp->path = NULL;

View File

@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -29,7 +29,7 @@
CURLcode Curl_ssh_connect(struct connectdata *conn, bool *done);
CURLcode Curl_scp_do(struct connectdata *conn, bool *done);
CURLcode Curl_scp_done(struct connectdata *conn, CURLcode);
CURLcode Curl_scp_done(struct connectdata *conn, CURLcode, bool premature);
ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
void *mem, size_t len);
@ -37,7 +37,7 @@ ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
char *mem, size_t len);
CURLcode Curl_sftp_do(struct connectdata *conn, bool *done);
CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode);
CURLcode Curl_sftp_done(struct connectdata *conn, CURLcode, bool premature);
ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
void *mem, size_t len);

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -1073,10 +1073,11 @@ void telrcv(struct connectdata *conn,
}
}
CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status)
CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode status, bool premature)
{
struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
(void)status; /* unused */
(void)premature; /* not used */
curl_slist_free_all(tn->telnet_vars);

View File

@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -25,6 +25,6 @@
***************************************************************************/
#ifndef CURL_DISABLE_TELNET
CURLcode Curl_telnet(struct connectdata *conn, bool *done);
CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode);
CURLcode Curl_telnet_done(struct connectdata *conn, CURLcode, bool premature);
#endif
#endif

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -77,6 +77,7 @@
#include "connect.h"
#include "strerror.h"
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "url.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@ -288,7 +289,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
}
/* As RFC3617 describes the separator slash is not actually part of the
file name so we skip the always-present first letter of the path string. */
filename = curl_easy_unescape(data, &state->conn->data->reqdata.path[1], 0, NULL);
filename = curl_easy_unescape(data, &state->conn->data->reqdata.path[1], 0,
NULL);
snprintf((char *)&state->spacket.data[2],
TFTP_BLOCKSIZE,
"%s%c%s%c", filename, '\0', mode, '\0');
@ -622,9 +624,11 @@ CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done)
* The done callback
*
**********************************************************/
CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status)
CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status,
bool premature)
{
(void)status; /* unused */
(void)premature; /* not used */
#if 0
free(conn->data->reqdata.proto.tftp);

View File

@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@ -26,6 +26,6 @@
#ifndef CURL_DISABLE_TFTP
CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done);
CURLcode Curl_tftp(struct connectdata *conn, bool *done);
CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode);
CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode, bool premature);
#endif
#endif

View File

@ -2303,7 +2303,7 @@ Curl_connect_host(struct SessionHandle *data,
to the new URL */
urlchanged = data->change.url_changed;
if ((CURLE_OK == res) && urlchanged) {
res = Curl_done(conn, res);
res = Curl_done(conn, res, FALSE);
if(CURLE_OK == res) {
char *gotourl = strdup(data->change.url);
res = Curl_follow(data, gotourl, FALSE);
@ -2379,7 +2379,7 @@ CURLcode Curl_perform(struct SessionHandle *data)
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
conn->bits.close = FALSE;
res = Curl_done(&conn, CURLE_OK);
res = Curl_done(&conn, CURLE_OK, FALSE);
break;
}
res = Curl_do(&conn, &do_done);
@ -2412,14 +2412,14 @@ CURLcode Curl_perform(struct SessionHandle *data)
/* Always run Curl_done(), even if some of the previous calls
failed, but return the previous (original) error code */
res2 = Curl_done(&conn, res);
res2 = Curl_done(&conn, res, FALSE);
if(CURLE_OK == res)
res = res2;
}
else
/* Curl_do() failed, clean up left-overs in the done-call */
res2 = Curl_done(&conn, res);
res2 = Curl_done(&conn, res, FALSE);
/*
* Important: 'conn' cannot be used here, since it may have been closed

View File

@ -4087,7 +4087,7 @@ CURLcode Curl_async_resolved(struct connectdata *conn,
CURLcode Curl_done(struct connectdata **connp,
CURLcode status) /* an error if this is called after an
CURLcode status, bool premature) /* an error if this is called after an
error was detected */
{
CURLcode result;
@ -4127,7 +4127,7 @@ CURLcode Curl_done(struct connectdata **connp,
/* this calls the protocol-specific function pointer previously set */
if(conn->curl_done)
result = conn->curl_done(conn, status);
result = conn->curl_done(conn, status, premature);
else
result = CURLE_OK;
@ -4193,7 +4193,7 @@ CURLcode Curl_do(struct connectdata **connp, bool *done)
infof(data, "Re-used connection seems dead, get a new one\n");
conn->bits.close = TRUE; /* enforce close of this connection */
result = Curl_done(&conn, result); /* we are so done with this */
result = Curl_done(&conn, result, FALSE); /* we are so done with this */
/* conn may no longer be a good pointer */

View File

@ -39,7 +39,7 @@ CURLcode Curl_async_resolved(struct connectdata *conn,
bool *protocol_connect);
CURLcode Curl_do(struct connectdata **, bool *done);
CURLcode Curl_do_more(struct connectdata *);
CURLcode Curl_done(struct connectdata **, CURLcode);
CURLcode Curl_done(struct connectdata **, CURLcode, bool premature);
CURLcode Curl_disconnect(struct connectdata *);
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);

View File

@ -614,7 +614,7 @@ struct Curl_async {
within the source when we need to cast between data pointers (such as NULL)
and function pointers. */
typedef CURLcode (*Curl_do_more_func)(struct connectdata *);
typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode);
typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool);
/*