Loading CHANGES +11 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,17 @@ 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) - 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 Loading hiper/STATUS +9 −0 Original line number Diff line number Diff line Loading @@ -289,3 +289,12 @@ July 9, 2006 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). --------------------------------------------------------------------------- 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! hiper/hipev.c +61 −70 Original line number Diff line number Diff line Loading @@ -71,9 +71,6 @@ struct connection { size_t dlcounter; struct globalinfo *global; 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 { Loading @@ -84,10 +81,27 @@ struct fdinfo { CURL *easy; int action; /* 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 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) { if(!f) Loading @@ -109,12 +123,29 @@ static void setsock(struct fdinfo *fdp, curl_socket_t s, CURL *easy, fdp->sockfd = s; fdp->action = action; 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) { struct fdinfo *fdp = calloc(sizeof(struct fdinfo), 1); fdp->multi = multi; fdp->running_handles = &running_handles; setsock(fdp, s, easy, action); if(allsocks) { Loading Loading @@ -189,7 +220,7 @@ static int socket_callback(CURL *easy, /* easy handle */ { 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) remsock(fdp); Loading Loading @@ -219,7 +250,7 @@ writecallback(void *ptr, size_t size, size_t nmemb, void *data) c->dlcounter += realsize; c->global->dlcounter += realsize; #if 0 #if 1 printf("%02d: %d, total %d\n", c->id, c->dlcounter, c->global->dlcounter); #endif Loading Loading @@ -360,6 +391,7 @@ int main(int argc, char **argv) int selectmaxamount; struct fdinfo *fdp; char act; long timeout_ms; memset(&info, 0, sizeof(struct globalinfo)); Loading Loading @@ -431,81 +463,40 @@ int main(int argc, char **argv) curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, multi_handle); /* 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); timer_start(); timer_pause(); while(1) { struct timeval timeout; int rc; /* select() return code */ long timeout_ms; fd2_set fdread; fd2_set fdwrite; int maxfd; /* event_dispatch() isn't good enough for us, since we need a global timeout to occur after a given time of inactivity */ /* get the timeout value from libcurl */ curl_multi_timeout(multi_handle, &timeout_ms); /* set timeout to wait */ while(running_handles) { struct timeval timeout; /* convert ms to timeval */ timeout.tv_sec = timeout_ms/1000; timeout.tv_usec = (timeout_ms%1000)*1000; /* convert file descriptors from the transfers to fd_sets */ fdinfo2fdset(&fdread, &fdwrite, &maxfd); selects++; rc = select(maxfd+1, (fd_set *)&fdread, (fd_set *)&fdwrite, NULL, &timeout); switch(rc) { case -1: /* select error */ break; case 0: timeouts++; curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT); break; default: /* timeout or readable/writable sockets */ for(i=0, fdp = allsocks; fdp; fdp = fdp->next) { act = 0; if((fdp->action & CURL_POLL_IN) && 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++; } event_loopexit(&timeout); if(act) { multi_socket++; timer_continue(); if(act & CURL_POLL_OUT) act--; curl_multi_socket(multi_handle, fdp->sockfd); timer_pause(); } } /* The event_loopexit() function may have taken a while and it may or may not have invoked libcurl calls during that time. During those calls, the timeout situation might very well have changed, so we check the timeout time again to see if we really need to call curl_multi_socket() at this point! */ performselect += rc; if(rc > topselect) topselect = rc; break; } /* get the timeout value from libcurl */ curl_multi_timeout(multi_handle, &timeout_ms); timer_total(); /* calculate the total time spent so far */ if(timeout_ms <= 0) { /* no time left */ curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT, &running_handles); if(total > RUN_FOR_THIS_LONG) { printf("Stopped after %ldus\n", total); break; /* and get the new timeout value again */ curl_multi_timeout(multi_handle, &timeout_ms); } } Loading include/curl/multi.h +4 −2 Original line number Diff line number Diff line Loading @@ -266,9 +266,11 @@ typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ void *socketp); /* private socket 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() Loading lib/multi.c +22 −18 Original line number Diff line number Diff line Loading @@ -1123,6 +1123,15 @@ static void singlesocket(struct Curl_multi *multi, 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 */ if(multi->socket_cb) { struct Curl_sh_entry *entry = Loading @@ -1132,16 +1141,13 @@ static void singlesocket(struct Curl_multi *multi, s, action, multi->socket_userp, entry->socketp); entry ? entry->socketp : NULL); } /* Update the sockhash accordingly */ if(action == CURL_POLL_REMOVE) /* remove from hash for this easy handle */ 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 */ memcpy(&easy->sockstate, ¤t, sizeof(struct socketstate)); Loading @@ -1154,16 +1160,16 @@ static void singlesocket(struct Curl_multi *multi, static CURLMcode multi_socket(struct Curl_multi *multi, bool checkall, curl_socket_t s) curl_socket_t s, int *running_handles) { 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); result = curl_multi_perform(multi, running_handles); /* walk through each easy handle and do the socket state change magic and callbacks */ Loading @@ -1190,7 +1196,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, 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) /* get the socket(s) and check if the state has been changed since Loading @@ -1212,7 +1218,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, /* the first loop lap 'data' can be NULL */ 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) /* get the socket(s) and check if the state has been changed since Loading Loading @@ -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 printf("multi_socket(%d)\n", (int)s); #endif return multi_socket((struct Curl_multi *)multi_handle, FALSE, s); return multi_socket((struct Curl_multi *)multi_handle, FALSE, s, running_handles); } 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, TRUE, CURL_SOCKET_BAD); TRUE, CURL_SOCKET_BAD, running_handles); } CURLMcode curl_multi_timeout(CURLM *multi_handle, Loading Loading
CHANGES +11 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,17 @@ 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) - 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 Loading
hiper/STATUS +9 −0 Original line number Diff line number Diff line Loading @@ -289,3 +289,12 @@ July 9, 2006 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). --------------------------------------------------------------------------- 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!
hiper/hipev.c +61 −70 Original line number Diff line number Diff line Loading @@ -71,9 +71,6 @@ struct connection { size_t dlcounter; struct globalinfo *global; 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 { Loading @@ -84,10 +81,27 @@ struct fdinfo { CURL *easy; int action; /* 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 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) { if(!f) Loading @@ -109,12 +123,29 @@ static void setsock(struct fdinfo *fdp, curl_socket_t s, CURL *easy, fdp->sockfd = s; fdp->action = action; 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) { struct fdinfo *fdp = calloc(sizeof(struct fdinfo), 1); fdp->multi = multi; fdp->running_handles = &running_handles; setsock(fdp, s, easy, action); if(allsocks) { Loading Loading @@ -189,7 +220,7 @@ static int socket_callback(CURL *easy, /* easy handle */ { 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) remsock(fdp); Loading Loading @@ -219,7 +250,7 @@ writecallback(void *ptr, size_t size, size_t nmemb, void *data) c->dlcounter += realsize; c->global->dlcounter += realsize; #if 0 #if 1 printf("%02d: %d, total %d\n", c->id, c->dlcounter, c->global->dlcounter); #endif Loading Loading @@ -360,6 +391,7 @@ int main(int argc, char **argv) int selectmaxamount; struct fdinfo *fdp; char act; long timeout_ms; memset(&info, 0, sizeof(struct globalinfo)); Loading Loading @@ -431,81 +463,40 @@ int main(int argc, char **argv) curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, multi_handle); /* 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); timer_start(); timer_pause(); while(1) { struct timeval timeout; int rc; /* select() return code */ long timeout_ms; fd2_set fdread; fd2_set fdwrite; int maxfd; /* event_dispatch() isn't good enough for us, since we need a global timeout to occur after a given time of inactivity */ /* get the timeout value from libcurl */ curl_multi_timeout(multi_handle, &timeout_ms); /* set timeout to wait */ while(running_handles) { struct timeval timeout; /* convert ms to timeval */ timeout.tv_sec = timeout_ms/1000; timeout.tv_usec = (timeout_ms%1000)*1000; /* convert file descriptors from the transfers to fd_sets */ fdinfo2fdset(&fdread, &fdwrite, &maxfd); selects++; rc = select(maxfd+1, (fd_set *)&fdread, (fd_set *)&fdwrite, NULL, &timeout); switch(rc) { case -1: /* select error */ break; case 0: timeouts++; curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT); break; default: /* timeout or readable/writable sockets */ for(i=0, fdp = allsocks; fdp; fdp = fdp->next) { act = 0; if((fdp->action & CURL_POLL_IN) && 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++; } event_loopexit(&timeout); if(act) { multi_socket++; timer_continue(); if(act & CURL_POLL_OUT) act--; curl_multi_socket(multi_handle, fdp->sockfd); timer_pause(); } } /* The event_loopexit() function may have taken a while and it may or may not have invoked libcurl calls during that time. During those calls, the timeout situation might very well have changed, so we check the timeout time again to see if we really need to call curl_multi_socket() at this point! */ performselect += rc; if(rc > topselect) topselect = rc; break; } /* get the timeout value from libcurl */ curl_multi_timeout(multi_handle, &timeout_ms); timer_total(); /* calculate the total time spent so far */ if(timeout_ms <= 0) { /* no time left */ curl_multi_socket(multi_handle, CURL_SOCKET_TIMEOUT, &running_handles); if(total > RUN_FOR_THIS_LONG) { printf("Stopped after %ldus\n", total); break; /* and get the new timeout value again */ curl_multi_timeout(multi_handle, &timeout_ms); } } Loading
include/curl/multi.h +4 −2 Original line number Diff line number Diff line Loading @@ -266,9 +266,11 @@ typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */ void *socketp); /* private socket 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() Loading
lib/multi.c +22 −18 Original line number Diff line number Diff line Loading @@ -1123,6 +1123,15 @@ static void singlesocket(struct Curl_multi *multi, 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 */ if(multi->socket_cb) { struct Curl_sh_entry *entry = Loading @@ -1132,16 +1141,13 @@ static void singlesocket(struct Curl_multi *multi, s, action, multi->socket_userp, entry->socketp); entry ? entry->socketp : NULL); } /* Update the sockhash accordingly */ if(action == CURL_POLL_REMOVE) /* remove from hash for this easy handle */ 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 */ memcpy(&easy->sockstate, ¤t, sizeof(struct socketstate)); Loading @@ -1154,16 +1160,16 @@ static void singlesocket(struct Curl_multi *multi, static CURLMcode multi_socket(struct Curl_multi *multi, bool checkall, curl_socket_t s) curl_socket_t s, int *running_handles) { 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); result = curl_multi_perform(multi, running_handles); /* walk through each easy handle and do the socket state change magic and callbacks */ Loading @@ -1190,7 +1196,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, 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) /* get the socket(s) and check if the state has been changed since Loading @@ -1212,7 +1218,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi, /* the first loop lap 'data' can be NULL */ 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) /* get the socket(s) and check if the state has been changed since Loading Loading @@ -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 printf("multi_socket(%d)\n", (int)s); #endif return multi_socket((struct Curl_multi *)multi_handle, FALSE, s); return multi_socket((struct Curl_multi *)multi_handle, FALSE, s, running_handles); } 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, TRUE, CURL_SOCKET_BAD); TRUE, CURL_SOCKET_BAD, running_handles); } CURLMcode curl_multi_timeout(CURLM *multi_handle, Loading