mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
First curl_multi_socket() commit. Should primarily be considered as an internal
code rearrange to fit the future better.
This commit is contained in:
parent
5dc02d53c3
commit
686d90745b
@ -8,7 +8,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \
|
|||||||
content_encoding.c share.c http_digest.c md5.c http_negotiate.c \
|
content_encoding.c share.c http_digest.c md5.c http_negotiate.c \
|
||||||
http_ntlm.c inet_pton.c strtoofft.c strerror.c hostares.c hostasyn.c \
|
http_ntlm.c inet_pton.c strtoofft.c strerror.c hostares.c hostasyn.c \
|
||||||
hostip4.c hostip6.c hostsyn.c hostthre.c inet_ntop.c parsedate.c \
|
hostip4.c hostip6.c hostsyn.c hostthre.c inet_ntop.c parsedate.c \
|
||||||
select.c gtls.c sslgen.c tftp.c
|
select.c gtls.c sslgen.c tftp.c splay.c
|
||||||
|
|
||||||
HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h \
|
HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h \
|
||||||
progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \
|
progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \
|
||||||
@ -18,6 +18,6 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h base64.h hostip.h \
|
|||||||
share.h md5.h http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h \
|
share.h md5.h http_digest.h http_negotiate.h http_ntlm.h ca-bundle.h \
|
||||||
inet_pton.h strtoofft.h strerror.h inet_ntop.h curlx.h memory.h \
|
inet_pton.h strtoofft.h strerror.h inet_ntop.h curlx.h memory.h \
|
||||||
setup.h transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h \
|
setup.h transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h \
|
||||||
gtls.h tftp.h sockaddr.h
|
gtls.h tftp.h sockaddr.h splay.h
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,6 +98,7 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "select.h"
|
#include "select.h"
|
||||||
#include "url.h" /* for Curl_safefree() */
|
#include "url.h" /* for Curl_safefree() */
|
||||||
|
#include "multiif.h"
|
||||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||||
|
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
@ -534,6 +535,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
|||||||
CURLcode code = CURLE_OK;
|
CURLcode code = CURLE_OK;
|
||||||
curl_socket_t sockfd = conn->sock[sockindex];
|
curl_socket_t sockfd = conn->sock[sockindex];
|
||||||
long allow = DEFAULT_CONNECT_TIMEOUT;
|
long allow = DEFAULT_CONNECT_TIMEOUT;
|
||||||
|
long allow_total = 0;
|
||||||
long has_passed;
|
long has_passed;
|
||||||
|
|
||||||
curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
|
curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
|
||||||
@ -546,12 +548,12 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
|||||||
/* subtract the most strict timeout of the ones */
|
/* subtract the most strict timeout of the ones */
|
||||||
if(data->set.timeout && data->set.connecttimeout) {
|
if(data->set.timeout && data->set.connecttimeout) {
|
||||||
if (data->set.timeout < data->set.connecttimeout)
|
if (data->set.timeout < data->set.connecttimeout)
|
||||||
allow = data->set.timeout*1000;
|
allow_total = allow = data->set.timeout*1000;
|
||||||
else
|
else
|
||||||
allow = data->set.connecttimeout*1000;
|
allow = data->set.connecttimeout*1000;
|
||||||
}
|
}
|
||||||
else if(data->set.timeout) {
|
else if(data->set.timeout) {
|
||||||
allow = data->set.timeout*1000;
|
allow_total = allow = data->set.timeout*1000;
|
||||||
}
|
}
|
||||||
else if(data->set.connecttimeout) {
|
else if(data->set.connecttimeout) {
|
||||||
allow = data->set.connecttimeout*1000;
|
allow = data->set.connecttimeout*1000;
|
||||||
@ -564,10 +566,13 @@ CURLcode Curl_is_connected(struct connectdata *conn,
|
|||||||
}
|
}
|
||||||
if(conn->bits.tcpconnect) {
|
if(conn->bits.tcpconnect) {
|
||||||
/* we are connected already! */
|
/* we are connected already! */
|
||||||
|
Curl_expire(data, allow_total);
|
||||||
*connected = TRUE;
|
*connected = TRUE;
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Curl_expire(data, allow);
|
||||||
|
|
||||||
/* check for connect without timeout as we want to return immediately */
|
/* check for connect without timeout as we want to return immediately */
|
||||||
rc = waitconnect(sockfd, 0);
|
rc = waitconnect(sockfd, 0);
|
||||||
|
|
||||||
@ -818,6 +823,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
|||||||
return CURLE_OPERATION_TIMEOUTED;
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Curl_expire(data, timeout_ms);
|
||||||
|
|
||||||
/* Max time for each address */
|
/* Max time for each address */
|
||||||
num_addr = Curl_num_addresses(remotehost->addr);
|
num_addr = Curl_num_addresses(remotehost->addr);
|
||||||
|
26
lib/ftp.c
26
lib/ftp.c
@ -96,6 +96,7 @@
|
|||||||
#include "select.h"
|
#include "select.h"
|
||||||
#include "parsedate.h" /* for the week day and month names */
|
#include "parsedate.h" /* for the week day and month names */
|
||||||
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
#include "sockaddr.h" /* required for Curl_sockaddr_storage */
|
||||||
|
#include "multiif.h"
|
||||||
|
|
||||||
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
|
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
|
||||||
#include "inet_ntoa_r.h"
|
#include "inet_ntoa_r.h"
|
||||||
@ -718,27 +719,24 @@ static CURLcode ftp_state_pwd(struct connectdata *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* For the FTP "protocol connect" and "doing" phases only */
|
/* For the FTP "protocol connect" and "doing" phases only */
|
||||||
CURLcode Curl_ftp_fdset(struct connectdata *conn,
|
int Curl_ftp_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks)
|
||||||
int *max_fdp)
|
|
||||||
{
|
{
|
||||||
struct FTP *ftp = conn->proto.ftp;
|
struct FTP *ftp = conn->proto.ftp;
|
||||||
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
|
|
||||||
|
if(!numsocks)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
|
socks[0] = conn->sock[FIRSTSOCKET];
|
||||||
|
|
||||||
if(ftp->sendleft) {
|
if(ftp->sendleft) {
|
||||||
/* write mode */
|
/* write mode */
|
||||||
FD_SET(sockfd, write_fd_set);
|
return GETSOCK_WRITESOCK(0);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
/* read mode */
|
/* read mode */
|
||||||
FD_SET(sockfd, read_fd_set);
|
return GETSOCK_READSOCK(0);
|
||||||
}
|
|
||||||
|
|
||||||
if((int)sockfd > *max_fdp)
|
|
||||||
*max_fdp = (int)sockfd;
|
|
||||||
|
|
||||||
return CURLE_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called after the FTP_QUOTE state is passed.
|
/* This is called after the FTP_QUOTE state is passed.
|
||||||
|
@ -34,10 +34,9 @@ CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
|
|||||||
int *ftpcode);
|
int *ftpcode);
|
||||||
CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
|
CURLcode Curl_ftp_nextconnect(struct connectdata *conn);
|
||||||
CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done);
|
CURLcode Curl_ftp_multi_statemach(struct connectdata *conn, bool *done);
|
||||||
CURLcode Curl_ftp_fdset(struct connectdata *conn,
|
int Curl_ftp_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks);
|
||||||
int *max_fdp);
|
|
||||||
CURLcode Curl_ftp_doing(struct connectdata *conn,
|
CURLcode Curl_ftp_doing(struct connectdata *conn,
|
||||||
bool *dophase_done);
|
bool *dophase_done);
|
||||||
#endif /* CURL_DISABLE_FTP */
|
#endif /* CURL_DISABLE_FTP */
|
||||||
|
26
lib/hash.c
26
lib/hash.c
@ -124,8 +124,11 @@ mk_hash_element(char *key, size_t key_len, const void *p)
|
|||||||
(struct curl_hash_element *) malloc(sizeof(struct curl_hash_element));
|
(struct curl_hash_element *) malloc(sizeof(struct curl_hash_element));
|
||||||
|
|
||||||
if(he) {
|
if(he) {
|
||||||
char *dup = strdup(key);
|
char *dup = malloc(key_len);
|
||||||
if(dup) {
|
if(dup) {
|
||||||
|
/* copy the key */
|
||||||
|
memcpy(dup, key, key_len);
|
||||||
|
|
||||||
he->key = dup;
|
he->key = dup;
|
||||||
he->key_len = key_len;
|
he->key_len = key_len;
|
||||||
he->ptr = (void *) p;
|
he->ptr = (void *) p;
|
||||||
@ -179,6 +182,23 @@ Curl_hash_add(struct curl_hash *h, char *key, size_t key_len, void *p)
|
|||||||
return NULL; /* failure */
|
return NULL; /* failure */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* remove the identified hash entry, returns non-zero on failure */
|
||||||
|
int Curl_hash_delete(struct curl_hash *h, char *key, size_t key_len)
|
||||||
|
{
|
||||||
|
struct curl_llist_element *le;
|
||||||
|
struct curl_hash_element *he;
|
||||||
|
struct curl_llist *l = FETCH_LIST(h, key, key_len);
|
||||||
|
|
||||||
|
for (le = l->head; le; le = le->next) {
|
||||||
|
he = le->ptr;
|
||||||
|
if (hash_key_compare(he->key, he->key_len, key, key_len)) {
|
||||||
|
Curl_llist_remove(l, le, (void *) h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
void *
|
void *
|
||||||
Curl_hash_pick(struct curl_hash *h, char *key, size_t key_len)
|
Curl_hash_pick(struct curl_hash *h, char *key, size_t key_len)
|
||||||
{
|
{
|
||||||
@ -186,9 +206,7 @@ Curl_hash_pick(struct curl_hash *h, char *key, size_t key_len)
|
|||||||
struct curl_hash_element *he;
|
struct curl_hash_element *he;
|
||||||
struct curl_llist *l = FETCH_LIST(h, key, key_len);
|
struct curl_llist *l = FETCH_LIST(h, key, key_len);
|
||||||
|
|
||||||
for (le = l->head;
|
for (le = l->head; le; le = le->next) {
|
||||||
le;
|
|
||||||
le = le->next) {
|
|
||||||
he = le->ptr;
|
he = le->ptr;
|
||||||
if (hash_key_compare(he->key, he->key_len, key, key_len)) {
|
if (hash_key_compare(he->key, he->key_len, key, key_len)) {
|
||||||
return he->ptr;
|
return he->ptr;
|
||||||
|
@ -105,17 +105,15 @@
|
|||||||
* Returns: CURLE_OK always!
|
* Returns: CURLE_OK always!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CURLcode Curl_resolv_fdset(struct connectdata *conn,
|
int Curl_resolv_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks)
|
||||||
int *max_fdp)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
int max = ares_fds(conn->data->state.areschannel,
|
int max = ares_getsock(conn->data->state.areschannel,
|
||||||
read_fd_set, write_fd_set);
|
(int *)socks, numsocks);
|
||||||
*max_fdp = max;
|
|
||||||
|
|
||||||
return CURLE_OK;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
13
lib/hostip.h
13
lib/hostip.h
@ -160,6 +160,14 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
|
|||||||
CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
CURLcode Curl_wait_for_resolv(struct connectdata *conn,
|
||||||
struct Curl_dns_entry **dnsentry);
|
struct Curl_dns_entry **dnsentry);
|
||||||
|
|
||||||
|
|
||||||
|
/* Curl_resolv_getsock() is a generic function that exists in multiple versions
|
||||||
|
depending on what name resolve technology we've built to use. The function
|
||||||
|
is called from the multi_getsock() function */
|
||||||
|
int Curl_resolv_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *sock,
|
||||||
|
int numsocks);
|
||||||
|
#if 0
|
||||||
/* Curl_resolv_fdset() is a generic function that exists in multiple versions
|
/* Curl_resolv_fdset() is a generic function that exists in multiple versions
|
||||||
depending on what name resolve technology we've built to use. The function
|
depending on what name resolve technology we've built to use. The function
|
||||||
is called from the curl_multi_fdset() function */
|
is called from the curl_multi_fdset() function */
|
||||||
@ -167,8 +175,11 @@ CURLcode Curl_resolv_fdset(struct connectdata *conn,
|
|||||||
fd_set *read_fd_set,
|
fd_set *read_fd_set,
|
||||||
fd_set *write_fd_set,
|
fd_set *write_fd_set,
|
||||||
int *max_fdp);
|
int *max_fdp);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* unlock a previously resolved dns entry */
|
/* unlock a previously resolved dns entry */
|
||||||
void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns);
|
void Curl_resolv_unlock(struct SessionHandle *data,
|
||||||
|
struct Curl_dns_entry *dns);
|
||||||
|
|
||||||
/* for debugging purposes only: */
|
/* for debugging purposes only: */
|
||||||
void Curl_scan_cache_used(void *user, void *ptr);
|
void Curl_scan_cache_used(void *user, void *ptr);
|
||||||
|
@ -126,17 +126,15 @@ CURLcode Curl_is_resolved(struct connectdata *conn,
|
|||||||
* It is present here to keep #ifdefs out from multi.c
|
* It is present here to keep #ifdefs out from multi.c
|
||||||
*/
|
*/
|
||||||
|
|
||||||
CURLcode Curl_resolv_fdset(struct connectdata *conn,
|
int Curl_resolv_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *sock,
|
||||||
fd_set *write_fd_set,
|
int numsocks)
|
||||||
int *max_fdp)
|
|
||||||
{
|
{
|
||||||
(void)conn;
|
(void)conn;
|
||||||
(void)read_fd_set;
|
(void)sock;
|
||||||
(void)write_fd_set;
|
(void)numsocks;
|
||||||
(void)max_fdp;
|
|
||||||
|
|
||||||
return CURLE_OK;
|
return 0; /* no bits since we don't use any socks */
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* truly sync */
|
#endif /* truly sync */
|
||||||
|
22
lib/http.c
22
lib/http.c
@ -97,6 +97,7 @@
|
|||||||
#include "select.h"
|
#include "select.h"
|
||||||
#include "parsedate.h" /* for the week day and month names */
|
#include "parsedate.h" /* for the week day and month names */
|
||||||
#include "strtoofft.h"
|
#include "strtoofft.h"
|
||||||
|
#include "multiif.h"
|
||||||
|
|
||||||
#define _MPRINTF_REPLACE /* use our functions only */
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
#include <curl/mprintf.h>
|
#include <curl/mprintf.h>
|
||||||
@ -1416,26 +1417,25 @@ CURLcode Curl_https_connecting(struct connectdata *conn, bool *done)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_SSLEAY
|
#ifdef USE_SSLEAY
|
||||||
CURLcode Curl_https_proto_fdset(struct connectdata *conn,
|
int Curl_https_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks)
|
||||||
int *max_fdp)
|
|
||||||
{
|
{
|
||||||
if (conn->protocol & PROT_HTTPS) {
|
if (conn->protocol & PROT_HTTPS) {
|
||||||
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
|
struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
|
||||||
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
|
|
||||||
|
if(!numsocks)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
if (connssl->connecting_state == ssl_connect_2_writing) {
|
if (connssl->connecting_state == ssl_connect_2_writing) {
|
||||||
/* write mode */
|
/* write mode */
|
||||||
FD_SET(sockfd, write_fd_set);
|
socks[0] = conn->sock[FIRSTSOCKET];
|
||||||
if((int)sockfd > *max_fdp)
|
return GETSOCK_WRITESOCK(0);
|
||||||
*max_fdp = (int)sockfd;
|
|
||||||
}
|
}
|
||||||
else if (connssl->connecting_state == ssl_connect_2_reading) {
|
else if (connssl->connecting_state == ssl_connect_2_reading) {
|
||||||
/* read mode */
|
/* read mode */
|
||||||
FD_SET(sockfd, read_fd_set);
|
socks[0] = conn->sock[FIRSTSOCKET];
|
||||||
if((int)sockfd > *max_fdp)
|
return GETSOCK_READSOCK(0);
|
||||||
*max_fdp = (int)sockfd;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CURLE_OK;
|
return CURLE_OK;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
* | (__| |_| | _ <| |___
|
* | (__| |_| | _ <| |___
|
||||||
* \___|\___/|_| \_\_____|
|
* \___|\___/|_| \_\_____|
|
||||||
*
|
*
|
||||||
* Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al.
|
* Copyright (C) 1998 - 2006, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||||
*
|
*
|
||||||
* This software is licensed as described in the file COPYING, which
|
* This software is licensed as described in the file COPYING, which
|
||||||
* you should have received as part of this distribution. The terms
|
* you should have received as part of this distribution. The terms
|
||||||
@ -38,10 +38,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done);
|
|||||||
CURLcode Curl_http_done(struct connectdata *, CURLcode);
|
CURLcode Curl_http_done(struct connectdata *, CURLcode);
|
||||||
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
|
CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
|
||||||
CURLcode Curl_https_connecting(struct connectdata *conn, bool *done);
|
CURLcode Curl_https_connecting(struct connectdata *conn, bool *done);
|
||||||
CURLcode Curl_https_proto_fdset(struct connectdata *conn,
|
int Curl_https_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks);
|
||||||
int *max_fdp);
|
|
||||||
|
|
||||||
/* The following functions are defined in http_chunks.c */
|
/* The following functions are defined in http_chunks.c */
|
||||||
void Curl_httpchunk_init(struct connectdata *conn);
|
void Curl_httpchunk_init(struct connectdata *conn);
|
||||||
|
705
lib/multi.c
705
lib/multi.c
@ -46,6 +46,7 @@
|
|||||||
#include "easyif.h"
|
#include "easyif.h"
|
||||||
#include "multiif.h"
|
#include "multiif.h"
|
||||||
#include "sendf.h"
|
#include "sendf.h"
|
||||||
|
#include "timeval.h"
|
||||||
|
|
||||||
/* The last #include file should be: */
|
/* The last #include file should be: */
|
||||||
#include "memdebug.h"
|
#include "memdebug.h"
|
||||||
@ -73,6 +74,18 @@ typedef enum {
|
|||||||
CURLM_STATE_LAST /* not a true state, never use this */
|
CURLM_STATE_LAST /* not a true state, never use this */
|
||||||
} CURLMstate;
|
} CURLMstate;
|
||||||
|
|
||||||
|
/* we support 16 sockets per easy handle. Set the corresponding bit to what
|
||||||
|
action we should wait for */
|
||||||
|
#define MAX_SOCKSPEREASYHANDLE 16
|
||||||
|
#define GETSOCK_READABLE (0x00ff)
|
||||||
|
#define GETSOCK_WRITABLE (0xff00)
|
||||||
|
|
||||||
|
struct socketstate {
|
||||||
|
curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
|
||||||
|
long action; /* socket action bitmap */
|
||||||
|
long timeout[MAX_SOCKSPEREASYHANDLE];
|
||||||
|
};
|
||||||
|
|
||||||
struct Curl_one_easy {
|
struct Curl_one_easy {
|
||||||
/* first, two fields for the linked list of these */
|
/* first, two fields for the linked list of these */
|
||||||
struct Curl_one_easy *next;
|
struct Curl_one_easy *next;
|
||||||
@ -90,6 +103,8 @@ struct Curl_one_easy {
|
|||||||
will be deleted when this handle is removed
|
will be deleted when this handle is removed
|
||||||
from the multi-handle */
|
from the multi-handle */
|
||||||
int msg_num; /* number of messages left in 'msg' to return */
|
int msg_num; /* number of messages left in 'msg' to return */
|
||||||
|
|
||||||
|
struct socketstate sockstate; /* for the socket API magic */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CURL_MULTI_HANDLE 0x000bab1e
|
#define CURL_MULTI_HANDLE 0x000bab1e
|
||||||
@ -111,8 +126,21 @@ struct Curl_multi {
|
|||||||
|
|
||||||
int num_msgs; /* total amount of messages in the easy handles */
|
int num_msgs; /* total amount of messages in the easy handles */
|
||||||
|
|
||||||
|
/* callback function and user data pointer for the *socket() API */
|
||||||
|
curl_socket_callback socket_cb;
|
||||||
|
void *socket_userp;
|
||||||
|
|
||||||
/* Hostname cache */
|
/* Hostname cache */
|
||||||
struct curl_hash *hostcache;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* always use this function to change state, to make debugging easier */
|
/* always use this function to change state, to make debugging easier */
|
||||||
@ -134,6 +162,7 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
|
|||||||
};
|
};
|
||||||
CURLMstate oldstate = easy->state;
|
CURLMstate oldstate = easy->state;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
easy->state = state;
|
easy->state = state;
|
||||||
|
|
||||||
#ifdef CURLDEBUG
|
#ifdef CURLDEBUG
|
||||||
@ -143,25 +172,166 @@ static void multistate(struct Curl_one_easy *easy, CURLMstate state)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We add one of these structs to the sockhash, and then if we add more easy
|
||||||
|
* handles for the same socket we just link them with the next/prev pointers
|
||||||
|
* from the node added to the hash. We only remove the node from the hash when
|
||||||
|
* the final easy handle/socket associated with the node is removed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct Curl_sh_entry {
|
||||||
|
struct Curl_sh_entry *next;
|
||||||
|
struct Curl_sh_entry *prev;
|
||||||
|
struct SessionHandle *easy;
|
||||||
|
time_t timestamp;
|
||||||
|
long inuse;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* make sure this socket is present in the hash for this handle */
|
||||||
|
static int sh_addentry(struct curl_hash *sh,
|
||||||
|
curl_socket_t s,
|
||||||
|
struct SessionHandle *data)
|
||||||
|
{
|
||||||
|
struct Curl_sh_entry *there =
|
||||||
|
Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
|
||||||
|
struct Curl_sh_entry *check;
|
||||||
|
|
||||||
|
if(there) {
|
||||||
|
/* verify that this particular handle is in here */
|
||||||
|
check = there;
|
||||||
|
while(check) {
|
||||||
|
if(check->easy == data)
|
||||||
|
/* it is, return fine */
|
||||||
|
return 0;
|
||||||
|
check = check->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* not present, add it */
|
||||||
|
check = calloc(sizeof(struct Curl_sh_entry), 1);
|
||||||
|
if(!check)
|
||||||
|
return 1; /* major failure */
|
||||||
|
check->easy = data;
|
||||||
|
|
||||||
|
if(there) {
|
||||||
|
/* the node for this socket is already here, now link in the struct for
|
||||||
|
the new handle */
|
||||||
|
|
||||||
|
check->next = there->next; /* get the previous next to point to */
|
||||||
|
there->next = check; /* make the new next point to the new entry */
|
||||||
|
|
||||||
|
check->next->prev = check; /* make sure the next one points back to the
|
||||||
|
new one */
|
||||||
|
/* check->prev = NULL; is already cleared and we have no previous
|
||||||
|
node */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* make/add new hash entry */
|
||||||
|
if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check))
|
||||||
|
return 1; /* major failure */
|
||||||
|
}
|
||||||
|
return 0; /* things are good in sockhash land */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* delete the given socket + handle from the hash */
|
||||||
|
static void sh_delentry(struct curl_hash *sh,
|
||||||
|
curl_socket_t s,
|
||||||
|
struct SessionHandle *data)
|
||||||
|
{
|
||||||
|
struct Curl_sh_entry *there =
|
||||||
|
Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
|
||||||
|
|
||||||
|
while(there) {
|
||||||
|
/* this socket is in the hash, now scan the list at this point and see if
|
||||||
|
the given easy handle is in there and if so remote that singe entry */
|
||||||
|
if(there->easy == data) {
|
||||||
|
/* match! */
|
||||||
|
if(there->next || there->prev) {
|
||||||
|
/* it is not the only handle for this socket, so only unlink this
|
||||||
|
particular easy handle and leave the actional hash entry */
|
||||||
|
|
||||||
|
/* unlink */
|
||||||
|
there->next->prev = there->prev;
|
||||||
|
there->prev->next = there->next;
|
||||||
|
free(there);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* This is the only easy handle for this socket, we must remove the
|
||||||
|
hash entry. (This'll end up in a call to sh_freeentry().) */
|
||||||
|
Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
there = there->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* free a sockhash entry
|
||||||
|
*/
|
||||||
|
static void sh_freeentry(void *freethis)
|
||||||
|
{
|
||||||
|
struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
|
||||||
|
struct Curl_sh_entry *more = p->next;
|
||||||
|
|
||||||
|
/* if there's a chain of more handles, remove that chain first */
|
||||||
|
while(more) {
|
||||||
|
struct Curl_sh_entry *next = more->next;
|
||||||
|
free(more);
|
||||||
|
more = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sh_init() creates a new socket hash and returns the handle for it.
|
||||||
|
*
|
||||||
|
* Quote from README.multi_socket:
|
||||||
|
*
|
||||||
|
* "Some tests at 7000 and 9000 connections showed that the socket hash lookup
|
||||||
|
* is somewhat of a bottle neck. Its current implementation may be a bit too
|
||||||
|
* limiting. It simply has a fixed-size array, and on each entry in the array
|
||||||
|
* it has a linked list with entries. So the hash only checks which list to
|
||||||
|
* scan through. The code I had used so for used a list with merely 7 slots
|
||||||
|
* (as that is what the DNS hash uses) but with 7000 connections that would
|
||||||
|
* make an average of 1000 nodes in each list to run through. I upped that to
|
||||||
|
* 97 slots (I believe a prime is suitable) and noticed a significant speed
|
||||||
|
* increase. I need to reconsider the hash implementation or use a rather
|
||||||
|
* large default value like this. At 9000 connections I was still below 10us
|
||||||
|
* per call."
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static struct curl_hash *sh_init(void)
|
||||||
|
{
|
||||||
|
return Curl_hash_alloc(97, sh_freeentry);
|
||||||
|
}
|
||||||
|
|
||||||
CURLM *curl_multi_init(void)
|
CURLM *curl_multi_init(void)
|
||||||
{
|
{
|
||||||
struct Curl_multi *multi;
|
struct Curl_multi *multi = (void *)calloc(sizeof(struct Curl_multi), 1);
|
||||||
|
|
||||||
multi = (void *)malloc(sizeof(struct Curl_multi));
|
if(!multi)
|
||||||
|
|
||||||
if(multi) {
|
|
||||||
memset(multi, 0, sizeof(struct Curl_multi));
|
|
||||||
multi->type = CURL_MULTI_HANDLE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
multi->type = CURL_MULTI_HANDLE;
|
||||||
|
|
||||||
multi->hostcache = Curl_mk_dnscache();
|
multi->hostcache = Curl_mk_dnscache();
|
||||||
if(!multi->hostcache) {
|
if(!multi->hostcache) {
|
||||||
/* failure, free mem and bail out */
|
/* failure, free mem and bail out */
|
||||||
free(multi);
|
free(multi);
|
||||||
multi = NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multi->sockhash = sh_init();
|
||||||
|
if(!multi->sockhash) {
|
||||||
|
/* failure, free mem and bail out */
|
||||||
|
Curl_hash_destroy(multi->hostcache);
|
||||||
|
free(multi);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
return (CURLM *) multi;
|
return (CURLM *) multi;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -170,6 +340,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
|||||||
{
|
{
|
||||||
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 i;
|
||||||
|
|
||||||
/* First, make some basic checks that the CURLM handle is a good handle */
|
/* First, make some basic checks that the CURLM handle is a good handle */
|
||||||
if(!GOOD_MULTI_HANDLE(multi))
|
if(!GOOD_MULTI_HANDLE(multi))
|
||||||
@ -180,12 +351,12 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
|||||||
return CURLM_BAD_EASY_HANDLE;
|
return CURLM_BAD_EASY_HANDLE;
|
||||||
|
|
||||||
/* Now, time to add an easy handle to the multi stack */
|
/* Now, time to add an easy handle to the multi stack */
|
||||||
easy = (struct Curl_one_easy *)malloc(sizeof(struct Curl_one_easy));
|
easy = (struct Curl_one_easy *)calloc(sizeof(struct Curl_one_easy), 1);
|
||||||
if(!easy)
|
if(!easy)
|
||||||
return CURLM_OUT_OF_MEMORY;
|
return CURLM_OUT_OF_MEMORY;
|
||||||
|
|
||||||
/* clean it all first (just to be sure) */
|
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
|
||||||
memset(easy, 0, sizeof(struct Curl_one_easy));
|
easy->sockstate.socks[i] = CURL_SOCKET_BAD;
|
||||||
|
|
||||||
/* set the easy handle */
|
/* set the easy handle */
|
||||||
easy->easy_handle = easy_handle;
|
easy->easy_handle = easy_handle;
|
||||||
@ -209,6 +380,9 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
|||||||
|
|
||||||
Curl_easy_addmulti(easy_handle, multi_handle);
|
Curl_easy_addmulti(easy_handle, multi_handle);
|
||||||
|
|
||||||
|
/* make the SessionHandle struct refer back to this struct */
|
||||||
|
easy->easy_handle->set.one_easy = easy;
|
||||||
|
|
||||||
/* increase the node-counter */
|
/* increase the node-counter */
|
||||||
multi->num_easy++;
|
multi->num_easy++;
|
||||||
|
|
||||||
@ -257,6 +431,8 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
if(easy->next)
|
if(easy->next)
|
||||||
easy->next->prev = easy->prev;
|
easy->next->prev = easy->prev;
|
||||||
|
|
||||||
|
easy->easy_handle->set.one_easy = NULL; /* detached */
|
||||||
|
|
||||||
/* NOTE NOTE NOTE
|
/* NOTE NOTE NOTE
|
||||||
We do not touch the easy handle here! */
|
We do not touch the easy handle here! */
|
||||||
if (easy->msg)
|
if (easy->msg)
|
||||||
@ -271,6 +447,65 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
|||||||
return CURLM_BAD_EASY_HANDLE; /* twasn't found */
|
return CURLM_BAD_EASY_HANDLE; /* twasn't found */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int waitconnect_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *sock,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
if(!numsocks)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
|
sock[0] = conn->sock[FIRSTSOCKET];
|
||||||
|
return GETSOCK_WRITESOCK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int domore_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *sock,
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
if(!numsocks)
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
|
/* When in DO_MORE state, we could be either waiting for us
|
||||||
|
to connect to a remote site, or we could wait for that site
|
||||||
|
to connect to us. It makes a difference in the way: if we
|
||||||
|
connect to the site we wait for the socket to become writable, if
|
||||||
|
the site connects to us we wait for it to become readable */
|
||||||
|
sock[0] = conn->sock[SECONDARYSOCKET];
|
||||||
|
|
||||||
|
return GETSOCK_WRITESOCK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* returns bitmapped flags for this handle and its sockets */
|
||||||
|
static int multi_getsock(struct Curl_one_easy *easy,
|
||||||
|
curl_socket_t *socks, /* points to numsocks number
|
||||||
|
of sockets */
|
||||||
|
int numsocks)
|
||||||
|
{
|
||||||
|
switch(easy->state) {
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case CURLM_STATE_WAITRESOLVE:
|
||||||
|
return Curl_resolv_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
|
case CURLM_STATE_PROTOCONNECT:
|
||||||
|
return Curl_protocol_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
|
case CURLM_STATE_DOING:
|
||||||
|
return Curl_doing_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
|
case CURLM_STATE_WAITCONNECT:
|
||||||
|
return waitconnect_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
|
case CURLM_STATE_DO_MORE:
|
||||||
|
return domore_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
|
||||||
|
case CURLM_STATE_PERFORM:
|
||||||
|
return Curl_single_getsock(easy->easy_conn, socks, numsocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
||||||
fd_set *read_fd_set, fd_set *write_fd_set,
|
fd_set *read_fd_set, fd_set *write_fd_set,
|
||||||
fd_set *exc_fd_set, int *max_fd)
|
fd_set *exc_fd_set, int *max_fd)
|
||||||
@ -281,104 +516,58 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
|||||||
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;
|
int this_max_fd=-1;
|
||||||
|
curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
|
||||||
|
int bitmap;
|
||||||
|
int i;
|
||||||
|
(void)exc_fd_set; /* not used */
|
||||||
|
|
||||||
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) {
|
bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case CURLM_STATE_WAITRESOLVE:
|
|
||||||
/* waiting for a resolve to complete */
|
|
||||||
Curl_resolv_fdset(easy->easy_conn, read_fd_set, write_fd_set,
|
|
||||||
&this_max_fd);
|
|
||||||
if(this_max_fd > *max_fd)
|
|
||||||
*max_fd = this_max_fd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_PROTOCONNECT:
|
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
|
||||||
Curl_protocol_fdset(easy->easy_conn, read_fd_set, write_fd_set,
|
curl_socket_t s = CURL_SOCKET_BAD;
|
||||||
&this_max_fd);
|
|
||||||
if(this_max_fd > *max_fd)
|
|
||||||
*max_fd = this_max_fd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_DOING:
|
if(bitmap & GETSOCK_READSOCK(i)) {
|
||||||
Curl_doing_fdset(easy->easy_conn, read_fd_set, write_fd_set,
|
FD_SET(sockbunch[i], read_fd_set);
|
||||||
&this_max_fd);
|
s = sockbunch[i];
|
||||||
if(this_max_fd > *max_fd)
|
|
||||||
*max_fd = this_max_fd;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case CURLM_STATE_WAITCONNECT:
|
|
||||||
case CURLM_STATE_DO_MORE:
|
|
||||||
{
|
|
||||||
/* when we're waiting for a connect, we wait for the socket to
|
|
||||||
become writable */
|
|
||||||
struct connectdata *conn = easy->easy_conn;
|
|
||||||
curl_socket_t sockfd;
|
|
||||||
|
|
||||||
if(CURLM_STATE_WAITCONNECT == easy->state) {
|
|
||||||
sockfd = conn->sock[FIRSTSOCKET];
|
|
||||||
FD_SET(sockfd, write_fd_set);
|
|
||||||
}
|
}
|
||||||
|
if(bitmap & GETSOCK_WRITESOCK(i)) {
|
||||||
|
FD_SET(sockbunch[i], write_fd_set);
|
||||||
|
s = sockbunch[i];
|
||||||
|
}
|
||||||
|
if(s == CURL_SOCKET_BAD)
|
||||||
|
/* this socket is unused, break out of loop */
|
||||||
|
break;
|
||||||
else {
|
else {
|
||||||
/* When in DO_MORE state, we could be either waiting for us
|
if(s > this_max_fd)
|
||||||
to connect to a remote site, or we could wait for that site
|
this_max_fd = s;
|
||||||
to connect to us. It makes a difference in the way: if we
|
}
|
||||||
connect to the site we wait for the socket to become writable, if
|
|
||||||
the site connects to us we wait for it to become readable */
|
|
||||||
sockfd = conn->sock[SECONDARYSOCKET];
|
|
||||||
FD_SET(sockfd, write_fd_set);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if((int)sockfd > *max_fd)
|
|
||||||
*max_fd = (int)sockfd;
|
|
||||||
}
|
|
||||||
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 */
|
easy = easy->next; /* check next handle */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*max_fd = this_max_fd;
|
||||||
|
|
||||||
return CURLM_OK;
|
return CURLM_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
static CURLMcode multi_runsingle(struct Curl_multi *multi,
|
||||||
|
struct Curl_one_easy *easy,
|
||||||
|
int *running_handles)
|
||||||
{
|
{
|
||||||
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
|
||||||
struct Curl_one_easy *easy;
|
|
||||||
bool done;
|
|
||||||
CURLMcode result=CURLM_OK;
|
|
||||||
struct Curl_message *msg = NULL;
|
struct Curl_message *msg = NULL;
|
||||||
bool connected;
|
bool connected;
|
||||||
bool async;
|
bool async;
|
||||||
bool protocol_connect;
|
bool protocol_connect;
|
||||||
bool dophase_done;
|
bool dophase_done;
|
||||||
|
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;
|
|
||||||
|
|
||||||
easy=multi->easy.next;
|
|
||||||
while(easy) {
|
|
||||||
do {
|
do {
|
||||||
if (CURLM_STATE_WAITCONNECT <= easy->state &&
|
if (CURLM_STATE_WAITCONNECT <= easy->state &&
|
||||||
easy->state <= CURLM_STATE_DO &&
|
easy->state <= CURLM_STATE_DO &&
|
||||||
@ -731,10 +920,45 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
|||||||
|
|
||||||
multi->num_msgs++; /* increase message counter */
|
multi->num_msgs++; /* increase message counter */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||||
|
{
|
||||||
|
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||||
|
struct Curl_one_easy *easy;
|
||||||
|
CURLMcode returncode=CURLM_OK;
|
||||||
|
struct Curl_tree *t;
|
||||||
|
|
||||||
|
*running_handles = 0; /* bump this once for every living handle */
|
||||||
|
|
||||||
|
if(!GOOD_MULTI_HANDLE(multi))
|
||||||
|
return CURLM_BAD_HANDLE;
|
||||||
|
|
||||||
|
easy=multi->easy.next;
|
||||||
|
while(easy) {
|
||||||
|
CURLMcode result = multi_runsingle(multi, easy, running_handles);
|
||||||
|
if(result)
|
||||||
|
returncode = result;
|
||||||
|
|
||||||
easy = easy->next; /* operate on next handle */
|
easy = easy->next; /* operate on next handle */
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
/*
|
||||||
|
* Simply remove all expired timers from the splay since handles are dealt
|
||||||
|
* with unconditionally by this function and curl_multi_timeout() requires
|
||||||
|
* that already passed/handled expire times are removed from the splay.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
struct timeval now = Curl_tvnow();
|
||||||
|
int key = now.tv_sec; /* drop the usec part */
|
||||||
|
|
||||||
|
multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
|
||||||
|
} while(t);
|
||||||
|
|
||||||
|
return returncode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is called when an easy handle is cleanup'ed that is part of a multi
|
/* This is called when an easy handle is cleanup'ed that is part of a multi
|
||||||
@ -753,6 +977,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
|||||||
if(GOOD_MULTI_HANDLE(multi)) {
|
if(GOOD_MULTI_HANDLE(multi)) {
|
||||||
multi->type = 0; /* not good anymore */
|
multi->type = 0; /* not good anymore */
|
||||||
Curl_hash_destroy(multi->hostcache);
|
Curl_hash_destroy(multi->hostcache);
|
||||||
|
Curl_hash_destroy(multi->sockhash);
|
||||||
|
|
||||||
/* remove all easy handles */
|
/* remove all easy handles */
|
||||||
easy = multi->easy.next;
|
easy = multi->easy.next;
|
||||||
@ -807,3 +1032,311 @@ CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
|
|||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check what sockets we deal with and their "action state" and if we have a
|
||||||
|
* difference from last time we call the callback accordingly.
|
||||||
|
*/
|
||||||
|
static void singlesocket(struct Curl_multi *multi,
|
||||||
|
struct Curl_one_easy *easy)
|
||||||
|
{
|
||||||
|
struct socketstate current;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(¤t, 0, sizeof(current));
|
||||||
|
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
|
||||||
|
current.socks[i] = CURL_SOCKET_BAD;
|
||||||
|
|
||||||
|
/* first fill in the 'current' struct with the state as it is now */
|
||||||
|
current.action = multi_getsock(easy, current.socks, MAX_SOCKSPEREASYHANDLE);
|
||||||
|
|
||||||
|
/* when filled in, we compare with the previous round's state */
|
||||||
|
if(memcmp(¤t, &easy->sockstate, sizeof(struct socketstate))) {
|
||||||
|
/* difference, call the callback once for every socket change ! */
|
||||||
|
for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
|
||||||
|
int action;
|
||||||
|
curl_socket_t s = current.socks[i];
|
||||||
|
|
||||||
|
/* Ok, this approach is probably too naive and simple-minded but
|
||||||
|
it might work for a start */
|
||||||
|
|
||||||
|
if((easy->sockstate.socks[i] == CURL_SOCKET_BAD) &&
|
||||||
|
(s == CURL_SOCKET_BAD)) {
|
||||||
|
/* no socket now and there was no socket before */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(s == CURL_SOCKET_BAD) {
|
||||||
|
/* socket is removed */
|
||||||
|
action = CURL_POLL_REMOVE;
|
||||||
|
s = easy->sockstate.socks[i]; /* this is the removed socket */
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(easy->sockstate.socks[i] == s) {
|
||||||
|
/* still the same socket, but are we waiting for the same actions? */
|
||||||
|
unsigned int curr;
|
||||||
|
unsigned int prev;
|
||||||
|
|
||||||
|
/* the current read/write bits for this particular socket */
|
||||||
|
curr = current.action & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i));
|
||||||
|
|
||||||
|
/* the previous read/write bits for this particular socket */
|
||||||
|
prev = easy->sockstate.action &
|
||||||
|
(GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i));
|
||||||
|
|
||||||
|
if(curr == prev)
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
action = (current.action & GETSOCK_READSOCK(i)?CURL_POLL_IN:0) |
|
||||||
|
(current.action & GETSOCK_WRITESOCK(i)?CURL_POLL_OUT:0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* call the callback with this new info */
|
||||||
|
if(multi->socket_cb) {
|
||||||
|
multi->socket_cb(easy->easy_handle,
|
||||||
|
s,
|
||||||
|
action,
|
||||||
|
multi->socket_userp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the sockhash accordingly */
|
||||||
|
if(action == CURL_POLL_REMOVE)
|
||||||
|
/* remove from hash for this easy handle */
|
||||||
|
sh_delentry(multi->sockhash, s, easy->easy_handle);
|
||||||
|
else
|
||||||
|
/* make sure this socket is present in the hash for this handle */
|
||||||
|
sh_addentry(multi->sockhash, s, easy->easy_handle);
|
||||||
|
}
|
||||||
|
/* copy the current state to the storage area */
|
||||||
|
memcpy(&easy->sockstate, ¤t, sizeof(struct socketstate));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* identical, nothing new happened so we don't do any callbacks */
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static CURLMcode multi_socket(struct Curl_multi *multi,
|
||||||
|
bool checkall,
|
||||||
|
curl_socket_t s)
|
||||||
|
{
|
||||||
|
CURLMcode result = CURLM_OK;
|
||||||
|
int running_handles;
|
||||||
|
struct SessionHandle *data = NULL;
|
||||||
|
struct Curl_tree *t;
|
||||||
|
|
||||||
|
if(checkall) {
|
||||||
|
struct Curl_one_easy *easyp;
|
||||||
|
result = curl_multi_perform(multi, &running_handles);
|
||||||
|
|
||||||
|
/* walk through each easy handle and do the socket state change magic
|
||||||
|
and callbacks */
|
||||||
|
easyp=multi->easy.next;
|
||||||
|
while(easyp) {
|
||||||
|
singlesocket(multi, easyp);
|
||||||
|
easyp = easyp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
else if (s != CURL_SOCKET_TIMEOUT) {
|
||||||
|
|
||||||
|
struct Curl_sh_entry *entry =
|
||||||
|
Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
|
||||||
|
|
||||||
|
if(!entry)
|
||||||
|
/* unmatched socket, major problemo! */
|
||||||
|
return CURLM_BAD_SOCKET; /* better return code? */
|
||||||
|
|
||||||
|
/* Now, there is potentially a chain of easy handles in this hash
|
||||||
|
entry struct and we need to deal with all of them */
|
||||||
|
|
||||||
|
do {
|
||||||
|
data = entry->easy;
|
||||||
|
|
||||||
|
result = multi_runsingle(multi, data->set.one_easy, &running_handles);
|
||||||
|
|
||||||
|
if(result == CURLM_OK)
|
||||||
|
/* get the socket(s) and check if the state has been changed since
|
||||||
|
last */
|
||||||
|
singlesocket(multi, data->set.one_easy);
|
||||||
|
|
||||||
|
entry = entry->next;
|
||||||
|
|
||||||
|
} while(entry);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The loop following here will go on as long as there are expire-times left
|
||||||
|
* to process in the splay and 'data' will be re-assigned for every expired
|
||||||
|
* handle we deal with.
|
||||||
|
*/
|
||||||
|
do {
|
||||||
|
int key;
|
||||||
|
struct timeval now;
|
||||||
|
|
||||||
|
/* the first loop lap 'data' can be NULL */
|
||||||
|
if(data) {
|
||||||
|
result = multi_runsingle(multi, data->set.one_easy, &running_handles);
|
||||||
|
|
||||||
|
if(result == CURLM_OK)
|
||||||
|
/* get the socket(s) and check if the state has been changed since
|
||||||
|
last */
|
||||||
|
singlesocket(multi, data->set.one_easy);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check if there's one (more) expired timer to deal with! This function
|
||||||
|
extracts a matching node if there is one */
|
||||||
|
|
||||||
|
now = Curl_tvnow();
|
||||||
|
key = now.tv_sec; /* drop the usec part */
|
||||||
|
|
||||||
|
multi->timetree = Curl_splaygetbest(key, multi->timetree, &t);
|
||||||
|
if(t)
|
||||||
|
data = t->payload;
|
||||||
|
|
||||||
|
} while(t);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLMcode curl_multi_setopt(CURLM *multi_handle,
|
||||||
|
CURLMoption option, ...)
|
||||||
|
{
|
||||||
|
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||||
|
CURLMcode res = CURLM_OK;
|
||||||
|
va_list param;
|
||||||
|
|
||||||
|
if(!GOOD_MULTI_HANDLE(multi))
|
||||||
|
return CURLM_BAD_HANDLE;
|
||||||
|
|
||||||
|
va_start(param, option);
|
||||||
|
|
||||||
|
switch(option) {
|
||||||
|
case CURLMOPT_SOCKETFUNCTION:
|
||||||
|
multi->socket_cb = va_arg(param, curl_socket_callback);
|
||||||
|
break;
|
||||||
|
case CURLMOPT_SOCKETDATA:
|
||||||
|
multi->socket_userp = va_arg(param, void *);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
res = CURLM_UNKNOWN_OPTION;
|
||||||
|
}
|
||||||
|
va_end(param);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
printf("multi_socket(%d)\n", (int)s);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return multi_socket((struct Curl_multi *)multi_handle, FALSE, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLMcode curl_multi_socket_all(CURLM *multi_handle)
|
||||||
|
|
||||||
|
{
|
||||||
|
return multi_socket((struct Curl_multi *)multi_handle,
|
||||||
|
TRUE, CURL_SOCKET_BAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLMcode curl_multi_timeout(CURLM *multi_handle,
|
||||||
|
long *timeout_ms)
|
||||||
|
{
|
||||||
|
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||||
|
|
||||||
|
/* First, make some basic checks that the CURLM handle is a good handle */
|
||||||
|
if(!GOOD_MULTI_HANDLE(multi))
|
||||||
|
return CURLM_BAD_HANDLE;
|
||||||
|
|
||||||
|
if(multi->timetree) {
|
||||||
|
/* we have a tree of expire times */
|
||||||
|
struct timeval now = Curl_tvnow();
|
||||||
|
|
||||||
|
/* splay the lowest to the bottom */
|
||||||
|
multi->timetree = Curl_splay(0, multi->timetree);
|
||||||
|
|
||||||
|
/* At least currently, the splay key is a time_t for the expire time */
|
||||||
|
*timeout_ms = (multi->timetree->key - now.tv_sec) * 1000 -
|
||||||
|
now.tv_usec/1000;
|
||||||
|
if(*timeout_ms < 0)
|
||||||
|
/* 0 means immediately */
|
||||||
|
*timeout_ms = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*timeout_ms = -1;
|
||||||
|
|
||||||
|
return CURLM_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* given a number of milliseconds from now to use to set the 'act before
|
||||||
|
this'-time for the transfer, to be extracted by curl_multi_timeout() */
|
||||||
|
void Curl_expire(struct SessionHandle *data, long milli)
|
||||||
|
{
|
||||||
|
struct Curl_multi *multi = data->multi;
|
||||||
|
struct timeval *nowp = &data->state.expiretime;
|
||||||
|
|
||||||
|
/* this is only interesting for multi-interface using libcurl, and only
|
||||||
|
while there is still a multi interface struct remaining! */
|
||||||
|
if(!multi)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(!milli) {
|
||||||
|
/* No timeout, clear the time data. */
|
||||||
|
if(nowp->tv_sec) {
|
||||||
|
/* Since this is an cleared time, we must remove the previous entry from
|
||||||
|
the splay tree */
|
||||||
|
multi->timetree = Curl_splayremovebyaddr(multi->timetree,
|
||||||
|
&data->state.timenode);
|
||||||
|
infof(data, "Expire cleared\n");
|
||||||
|
}
|
||||||
|
nowp->tv_sec = nowp->tv_usec = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
struct timeval set;
|
||||||
|
int rest;
|
||||||
|
|
||||||
|
set = Curl_tvnow();
|
||||||
|
set.tv_sec += milli/1000;
|
||||||
|
set.tv_usec += (milli%1000)*1000;
|
||||||
|
|
||||||
|
rest = (int)(set.tv_usec - 1000000);
|
||||||
|
if(rest > 0) {
|
||||||
|
/* bigger than a full microsec */
|
||||||
|
set.tv_sec++;
|
||||||
|
set.tv_usec -= 1000000;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nowp->tv_sec) {
|
||||||
|
/* compare if the new time is earlier, and only set it if so */
|
||||||
|
long diff = curlx_tvdiff(set, *nowp);
|
||||||
|
if(diff > 0)
|
||||||
|
/* the new expire time was later so we don't change this */
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Since this is an updated time, we must remove the previous entry from
|
||||||
|
the splay tree first and then re-add the new value */
|
||||||
|
multi->timetree = Curl_splayremovebyaddr(multi->timetree,
|
||||||
|
&data->state.timenode);
|
||||||
|
}
|
||||||
|
|
||||||
|
*nowp = set;
|
||||||
|
infof(data, "Expire at %ld / %ld (%ldms)\n",
|
||||||
|
(long)nowp->tv_sec, (long)nowp->tv_usec, milli);
|
||||||
|
|
||||||
|
data->state.timenode.payload = data;
|
||||||
|
multi->timetree = Curl_splayinsert((int)nowp->tv_sec,
|
||||||
|
multi->timetree,
|
||||||
|
&data->state.timenode);
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
Curl_splayprint(multi->timetree, 0, TRUE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -26,5 +26,19 @@
|
|||||||
/*
|
/*
|
||||||
* Prototypes for library-wide functions provided by multi.c
|
* Prototypes for library-wide functions provided by multi.c
|
||||||
*/
|
*/
|
||||||
|
void Curl_expire(struct SessionHandle *data, long milli);
|
||||||
|
|
||||||
void Curl_multi_rmeasy(void *multi, CURL *data);
|
void Curl_multi_rmeasy(void *multi, CURL *data);
|
||||||
|
|
||||||
|
/* the write bits start at bit 16 for the *getsock() bitmap */
|
||||||
|
#define GETSOCK_WRITEBITSTART 16
|
||||||
|
|
||||||
|
#define GETSOCK_BLANK 0 /* no bits set */
|
||||||
|
|
||||||
|
/* set the bit for the given sock number to make the bitmap for writable */
|
||||||
|
#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x)))
|
||||||
|
|
||||||
|
/* set the bit for the given sock number to make the bitmap for readable */
|
||||||
|
#define GETSOCK_READSOCK(x) (1 << (x))
|
||||||
|
|
||||||
#endif /* __MULTIIF_H */
|
#endif /* __MULTIIF_H */
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include "urldata.h"
|
#include "urldata.h"
|
||||||
#include "sendf.h"
|
#include "sendf.h"
|
||||||
|
#include "multiif.h"
|
||||||
#include "speedcheck.h"
|
#include "speedcheck.h"
|
||||||
|
|
||||||
void Curl_speedinit(struct SessionHandle *data)
|
void Curl_speedinit(struct SessionHandle *data)
|
||||||
@ -43,13 +44,13 @@ CURLcode Curl_speedcheck(struct SessionHandle *data,
|
|||||||
data->set.low_speed_time &&
|
data->set.low_speed_time &&
|
||||||
(Curl_tvlong(data->state.keeps_speed) != 0) &&
|
(Curl_tvlong(data->state.keeps_speed) != 0) &&
|
||||||
(data->progress.current_speed < data->set.low_speed_limit)) {
|
(data->progress.current_speed < data->set.low_speed_limit)) {
|
||||||
|
long howlong = Curl_tvdiff(now, data->state.keeps_speed);
|
||||||
|
|
||||||
/* We are now below the "low speed limit". If we are below it
|
/* We are now below the "low speed limit". If we are below it
|
||||||
for "low speed time" seconds we consider that enough reason
|
for "low speed time" seconds we consider that enough reason
|
||||||
to abort the download. */
|
to abort the download. */
|
||||||
|
|
||||||
if( (Curl_tvdiff(now, data->state.keeps_speed)/1000) >
|
if( (howlong/1000) > data->set.low_speed_time) {
|
||||||
data->set.low_speed_time) {
|
|
||||||
/* we have been this slow for long enough, now die */
|
/* we have been this slow for long enough, now die */
|
||||||
failf(data,
|
failf(data,
|
||||||
"Operation too slow. "
|
"Operation too slow. "
|
||||||
@ -58,6 +59,7 @@ CURLcode Curl_speedcheck(struct SessionHandle *data,
|
|||||||
data->set.low_speed_time);
|
data->set.low_speed_time);
|
||||||
return CURLE_OPERATION_TIMEOUTED;
|
return CURLE_OPERATION_TIMEOUTED;
|
||||||
}
|
}
|
||||||
|
Curl_expire(data, howlong);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* we keep up the required speed all right */
|
/* we keep up the required speed all right */
|
||||||
|
406
lib/splay.c
Normal file
406
lib/splay.c
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997 - 2006, 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.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "splay.h"
|
||||||
|
|
||||||
|
#define compare(i,j) ((i)-(j))
|
||||||
|
|
||||||
|
/* Set this to a key value that will *NEVER* appear otherwise */
|
||||||
|
#define KEY_NOTUSED -1
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Splay using the key i (which may or may not be in the tree.) The starting
|
||||||
|
* root is t.
|
||||||
|
*/
|
||||||
|
struct Curl_tree *Curl_splay(int i, struct Curl_tree *t)
|
||||||
|
{
|
||||||
|
struct Curl_tree N, *l, *r, *y;
|
||||||
|
int comp;
|
||||||
|
|
||||||
|
if (t == NULL)
|
||||||
|
return t;
|
||||||
|
N.smaller = N.larger = NULL;
|
||||||
|
l = r = &N;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
comp = compare(i, t->key);
|
||||||
|
if (comp < 0) {
|
||||||
|
if (t->smaller == NULL)
|
||||||
|
break;
|
||||||
|
if (compare(i, t->smaller->key) < 0) {
|
||||||
|
y = t->smaller; /* rotate smaller */
|
||||||
|
t->smaller = y->larger;
|
||||||
|
y->larger = t;
|
||||||
|
t = y;
|
||||||
|
if (t->smaller == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
r->smaller = t; /* link smaller */
|
||||||
|
r = t;
|
||||||
|
t = t->smaller;
|
||||||
|
}
|
||||||
|
else if (comp > 0) {
|
||||||
|
if (t->larger == NULL)
|
||||||
|
break;
|
||||||
|
if (compare(i, t->larger->key) > 0) {
|
||||||
|
y = t->larger; /* rotate larger */
|
||||||
|
t->larger = y->smaller;
|
||||||
|
y->smaller = t;
|
||||||
|
t = y;
|
||||||
|
if (t->larger == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l->larger = t; /* link larger */
|
||||||
|
l = t;
|
||||||
|
t = t->larger;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
l->larger = r->smaller = NULL;
|
||||||
|
|
||||||
|
l->larger = t->smaller; /* assemble */
|
||||||
|
r->smaller = t->larger;
|
||||||
|
t->smaller = N.larger;
|
||||||
|
t->larger = N.smaller;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Insert key i into the tree t. Return a pointer to the resulting tree or
|
||||||
|
NULL if something went wrong. */
|
||||||
|
struct Curl_tree *Curl_splayinsert(int i, struct Curl_tree *t,
|
||||||
|
struct Curl_tree *area)
|
||||||
|
{
|
||||||
|
if (area == NULL)
|
||||||
|
return t;
|
||||||
|
|
||||||
|
if (t != NULL) {
|
||||||
|
t = Curl_splay(i,t);
|
||||||
|
if (compare(i, t->key)==0) {
|
||||||
|
/* it already exists one of this size */
|
||||||
|
|
||||||
|
area->same = t;
|
||||||
|
area->key = i;
|
||||||
|
area->smaller = t->smaller;
|
||||||
|
area->larger = t->larger;
|
||||||
|
|
||||||
|
t->smaller = area;
|
||||||
|
t->key = KEY_NOTUSED;
|
||||||
|
|
||||||
|
return area; /* new root node */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t == NULL) {
|
||||||
|
area->smaller = area->larger = NULL;
|
||||||
|
}
|
||||||
|
else if (compare(i, t->key) < 0) {
|
||||||
|
area->smaller = t->smaller;
|
||||||
|
area->larger = t;
|
||||||
|
t->smaller = NULL;
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
area->larger = t->larger;
|
||||||
|
area->smaller = t;
|
||||||
|
t->larger = NULL;
|
||||||
|
}
|
||||||
|
area->key = i;
|
||||||
|
|
||||||
|
area->same = NULL; /* no identical node (yet) */
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deletes 'i' from the tree if it's there (with an exact match). Returns a
|
||||||
|
pointer to the resulting tree. */
|
||||||
|
struct Curl_tree *Curl_splayremove(int i, struct Curl_tree *t,
|
||||||
|
struct Curl_tree **removed)
|
||||||
|
{
|
||||||
|
struct Curl_tree *x;
|
||||||
|
|
||||||
|
if (t==NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
t = Curl_splay(i,t);
|
||||||
|
if (compare(i, t->key) == 0) { /* found it */
|
||||||
|
|
||||||
|
/* FIRST! Check if there is a list with identical sizes */
|
||||||
|
if((x = t->same)) {
|
||||||
|
/* there is, pick one from the list */
|
||||||
|
|
||||||
|
/* 'x' is the new root node */
|
||||||
|
|
||||||
|
x->key = t->key;
|
||||||
|
x->larger = t->larger;
|
||||||
|
x->smaller = t->smaller;
|
||||||
|
|
||||||
|
*removed = t;
|
||||||
|
return x; /* new root */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->smaller == NULL) {
|
||||||
|
x = t->larger;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = Curl_splay(i, t->smaller);
|
||||||
|
x->larger = t->larger;
|
||||||
|
}
|
||||||
|
*removed = t;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*removed = NULL; /* no match */
|
||||||
|
return t; /* It wasn't there */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finds and deletes the best-fit node from the tree. Return a pointer to the
|
||||||
|
resulting tree. best-fit means the node with the given or lower number */
|
||||||
|
struct Curl_tree *Curl_splaygetbest(int i, struct Curl_tree *t,
|
||||||
|
struct Curl_tree **removed)
|
||||||
|
{
|
||||||
|
struct Curl_tree *x;
|
||||||
|
|
||||||
|
if (!t) {
|
||||||
|
*removed = NULL; /* none removed since there was no root */
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = Curl_splay(i,t);
|
||||||
|
if(compare(i, t->key) < 0) {
|
||||||
|
/* too big node, try the smaller chain */
|
||||||
|
if(t->smaller)
|
||||||
|
t=Curl_splay(t->smaller->key, t);
|
||||||
|
else {
|
||||||
|
/* fail */
|
||||||
|
*removed = NULL;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compare(i, t->key) >= 0) { /* found it */
|
||||||
|
/* FIRST! Check if there is a list with identical sizes */
|
||||||
|
x = t->same;
|
||||||
|
if(x) {
|
||||||
|
/* there is, pick one from the list */
|
||||||
|
|
||||||
|
/* 'x' is the new root node */
|
||||||
|
|
||||||
|
x->key = t->key;
|
||||||
|
x->larger = t->larger;
|
||||||
|
x->smaller = t->smaller;
|
||||||
|
|
||||||
|
*removed = t;
|
||||||
|
return x; /* new root */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->smaller == NULL) {
|
||||||
|
x = t->larger;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x = Curl_splay(i, t->smaller);
|
||||||
|
x->larger = t->larger;
|
||||||
|
}
|
||||||
|
*removed = t;
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*removed = NULL; /* no match */
|
||||||
|
return t; /* It wasn't there */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Deletes the node we point out from the tree if it's there. Return a pointer
|
||||||
|
to the resulting tree. */
|
||||||
|
struct Curl_tree *Curl_splayremovebyaddr(struct Curl_tree *t,
|
||||||
|
struct Curl_tree *remove)
|
||||||
|
{
|
||||||
|
struct Curl_tree *x;
|
||||||
|
|
||||||
|
if (!t || !remove)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if(KEY_NOTUSED == remove->key) {
|
||||||
|
/* just unlink ourselves nice and quickly: */
|
||||||
|
remove->smaller->same = remove->same;
|
||||||
|
if(remove->same)
|
||||||
|
remove->same->smaller = remove->smaller;
|
||||||
|
/* voila, we're done! */
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
t = Curl_splay(remove->key, t);
|
||||||
|
|
||||||
|
/* Check if there is a list with identical sizes */
|
||||||
|
|
||||||
|
x = t->same;
|
||||||
|
if(x) {
|
||||||
|
/* 'x' is the new root node */
|
||||||
|
|
||||||
|
x->key = t->key;
|
||||||
|
x->larger = t->larger;
|
||||||
|
x->smaller = t->smaller;
|
||||||
|
|
||||||
|
return x; /* new root */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the actualy root node: */
|
||||||
|
if (t->smaller == NULL)
|
||||||
|
x = t->larger;
|
||||||
|
else {
|
||||||
|
x = Curl_splay(remove->key, t->smaller);
|
||||||
|
x->larger = t->larger;
|
||||||
|
}
|
||||||
|
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CURLDEBUG
|
||||||
|
|
||||||
|
int Curl_splayprint(struct Curl_tree * t, int d, char output)
|
||||||
|
{
|
||||||
|
int distance=0;
|
||||||
|
struct Curl_tree *node;
|
||||||
|
int i;
|
||||||
|
if (t == NULL)
|
||||||
|
return 0;
|
||||||
|
distance += Curl_splayprint(t->larger, d+1, output);
|
||||||
|
for (i=0; i<d; i++)
|
||||||
|
if(output)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
if(output) {
|
||||||
|
printf("%d[%d]", t->key, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(node = t->same; node; node = node->same) {
|
||||||
|
distance += i; /* this has the same "virtual" distance */
|
||||||
|
|
||||||
|
if(output)
|
||||||
|
printf(" [+]");
|
||||||
|
}
|
||||||
|
if(output)
|
||||||
|
puts("");
|
||||||
|
|
||||||
|
distance += i;
|
||||||
|
|
||||||
|
distance += Curl_splayprint(t->smaller, d+1, output);
|
||||||
|
|
||||||
|
return distance;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_SPLAY
|
||||||
|
|
||||||
|
/*#define TEST2 */
|
||||||
|
#define MAX 50
|
||||||
|
#define OUTPUT 0 /* 1 enables, 0 disables */
|
||||||
|
|
||||||
|
/* A sample use of these functions. Start with the empty tree, insert some
|
||||||
|
stuff into it, and then delete it */
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct Curl_tree *root, *t;
|
||||||
|
void *ptrs[MAX];
|
||||||
|
|
||||||
|
long sizes[]={
|
||||||
|
50, 60, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200, 300,
|
||||||
|
220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120, 200,
|
||||||
|
300, 220, 80, 90, 50, 100, 60, 200, 120, 300, 400, 200, 256, 122, 60, 120,
|
||||||
|
200, 300, 220, 80, 90};
|
||||||
|
int i;
|
||||||
|
root = NULL; /* the empty tree */
|
||||||
|
|
||||||
|
for (i = 0; i < MAX; i++) {
|
||||||
|
ptrs[i] = t = (struct Curl_tree *)malloc(sizeof(struct Curl_tree));
|
||||||
|
if(!t) {
|
||||||
|
puts("out of memory!");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#ifdef TEST2
|
||||||
|
root = Curl_splayinsert(sizes[i], root, t);
|
||||||
|
#else
|
||||||
|
root = Curl_splayinsert((541*i)&1023, root, t);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
puts("Result:");
|
||||||
|
printtree(root, 0, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
for (i=0; root; i+=30) {
|
||||||
|
Curl_splayprint(root, 0, 1);
|
||||||
|
do {
|
||||||
|
root = Curl_splaygetbest(i, root, &t);
|
||||||
|
if(t)
|
||||||
|
printf("bestfit %d became %d\n", i, t->key);
|
||||||
|
else
|
||||||
|
printf("bestfit %d failed!\n", i);
|
||||||
|
} while(t && root);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if 0
|
||||||
|
for (i = 0; i < MAX; i++) {
|
||||||
|
printf("remove pointer %d size %d\n", i, sizes[i]);
|
||||||
|
root = removebyaddr(root, (struct Curl_tree *)ptrs[i]);
|
||||||
|
Curl_splayprint(root, 0, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifdef WEIGHT
|
||||||
|
for (i = -1; i<=root->weight; i++) {
|
||||||
|
t = find_rank(i, root);
|
||||||
|
if (t == NULL) {
|
||||||
|
printf("could not find a node of rank %d.\n", i);
|
||||||
|
} else {
|
||||||
|
printf("%d is of rank %d\n", t->key, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#ifdef TEST2
|
||||||
|
for (i = 0; i < MAX; i++) {
|
||||||
|
printf("remove size %d\n", sizes[i]);
|
||||||
|
root = Curl_splayremove(sizes[i], root, &t);
|
||||||
|
free(t);
|
||||||
|
Curl_splayprint(root, 0, 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* TEST_SPLAY */
|
50
lib/splay.h
Normal file
50
lib/splay.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#ifndef __SPLAY_H
|
||||||
|
#define __SPLAY_H
|
||||||
|
/***************************************************************************
|
||||||
|
* _ _ ____ _
|
||||||
|
* Project ___| | | | _ \| |
|
||||||
|
* / __| | | | |_) | |
|
||||||
|
* | (__| |_| | _ <| |___
|
||||||
|
* \___|\___/|_| \_\_____|
|
||||||
|
*
|
||||||
|
* Copyright (C) 1997 - 2006, 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.
|
||||||
|
*
|
||||||
|
* $Id$
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
struct Curl_tree {
|
||||||
|
struct Curl_tree *smaller; /* smaller node */
|
||||||
|
struct Curl_tree *larger; /* larger node */
|
||||||
|
struct Curl_tree *same; /* points to a node with identical key */
|
||||||
|
int key; /* the "sort" key */
|
||||||
|
void *payload; /* data the splay code doesn't care about */
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Curl_tree *Curl_splay(int i, struct Curl_tree *t);
|
||||||
|
struct Curl_tree *Curl_splayinsert(int key, struct Curl_tree *t,
|
||||||
|
struct Curl_tree *new);
|
||||||
|
struct Curl_tree *Curl_splayremove(int key, struct Curl_tree *t,
|
||||||
|
struct Curl_tree **removed);
|
||||||
|
struct Curl_tree *Curl_splaygetbest(int key, struct Curl_tree *t,
|
||||||
|
struct Curl_tree **removed);
|
||||||
|
struct Curl_tree *Curl_splayremovebyaddr(struct Curl_tree *t,
|
||||||
|
struct Curl_tree *remove);
|
||||||
|
|
||||||
|
#ifdef CURLDEBUG
|
||||||
|
int Curl_splayprint(struct Curl_tree * t, int d, char output);
|
||||||
|
#else
|
||||||
|
#define Curl_splayprint(x,y,z)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -329,6 +329,12 @@ curl_multi_strerror(CURLMcode error)
|
|||||||
case CURLM_INTERNAL_ERROR:
|
case CURLM_INTERNAL_ERROR:
|
||||||
return "internal error";
|
return "internal error";
|
||||||
|
|
||||||
|
case CURLM_BAD_SOCKET:
|
||||||
|
return "invalid socket argument";
|
||||||
|
|
||||||
|
case CURLM_UNKNOWN_OPTION:
|
||||||
|
return "unknown option";
|
||||||
|
|
||||||
case CURLM_LAST:
|
case CURLM_LAST:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,7 @@
|
|||||||
#include "share.h"
|
#include "share.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "select.h"
|
#include "select.h"
|
||||||
|
#include "multiif.h"
|
||||||
#include "easyif.h" /* for Curl_convert_to_network prototype */
|
#include "easyif.h" /* for Curl_convert_to_network prototype */
|
||||||
|
|
||||||
#define _MPRINTF_REPLACE /* use our functions only */
|
#define _MPRINTF_REPLACE /* use our functions only */
|
||||||
@ -1522,34 +1523,42 @@ CURLcode Curl_readwrite_init(struct connectdata *conn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Curl_single_fdset() gets called by the multi interface code when the app
|
* Curl_single_getsock() gets called by the multi interface code when the app
|
||||||
* has requested to get the fd_sets for the current connection. This function
|
* has requested to get the sockets for the current connection. This function
|
||||||
* will then be called once for every connection that the multi interface
|
* will then be called once for every connection that the multi interface
|
||||||
* keeps track of. This function will only be called for connections that are
|
* keeps track of. This function will only be called for connections that are
|
||||||
* in the proper state to have this information available.
|
* in the proper state to have this information available.
|
||||||
*/
|
*/
|
||||||
void Curl_single_fdset(struct connectdata *conn,
|
int Curl_single_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *sock, /* points to numsocks number
|
||||||
fd_set *write_fd_set,
|
of sockets */
|
||||||
fd_set *exc_fd_set,
|
int numsocks)
|
||||||
int *max_fd)
|
|
||||||
{
|
{
|
||||||
*max_fd = -1; /* init */
|
int bitmap = GETSOCK_BLANK;
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
if(numsocks < 2)
|
||||||
|
/* simple check but we might need two slots */
|
||||||
|
return GETSOCK_BLANK;
|
||||||
|
|
||||||
if(conn->keep.keepon & KEEP_READ) {
|
if(conn->keep.keepon & KEEP_READ) {
|
||||||
FD_SET(conn->sockfd, read_fd_set);
|
bitmap |= GETSOCK_READSOCK(index);
|
||||||
*max_fd = (int)conn->sockfd;
|
sock[index] = conn->sockfd;
|
||||||
}
|
}
|
||||||
if(conn->keep.keepon & KEEP_WRITE) {
|
if(conn->keep.keepon & KEEP_WRITE) {
|
||||||
FD_SET(conn->writesockfd, write_fd_set);
|
|
||||||
|
|
||||||
/* since sockets are curl_socket_t nowadays, we typecast it to int here
|
if((conn->sockfd != conn->writesockfd) &&
|
||||||
to compare it nicely */
|
(conn->keep.keepon & KEEP_READ)) {
|
||||||
if((int)conn->writesockfd > *max_fd)
|
/* only if they are not the same socket and we had a readable one,
|
||||||
*max_fd = (int)conn->writesockfd;
|
we increase index */
|
||||||
|
index++;
|
||||||
|
sock[index] = conn->writesockfd;
|
||||||
}
|
}
|
||||||
/* we don't use exceptions, only touch that one to prevent compiler
|
|
||||||
warnings! */
|
bitmap |= GETSOCK_WRITESOCK(index);
|
||||||
*exc_fd_set = *exc_fd_set;
|
}
|
||||||
|
|
||||||
|
return bitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,11 +28,9 @@ CURLcode Curl_second_connect(struct connectdata *conn);
|
|||||||
CURLcode Curl_posttransfer(struct SessionHandle *data);
|
CURLcode Curl_posttransfer(struct SessionHandle *data);
|
||||||
CURLcode Curl_follow(struct SessionHandle *data, char *newurl, bool retry);
|
CURLcode Curl_follow(struct SessionHandle *data, char *newurl, bool retry);
|
||||||
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
|
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
|
||||||
void Curl_single_fdset(struct connectdata *conn,
|
int Curl_single_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks);
|
||||||
fd_set *exc_fd_set,
|
|
||||||
int *max_fd);
|
|
||||||
CURLcode Curl_readwrite_init(struct connectdata *conn);
|
CURLcode Curl_readwrite_init(struct connectdata *conn);
|
||||||
CURLcode Curl_readrewind(struct connectdata *conn);
|
CURLcode Curl_readrewind(struct connectdata *conn);
|
||||||
CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
|
CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
|
||||||
|
37
lib/url.c
37
lib/url.c
@ -1552,6 +1552,7 @@ CURLcode Curl_disconnect(struct connectdata *conn)
|
|||||||
NULL, Curl_scan_cache_used);
|
NULL, Curl_scan_cache_used);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Curl_expire(data, 0); /* shut off timers */
|
||||||
Curl_hostcache_prune(data); /* kill old DNS cache entries */
|
Curl_hostcache_prune(data); /* kill old DNS cache entries */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2318,26 +2319,22 @@ static void verboseconnect(struct connectdata *conn)
|
|||||||
conn->ip_addr_str, conn->port);
|
conn->ip_addr_str, conn->port);
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_protocol_fdset(struct connectdata *conn,
|
int Curl_protocol_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks)
|
||||||
int *max_fdp)
|
|
||||||
{
|
{
|
||||||
CURLcode res = CURLE_OK;
|
if(conn->curl_proto_getsock)
|
||||||
if(conn->curl_proto_fdset)
|
return conn->curl_proto_getsock(conn, socks, numsocks);
|
||||||
res = conn->curl_proto_fdset(conn, read_fd_set, write_fd_set, max_fdp);
|
return GETSOCK_BLANK;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLcode Curl_doing_fdset(struct connectdata *conn,
|
int Curl_doing_getsock(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks)
|
||||||
int *max_fdp)
|
|
||||||
{
|
{
|
||||||
CURLcode res = CURLE_OK;
|
if(conn && conn->curl_doing_getsock)
|
||||||
if(conn && conn->curl_doing_fdset)
|
return conn->curl_doing_getsock(conn, socks, numsocks);
|
||||||
res = conn->curl_doing_fdset(conn, read_fd_set, write_fd_set, max_fdp);
|
return GETSOCK_BLANK;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3034,7 +3031,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
conn->curl_done = Curl_http_done;
|
conn->curl_done = Curl_http_done;
|
||||||
conn->curl_connect = Curl_http_connect;
|
conn->curl_connect = Curl_http_connect;
|
||||||
conn->curl_connecting = Curl_https_connecting;
|
conn->curl_connecting = Curl_https_connecting;
|
||||||
conn->curl_proto_fdset = Curl_https_proto_fdset;
|
conn->curl_proto_getsock = Curl_https_getsock;
|
||||||
|
|
||||||
#else /* USE_SS */
|
#else /* USE_SS */
|
||||||
failf(data, LIBCURL_NAME
|
failf(data, LIBCURL_NAME
|
||||||
@ -3086,8 +3083,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
|
|||||||
conn->curl_connect = Curl_ftp_connect;
|
conn->curl_connect = Curl_ftp_connect;
|
||||||
conn->curl_connecting = Curl_ftp_multi_statemach;
|
conn->curl_connecting = Curl_ftp_multi_statemach;
|
||||||
conn->curl_doing = Curl_ftp_doing;
|
conn->curl_doing = Curl_ftp_doing;
|
||||||
conn->curl_proto_fdset = Curl_ftp_fdset;
|
conn->curl_proto_getsock = Curl_ftp_getsock;
|
||||||
conn->curl_doing_fdset = Curl_ftp_fdset;
|
conn->curl_doing_getsock = Curl_ftp_getsock;
|
||||||
conn->curl_disconnect = Curl_ftp_disconnect;
|
conn->curl_disconnect = Curl_ftp_disconnect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4027,6 +4024,8 @@ CURLcode Curl_done(struct connectdata **connp,
|
|||||||
struct connectdata *conn = *connp;
|
struct connectdata *conn = *connp;
|
||||||
struct SessionHandle *data=conn->data;
|
struct SessionHandle *data=conn->data;
|
||||||
|
|
||||||
|
Curl_expire(data, 0); /* stop timer */
|
||||||
|
|
||||||
if(conn->bits.done)
|
if(conn->bits.done)
|
||||||
return CURLE_OK; /* Curl_done() has already been called */
|
return CURLE_OK; /* Curl_done() has already been called */
|
||||||
|
|
||||||
|
12
lib/url.h
12
lib/url.h
@ -45,6 +45,16 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
|
|||||||
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
|
CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
|
||||||
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
|
CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
|
||||||
void Curl_safefree(void *ptr);
|
void Curl_safefree(void *ptr);
|
||||||
|
|
||||||
|
|
||||||
|
int Curl_protocol_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks);
|
||||||
|
int Curl_doing_getsock(struct connectdata *conn,
|
||||||
|
curl_socket_t *socks,
|
||||||
|
int numsocks);
|
||||||
|
|
||||||
|
#if 0
|
||||||
CURLcode Curl_protocol_fdset(struct connectdata *conn,
|
CURLcode Curl_protocol_fdset(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
fd_set *read_fd_set,
|
||||||
fd_set *write_fd_set,
|
fd_set *write_fd_set,
|
||||||
@ -54,3 +64,5 @@ CURLcode Curl_doing_fdset(struct connectdata *conn,
|
|||||||
fd_set *write_fd_set,
|
fd_set *write_fd_set,
|
||||||
int *max_fdp);
|
int *max_fdp);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -96,6 +96,7 @@
|
|||||||
#include "http_chunks.h" /* for the structs and enum stuff */
|
#include "http_chunks.h" /* for the structs and enum stuff */
|
||||||
#include "hostip.h"
|
#include "hostip.h"
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
#include "splay.h"
|
||||||
|
|
||||||
#ifdef HAVE_GSSAPI
|
#ifdef HAVE_GSSAPI
|
||||||
# ifdef HAVE_GSSGNU
|
# ifdef HAVE_GSSGNU
|
||||||
@ -657,17 +658,15 @@ struct connectdata {
|
|||||||
|
|
||||||
/* Called from the multi interface during the PROTOCONNECT phase, and it
|
/* Called from the multi interface during the PROTOCONNECT phase, and it
|
||||||
should then return a proper fd set */
|
should then return a proper fd set */
|
||||||
CURLcode (*curl_proto_fdset)(struct connectdata *conn,
|
int (*curl_proto_getsock)(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks);
|
||||||
int *max_fdp);
|
|
||||||
|
|
||||||
/* Called from the multi interface during the DOING phase, and it should
|
/* Called from the multi interface during the DOING phase, and it should
|
||||||
then return a proper fd set */
|
then return a proper fd set */
|
||||||
CURLcode (*curl_doing_fdset)(struct connectdata *conn,
|
int (*curl_doing_getsock)(struct connectdata *conn,
|
||||||
fd_set *read_fd_set,
|
curl_socket_t *socks,
|
||||||
fd_set *write_fd_set,
|
int numsocks);
|
||||||
int *max_fdp);
|
|
||||||
|
|
||||||
/* This function *MAY* be set to a protocol-dependent function that is run
|
/* This function *MAY* be set to a protocol-dependent function that is run
|
||||||
* by the curl_disconnect(), as a step in the disconnection.
|
* by the curl_disconnect(), as a step in the disconnection.
|
||||||
@ -932,10 +931,11 @@ struct UrlState {
|
|||||||
#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
|
#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
|
||||||
ENGINE *engine;
|
ENGINE *engine;
|
||||||
#endif /* USE_SSLEAY */
|
#endif /* USE_SSLEAY */
|
||||||
|
struct timeval expiretime; /* set this with Curl_expire() only */
|
||||||
|
struct Curl_tree timenode; /* for the splay stuff */
|
||||||
|
|
||||||
/* a place to store the most recenlty set FTP entrypath */
|
/* a place to store the most recenlty set FTP entrypath */
|
||||||
char *most_recent_ftp_entrypath;
|
char *most_recent_ftp_entrypath;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -968,6 +968,8 @@ struct DynamicStatic {
|
|||||||
* 'struct UrlState' instead. The only exceptions MUST note the changes in
|
* 'struct UrlState' instead. The only exceptions MUST note the changes in
|
||||||
* the 'DynamicStatic' struct.
|
* the 'DynamicStatic' struct.
|
||||||
*/
|
*/
|
||||||
|
struct Curl_one_easy; /* declared and used only in multi.c */
|
||||||
|
struct Curl_multi; /* declared and used only in multi.c */
|
||||||
|
|
||||||
struct UserDefined {
|
struct UserDefined {
|
||||||
FILE *err; /* the stderr user data goes here */
|
FILE *err; /* the stderr user data goes here */
|
||||||
@ -1071,6 +1073,12 @@ struct UserDefined {
|
|||||||
|
|
||||||
char *private_data; /* Private data */
|
char *private_data; /* Private data */
|
||||||
|
|
||||||
|
struct Curl_one_easy *one_easy; /* When adding an easy handle to a multi
|
||||||
|
handle, an internal 'Curl_one_easy'
|
||||||
|
struct is created and this is a pointer
|
||||||
|
to the particular struct associated with
|
||||||
|
this SessionHandle */
|
||||||
|
|
||||||
struct curl_slist *http200aliases; /* linked list of aliases for http200 */
|
struct curl_slist *http200aliases; /* linked list of aliases for http200 */
|
||||||
|
|
||||||
long ip_version;
|
long ip_version;
|
||||||
@ -1139,7 +1147,7 @@ struct UserDefined {
|
|||||||
|
|
||||||
struct SessionHandle {
|
struct SessionHandle {
|
||||||
struct curl_hash *hostcache;
|
struct curl_hash *hostcache;
|
||||||
void *multi; /* if non-NULL, points to the multi handle
|
struct Curl_multi *multi; /* if non-NULL, points to the multi handle
|
||||||
struct of which this "belongs" */
|
struct of which this "belongs" */
|
||||||
struct Curl_share *share; /* Share, handles global variable mutexing */
|
struct Curl_share *share; /* Share, handles global variable mutexing */
|
||||||
struct UserDefined set; /* values set by the libcurl user */
|
struct UserDefined set; /* values set by the libcurl user */
|
||||||
|
Loading…
Reference in New Issue
Block a user