mirror of
https://github.com/moparisthebest/curl
synced 2024-11-16 14:35:03 -05:00
merged the multi-dev branch back into MAIN again
This commit is contained in:
parent
6de7dc5879
commit
8b6314ccfb
@ -57,7 +57,8 @@ escape.h getpass.c netrc.c telnet.h \
|
||||
getinfo.c getinfo.h transfer.c strequal.c strequal.h easy.c \
|
||||
security.h security.c krb4.c krb4.h memdebug.c memdebug.h inet_ntoa_r.h \
|
||||
http_chunks.c http_chunks.h strtok.c strtok.h connect.c connect.h \
|
||||
llist.c llist.h hash.c hash.h
|
||||
llist.c llist.h hash.c hash.h multi.c multi.h
|
||||
|
||||
|
||||
noinst_HEADERS = setup.h transfer.h
|
||||
|
||||
|
56
lib/multi.c
56
lib/multi.c
@ -22,10 +22,16 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "setup.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "multi.h" /* will become <curl/multi.h> soon */
|
||||
|
||||
#include "urldata.h"
|
||||
#include "transfer.h"
|
||||
#include "url.h"
|
||||
|
||||
struct Curl_message {
|
||||
/* the 'CURLMsg' is the part that is visible to the external user */
|
||||
struct CURLMsg extmsg;
|
||||
@ -48,7 +54,9 @@ struct Curl_one_easy {
|
||||
struct Curl_one_easy *next;
|
||||
struct Curl_one_easy *prev;
|
||||
|
||||
CURL *easy_handle; /* this is the easy handle for this unit */
|
||||
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 */
|
||||
};
|
||||
@ -134,7 +142,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
||||
/* increase the node-counter */
|
||||
multi->num_easy++;
|
||||
|
||||
return CURLM_OK;
|
||||
return CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
||||
@ -190,23 +198,30 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
||||
and then we must make sure that is done. */
|
||||
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||
struct Curl_one_easy *easy;
|
||||
int this_max_fd=-1;
|
||||
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
*max_fd = -1; /* so far none! */
|
||||
|
||||
easy=multi->easy.next;
|
||||
while(easy) {
|
||||
switch(easy->state) {
|
||||
case CURLM_STATE_INIT:
|
||||
case CURLM_STATE_CONNECT:
|
||||
case CURLM_STATE_DO:
|
||||
case CURLM_STATE_DONE:
|
||||
/* we want curl_multi_perform() to get called, but we don't have any
|
||||
file descriptors to set */
|
||||
default:
|
||||
break;
|
||||
case CURLM_STATE_PERFORM:
|
||||
/* This should have a set of file descriptors for us to set. */
|
||||
/* after the transfer is done, go DONE */
|
||||
|
||||
Curl_single_fdset(easy->easy_conn,
|
||||
read_fd_set, write_fd_set,
|
||||
exc_fd_set, &this_max_fd);
|
||||
|
||||
/* remember the maximum file descriptor */
|
||||
if(this_max_fd > *max_fd)
|
||||
*max_fd = this_max_fd;
|
||||
|
||||
break;
|
||||
}
|
||||
easy = easy->next; /* check next handle */
|
||||
@ -222,6 +237,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
bool done;
|
||||
CURLMcode result=CURLM_OK;
|
||||
|
||||
*running_handles = 0; /* bump this once for every living handle */
|
||||
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
@ -239,8 +256,9 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
}
|
||||
break;
|
||||
case CURLM_STATE_CONNECT:
|
||||
/* connect */
|
||||
easy->result = Curl_connect(easy->easy_handle);
|
||||
/* Connect. We get a connection identifier filled in. */
|
||||
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
|
||||
|
||||
/* after connect, go DO */
|
||||
if(CURLE_OK == easy->result) {
|
||||
easy->state = CURLM_STATE_DO;
|
||||
@ -249,15 +267,18 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
break;
|
||||
case CURLM_STATE_DO:
|
||||
/* Do the fetch or put request */
|
||||
easy->result = Curl_do(easy->easy_handle);
|
||||
easy->result = Curl_do(&easy->easy_conn);
|
||||
/* after do, go PERFORM */
|
||||
if(CURLE_OK == easy->result) {
|
||||
if(CURLE_OK == Curl_readwrite_init(easy->easy_conn)) {
|
||||
easy->state = CURLM_STATE_PERFORM;
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CURLM_STATE_PERFORM:
|
||||
/* read/write data if it is ready to do so */
|
||||
easy->result = Curl_readwrite(easy->easy_handle, &done);
|
||||
easy->result = Curl_readwrite(easy->easy_conn, &done);
|
||||
/* hm, when we follow redirects, we may need to go back to the CONNECT
|
||||
state */
|
||||
/* after the transfer is done, go DONE */
|
||||
@ -265,11 +286,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
/* call this even if the readwrite function returned error */
|
||||
easy->result = Curl_posttransfer(easy->easy_handle);
|
||||
easy->state = CURLM_STATE_DONE;
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
break;
|
||||
case CURLM_STATE_DONE:
|
||||
/* post-transfer command */
|
||||
easy->result = Curl_done(easy->easy_handle);
|
||||
easy->result = Curl_done(easy->easy_conn);
|
||||
/* after we have DONE what we're supposed to do, go COMPLETED */
|
||||
if(CURLE_OK == easy->result)
|
||||
easy->state = CURLM_STATE_COMPLETED;
|
||||
@ -280,7 +302,10 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
/* This node should be delinked from the list now and we should post
|
||||
an information message that we are complete. */
|
||||
break;
|
||||
default:
|
||||
return CURLM_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if((CURLM_STATE_COMPLETED != easy->state) &&
|
||||
(CURLE_OK != easy->result)) {
|
||||
/*
|
||||
@ -289,10 +314,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
*/
|
||||
easy->state = CURLM_STATE_COMPLETED;
|
||||
}
|
||||
else if(CURLM_STATE_COMPLETED != easy->state)
|
||||
/* this one still lives! */
|
||||
(*running_handles)++;
|
||||
|
||||
easy = easy->next; /* operate on next handle */
|
||||
}
|
||||
return CURLM_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
||||
|
@ -50,7 +50,7 @@
|
||||
#ifdef HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <curl/types.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
typedef void CURLM;
|
||||
|
||||
@ -60,6 +60,7 @@ typedef enum {
|
||||
CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
|
||||
CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
|
||||
CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
|
||||
CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
|
||||
CURLM_LAST
|
||||
} CURLMcode;
|
||||
|
||||
|
740
lib/transfer.c
740
lib/transfer.c
File diff suppressed because it is too large
Load Diff
@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* In order to be useful for every potential user, curl and libcurl are
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
@ -24,6 +24,17 @@
|
||||
*****************************************************************************/
|
||||
CURLcode Curl_perform(struct SessionHandle *data);
|
||||
|
||||
CURLcode Curl_pretransfer(struct SessionHandle *data);
|
||||
CURLcode Curl_posttransfer(struct SessionHandle *data);
|
||||
|
||||
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
|
||||
void Curl_single_fdset(struct connectdata *conn,
|
||||
fd_set *read_fd_set,
|
||||
fd_set *write_fd_set,
|
||||
fd_set *exc_fd_set,
|
||||
int *max_fd);
|
||||
CURLcode Curl_readwrite_init(struct connectdata *conn);
|
||||
|
||||
/* This sets up a forthcoming transfer */
|
||||
CURLcode
|
||||
Curl_Transfer (struct connectdata *data,
|
||||
|
57
lib/url.c
57
lib/url.c
@ -1214,8 +1214,7 @@ static CURLcode ConnectPlease(struct connectdata *conn)
|
||||
}
|
||||
|
||||
static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
struct connectdata **in_connect,
|
||||
bool allow_port) /* allow set.use_port? */
|
||||
struct connectdata **in_connect)
|
||||
{
|
||||
char *tmp;
|
||||
char *buf;
|
||||
@ -1614,7 +1613,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
*************************************************************/
|
||||
|
||||
if (strequal(conn->protostr, "HTTP")) {
|
||||
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_HTTP;
|
||||
conn->port = (data->set.use_port && data->state.allow_port)?
|
||||
data->set.use_port:PORT_HTTP;
|
||||
conn->remote_port = PORT_HTTP;
|
||||
conn->protocol |= PROT_HTTP;
|
||||
conn->curl_do = Curl_http;
|
||||
@ -1624,7 +1624,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
else if (strequal(conn->protostr, "HTTPS")) {
|
||||
#ifdef USE_SSLEAY
|
||||
|
||||
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_HTTPS;
|
||||
conn->port = (data->set.use_port && data->state.allow_port)?
|
||||
data->set.use_port:PORT_HTTPS;
|
||||
conn->remote_port = PORT_HTTPS;
|
||||
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
|
||||
|
||||
@ -1639,7 +1640,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
#endif /* !USE_SSLEAY */
|
||||
}
|
||||
else if (strequal(conn->protostr, "GOPHER")) {
|
||||
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_GOPHER;
|
||||
conn->port = (data->set.use_port && data->state.allow_port)?
|
||||
data->set.use_port:PORT_GOPHER;
|
||||
conn->remote_port = PORT_GOPHER;
|
||||
/* Skip /<item-type>/ in path if present */
|
||||
if (isdigit((int)conn->path[1])) {
|
||||
@ -1665,7 +1667,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
#endif /* !USE_SSLEAY */
|
||||
}
|
||||
|
||||
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_FTP;
|
||||
conn->port = (data->set.use_port && data->state.allow_port)?
|
||||
data->set.use_port:PORT_FTP;
|
||||
conn->remote_port = PORT_FTP;
|
||||
conn->protocol |= PROT_FTP;
|
||||
|
||||
@ -1720,21 +1723,24 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
/* telnet testing factory */
|
||||
conn->protocol |= PROT_TELNET;
|
||||
|
||||
conn->port = (data->set.use_port && allow_port)?data->set.use_port: PORT_TELNET;
|
||||
conn->port = (data->set.use_port && data->state.allow_port)?
|
||||
data->set.use_port: PORT_TELNET;
|
||||
conn->remote_port = PORT_TELNET;
|
||||
conn->curl_do = Curl_telnet;
|
||||
conn->curl_done = Curl_telnet_done;
|
||||
}
|
||||
else if (strequal(conn->protostr, "DICT")) {
|
||||
conn->protocol |= PROT_DICT;
|
||||
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_DICT;
|
||||
conn->port = (data->set.use_port && data->state.allow_port)?
|
||||
data->set.use_port:PORT_DICT;
|
||||
conn->remote_port = PORT_DICT;
|
||||
conn->curl_do = Curl_dict;
|
||||
conn->curl_done = NULL; /* no DICT-specific done */
|
||||
}
|
||||
else if (strequal(conn->protostr, "LDAP")) {
|
||||
conn->protocol |= PROT_LDAP;
|
||||
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_LDAP;
|
||||
conn->port = (data->set.use_port && data->state.allow_port)?
|
||||
data->set.use_port:PORT_LDAP;
|
||||
conn->remote_port = PORT_LDAP;
|
||||
conn->curl_do = Curl_ldap;
|
||||
conn->curl_done = NULL; /* no LDAP-specific done */
|
||||
@ -2228,14 +2234,13 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
||||
}
|
||||
|
||||
CURLcode Curl_connect(struct SessionHandle *data,
|
||||
struct connectdata **in_connect,
|
||||
bool allow_port)
|
||||
struct connectdata **in_connect)
|
||||
{
|
||||
CURLcode code;
|
||||
struct connectdata *conn;
|
||||
|
||||
/* call the stuff that needs to be called */
|
||||
code = CreateConnection(data, in_connect, allow_port);
|
||||
code = CreateConnection(data, in_connect);
|
||||
|
||||
if(CURLE_OK != code) {
|
||||
/* We're not allowed to return failure with memory left allocated
|
||||
@ -2291,14 +2296,38 @@ CURLcode Curl_done(struct connectdata *conn)
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLcode Curl_do(struct connectdata *conn)
|
||||
CURLcode Curl_do(struct connectdata **connp)
|
||||
{
|
||||
CURLcode result=CURLE_OK;
|
||||
struct connectdata *conn = *connp;
|
||||
struct SessionHandle *data=conn->data;
|
||||
|
||||
if(conn->curl_do)
|
||||
if(conn->curl_do) {
|
||||
/* generic protocol-specific function pointer set in curl_connect() */
|
||||
result = conn->curl_do(conn);
|
||||
|
||||
/* This was formerly done in transfer.c, but we better do it here */
|
||||
|
||||
if((CURLE_WRITE_ERROR == result) && conn->bits.reuse) {
|
||||
/* This was a re-use of a connection and we got a write error in the
|
||||
* DO-phase. Then we DISCONNECT this connection and have another attempt
|
||||
* to CONNECT and then DO again! The retry cannot possibly find another
|
||||
* connection to re-use, since we only keep one possible connection for
|
||||
* each. */
|
||||
|
||||
infof(data, "Re-used connection seems dead, get a new one\n");
|
||||
|
||||
conn->bits.close = TRUE; /* enforce close of this connetion */
|
||||
result = Curl_done(conn); /* we are so done with this */
|
||||
if(CURLE_OK == result) {
|
||||
/* Now, redo the connect and get a new connection */
|
||||
result = Curl_connect(data, connp);
|
||||
if(CURLE_OK == result)
|
||||
/* ... finally back to actually retry the DO phase */
|
||||
result = conn->curl_do(*connp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
10
lib/url.h
10
lib/url.h
@ -7,7 +7,7 @@
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* In order to be useful for every potential user, curl and libcurl are
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
@ -29,11 +29,9 @@
|
||||
|
||||
CURLcode Curl_open(struct SessionHandle **curl);
|
||||
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
|
||||
CURLcode Curl_close(struct SessionHandle *data); /* the opposite of curl_open() */
|
||||
CURLcode Curl_connect(struct SessionHandle *,
|
||||
struct connectdata **,
|
||||
bool allow_port);
|
||||
CURLcode Curl_do(struct connectdata *);
|
||||
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
|
||||
CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
|
||||
CURLcode Curl_do(struct connectdata **);
|
||||
CURLcode Curl_done(struct connectdata *);
|
||||
CURLcode Curl_disconnect(struct connectdata *);
|
||||
|
||||
|
@ -211,6 +211,57 @@ struct ConnectBits {
|
||||
complete */
|
||||
};
|
||||
|
||||
/*
|
||||
* This struct is all the previously local variables from Curl_perform() moved
|
||||
* to struct to allow the function to return and get re-invoked better without
|
||||
* losing state.
|
||||
*/
|
||||
|
||||
struct Curl_transfer_keeper {
|
||||
int bytecount; /* total number of bytes read */
|
||||
int writebytecount; /* number of bytes written */
|
||||
long contentlength; /* size of incoming data */
|
||||
struct timeval start; /* transfer started at this time */
|
||||
struct timeval now; /* current time */
|
||||
bool header; /* incoming data has HTTP header */
|
||||
int headerline; /* counts header lines to better track the
|
||||
first one */
|
||||
char *hbufp; /* points at *end* of header line */
|
||||
int hbuflen;
|
||||
char *str; /* within buf */
|
||||
char *str_start; /* within buf */
|
||||
char *end_ptr; /* within buf */
|
||||
char *p; /* within headerbuff */
|
||||
bool content_range; /* set TRUE if Content-Range: was found */
|
||||
int offset; /* possible resume offset read from the
|
||||
Content-Range: header */
|
||||
int httpcode; /* error code from the 'HTTP/1.? XXX' line */
|
||||
int httpversion; /* the HTTP version*10 */
|
||||
bool write_after_100_header; /* should we enable the write after
|
||||
we received a 100-continue/timeout
|
||||
or directly */
|
||||
|
||||
/* for the low speed checks: */
|
||||
time_t timeofdoc;
|
||||
long bodywrites;
|
||||
int writetype;
|
||||
|
||||
/* the highest fd we use + 1 */
|
||||
struct SessionHandle *data;
|
||||
struct connectdata *conn;
|
||||
char *buf;
|
||||
int maxfd;
|
||||
|
||||
/* the file descriptors to play with */
|
||||
fd_set readfd;
|
||||
fd_set writefd;
|
||||
fd_set rkeepfd;
|
||||
fd_set wkeepfd;
|
||||
int keepon;
|
||||
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The connectdata struct contains all fields and variables that should be
|
||||
* unique for an entire connection.
|
||||
@ -355,6 +406,8 @@ struct connectdata {
|
||||
void *generic;
|
||||
} proto;
|
||||
|
||||
/* This struct is inited when needed */
|
||||
struct Curl_transfer_keeper keep;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -460,6 +513,13 @@ struct UrlState {
|
||||
bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
|
||||
This must be set to FALSE every time _easy_perform() is
|
||||
called. */
|
||||
|
||||
#ifdef HAVE_SIGNAL
|
||||
/* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
|
||||
void (*prev_signal)(int sig);
|
||||
#endif
|
||||
bool allow_port; /* Is set.use_port allowed to take effect or not. This
|
||||
is always set TRUE when curl_easy_perform() is called. */
|
||||
};
|
||||
|
||||
|
||||
@ -569,7 +629,6 @@ struct UserDefined {
|
||||
bool hide_progress;
|
||||
bool http_fail_on_error;
|
||||
bool http_follow_location;
|
||||
|
||||
bool include_header;
|
||||
#define http_include_header include_header /* former name */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user