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"
libs "anl" platform="linux"
configuration "native" {
}

View file

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