mirror of
https://github.com/moparisthebest/curl
synced 2025-03-11 07:39:50 -04:00
curl_multi_socket() and curl_multi_socket_all() got modified prototypes: they
both now provide the number of running handles back to the calling function.
This commit is contained in:
parent
c033c4c71c
commit
01b2cf82ec
11
CHANGES
11
CHANGES
@ -6,6 +6,17 @@
|
|||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
|
|
||||||
|
Daniel (31 July 2006)
|
||||||
|
- *ARLERT* curl_multi_socket() and curl_multi_socket_all() got modified
|
||||||
|
prototypes: they both now provide the number of running handles back to the
|
||||||
|
calling function. It makes the functions resemble the good old
|
||||||
|
curl_multi_perform() more and provides a nice way to know when the multi
|
||||||
|
handle goes empty.
|
||||||
|
|
||||||
|
ALERT2: don't use the curl_multi_socket*() functionality in anything
|
||||||
|
production-like until I say it's somewhat settled, as I suspect there might
|
||||||
|
be some further API changes before I'm done...
|
||||||
|
|
||||||
Daniel (28 July 2006)
|
Daniel (28 July 2006)
|
||||||
- Yves Lejeune fixed so that replacing Content-Type: when doing multipart
|
- Yves Lejeune fixed so that replacing Content-Type: when doing multipart
|
||||||
formposts work exactly the way you want it (and the way you'd assume it
|
formposts work exactly the way you want it (and the way you'd assume it
|
||||||
|
@ -289,3 +289,12 @@ July 9, 2006
|
|||||||
|
|
||||||
The set hashp pointer will then be passed on to the callback in upcoming
|
The set hashp pointer will then be passed on to the callback in upcoming
|
||||||
calls when this same socket is used (in the brand new 'socketp' argument).
|
calls when this same socket is used (in the brand new 'socketp' argument).
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
July 30, 2006
|
||||||
|
|
||||||
|
Shockingly stupid (of me not having realized this before), but we really need
|
||||||
|
to add a 'running_handles' argument to the curl_multi_socket() and
|
||||||
|
curl_multi_socket_all() prototypes so that the caller can get to know when
|
||||||
|
all the transfers are actually done!
|
||||||
|
129
hiper/hipev.c
129
hiper/hipev.c
@ -71,9 +71,6 @@ struct connection {
|
|||||||
size_t dlcounter;
|
size_t dlcounter;
|
||||||
struct globalinfo *global;
|
struct globalinfo *global;
|
||||||
char error[CURL_ERROR_SIZE];
|
char error[CURL_ERROR_SIZE];
|
||||||
struct event ev[3]; /* maximum 3 events per handle NOTE: should this rather
|
|
||||||
be a define in a public curl header file or possibly
|
|
||||||
just documented somewhere or... ? */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fdinfo {
|
struct fdinfo {
|
||||||
@ -84,10 +81,27 @@ struct fdinfo {
|
|||||||
CURL *easy;
|
CURL *easy;
|
||||||
int action; /* as set by libcurl */
|
int action; /* as set by libcurl */
|
||||||
long timeout; /* as set by libcurl */
|
long timeout; /* as set by libcurl */
|
||||||
|
struct event ev; /* */
|
||||||
|
int evset; /* true if the 'ev' struct has been used in a event_set() call */
|
||||||
|
CURLMcode *multi; /* pointer to the multi handle */
|
||||||
|
int *running_handles; /* pointer to the running_handles counter */
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct fdinfo *allsocks;
|
static struct fdinfo *allsocks;
|
||||||
|
|
||||||
|
static int running_handles;
|
||||||
|
|
||||||
|
/* called from libevent on action on a particular socket ("event") */
|
||||||
|
static void eventcallback(int fd, short type, void *userp)
|
||||||
|
{
|
||||||
|
struct fdinfo *fdp = (struct fdinfo *)userp;
|
||||||
|
|
||||||
|
fprintf(stderr, "EVENT callback\n");
|
||||||
|
|
||||||
|
/* tell libcurl to deal with the transfer associated with this socket */
|
||||||
|
curl_multi_socket(fdp->multi, fd, fdp->running_handles);
|
||||||
|
}
|
||||||
|
|
||||||
static void remsock(struct fdinfo *f)
|
static void remsock(struct fdinfo *f)
|
||||||
{
|
{
|
||||||
if(!f)
|
if(!f)
|
||||||
@ -109,12 +123,29 @@ static void setsock(struct fdinfo *fdp, curl_socket_t s, CURL *easy,
|
|||||||
fdp->sockfd = s;
|
fdp->sockfd = s;
|
||||||
fdp->action = action;
|
fdp->action = action;
|
||||||
fdp->easy = easy;
|
fdp->easy = easy;
|
||||||
|
|
||||||
|
if(fdp->evset)
|
||||||
|
/* first remove the existing event if the old setup was used */
|
||||||
|
event_del(&fdp->ev);
|
||||||
|
|
||||||
|
/* now use and add the current socket setup */
|
||||||
|
event_set(&fdp->ev, fdp->sockfd,
|
||||||
|
(action&CURL_POLL_IN?EV_READ:0)|
|
||||||
|
(action&CURL_POLL_OUT?EV_WRITE:0),
|
||||||
|
eventcallback, fdp);
|
||||||
|
|
||||||
|
fdp->evset=1;
|
||||||
|
|
||||||
|
fprintf(stderr, "event_add() for fd %d\n", s);
|
||||||
|
event_add(&fdp->ev, NULL); /* no timeout */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addsock(curl_socket_t s, CURL *easy, int action, CURLM *multi)
|
static void addsock(curl_socket_t s, CURL *easy, int action, CURLM *multi)
|
||||||
{
|
{
|
||||||
struct fdinfo *fdp = calloc(sizeof(struct fdinfo), 1);
|
struct fdinfo *fdp = calloc(sizeof(struct fdinfo), 1);
|
||||||
|
|
||||||
|
fdp->multi = multi;
|
||||||
|
fdp->running_handles = &running_handles;
|
||||||
setsock(fdp, s, easy, action);
|
setsock(fdp, s, easy, action);
|
||||||
|
|
||||||
if(allsocks) {
|
if(allsocks) {
|
||||||
@ -189,7 +220,7 @@ static int socket_callback(CURL *easy, /* easy handle */
|
|||||||
{
|
{
|
||||||
struct fdinfo *fdp = (struct fdinfo *)socketp;
|
struct fdinfo *fdp = (struct fdinfo *)socketp;
|
||||||
|
|
||||||
printf("socket %d easy %p what %d\n", s, easy, what);
|
fprintf(stderr, "socket %d easy %p what %d\n", s, easy, what);
|
||||||
|
|
||||||
if(what == CURL_POLL_REMOVE)
|
if(what == CURL_POLL_REMOVE)
|
||||||
remsock(fdp);
|
remsock(fdp);
|
||||||
@ -219,7 +250,7 @@ writecallback(void *ptr, size_t size, size_t nmemb, void *data)
|
|||||||
c->dlcounter += realsize;
|
c->dlcounter += realsize;
|
||||||
c->global->dlcounter += realsize;
|
c->global->dlcounter += realsize;
|
||||||
|
|
||||||
#if 0
|
#if 1
|
||||||
printf("%02d: %d, total %d\n",
|
printf("%02d: %d, total %d\n",
|
||||||
c->id, c->dlcounter, c->global->dlcounter);
|
c->id, c->dlcounter, c->global->dlcounter);
|
||||||
#endif
|
#endif
|
||||||
@ -360,6 +391,7 @@ int main(int argc, char **argv)
|
|||||||
int selectmaxamount;
|
int selectmaxamount;
|
||||||
struct fdinfo *fdp;
|
struct fdinfo *fdp;
|
||||||
char act;
|
char act;
|
||||||
|
long timeout_ms;
|
||||||
|
|
||||||
memset(&info, 0, sizeof(struct globalinfo));
|
memset(&info, 0, sizeof(struct globalinfo));
|
||||||
|
|
||||||
@ -431,81 +463,40 @@ int main(int argc, char **argv)
|
|||||||
curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, multi_handle);
|
curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, multi_handle);
|
||||||
|
|
||||||
/* we start the action by calling *socket() right away */
|
/* we start the action by calling *socket() right away */
|
||||||
while(CURLM_CALL_MULTI_PERFORM == curl_multi_socket_all(multi_handle));
|
while(CURLM_CALL_MULTI_PERFORM == curl_multi_socket_all(multi_handle,
|
||||||
|
&running_handles));
|
||||||
|
|
||||||
printf("Starting timer, expects to run for %ldus\n", RUN_FOR_THIS_LONG);
|
/* event_dispatch() isn't good enough for us, since we need a global timeout
|
||||||
timer_start();
|
to occur after a given time of inactivity
|
||||||
timer_pause();
|
*/
|
||||||
|
|
||||||
while(1) {
|
/* get the timeout value from libcurl */
|
||||||
|
curl_multi_timeout(multi_handle, &timeout_ms);
|
||||||
|
|
||||||
|
while(running_handles) {
|
||||||
struct timeval timeout;
|
struct timeval timeout;
|
||||||
int rc; /* select() return code */
|
|
||||||
long timeout_ms;
|
|
||||||
|
|
||||||
fd2_set fdread;
|
/* convert ms to timeval */
|
||||||
fd2_set fdwrite;
|
|
||||||
int maxfd;
|
|
||||||
|
|
||||||
curl_multi_timeout(multi_handle, &timeout_ms);
|
|
||||||
|
|
||||||
/* set timeout to wait */
|
|
||||||
timeout.tv_sec = timeout_ms/1000;
|
timeout.tv_sec = timeout_ms/1000;
|
||||||
timeout.tv_usec = (timeout_ms%1000)*1000;
|
timeout.tv_usec = (timeout_ms%1000)*1000;
|
||||||
|
|
||||||
/* convert file descriptors from the transfers to fd_sets */
|
event_loopexit(&timeout);
|
||||||
fdinfo2fdset(&fdread, &fdwrite, &maxfd);
|
|
||||||
|
|
||||||
selects++;
|
/* The event_loopexit() function may have taken a while and it may or may
|
||||||
rc = select(maxfd+1,
|
not have invoked libcurl calls during that time. During those calls,
|
||||||
(fd_set *)&fdread,
|
the timeout situation might very well have changed, so we check the
|
||||||
(fd_set *)&fdwrite,
|
timeout time again to see if we really need to call curl_multi_socket()
|
||||||
NULL, &timeout);
|
at this point! */
|
||||||
switch(rc) {
|
|
||||||
case -1:
|
|
||||||
/* select error */
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
timeouts++;
|
|
||||||
curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
/* get the timeout value from libcurl */
|
||||||
/* timeout or readable/writable sockets */
|
curl_multi_timeout(multi_handle, &timeout_ms);
|
||||||
|
|
||||||
for(i=0, fdp = allsocks; fdp; fdp = fdp->next) {
|
if(timeout_ms <= 0) {
|
||||||
act = 0;
|
/* no time left */
|
||||||
if((fdp->action & CURL_POLL_IN) &&
|
curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT, &running_handles);
|
||||||
FD_ISSET(fdp->sockfd, &fdread)) {
|
|
||||||
act |= CURL_POLL_IN;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
if((fdp->action & CURL_POLL_OUT) &&
|
|
||||||
FD_ISSET(fdp->sockfd, &fdwrite)) {
|
|
||||||
act |= CURL_POLL_OUT;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(act) {
|
/* and get the new timeout value again */
|
||||||
multi_socket++;
|
curl_multi_timeout(multi_handle, &timeout_ms);
|
||||||
timer_continue();
|
|
||||||
if(act & CURL_POLL_OUT)
|
|
||||||
act--;
|
|
||||||
curl_multi_socket(multi_handle, fdp->sockfd);
|
|
||||||
timer_pause();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
performselect += rc;
|
|
||||||
if(rc > topselect)
|
|
||||||
topselect = rc;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
timer_total(); /* calculate the total time spent so far */
|
|
||||||
|
|
||||||
if(total > RUN_FOR_THIS_LONG) {
|
|
||||||
printf("Stopped after %ldus\n", total);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,9 +266,11 @@ typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
|
|||||||
void *socketp); /* private socket
|
void *socketp); /* private socket
|
||||||
pointer */
|
pointer */
|
||||||
|
|
||||||
CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s);
|
CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
|
||||||
|
int *running_handles);
|
||||||
|
|
||||||
CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle);
|
CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
|
||||||
|
int *running_handles);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Name: curl_multi_timeout()
|
* Name: curl_multi_timeout()
|
||||||
|
40
lib/multi.c
40
lib/multi.c
@ -1123,6 +1123,15 @@ static void singlesocket(struct Curl_multi *multi,
|
|||||||
action |= CURL_POLL_OUT;
|
action |= CURL_POLL_OUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Update the sockhash accordingly BEFORE the callback of not a removal,
|
||||||
|
in case the callback wants to use curl_multi_assign(), but do the
|
||||||
|
removal AFTER the callback for the very same reason (but then to be
|
||||||
|
able to pass the correct entry->socketp) */
|
||||||
|
|
||||||
|
if(action != CURL_POLL_REMOVE)
|
||||||
|
/* make sure this socket is present in the hash for this handle */
|
||||||
|
sh_addentry(multi->sockhash, s, easy->easy_handle);
|
||||||
|
|
||||||
/* call the callback with this new info */
|
/* call the callback with this new info */
|
||||||
if(multi->socket_cb) {
|
if(multi->socket_cb) {
|
||||||
struct Curl_sh_entry *entry =
|
struct Curl_sh_entry *entry =
|
||||||
@ -1132,16 +1141,13 @@ static void singlesocket(struct Curl_multi *multi,
|
|||||||
s,
|
s,
|
||||||
action,
|
action,
|
||||||
multi->socket_userp,
|
multi->socket_userp,
|
||||||
entry->socketp);
|
entry ? entry->socketp : NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update the sockhash accordingly */
|
|
||||||
if(action == CURL_POLL_REMOVE)
|
if(action == CURL_POLL_REMOVE)
|
||||||
/* remove from hash for this easy handle */
|
/* remove from hash for this easy handle */
|
||||||
sh_delentry(multi->sockhash, s);
|
sh_delentry(multi->sockhash, s);
|
||||||
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 */
|
/* copy the current state to the storage area */
|
||||||
memcpy(&easy->sockstate, ¤t, sizeof(struct socketstate));
|
memcpy(&easy->sockstate, ¤t, sizeof(struct socketstate));
|
||||||
@ -1154,16 +1160,16 @@ static void singlesocket(struct Curl_multi *multi,
|
|||||||
|
|
||||||
static CURLMcode multi_socket(struct Curl_multi *multi,
|
static CURLMcode multi_socket(struct Curl_multi *multi,
|
||||||
bool checkall,
|
bool checkall,
|
||||||
curl_socket_t s)
|
curl_socket_t s,
|
||||||
|
int *running_handles)
|
||||||
{
|
{
|
||||||
CURLMcode result = CURLM_OK;
|
CURLMcode result = CURLM_OK;
|
||||||
int running_handles;
|
|
||||||
struct SessionHandle *data = NULL;
|
struct SessionHandle *data = NULL;
|
||||||
struct Curl_tree *t;
|
struct Curl_tree *t;
|
||||||
|
|
||||||
if(checkall) {
|
if(checkall) {
|
||||||
struct Curl_one_easy *easyp;
|
struct Curl_one_easy *easyp;
|
||||||
result = curl_multi_perform(multi, &running_handles);
|
result = curl_multi_perform(multi, running_handles);
|
||||||
|
|
||||||
/* walk through each easy handle and do the socket state change magic
|
/* walk through each easy handle and do the socket state change magic
|
||||||
and callbacks */
|
and callbacks */
|
||||||
@ -1190,7 +1196,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
|
|||||||
|
|
||||||
data = entry->easy;
|
data = entry->easy;
|
||||||
|
|
||||||
result = multi_runsingle(multi, data->set.one_easy, &running_handles);
|
result = multi_runsingle(multi, data->set.one_easy, running_handles);
|
||||||
|
|
||||||
if(result == CURLM_OK)
|
if(result == CURLM_OK)
|
||||||
/* get the socket(s) and check if the state has been changed since
|
/* get the socket(s) and check if the state has been changed since
|
||||||
@ -1212,7 +1218,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
|
|||||||
|
|
||||||
/* the first loop lap 'data' can be NULL */
|
/* the first loop lap 'data' can be NULL */
|
||||||
if(data) {
|
if(data) {
|
||||||
result = multi_runsingle(multi, data->set.one_easy, &running_handles);
|
result = multi_runsingle(multi, data->set.one_easy, running_handles);
|
||||||
|
|
||||||
if(result == CURLM_OK)
|
if(result == CURLM_OK)
|
||||||
/* get the socket(s) and check if the state has been changed since
|
/* get the socket(s) and check if the state has been changed since
|
||||||
@ -1269,20 +1275,18 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s)
|
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
|
||||||
|
int *running_handles)
|
||||||
{
|
{
|
||||||
#if 0
|
return multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
|
||||||
printf("multi_socket(%d)\n", (int)s);
|
running_handles);
|
||||||
#endif
|
|
||||||
|
|
||||||
return multi_socket((struct Curl_multi *)multi_handle, FALSE, s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLMcode curl_multi_socket_all(CURLM *multi_handle)
|
CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
|
||||||
|
|
||||||
{
|
{
|
||||||
return multi_socket((struct Curl_multi *)multi_handle,
|
return multi_socket((struct Curl_multi *)multi_handle,
|
||||||
TRUE, CURL_SOCKET_BAD);
|
TRUE, CURL_SOCKET_BAD, running_handles);
|
||||||
}
|
}
|
||||||
|
|
||||||
CURLMcode curl_multi_timeout(CURLM *multi_handle,
|
CURLMcode curl_multi_timeout(CURLM *multi_handle,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user