1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -05: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 \ 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 \ 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 \ 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 noinst_HEADERS = setup.h transfer.h

View File

@ -22,10 +22,16 @@
*****************************************************************************/ *****************************************************************************/
#include "setup.h" #include "setup.h"
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h> #include <curl/curl.h>
#include "multi.h" /* will become <curl/multi.h> soon */ #include "multi.h" /* will become <curl/multi.h> soon */
#include "urldata.h"
#include "transfer.h"
#include "url.h"
struct Curl_message { struct Curl_message {
/* the 'CURLMsg' is the part that is visible to the external user */ /* the 'CURLMsg' is the part that is visible to the external user */
struct CURLMsg extmsg; struct CURLMsg extmsg;
@ -48,7 +54,9 @@ struct Curl_one_easy {
struct Curl_one_easy *next; struct Curl_one_easy *next;
struct Curl_one_easy *prev; 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 */ CURLMstate state; /* the handle's state */
CURLcode result; /* previous result */ CURLcode result; /* previous result */
}; };
@ -134,7 +142,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* increase the node-counter */ /* increase the node-counter */
multi->num_easy++; multi->num_easy++;
return CURLM_OK; return CURLM_CALL_MULTI_PERFORM;
} }
CURLMcode curl_multi_remove_handle(CURLM *multi_handle, 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. */ and then we must make sure that is done. */
struct Curl_multi *multi=(struct Curl_multi *)multi_handle; struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
struct Curl_one_easy *easy; struct Curl_one_easy *easy;
int this_max_fd=-1;
if(!GOOD_MULTI_HANDLE(multi)) if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE; return CURLM_BAD_HANDLE;
*max_fd = -1; /* so far none! */
easy=multi->easy.next; easy=multi->easy.next;
while(easy) { while(easy) {
switch(easy->state) { switch(easy->state) {
case CURLM_STATE_INIT: default:
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 */
break; break;
case CURLM_STATE_PERFORM: case CURLM_STATE_PERFORM:
/* This should have a set of file descriptors for us to set. */ /* This should have a set of file descriptors for us to set. */
/* after the transfer is done, go DONE */ /* 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; break;
} }
easy = easy->next; /* check next handle */ easy = easy->next; /* check next handle */
@ -222,6 +237,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
bool done; bool done;
CURLMcode result=CURLM_OK; CURLMcode result=CURLM_OK;
*running_handles = 0; /* bump this once for every living handle */
if(!GOOD_MULTI_HANDLE(multi)) if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE; return CURLM_BAD_HANDLE;
@ -239,8 +256,9 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
} }
break; break;
case CURLM_STATE_CONNECT: case CURLM_STATE_CONNECT:
/* connect */ /* Connect. We get a connection identifier filled in. */
easy->result = Curl_connect(easy->easy_handle); easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
/* after connect, go DO */ /* after connect, go DO */
if(CURLE_OK == easy->result) { if(CURLE_OK == easy->result) {
easy->state = CURLM_STATE_DO; easy->state = CURLM_STATE_DO;
@ -249,15 +267,18 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
break; break;
case CURLM_STATE_DO: case CURLM_STATE_DO:
/* Do the fetch or put request */ /* Do the fetch or put request */
easy->result = Curl_do(easy->easy_handle); easy->result = Curl_do(&easy->easy_conn);
/* after do, go PERFORM */ /* after do, go PERFORM */
if(CURLE_OK == easy->result) { 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; break;
case CURLM_STATE_PERFORM: case CURLM_STATE_PERFORM:
/* read/write data if it is ready to do so */ /* 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 /* hm, when we follow redirects, we may need to go back to the CONNECT
state */ state */
/* after the transfer is done, go DONE */ /* 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 */ /* call this even if the readwrite function returned error */
easy->result = Curl_posttransfer(easy->easy_handle); easy->result = Curl_posttransfer(easy->easy_handle);
easy->state = CURLM_STATE_DONE; easy->state = CURLM_STATE_DONE;
result = CURLM_CALL_MULTI_PERFORM;
} }
break; break;
case CURLM_STATE_DONE: case CURLM_STATE_DONE:
/* post-transfer command */ /* 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 */ /* after we have DONE what we're supposed to do, go COMPLETED */
if(CURLE_OK == easy->result) if(CURLE_OK == easy->result)
easy->state = CURLM_STATE_COMPLETED; 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 /* This node should be delinked from the list now and we should post
an information message that we are complete. */ an information message that we are complete. */
break; break;
default:
return CURLM_INTERNAL_ERROR;
} }
if((CURLM_STATE_COMPLETED != easy->state) && if((CURLM_STATE_COMPLETED != easy->state) &&
(CURLE_OK != easy->result)) { (CURLE_OK != easy->result)) {
/* /*
@ -289,10 +314,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
*/ */
easy->state = CURLM_STATE_COMPLETED; 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 */ easy = easy->next; /* operate on next handle */
} }
return CURLM_OK; return result;
} }
CURLMcode curl_multi_cleanup(CURLM *multi_handle) CURLMcode curl_multi_cleanup(CURLM *multi_handle)

View File

@ -50,7 +50,7 @@
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#include <curl/types.h> #include <curl/curl.h>
typedef void CURLM; typedef void CURLM;
@ -60,6 +60,7 @@ typedef enum {
CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */ 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_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_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
CURLM_LAST CURLM_LAST
} CURLMcode; } 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 * In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses. * dual-licensed under the MPL and the MIT/X-derivate licenses.
@ -24,6 +24,17 @@
*****************************************************************************/ *****************************************************************************/
CURLcode Curl_perform(struct SessionHandle *data); 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 */ /* This sets up a forthcoming transfer */
CURLcode CURLcode
Curl_Transfer (struct connectdata *data, Curl_Transfer (struct connectdata *data,

View File

@ -1214,8 +1214,7 @@ static CURLcode ConnectPlease(struct connectdata *conn)
} }
static CURLcode CreateConnection(struct SessionHandle *data, static CURLcode CreateConnection(struct SessionHandle *data,
struct connectdata **in_connect, struct connectdata **in_connect)
bool allow_port) /* allow set.use_port? */
{ {
char *tmp; char *tmp;
char *buf; char *buf;
@ -1614,7 +1613,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
*************************************************************/ *************************************************************/
if (strequal(conn->protostr, "HTTP")) { 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->remote_port = PORT_HTTP;
conn->protocol |= PROT_HTTP; conn->protocol |= PROT_HTTP;
conn->curl_do = Curl_http; conn->curl_do = Curl_http;
@ -1624,7 +1624,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
else if (strequal(conn->protostr, "HTTPS")) { else if (strequal(conn->protostr, "HTTPS")) {
#ifdef USE_SSLEAY #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->remote_port = PORT_HTTPS;
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL; conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
@ -1639,7 +1640,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#endif /* !USE_SSLEAY */ #endif /* !USE_SSLEAY */
} }
else if (strequal(conn->protostr, "GOPHER")) { 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; conn->remote_port = PORT_GOPHER;
/* Skip /<item-type>/ in path if present */ /* Skip /<item-type>/ in path if present */
if (isdigit((int)conn->path[1])) { if (isdigit((int)conn->path[1])) {
@ -1665,7 +1667,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#endif /* !USE_SSLEAY */ #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->remote_port = PORT_FTP;
conn->protocol |= PROT_FTP; conn->protocol |= PROT_FTP;
@ -1720,21 +1723,24 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* telnet testing factory */ /* telnet testing factory */
conn->protocol |= PROT_TELNET; 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->remote_port = PORT_TELNET;
conn->curl_do = Curl_telnet; conn->curl_do = Curl_telnet;
conn->curl_done = Curl_telnet_done; conn->curl_done = Curl_telnet_done;
} }
else if (strequal(conn->protostr, "DICT")) { else if (strequal(conn->protostr, "DICT")) {
conn->protocol |= PROT_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->remote_port = PORT_DICT;
conn->curl_do = Curl_dict; conn->curl_do = Curl_dict;
conn->curl_done = NULL; /* no DICT-specific done */ conn->curl_done = NULL; /* no DICT-specific done */
} }
else if (strequal(conn->protostr, "LDAP")) { else if (strequal(conn->protostr, "LDAP")) {
conn->protocol |= PROT_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->remote_port = PORT_LDAP;
conn->curl_do = Curl_ldap; conn->curl_do = Curl_ldap;
conn->curl_done = NULL; /* no LDAP-specific done */ conn->curl_done = NULL; /* no LDAP-specific done */
@ -2228,14 +2234,13 @@ static CURLcode CreateConnection(struct SessionHandle *data,
} }
CURLcode Curl_connect(struct SessionHandle *data, CURLcode Curl_connect(struct SessionHandle *data,
struct connectdata **in_connect, struct connectdata **in_connect)
bool allow_port)
{ {
CURLcode code; CURLcode code;
struct connectdata *conn; struct connectdata *conn;
/* call the stuff that needs to be called */ /* call the stuff that needs to be called */
code = CreateConnection(data, in_connect, allow_port); code = CreateConnection(data, in_connect);
if(CURLE_OK != code) { if(CURLE_OK != code) {
/* We're not allowed to return failure with memory left allocated /* We're not allowed to return failure with memory left allocated
@ -2291,14 +2296,38 @@ CURLcode Curl_done(struct connectdata *conn)
return result; return result;
} }
CURLcode Curl_do(struct connectdata *conn) CURLcode Curl_do(struct connectdata **connp)
{ {
CURLcode result=CURLE_OK; 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() */ /* generic protocol-specific function pointer set in curl_connect() */
result = conn->curl_do(conn); 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; 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 * In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses. * dual-licensed under the MPL and the MIT/X-derivate licenses.
@ -29,11 +29,9 @@
CURLcode Curl_open(struct SessionHandle **curl); CURLcode Curl_open(struct SessionHandle **curl);
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...); CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
CURLcode Curl_close(struct SessionHandle *data); /* the opposite of curl_open() */ CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
CURLcode Curl_connect(struct SessionHandle *, CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
struct connectdata **, CURLcode Curl_do(struct connectdata **);
bool allow_port);
CURLcode Curl_do(struct connectdata *);
CURLcode Curl_done(struct connectdata *); CURLcode Curl_done(struct connectdata *);
CURLcode Curl_disconnect(struct connectdata *); CURLcode Curl_disconnect(struct connectdata *);

View File

@ -211,6 +211,57 @@ struct ConnectBits {
complete */ 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 * The connectdata struct contains all fields and variables that should be
* unique for an entire connection. * unique for an entire connection.
@ -355,6 +406,8 @@ struct connectdata {
void *generic; void *generic;
} proto; } 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. bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
This must be set to FALSE every time _easy_perform() is This must be set to FALSE every time _easy_perform() is
called. */ 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 hide_progress;
bool http_fail_on_error; bool http_fail_on_error;
bool http_follow_location; bool http_follow_location;
bool include_header; bool include_header;
#define http_include_header include_header /* former name */ #define http_include_header include_header /* former name */