Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

curl_multi_fdvec #38

Closed
wants to merge 5 commits into from

2 participants

@sgolemon

Here's an alternative to curl_multi_select() which addresses your desire for being able to add arbitrary file descriptors. Workflow here is:

long read_fds, write_fds;

curl_multi_getinfo(multi, CURLMINFO_NUM_READ_FDS, &read_fds);
curl_multi_getinfo(multi, CURLMINFO_NUM_WRITE_FDS, &write_fds);

int *rfds = calloc(read_fds, sizeof(int));
int *wfds = calloc(write_fds, sizeof(int));

curl_multi_fdvec(multi, rfds, wfds, NULL);

Then the caller can put into fd_set or struct pollfd as desired, allocating extra space for external fds if desired.

LMK what you think of this approach, and I can add manpages/tests if you like it better.

Note that although I included support for exception fds, there's no internal plumbing for it in keeping with curl_multi_fdset().

@sgolemon

Ick, dunno what I did to my repo to make it look like this. Will resubmit a clean pull if the overall strat looks okay. :/

@bagder
Owner
@sgolemon

I think the primary reason I went this direction instead of what you propose (which is certainly simpler to use) was to allow more flexibility in how poll() gets called. For my purposes, I don't actually need the flexibility so I wouldn't mind the approach you describe at all.

Want me to do the work and submit a pull request for that?

@sgolemon sgolemon closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
Showing with 133 additions and 0 deletions.
  1. +36 −0 include/curl/multi.h
  2. +97 −0 lib/multi.c
View
36 include/curl/multi.h
@@ -67,6 +67,21 @@ typedef enum {
CURLM_LAST
} CURLMcode;
+#define CURLMINFO_STRING CURLINFO_STRING
+#define CURLMINFO_LONG CURLINFO_LONG
+#define CURLMINFO_DOUBLE CURLINFO_DOUBLE
+#define CURLMINFO_SLIST CURLINFO_SLIST
+#define CURLMINFO_MASK CURLINFO_MASK
+#define CURLMINFO_TYPEMASK CURLINFO_TYPEMASK
+
+typedef enum {
+ CURLMINFO_NONE,
+ CURLMINFO_NUM_READ_FDS = CURLMINFO_LONG + 1,
+ CURLMINFO_NUM_WRITE_FDS = CURLMINFO_LONG + 2,
+ CURLMINFO_NUM_EX_FDS = CURLMINFO_LONG + 3,
+ CURLMINFO_NUM_FDS = CURLMINFO_LONG + 4
+} CURLMINFO;
+
/* just to make code nicer when using curl_multi_socket() you can now check
for CURLM_CALL_MULTI_SOCKET too in the same style it works for
curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
@@ -133,6 +148,18 @@ CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
fd_set *exc_fd_set,
int *max_fd);
+/*
+ * Name: curl_multi_fdvec()
+ *
+ * Desc: Retreive a vector of fds contained in the multi handle
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_fdvec(CURLM *multi_handle,
+ int *read_fds,
+ int *write_fds,
+ int *ex_fds);
+
/*
* Name: curl_multi_perform()
*
@@ -325,6 +352,15 @@ typedef enum {
CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
CURLMoption option, ...);
+/*
+ * Name: curl_multi_getinfo()
+ *
+ * Desc: Retreives info from a multi handle.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_getinfo(CURLM *multi_handle,
+ CURLMINFO info, ...);
/*
* Name: curl_multi_assign()
View
97 lib/multi.c
@@ -941,6 +941,38 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
return CURLM_OK;
}
+CURLMcode curl_multi_fdvec(CURLM *multi_handle,
+ int *read_fds,
+ int *write_fds,
+ int *ex_fds)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct Curl_one_easy *easy;
+ int rfds = 0, wfds = 0, xfds = 0;
+ (void)ex_fds; /* not used */
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ for(easy = multi->easy.next;
+ easy != &multi->easy;
+ easy = easy->next) {
+ curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
+ int i, bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ if (read_fds && (bitmap & GETSOCK_READSOCK(i))) {
+ read_fds[rfds++] = sockbunch[i];
+ }
+ if (write_fds && (bitmap & GETSOCK_WRITESOCK(i))) {
+ write_fds[wfds++] = sockbunch[i];
+ }
+ }
+ }
+
+ return CURLM_OK;
+}
+
static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct timeval now,
struct Curl_one_easy *easy)
@@ -2269,6 +2301,71 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle,
return res;
}
+static unsigned long curl_multi_count_fds(struct Curl_multi *multi,
+ char readH, char writeH, char exH)
+{
+ struct Curl_one_easy *easy;
+ int nfds = 0;
+ (void)exH; /* not used */
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ for(easy = multi->easy.next;
+ easy != &multi->easy;
+ easy = easy->next) {
+ curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
+ int i, bitmap = multi_getsock(easy, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ if ((readH && (bitmap & GETSOCK_READSOCK(i))) ||
+ (writeH && (bitmap & GETSOCK_WRITESOCK(i)))) {
+ nfds++;
+ }
+ }
+ }
+
+ return nfds;
+}
+
+#undef curl_multi_getinfo
+CURLMcode curl_multi_getinfo(CURLM *multi_handle,
+ CURLMINFO info, ...)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ CURLMcode res = CURLM_OK;
+ va_list param;
+ void *voidp;
+ long *longp;
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ va_start(param, info);
+ voidp = va_arg(param, void *);
+ longp = (long*)voidp;
+
+ switch(info) {
+ case CURLMINFO_NUM_READ_FDS:
+ *longp = curl_multi_count_fds(multi, 1, 0, 0);
+ break;
+ case CURLMINFO_NUM_WRITE_FDS:
+ *longp = curl_multi_count_fds(multi, 0, 1, 0);
+ break;
+ case CURLMINFO_NUM_EX_FDS:
+ *longp = curl_multi_count_fds(multi, 0, 0, 1);
+ break;
+ case CURLMINFO_NUM_FDS:
+ *longp = curl_multi_count_fds(multi, 1, 1, 1);
+ break;
+ default:
+ res = CURLM_UNKNOWN_OPTION;
+ }
+
+ va_end(param);
+ return res;
+}
+
/* we define curl_multi_socket() in the public multi.h header */
#undef curl_multi_socket
Something went wrong with that request. Please try again.