aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)