Question about integrating udns in Ruby EventMachine

Michael Tokarev mjt at tls.msk.ru
Tue Feb 8 22:10:07 MSK 2011


07.02.2011 13:18, Iñaki Baz Castillo пишет:
[]
> I've tested it with high traffic, by using 2 (non-)responding
> nameservers (NAMESERVERS="1.1.1.1 2.2.2.2"), with local working
> "unbound", and so on. And IMHO it's working very well, I get all the
> callbacks called (even when timeouts occur), retransmissions occur
> after 4-8 seconds. :)

> So IMHO my issue it solved, but perhaps I miss something in the above
> mechanims. However I'll investigate what you say about setting a call
> before poll/select (I strongly think this is not possible since
> EventMachine IO-evented core library is written in C/C++, but the API
> it provides is for Ruby language). Also note that my code depends on
> EventMachine as it is, this is, I cannot modify EventMachine C/C++
> core.
> 
> PS: I've read dns_set_tmcbck() documentation (NOTE: the manual says
> "dns_set_cbck()" but the existing name is "dns_set_tmcbck()" as you
> say). Honestly I don't understand how I could use such function,
> neither how to integrate it with EventMachine reactor. Anyhow, would
> it be better than my above approach?

Dunno about the "better" thing.

What I mean is something like this.  Pseudo-code.

 at init time:

  udns_timer = EventMachine::newTimer();
  dns_set_tmcbck(ctx, timer_fn, udns_timer);

The function:

void timer_fn(ctx, int timeout, timer) {
  if (!ctx)
     EventMachine::DestroyTimer(timer);
  else if (timeout < 0)
     EventMachine::StopTimer(timer);
  else if (timeout == 0)
     EventMachine::QueueTimerEvent(timer, dns_timeouts);
  else
     EventMachine::StartTimer(timer, timeout, dns_timeouts);
}

I don't know which code should be ruby and which
should be C.  Ruby is able to call C code, and
C code - probably - is able to call Ruby code, but
I'm not sure.  So maybe it will be Ruby code calling
some C routines.

Basically, you register a function with udns which will
be called by the library when time-related things are changed.
By calling this function, the library tells your event machine
about these changes.

Let me illustrate this based on an example.

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".

2. When this "after now" happens, EventMachine calls the
provided callback routine, which is dns_timeouts().  udns
executes your query by sending appropriate UDP packet.

3. now udns has a 2-second timeout to wait for the reply
(the control is still in the dns_timeouts() routine).
udns calls the timer callback (timer_fn above) again,
now with "2" as the timeout value - it means "call my
dns_timeouts() routine after 2 seconds".

4. your timer_fn() renews the timer with EventMachine,
to fire after 2 seconds.

5. Now we've one of two choices: either the nameserver
responds, in which case dns_ioevent() will be called
and udns will cancel the 2-second timer by calling the
same timer_fn routine again with timeout=-1;
or, in case there will be no reply, EventMachine will
fire dns_timeouts() after 2sec delay, and in that case
dns_timeouts() will send another query, and call your
timer_fn with timeout=4 to fire it after 4 seconds.

And so on.

When you submit more queries, this timer will be set
and reset multiple times, according to internal udns
logic.

So if you can't hook into the pre-poll() point, you
should have ability to use timers in a way similar
to above, and this is the alternative designed especially
for this case - clean and more or less understandable.

Or I hope anyway... ;)

/mj


More information about the udns mailing list