Implement getaddrinfo_a based DNS lookup for Linux.

This commit is contained in:
Sönke Ludwig 2016-10-16 23:01:22 +02:00
parent bdaff3264f
commit 270543d3d8
2 changed files with 52 additions and 24 deletions

View file

@ -5,6 +5,8 @@ copyright "Copyright © 2012-2016 rejectedsoftware e.K."
targetType "library" targetType "library"
libs "anl" platform="linux"
configuration "native" { configuration "native" {
} }

View file

@ -49,8 +49,8 @@ final class PosixEventDriver(Loop : PosixEventLoop) : EventDriver {
alias SignalsDriver = PosixEventDriverSignals!Loop; alias SignalsDriver = PosixEventDriverSignals!Loop;
alias TimerDriver = LoopTimeoutTimerDriver; alias TimerDriver = LoopTimeoutTimerDriver;
alias SocketsDriver = PosixEventDriverSockets!Loop; alias SocketsDriver = PosixEventDriverSockets!Loop;
/*version (linux) alias DNSDriver = EventDriverDNS_GAIA!(EventsDriver, SignalsDriver); version (linux) alias DNSDriver = EventDriverDNS_GAIA!(EventsDriver, SignalsDriver);
else*/ alias DNSDriver = EventDriverDNS_GAI!(EventsDriver, SignalsDriver); else alias DNSDriver = EventDriverDNS_GAI!(EventsDriver, SignalsDriver);
alias FileDriver = ThreadedFileEventDriver!EventsDriver; alias FileDriver = ThreadedFileEventDriver!EventsDriver;
alias WatcherDriver = PosixEventDriverWatchers!Loop; alias WatcherDriver = PosixEventDriverWatchers!Loop;
@ -857,14 +857,7 @@ final class EventDriverDNS_GAI(Events : EventDriverEvents, Signals : EventDriver
/// getaddrinfo+thread based lookup - does not support true cancellation /// getaddrinfo+thread based lookup - does not support true cancellation
final class EventDriverDNS_GAIA(Events : EventDriverEvents, Signals : EventDriverSignals) : EventDriverDNS { final class EventDriverDNS_GAIA(Events : EventDriverEvents, Signals : EventDriverSignals) : EventDriverDNS {
import core.sys.posix.signal : SIGRTMIN; import core.sys.posix.signal : SIGEV_SIGNAL, SIGRTMIN, sigevent;
private static extern(C) struct gaicb {
const(char)* ar_name;
const(char)* ar_service;
const(addrinfo)* ar_request;
addrinfo* ar_result;
};
private { private {
static struct Lookup { static struct Lookup {
@ -874,6 +867,7 @@ final class EventDriverDNS_GAIA(Events : EventDriverEvents, Signals : EventDrive
ChoppedVector!Lookup m_lookups; ChoppedVector!Lookup m_lookups;
Signals m_signals; Signals m_signals;
int m_dnsSignal; int m_dnsSignal;
SignalListenID m_sighandle;
} }
@safe nothrow: @safe nothrow:
@ -882,24 +876,26 @@ final class EventDriverDNS_GAIA(Events : EventDriverEvents, Signals : EventDrive
{ {
m_signals = signals; m_signals = signals;
m_dnsSignal = () @trusted { return SIGRTMIN; } (); m_dnsSignal = () @trusted { return SIGRTMIN; } ();
signals.wait(m_dnsSignal, &onDNSSignal); m_sighandle = signals.listen(m_dnsSignal, &onDNSSignal);
} }
void dispose() void dispose()
{ {
m_signals.cancelWait(m_dnsSignal); m_signals.releaseRef(m_sighandle);
} }
override DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished) override DNSLookupID lookupHost(string name, DNSLookupCallback on_lookup_finished)
{ {
import std.string : toStringz;
auto handle = getFreeHandle(); auto handle = getFreeHandle();
sigevent evt; sigevent evt;
evt.sigev_notify = SIGEV_SIGNAL; evt.sigev_notify = SIGEV_SIGNAL;
evt.sigev_signo = m_dnsSignal; evt.sigev_signo = m_dnsSignal;
evt.sigev_value = handle; gaicb* res = &m_lookups[handle].ctx;
gaicb[16] res; res.ar_name = name.toStringz();
auto ret = getaddrinfo_a(GAI_NOWAIT, &res[0], res.length, &evp); auto ret = () @trusted { return getaddrinfo_a(GAI_NOWAIT, &res, 1, &evt); } ();
if (ret != 0) if (ret != 0)
return DNSLookupID.invalid; return DNSLookupID.invalid;
@ -911,29 +907,59 @@ final class EventDriverDNS_GAIA(Events : EventDriverEvents, Signals : EventDrive
override void cancelLookup(DNSLookupID handle) override void cancelLookup(DNSLookupID handle)
{ {
gai_cancel(m_lookups[handle]); gai_cancel(&m_lookups[handle].ctx);
m_lookups[handle].callback = null; m_lookups[handle].callback = null;
} }
private void onDNSSignal(int signal, int value) private void onDNSSignal(SignalListenID, SignalStatus status, int signal)
@safe nothrow @safe nothrow
{ {
auto cb = m_lookups[value].callback; assert(status == SignalStatus.ok);
auto ai = m_lookups[value].ctx.ar_result; foreach (i, l; m_lookups) {
m_lookups[value].callback = null; if (!l.callback) continue;
m_lookups[value].ctx.ar_result = null; auto err = gai_error(&l.ctx);
passToDNSCallback(cast(DNSLookupID)value, cb, ai); if (err == EAI_INPROGRESS) continue;
DNSStatus status;
switch (err) {
default: status = DNSStatus.error; break;
case 0: status = DNSStatus.ok; break;
}
auto cb = l.callback;
auto ai = l.ctx.ar_result;
l.callback = null;
l.ctx.ar_result = null;
passToDNSCallback(cast(DNSLookupID)cast(int)i, cb, status, ai);
}
} }
private DNSLookupID getFreeHandle() private DNSLookupID getFreeHandle()
{ {
foreach (i, ref l; m_lookups) foreach (i, ref l; m_lookups)
if (!l.callback) if (!l.callback)
return i; return cast(DNSLookupID)cast(int)i;
return m_lookups.length; return cast(DNSLookupID)cast(int)m_lookups.length;
} }
} }
version (linux) extern(C) {
import core.sys.posix.signal : sigevent;
struct gaicb {
const(char)* ar_name;
const(char)* ar_service;
const(addrinfo)* ar_request;
addrinfo* ar_result;
}
enum GAI_NOWAIT = 1;
enum EAI_INPROGRESS = -100;
int getaddrinfo_a(int mode, gaicb** list, int nitems, sigevent *sevp);
int gai_error(gaicb *req);
int gai_cancel(gaicb *req);
}
private void passToDNSCallback(DNSLookupID id, scope DNSLookupCallback cb, DNSStatus status, addrinfo* ai_orig) private void passToDNSCallback(DNSLookupID id, scope DNSLookupCallback cb, DNSStatus status, addrinfo* ai_orig)
@trusted nothrow @trusted nothrow
{ {