cURL / Mailing Lists / curl-library / Single Mail


Re: curl_multi_socket_action, http pipelining

From: Josef Drexler <>
Date: Sun, 17 Aug 2008 12:43:22 +0200

On Aug 17, 2008, at 2:39 AM, George Kola wrote:
> I am writing a program that monitors something and reports the
> status to a web server. I am using Linux (RedHat Enterprise 4.5)
> and libcurl-7.18-2
> Since, I wanted to do the monitoring and status reporting in
> parallel, I decided to use curl_multi_socket action.
> [...]
> 3. call curl_multi_socket_all -- to start the transfers
> I)First question is about step 3. Documentation (http://
> says there should be
> no reason to use curl_multi_socket_all. If I am not to use it, what
> should I use in step 3 (curl_multi_perform ?)

You don't need to call curl_multi_socket_all, anytime you think you
need to call it must be considered a bug somewhere. Adding the easy
handle should generate a socket and/or timeout callback, so you can
add the socket to your event backend. When the socket becomes
readable or writable, you call curl_multi_socket_action on it. You
don't manually have to "start" the transfer. At least I never did.

> II) curl_multi_socket_all is returning
> CURLM_CALL_MULTI_PERFORM and I have to call it twice (on every
> invocation). The docs say that modern libcurl do not return
> CURLM_CALL_MULTI_PERFORM -- am I doing something wrong ?

I think that refers to curl_multi_socket_action, which should not
return CURLM_CALL_MULTI_PERFORM in recent libcurl versions, though it
will, occasionally, in older ones where you should call it again like
you would call it for a timeout. I suspect that curl_multi_socket_all
will still return it. But you shouldn't use curl_multi_socket_all
anyway since it needs to poll the readiness of all sockets, so you
waste a syscall per socket per iteration.

> I am using EPOLL on Linux 2.6.9. I would prefer to use
> edge triggerred and set EPOLLIN|EPOLLOUT|EPOLLET once and be done
> for the socket. Will that work ? (experimenting with it seems to
> work)

If it works, it's by coincidence. You probably shouldn't generate
read or write readiness events when libcurl isn't expecting them yet.
You should set either EPOLLIN, EPOLLOUT, or both, or none according
to the socket callback argument.

This is perhaps of lesser importance if the socket isn't pipelined,
because then the socket will only be written to first and then only
read from until it is closed. But if you were to do chunked POSTs, or
make it actually use pipelining, it would probably break. Since epoll
is known to generate spurious events when using edge triggering, this
breakage would not be immediately apparent but it will come to bite you.

> I find that curl makes a lot of socket callbacks (first
> passing CURL_POLL_OUT and then passing CURL_POLL_IN and the process
> repeats multiple times for the same fd).I would like not to make
> too many epoll calls.

Normally, it should wait for read readiness until the connect()
succeeds, then switch to write readiness to write the request, and
finally to read readiness again to read the reply.

Since you're using edge triggering however, if you pass an event that
libcurl does not expect and hence ignores, the event will not be
repeated when libcurl *does* expect it later. (Even though Linux
epoll sometimes does repeat it later anyway, you should not rely on
this.) However it would probably work if you "cache" the read/write
readiness of the socket, and pass that on to libcurl when it does
request CURL_POLL_IN/CURL_POLL_OUT, essentially building a level
triggered mechanism for libcurl on top of the edge triggered
mechanism of EPOLLET. This should work and also allows you to not
update the event mask constantly.

Without it, I think edge triggering will only work reliably (i.e.
without relying on spurious events or calling curl_multi_socket_all)
if you set the event mask properly as the callback instructs you.

As for your other pipelining questions, I don't have much experience
with that and hope someone else can answer those.

Josef Drexler
Received on 2008-08-17