mirror of
https://github.com/curl/curl.git
synced 2024-11-21 01:16:58 +08: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:
parent
9fd88abb70
commit
c43127414d
14
docs/TODO
14
docs/TODO
@ -21,8 +21,7 @@
|
||||
|
||||
2. libcurl - multi interface
|
||||
2.1 More non-blocking
|
||||
2.2 Remove easy interface internally
|
||||
2.4 Fix HTTP Pipelining for PUT
|
||||
2.2 Fix HTTP Pipelining for PUT
|
||||
|
||||
3. Documentation
|
||||
3.1 More and better
|
||||
@ -191,16 +190,7 @@
|
||||
- The "DONE" operation (post transfer protocol-specific actions) for the
|
||||
protocols SFTP, SMTP, FTP. Fixing Curl_done() for this is a worthy task.
|
||||
|
||||
2.2 Remove easy interface internally
|
||||
|
||||
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
|
||||
2.2 Fix HTTP Pipelining for PUT
|
||||
|
||||
HTTP Pipelining can be a way to greatly enhance performance for multiple
|
||||
serial requests and currently libcurl only supports that for HEAD and GET
|
||||
|
@ -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 \
|
||||
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 \
|
||||
hostcheck.h bundles.h conncache.h curl_setup_once.h
|
||||
hostcheck.h bundles.h conncache.h curl_setup_once.h multihandle.h
|
||||
|
@ -6,7 +6,7 @@
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* 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
|
||||
* 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);
|
||||
}
|
||||
|
||||
struct conncache *Curl_conncache_init(conncachetype type)
|
||||
struct conncache *Curl_conncache_init(void)
|
||||
{
|
||||
struct conncache *connc;
|
||||
|
||||
@ -63,9 +63,6 @@ struct conncache *Curl_conncache_init(conncachetype type)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
connc->type = type;
|
||||
connc->num_connections = 0;
|
||||
|
||||
return connc;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
* 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 curl_hash *hash;
|
||||
conncachetype type;
|
||||
size_t num_connections;
|
||||
};
|
||||
|
||||
struct conncache *Curl_conncache_init(conncachetype type);
|
||||
struct conncache *Curl_conncache_init(void);
|
||||
|
||||
void Curl_conncache_destroy(struct conncache *connc);
|
||||
|
||||
|
@ -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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@ -74,6 +74,8 @@
|
||||
#include "sslgen.h" /* for Curl_ssl_check_cxn() */
|
||||
#include "progress.h"
|
||||
#include "warnless.h"
|
||||
#include "conncache.h"
|
||||
#include "multihandle.h"
|
||||
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
@ -980,8 +982,7 @@ singleipconnect(struct connectdata *conn,
|
||||
|
||||
/* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
|
||||
connect(). We can be sure of this since connect() cannot return 1. */
|
||||
if((WAITCONN_TIMEOUT == rc) &&
|
||||
(data->state.used_interface == Curl_if_multi)) {
|
||||
if(WAITCONN_TIMEOUT == rc) {
|
||||
/* Timeout when running the multi interface */
|
||||
*sockp = sockfd;
|
||||
return CURLE_OK;
|
||||
@ -1072,9 +1073,8 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
|
||||
/* start connecting to the IP curr_addr points to */
|
||||
res = singleipconnect(conn, curr_addr,
|
||||
/* don't hang when doing multi */
|
||||
(data->state.used_interface == Curl_if_multi)?0:
|
||||
conn->timeoutms_per_addr, &sockfd, connected);
|
||||
0, /* don't hang when doing multi */
|
||||
&sockfd, connected);
|
||||
if(res)
|
||||
return res;
|
||||
|
||||
@ -1112,6 +1112,21 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
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
|
||||
* transfer on the given SessionHandle.
|
||||
@ -1125,8 +1140,21 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *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 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)
|
||||
/* only store this if the caller cares for it */
|
||||
*connp = c;
|
||||
|
163
lib/easy.c
163
lib/easy.c
@ -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
|
||||
* 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;
|
||||
}
|
||||
|
||||
#ifdef CURL_MULTIEASY
|
||||
/***************************************************************************
|
||||
* This function is still only for testing purposes. It makes a great way
|
||||
* to run the full test suite on the multi interface instead of the easy one.
|
||||
***************************************************************************
|
||||
/*
|
||||
* curl_easy_perform() is the external interface that performs a blocking
|
||||
* transfer as previously setup.
|
||||
*
|
||||
* The *new* curl_easy_perform() is the external interface that performs a
|
||||
* transfer previously setup.
|
||||
*
|
||||
* Wrapper-function that: creates a multi handle, adds the easy handle to it,
|
||||
* CONCEPT: This function creates a multi handle, adds the easy handle to it,
|
||||
* 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
|
||||
* 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)
|
||||
{
|
||||
CURLM *multi;
|
||||
CURLMcode mcode;
|
||||
CURLcode code = CURLE_OK;
|
||||
int still_running;
|
||||
struct timeval timeout;
|
||||
int rc;
|
||||
CURLMsg *msg;
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
int maxfd;
|
||||
bool done = FALSE;
|
||||
int rc;
|
||||
struct SessionHandle *data = easy;
|
||||
|
||||
if(!easy)
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
|
||||
multi = curl_multi_init();
|
||||
if(!multi)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
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();
|
||||
if(!multi)
|
||||
return CURLE_OUT_OF_MEMORY;
|
||||
data->multi_easy = multi;
|
||||
}
|
||||
|
||||
mcode = curl_multi_add_handle(multi, easy);
|
||||
if(mcode) {
|
||||
@ -429,108 +435,33 @@ CURLcode curl_easy_perform(CURL *easy)
|
||||
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(CURLM_CALL_MULTI_PERFORM ==
|
||||
curl_multi_perform(multi, &still_running));
|
||||
while(!done && !mcode) {
|
||||
int still_running;
|
||||
|
||||
if(!still_running)
|
||||
break;
|
||||
mcode = curl_multi_wait(multi, NULL, 0, 1000, NULL);
|
||||
|
||||
FD_ZERO(&fdread);
|
||||
FD_ZERO(&fdwrite);
|
||||
FD_ZERO(&fdexcep);
|
||||
if(mcode == CURLM_OK)
|
||||
mcode = curl_multi_perform(multi, &still_running);
|
||||
|
||||
/* 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);
|
||||
|
||||
msg = curl_multi_info_read(multi, &rc);
|
||||
if(msg)
|
||||
code = msg->data.result;
|
||||
/* only read 'still_running' if curl_multi_perform() return OK */
|
||||
if((mcode == CURLM_OK) && !still_running) {
|
||||
msg = curl_multi_info_read(multi, &rc);
|
||||
if(msg) {
|
||||
code = msg->data.result;
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
#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
|
||||
@ -553,10 +484,6 @@ void Curl_easy_addmulti(struct SessionHandle *data,
|
||||
void *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)
|
||||
|
168
lib/ftp.c
168
lib/ftp.c
@ -101,8 +101,17 @@
|
||||
#endif
|
||||
|
||||
/* Local API functions */
|
||||
static void state(struct connectdata *conn,
|
||||
ftpstate newstate);
|
||||
#ifndef DEBUGBUILD
|
||||
static void _state(struct connectdata *conn,
|
||||
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,
|
||||
struct curl_slist *quote);
|
||||
static CURLcode ftp_quit(struct connectdata *conn);
|
||||
@ -149,6 +158,8 @@ static CURLcode ftp_readresp(curl_socket_t sockfd,
|
||||
struct pingpong *pp,
|
||||
int *ftpcode,
|
||||
size_t *size);
|
||||
static CURLcode ftp_dophase_done(struct connectdata *conn,
|
||||
bool connected);
|
||||
|
||||
/* easy-to-use macro: */
|
||||
#define FTPSENDF(x,y,z) if((result = Curl_ftpsendf(x,y,z)) != CURLE_OK) \
|
||||
@ -411,7 +422,7 @@ static long ftp_timeleft_accept(struct SessionHandle *data)
|
||||
* connection for a negative response regarding a failure in connecting
|
||||
*
|
||||
*/
|
||||
static CURLcode ReceivedServerConnect(struct connectdata* conn, bool* received)
|
||||
static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
|
||||
@ -514,8 +525,8 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
|
||||
else {
|
||||
/* FTP download: */
|
||||
Curl_setup_transfer(conn, SECONDARYSOCKET,
|
||||
conn->proto.ftpc.retr_size_saved, FALSE,
|
||||
ftp->bytecountp, -1, NULL); /* no upload here */
|
||||
conn->proto.ftpc.retr_size_saved, FALSE,
|
||||
ftp->bytecountp, -1, NULL); /* no upload here */
|
||||
}
|
||||
|
||||
conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
|
||||
@ -528,18 +539,15 @@ static CURLcode InitiateTransfer(struct connectdata *conn)
|
||||
*
|
||||
* AllowServerConnect()
|
||||
*
|
||||
* When we've issue the PORT command, we have told the server to connect
|
||||
* to us. This function
|
||||
* - will sit and wait here until the server has connected for easy interface
|
||||
* - will check whether data connection is established if so it is accepted
|
||||
* for multi interface
|
||||
* When we've issue the PORT command, we have told the server to connect to
|
||||
* us. This function checks whether data connection is established if so it is
|
||||
* accepted.
|
||||
*
|
||||
*/
|
||||
static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
long timeout_ms;
|
||||
long interval_ms;
|
||||
CURLcode ret = CURLE_OK;
|
||||
|
||||
*connected = FALSE;
|
||||
@ -548,50 +556,34 @@ static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
|
||||
/* Save the time we start accepting server connect */
|
||||
Curl_pgrsTime(data, TIMER_STARTACCEPT);
|
||||
|
||||
for(;;) {
|
||||
timeout_ms = ftp_timeleft_accept(data);
|
||||
if(timeout_ms < 0) {
|
||||
/* if a timeout was already reached, bail out */
|
||||
failf(data, "Accept timeout occurred while waiting server connect");
|
||||
return CURLE_FTP_ACCEPT_TIMEOUT;
|
||||
}
|
||||
timeout_ms = ftp_timeleft_accept(data);
|
||||
if(timeout_ms < 0) {
|
||||
/* if a timeout was already reached, bail out */
|
||||
failf(data, "Accept timeout occurred while waiting server connect");
|
||||
return CURLE_FTP_ACCEPT_TIMEOUT;
|
||||
}
|
||||
|
||||
/* see if the connection request is already here */
|
||||
ret = ReceivedServerConnect(conn, connected);
|
||||
/* see if the connection request is already here */
|
||||
ret = ReceivedServerConnect(conn, connected);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
if(*connected) {
|
||||
ret = AcceptServerConnect(conn);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
if(*connected) {
|
||||
ret = AcceptServerConnect(conn);
|
||||
if(ret)
|
||||
return ret;
|
||||
|
||||
ret = InitiateTransfer(conn);
|
||||
if(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 {
|
||||
/* Add timeout to multi handle and break out of the loop */
|
||||
if(ret == CURLE_OK && *connected == FALSE) {
|
||||
if(data->set.accepttimeout > 0)
|
||||
Curl_expire(data, data->set.accepttimeout);
|
||||
else
|
||||
Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
|
||||
}
|
||||
|
||||
break; /* connection was not accepted immediately */
|
||||
}
|
||||
ret = InitiateTransfer(conn);
|
||||
if(ret)
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
/* Add timeout to multi handle and break out of the loop */
|
||||
if(ret == CURLE_OK && *connected == FALSE) {
|
||||
if(data->set.accepttimeout > 0)
|
||||
Curl_expire(data, data->set.accepttimeout);
|
||||
else
|
||||
Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
@ -787,8 +779,12 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
|
||||
}
|
||||
|
||||
/* This is the ONLY way to change FTP state! */
|
||||
static void state(struct connectdata *conn,
|
||||
ftpstate newstate)
|
||||
static void _state(struct connectdata *conn,
|
||||
ftpstate newstate
|
||||
#ifdef DEBUGBUILD
|
||||
, int lineno
|
||||
#endif
|
||||
)
|
||||
{
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
/* for debug purposes */
|
||||
@ -833,8 +829,8 @@ static void state(struct connectdata *conn,
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
|
||||
if(ftpc->state != newstate)
|
||||
infof(conn->data, "FTP %p state change from %s to %s\n",
|
||||
ftpc, names[ftpc->state], names[newstate]);
|
||||
infof(conn->data, "FTP %p (line %d) state change from %s to %s\n",
|
||||
ftpc, lineno, names[ftpc->state], names[newstate]);
|
||||
#endif
|
||||
ftpc->state = newstate;
|
||||
}
|
||||
@ -2071,10 +2067,19 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
|
||||
|
||||
if(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.do_more = TRUE;
|
||||
state(conn, FTP_STOP); /* this phase is completed */
|
||||
|
||||
return result;
|
||||
@ -2108,6 +2113,7 @@ static CURLcode ftp_state_port_resp(struct connectdata *conn,
|
||||
else {
|
||||
infof(data, "Connect data stream actively\n");
|
||||
state(conn, FTP_STOP); /* end of DO phase */
|
||||
result = ftp_dophase_done(conn, FALSE);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -3206,7 +3212,6 @@ static CURLcode ftp_connect(struct connectdata *conn,
|
||||
{
|
||||
CURLcode result;
|
||||
struct ftp_conn *ftpc = &conn->proto.ftpc;
|
||||
struct SessionHandle *data=conn->data;
|
||||
struct pingpong *pp = &ftpc->pp;
|
||||
|
||||
*done = FALSE; /* default to not done yet */
|
||||
@ -3240,13 +3245,7 @@ static CURLcode ftp_connect(struct connectdata *conn,
|
||||
response */
|
||||
state(conn, FTP_WAIT220);
|
||||
|
||||
if(data->state.used_interface == Curl_if_multi)
|
||||
result = ftp_multi_statemach(conn, done);
|
||||
else {
|
||||
result = ftp_easy_statemach(conn);
|
||||
if(!result)
|
||||
*done = TRUE;
|
||||
}
|
||||
result = ftp_multi_statemach(conn, done);
|
||||
|
||||
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(!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);
|
||||
|
||||
/* Ready to do more? */
|
||||
@ -3691,9 +3698,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
return result;
|
||||
}
|
||||
|
||||
if((data->state.used_interface == Curl_if_multi) &&
|
||||
ftpc->state) {
|
||||
/* multi interface and already in a state so skip the intial commands.
|
||||
if(ftpc->state) {
|
||||
/* already in a state so skip the intial commands.
|
||||
They are only done to kickstart the do_more state */
|
||||
result = ftp_multi_statemach(conn, complete);
|
||||
|
||||
@ -3701,6 +3707,12 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
immediately */
|
||||
if(result || (ftpc->wait_data_conn != TRUE))
|
||||
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) {
|
||||
@ -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);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
result = ftp_multi_statemach(conn, complete);
|
||||
}
|
||||
else {
|
||||
/* download */
|
||||
@ -3755,14 +3769,10 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete)
|
||||
if(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
|
||||
result = ftp_easy_statemach(conn);
|
||||
return result;
|
||||
}
|
||||
|
||||
if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
|
||||
@ -3805,7 +3815,6 @@ CURLcode ftp_perform(struct connectdata *conn,
|
||||
ftp->transfer = FTPTRANSFER_INFO;
|
||||
}
|
||||
|
||||
|
||||
*dophase_done = FALSE; /* not done yet */
|
||||
|
||||
/* start the first command in the DO phase */
|
||||
@ -3814,16 +3823,12 @@ CURLcode ftp_perform(struct connectdata *conn,
|
||||
return result;
|
||||
|
||||
/* run the state-machine */
|
||||
if(conn->data->state.used_interface == Curl_if_multi)
|
||||
result = ftp_multi_statemach(conn, dophase_done);
|
||||
else {
|
||||
result = ftp_easy_statemach(conn);
|
||||
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||
}
|
||||
result = ftp_multi_statemach(conn, dophase_done);
|
||||
|
||||
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
|
||||
|
||||
if(*dophase_done)
|
||||
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||
DEBUGF(infof(conn->data, "DO phase is complete1\n"));
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -4476,7 +4481,7 @@ static CURLcode ftp_doing(struct connectdata *conn,
|
||||
else if(*dophase_done) {
|
||||
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;
|
||||
}
|
||||
@ -4521,6 +4526,7 @@ CURLcode ftp_regular_transfer(struct connectdata *conn,
|
||||
return CURLE_OK;
|
||||
|
||||
result = ftp_dophase_done(conn, connected);
|
||||
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
|
34
lib/http.c
34
lib/http.c
@ -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
|
||||
* 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)
|
||||
{
|
||||
struct SessionHandle *data;
|
||||
CURLcode result;
|
||||
|
||||
data=conn->data;
|
||||
|
||||
/* 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. */
|
||||
conn->bits.close = FALSE;
|
||||
|
||||
if(data->state.used_interface == Curl_if_multi) {
|
||||
/* when the multi interface is used, the CONNECT procedure might not have
|
||||
been completed */
|
||||
result = Curl_proxy_connect(conn);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
/* the CONNECT procedure might not have been completed */
|
||||
result = Curl_proxy_connect(conn);
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
|
||||
/* 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) {
|
||||
/* perform SSL initialization */
|
||||
if(data->state.used_interface == Curl_if_multi) {
|
||||
result = https_connecting(conn, done);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
/* BLOCKING */
|
||||
result = Curl_ssl_connect(conn, FIRSTSOCKET);
|
||||
if(result)
|
||||
return result;
|
||||
*done = TRUE;
|
||||
}
|
||||
result = https_connecting(conn, done);
|
||||
if(result)
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
else
|
||||
*done = TRUE;
|
||||
}
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
@ -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
|
||||
* 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
|
||||
* 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 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,
|
||||
@ -244,19 +237,13 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||
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))
|
||||
/* return so we'll be called again polling-style */
|
||||
return CURLE_OK;
|
||||
else {
|
||||
DEBUGF(infof(data,
|
||||
"Multi mode finished polling for response from "
|
||||
"proxy CONNECT\n"));
|
||||
}
|
||||
}
|
||||
if(0 == Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD, 0))
|
||||
/* return so we'll be called again polling-style */
|
||||
return CURLE_OK;
|
||||
else {
|
||||
DEBUGF(infof(data, "Easy mode waiting response from proxy CONNECT\n"));
|
||||
DEBUGF(infof(data,
|
||||
"Multi mode finished polling for response from "
|
||||
"proxy CONNECT\n"));
|
||||
}
|
||||
|
||||
/* at this point, either:
|
||||
@ -572,6 +559,12 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
|
||||
if(closeConnection && data->req.newurl)
|
||||
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 */
|
||||
conn->tunnel_state[sockindex] = TUNNEL_INIT;
|
||||
|
||||
|
45
lib/imap.c
45
lib/imap.c
@ -633,19 +633,9 @@ static CURLcode imap_state_starttls_resp(struct connectdata *conn,
|
||||
result = imap_state_capability(conn);
|
||||
}
|
||||
else {
|
||||
if(data->state.used_interface == Curl_if_multi) {
|
||||
state(conn, IMAP_UPGRADETLS);
|
||||
result = 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);
|
||||
}
|
||||
}
|
||||
state(conn, IMAP_UPGRADETLS);
|
||||
return imap_state_upgrade_tls(conn);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1358,7 +1348,6 @@ static CURLcode imap_connect(struct connectdata *conn,
|
||||
{
|
||||
CURLcode result;
|
||||
struct imap_conn *imapc = &conn->proto.imapc;
|
||||
struct SessionHandle *data=conn->data;
|
||||
struct pingpong *pp = &imapc->pp;
|
||||
|
||||
*done = FALSE; /* default to not done yet */
|
||||
@ -1379,17 +1368,7 @@ static CURLcode imap_connect(struct connectdata *conn,
|
||||
pp->endofresp = imap_endofresp;
|
||||
pp->conn = conn;
|
||||
|
||||
if((conn->handler->flags & PROTOPT_SSL) &&
|
||||
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);
|
||||
Curl_pp_init(pp); /* init generic pingpong data */
|
||||
|
||||
/* Start off waiting for the server greeting response */
|
||||
state(conn, IMAP_SERVERGREET);
|
||||
@ -1397,13 +1376,7 @@ static CURLcode imap_connect(struct connectdata *conn,
|
||||
/* Start off with an id of '*' */
|
||||
imapc->idstr = "*";
|
||||
|
||||
if(data->state.used_interface == Curl_if_multi)
|
||||
result = imap_multi_statemach(conn, done);
|
||||
else {
|
||||
result = imap_easy_statemach(conn);
|
||||
if(!result)
|
||||
*done = TRUE;
|
||||
}
|
||||
result = imap_multi_statemach(conn, done);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1473,13 +1446,9 @@ static CURLcode imap_perform(struct connectdata *conn, bool *connected,
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Run the state-machine */
|
||||
if(conn->data->state.used_interface == Curl_if_multi)
|
||||
result = imap_multi_statemach(conn, dophase_done);
|
||||
else {
|
||||
result = imap_easy_statemach(conn);
|
||||
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||
}
|
||||
/* run the state-machine */
|
||||
result = imap_multi_statemach(conn, dophase_done);
|
||||
|
||||
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
|
||||
|
||||
if(*dophase_done)
|
||||
|
183
lib/multi.c
183
lib/multi.c
@ -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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@ -39,6 +39,7 @@
|
||||
#include "speedcheck.h"
|
||||
#include "conncache.h"
|
||||
#include "bundles.h"
|
||||
#include "multihandle.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
@ -56,62 +57,6 @@
|
||||
#define CURL_SOCKET_HASH_TABLE_SIZE 911
|
||||
#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
|
||||
|
||||
@ -120,57 +65,6 @@ struct Curl_one_easy {
|
||||
#define GOOD_EASY_HANDLE(x) \
|
||||
((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,
|
||||
struct Curl_one_easy *easy);
|
||||
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);
|
||||
|
||||
/* 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
|
||||
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;
|
||||
|
||||
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],
|
||||
(char *)easy, connection_id);
|
||||
(char *)easy, lineno, connection_id);
|
||||
}
|
||||
#endif
|
||||
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--;
|
||||
}
|
||||
|
||||
#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
|
||||
*/
|
||||
@ -396,7 +300,7 @@ CURLM *curl_multi_init(void)
|
||||
if(!multi->sockhash)
|
||||
goto error;
|
||||
|
||||
multi->conn_cache = Curl_conncache_init(CONNCACHE_MULTI);
|
||||
multi->conn_cache = Curl_conncache_init();
|
||||
if(!multi->conn_cache)
|
||||
goto error;
|
||||
|
||||
@ -516,29 +420,14 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
||||
easy->easy_handle->multi_pos = easy;
|
||||
|
||||
/* for multi interface connections, we share DNS cache automatically if the
|
||||
easy handle's one is currently private. */
|
||||
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;
|
||||
}
|
||||
|
||||
easy handle's one is currently not set. */
|
||||
if(!easy->easy_handle->dns.hostcache ||
|
||||
(easy->easy_handle->dns.hostcachetype == HCACHE_NONE)) {
|
||||
easy->easy_handle->dns.hostcache = multi->hostcache;
|
||||
easy->easy_handle->dns.hostcachetype = HCACHE_MULTI;
|
||||
}
|
||||
|
||||
/* On a multi stack the connection cache, owned by the multi handle,
|
||||
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 */
|
||||
/* Point to the multi's connection cache */
|
||||
easy->easy_handle->state.conn_cache = multi->conn_cache;
|
||||
|
||||
/* 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(multi->num_easy == 1) {
|
||||
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 */
|
||||
/* stop using the multi handle's DNS cache */
|
||||
easy->easy_handle->dns.hostcache = NULL;
|
||||
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);
|
||||
}
|
||||
|
||||
if(easy->easy_handle->state.conn_cache->type == CONNCACHE_MULTI) {
|
||||
/* if this was using the shared connection cache we clear the pointer
|
||||
to that since we're not part of that handle anymore */
|
||||
easy->easy_handle->state.conn_cache = NULL;
|
||||
easy->easy_handle->state.lastconnect = NULL;
|
||||
}
|
||||
/* as this was using a shared connection cache we clear the pointer
|
||||
to that since we're not part of that multi handle anymore */
|
||||
easy->easy_handle->state.conn_cache = NULL;
|
||||
|
||||
/* change state without using multistate(), only to make singlesocket() do
|
||||
what we want */
|
||||
@ -1025,7 +900,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
bool connected;
|
||||
bool async;
|
||||
bool protocol_connect = FALSE;
|
||||
bool dophase_done;
|
||||
bool dophase_done = FALSE;
|
||||
bool done = FALSE;
|
||||
CURLMcode result = CURLM_OK;
|
||||
struct SingleRequest *k;
|
||||
@ -1120,8 +995,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
/* after init, go CONNECT */
|
||||
multistate(easy, CURLM_STATE_CONNECT);
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
|
||||
data->state.used_interface = Curl_if_multi;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -1577,9 +1450,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||
if(!ret)
|
||||
retry = (newurl)?TRUE:FALSE;
|
||||
|
||||
if(retry)
|
||||
/* if we are to retry, set the result to OK */
|
||||
if(retry) {
|
||||
/* if we are to retry, set the result to OK and consider the
|
||||
request as done */
|
||||
easy->result = CURLE_OK;
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if(easy->result) {
|
||||
@ -1897,6 +1773,9 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
||||
/* Close all the connections in the connection cache */
|
||||
close_all_connections(multi);
|
||||
|
||||
multi->closure_handle->dns.hostcache = multi->hostcache;
|
||||
Curl_hostcache_clean(multi->closure_handle);
|
||||
|
||||
Curl_close(multi->closure_handle);
|
||||
multi->closure_handle = NULL;
|
||||
|
||||
|
134
lib/multihandle.h
Normal file
134
lib/multihandle.h
Normal 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 */
|
||||
|
@ -6,7 +6,7 @@
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* 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
|
||||
* 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;
|
||||
int rc, proto = LDAP_VERSION3;
|
||||
char hosturl[1024], *ptr;
|
||||
(void)done;
|
||||
|
||||
strcpy(hosturl, "ldap");
|
||||
ptr = hosturl+4;
|
||||
@ -212,23 +213,12 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
|
||||
#ifdef USE_SSL
|
||||
if(conn->handler->flags & PROTOPT_SSL) {
|
||||
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);
|
||||
if(res)
|
||||
return res;
|
||||
}
|
||||
res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
|
||||
if(res)
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
if(data->state.used_interface == Curl_if_easy)
|
||||
return ldap_connecting(conn, done);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
@ -262,10 +252,7 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
|
||||
}
|
||||
#endif
|
||||
|
||||
if(data->state.used_interface == Curl_if_easy)
|
||||
tvp = NULL; /* let ldap_result block indefinitely */
|
||||
else
|
||||
tvp = &tv;
|
||||
tvp = &tv;
|
||||
|
||||
retry:
|
||||
if(!li->didbind) {
|
||||
|
30
lib/pop3.c
30
lib/pop3.c
@ -570,17 +570,8 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
|
||||
result = pop3_state_capa(conn);
|
||||
}
|
||||
else {
|
||||
if(data->state.used_interface == Curl_if_multi) {
|
||||
state(conn, POP3_UPGRADETLS);
|
||||
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);
|
||||
}
|
||||
}
|
||||
state(conn, POP3_UPGRADETLS);
|
||||
result = pop3_state_upgrade_tls(conn);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -1301,7 +1292,6 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done)
|
||||
{
|
||||
CURLcode result;
|
||||
struct pop3_conn *pop3c = &conn->proto.pop3c;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct pingpong *pp = &pop3c->pp;
|
||||
|
||||
*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 */
|
||||
state(conn, POP3_SERVERGREET);
|
||||
|
||||
if(data->state.used_interface == Curl_if_multi)
|
||||
result = pop3_multi_statemach(conn, done);
|
||||
else {
|
||||
result = pop3_easy_statemach(conn);
|
||||
if(!result)
|
||||
*done = TRUE;
|
||||
}
|
||||
result = pop3_multi_statemach(conn, done);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1418,12 +1402,8 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
|
||||
return result;
|
||||
|
||||
/* Run the state-machine */
|
||||
if(conn->data->state.used_interface == Curl_if_multi)
|
||||
result = pop3_multi_statemach(conn, dophase_done);
|
||||
else {
|
||||
result = pop3_easy_statemach(conn);
|
||||
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||
}
|
||||
result = pop3_multi_statemach(conn, dophase_done);
|
||||
|
||||
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
|
||||
|
||||
if(*dophase_done)
|
||||
|
41
lib/smtp.c
41
lib/smtp.c
@ -493,17 +493,8 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
|
||||
result = smtp_authenticate(conn);
|
||||
}
|
||||
else {
|
||||
if(data->state.used_interface == Curl_if_multi) {
|
||||
state(conn, SMTP_UPGRADETLS);
|
||||
result = 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);
|
||||
}
|
||||
}
|
||||
state(conn, SMTP_UPGRADETLS);
|
||||
return smtp_state_upgrade_tls(conn);
|
||||
}
|
||||
|
||||
return result;
|
||||
@ -1300,7 +1291,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
|
||||
{
|
||||
CURLcode result;
|
||||
struct smtp_conn *smtpc = &conn->proto.smtpc;
|
||||
struct SessionHandle *data = conn->data;
|
||||
struct pingpong *pp = &smtpc->pp;
|
||||
const char *path = conn->data->state.path;
|
||||
char localhost[HOSTNAME_MAX + 1];
|
||||
@ -1323,15 +1313,6 @@ static CURLcode smtp_connect(struct connectdata *conn, bool *done)
|
||||
pp->endofresp = smtp_endofresp;
|
||||
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 */
|
||||
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 */
|
||||
state(conn, SMTP_SERVERGREET);
|
||||
|
||||
if(data->state.used_interface == Curl_if_multi)
|
||||
result = smtp_multi_statemach(conn, done);
|
||||
else {
|
||||
result = smtp_easy_statemach(conn);
|
||||
if(!result)
|
||||
*done = TRUE;
|
||||
}
|
||||
result = smtp_multi_statemach(conn, done);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -1470,13 +1445,9 @@ static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Run the state-machine */
|
||||
if(conn->data->state.used_interface == Curl_if_multi)
|
||||
result = smtp_multi_statemach(conn, dophase_done);
|
||||
else {
|
||||
result = smtp_easy_statemach(conn);
|
||||
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||
}
|
||||
/* run the state-machine */
|
||||
result = smtp_multi_statemach(conn, dophase_done);
|
||||
|
||||
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
|
||||
|
||||
if(*dophase_done)
|
||||
|
28
lib/ssh.c
28
lib/ssh.c
@ -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
|
||||
* 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);
|
||||
|
||||
if(data->state.used_interface == Curl_if_multi)
|
||||
result = ssh_multi_statemach(conn, done);
|
||||
else {
|
||||
result = ssh_easy_statemach(conn, TRUE);
|
||||
if(!result)
|
||||
*done = TRUE;
|
||||
}
|
||||
result = ssh_multi_statemach(conn, done);
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -2828,13 +2822,8 @@ CURLcode scp_perform(struct connectdata *conn,
|
||||
state(conn, SSH_SCP_TRANS_INIT);
|
||||
|
||||
/* run the state-machine */
|
||||
if(conn->data->state.used_interface == Curl_if_multi) {
|
||||
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 */
|
||||
}
|
||||
result = ssh_multi_statemach(conn, dophase_done);
|
||||
|
||||
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
|
||||
|
||||
if(*dophase_done) {
|
||||
@ -3037,13 +3026,8 @@ CURLcode sftp_perform(struct connectdata *conn,
|
||||
state(conn, SSH_SFTP_QUOTE_INIT);
|
||||
|
||||
/* run the state-machine */
|
||||
if(conn->data->state.used_interface == Curl_if_multi) {
|
||||
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 */
|
||||
}
|
||||
result = ssh_multi_statemach(conn, dophase_done);
|
||||
|
||||
*connected = conn->bits.tcpconnect[FIRSTSOCKET];
|
||||
|
||||
if(*dophase_done) {
|
||||
|
12
lib/ssluse.c
12
lib/ssluse.c
@ -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
|
||||
* 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);
|
||||
|
||||
#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(!cert_stuff(conn,
|
||||
connssl->ctx,
|
||||
|
132
lib/tftp.c
132
lib/tftp.c
@ -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
|
||||
* 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);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************
|
||||
*
|
||||
* 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
|
||||
@ -1404,12 +1281,7 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
|
||||
if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
|
||||
return(result);
|
||||
|
||||
if(conn->data->state.used_interface == Curl_if_multi)
|
||||
tftp_multi_statemach(conn, dophase_done);
|
||||
else {
|
||||
result = tftp_easy_statemach(conn);
|
||||
*dophase_done = TRUE; /* with the easy interface we are done here */
|
||||
}
|
||||
tftp_multi_statemach(conn, dophase_done);
|
||||
|
||||
if(*dophase_done)
|
||||
DEBUGF(infof(conn->data, "DO phase is complete\n"));
|
||||
|
@ -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
|
||||
* 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! */
|
||||
followtype follow = FOLLOW_NONE;
|
||||
|
||||
data->state.used_interface = Curl_if_easy;
|
||||
|
||||
res = Curl_pretransfer(data);
|
||||
if(res)
|
||||
return res;
|
||||
|
98
lib/url.c
98
lib/url.c
@ -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
|
||||
* 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"
|
||||
|
||||
/* Local static prototypes */
|
||||
static bool ConnectionKillOne(struct SessionHandle *data);
|
||||
static void conn_free(struct connectdata *conn);
|
||||
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
|
||||
static CURLcode do_init(struct connectdata *conn);
|
||||
@ -255,15 +254,6 @@ static const struct Curl_handler Curl_handler_dummy = {
|
||||
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)
|
||||
{
|
||||
/* 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. */
|
||||
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
|
||||
/normally/ done by curl_multi_remove_handle() but this is "just in
|
||||
case" */
|
||||
@ -398,19 +393,6 @@ CURLcode Curl_close(struct SessionHandle *data)
|
||||
the multi handle, since that function uses the magic
|
||||
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)
|
||||
free(data->state.range);
|
||||
|
||||
@ -2000,10 +1982,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
|
||||
data->share->dirty++;
|
||||
|
||||
if(data->share->hostcache) {
|
||||
/* use shared host cache, first free the private one if any */
|
||||
if(data->dns.hostcachetype == HCACHE_PRIVATE)
|
||||
Curl_hostcache_destroy(data);
|
||||
|
||||
/* use shared host cache */
|
||||
data->dns.hostcache = data->share->hostcache;
|
||||
data->dns.hostcachetype = HCACHE_SHARED;
|
||||
}
|
||||
@ -2982,69 +2961,6 @@ ConnectionExists(struct SessionHandle *data,
|
||||
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' */
|
||||
static void
|
||||
ConnectionDone(struct connectdata *conn)
|
||||
|
@ -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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@ -1147,15 +1147,15 @@ struct auth {
|
||||
};
|
||||
|
||||
struct UrlState {
|
||||
enum {
|
||||
Curl_if_none,
|
||||
Curl_if_easy,
|
||||
Curl_if_multi
|
||||
} used_interface;
|
||||
|
||||
/* Points to the connection 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 */
|
||||
struct timeval keeps_speed; /* for the progress meter really */
|
||||
|
||||
@ -1588,7 +1588,6 @@ struct Names {
|
||||
struct curl_hash *hostcache;
|
||||
enum {
|
||||
HCACHE_NONE, /* not pointing to anything */
|
||||
HCACHE_PRIVATE, /* points to our own */
|
||||
HCACHE_GLOBAL, /* points to the (shrug) global one */
|
||||
HCACHE_MULTI, /* points to a shared one in the multi handle */
|
||||
HCACHE_SHARED /* points to a shared one in a shared object */
|
||||
@ -1608,7 +1607,11 @@ struct Names {
|
||||
struct SessionHandle {
|
||||
struct Names dns;
|
||||
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
|
||||
in multi controlling structure to assist
|
||||
in removal. */
|
||||
|
@ -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 \
|
||||
sshserver.pl sshhelp.pm testcurl.1 runtests.1 $(HTMLPAGES) $(PDFPAGES) \
|
||||
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'
|
||||
# added twice as then targets such as 'distclean' misbehave and try to
|
||||
|
@ -36,6 +36,11 @@ FTP PORT download, no data conn and no transient negative reply
|
||||
<strippart>
|
||||
s/^EPRT \|1\|(.*)/EPRT \|1\|/
|
||||
</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>
|
||||
USER anonymous
|
||||
PASS ftp@example.com
|
||||
@ -44,10 +49,9 @@ EPRT |1|
|
||||
TYPE I
|
||||
SIZE 1208
|
||||
RETR 1208
|
||||
QUIT
|
||||
</protocol>
|
||||
<errorcode>
|
||||
12
|
||||
28
|
||||
</errorcode>
|
||||
</verify>
|
||||
</testcase>
|
||||
|
@ -54,6 +54,8 @@ fooo
|
||||
mooo
|
||||
</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">
|
||||
220- _ _ ____ _
|
||||
220- ___| | | | _ \| |
|
||||
@ -69,7 +71,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1349 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -54,6 +54,8 @@ fooo
|
||||
mooo
|
||||
</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">
|
||||
220- _ _ ____ _
|
||||
220- ___| | | | _ \| |
|
||||
@ -69,7 +71,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1350 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -55,6 +55,8 @@ fooo
|
||||
mooo
|
||||
</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">
|
||||
220- _ _ ____ _
|
||||
220- ___| | | | _ \| |
|
||||
@ -70,7 +72,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1351 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -55,6 +55,8 @@ fooo
|
||||
mooo
|
||||
</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">
|
||||
220- _ _ ____ _
|
||||
220- ___| | | | _ \| |
|
||||
@ -70,7 +72,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1352 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -54,6 +54,8 @@ fooo
|
||||
mooo
|
||||
</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">
|
||||
220- _ _ ____ _
|
||||
220- ___| | | | _ \| |
|
||||
@ -69,7 +71,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1353 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -69,7 +69,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1354 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -87,7 +87,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1357 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -87,7 +87,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1358 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -88,7 +88,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1359 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -88,7 +88,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1360 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -87,7 +87,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1361 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -87,7 +87,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1362 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -64,7 +64,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1379 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -64,7 +64,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1380 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -65,7 +65,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1381 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -65,7 +65,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1382 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -64,7 +64,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1383 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -64,7 +64,6 @@ mooo
|
||||
213 10
|
||||
150 Binary data connection for 1384 () (10 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -79,7 +79,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1387 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -79,7 +79,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1388 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -80,7 +80,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1389 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -80,7 +80,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1390 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -79,7 +79,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1391 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -79,7 +79,6 @@ MOOOO
|
||||
213 214
|
||||
150 Binary data connection for 1392 () (214 bytes).
|
||||
226 File transfer complete
|
||||
221 bye bye baby
|
||||
</file2>
|
||||
<stripfile2>
|
||||
s/^(229 Entering Passive Mode \().*(\).*)/${1}stripped${2}/
|
||||
|
@ -12,7 +12,7 @@ LIST
|
||||
# Server-side
|
||||
<reply>
|
||||
<servercmd>
|
||||
REPLY LIST +OK 1407 100
|
||||
REPLY LIST +OK 1407 100\r\n.
|
||||
</servercmd>
|
||||
</reply>
|
||||
|
||||
|
@ -101,66 +101,60 @@ run 1: set cookie 1, 2 and 3
|
||||
lock: dns [Pigs in space]: 14
|
||||
unlock: dns [Pigs in space]: 15
|
||||
CLEANUP
|
||||
lock: dns [Pigs in space]: 16
|
||||
unlock: dns [Pigs in space]: 17
|
||||
lock: cookie [Pigs in space]: 18
|
||||
unlock: cookie [Pigs in space]: 19
|
||||
lock: share [Pigs in space]: 20
|
||||
unlock: share [Pigs in space]: 21
|
||||
lock: cookie [Pigs in space]: 16
|
||||
unlock: cookie [Pigs in space]: 17
|
||||
lock: share [Pigs in space]: 18
|
||||
unlock: share [Pigs in space]: 19
|
||||
*** run 2
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 22
|
||||
unlock: share [Pigs in space]: 23
|
||||
lock: share [Pigs in space]: 20
|
||||
unlock: share [Pigs in space]: 21
|
||||
PERFORM
|
||||
lock: dns [Pigs in space]: 24
|
||||
unlock: dns [Pigs in space]: 25
|
||||
lock: dns [Pigs in space]: 22
|
||||
unlock: dns [Pigs in space]: 23
|
||||
lock: cookie [Pigs in space]: 24
|
||||
unlock: cookie [Pigs in space]: 25
|
||||
lock: cookie [Pigs in space]: 26
|
||||
unlock: cookie [Pigs in space]: 27
|
||||
lock: cookie [Pigs in space]: 28
|
||||
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
|
||||
lock: dns [Pigs in space]: 32
|
||||
unlock: dns [Pigs in space]: 33
|
||||
lock: dns [Pigs in space]: 30
|
||||
unlock: dns [Pigs in space]: 31
|
||||
CLEANUP
|
||||
lock: dns [Pigs in space]: 34
|
||||
unlock: dns [Pigs in space]: 35
|
||||
lock: cookie [Pigs in space]: 36
|
||||
unlock: cookie [Pigs in space]: 37
|
||||
lock: share [Pigs in space]: 38
|
||||
unlock: share [Pigs in space]: 39
|
||||
lock: cookie [Pigs in space]: 32
|
||||
unlock: cookie [Pigs in space]: 33
|
||||
lock: share [Pigs in space]: 34
|
||||
unlock: share [Pigs in space]: 35
|
||||
*** run 3
|
||||
CURLOPT_SHARE
|
||||
lock: share [Pigs in space]: 40
|
||||
unlock: share [Pigs in space]: 41
|
||||
lock: share [Pigs in space]: 36
|
||||
unlock: share [Pigs in space]: 37
|
||||
CURLOPT_COOKIEJAR
|
||||
PERFORM
|
||||
lock: dns [Pigs in space]: 42
|
||||
unlock: dns [Pigs in space]: 43
|
||||
lock: dns [Pigs in space]: 38
|
||||
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
|
||||
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
|
||||
lock: dns [Pigs in space]: 50
|
||||
unlock: dns [Pigs in space]: 51
|
||||
lock: dns [Pigs in space]: 46
|
||||
unlock: dns [Pigs in space]: 47
|
||||
try SHARE_CLEANUP...
|
||||
lock: share [Pigs in space]: 52
|
||||
unlock: share [Pigs in space]: 53
|
||||
lock: share [Pigs in space]: 48
|
||||
unlock: share [Pigs in space]: 49
|
||||
SHARE_CLEANUP failed, correct
|
||||
CLEANUP
|
||||
lock: dns [Pigs in space]: 54
|
||||
unlock: dns [Pigs in space]: 55
|
||||
lock: cookie [Pigs in space]: 56
|
||||
unlock: cookie [Pigs in space]: 57
|
||||
lock: share [Pigs in space]: 58
|
||||
unlock: share [Pigs in space]: 59
|
||||
lock: cookie [Pigs in space]: 50
|
||||
unlock: cookie [Pigs in space]: 51
|
||||
lock: share [Pigs in space]: 52
|
||||
unlock: share [Pigs in space]: 53
|
||||
SHARE_CLEANUP
|
||||
lock: share [Pigs in space]: 60
|
||||
unlock: share [Pigs in space]: 61
|
||||
lock: share [Pigs in space]: 54
|
||||
unlock: share [Pigs in space]: 55
|
||||
GLOBAL_CLEANUP
|
||||
</stdout>
|
||||
<stderr>
|
||||
|
@ -10,7 +10,8 @@ LIST
|
||||
# Server-side
|
||||
<reply>
|
||||
<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>
|
||||
</reply>
|
||||
|
||||
|
@ -34,11 +34,13 @@ pop3://%HOSTIP:%POP3PORT/813 -u user:wrong
|
||||
<errorcode>
|
||||
67
|
||||
</errorcode>
|
||||
#
|
||||
# The multi interface considers a broken "DO" request as a prematurely broken
|
||||
# transfer and such a connection will not get a "QUIT"
|
||||
<protocol>
|
||||
CAPA
|
||||
USER user
|
||||
PASS wrong
|
||||
QUIT
|
||||
</protocol>
|
||||
</verify>
|
||||
</testcase>
|
||||
|
@ -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
|
||||
* you should have received as part of this distribution. The terms
|
||||
@ -41,7 +41,7 @@
|
||||
#error "this test requires FD_SETSIZE"
|
||||
#endif
|
||||
|
||||
#define SAFETY_MARGIN (10)
|
||||
#define SAFETY_MARGIN (11)
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(MSDOS)
|
||||
#define DEV_NULL "NUL"
|
||||
|
@ -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
|
||||
# you should have received as part of this distribution. The terms
|
||||
@ -3084,6 +3084,7 @@ sub singletest {
|
||||
my $valgrindcmd = "$valgrind ";
|
||||
$valgrindcmd .= "$valgrind_tool " if($valgrind_tool);
|
||||
$valgrindcmd .= "--leak-check=yes ";
|
||||
$valgrindcmd .= "--suppressions=valgrind.supp ";
|
||||
$valgrindcmd .= "--num-callers=16 ";
|
||||
$valgrindcmd .= "${valgrind_logfile}=$LOGDIR/valgrind$testnum";
|
||||
$CMDLINE = "$valgrindcmd $CMDLINE";
|
||||
|
16
tests/valgrind.supp
Normal file
16
tests/valgrind.supp
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user