cURL / Mailing Lists / curl-library / Single Mail


Re: Multi-handle hanging up immediately after creating FTP data socket (using GCD)

From: Bill Doyle <>
Date: Thu, 8 Aug 2013 09:44:04 -0400

On Thu, Aug 8, 2013 at 5:50 AM, Daniel Stenberg <> wrote:
> Right, but that was also highly unreadable and hard to follow so that wasn't
> really a good read for me either.

That I can't argue with, it took me a week of poking at it to figure
out what was going on. I chalked it up to not entirely understanding
libcurl or GCD, but good to know that it isn't just me.

> Can you perhaps describe in words which libcurl functions you're using in
> this program and in which order, like just a high-level description of what
> it is supposed to do?

Yeah, I can give it a try. I'm still in the process of learning both
components here, but I think I understand what's *supposed* to be
going on:

When the CURLInterface object is initially created (so everything
inside the -init method), I go through the process of a) setting up
the GCD queue, and b) the curl multi-handle. The queue is pretty easy,
just a single call to dispatch_queue_create() telling it that I want a
serial queue, and then creating/attaching the initial timeout to kick
everything off. How this happens is described a few paragraphs down.
(I haven't set a specific timer interval here, but that doesn't seem
to affect it, so I assume that it defaults to not doing anything? I
haven't been able to find any info on that, I'm going to ping the
#macdev room on Freenode later today and see if anyone knows.)

Once the object is set up, it simply waits for someone to call
-addUpload: with all the various info it needs to do so. The first
thing it does is construct a simple data object that stores all of the
state info about the handle, such as current byte, status code, debug
output, etc. It then creates an easy-handle, sets all of the various
options on it, and adds it to the multi-handle. In particular, the
state object (an instance of CURLHandleData) is attached using
CURLOPT_PRIVATE and also as the userData pointer for most of the
callbacks. It is also returned to whoever called -addUpload: so that
they can use it to track the upload's progress.

From there, it follows the typical multi-handle flow. socket_callback
and timer_callback handle requests from the multi-handle to attach
event handlers to GCD. socket_callback needs access to the
CURLInterface to attach things properly, so that's what it receives as
its userData pointer. Because of that, you can think of the
socket_callback and -attachSourceOfType: method as being a single
piece. socket_callback's socketData pointer is configured to point at
a simple struct that keeps track of the GCD sources used to watch for
events on the specified socket, so they can be updated or removed as

When activity is detected on the sockets, or from the timer, a call to
-performPartialUpload:forSocket: is added to the GCD queue. This
method calls curl_multi_socket_action, and then reads through any
available info from curl_multi_info_read so that it can notify the
object's delegate (whoever is managing the uploads) that something has
happened, be it success, failure, whatever. It also performs the
cleanup of completed easy-handles and their attached CURLHandleData

As far as the callbacks for the easy-handles go:
- read_function is reading from an NSData object, which is basically
just a wrapper around some data stored in memory. It uses the
CURLHandleData object assigned as its userData pointer to keep track
this NSData object, and also its current position within the data.
- progress_callback simply updates the progress that's also stored in
the CURLHandleData object, and also calls a method on the delegate to
inform it of the progress.
- debug_callback writes the debug information into the CURLHandleData object.
- socket_function sets a keepalive on the sockets, but it doesn't seem
to have any effect on how things work (or don't).

Sorry for the long post, but I think that covers just about anything.
It's entirely possible that I've forgotten something, as I'm typing
this in a hurry. Just poke at me and I can add info later this

List admin:
Received on 2013-08-08