Brian McFarland | 23 Apr 2012 22:31
Picon

Integrating with libev

I'm using libev in my application and trying to figure out if c-ares is suitable for DNS.


My general thinking is that I'll use a libev io watcher per socket created by c-ares.  Then I'll just need to call ares_process_fd when the watcher wakes up.  I'll also likely need a timer, which is probably as simple as reseting a libev timer to ares_timeout() every time an I/O callback wakes up.

It looks like I can use the "ARES_OPT_SOCK_STATE_CB" to detect when I need to enable/disable my watchers (i.e. event listeners) for each socket.

It also appears that ares_set_socket_callback can be used to detect when new sockets are created and in turn initialize my libev watchers. 

However, I'm not sure of the correct way to detect when sockets are closed so that I can safely destroy libev watchers.  Is there a callback I'm missing that provides that information?  If not, any thoughts on where to insert it?


Jérémy Lal | 23 Apr 2012 22:52
Gravatar

Re: Integrating with libev

On 23/04/2012 22:31, Brian McFarland wrote:
> I'm using libev in my application and trying to figure out if c-ares is suitable for DNS.
> 
> My general thinking is that I'll use a libev io watcher per socket created by c-ares.  Then I'll just need to
call ares_process_fd when the watcher wakes up.  I'll also likely need a timer, which is probably as simple
as reseting a libev timer to ares_timeout() every time an I/O callback wakes up.
> 
> It looks like I can use the "ARES_OPT_SOCK_STATE_CB" to detect when I need to enable/disable my watchers
(i.e. event listeners) for each socket.
> 
> It also appears that ares_set_socket_callback can be used to detect when new sockets are created and in
turn initialize my libev watchers. 
> 
> However, I'm not sure of the correct way to detect when sockets are closed so that I can safely destroy libev
watchers.  Is there a callback I'm missing that provides that information?  If not, any thoughts on where to
insert it?

Hello,
i have no idea what you're talking about, except for one thing :
Node.js is using c-ares and libev too.

Regards,
Jérémy.

Daniel Stenberg | 23 Apr 2012 23:00
Picon
Favicon
Gravatar

Re: Integrating with libev

On Mon, 23 Apr 2012, Brian McFarland wrote:

> It looks like I can use the "ARES_OPT_SOCK_STATE_CB" to detect when I need 
> to enable/disable my watchers (i.e. event listeners) for each socket.
>
> It also appears that ares_set_socket_callback can be used to detect when
> new sockets are created and in turn initialize my libev watchers.

Yes, that's one way to do it. In libcurl we don't however and instead rely 
entirely on ares_getsock().

> However, I'm not sure of the correct way to detect when sockets are closed 
> so that I can safely destroy libev watchers.  Is there a callback I'm 
> missing that provides that information?  If not, any thoughts on where to 
> insert it?

The ARES_OPT_SOCK_STATE_CB callback is called on closes as well so it should 
be sufficient! Unless there are bugs...

--

-- 

  / daniel.haxx.se

Timo Teräs | 24 Apr 2012 15:56
Picon
Picon
Favicon

Re: Integrating with libev

On Mon, Apr 23, 2012 at 10:31 PM, Brian McFarland
<mcfarlandjb@...> wrote:
> I'm using libev in my application and trying to figure out if c-ares is
> suitable for DNS.
>
> My general thinking is that I'll use a libev io watcher per socket created
> by c-ares.  Then I'll just need to call ares_process_fd when the watcher
> wakes up.  I'll also likely need a timer, which is probably as simple as
> reseting a libev timer to ares_timeout() every time an I/O callback wakes
> up.
>
> It looks like I can use the "ARES_OPT_SOCK_STATE_CB" to detect when I need
> to enable/disable my watchers (i.e. event listeners) for each socket.
>
> It also appears that ares_set_socket_callback can be used to detect when new
> sockets are created and in turn initialize my libev watchers.
>
> However, I'm not sure of the correct way to detect when sockets are closed
> so that I can safely destroy libev watchers.  Is there a callback I'm
> missing that provides that information?  If not, any thoughts on where to
> insert it?

I used libev + ares for my opennhrp project. See:
http://opennhrp.git.sourceforge.net/git/gitweb.cgi?p=opennhrp/opennhrp;a=blob;f=nhrp/nhrp_address.c;hb=HEAD

-Timo

Brian McFarland | 24 Apr 2012 18:23
Picon

Re: Integrating with libev


Thanks Timo.  That's a great example that confirms what i'm trying to do is feasible.  Your design has prompted a few more questions.

So correct me if I'm wrong, but it looks like the ares_socket_callback() function is called whenever the sockets are created as well?   

How did you decide on keeping watchers for just 4 fd's at a time?  Is there something in your ares_opts or inherent to the nature of c-ares architecture that allowed for this decision?  It's also not entirely clear to me what happens if you exceed 4 fd's that need watching.

- Brian
Timo Teras | 25 Apr 2012 07:47
Picon
Picon
Favicon

Re: Integrating with libev

On Tue, 24 Apr 2012 12:23:40 -0400 Brian McFarland
<mcfarlandjb@...> wrote:

> Thanks Timo.  That's a great example that confirms what i'm trying to
> do is feasible.  Your design has prompted a few more questions.
> 
> So correct me if I'm wrong, but it looks like the
> ares_socket_callback() function is called whenever the sockets are
> created as well?

Yes, it seems that state callback is invoked also on socket creation.
However, you cannot distinguish really if it's created or deleted there
since in both cases readable and writable are 0. If you need to
allocate stuff on socket creation, you need to use the sock_create_cb.
(Checked version 1.7.5.)

Though, it doesn't matter for my code; it is enough to get called when
the socket is first started to be monitored.

> How did you decide on keeping watchers for just 4 fd's at a time?  Is
> there something in your ares_opts or inherent to the nature of c-ares
> architecture that allowed for this decision?  It's also not entirely
> clear to me what happens if you exceed 4 fd's that need watching.

No particular reason. It limits the concurrency; and my code does not
expect to do many parallel queries. If there's more queries pending,
NHRP_BUG_ON triggers runtime assertion.

Though, hmm, looking at my code again after a year, it might have a bug
in it. The fds[i].fd is not reset to -1 after a fd is no longer
monitored.

-Timo

Brian McFarland | 25 Apr 2012 17:30
Picon

Re: Integrating with libev

>Yes, it seems that state callback is invoked also on socket creation. 
>However, you cannot distinguish really if it's created or deleted there 
>since in both cases readable and writable are 0. If you need to 
>allocate stuff on socket creation, you need to use the sock_create_cb. 
>(Checked version 1.7.5.) 

I did some more digging around in the 1.7.5 code.  As far as I can tell, the socket state callback is always invoked through the macro SOCK_STATE_CALLBACK.  A simple find & grep shows that it is only called with 0/0 when closing the socket.  If you look at open_[tcp|udp]_socket() in ares_process.c, you'll see that SOCK_STATE_CALLBACK(channel, s, 1, 0) is called immediately after the sock_create_cb, but only if sock_create_cb return ARES_SUCCESS.   

So sock_create_cb, according to the current implementation, is definitely the appropriate place to allocate any per-connection memory since you can return ARES_ENOMEM if malloc fails.  As far as I can tell, that's the only way you can indicate to your gethostbyname callbacks that a malloc error occurred. 

Brian

Gmane