]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
Jeff Pohlmeyer has been working with the hiperfifo.c example source code,
authorDaniel Stenberg <daniel@haxx.se>
Thu, 12 Oct 2006 08:36:47 +0000 (08:36 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 12 Oct 2006 08:36:47 +0000 (08:36 +0000)
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.

CHANGES
RELEASE-NOTES
TODO-RELEASE
docs/libcurl/curl_multi_setopt.3
include/curl/multi.h
lib/multi.c

diff --git a/CHANGES b/CHANGES
index f572e7ef525874d9faf0f0014d21f0d11592c627..7eabba8d462fdd317e9d5c6813077293f84ca7ff 100644 (file)
--- 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
index 950784f23199ebd2046e0d401f2d50e6b565dfe5..5b70767b95f35023eed1aed36637fca2876635e6 100644 (file)
@@ -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
index 03ffa88bef76ade294109455ca2c637418ede489..7d0a1e38fa564e665553c11bb98b9b369f207f0f 100644 (file)
@@ -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 - 
index 5279055ce78aff3754cd4fb8258f34fde873c246..5ba81b95252ef56377a77fb04719f16cb8b63be7 100644 (file)
@@ -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
index 23fe180d351ffeede4e51265865cd835188d1d84..d2533728d919ddedc4ba5b80dfa5b4fd5bd362b4 100644 (file)
@@ -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;
 
index e901bddfd9fd06492e27d0f7b2b7d2bba2d30233..aaa80b228b12f94d8810a54cc389aa165d7aa295 100644 (file)
@@ -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)