1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-22 08:08:50 -05:00

always-multi: always use non-blocking internals

Remove internal separated behavior of the easy vs multi intercace.
curl_easy_perform() is now using the multi interface itself.

Several minor multi interface quirks and bugs have been fixed in the
process.

Much help with debugging this has been provided by: Yang Tse
This commit is contained in:
Daniel Stenberg 2013-01-17 12:59:23 +01:00
parent 9fd88abb70
commit c43127414d
54 changed files with 490 additions and 884 deletions

View File

@ -21,8 +21,7 @@
2. libcurl - multi interface 2. libcurl - multi interface
2.1 More non-blocking 2.1 More non-blocking
2.2 Remove easy interface internally 2.2 Fix HTTP Pipelining for PUT
2.4 Fix HTTP Pipelining for PUT
3. Documentation 3. Documentation
3.1 More and better 3.1 More and better
@ -191,16 +190,7 @@
- The "DONE" operation (post transfer protocol-specific actions) for the - The "DONE" operation (post transfer protocol-specific actions) for the
protocols SFTP, SMTP, FTP. Fixing Curl_done() for this is a worthy task. protocols SFTP, SMTP, FTP. Fixing Curl_done() for this is a worthy task.
2.2 Remove easy interface internally 2.2 Fix HTTP Pipelining for PUT
Make curl_easy_perform() a wrapper-function that simply creates a multi
handle, adds the easy handle to it, runs curl_multi_perform() until the
transfer is done, then detach the easy handle, destroy the multi handle and
return the easy handle's return code. This will thus make everything
internally use and assume the multi interface. The select()-loop should use
curl_multi_socket().
2.4 Fix HTTP Pipelining for PUT
HTTP Pipelining can be a way to greatly enhance performance for multiple HTTP Pipelining can be a way to greatly enhance performance for multiple
serial requests and currently libcurl only supports that for HEAD and GET serial requests and currently libcurl only supports that for HEAD and GET

View File

@ -43,4 +43,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \
gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h \ gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h \
curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h \ curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h \
curl_sasl.h curl_schannel.h curl_multibyte.h curl_darwinssl.h \ curl_sasl.h curl_schannel.h curl_multibyte.h curl_darwinssl.h \
hostcheck.h bundles.h conncache.h curl_setup_once.h hostcheck.h bundles.h conncache.h curl_setup_once.h multihandle.h

View File

@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se> * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
* Copyright (C) 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2012 - 2013, 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
@ -47,7 +47,7 @@ static void free_bundle_hash_entry(void *freethis)
Curl_bundle_destroy(b); Curl_bundle_destroy(b);
} }
struct conncache *Curl_conncache_init(conncachetype type) struct conncache *Curl_conncache_init(void)
{ {
struct conncache *connc; struct conncache *connc;
@ -63,9 +63,6 @@ struct conncache *Curl_conncache_init(conncachetype type)
return NULL; return NULL;
} }
connc->type = type;
connc->num_connections = 0;
return connc; return connc;
} }

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se> * Copyright (C) 2012, 2013, Linus Nielsen Feltzing, <linus@haxx.se>
* *
* 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
@ -22,18 +22,12 @@
* *
***************************************************************************/ ***************************************************************************/
typedef enum {
CONNCACHE_PRIVATE, /* used for an easy handle alone */
CONNCACHE_MULTI /* shared within a multi handle */
} conncachetype;
struct conncache { struct conncache {
struct curl_hash *hash; struct curl_hash *hash;
conncachetype type;
size_t num_connections; size_t num_connections;
}; };
struct conncache *Curl_conncache_init(conncachetype type); struct conncache *Curl_conncache_init(void);
void Curl_conncache_destroy(struct conncache *connc); void Curl_conncache_destroy(struct conncache *connc);

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -74,6 +74,8 @@
#include "sslgen.h" /* for Curl_ssl_check_cxn() */ #include "sslgen.h" /* for Curl_ssl_check_cxn() */
#include "progress.h" #include "progress.h"
#include "warnless.h" #include "warnless.h"
#include "conncache.h"
#include "multihandle.h"
/* The last #include file should be: */ /* The last #include file should be: */
#include "memdebug.h" #include "memdebug.h"
@ -980,8 +982,7 @@ singleipconnect(struct connectdata *conn,
/* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
connect(). We can be sure of this since connect() cannot return 1. */ connect(). We can be sure of this since connect() cannot return 1. */
if((WAITCONN_TIMEOUT == rc) && if(WAITCONN_TIMEOUT == rc) {
(data->state.used_interface == Curl_if_multi)) {
/* Timeout when running the multi interface */ /* Timeout when running the multi interface */
*sockp = sockfd; *sockp = sockfd;
return CURLE_OK; return CURLE_OK;
@ -1072,9 +1073,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* start connecting to the IP curr_addr points to */ /* start connecting to the IP curr_addr points to */
res = singleipconnect(conn, curr_addr, res = singleipconnect(conn, curr_addr,
/* don't hang when doing multi */ 0, /* don't hang when doing multi */
(data->state.used_interface == Curl_if_multi)?0: &sockfd, connected);
conn->timeoutms_per_addr, &sockfd, connected);
if(res) if(res)
return res; return res;
@ -1112,6 +1112,21 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
return CURLE_OK; return CURLE_OK;
} }
struct connfind {
struct connectdata *tofind;
bool found;
};
static int conn_is_conn(struct connectdata *conn, void *param)
{
struct connfind *f = (struct connfind *)param;
if(conn == f->tofind) {
f->found = TRUE;
return 1;
}
return 0;
}
/* /*
* Used to extract socket and connectdata struct for the most recent * Used to extract socket and connectdata struct for the most recent
* transfer on the given SessionHandle. * transfer on the given SessionHandle.
@ -1125,8 +1140,21 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
DEBUGASSERT(data); DEBUGASSERT(data);
if(data->state.lastconnect) { /* this only works for an easy handle that has been used for
curl_easy_perform()! */
if(data->state.lastconnect && data->multi_easy) {
struct connectdata *c = data->state.lastconnect; struct connectdata *c = data->state.lastconnect;
struct connfind find;
find.tofind = data->state.lastconnect;
find.found = FALSE;
Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
if(!find.found) {
data->state.lastconnect = NULL;
return CURL_SOCKET_BAD;
}
if(connp) if(connp)
/* only store this if the caller cares for it */ /* only store this if the caller cares for it */
*connp = c; *connp = c;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -385,40 +385,46 @@ CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
return ret; return ret;
} }
#ifdef CURL_MULTIEASY /*
/*************************************************************************** * curl_easy_perform() is the external interface that performs a blocking
* This function is still only for testing purposes. It makes a great way * transfer as previously setup.
* to run the full test suite on the multi interface instead of the easy one.
***************************************************************************
* *
* The *new* curl_easy_perform() is the external interface that performs a * CONCEPT: This function creates a multi handle, adds the easy handle to it,
* transfer previously setup.
*
* Wrapper-function that: creates a multi handle, adds the easy handle to it,
* runs curl_multi_perform() until the transfer is done, then detaches the * runs curl_multi_perform() until the transfer is done, then detaches the
* easy handle, destroys the multi handle and returns the easy handle's return * easy handle, destroys the multi handle and returns the easy handle's return
* code. This will make everything internally use and assume multi interface. * code.
*
* REALITY: it can't just create and destroy the multi handle that easily. It
* needs to keep it around since if this easy handle is used again by this
* function, the same multi handle must be re-used so that the same pools and
* caches can be used.
*/ */
CURLcode curl_easy_perform(CURL *easy) CURLcode curl_easy_perform(CURL *easy)
{ {
CURLM *multi; CURLM *multi;
CURLMcode mcode; CURLMcode mcode;
CURLcode code = CURLE_OK; CURLcode code = CURLE_OK;
int still_running;
struct timeval timeout;
int rc;
CURLMsg *msg; CURLMsg *msg;
fd_set fdread; bool done = FALSE;
fd_set fdwrite; int rc;
fd_set fdexcep; struct SessionHandle *data = easy;
int maxfd;
if(!easy) if(!easy)
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
if(data->multi) {
failf(data, "easy handled already used in multi handle");
return CURLE_FAILED_INIT;
}
if(data->multi_easy)
multi = data->multi_easy;
else {
multi = curl_multi_init(); multi = curl_multi_init();
if(!multi) if(!multi)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
data->multi_easy = multi;
}
mcode = curl_multi_add_handle(multi, easy); mcode = curl_multi_add_handle(multi, easy);
if(mcode) { if(mcode) {
@ -429,108 +435,33 @@ CURLcode curl_easy_perform(CURL *easy)
return CURLE_FAILED_INIT; return CURLE_FAILED_INIT;
} }
/* we start some action by calling perform right away */ /* assign this after curl_multi_add_handle() since that function checks for
it and rejects this handle otherwise */
data->multi = multi;
do { while(!done && !mcode) {
while(CURLM_CALL_MULTI_PERFORM == int still_running;
curl_multi_perform(multi, &still_running));
if(!still_running) mcode = curl_multi_wait(multi, NULL, 0, 1000, NULL);
break;
FD_ZERO(&fdread); if(mcode == CURLM_OK)
FD_ZERO(&fdwrite); mcode = curl_multi_perform(multi, &still_running);
FD_ZERO(&fdexcep);
/* timeout once per second */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
/* Old deprecated style: get file descriptors from the transfers */
curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd);
rc = Curl_select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
/* The way is to extract the sockets and wait for them without using
select. This whole alternative version should probably rather use the
curl_multi_socket() approach. */
if(rc == -1)
/* select error */
break;
/* timeout or data to send/receive => loop! */
} while(still_running);
/* only read 'still_running' if curl_multi_perform() return OK */
if((mcode == CURLM_OK) && !still_running) {
msg = curl_multi_info_read(multi, &rc); msg = curl_multi_info_read(multi, &rc);
if(msg) if(msg) {
code = msg->data.result; code = msg->data.result;
done = TRUE;
}
}
}
mcode = curl_multi_remove_handle(multi, easy); mcode = curl_multi_remove_handle(multi, easy);
/* what to do if it fails? */
mcode = curl_multi_cleanup(multi);
/* what to do if it fails? */
/* The multi handle is kept alive, owned by the easy handle */
return code; return code;
} }
#else
/*
* curl_easy_perform() is the external interface that performs a transfer
* previously setup.
*/
CURLcode curl_easy_perform(CURL *curl)
{
struct SessionHandle *data = (struct SessionHandle *)curl;
if(!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
if(! (data->share && data->share->hostcache)) {
/* this handle is not using a shared dns cache */
if(data->set.global_dns_cache &&
(data->dns.hostcachetype != HCACHE_GLOBAL)) {
/* global dns cache was requested but still isn't */
struct curl_hash *ptr;
if(data->dns.hostcachetype == HCACHE_PRIVATE) {
/* if the current cache is private, kill it first */
Curl_hash_destroy(data->dns.hostcache);
data->dns.hostcachetype = HCACHE_NONE;
data->dns.hostcache = NULL;
}
ptr = Curl_global_host_cache_init();
if(ptr) {
/* only do this if the global cache init works */
data->dns.hostcache = ptr;
data->dns.hostcachetype = HCACHE_GLOBAL;
}
}
if(!data->dns.hostcache) {
data->dns.hostcachetype = HCACHE_PRIVATE;
data->dns.hostcache = Curl_mk_dnscache();
if(!data->dns.hostcache)
/* While we possibly could survive and do good without a host cache,
the fact that creating it failed indicates that things are truly
screwed up and we should bail out! */
return CURLE_OUT_OF_MEMORY;
}
}
if(!data->state.conn_cache) {
/* Oops, no connection cache, create one */
data->state.conn_cache = Curl_conncache_init(CONNCACHE_PRIVATE);
if(!data->state.conn_cache)
return CURLE_OUT_OF_MEMORY;
}
return Curl_perform(data);
}
#endif
/* /*
* curl_easy_cleanup() is the external interface to cleaning/freeing the given * curl_easy_cleanup() is the external interface to cleaning/freeing the given
@ -553,10 +484,6 @@ void Curl_easy_addmulti(struct SessionHandle *data,
void *multi) void *multi)
{ {
data->multi = multi; data->multi = multi;
if(multi == NULL)
/* the association is cleared, mark the easy handle as not used by an
interface */
data->state.used_interface = Curl_if_none;
} }
void Curl_easy_initHandleData(struct SessionHandle *data) void Curl_easy_initHandleData(struct SessionHandle *data)

108
lib/ftp.c
View File

@ -101,8 +101,17 @@
#endif #endif
/* Local API functions */ /* Local API functions */
static void state(struct connectdata *conn, #ifndef DEBUGBUILD
static void _state(struct connectdata *conn,
ftpstate newstate); ftpstate newstate);
#define state(x,y) _state(x,y)
#else
static void _state(struct connectdata *conn,
ftpstate newstate,
int lineno);
#define state(x,y) _state(x,y,__LINE__)
#endif
static CURLcode ftp_sendquote(struct connectdata *conn, static CURLcode ftp_sendquote(struct connectdata *conn,
struct curl_slist *quote); struct curl_slist *quote);
static CURLcode ftp_quit(struct connectdata *conn); static CURLcode ftp_quit(struct connectdata *conn);
@ -149,6 +158,8 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
struct pingpong *pp, struct pingpong *pp,
int *ftpcode, int *ftpcode,
size_t *size); size_t *size);
static CURLcode ftp_dophase_done(struct connectdata *conn,
bool connected);
/* easy-to-use macro: */ /* easy-to-use macro: */
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \ #define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
@ -528,18 +539,15 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
* *
* AllowServerConnect() * AllowServerConnect()
* *
* When we've issue the PORT command, we have told the server to connect * When we've issue the PORT command, we have told the server to connect to
* to us. This function * us. This function checks whether data connection is established if so it is
* - will sit and wait here until the server has connected for easy interface * accepted.
* - will check whether data connection is established if so it is accepted
* for multi interface
* *
*/ */
static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected) static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
{ {
struct SessionHandle *data = conn->data; struct SessionHandle *data = conn->data;
long timeout_ms; long timeout_ms;
long interval_ms;
CURLcode ret = CURLE_OK; CURLcode ret = CURLE_OK;
*connected = FALSE; *connected = FALSE;
@ -548,7 +556,6 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
/* Save the time we start accepting server connect */ /* Save the time we start accepting server connect */
Curl_pgrsTime(data, TIMER_STARTACCEPT); Curl_pgrsTime(data, TIMER_STARTACCEPT);
for(;;) {
timeout_ms = ftp_timeleft_accept(data); timeout_ms = ftp_timeleft_accept(data);
if(timeout_ms < 0) { if(timeout_ms < 0) {
/* if a timeout was already reached, bail out */ /* if a timeout was already reached, bail out */
@ -569,17 +576,6 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
ret = InitiateTransfer(conn); ret = InitiateTransfer(conn);
if(ret) if(ret)
return ret; return ret;
break; /* connection is accepted, break the loop */
}
else {
if(data->state.used_interface == Curl_if_easy) {
interval_ms = 1000;
if(timeout_ms < interval_ms)
interval_ms = timeout_ms;
/* sleep for 1 second and then continue */
Curl_socket_ready(CURL_SOCKET_BAD, CURL_SOCKET_BAD, interval_ms);
} }
else { else {
/* Add timeout to multi handle and break out of the loop */ /* Add timeout to multi handle and break out of the loop */
@ -589,10 +585,6 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
else else
Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT); Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
} }
break; /* connection was not accepted immediately */
}
}
} }
return ret; return ret;
@ -787,8 +779,12 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
} }
/* This is the ONLY way to change FTP state! */ /* This is the ONLY way to change FTP state! */
static void state(struct connectdata *conn, static void _state(struct connectdata *conn,
ftpstate newstate) ftpstate newstate
#ifdef DEBUGBUILD
, int lineno
#endif
)
{ {
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
/* for debug purposes */ /* for debug purposes */
@ -833,8 +829,8 @@ static void state(struct connectdata *conn,
struct ftp_conn *ftpc = &conn->proto.ftpc; struct ftp_conn *ftpc = &conn->proto.ftpc;
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
if(ftpc->state != newstate) if(ftpc->state != newstate)
infof(conn->data, "FTP %p state change from %s to %s\n", infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
ftpc, names[ftpc->state], names[newstate]); ftpc, lineno, names[ftpc->state], names[newstate]);
#endif #endif
ftpc->state = newstate; ftpc->state = newstate;
} }
@ -2071,10 +2067,19 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
if(result) if(result)
return result; return result;
if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
/* the CONNECT procedure is not complete, the tunnel is not yet up */
state(conn, FTP_STOP); /* this phase is completed */
conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
return result;
}
} }
conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
conn->bits.do_more = TRUE;
state(conn, FTP_STOP); /* this phase is completed */ state(conn, FTP_STOP); /* this phase is completed */
return result; return result;
@ -2108,6 +2113,7 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn,
else { else {
infof(data, "Connect data stream actively\n"); infof(data, "Connect data stream actively\n");
state(conn, FTP_STOP); /* end of DO phase */ state(conn, FTP_STOP); /* end of DO phase */
result = ftp_dophase_done(conn, FALSE);
} }
return result; return result;
@ -3206,7 +3212,6 @@ static CURLcode ftp_connect(struct connectdata *conn,
{ {
CURLcode result; CURLcode result;
struct ftp_conn *ftpc = &conn->proto.ftpc; struct ftp_conn *ftpc = &conn->proto.ftpc;
struct SessionHandle *data=conn->data;
struct pingpong *pp = &ftpc->pp; struct pingpong *pp = &ftpc->pp;
*done = FALSE; /* default to not done yet */ *done = FALSE; /* default to not done yet */
@ -3240,13 +3245,7 @@ static CURLcode ftp_connect(struct connectdata *conn,
response */ response */
state(conn, FTP_WAIT220); state(conn, FTP_WAIT220);
if(data->state.used_interface == Curl_if_multi)
result = ftp_multi_statemach(conn, done); result = ftp_multi_statemach(conn, done);
else {
result = ftp_easy_statemach(conn);
if(!result)
*done = TRUE;
}
return result; return result;
} }
@ -3681,6 +3680,14 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
/* if the second connection isn't done yet, wait for it */ /* if the second connection isn't done yet, wait for it */
if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
/* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
aren't used so we blank their arguments. TODO: make this nicer */
result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
return result;
}
result = Curl_is_connected(conn, SECONDARYSOCKET, &connected); result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
/* Ready to do more? */ /* Ready to do more? */
@ -3691,9 +3698,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
return result; return result;
} }
if((data->state.used_interface == Curl_if_multi) && if(ftpc->state) {
ftpc->state) { /* already in a state so skip the intial commands.
/* multi interface and already in a state so skip the intial commands.
They are only done to kickstart the do_more state */ They are only done to kickstart the do_more state */
result = ftp_multi_statemach(conn, complete); result = ftp_multi_statemach(conn, complete);
@ -3701,6 +3707,12 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
immediately */ immediately */
if(result || (ftpc->wait_data_conn != TRUE)) if(result || (ftpc->wait_data_conn != TRUE))
return result; return result;
if(ftpc->wait_data_conn)
/* if we reach the end of the FTP state machine here, *complete will be
TRUE but so is ftpc->wait_data_conn, which says we need to wait for
the data connection and therefore we're not actually complete */
*complete = FALSE;
} }
if(ftp->transfer <= FTPTRANSFER_INFO) { if(ftp->transfer <= FTPTRANSFER_INFO) {
@ -3729,6 +3741,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE); result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
if(result) if(result)
return result; return result;
result = ftp_multi_statemach(conn, complete);
} }
else { else {
/* download */ /* download */
@ -3755,14 +3769,10 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
if(result) if(result)
return result; return result;
} }
}
if(data->state.used_interface == Curl_if_multi) {
result = ftp_multi_statemach(conn, complete);
return result; result = ftp_multi_statemach(conn, complete);
} }
else return result;
result = ftp_easy_statemach(conn);
} }
if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY)) if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
@ -3805,7 +3815,6 @@ CURLcode ftp_perform(struct connectdata *conn,
ftp->transfer = FTPTRANSFER_INFO; ftp->transfer = FTPTRANSFER_INFO;
} }
*dophase_done = FALSE; /* not done yet */ *dophase_done = FALSE; /* not done yet */
/* start the first command in the DO phase */ /* start the first command in the DO phase */
@ -3814,16 +3823,12 @@ CURLcode ftp_perform(struct connectdata *conn,
return result; return result;
/* run the state-machine */ /* run the state-machine */
if(conn->data->state.used_interface == Curl_if_multi)
result = ftp_multi_statemach(conn, dophase_done); result = ftp_multi_statemach(conn, dophase_done);
else {
result = ftp_easy_statemach(conn);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect[FIRSTSOCKET]; *connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) if(*dophase_done)
DEBUGF(infof(conn->data, "DO phase is complete\n")); DEBUGF(infof(conn->data, "DO phase is complete1\n"));
return result; return result;
} }
@ -4476,7 +4481,7 @@ static CURLcode ftp_doing(struct connectdata *conn,
else if(*dophase_done) { else if(*dophase_done) {
result = ftp_dophase_done(conn, FALSE /* not connected */); result = ftp_dophase_done(conn, FALSE /* not connected */);
DEBUGF(infof(conn->data, "DO phase is complete\n")); DEBUGF(infof(conn->data, "DO phase is complete2\n"));
} }
return result; return result;
} }
@ -4521,6 +4526,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
return CURLE_OK; return CURLE_OK;
result = ftp_dophase_done(conn, connected); result = ftp_dophase_done(conn, connected);
if(result) if(result)
return result; return result;
} }

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -1295,22 +1295,16 @@ Curl_compareheader(const char *headerline, /* line to check */
*/ */
CURLcode Curl_http_connect(struct connectdata *conn, bool *done) CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
{ {
struct SessionHandle *data;
CURLcode result; CURLcode result;
data=conn->data;
/* We default to persistent connections. We set this already in this connect /* We default to persistent connections. We set this already in this connect
function to make the re-use checks properly be able to check this bit. */ function to make the re-use checks properly be able to check this bit. */
conn->bits.close = FALSE; conn->bits.close = FALSE;
if(data->state.used_interface == Curl_if_multi) { /* the CONNECT procedure might not have been completed */
/* when the multi interface is used, the CONNECT procedure might not have
been completed */
result = Curl_proxy_connect(conn); result = Curl_proxy_connect(conn);
if(result) if(result)
return result; return result;
}
if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
/* nothing else to do except wait right now - we're not done here. */ /* nothing else to do except wait right now - we're not done here. */
@ -1318,22 +1312,12 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
if(conn->given->flags & PROTOPT_SSL) { if(conn->given->flags & PROTOPT_SSL) {
/* perform SSL initialization */ /* perform SSL initialization */
if(data->state.used_interface == Curl_if_multi) {
result = https_connecting(conn, done); result = https_connecting(conn, done);
if(result) if(result)
return result; return result;
} }
else { else
/* BLOCKING */
result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(result)
return result;
*done = TRUE; *done = TRUE;
}
}
else {
*done = TRUE;
}
return CURLE_OK; return CURLE_OK;
} }

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -87,13 +87,6 @@ CURLcode Curl_proxy_connect(struct connectdata *conn)
* Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
* function will issue the necessary commands to get a seamless tunnel through * function will issue the necessary commands to get a seamless tunnel through
* this proxy. After that, the socket can be used just as a normal socket. * this proxy. After that, the socket can be used just as a normal socket.
*
* This badly needs to be rewritten. CONNECT should be sent and dealt with
* like any ordinary HTTP request, and not specially crafted like this. This
* function only remains here like this for now since the rewrite is a bit too
* much work to do at the moment.
*
* This function is BLOCKING which is nasty for all multi interface using apps.
*/ */
CURLcode Curl_proxyCONNECT(struct connectdata *conn, CURLcode Curl_proxyCONNECT(struct connectdata *conn,
@ -244,8 +237,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
return CURLE_RECV_ERROR; return CURLE_RECV_ERROR;
} }
/* if we're in multi-mode and we would block, return instead for a retry */
if(Curl_if_multi == data->state.used_interface) {
if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0)) if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
/* return so we'll be called again polling-style */ /* return so we'll be called again polling-style */
return CURLE_OK; return CURLE_OK;
@ -254,10 +245,6 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
"Multi mode finished polling for response from " "Multi mode finished polling for response from "
"proxy CONNECT\n")); "proxy CONNECT\n"));
} }
}
else {
DEBUGF(infof(data, "Easy mode waiting response from proxy CONNECT\n"));
}
/* at this point, either: /* at this point, either:
1) we're in easy-mode and so it's okay to block waiting for a CONNECT 1) we're in easy-mode and so it's okay to block waiting for a CONNECT
@ -572,6 +559,12 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
if(closeConnection && data->req.newurl) if(closeConnection && data->req.newurl)
conn->bits.proxy_connect_closed = TRUE; conn->bits.proxy_connect_closed = TRUE;
if(data->req.newurl) {
/* this won't be used anymore for the CONNECT so free it now */
free(data->req.newurl);
data->req.newurl = NULL;
}
/* to back to init state */ /* to back to init state */
conn->tunnel_state[sockindex] = TUNNEL_INIT; conn->tunnel_state[sockindex] = TUNNEL_INIT;

View File

@ -633,19 +633,9 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
result = imap_state_capability(conn); result = imap_state_capability(conn);
} }
else { else {
if(data->state.used_interface == Curl_if_multi) {
state(conn, IMAP_UPGRADETLS); state(conn, IMAP_UPGRADETLS);
result = imap_state_upgrade_tls(conn); return imap_state_upgrade_tls(conn);
} }
else {
result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(CURLE_OK == result) {
imap_to_imaps(conn);
result = imap_state_capability(conn);
}
}
}
return result; return result;
} }
@ -1358,7 +1348,6 @@ static CURLcode imap_connect(struct connectdata *conn,
{ {
CURLcode result; CURLcode result;
struct imap_conn *imapc = &conn->proto.imapc; struct imap_conn *imapc = &conn->proto.imapc;
struct SessionHandle *data=conn->data;
struct pingpong *pp = &imapc->pp; struct pingpong *pp = &imapc->pp;
*done = FALSE; /* default to not done yet */ *done = FALSE; /* default to not done yet */
@ -1379,17 +1368,7 @@ static CURLcode imap_connect(struct connectdata *conn,
pp->endofresp = imap_endofresp; pp->endofresp = imap_endofresp;
pp->conn = conn; pp->conn = conn;
if((conn->handler->flags & PROTOPT_SSL) && Curl_pp_init(pp); /* init generic pingpong data */
data->state.used_interface != Curl_if_multi) {
/* IMAPS is simply imap with SSL for the control channel */
/* so perform the SSL initialization for this socket */
result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(result)
return result;
}
/* Initialise the response reader stuff */
Curl_pp_init(pp);
/* Start off waiting for the server greeting response */ /* Start off waiting for the server greeting response */
state(conn, IMAP_SERVERGREET); state(conn, IMAP_SERVERGREET);
@ -1397,13 +1376,7 @@ static CURLcode imap_connect(struct connectdata *conn,
/* Start off with an id of '*' */ /* Start off with an id of '*' */
imapc->idstr = "*"; imapc->idstr = "*";
if(data->state.used_interface == Curl_if_multi)
result = imap_multi_statemach(conn, done); result = imap_multi_statemach(conn, done);
else {
result = imap_easy_statemach(conn);
if(!result)
*done = TRUE;
}
return result; return result;
} }
@ -1473,13 +1446,9 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
if(result) if(result)
return result; return result;
/* Run the state-machine */ /* run the state-machine */
if(conn->data->state.used_interface == Curl_if_multi)
result = imap_multi_statemach(conn, dophase_done); result = imap_multi_statemach(conn, dophase_done);
else {
result = imap_easy_statemach(conn);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect[FIRSTSOCKET]; *connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) if(*dophase_done)

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -39,6 +39,7 @@
#include "speedcheck.h" #include "speedcheck.h"
#include "conncache.h" #include "conncache.h"
#include "bundles.h" #include "bundles.h"
#include "multihandle.h"
#define _MPRINTF_REPLACE /* use our functions only */ #define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h> #include <curl/mprintf.h>
@ -56,62 +57,6 @@
#define CURL_SOCKET_HASH_TABLE_SIZE 911 #define CURL_SOCKET_HASH_TABLE_SIZE 911
#endif #endif
struct Curl_message {
/* the 'CURLMsg' is the part that is visible to the external user */
struct CURLMsg extmsg;
};
/* NOTE: if you add a state here, add the name to the statename[] array as
well!
*/
typedef enum {
CURLM_STATE_INIT, /* 0 - start in this state */
CURLM_STATE_CONNECT, /* 1 - resolve/connect has been sent off */
CURLM_STATE_WAITRESOLVE, /* 2 - awaiting the resolve to finalize */
CURLM_STATE_WAITCONNECT, /* 3 - awaiting the connect to finalize */
CURLM_STATE_WAITPROXYCONNECT, /* 4 - awaiting proxy CONNECT to finalize */
CURLM_STATE_PROTOCONNECT, /* 5 - completing the protocol-specific connect
phase */
CURLM_STATE_WAITDO, /* 6 - wait for our turn to send the request */
CURLM_STATE_DO, /* 7 - start send off the request (part 1) */
CURLM_STATE_DOING, /* 8 - sending off the request (part 1) */
CURLM_STATE_DO_MORE, /* 9 - send off the request (part 2) */
CURLM_STATE_DO_DONE, /* 10 - done sending off request */
CURLM_STATE_WAITPERFORM, /* 11 - wait for our turn to read the response */
CURLM_STATE_PERFORM, /* 12 - transfer data */
CURLM_STATE_TOOFAST, /* 13 - wait because limit-rate exceeded */
CURLM_STATE_DONE, /* 14 - post data transfer operation */
CURLM_STATE_COMPLETED, /* 15 - operation complete */
CURLM_STATE_MSGSENT, /* 16 - the operation complete message is sent */
CURLM_STATE_LAST /* 17 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
action we should wait for */
#define MAX_SOCKSPEREASYHANDLE 5
#define GETSOCK_READABLE (0x00ff)
#define GETSOCK_WRITABLE (0xff00)
struct Curl_one_easy {
/* first, two fields for the linked list of these */
struct Curl_one_easy *next;
struct Curl_one_easy *prev;
struct SessionHandle *easy_handle; /* the easy handle for this unit */
struct connectdata *easy_conn; /* the "unit's" connection */
CURLMstate state; /* the handle's state */
CURLcode result; /* previous result */
struct Curl_message msg; /* A single posted message. */
/* Array with the plain socket numbers this handle takes care of, in no
particular order. Note that all sockets are added to the sockhash, where
the state etc are also kept. This array is mostly used to detect when a
socket is to be removed from the hash. See singlesocket(). */
curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
int numsocks;
};
#define CURL_MULTI_HANDLE 0x000bab1e #define CURL_MULTI_HANDLE 0x000bab1e
@ -120,57 +65,6 @@ struct Curl_one_easy {
#define GOOD_EASY_HANDLE(x) \ #define GOOD_EASY_HANDLE(x) \
((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
/* This is the struct known as CURLM on the outside */
struct Curl_multi {
/* First a simple identifier to easier detect if a user mix up
this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
long type;
/* We have a doubly-linked circular list with easy handles */
struct Curl_one_easy easy;
int num_easy; /* amount of entries in the linked list above. */
int num_alive; /* amount of easy handles that are added but have not yet
reached COMPLETE state */
struct curl_llist *msglist; /* a list of messages from completed transfers */
/* callback function and user data pointer for the *socket() API */
curl_socket_callback socket_cb;
void *socket_userp;
/* Hostname cache */
struct curl_hash *hostcache;
/* timetree points to the splay-tree of time nodes to figure out expire
times of all currently set timers */
struct Curl_tree *timetree;
/* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
the pluralis form, there can be more than one easy handle waiting on the
same actual socket) */
struct curl_hash *sockhash;
/* Whether pipelining is enabled for this multi handle */
bool pipelining_enabled;
/* Shared connection cache (bundles)*/
struct conncache *conn_cache;
/* This handle will be used for closing the cached connections in
curl_multi_cleanup() */
struct SessionHandle *closure_handle;
long maxconnects; /* if >0, a fixed limit of the maximum number of entries
we're allowed to grow the connection cache to */
/* timer callback and user data pointer for the *socket() API */
curl_multi_timer_callback timer_cb;
void *timer_userp;
struct timeval timer_lastcall; /* the fixed time for the timeout for the
previous callback */
};
static void singlesocket(struct Curl_multi *multi, static void singlesocket(struct Curl_multi *multi,
struct Curl_one_easy *easy); struct Curl_one_easy *easy);
static int update_timer(struct Curl_multi *multi); static int update_timer(struct Curl_multi *multi);
@ -213,7 +107,11 @@ static const char * const statename[]={
static void multi_freetimeout(void *a, void *b); static void multi_freetimeout(void *a, void *b);
/* always use this function to change state, to make debugging easier */ /* always use this function to change state, to make debugging easier */
static void multistate(struct Curl_one_easy *easy, CURLMstate state) static void mstate(struct Curl_one_easy *easy, CURLMstate state
#ifdef DEBUGBUILD
, int lineno
#endif
)
{ {
#ifdef DEBUGBUILD #ifdef DEBUGBUILD
long connection_id = -5000; long connection_id = -5000;
@ -233,9 +131,9 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
connection_id = easy->easy_conn->connection_id; connection_id = easy->easy_conn->connection_id;
infof(easy->easy_handle, infof(easy->easy_handle,
"STATE: %s => %s handle %p; (connection #%ld) \n", "STATE: %s => %s handle %p; line %d (connection #%ld) \n",
statename[oldstate], statename[easy->state], statename[oldstate], statename[easy->state],
(char *)easy, connection_id); (char *)easy, lineno, connection_id);
} }
#endif #endif
if(state == CURLM_STATE_COMPLETED) if(state == CURLM_STATE_COMPLETED)
@ -243,6 +141,12 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
easy->easy_handle->multi->num_alive--; easy->easy_handle->multi->num_alive--;
} }
#ifndef DEBUGBUILD
#define multistate(x,y) mstate(x,y)
#else
#define multistate(x,y) mstate(x,y, __LINE__)
#endif
/* /*
* We add one of these structs to the sockhash for a particular socket * We add one of these structs to the sockhash for a particular socket
*/ */
@ -396,7 +300,7 @@ CURLM *curl_multi_init(void)
if(!multi->sockhash) if(!multi->sockhash)
goto error; goto error;
multi->conn_cache = Curl_conncache_init(CONNCACHE_MULTI); multi->conn_cache = Curl_conncache_init();
if(!multi->conn_cache) if(!multi->conn_cache)
goto error; goto error;
@ -516,29 +420,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
easy->easy_handle->multi_pos = easy; easy->easy_handle->multi_pos = easy;
/* for multi interface connections, we share DNS cache automatically if the /* for multi interface connections, we share DNS cache automatically if the
easy handle's one is currently private. */ easy handle's one is currently not set. */
if(easy->easy_handle->dns.hostcache &&
(easy->easy_handle->dns.hostcachetype == HCACHE_PRIVATE)) {
Curl_hash_destroy(easy->easy_handle->dns.hostcache);
easy->easy_handle->dns.hostcache = NULL;
easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
}
if(!easy->easy_handle->dns.hostcache || if(!easy->easy_handle->dns.hostcache ||
(easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) { (easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
easy->easy_handle->dns.hostcache = multi->hostcache; easy->easy_handle->dns.hostcache = multi->hostcache;
easy->easy_handle->dns.hostcachetype = HCACHE_MULTI; easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
} }
/* On a multi stack the connection cache, owned by the multi handle, /* Point to the multi's connection cache */
is shared between all easy handles within the multi handle.
Therefore we free the private connection cache if there is one */
if(easy->easy_handle->state.conn_cache &&
easy->easy_handle->state.conn_cache->type == CONNCACHE_PRIVATE) {
Curl_conncache_destroy(easy->easy_handle->state.conn_cache);
}
/* Point now to this multi's connection cache */
easy->easy_handle->state.conn_cache = multi->conn_cache; easy->easy_handle->state.conn_cache = multi->conn_cache;
/* This adds the new entry at the 'end' of the doubly-linked circular /* This adds the new entry at the 'end' of the doubly-linked circular
@ -666,18 +555,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
} }
if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) { if(easy->easy_handle->dns.hostcachetype == HCACHE_MULTI) {
if(multi->num_easy == 1) { /* stop using the multi handle's DNS cache */
if(easy_owns_conn) {
Curl_resolver_cancel(easy->easy_conn);
if(easy->easy_conn->dns_entry) {
Curl_resolv_unlock(easy->easy_handle, easy->easy_conn->dns_entry);
easy->easy_conn->dns_entry = NULL;
}
}
Curl_hostcache_destroy(easy->easy_handle);
multi->hostcache = NULL;
}
/* clear out the usage of the shared DNS cache */
easy->easy_handle->dns.hostcache = NULL; easy->easy_handle->dns.hostcache = NULL;
easy->easy_handle->dns.hostcachetype = HCACHE_NONE; easy->easy_handle->dns.hostcachetype = HCACHE_NONE;
} }
@ -700,12 +578,9 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn); Curl_getoff_all_pipelines(easy->easy_handle, easy->easy_conn);
} }
if(easy->easy_handle->state.conn_cache->type == CONNCACHE_MULTI) { /* as this was using a shared connection cache we clear the pointer
/* if this was using the shared connection cache we clear the pointer to that since we're not part of that multi handle anymore */
to that since we're not part of that handle anymore */
easy->easy_handle->state.conn_cache = NULL; easy->easy_handle->state.conn_cache = NULL;
easy->easy_handle->state.lastconnect = NULL;
}
/* change state without using multistate(), only to make singlesocket() do /* change state without using multistate(), only to make singlesocket() do
what we want */ what we want */
@ -1025,7 +900,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool connected; bool connected;
bool async; bool async;
bool protocol_connect = FALSE; bool protocol_connect = FALSE;
bool dophase_done; bool dophase_done = FALSE;
bool done = FALSE; bool done = FALSE;
CURLMcode result = CURLM_OK; CURLMcode result = CURLM_OK;
struct SingleRequest *k; struct SingleRequest *k;
@ -1120,8 +995,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* after init, go CONNECT */ /* after init, go CONNECT */
multistate(easy, CURLM_STATE_CONNECT); multistate(easy, CURLM_STATE_CONNECT);
result = CURLM_CALL_MULTI_PERFORM; result = CURLM_CALL_MULTI_PERFORM;
data->state.used_interface = Curl_if_multi;
} }
break; break;
@ -1577,9 +1450,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!ret) if(!ret)
retry = (newurl)?TRUE:FALSE; retry = (newurl)?TRUE:FALSE;
if(retry) if(retry) {
/* if we are to retry, set the result to OK */ /* if we are to retry, set the result to OK and consider the
request as done */
easy->result = CURLE_OK; easy->result = CURLE_OK;
done = TRUE;
}
} }
if(easy->result) { if(easy->result) {
@ -1897,6 +1773,9 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
/* Close all the connections in the connection cache */ /* Close all the connections in the connection cache */
close_all_connections(multi); close_all_connections(multi);
multi->closure_handle->dns.hostcache = multi->hostcache;
Curl_hostcache_clean(multi->closure_handle);
Curl_close(multi->closure_handle); Curl_close(multi->closure_handle);
multi->closure_handle = NULL; multi->closure_handle = NULL;

134
lib/multihandle.h Normal file
View File

@ -0,0 +1,134 @@
#ifndef HEADER_CURL_MULTIHANDLE_H
#define HEADER_CURL_MULTIHANDLE_H
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2013, 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
* 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.
*
***************************************************************************/
struct Curl_message {
/* the 'CURLMsg' is the part that is visible to the external user */
struct CURLMsg extmsg;
};
/* NOTE: if you add a state here, add the name to the statename[] array as
well!
*/
typedef enum {
CURLM_STATE_INIT, /* 0 - start in this state */
CURLM_STATE_CONNECT, /* 1 - resolve/connect has been sent off */
CURLM_STATE_WAITRESOLVE, /* 2 - awaiting the resolve to finalize */
CURLM_STATE_WAITCONNECT, /* 3 - awaiting the connect to finalize */
CURLM_STATE_WAITPROXYCONNECT, /* 4 - awaiting proxy CONNECT to finalize */
CURLM_STATE_PROTOCONNECT, /* 5 - completing the protocol-specific connect
phase */
CURLM_STATE_WAITDO, /* 6 - wait for our turn to send the request */
CURLM_STATE_DO, /* 7 - start send off the request (part 1) */
CURLM_STATE_DOING, /* 8 - sending off the request (part 1) */
CURLM_STATE_DO_MORE, /* 9 - send off the request (part 2) */
CURLM_STATE_DO_DONE, /* 10 - done sending off request */
CURLM_STATE_WAITPERFORM, /* 11 - wait for our turn to read the response */
CURLM_STATE_PERFORM, /* 12 - transfer data */
CURLM_STATE_TOOFAST, /* 13 - wait because limit-rate exceeded */
CURLM_STATE_DONE, /* 14 - post data transfer operation */
CURLM_STATE_COMPLETED, /* 15 - operation complete */
CURLM_STATE_MSGSENT, /* 16 - the operation complete message is sent */
CURLM_STATE_LAST /* 17 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
action we should wait for */
#define MAX_SOCKSPEREASYHANDLE 5
#define GETSOCK_READABLE (0x00ff)
#define GETSOCK_WRITABLE (0xff00)
struct Curl_one_easy {
/* first, two fields for the linked list of these */
struct Curl_one_easy *next;
struct Curl_one_easy *prev;
struct SessionHandle *easy_handle; /* the easy handle for this unit */
struct connectdata *easy_conn; /* the "unit's" connection */
CURLMstate state; /* the handle's state */
CURLcode result; /* previous result */
struct Curl_message msg; /* A single posted message. */
/* Array with the plain socket numbers this handle takes care of, in no
particular order. Note that all sockets are added to the sockhash, where
the state etc are also kept. This array is mostly used to detect when a
socket is to be removed from the hash. See singlesocket(). */
curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
int numsocks;
};
/* This is the struct known as CURLM on the outside */
struct Curl_multi {
/* First a simple identifier to easier detect if a user mix up
this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
long type;
/* We have a doubly-linked circular list with easy handles */
struct Curl_one_easy easy;
int num_easy; /* amount of entries in the linked list above. */
int num_alive; /* amount of easy handles that are added but have not yet
reached COMPLETE state */
struct curl_llist *msglist; /* a list of messages from completed transfers */
/* callback function and user data pointer for the *socket() API */
curl_socket_callback socket_cb;
void *socket_userp;
/* Hostname cache */
struct curl_hash *hostcache;
/* timetree points to the splay-tree of time nodes to figure out expire
times of all currently set timers */
struct Curl_tree *timetree;
/* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
the pluralis form, there can be more than one easy handle waiting on the
same actual socket) */
struct curl_hash *sockhash;
/* Whether pipelining is enabled for this multi handle */
bool pipelining_enabled;
/* Shared connection cache (bundles)*/
struct conncache *conn_cache;
/* This handle will be used for closing the cached connections in
curl_multi_cleanup() */
struct SessionHandle *closure_handle;
long maxconnects; /* if >0, a fixed limit of the maximum number of entries
we're allowed to grow the connection cache to */
/* timer callback and user data pointer for the *socket() API */
curl_multi_timer_callback timer_cb;
void *timer_userp;
struct timeval timer_lastcall; /* the fixed time for the timeout for the
previous callback */
};
#endif /* HEADER_CURL_MULTIHANDLE_H */

View File

@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 2010, Howard Chu, <hyc@openldap.org> * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
* Copyright (C) 2011 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 2011 - 2013, 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
@ -192,6 +192,7 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
struct SessionHandle *data=conn->data; struct SessionHandle *data=conn->data;
int rc, proto = LDAP_VERSION3; int rc, proto = LDAP_VERSION3;
char hosturl[1024], *ptr; char hosturl[1024], *ptr;
(void)done;
strcpy(hosturl, "ldap"); strcpy(hosturl, "ldap");
ptr = hosturl+4; ptr = hosturl+4;
@ -212,23 +213,12 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
#ifdef USE_SSL #ifdef USE_SSL
if(conn->handler->flags & PROTOPT_SSL) { if(conn->handler->flags & PROTOPT_SSL) {
CURLcode res; CURLcode res;
if(data->state.used_interface == Curl_if_easy) {
res = Curl_ssl_connect(conn, FIRSTSOCKET);
if(res)
return res;
li->ssldone = TRUE;
}
else {
res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
if(res) if(res)
return res; return res;
} }
}
#endif #endif
if(data->state.used_interface == Curl_if_easy)
return ldap_connecting(conn, done);
return CURLE_OK; return CURLE_OK;
} }
@ -262,9 +252,6 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
} }
#endif #endif
if(data->state.used_interface == Curl_if_easy)
tvp = NULL; /* let ldap_result block indefinitely */
else
tvp = &tv; tvp = &tv;
retry: retry:

View File

@ -570,18 +570,9 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
result = pop3_state_capa(conn); result = pop3_state_capa(conn);
} }
else { else {
if(data->state.used_interface == Curl_if_multi) {
state(conn, POP3_UPGRADETLS); state(conn, POP3_UPGRADETLS);
result = pop3_state_upgrade_tls(conn); result = pop3_state_upgrade_tls(conn);
} }
else {
result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(CURLE_OK == result) {
pop3_to_pop3s(conn);
result = pop3_state_capa(conn);
}
}
}
return result; return result;
} }
@ -1301,7 +1292,6 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
{ {
CURLcode result; CURLcode result;
struct pop3_conn *pop3c = &conn->proto.pop3c; struct pop3_conn *pop3c = &conn->proto.pop3c;
struct SessionHandle *data = conn->data;
struct pingpong *pp = &pop3c->pp; struct pingpong *pp = &pop3c->pp;
*done = FALSE; /* default to not done yet */ *done = FALSE; /* default to not done yet */
@ -1336,13 +1326,7 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
/* Start off waiting for the server greeting response */ /* Start off waiting for the server greeting response */
state(conn, POP3_SERVERGREET); state(conn, POP3_SERVERGREET);
if(data->state.used_interface == Curl_if_multi)
result = pop3_multi_statemach(conn, done); result = pop3_multi_statemach(conn, done);
else {
result = pop3_easy_statemach(conn);
if(!result)
*done = TRUE;
}
return result; return result;
} }
@ -1418,12 +1402,8 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
return result; return result;
/* Run the state-machine */ /* Run the state-machine */
if(conn->data->state.used_interface == Curl_if_multi)
result = pop3_multi_statemach(conn, dophase_done); result = pop3_multi_statemach(conn, dophase_done);
else {
result = pop3_easy_statemach(conn);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect[FIRSTSOCKET]; *connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) if(*dophase_done)

View File

@ -493,17 +493,8 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
result = smtp_authenticate(conn); result = smtp_authenticate(conn);
} }
else { else {
if(data->state.used_interface == Curl_if_multi) {
state(conn, SMTP_UPGRADETLS); state(conn, SMTP_UPGRADETLS);
result = smtp_state_upgrade_tls(conn); return smtp_state_upgrade_tls(conn);
}
else {
result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(CURLE_OK == result) {
smtp_to_smtps(conn);
result = smtp_state_ehlo(conn);
}
}
} }
return result; return result;
@ -1300,7 +1291,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
{ {
CURLcode result; CURLcode result;
struct smtp_conn *smtpc = &conn->proto.smtpc; struct smtp_conn *smtpc = &conn->proto.smtpc;
struct SessionHandle *data = conn->data;
struct pingpong *pp = &smtpc->pp; struct pingpong *pp = &smtpc->pp;
const char *path = conn->data->state.path; const char *path = conn->data->state.path;
char localhost[HOSTNAME_MAX + 1]; char localhost[HOSTNAME_MAX + 1];
@ -1323,15 +1313,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
pp->endofresp = smtp_endofresp; pp->endofresp = smtp_endofresp;
pp->conn = conn; pp->conn = conn;
if((conn->handler->protocol & CURLPROTO_SMTPS) &&
data->state.used_interface != Curl_if_multi) {
/* SMTPS is simply smtp with SSL for the control channel */
/* so perform the SSL initialization for this socket */
result = Curl_ssl_connect(conn, FIRSTSOCKET);
if(result)
return result;
}
/* Initialise the response reader stuff */ /* Initialise the response reader stuff */
Curl_pp_init(pp); Curl_pp_init(pp);
@ -1357,13 +1338,7 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
/* Start off waiting for the server greeting response */ /* Start off waiting for the server greeting response */
state(conn, SMTP_SERVERGREET); state(conn, SMTP_SERVERGREET);
if(data->state.used_interface == Curl_if_multi)
result = smtp_multi_statemach(conn, done); result = smtp_multi_statemach(conn, done);
else {
result = smtp_easy_statemach(conn);
if(!result)
*done = TRUE;
}
return result; return result;
} }
@ -1470,13 +1445,9 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
if(result) if(result)
return result; return result;
/* Run the state-machine */ /* run the state-machine */
if(conn->data->state.used_interface == Curl_if_multi)
result = smtp_multi_statemach(conn, dophase_done); result = smtp_multi_statemach(conn, dophase_done);
else {
result = smtp_easy_statemach(conn);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect[FIRSTSOCKET]; *connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) if(*dophase_done)

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -2793,13 +2793,7 @@ static CURLcode ssh_connect(struct connectdata *conn, bool *done)
state(conn, SSH_INIT); state(conn, SSH_INIT);
if(data->state.used_interface == Curl_if_multi)
result = ssh_multi_statemach(conn, done); result = ssh_multi_statemach(conn, done);
else {
result = ssh_easy_statemach(conn, TRUE);
if(!result)
*done = TRUE;
}
return result; return result;
} }
@ -2828,13 +2822,8 @@ CURLcode scp_perform(struct connectdata *conn,
state(conn, SSH_SCP_TRANS_INIT); state(conn, SSH_SCP_TRANS_INIT);
/* run the state-machine */ /* run the state-machine */
if(conn->data->state.used_interface == Curl_if_multi) {
result = ssh_multi_statemach(conn, dophase_done); result = ssh_multi_statemach(conn, dophase_done);
}
else {
result = ssh_easy_statemach(conn, FALSE);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect[FIRSTSOCKET]; *connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) { if(*dophase_done) {
@ -3037,13 +3026,8 @@ CURLcode sftp_perform(struct connectdata *conn,
state(conn, SSH_SFTP_QUOTE_INIT); state(conn, SSH_SFTP_QUOTE_INIT);
/* run the state-machine */ /* run the state-machine */
if(conn->data->state.used_interface == Curl_if_multi) {
result = ssh_multi_statemach(conn, dophase_done); result = ssh_multi_statemach(conn, dophase_done);
}
else {
result = ssh_easy_statemach(conn, FALSE);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
*connected = conn->bits.tcpconnect[FIRSTSOCKET]; *connected = conn->bits.tcpconnect[FIRSTSOCKET];
if(*dophase_done) { if(*dophase_done) {

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -1520,16 +1520,6 @@ ossl_connect_step1(struct connectdata *conn,
SSL_CTX_set_options(connssl->ctx, ctx_options); SSL_CTX_set_options(connssl->ctx, ctx_options);
#if 0
/*
* Not sure it's needed to tell SSL_connect() that socket is
* non-blocking. It doesn't seem to care, but just return with
* SSL_ERROR_WANT_x.
*/
if(data->state.used_interface == Curl_if_multi)
SSL_CTX_ctrl(connssl->ctx, BIO_C_SET_NBIO, 1, NULL);
#endif
if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) { if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) {
if(!cert_stuff(conn, if(!cert_stuff(conn,
connssl->ctx, connssl->ctx,

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -1185,129 +1185,6 @@ static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
return (long)(state->max_time - current); return (long)(state->max_time - current);
} }
/**********************************************************
*
* tftp_easy_statemach
*
* Handle easy request until completion
*
**********************************************************/
static CURLcode tftp_easy_statemach(struct connectdata *conn)
{
int rc;
int check_time = 0;
CURLcode result = CURLE_OK;
struct SessionHandle *data = conn->data;
tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
curl_socket_t fd_read;
long timeout_ms;
struct SingleRequest *k = &data->req;
struct timeval transaction_start = Curl_tvnow();
k->start = transaction_start;
k->now = transaction_start;
/* Run the TFTP State Machine */
for(; (state->state != TFTP_STATE_FIN) && (result == CURLE_OK); ) {
timeout_ms = state->retry_time * 1000;
if(data->set.upload) {
if(data->set.max_send_speed &&
(data->progress.ulspeed > data->set.max_send_speed)) {
fd_read = CURL_SOCKET_BAD;
timeout_ms = Curl_sleep_time(data->set.max_send_speed,
data->progress.ulspeed, state->blksize);
}
else {
fd_read = state->sockfd;
}
}
else {
if(data->set.max_recv_speed &&
(data->progress.dlspeed > data->set.max_recv_speed)) {
fd_read = CURL_SOCKET_BAD;
timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
data->progress.dlspeed, state->blksize);
}
else
fd_read = state->sockfd;
}
if(data->set.timeout) {
timeout_ms = data->set.timeout - Curl_tvdiff(k->now, k->start);
if(timeout_ms > state->retry_time * 1000)
timeout_ms = state->retry_time * 1000;
else if(timeout_ms < 0)
timeout_ms = 0;
}
/* Wait until ready to read or timeout occurs */
rc = Curl_socket_ready(fd_read, CURL_SOCKET_BAD, timeout_ms);
k->now = Curl_tvnow();
/* Force a progress callback if it's been too long */
if(Curl_tvdiff(k->now, k->start) >= data->set.timeout) {
if(Curl_pgrsUpdate(conn)) {
tftp_state_machine(state, TFTP_EVENT_ERROR);
return CURLE_ABORTED_BY_CALLBACK;
}
k->start = k->now;
}
if(rc == -1) {
/* bail out */
int error = SOCKERRNO;
failf(data, "%s", Curl_strerror(conn, error));
state->event = TFTP_EVENT_ERROR;
}
else {
if(rc==0) {
/* A timeout occurred, but our timeout is variable, so maybe
just continue? */
long rtms = state->retry_time * 1000;
if(Curl_tvdiff(k->now, transaction_start) > rtms) {
state->event = TFTP_EVENT_TIMEOUT;
/* Force a look at transfer timeouts */
check_time = 1;
}
else {
continue; /* skip state machine */
}
}
else {
result = tftp_receive_packet(conn);
if(result == CURLE_OK)
transaction_start = Curl_tvnow();
if(k->bytecountp)
*k->bytecountp = k->bytecount; /* read count */
if(k->writebytecountp)
*k->writebytecountp = k->writebytecount; /* write count */
}
}
if(check_time) {
tftp_state_timeout(conn, NULL);
check_time = 0;
}
if(result)
return(result);
result = tftp_state_machine(state, state->event);
}
/* Tell curl we're done */
Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
return(result);
}
/********************************************************** /**********************************************************
* *
* tftp_multi_statemach * tftp_multi_statemach
@ -1404,12 +1281,7 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
if(state->state == TFTP_STATE_FIN || result != CURLE_OK) if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
return(result); return(result);
if(conn->data->state.used_interface == Curl_if_multi)
tftp_multi_statemach(conn, dophase_done); tftp_multi_statemach(conn, dophase_done);
else {
result = tftp_easy_statemach(conn);
*dophase_done = TRUE; /* with the easy interface we are done here */
}
if(*dophase_done) if(*dophase_done)
DEBUGF(infof(conn->data, "DO phase is complete\n")); DEBUGF(infof(conn->data, "DO phase is complete\n"));

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -2068,8 +2068,6 @@ static CURLcode Curl_do_perform(struct SessionHandle *data)
char *newurl = NULL; /* possibly a new URL to follow to! */ char *newurl = NULL; /* possibly a new URL to follow to! */
followtype follow = FOLLOW_NONE; followtype follow = FOLLOW_NONE;
data->state.used_interface = Curl_if_easy;
res = Curl_pretransfer(data); res = Curl_pretransfer(data);
if(res) if(res)
return res; return res;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -131,7 +131,6 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
#include "memdebug.h" #include "memdebug.h"
/* Local static prototypes */ /* Local static prototypes */
static bool ConnectionKillOne(struct SessionHandle *data);
static void conn_free(struct connectdata *conn); static void conn_free(struct connectdata *conn);
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
static CURLcode do_init(struct connectdata *conn); static CURLcode do_init(struct connectdata *conn);
@ -255,15 +254,6 @@ static const struct Curl_handler Curl_handler_dummy = {
PROTOPT_NONE /* flags */ PROTOPT_NONE /* flags */
}; };
static void close_connections(struct SessionHandle *data)
{
/* Loop through all open connections and kill them one by one */
bool killed;
do {
killed = ConnectionKillOne(data);
} while(killed);
}
void Curl_freeset(struct SessionHandle * data) void Curl_freeset(struct SessionHandle * data)
{ {
/* Free all dynamic strings stored in the data->set substructure. */ /* Free all dynamic strings stored in the data->set substructure. */
@ -386,6 +376,11 @@ CURLcode Curl_close(struct SessionHandle *data)
and detach this handle from there. */ and detach this handle from there. */
curl_multi_remove_handle(data->multi, data); curl_multi_remove_handle(data->multi, data);
if(data->multi_easy)
/* when curl_easy_perform() is used, it creates its own multi handle to
use and this is the one */
curl_multi_cleanup(data->multi_easy);
/* Destroy the timeout list that is held in the easy handle. It is /* Destroy the timeout list that is held in the easy handle. It is
/normally/ done by curl_multi_remove_handle() but this is "just in /normally/ done by curl_multi_remove_handle() but this is "just in
case" */ case" */
@ -398,19 +393,6 @@ CURLcode Curl_close(struct SessionHandle *data)
the multi handle, since that function uses the magic the multi handle, since that function uses the magic
field! */ field! */
if(data->state.conn_cache) {
if(data->state.conn_cache->type == CONNCACHE_PRIVATE) {
/* close all connections still alive that are in the private connection
cache, as we no longer have the pointer left to the shared one. */
close_connections(data);
Curl_conncache_destroy(data->state.conn_cache);
data->state.conn_cache = NULL;
}
}
if(data->dns.hostcachetype == HCACHE_PRIVATE)
Curl_hostcache_destroy(data);
if(data->state.rangestringalloc) if(data->state.rangestringalloc)
free(data->state.range); free(data->state.range);
@ -2000,10 +1982,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
data->share->dirty++; data->share->dirty++;
if(data->share->hostcache) { if(data->share->hostcache) {
/* use shared host cache, first free the private one if any */ /* use shared host cache */
if(data->dns.hostcachetype == HCACHE_PRIVATE)
Curl_hostcache_destroy(data);
data->dns.hostcache = data->share->hostcache; data->dns.hostcache = data->share->hostcache;
data->dns.hostcachetype = HCACHE_SHARED; data->dns.hostcachetype = HCACHE_SHARED;
} }
@ -2982,69 +2961,6 @@ ConnectionExists(struct SessionHandle *data,
return FALSE; /* no matching connecting exists */ return FALSE; /* no matching connecting exists */
} }
/*
* This function kills and removes an existing connection in the connection
* cache. The connection that has been unused for the longest time.
*
* Returns FALSE if it can't find any unused connection to kill.
*/
static bool
ConnectionKillOne(struct SessionHandle *data)
{
struct conncache *bc = data->state.conn_cache;
struct curl_hash_iterator iter;
struct curl_llist_element *curr;
struct curl_hash_element *he;
long highscore=-1;
long score;
struct timeval now;
struct connectdata *conn_candidate = NULL;
struct connectbundle *bundle;
now = Curl_tvnow();
Curl_hash_start_iterate(bc->hash, &iter);
he = Curl_hash_next_element(&iter);
while(he) {
struct connectdata *conn;
bundle = he->ptr;
curr = bundle->conn_list->head;
while(curr) {
conn = curr->ptr;
if(!conn->inuse) {
/* Set higher score for the age passed since the connection was used */
score = Curl_tvdiff(now, conn->now);
if(score > highscore) {
highscore = score;
conn_candidate = conn;
}
}
curr = curr->next;
}
he = Curl_hash_next_element(&iter);
}
if(conn_candidate) {
/* Set the connection's owner correctly */
conn_candidate->data = data;
bundle = conn_candidate->bundle;
/* the winner gets the honour of being disconnected */
(void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
return TRUE;
}
return FALSE;
}
/* this connection can now be marked 'idle' */ /* this connection can now be marked 'idle' */
static void static void
ConnectionDone(struct connectdata *conn) ConnectionDone(struct connectdata *conn)

View File

@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -1147,15 +1147,15 @@ struct auth {
}; };
struct UrlState { struct UrlState {
enum {
Curl_if_none,
Curl_if_easy,
Curl_if_multi
} used_interface;
/* Points to the connection cache */ /* Points to the connection cache */
struct conncache *conn_cache; struct conncache *conn_cache;
/* when curl_easy_perform() is called, the multi handle is "owned" by
the easy handle so curl_easy_cleanup() on such an easy handle will
also close the multi handle! */
bool multi_owned_by_easy;
/* buffers to store authentication data in, as parsed from input options */ /* buffers to store authentication data in, as parsed from input options */
struct timeval keeps_speed; /* for the progress meter really */ struct timeval keeps_speed; /* for the progress meter really */
@ -1588,7 +1588,6 @@ struct Names {
struct curl_hash *hostcache; struct curl_hash *hostcache;
enum { enum {
HCACHE_NONE, /* not pointing to anything */ HCACHE_NONE, /* not pointing to anything */
HCACHE_PRIVATE, /* points to our own */
HCACHE_GLOBAL, /* points to the (shrug) global one */ HCACHE_GLOBAL, /* points to the (shrug) global one */
HCACHE_MULTI, /* points to a shared one in the multi handle */ HCACHE_MULTI, /* points to a shared one in the multi handle */
HCACHE_SHARED /* points to a shared one in a shared object */ HCACHE_SHARED /* points to a shared one in a shared object */
@ -1608,7 +1607,11 @@ struct Names {
struct SessionHandle { struct SessionHandle {
struct Names dns; struct Names dns;
struct Curl_multi *multi; /* if non-NULL, points to the multi handle struct Curl_multi *multi; /* if non-NULL, points to the multi handle
struct to which this "belongs" */ struct to which this "belongs" when used by
the multi interface */
struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle
struct to which this "belongs" when used
by the easy interface */
struct Curl_one_easy *multi_pos; /* if non-NULL, points to its position struct Curl_one_easy *multi_pos; /* if non-NULL, points to its position
in multi controlling structure to assist in multi controlling structure to assist
in removal. */ in removal. */

View File

@ -27,7 +27,7 @@ EXTRA_DIST = ftpserver.pl httpserver.pl secureserver.pl runtests.pl getpart.pm \
FILEFORMAT README stunnel.pem memanalyze.pl testcurl.pl valgrind.pm ftp.pm \ FILEFORMAT README stunnel.pem memanalyze.pl testcurl.pl valgrind.pm ftp.pm \
sshserver.pl sshhelp.pm testcurl.1 runtests.1 $(HTMLPAGES) $(PDFPAGES) \ sshserver.pl sshhelp.pm testcurl.1 runtests.1 $(HTMLPAGES) $(PDFPAGES) \
serverhelp.pm tftpserver.pl rtspserver.pl directories.pm symbol-scan.pl \ serverhelp.pm tftpserver.pl rtspserver.pl directories.pm symbol-scan.pl \
CMakeLists.txt mem-include-scan.pl CMakeLists.txt mem-include-scan.pl valgrind.supp
# we have two variables here to make sure DIST_SUBDIRS won't get 'unit' # we have two variables here to make sure DIST_SUBDIRS won't get 'unit'
# added twice as then targets such as 'distclean' misbehave and try to # added twice as then targets such as 'distclean' misbehave and try to

View File

@ -36,6 +36,11 @@ FTP PORT download, no data conn and no transient negative reply
<strippart> <strippart>
s/^EPRT \|1\|(.*)/EPRT \|1\|/ s/^EPRT \|1\|(.*)/EPRT \|1\|/
</strippart> </strippart>
# This test doesn't send a QUIT because the main state machine in multi.c
# triggers the timeout and sets the CURLE_OPERATION_TIMEDOUT error (28) for
# which the FTP disconect code generically has to assume could mean the
# control the connection and thus it cannot send any command.
<protocol> <protocol>
USER anonymous USER anonymous
PASS ftp@example.com PASS ftp@example.com
@ -44,10 +49,9 @@ EPRT |1|
TYPE I TYPE I
SIZE 1208 SIZE 1208
RETR 1208 RETR 1208
QUIT
</protocol> </protocol>
<errorcode> <errorcode>
12 28
</errorcode> </errorcode>
</verify> </verify>
</testcase> </testcase>

View File

@ -54,6 +54,8 @@ fooo
mooo mooo
</file1> </file1>
# The final "221 bye bye baby" response to QUIT will not be recorded
# since that is not considered part of this particular transfer!
<file2 name="log/heads1349"> <file2 name="log/heads1349">
220- _ _ ____ _ 220- _ _ ____ _
220- ___| | | | _ \| | 220- ___| | | | _ \| |
@ -69,7 +71,6 @@ mooo
213 10 213 10
150 Binary data connection for 1349 () (10 bytes). 150 Binary data connection for 1349 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -54,6 +54,8 @@ fooo
mooo mooo
</file1> </file1>
# The final "221 bye bye baby" response to QUIT will not be recorded
# since that is not considered part of this particular transfer!
<file2 name="log/stdout1350"> <file2 name="log/stdout1350">
220- _ _ ____ _ 220- _ _ ____ _
220- ___| | | | _ \| | 220- ___| | | | _ \| |
@ -69,7 +71,6 @@ mooo
213 10 213 10
150 Binary data connection for 1350 () (10 bytes). 150 Binary data connection for 1350 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -55,6 +55,8 @@ fooo
mooo mooo
</file1> </file1>
# The final "221 bye bye baby" response to QUIT will not be recorded
# since that is not considered part of this particular transfer!
<file2 name="log/heads1351"> <file2 name="log/heads1351">
220- _ _ ____ _ 220- _ _ ____ _
220- ___| | | | _ \| | 220- ___| | | | _ \| |
@ -70,7 +72,6 @@ mooo
213 10 213 10
150 Binary data connection for 1351 () (10 bytes). 150 Binary data connection for 1351 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -55,6 +55,8 @@ fooo
mooo mooo
</file1> </file1>
# The final "221 bye bye baby" response to QUIT will not be recorded
# since that is not considered part of this particular transfer!
<file2 name="log/stdout1352"> <file2 name="log/stdout1352">
220- _ _ ____ _ 220- _ _ ____ _
220- ___| | | | _ \| | 220- ___| | | | _ \| |
@ -70,7 +72,6 @@ mooo
213 10 213 10
150 Binary data connection for 1352 () (10 bytes). 150 Binary data connection for 1352 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -54,6 +54,8 @@ fooo
mooo mooo
</file1> </file1>
# The final "221 bye bye baby" response to QUIT will not be recorded
# since that is not considered part of this particular transfer!
<file2 name="log/heads1353"> <file2 name="log/heads1353">
220- _ _ ____ _ 220- _ _ ____ _
220- ___| | | | _ \| | 220- ___| | | | _ \| |
@ -69,7 +71,6 @@ mooo
213 10 213 10
150 Binary data connection for 1353 () (10 bytes). 150 Binary data connection for 1353 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -69,7 +69,6 @@ mooo
213 10 213 10
150 Binary data connection for 1354 () (10 bytes). 150 Binary data connection for 1354 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -87,7 +87,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1357 () (214 bytes). 150 Binary data connection for 1357 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -87,7 +87,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1358 () (214 bytes). 150 Binary data connection for 1358 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -88,7 +88,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1359 () (214 bytes). 150 Binary data connection for 1359 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -88,7 +88,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1360 () (214 bytes). 150 Binary data connection for 1360 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -87,7 +87,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1361 () (214 bytes). 150 Binary data connection for 1361 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -87,7 +87,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1362 () (214 bytes). 150 Binary data connection for 1362 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -64,7 +64,6 @@ mooo
213 10 213 10
150 Binary data connection for 1379 () (10 bytes). 150 Binary data connection for 1379 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -64,7 +64,6 @@ mooo
213 10 213 10
150 Binary data connection for 1380 () (10 bytes). 150 Binary data connection for 1380 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -65,7 +65,6 @@ mooo
213 10 213 10
150 Binary data connection for 1381 () (10 bytes). 150 Binary data connection for 1381 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -65,7 +65,6 @@ mooo
213 10 213 10
150 Binary data connection for 1382 () (10 bytes). 150 Binary data connection for 1382 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -64,7 +64,6 @@ mooo
213 10 213 10
150 Binary data connection for 1383 () (10 bytes). 150 Binary data connection for 1383 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -64,7 +64,6 @@ mooo
213 10 213 10
150 Binary data connection for 1384 () (10 bytes). 150 Binary data connection for 1384 () (10 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -79,7 +79,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1387 () (214 bytes). 150 Binary data connection for 1387 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -79,7 +79,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1388 () (214 bytes). 150 Binary data connection for 1388 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -80,7 +80,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1389 () (214 bytes). 150 Binary data connection for 1389 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -80,7 +80,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1390 () (214 bytes). 150 Binary data connection for 1390 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -79,7 +79,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1391 () (214 bytes). 150 Binary data connection for 1391 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -79,7 +79,6 @@ MOOOO
213 214 213 214
150 Binary data connection for 1392 () (214 bytes). 150 Binary data connection for 1392 () (214 bytes).
226 File transfer complete 226 File transfer complete
221 bye bye baby
</file2> </file2>
<stripfile2> <stripfile2>
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/ s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/

View File

@ -12,7 +12,7 @@ LIST
# Server-side # Server-side
<reply> <reply>
<servercmd> <servercmd>
REPLY LIST +OK 1407 100 REPLY LIST +OK 1407 100\r\n.
</servercmd> </servercmd>
</reply> </reply>

View File

@ -101,66 +101,60 @@ run 1: set cookie 1, 2 and 3
lock: dns [Pigs in space]: 14 lock: dns [Pigs in space]: 14
unlock: dns [Pigs in space]: 15 unlock: dns [Pigs in space]: 15
CLEANUP CLEANUP
lock: dns [Pigs in space]: 16 lock: cookie [Pigs in space]: 16
unlock: dns [Pigs in space]: 17 unlock: cookie [Pigs in space]: 17
lock: cookie [Pigs in space]: 18 lock: share [Pigs in space]: 18
unlock: cookie [Pigs in space]: 19 unlock: share [Pigs in space]: 19
lock: share [Pigs in space]: 20
unlock: share [Pigs in space]: 21
*** run 2 *** run 2
CURLOPT_SHARE CURLOPT_SHARE
lock: share [Pigs in space]: 22 lock: share [Pigs in space]: 20
unlock: share [Pigs in space]: 23 unlock: share [Pigs in space]: 21
PERFORM PERFORM
lock: dns [Pigs in space]: 24 lock: dns [Pigs in space]: 22
unlock: dns [Pigs in space]: 25 unlock: dns [Pigs in space]: 23
lock: cookie [Pigs in space]: 24
unlock: cookie [Pigs in space]: 25
lock: cookie [Pigs in space]: 26 lock: cookie [Pigs in space]: 26
unlock: cookie [Pigs in space]: 27 unlock: cookie [Pigs in space]: 27
lock: cookie [Pigs in space]: 28 lock: cookie [Pigs in space]: 28
unlock: cookie [Pigs in space]: 29 unlock: cookie [Pigs in space]: 29
lock: cookie [Pigs in space]: 30
unlock: cookie [Pigs in space]: 31
run 2: set cookie 4 and 5 run 2: set cookie 4 and 5
lock: dns [Pigs in space]: 32 lock: dns [Pigs in space]: 30
unlock: dns [Pigs in space]: 33 unlock: dns [Pigs in space]: 31
CLEANUP CLEANUP
lock: dns [Pigs in space]: 34 lock: cookie [Pigs in space]: 32
unlock: dns [Pigs in space]: 35 unlock: cookie [Pigs in space]: 33
lock: cookie [Pigs in space]: 36 lock: share [Pigs in space]: 34
unlock: cookie [Pigs in space]: 37 unlock: share [Pigs in space]: 35
lock: share [Pigs in space]: 38
unlock: share [Pigs in space]: 39
*** run 3 *** run 3
CURLOPT_SHARE CURLOPT_SHARE
lock: share [Pigs in space]: 40 lock: share [Pigs in space]: 36
unlock: share [Pigs in space]: 41 unlock: share [Pigs in space]: 37
CURLOPT_COOKIEJAR CURLOPT_COOKIEJAR
PERFORM PERFORM
lock: dns [Pigs in space]: 42 lock: dns [Pigs in space]: 38
unlock: dns [Pigs in space]: 43 unlock: dns [Pigs in space]: 39
lock: cookie [Pigs in space]: 40
unlock: cookie [Pigs in space]: 41
lock: cookie [Pigs in space]: 42
unlock: cookie [Pigs in space]: 43
lock: cookie [Pigs in space]: 44 lock: cookie [Pigs in space]: 44
unlock: cookie [Pigs in space]: 45 unlock: cookie [Pigs in space]: 45
lock: cookie [Pigs in space]: 46
unlock: cookie [Pigs in space]: 47
lock: cookie [Pigs in space]: 48
unlock: cookie [Pigs in space]: 49
run 3: overwrite cookie 1 and 4 run 3: overwrite cookie 1 and 4
lock: dns [Pigs in space]: 50 lock: dns [Pigs in space]: 46
unlock: dns [Pigs in space]: 51 unlock: dns [Pigs in space]: 47
try SHARE_CLEANUP... try SHARE_CLEANUP...
lock: share [Pigs in space]: 52 lock: share [Pigs in space]: 48
unlock: share [Pigs in space]: 53 unlock: share [Pigs in space]: 49
SHARE_CLEANUP failed, correct SHARE_CLEANUP failed, correct
CLEANUP CLEANUP
lock: dns [Pigs in space]: 54 lock: cookie [Pigs in space]: 50
unlock: dns [Pigs in space]: 55 unlock: cookie [Pigs in space]: 51
lock: cookie [Pigs in space]: 56 lock: share [Pigs in space]: 52
unlock: cookie [Pigs in space]: 57 unlock: share [Pigs in space]: 53
lock: share [Pigs in space]: 58
unlock: share [Pigs in space]: 59
SHARE_CLEANUP SHARE_CLEANUP
lock: share [Pigs in space]: 60 lock: share [Pigs in space]: 54
unlock: share [Pigs in space]: 61 unlock: share [Pigs in space]: 55
GLOBAL_CLEANUP GLOBAL_CLEANUP
</stdout> </stdout>
<stderr> <stderr>

View File

@ -10,7 +10,8 @@ LIST
# Server-side # Server-side
<reply> <reply>
<servercmd> <servercmd>
REPLY LIST +OK 808 100 # include the '.\r\n' 3-byte trailer to end the transfer poperly!
REPLY LIST +OK 808 100\r\n.
</servercmd> </servercmd>
</reply> </reply>

View File

@ -34,11 +34,13 @@ pop3://%HOSTIP:%POP3PORT/813 -u user:wrong
<errorcode> <errorcode>
67 67
</errorcode> </errorcode>
#
# The multi interface considers a broken "DO" request as a prematurely broken
# transfer and such a connection will not get a "QUIT"
<protocol> <protocol>
CAPA CAPA
USER user USER user
PASS wrong PASS wrong
QUIT
</protocol> </protocol>
</verify> </verify>
</testcase> </testcase>

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2013, 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
@ -41,7 +41,7 @@
#error "this test requires FD_SETSIZE" #error "this test requires FD_SETSIZE"
#endif #endif
#define SAFETY_MARGIN (10) #define SAFETY_MARGIN (11)
#if defined(WIN32) || defined(_WIN32) || defined(MSDOS) #if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
#define DEV_NULL "NUL" #define DEV_NULL "NUL"

View File

@ -6,7 +6,7 @@
# | (__| |_| | _ <| |___ # | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____| # \___|\___/|_| \_\_____|
# #
# Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. # Copyright (C) 1998 - 2013, 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
@ -3084,6 +3084,7 @@ sub singletest {
my $valgrindcmd = "$valgrind "; my $valgrindcmd = "$valgrind ";
$valgrindcmd .= "$valgrind_tool " if($valgrind_tool); $valgrindcmd .= "$valgrind_tool " if($valgrind_tool);
$valgrindcmd .= "--leak-check=yes "; $valgrindcmd .= "--leak-check=yes ";
$valgrindcmd .= "--suppressions=valgrind.supp ";
$valgrindcmd .= "--num-callers=16 "; $valgrindcmd .= "--num-callers=16 ";
$valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum"; $valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum";
$CMDLINE = "$valgrindcmd $CMDLINE"; $CMDLINE = "$valgrindcmd $CMDLINE";

16
tests/valgrind.supp Normal file
View File

@ -0,0 +1,16 @@
{
libidn-idna_to_ascii-error
Memcheck:Addr4
fun:idna_to_ascii_4z
fun:idna_to_ascii_8z
fun:idna_to_ascii_lz
fun:fix_hostname
fun:resolve_server
fun:create_conn
fun:Curl_connect
fun:multi_runsingle
fun:curl_multi_perform
fun:curl_easy_perform
fun:operate
fun:main
}