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

merged the multi-dev branch back into MAIN again

This commit is contained in:
Daniel Stenberg 2002-01-03 15:01:22 +00:00
parent 6de7dc5879
commit 8b6314ccfb
8 changed files with 971 additions and 788 deletions

View File

@ -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

View File

@ -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) {
easy->state = CURLM_STATE_PERFORM;
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)

View File

@ -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;

File diff suppressed because it is too large Load Diff

View File

@ -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,

View File

@ -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;
}

View File

@ -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 *);

View File

@ -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 */