1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-21 23:58:49 -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:
Daniel Stenberg 2006-04-10 15:00:53 +00:00
parent 5dc02d53c3
commit 686d90745b
21 changed files with 1609 additions and 545 deletions

View File

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

View File

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

View File

@ -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 */
FD_SET(sockfd, read_fd_set);
} }
if((int)sockfd > *max_fdp) /* read mode */
*max_fdp = (int)sockfd; return GETSOCK_READSOCK(0);
return CURLE_OK;
} }
/* This is called after the FTP_QUOTE state is passed. /* This is called after the FTP_QUOTE state is passed.

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

@ -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;
}
bitmap |= GETSOCK_WRITESOCK(index);
} }
/* we don't use exceptions, only touch that one to prevent compiler
warnings! */ return bitmap;
*exc_fd_set = *exc_fd_set;
} }

View File

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

View File

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

View File

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

View File

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