Index: include/curl/multi.h
===================================================================
RCS file: /cvsroot/curl/curl/include/curl/multi.h,v
retrieving revision 1.41
diff -u -r1.41 multi.h
--- include/curl/multi.h	7 Sep 2006 21:49:21 -0000	1.41
+++ include/curl/multi.h	10 Oct 2006 15:07:22 -0000
@@ -231,6 +231,20 @@
                                                         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 @@
     /* 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: lib/multi.c
===================================================================
RCS file: /cvsroot/curl/curl/lib/multi.c,v
retrieving revision 1.116
diff -u -r1.116 multi.c
--- lib/multi.c	10 Oct 2006 14:23:34 -0000	1.116
+++ lib/multi.c	10 Oct 2006 15:07:23 -0000
@@ -166,6 +166,12 @@
 
   /* 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 @@
                          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 @@
   /* increase the alive-counter */
   multi->num_alive++;
 
+  update_timer(multi);
   return CURLM_OK;
 }
 
@@ -610,6 +618,7 @@
 
     multi->num_easy--; /* one less to care about now */
 
+    update_timer(multi);
     return CURLM_OK;
   }
   else
@@ -1342,6 +1351,8 @@
 
   *running_handles = multi->num_alive;
 
+  if ( CURLM_OK == returncode )
+    update_timer(multi);
   return returncode;
 }
 
@@ -1673,8 +1684,15 @@
   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_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 @@
   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)
