- 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

@ -6,6 +6,12 @@
Changelog 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) Dan F (16 January 2007)
- Fixed a small memory leak in tftp uploads discovered by curl's memory leak - Fixed a small memory leak in tftp uploads discovered by curl's memory leak
detector. Also changed tftp downloads to URL-unescape the downloaded detector. Also changed tftp downloads to URL-unescape the downloaded

@ -51,6 +51,8 @@ This release includes the following bugfixes:
o base64 encoding/decoding works on non-ASCII platforms o base64 encoding/decoding works on non-ASCII platforms
o large file downloads o large file downloads
o CURLOPT_COOKIELIST set to "ALL" crash 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: Other curl-related news:
@ -71,6 +73,7 @@ advice from friends like these:
Matt Witherspoon, Alexey Simak, Martin Skinner, Sh Diao, Jared Lundell, Matt Witherspoon, Alexey Simak, Martin Skinner, Sh Diao, Jared Lundell,
Stefan Krause, Sebastien Willemijns, Alexey Simak, Brendan Jurd, Stefan Krause, Sebastien Willemijns, Alexey Simak, Brendan Jurd,
Robson Braga Araujo, David McCreedy, Robert Foreman, Nathanael Nerode, 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) Thanks! (and sorry if I forgot to mention someone)

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * 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; file->fd = fd;
if(!conn->data->set.upload && (fd == -1)) { if(!conn->data->set.upload && (fd == -1)) {
failf(conn->data, "Couldn't open file %s", conn->data->reqdata.path); 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; 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 Curl_file_done(struct connectdata *conn,
CURLcode status) CURLcode status, bool premature)
{ {
struct FILEPROTO *file = conn->data->reqdata.proto.file; struct FILEPROTO *file = conn->data->reqdata.proto.file;
(void)status; /* not used */ (void)status; /* not used */
(void)premature; /* not used */
Curl_safefree(file->freepath); Curl_safefree(file->freepath);
if(file->fd != -1) if(file->fd != -1)

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -25,7 +25,7 @@
***************************************************************************/ ***************************************************************************/
#ifndef CURL_DISABLE_FILE #ifndef CURL_DISABLE_FILE
CURLcode Curl_file(struct connectdata *, bool *done); 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 *); CURLcode Curl_file_connect(struct connectdata *);
#endif #endif
#endif #endif

@ -2964,7 +2964,7 @@ CURLcode Curl_ftp_connect(struct connectdata *conn,
* *
* Input argument is already checked for validity. * 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 SessionHandle *data = conn->data;
struct FTP *ftp = data->reqdata.proto.ftp; 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 */ /* the connection stays alive fine even though this happened */
/* fall-through */ /* fall-through */
case CURLE_OK: /* doesn't affect the control connection's status */ case CURLE_OK: /* doesn't affect the control connection's status */
ftpc->ctl_valid = was_ctl_valid; if (!premature) {
break; 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 default: /* by default, an error means the control connection is
wedged and should not be used anymore */ wedged and should not be used anymore */
ftpc->ctl_valid = FALSE; ftpc->ctl_valid = FALSE;
@ -3048,7 +3052,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; 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, * 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 * 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 /* the response code from the transfer showed an error already so no
use checking further */ use checking further */
; ;
@ -3123,7 +3127,7 @@ CURLcode Curl_ftp_done(struct connectdata *conn, CURLcode status)
ftpc->dont_check = FALSE; ftpc->dont_check = FALSE;
/* Send any post-transfer QUOTE strings? */ /* 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); result = ftp_sendquote(conn, data->set.postquote);
return result; return result;

@ -25,7 +25,7 @@
#ifndef CURL_DISABLE_FTP #ifndef CURL_DISABLE_FTP
CURLcode Curl_ftp(struct connectdata *conn, bool *done); 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_connect(struct connectdata *conn, bool *done);
CURLcode Curl_ftp_disconnect(struct connectdata *conn); CURLcode Curl_ftp_disconnect(struct connectdata *conn);
CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...); CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);

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

@ -35,7 +35,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
/* protocol-specific functions set up to be called by the main engine */ /* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn, bool *done); 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_http_connect(struct connectdata *conn, bool *done);
CURLcode Curl_https_connecting(struct connectdata *conn, bool *done); CURLcode Curl_https_connecting(struct connectdata *conn, bool *done);
int Curl_https_getsock(struct connectdata *conn, int Curl_https_getsock(struct connectdata *conn,

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

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * 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; 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; struct SSHPROTO *scp = conn->data->reqdata.proto.ssh;
(void)premature; /* not used */
Curl_safefree(scp->path); Curl_safefree(scp->path);
scp->path = NULL; scp->path = NULL;
@ -891,9 +893,11 @@ CURLcode Curl_sftp_do(struct connectdata *conn, bool *done)
return res; 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; struct SSHPROTO *sftp = conn->data->reqdata.proto.ssh;
(void)premature; /* not used */
Curl_safefree(sftp->path); Curl_safefree(sftp->path);
sftp->path = NULL; sftp->path = NULL;

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * 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_ssh_connect(struct connectdata *conn, bool *done);
CURLcode Curl_scp_do(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, ssize_t Curl_scp_send(struct connectdata *conn, int sockindex,
void *mem, size_t len); void *mem, size_t len);
@ -37,7 +37,7 @@ ssize_t Curl_scp_recv(struct connectdata *conn, int sockindex,
char *mem, size_t len); char *mem, size_t len);
CURLcode Curl_sftp_do(struct connectdata *conn, bool *done); 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, ssize_t Curl_sftp_send(struct connectdata *conn, int sockindex,
void *mem, size_t len); void *mem, size_t len);

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * 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; struct TELNET *tn = (struct TELNET *)conn->data->reqdata.proto.telnet;
(void)status; /* unused */ (void)status; /* unused */
(void)premature; /* not used */
curl_slist_free_all(tn->telnet_vars); curl_slist_free_all(tn->telnet_vars);

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -25,6 +25,6 @@
***************************************************************************/ ***************************************************************************/
#ifndef CURL_DISABLE_TELNET #ifndef CURL_DISABLE_TELNET
CURLcode Curl_telnet(struct connectdata *conn, bool *done); 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
#endif #endif

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -77,6 +77,7 @@
#include "connect.h" #include "connect.h"
#include "strerror.h" #include "strerror.h"
#include "sockaddr.h" /* required for Curl_sockaddr_storage */ #include "sockaddr.h" /* required for Curl_sockaddr_storage */
#include "url.h"
#define _MPRINTF_REPLACE /* use our functions only */ #define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h> #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 /* 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. */ 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], snprintf((char *)&state->spacket.data[2],
TFTP_BLOCKSIZE, TFTP_BLOCKSIZE,
"%s%c%s%c", filename, '\0', mode, '\0'); "%s%c%s%c", filename, '\0', mode, '\0');
@ -622,9 +624,11 @@ CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done)
* The done callback * 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)status; /* unused */
(void)premature; /* not used */
#if 0 #if 0
free(conn->data->reqdata.proto.tftp); free(conn->data->reqdata.proto.tftp);

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -26,6 +26,6 @@
#ifndef CURL_DISABLE_TFTP #ifndef CURL_DISABLE_TFTP
CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done); CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done);
CURLcode Curl_tftp(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
#endif #endif

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

@ -4087,7 +4087,7 @@ CURLcode Curl_async_resolved(struct connectdata *conn,
CURLcode Curl_done(struct connectdata **connp, 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 */ error was detected */
{ {
CURLcode result; CURLcode result;
@ -4127,7 +4127,7 @@ CURLcode Curl_done(struct connectdata **connp,
/* this calls the protocol-specific function pointer previously set */ /* this calls the protocol-specific function pointer previously set */
if(conn->curl_done) if(conn->curl_done)
result = conn->curl_done(conn, status); result = conn->curl_done(conn, status, premature);
else else
result = CURLE_OK; 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"); infof(data, "Re-used connection seems dead, get a new one\n");
conn->bits.close = TRUE; /* enforce close of this connection */ 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 */ /* conn may no longer be a good pointer */

@ -39,7 +39,7 @@ CURLcode Curl_async_resolved(struct connectdata *conn,
bool *protocol_connect); bool *protocol_connect);
CURLcode Curl_do(struct connectdata **, bool *done); CURLcode Curl_do(struct connectdata **, bool *done);
CURLcode Curl_do_more(struct connectdata *); 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_disconnect(struct connectdata *);
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);

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