Question about integrating udns in Ruby EventMachine

Michael Tokarev mjt at tls.msk.ru
Sun Feb 6 23:11:15 MSK 2011


06.02.2011 20:31, Iñaki Baz Castillo wrote:
> 2011/2/1 Michael Tokarev <mjt at tls.msk.ru>:
>> udns knows when next query
>> will expire, your application calls provided function -- dns_timeouts() --
>> to perform two tasks: 1) process expired queries, and 2) determine
>> when next query will expire.  The second case is used in the
>> main event loop to determine how much time we can sleep waiting
>> for next event.
> 
> Please let me know if I'm wrong in some point:
> 
> The application using udns must:
> 
> 1) Do poll/select on the UDP socket opened by udns.
> 2) Invoke dns_ioevents() when data is ready to read.
> 3) dns_ioevents() calls application provided callback for each query
> for which there is a response.
> 
> I have these 3 points perfectly working in my EventMachine library using udns.
> 
> 4) The application must also invoke dns_timeouts() periodically to
> trigger the execution of the callback when timeout occurs for a query
> (so dns_status() returns DNS_E_TEMPFAIL).

You call dns_timeouts() right before poll/select, to process
any expired entries and to determine the timeout to use for
poll/select call, as I demonstrated in my first reply, and
as shown in example code.

> 5) dns_timeouts() returns the number of second remaining until the
> first query expires, so the application just has to invoke
> dns_timeouts() again after those ammout of seconds.

No, you invoke dns_timeouts() before each poll/select.

> - Why must I call dns_timeouts() after dns_submit_xxx() ?. If I dont'
> call dns_timeouts() then I don't see outgoing UDP-DNS traffic.

Because all newly submitted queries are queued (with zero timeout).
Or else, if queries will be sent right away, especially with
error handling, the application will have hard time figuring out
why just submitted query has been processed already (due to
errors sending it or whatnot).

> - I've realized that, in case of a non responding DNS server (i.e:
> 1.2.3.4) then dns_timeouts() returns the number of second after next
> retransmission of the request (which is not a real timeout yet as the
> callback is not executed with DNS_E_TEMPFAIL). This is, my example

The only place to use value returned by dns_timeouts() is to
calculate time to pass to poll/select.  There's no other usage
for that.

> code invokes dns_submit_xxx(), then dns_timeouts(), and periodically
> invokes dns_timeouts() and prints its return value. I get this:
> 
>   - sec  0: DNS request sent. dns_timeouts returns 4.
>   - sec  4: retransmission sent. dns_timeouts returns 8.
>   - sec 12: retransmission sent. dns_timeouts returns 16.
>   - sec 28: callback is called with DNS_E_TEMPFAIL. dns_timeouts
> returns -1 (no pending timeouts).

> So:
> - If I don't call dns_timeout after first 4 seconds a retransmission
> is not sent, so dns_timeouts is needed, but why is it required after
> calling dns_submit_xxx()?

See above.  Just call dns_timeouts() before poll/select.

> BTW I suppose 4-8-16 seconds are the default DNS retransmission
> timers. Can I modify these values in udns?

Yes, there's number of seconds to wait and number of retries.
Can be set in resolv.conf, RESOLV_OPTIONS or programmatically.

> And last question (sorry for so long mail):
> 
>    dns_timeouts(ctx, int maxwait, time_t now)
> 
> - What is the purpose of maxwait? I know what it does (for example it
> makes dns_timeouts to return 4 even if next timeout will occur after 8
> seconds). Why is it useful?

If you've other timeouts from other parts of the code, that'll
be a convenient way to calculate the minimum.  Since it's not
really minimum (-1 is treated as infinite) you can't just call
min(timeout1, timeout2).  So dns_timeouts() will calculate
minimum for you.

> - Is it safe to use 0 as "now" parameter? when is useful to use any
> other value or time(NULL)?

Yes you can use 0, in which case the library will call time()
by its own, or you can pass time(NULL) there.  The parameter
is here to minimize amount of system calls needed.  You,
most likely, already have the "now" value after you called
select/poll (to watch for your own timers), so there's no
need to call time() again, just pass it to dns_timeouts()
and dns_ioevents().  Just like in the examples - watch them
carefully.

/mjt


More information about the udns mailing list