aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES11
-rw-r--r--hiper/STATUS9
-rw-r--r--hiper/hipev.c131
-rw-r--r--include/curl/multi.h6
-rw-r--r--lib/multi.c40
5 files changed, 107 insertions, 90 deletions
diff --git a/CHANGES b/CHANGES
index 3fcac9b36..66a810baf 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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
diff --git a/hiper/STATUS b/hiper/STATUS
index 6b3e511f4..918611b8f 100644
--- a/hiper/STATUS
+++ b/hiper/STATUS
@@ -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!
diff --git a/hiper/hipev.c b/hiper/hipev.c
index b5a015918..e99f9086a 100644
--- a/hiper/hipev.c
+++ b/hiper/hipev.c
@@ -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 {
@@ -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)
@@ -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) {
@@ -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);
@@ -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
@@ -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));
@@ -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));
-
- printf("Starting timer, expects to run for %ldus\n", RUN_FOR_THIS_LONG);
- timer_start();
- timer_pause();
+ while(CURLM_CALL_MULTI_PERFORM == curl_multi_socket_all(multi_handle,
+ &running_handles));
- while(1) {
- struct timeval timeout;
- int rc; /* select() return code */
- long timeout_ms;
+ /* event_dispatch() isn't good enough for us, since we need a global timeout
+ to occur after a given time of inactivity
+ */
- fd2_set fdread;
- fd2_set fdwrite;
- int maxfd;
+ /* get the timeout value from libcurl */
+ curl_multi_timeout(multi_handle, &timeout_ms);
- curl_multi_timeout(multi_handle, &timeout_ms);
+ while(running_handles) {
+ struct timeval timeout;
- /* set timeout to wait */
+ /* 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++;
- }
-
- if(act) {
- multi_socket++;
- timer_continue();
- if(act & CURL_POLL_OUT)
- act--;
- curl_multi_socket(multi_handle, fdp->sockfd);
- timer_pause();
- }
- }
+ event_loopexit(&timeout);
- performselect += rc;
- if(rc > topselect)
- topselect = rc;
- break;
- }
+ /* 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! */
+
+ /* 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);
}
}
diff --git a/include/curl/multi.h b/include/curl/multi.h
index eb62446df..3c8bb9e53 100644
--- a/include/curl/multi.h
+++ b/include/curl/multi.h
@@ -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()
diff --git a/lib/multi.c b/lib/multi.c
index 3296f09e5..7f553bda5 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -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 =
@@ -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, &current, sizeof(struct socketstate));
@@ -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 */
@@ -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
@@ -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
@@ -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,