[Hiper-related work] Added a function called curl_multi_assign() that will
authorDaniel Stenberg <daniel@haxx.se>
Wed, 26 Jul 2006 22:19:42 +0000 (22:19 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 26 Jul 2006 22:19:42 +0000 (22:19 +0000)
set a private pointer added to the internal libcurl hash table for the
particular socket passed in to this function.

CHANGES
docs/libcurl/Makefile.am
docs/libcurl/curl_global_init.3
docs/libcurl/curl_multi_assign.3 [new file with mode: 0644]
docs/libcurl/curl_multi_setopt.3
docs/libcurl/curl_multi_socket.3
hiper/STATUS
hiper/hipev.c
include/curl/multi.h
lib/multi.c

diff --git a/CHANGES b/CHANGES
index 29c2aa2..2478c17 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,22 @@
 
                                   Changelog
 
+Daniel (27 July 2006)
+- [Hiper-related work] Added a function called curl_multi_assign() that will
+  set a private pointer added to the internal libcurl hash table for the
+  particular socket passed in to this function:
+
+  CURLMcode curl_multi_assign(CURLM *multi_handle,
+                              curl_socket_t sockfd,
+                              void *sockp);
+
+  'sockp' being a custom pointer set by the application to be associated with
+  this socket. The socket has to be already existing and in-use by libcurl,
+  like having already called the callback telling about its existance.
+
+  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).
+
 Daniel (26 July 2006)
 - Dan Nelson added the CURLOPT_FTP_ALTERNATIVE_TO_USER libcurl option and curl
   tool option named --ftp-alternative-to-user. It provides a mean to send a
index e43a0b6..ea96cea 100644 (file)
@@ -18,7 +18,7 @@ man_MANS = curl_easy_cleanup.3 curl_easy_getinfo.3 curl_easy_init.3    \
  curl_multi_strerror.3 curl_share_strerror.3 curl_global_init_mem.3     \
  libcurl-tutorial.3 curl_easy_reset.3 curl_easy_escape.3                \
  curl_easy_unescape.3 curl_multi_setopt.3 curl_multi_socket.3           \
- curl_multi_timeout.3 curl_formget.3
+ curl_multi_timeout.3 curl_formget.3 curl_multi_assign.3
 
 HTMLPAGES = curl_easy_cleanup.html curl_easy_getinfo.html                \
  curl_easy_init.html curl_easy_perform.html curl_easy_setopt.html        \
@@ -35,8 +35,8 @@ HTMLPAGES = curl_easy_cleanup.html curl_easy_getinfo.html               \
  libcurl-errors.html curl_easy_strerror.html curl_multi_strerror.html    \
  curl_share_strerror.html curl_global_init_mem.html libcurl-tutorial.html \
  curl_easy_reset.html curl_easy_escape.html curl_easy_unescape.html      \
- curl_multi_setopt.html curl_multi_socket.html curl_multi_timeout.html         \
- curl_formget.html
+ curl_multi_setopt.html curl_multi_socket.html curl_multi_timeout.html   \
+ curl_formget.html curl_multi_assign.html
 
 PDFPAGES = curl_easy_cleanup.pdf curl_easy_getinfo.pdf curl_easy_init.pdf \
  curl_easy_perform.pdf curl_easy_setopt.pdf curl_easy_duphandle.pdf      \
@@ -52,8 +52,8 @@ PDFPAGES = curl_easy_cleanup.pdf curl_easy_getinfo.pdf curl_easy_init.pdf \
  libcurl-errors.pdf curl_easy_strerror.pdf curl_multi_strerror.pdf       \
  curl_share_strerror.pdf curl_global_init_mem.pdf libcurl-tutorial.pdf   \
  curl_easy_reset.pdf curl_easy_escape.pdf curl_easy_unescape.pdf         \
- curl_multi_setopt.pdf curl_multi_socket.pdf curl_multi_timeout.pdf    \
- curl_formget.pdf
+ curl_multi_setopt.pdf curl_multi_socket.pdf curl_multi_timeout.pdf      \
+ curl_formget.pdf curl_multi_assign.pdf
 
 CLEANFILES = $(HTMLPAGES) $(PDFPAGES)
 
index 0729ef7..ba15ad4 100644 (file)
@@ -11,30 +11,30 @@ curl_global_init - Global libcurl initialisation
 .BI "CURLcode curl_global_init(long " flags ");"
 .ad
 .SH DESCRIPTION
-This function sets up the program environment that libcurl needs.  Think
-of it as an extension of the library loader.
+This function sets up the program environment that libcurl needs.  Think of it
+as an extension of the library loader.
 
-This function must be called at least once within a program (a program is
-all the code that shares a memory space) before the program calls any other
-function in libcurl.  The environment it sets up is constant for the life
-of the program and is the same for every program, so multiple calls have
-the same effect as one call.
+This function must be called at least once within a program (a program is all
+the code that shares a memory space) before the program calls any other
+function in libcurl.  The environment it sets up is constant for the life of
+the program and is the same for every program, so multiple calls have the same
+effect as one call.
 
 The flags option is a bit pattern that tells libcurl exactly what features to
 init, as described below. Set the desired bits by ORing the values together.
 In normal operation, you must specify CURL_GLOBAL_ALL.  Don't use any other
-value unless you are familiar with and mean to control internal operations
-of libcurl.
+value unless you are familiar with and mean to control internal operations of
+libcurl.
 
-\fBThis function is not thread safe.\fP  You must not call it when any
-other thread in the program (i.e. a thread sharing the same memory) is
-running.  This doesn't just mean no other thread that is using
-libcurl.  Because \fIcurl_global_init()\fP calls functions of other
-libraries that are similarly thread unsafe, it could conflict with any
-other thread that uses these other libraries.
+\fBThis function is not thread safe.\fP You must not call it when any other
+thread in the program (i.e. a thread sharing the same memory) is running.
+This doesn't just mean no other thread that is using libcurl.  Because
+\fIcurl_global_init()\fP calls functions of other libraries that are similarly
+thread unsafe, it could conflict with any other thread that uses these other
+libraries.
 
-See the description in \fBlibcurl\fP(3) of global environment
-requirements for details of how to use this function.
+See the description in \fBlibcurl\fP(3) of global environment requirements for
+details of how to use this function.
 
 .SH FLAGS
 .TP 5
diff --git a/docs/libcurl/curl_multi_assign.3 b/docs/libcurl/curl_multi_assign.3
new file mode 100644 (file)
index 0000000..cb47a5e
--- /dev/null
@@ -0,0 +1,44 @@
+.\" $Id$
+.\"
+.TH curl_multi_assign 3 "9 Jul 2006" "libcurl 7.16.0" "libcurl Manual"
+.SH NAME
+curl_multi_assign \- set data to associated with an internal socket
+.SH SYNOPSIS
+#include <curl/curl.h>
+
+CURLMcode curl_multi_assign(CURLM *multi_handle, curl_socket_t sockfd,
+                            void *sockptr);
+.SH DESCRIPTION
+This function assigns an association in the multi handle between the given
+socket and a private pointer of the application. This is (only) useful for
+\fIcurl_multi_socket(3)\fP uses.
+
+When set, the \fIsockptr\fP pointer will be passed to all future socket
+callbacks for the specific \fIsockfd\fP socket.
+
+If the given \fIsockfd\fP isn't already in use by libcurl, this function will
+return an error.
+
+libcurl only keeps one single pointer associated with a socket, so calling
+this function several times for the same socket will make the last set pointer
+get used.
+
+The idea here being that this association (socket to private pointer) is
+something that just about every application that uses this API will need and
+then libcurl can just as well do it since it already has an internal hash
+table lookup for this.
+.SH "RETURN VALUE"
+The standard CURLMcode for multi interface error codes.
+.SH "TYPICAL USAGE"
+In a typical application you allocate a struct or at least use some kind of
+semi-dynamic data for each socket that we must wait for action on when using
+the \fIcurl_multi_socket(3)\fP approach.
+
+When our socket-callback get called by libcurl and we get to know about yet
+another socket to wait for, we can use \fIcurl_multi_assign(3)\fP to point out
+the particular data so that when we get updates about this same socket again,
+we don't have to find the struct associated with this socket by ourselves.
+.SH AVAILABILITY
+This function was added in libcurl 7.15.5, although not deemed stable yet.
+.SH "SEE ALSO"
+.BR curl_multi_setopt "(3), " curl_multi_socket "(3) "
index 623daa5..0228e3d 100644 (file)
@@ -25,8 +25,9 @@ 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 fourth argument with \fICURLMOPT_SOCKETDATA\fP.
-See \fIcurl_multi_socket(3)\fP for more callback details.
+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
index e5312c8..0c5ba73 100644 (file)
@@ -1,6 +1,6 @@
 .\" $Id$
 .\"
-.TH curl_multi_socket 3 "21 Dec 2005" "libcurl 7.16.0" "libcurl Manual"
+.TH curl_multi_socket 3 "9 Jul 2006" "libcurl 7.16.0" "libcurl Manual"
 .SH NAME
 curl_multi_socket \- reads/writes available data
 .SH SYNOPSIS
@@ -19,32 +19,41 @@ application has detected action on a socket handled by libcurl, it should call
 with the action.
 
 These 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 with the CURLMOPT_SOCKETFUNCTION option to
+descriptor) status by doing none, one or multiple calls to the callback
+function set with the CURLMOPT_SOCKETFUNCTION option to
 \fIcurl_multi_setopt(3)\fP. They update the status with changes since the
 previous time this function was called.
 
-If you want to force libcurl to (re-)check all its internal sockets and
-transfers instead of just a single one, you call
-\fBcurl_multi_socket_all(3)\fP instead.
+To force libcurl to (re-)check all its internal sockets and transfers instead
+of just a single one, you call \fBcurl_multi_socket_all(3)\fP.
 
-An application should call \fBcurl_multi_timeout(3)\fP to figure out how long
-it should wait for socket actions \- at most \- before doing the timeout
-action: call the \fBcurl_multi_socket(3)\fP function with the \fBsockfd\fP
-argument set to CURL_SOCKET_TIMEOUT.
+Applications should call \fBcurl_multi_timeout(3)\fP to figure out how long to
+wait for socket actions \- at most \- before doing the timeout action: call
+the \fBcurl_multi_socket(3)\fP function with the \fBsockfd\fP argument set to
+CURL_SOCKET_TIMEOUT.
+
+.SH "CALLBACK DETAILS"
 
 The socket \fBcallback\fP function uses a prototype like this
 .nf
 
-     int curl_socket_callback(CURL *easy,      /* easy handle */
-                              curl_socket_t s, /* socket */
-                              int action,      /* see values below */
-                              void *userp);    /* "private" pointer */
+  int curl_socket_callback(CURL *easy,      /* easy handle */
+                           curl_socket_t s, /* socket */
+                           int action,      /* see values below */
+                           void *userp,    /* private callback pointer */
+                           void *socketp); /* private socket pointer */
 
 .fi
 The callback MUST return 0.
 
-The \fIaction\fP (third) argument to the callback has one of five values:
+The \fIeasy\fP argument is a pointer to the easy handle that deals with this
+particular socket. Note that a single handle may work with several sockets
+simultaneously.
+
+The \fIs\fP argument is the actual socket value as you use it within your
+system.
+
+The \fIaction\fP argument to the callback has one of five values:
 .RS
 .IP "CURL_POLL_NONE (0)"
 register, not interested in readiness (yet)
@@ -57,6 +66,15 @@ register, interested in both read and write readiness
 .IP "CURL_POLL_REMOVE (4)"
 deregister
 .RE
+
+The \fIsocketp\fP argument is a private pointer you have previously set with
+\fIcurl_multi_assign(3)\fP to be associated with the \fIs\fP socket. If no
+pointer has been set, socketp will be NULL. This argument is of course a
+service to applications that want to keep certain data or structs that are
+strictly associated to the given socket.
+
+The \fIuserp\fP argument is a private pointer you have previously set with
+\fIcurl_multi_setopt(3)\fP and the CURLMOPT_SOCKETDATA option.
 .SH "RETURN VALUE"
 CURLMcode type, general libcurl multi interface error code.
 
index df8f451..6b3e511 100644 (file)
@@ -267,3 +267,25 @@ April 20, 2006
  using the same socket. I've cleaned up and simplified code now to adjust to
  this.
 
+---------------------------------------------------------------------------
+
+July 9, 2006
+
+ TODO: We need to alter how we use c-ares for getting info about its sockets,
+ as c-ares now provides a callback approach very similar to how libcurl is
+ about to work.
+
+ I'm adding a function called curl_multi_assign() that will set a private
+ pointer added to the internal libcurl hash table for the particular socket
+ passed in to this function:
+
+ CURLMcode curl_multi_assign(CURLM *multi_handle,
+                             curl_socket_t sockfd,
+                             void *sockp);
+
+ 'sockp' being a custom pointer set by the application to be associated with
+ this socket. The socket has to be already existing and in-use by libcurl,
+ like having already called the callback telling about its existance.
+
+ 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).
index d82d734..b5a0159 100644 (file)
@@ -88,36 +88,16 @@ struct fdinfo {
 
 static struct fdinfo *allsocks;
 
-static struct fdinfo *findsock(curl_socket_t s)
+static void remsock(struct fdinfo *f)
 {
-  /* return the struct for the given socket */
-  struct fdinfo *fdp = allsocks;
-
-  while(fdp) {
-    if(fdp->sockfd == s)
-      break;
-    fdp = fdp->next;
-  }
-  return fdp; /* a struct pointer or NULL */
-}
-
-static void remsock(curl_socket_t s)
-{
-  struct fdinfo *fdp = allsocks;
-
-  while(fdp) {
-    if(fdp->sockfd == s)
-      break;
-    fdp = fdp->next;
-  }
-  if(!fdp)
+  if(!f)
     /* did not find socket to remove! */
     return;
 
-  if(fdp->prev)
-    fdp->prev->next = fdp->next;
-  if(fdp->next)
-    fdp->next->prev = fdp->prev;
+  if(f->prev)
+    f->prev->next = f->next;
+  if(f->next)
+    f->next->prev = f->prev;
   else
     /* this was the last entry */
     allsocks = NULL;
@@ -131,7 +111,7 @@ static void setsock(struct fdinfo *fdp, curl_socket_t s, CURL *easy,
   fdp->easy = easy;
 }
 
-static void addsock(curl_socket_t s, CURL *easy, int action)
+static void addsock(curl_socket_t s, CURL *easy, int action, CURLM *multi)
 {
   struct fdinfo *fdp = calloc(sizeof(struct fdinfo), 1);
 
@@ -146,6 +126,9 @@ static void addsock(curl_socket_t s, CURL *easy, int action)
   }
   else
     allsocks = fdp;
+
+  /* Set this association in libcurl */
+  curl_multi_assign(multi, s, fdp);
 }
 
 static void fdinfo2fdset(fd2_set *fdread, fd2_set *fdwrite, int *maxfd)
@@ -201,18 +184,20 @@ static void fdinfo2fdset(fd2_set *fdread, fd2_set *fdwrite, int *maxfd)
 static int socket_callback(CURL *easy,      /* easy handle */
                            curl_socket_t s, /* socket */
                            int what,        /* see above */
-                           void *userp)     /* "private" pointer */
+                           void *cbp,       /* callback pointer */
+                           void *socketp)   /* socket pointer */
 {
-  struct fdinfo *fdp;
+  struct fdinfo *fdp = (struct fdinfo *)socketp;
+
   printf("socket %d easy %p what %d\n", s, easy, what);
 
   if(what == CURL_POLL_REMOVE)
-    remsock(s);
+    remsock(fdp);
   else {
-    fdp = findsock(s);
-
     if(!fdp) {
-      addsock(s, easy, what);
+      /* not previously known, add it and set association */
+      printf("Add info for socket %d (%d)\n", s, what);
+      addsock(s, easy, what, cbp);
     }
     else {
       /* we already know about it, just change action/timeout */
@@ -443,7 +428,7 @@ int main(int argc, char **argv)
   }
 
   curl_multi_setopt(multi_handle, CURLMOPT_SOCKETFUNCTION, socket_callback);
-  curl_multi_setopt(multi_handle, CURLMOPT_SOCKETDATA, NULL);
+  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));
index 4fc7064..eb62446 100644 (file)
@@ -261,11 +261,14 @@ CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
 typedef int (*curl_socket_callback)(CURL *easy,      /* easy handle */
                                     curl_socket_t s, /* socket */
                                     int what,        /* see above */
-                                    void *userp);    /* "private" pointer */
+                                    void *userp,     /* private callback
+                                                        pointer */
+                                    void *socketp);  /* private socket
+                                                        pointer */
 
-CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s);
+CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s);
 
-CURLMcode curl_multi_socket_all(CURLM *multi_handle);
+CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle);
 
 /*
  * Name:    curl_multi_timeout()
@@ -276,7 +279,8 @@ CURLMcode curl_multi_socket_all(CURLM *multi_handle);
  *
  * Returns: CURLM error code.
  */
-CURLMcode curl_multi_timeout(CURLM *multi_handle, long *milliseconds);
+CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
+                                         long *milliseconds);
 
 #undef CINIT /* re-using the same name as in curl.h */
 
@@ -309,8 +313,21 @@ typedef enum {
  *
  * Returns: CURLM error code.
  */
-CURLMcode curl_multi_setopt(CURLM *multi_handle,
-                            CURLMoption option, ...);
+CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
+                                        CURLMoption option, ...);
+
+
+/*
+ * Name:    curl_multi_assign()
+ *
+ * Desc:    This function sets an association in the multi handle between the
+ *          given socket and a private pointer of the application. This is
+ *          (only) useful for curl_multi_socket uses.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
+                                        curl_socket_t sockfd, void *sockp);
 
 #ifdef __cplusplus
 } /* end of extern "C" */
index 44c7424..3296f09 100644 (file)
@@ -182,7 +182,7 @@ struct Curl_sh_entry {
   time_t timestamp;
   long inuse;
   int action;  /* what action READ/WRITE this socket waits for */
-  void *userp; /* settable by users (not yet decided exactly how) */
+  void *socketp; /* settable by users with curl_multi_assign() */
 };
 /* bits for 'action' having no bits means this socket is not expecting any
    action */
@@ -1125,10 +1125,14 @@ static void singlesocket(struct Curl_multi *multi,
 
       /* call the callback with this new info */
       if(multi->socket_cb) {
+        struct Curl_sh_entry *entry =
+          Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
         multi->socket_cb(easy->easy_handle,
                          s,
                          action,
-                         multi->socket_userp);
+                         multi->socket_userp,
+                         entry->socketp);
       }
 
       /* Update the sockhash accordingly */
@@ -1385,3 +1389,19 @@ void Curl_expire(struct SessionHandle *data, long milli)
 #endif
 }
 
+CURLMcode curl_multi_assign(CURLM *multi_handle,
+                            curl_socket_t s, void *hashp)
+{
+  struct Curl_sh_entry *there = NULL;
+  struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
+
+  if(s != CURL_SOCKET_BAD)
+    there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t));
+
+  if(!there)
+    return CURLM_BAD_SOCKET;
+
+  there->socketp = hashp;
+
+  return CURLM_OK;
+}