aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2006-10-12 08:36:47 +0000
committerDaniel Stenberg <daniel@haxx.se>2006-10-12 08:36:47 +0000
commitb61c06384ab88baf4b3231e84386c4a70126d888 (patch)
treeaac26b1242718b6093edcefd99c6e3e4b04cd52b
parente7742bfb7cc40d6b840fabc8632f9625cc2fc26f (diff)
Jeff Pohlmeyer has been working with the hiperfifo.c example source code,
and while doing so it became apparent that the current timeout system for the socket API really was a bit awkward since it become quite some work to be sure we have the correct timeout set. Jeff then provided the new CURLMOPT_TIMERFUNCTION that is yet another callback the app can set to get to know when the general timeout time changes and thus for an application like hiperfifo.c it makes everything a lot easier and nicer. There's a CURLMOPT_TIMERDATA option too of course in good old libcurl tradition.
-rw-r--r--CHANGES14
-rw-r--r--RELEASE-NOTES1
-rw-r--r--TODO-RELEASE6
-rw-r--r--docs/libcurl/curl_multi_setopt.345
-rw-r--r--include/curl/multi.h20
-rw-r--r--lib/multi.c80
6 files changed, 136 insertions, 30 deletions
diff --git a/CHANGES b/CHANGES
index f572e7ef5..7eabba8d4 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,20 @@
Changelog
+Daniel (12 October 2006)
+- Jeff Pohlmeyer has been working with the hiperfifo.c example source code,
+ and while doing so it became apparent that the current timeout system for
+ the socket API really was a bit awkward since it become quite some work to
+ be sure we have the correct timeout set.
+
+ Jeff then provided the new CURLMOPT_TIMERFUNCTION that is yet another
+ callback the app can set to get to know when the general timeout time
+ changes and thus for an application like hiperfifo.c it makes everything a
+ lot easier and nicer. There's a CURLMOPT_TIMERDATA option too of course in
+ good old libcurl tradition.
+
+ Jeff has also updated the hiperfifo.c example code to use this news.
+
Daniel (9 October 2006)
- Bogdan Nicula's second test case (posted Sun, 08 Oct 2006) converted to test
case 535 and it now runs fine. Again a problem with the pipelining code not
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index 950784f23..5b70767b9 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -11,6 +11,7 @@ Curl and libcurl 7.16.0
This release includes the following changes:
+ o Added CURLMOPT_TIMERFUNCTION
o The CURLOPT_SOURCE_* options are removed and so are the --3p* command line
options
o curl_multi_socket() and family are suitable to start using
diff --git a/TODO-RELEASE b/TODO-RELEASE
index 03ffa88be..7d0a1e38f 100644
--- a/TODO-RELEASE
+++ b/TODO-RELEASE
@@ -1,8 +1,6 @@
To get fixed in 7.16.0 (planned release: October 2006)
======================
-67 - Jeff Pohlmeyer's test case
+67 - Jeff Pohlmeyer's crashing pipelining test case
-68 - Dmitriy Sergeyev's test02.c and test03.c
-
-69 - \ No newline at end of file
+69 -
diff --git a/docs/libcurl/curl_multi_setopt.3 b/docs/libcurl/curl_multi_setopt.3
index 5279055ce..5ba81b952 100644
--- a/docs/libcurl/curl_multi_setopt.3
+++ b/docs/libcurl/curl_multi_setopt.3
@@ -1,6 +1,6 @@
.\" $Id$
.\"
-.TH curl_multi_setopt 3 "8 Jan 2006" "libcurl 7.16.0" "libcurl Manual"
+.TH curl_multi_setopt 3 "10 Oct 2006" "libcurl 7.16.0" "libcurl Manual"
.SH NAME
curl_multi_setopt \- set options for a curl multi handle
.SH SYNOPSIS
@@ -9,7 +9,7 @@ curl_multi_setopt \- set options for a curl multi handle
CURLMcode curl_multi_setopt(CURLM * multi_handle, CURLMoption option, param);
.SH DESCRIPTION
curl_multi_setopt() is used to tell a libcurl multi handle how to behave. By
-using the appropriate options to \fIcurl_multi_setopt\fP, you can change
+using the appropriate options to \fIcurl_multi_setopt(3)\fP, you can change
libcurl's behaviour when using that multi handle. All options are set with
the \fIoption\fP followed by the parameter \fIparam\fP. That parameter can be
a \fBlong\fP, a \fBfunction pointer\fP, an \fBobject pointer\fP or a
@@ -19,19 +19,20 @@ You can only set one option in each function call.
.SH OPTIONS
.IP CURLMOPT_SOCKETFUNCTION
-Pass a pointer to a function matching the curl_socket_callback prototype. The
-\fIcurl_multi_socket(3)\fP functions inform the application about updates in
-the socket (file descriptor) status by doing none, one or multiple calls to
-the curl_socket_callback given in the \fBparam\fP argument. They update the
-status with changes since the previous time a \fIcurl_multi_socket(3)\fP
-function was called. If the given callback pointer is NULL, no callback will
-be called. Set the callback's \fBuserp\fP argument with
-\fICURLMOPT_SOCKETDATA\fP. See \fIcurl_multi_socket(3)\fP for more callback
-details.
+Pass a pointer to a function matching the \fBcurl_socket_callback\fP
+prototype. The \fIcurl_multi_socket(3)\fP functions inform the application
+about updates in the socket (file descriptor) status by doing none, one or
+multiple calls to the curl_socket_callback given in the \fBparam\fP
+argument. They update the status with changes since the previous time a
+\fIcurl_multi_socket(3)\fP function was called. If the given callback pointer
+is NULL, no callback will be called. Set the callback's \fBuserp\fP argument
+with \fICURLMOPT_SOCKETDATA\fP. See \fIcurl_multi_socket(3)\fP for more
+callback details.
.IP CURLMOPT_SOCKETDATA
-Pass a pointer to whatever you want passed to the curl_socket_callback's forth
-argument, the userp pointer. This is not used by libcurl but only passed-thru
-as-is. Set the callback pointer with \fICURLMOPT_SOCKETFUNCTION\fP.
+Pass a pointer to whatever you want passed to the \fBcurl_socket_callback\fP's
+forth argument, the userp pointer. This is not used by libcurl but only
+passed-thru as-is. Set the callback pointer with
+\fICURLMOPT_SOCKETFUNCTION\fP.
.IP CURLMOPT_PIPELINING
Pass a long set to 1 to enable or 0 to disable. Enabling pipelining on a multi
handle will make it attempt to perform HTTP Pipelining as far as possible for
@@ -39,6 +40,22 @@ transfers using this handle. This means that if you add a second request that
can use an already existing connection, the second request will be \&"piped"
on the same connection rather than being executed in parallell. (Added in
7.16.0)
+.IP CURLMOPT_TIMERFUNCTION
+Pass a pointer to a function matching the \fBcurl_multi_timer_callback\fP
+prototype. This function will then be called when the timeout value
+changes. The timeout value is at what latest time the application should call
+one of the \&"performing" functions of the multi interface
+(\fIcurl_multi_socket(3)\fP, \fIcurl_multi_socket_all(3)\fP and
+\fIcurl_multi_perform(3)\fP) - to allow libcurl to keep timeouts and retries
+etc to work. Libcurl attempts to limit calling this only when the fixed future
+timeout time actually change. See also \fICURLMOPT_TIMERDATA\fP. This callback
+can be used instead of, or in addition to, \fIcurl_multi_timeout(3)\fP. (Added
+in 7.16.0)
+.IP CURLMOPT_TIMERDATA
+Pass a pointer to whatever you want passed to the
+\fBcurl_multi_timer_callback\fP's third argument, the userp pointer. This is
+not used by libcurl but only passed-thru as-is. Set the callback pointer with
+\fICURLMOPT_TIMERFUNCTION\fP. (Added in 7.16.0)
.SH RETURNS
The standard CURLMcode for multi interface error codes. Note that it returns a
CURLM_UNKNOWN_OPTION if you try setting an option that this version of libcurl
diff --git a/include/curl/multi.h b/include/curl/multi.h
index 23fe180d3..d2533728d 100644
--- a/include/curl/multi.h
+++ b/include/curl/multi.h
@@ -231,6 +231,20 @@ typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
pointer */
void *socketp); /* private socket
pointer */
+/*
+ * Name: curl_multi_timer_callback
+ *
+ * Desc: Called by libcurl whenever the library detects a change in the
+ * maximum number of milliseconds the app is allowed to wait before
+ * curl_multi_socket() or curl_multi_perform() must be called
+ * (to allow libcurl's timed events to take place).
+ *
+ * Returns: The callback should return zero.
+ */
+typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
+ long timeout_ms, /* see above */
+ void *userp); /* private callback
+ pointer */
CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
int *running_handles);
@@ -273,6 +287,12 @@ typedef enum {
/* set to 1 to enable pipelining for this multi handle */
CINIT(PIPELINING, LONG, 3),
+ /* This is the timer callback function pointer */
+ CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
+
+ /* This is the argument passed to the timer callback */
+ CINIT(TIMERDATA, OBJECTPOINT, 5),
+
CURLMOPT_LASTENTRY /* the last unused */
} CURLMoption;
diff --git a/lib/multi.c b/lib/multi.c
index e901bddfd..aaa80b228 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -166,6 +166,12 @@ struct Curl_multi {
/* list of easy handles kept around for doing nice connection closures */
struct closure *closure;
+
+ /* timer callback and user data pointer for the *socket() API */
+ curl_multi_timer_callback timer_cb;
+ void *timer_userp;
+ time_t timer_lastcall; /* the fixed time for the timeout for the previous
+ callback */
};
static bool multi_conn_using(struct Curl_multi *multi,
@@ -174,6 +180,7 @@ static void singlesocket(struct Curl_multi *multi,
struct Curl_one_easy *easy);
static void add_closure(struct Curl_multi *multi,
struct SessionHandle *data);
+static int update_timer(struct Curl_multi *multi);
/* always use this function to change state, to make debugging easier */
static void multistate(struct Curl_one_easy *easy, CURLMstate state)
@@ -460,6 +467,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* increase the alive-counter */
multi->num_alive++;
+ update_timer(multi);
return CURLM_OK;
}
@@ -610,6 +618,7 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
multi->num_easy--; /* one less to care about now */
+ update_timer(multi);
return CURLM_OK;
}
else
@@ -1342,6 +1351,8 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
*running_handles = multi->num_alive;
+ if ( CURLM_OK == returncode )
+ update_timer(multi);
return returncode;
}
@@ -1673,8 +1684,15 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
case CURLMOPT_PIPELINING:
multi->pipelining_enabled = (bool)(0 != va_arg(param, long));
break;
+ case CURLMOPT_TIMERFUNCTION:
+ multi->timer_cb = va_arg(param, curl_multi_timer_callback);
+ break;
+ case CURLMOPT_TIMERDATA:
+ multi->timer_userp = va_arg(param, void *);
+ break;
default:
res = CURLM_UNKNOWN_OPTION;
+ break;
}
va_end(param);
return res;
@@ -1684,26 +1702,26 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
int *running_handles)
{
- return multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
- running_handles);
+ CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+ running_handles);
+ if (CURLM_OK == result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
}
CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
{
- return multi_socket((struct Curl_multi *)multi_handle,
- TRUE, CURL_SOCKET_BAD, running_handles);
+ CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
+ TRUE, CURL_SOCKET_BAD, running_handles);
+ if (CURLM_OK == result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
}
-CURLMcode curl_multi_timeout(CURLM *multi_handle,
- long *timeout_ms)
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+ 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();
@@ -1724,6 +1742,44 @@ CURLMcode curl_multi_timeout(CURLM *multi_handle,
return CURLM_OK;
}
+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;
+
+ return multi_timeout(multi, timeout_ms);
+}
+
+/*
+ * Tell the application it should update its timers, if it subscribes to the
+ * update timer callback.
+ */
+static int update_timer(struct Curl_multi *multi)
+{
+ long timeout_ms;
+ if (!multi->timer_cb)
+ return 0;
+ if ( multi_timeout(multi, &timeout_ms) != CURLM_OK )
+ return -1;
+ if ( timeout_ms < 0 )
+ return 0;
+
+ /* When multi_timeout() is done, multi->timetree points to the node with the
+ * timeout we got the (relative) time-out time for. We can thus easily check
+ * if this is the same (fixed) time as we got in a previous call and then
+ * avoid calling the callback again. */
+ if(multi->timetree->key == multi->timer_lastcall)
+ return 0;
+
+ multi->timer_lastcall = multi->timetree->key;
+
+ return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
+}
+
/* 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)