cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: adding easy handles when using curl_multi_socket*

From: Christopher Palow <cpalow_at_facebook.com>
Date: Mon, 28 Apr 2008 20:18:56 -0700

Markus,

Looking through your code I have a couple of suggestions that may or may not
help with the issues youıre having. The documentation is a little out of
date. At least in the current version of libcurl you donıt need to call
curl_multi_socket_all() to start a connection after adding an easy handle to
a multi handle with curl_multi_add_handle(). Curl_multi_add_handle() starts
a connection as well as adding it to a multi handle.

Likewise, in load() you then donıt need ³while (CURLM_CALL_MULTI_PERFORM ==
curl_multi_socket_all(cm, &U));² after the loop of requesthandler()s.

In socket_callback() why do you call event_del(ev) when ev exists? From
watching traces certainly the socket_callback seems to do the sequence
CURL_POLL_OUT, CURL_POLL_REMOVE, then CURL_POLL_IN, CURL_POLL_REMOVE but I
donıt think the API specifies that.

Chris

On 4/28/08 5:48 PM, "koettermarkus_at_gmx.de" <koettermarkus_at_gmx.de> wrote:

> luckily I just had a run which errord:
>
>
> ./load
> load.c:138 Callback on socket 6 (OUT)
> load.c:180 Updating timeout (10, 711000)
> load.c:36 Added request 1
> Event on socket 6 (WRITE)
> load.c:138 Callback on socket 6 (REMOVE)
> load.c:138 Callback on socket 6 (IN)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> Event on socket 6 (READ)
> load.c:138 Callback on socket 6 (REMOVE)
> load.c:180 Updating timeout (10, 3000)
> E: load.c:111 invalid socket argument (6)
>
>
>
> curl-config --version
> libcurl 7.16.4
>
> code is attached, ebay.de worked best for me.
>
> MfG
> Markus Kötter
>
>
> #include <stdlib.h>
> #include <curl/curl.h>
> #include <event.h>
>
> /* I have libcurl4 in /usr/local/lib and libcurl3 in /usr/local, hence:
> $ gcc -g -levent `curl-config --cflags --libs` -Wl,-rpath -Wl,/usr/local/lib
> -o load load.c */
>
> static const char url[] = "http://www.ebay.de/";
> static const size_t num = 100; /* number of transfers */
> static const size_t ccy = 1; /* concurrency */
>
> static struct event timeout;
> static int U;
> static size_t C, F;
>
> static int dummy(CURL *easy, size_t n, size_t s, void *data)
> {
> return n*s;
> }
>
> static void requesthandler(CURLM *cm)
> {
> CURL *ch = curl_easy_init();
> size_t *P = malloc(sizeof(size_t));
>
> ++U;
> *P = ++C;
>
> curl_easy_setopt(ch, CURLOPT_PRIVATE, P);
> curl_easy_setopt(ch, CURLOPT_URL, url);
> curl_easy_setopt(ch, CURLOPT_WRITEFUNCTION, dummy);
> curl_multi_add_handle(cm, ch);
>
> while ( CURLM_CALL_MULTI_PERFORM == curl_multi_socket_all(cm, &U) );
>
> fprintf(stderr, "%s:%i Added request %6zu\n",__FILE__, __LINE__, C);
>
> }
>
> static void responsehandler(CURLM *cm)
> {
> CURLMsg *msg;
> int remaining = 0;
>
> do {
> msg = curl_multi_info_read(cm, &remaining);
> if (msg && CURLMSG_DONE == msg->msg) {
> int *P;
>
> if (CURLE_OK != msg->data.result) {
> fprintf(stderr, "E:%s:%i %s\n", __FILE__, __LINE__,
> curl_easy_strerror(msg->data.result));
> }
>
> curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, &P);
>
> fprintf(stderr, "%s:%i Finished request %6zu\n", __FILE__, __LINE__, *P);
> free(P);
>
> if (C < num) {
> requesthandler(cm);
> }
>
> CURL *curl = msg->easy_handle;
> curl_multi_remove_handle(cm, msg->easy_handle);
> curl_easy_cleanup(curl);
> ++F;
> }
> } while (remaining);
> }
>
> static void timeout_callback(int socket, short action, void *event_data)
> {
> CURLMcode rc;
> CURLM *cm = event_data;
>
> fprintf(stderr, "%s:%i Timeout occurred\n",__FILE__, __LINE__);
>
> while (CURLM_CALL_MULTI_PERFORM == (rc = curl_multi_socket(cm,
> CURL_SOCKET_TIMEOUT, &U)));
>
> if (CURLM_OK != rc) {
> fprintf(stderr, "E: %s:%i %s\n", __FILE__, __LINE__,
> curl_multi_strerror(rc));
> }
> }
>
> static void event_callback(int socket, short action, void *event_data)
> {
> CURLMcode rc = CURLE_OK;
> CURLM *cm = event_data;
>
> static const char event_strings[][20] =
> {"NONE","TIMEOUT","READ","TIMEOUT|READ","WRITE","TIMEOUT|WRITE","READ|WRITE","
> TIMEOUT|READ|WRITE","SIGNAL"};
> fprintf(stderr, "Event on socket %d (%s)\n", socket, event_strings[action]);
>
> do {
> switch (action & (EV_READ|EV_WRITE)) {
> case EV_READ:
> rc = curl_multi_socket_action(cm, socket, CURL_CSELECT_IN, &U);
> break;
> case EV_WRITE:
> rc = curl_multi_socket_action(cm, socket, CURL_CSELECT_OUT, &U);
> break;
> case EV_READ|EV_WRITE:
> rc = curl_multi_socket_action(cm, socket,
> CURL_CSELECT_IN|CURL_CSELECT_OUT, &U);
> break;
> default:
> fprintf(stderr, "Unknown event %d\n", (int) action);
> return;
> }
> } while (CURLM_CALL_MULTI_PERFORM == rc);
>
> if (CURLM_OK != rc) {
> fprintf(stderr, "E: %s:%i %s (%d)\n", __FILE__, __LINE__,
> curl_multi_strerror(rc), (int) socket);
> }
>
> responsehandler(cm);
>
> /* remove timeout if there are no transfers left */
> if (!U && event_initialized(&timeout) && event_pending(&timeout, EV_TIMEOUT,
> NULL)) {
> event_del(&timeout);
> fprintf(stderr, "%s:%i Removed timeout\n", __FILE__, __LINE__);
> }
> }
>
> static int socket_callback(CURL *easy, curl_socket_t sock, int action, void
> *socket_data, void *assign_data)
> {
> int events = EV_PERSIST;
> CURLM *cm = socket_data;
> struct event *ev = assign_data;
>
> if (!ev) {
> ev = calloc(1, sizeof(struct event));
> curl_multi_assign(cm, sock, ev);
> } else {
> event_del(ev);
> }
>
> {
> static const char action_strings[][8] = {"NONE", "IN", "OUT", "INOUT",
> "REMOVE"};
> fprintf(stderr, "%s:%i Callback on socket %d (%s)\n", __FILE__, __LINE__,
> (int) sock, action_strings[action]);
> }
>
> switch (action) {
> case CURL_POLL_IN:
> events |= EV_READ;
> break;
> case CURL_POLL_OUT:
> events |= EV_WRITE;
> break;
> case CURL_POLL_INOUT:
> events |= EV_READ|EV_WRITE;
> break;
>
> case CURL_POLL_REMOVE:
> free(ev);
> case CURL_POLL_NONE:
> return 0;
>
> default:
> fprintf(stderr, "%s:%i Unknown socket action %d\n",__FILE__, __LINE__,
> action);
> return -1;
> }
>
> event_set(ev, sock, events, event_callback, cm);
> event_add(ev, NULL);
>
> return 0;
> }
>
> static void timer_callback(CURLM *multi, long timeout_ms, void *timer_data)
> {
> if (timeout_ms) {
> struct timeval tv = {10, (timeout_ms % 1000) * 1000};
>
> if (event_initialized(&timeout) && event_pending(&timeout, EV_TIMEOUT,
> NULL)) {
> event_del(&timeout);
> }
>
> event_set(&timeout, -1, 0, timeout_callback, multi);
> event_add(&timeout, &tv);
>
> fprintf(stderr, "%s:%i Updating timeout (%lu, %lu)\n", __FILE__, __LINE__,
> (ulong) tv.tv_sec, (ulong) tv.tv_usec);
> }
> }
>
> void load(void)
> {
> int i;
> struct timeval start_time, end_time;
> CURLM *cm = curl_multi_init();
>
> curl_multi_setopt(cm, CURLMOPT_SOCKETDATA, cm);
> curl_multi_setopt(cm, CURLMOPT_SOCKETFUNCTION, socket_callback);
> curl_multi_setopt(cm, CURLMOPT_TIMERDATA, cm);
> curl_multi_setopt(cm, CURLMOPT_TIMERFUNCTION, timer_callback);
>
> gettimeofday(&start_time, NULL);
> for (i = 0; i < ccy; ++i) {
> requesthandler(cm);
> }
> while (CURLM_CALL_MULTI_PERFORM == curl_multi_socket_all(cm, &U));
> event_dispatch();
> gettimeofday(&end_time, NULL);
>
> curl_multi_cleanup(cm);
>
> fprintf(stdout, "Added: %zu, Finished: %zu, Time: %lums\n", C, F,
> (end_time.tv_sec*1000+end_time.tv_usec/1000)-(start_time.tv_sec*1000+start_tim
> e.tv_usec/1000));
> }
>
> int main(int argc, char *argv[])
> {
> event_init();
> curl_global_init(CURL_GLOBAL_ALL);
>
> load();
>
> curl_global_cleanup();
>
> return 0;
> }
Received on 2008-04-29