Question about integrating udns in Ruby EventMachine

Michael Tokarev mjt at tls.msk.ru
Wed Feb 9 09:41:33 MSK 2011


09.02.2011 01:59, Iñaki Baz Castillo wrote:

>> 1. You submit a first query to udns.  It calls the callback routine (timer_fn above) with zero timeout, to mean "queue the timer event right at next main loop cycle", or "queue this timer to fire right after now".
> 
> Question: couldn't dns_timeout() be called right "now" rather than in
> the very next loop cycle? which is the difference? (assuming I don't
> need to run more code after calling dns_submit_xxx). This is:
> 
> void timer_fn(ctx, int timeout, timer) {
>  if (!ctx)
>     EventMachine::DestroyTimer(timer);
>  else if (timeout < 0)
>     EventMachine::StopTimer(timer);
>  else if (timeout == 0)
>     dns_timeouts();
>  else
>     EventMachine::StartTimer(timer, timeout, dns_timeouts);
> }

Don't do that, queue it instead of firing it right away.
If it were possible to do it "now" there'd be no need to
queue such timer.  If you call it right away you're risking
to get too deep recursion and memory corruption.

For example, suppose there's an error with the UDP socket
in use, any sort of error, so that sending to it does not
work.

You submit query to udns.  It asks your callback to queue
"after now" event.  Your callback executes dns_timeouts()
rigth away without queing it.  dns_timeouts() tries to
send the query, but encounters the error.  So it calls
query-specific callback, so the control is again in your
application.  The application sees error resolving the
query, so it submits a new query using dns_submit() (it
has many queries to do but has a limit of N queries at
a time like ex-rdns.c).  And we're in a recursive loop:

 your code -> dns_submit()
  udns calls tmcbck() -> timer_fn()
   timer_fn() calls dns_timeouts()
    dns_timeouts() calls query callback
     query callback submits another query, dns_submit()
      udns calls tmcbck() -> timer_fn()
       ...

Think about this from a different angle.  Your code may
want to check value returned from dns_submit(), in order
to watch its completion or something - for example the
way I already described, when only one of two queries
is interesting so the other query will be cancelled.
But when - finally - first dns_submit() will return,
the pointer it returned is already invalid (it becomes
invalid after query callback finishes).  You'll get
memory corruption.

That's why the library _queues_ the "timer" to "next to
now" instead of running your callbacks right away, to
keep all this things under control.

How _you_ use it is your call.. ;)

/mjt


More information about the udns mailing list