From 6f6b93da02019141812b81bfdbb6bcda430c3b4d Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 26 Jul 2006 22:19:42 +0000 Subject: [PATCH] [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. --- CHANGES | 16 ++++++++++ docs/libcurl/Makefile.am | 10 +++--- docs/libcurl/curl_global_init.3 | 34 ++++++++++---------- docs/libcurl/curl_multi_assign.3 | 44 ++++++++++++++++++++++++++ docs/libcurl/curl_multi_setopt.3 | 5 +-- docs/libcurl/curl_multi_socket.3 | 48 ++++++++++++++++++++--------- hiper/STATUS | 22 +++++++++++++ hiper/hipev.c | 53 ++++++++++++-------------------- include/curl/multi.h | 29 +++++++++++++---- lib/multi.c | 24 +++++++++++++-- 10 files changed, 204 insertions(+), 81 deletions(-) create mode 100644 docs/libcurl/curl_multi_assign.3 diff --git a/CHANGES b/CHANGES index 29c2aa2639..2478c17664 100644 --- 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 diff --git a/docs/libcurl/Makefile.am b/docs/libcurl/Makefile.am index e43a0b67ce..ea96cea1db 100644 --- a/docs/libcurl/Makefile.am +++ b/docs/libcurl/Makefile.am @@ -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) diff --git a/docs/libcurl/curl_global_init.3 b/docs/libcurl/curl_global_init.3 index 0729ef787d..ba15ad4e0b 100644 --- a/docs/libcurl/curl_global_init.3 +++ b/docs/libcurl/curl_global_init.3 @@ -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 index 0000000000..cb47a5e254 --- /dev/null +++ b/docs/libcurl/curl_multi_assign.3 @@ -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 + +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) " diff --git a/docs/libcurl/curl_multi_setopt.3 b/docs/libcurl/curl_multi_setopt.3 index 623daa53f3..0228e3d644 100644 --- a/docs/libcurl/curl_multi_setopt.3 +++ b/docs/libcurl/curl_multi_setopt.3 @@ -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 diff --git a/docs/libcurl/curl_multi_socket.3 b/docs/libcurl/curl_multi_socket.3 index e5312c840f..0c5ba73459 100644 --- a/docs/libcurl/curl_multi_socket.3 +++ b/docs/libcurl/curl_multi_socket.3 @@ -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. diff --git a/hiper/STATUS b/hiper/STATUS index df8f4515cd..6b3e511f41 100644 --- a/hiper/STATUS +++ b/hiper/STATUS @@ -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). diff --git a/hiper/hipev.c b/hiper/hipev.c index d82d7349f3..b5a015918b 100644 --- a/hiper/hipev.c +++ b/hiper/hipev.c @@ -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)); diff --git a/include/curl/multi.h b/include/curl/multi.h index 4fc70640a8..eb62446df4 100644 --- a/include/curl/multi.h +++ b/include/curl/multi.h @@ -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" */ diff --git a/lib/multi.c b/lib/multi.c index 44c7424766..3296f09e57 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -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; +}