local tquery = {"www.lua.org", "lua-users.org","localhost"}
if #arg > 0 then tquery = arg end
local n = #tquery
local ffi = require "ffi"
local bit = require "bit"
local anl = ffi.load "anl"
ffi.cdef[[
char *strerror(int errnum);
typedef struct {
unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))];
} sigset_t;
typedef int pid_t;
enum {
SIGEV_SIGNAL = 0,
SIGEV_NONE,
SIGEV_THREAD,
SIGEV_THREAD_ID = 4
};
int sigemptyset(sigset_t *set);
int sigaddset(sigset_t *set, int signum);
int sigprocmask(int how, const sigset_t *restrict set,
sigset_t *restrict oset);
extern int __libc_current_sigrtmin (void);
struct signalfd_siginfo {
uint32_t ssi_signo; /* Signal number */
int32_t ssi_errno; /* Error number (unused) */
int32_t ssi_code; /* Signal code */
uint32_t ssi_pid; /* PID of sender */
uint32_t ssi_uid; /* Real UID of sender */
int32_t ssi_fd; /* File descriptor (SIGIO) */
uint32_t ssi_tid; /* Kernel timer ID (POSIX timers)
uint32_t ssi_band; /* Band event (SIGIO) */
uint32_t ssi_overrun; /* POSIX timer overrun count */
uint32_t ssi_trapno; /* Trap number that caused signal */
int32_t ssi_status; /* Exit status or signal (SIGCHLD) */
int32_t ssi_int; /* Integer sent by sigqueue(3) */
uint64_t ssi_ptr; /* Pointer sent by sigqueue(3) */
uint64_t ssi_utime; /* User CPU time consumed (SIGCHLD) */
uint64_t ssi_stime; /* System CPU time consumed (SIGCHLD) */
uint64_t ssi_addr; /* Address that generated signal (for hardware-generated signals) */
uint8_t pad[48]; /* Pad size to 128 bytes (allow for additional fields in the future) */
};
enum {
SFD_CLOEXEC = 02000000,
SFD_NONBLOCK = 04000
};
int signalfd(int fd, const sigset_t *mask, int flags);
union sigval { /* Data passed with notification */
int sival_int; /* Integer value */
void *sival_ptr; /* Pointer value */
};
struct sigevent {
int sigev_notify; /* Notification method */
int sigev_signo; /* Notification signal */
union sigval sigev_value; /* Data passed with notification */
void (*sigev_notify_function) (union sigval);
/* Function used for thread notification (SIGEV_THREAD) */
void *sigev_notify_attributes;
/* Attributes for notification thread (SIGEV_THREAD) */
pid_t sigev_notify_thread_id;
/* ID of thread to signal (SIGEV_THREAD_ID) */
};
void free(void *ptr);
void *calloc(size_t nmemb, size_t size);
typedef long int ssize_t;
ssize_t read(int fd, void *buf, size_t count);
enum
{
SI_ASYNCNL = -60,
SI_TKILL = -6,
SI_SIGIO,
SI_ASYNCIO,
SI_MESGQ,
SI_TIMER,
SI_QUEUE,
SI_USER,
SI_KERNEL = 0x80
};
const char *gai_strerror(int errcode);
struct gaicb {
const char *ar_name;
const char *ar_service;
const struct addrinfo *ar_request;
struct addrinfo *ar_result;
int __return;
int __unused[5];
};
int getaddrinfo_a(int mode, struct gaicb *list[], int nitems, struct sigevent *sevp);
int gai_error(struct gaicb *req);
int gai_cancel(struct gaicb *req);
]]
SIG_BLOCK = 0 -- Block signals.
SIGUSR1 = 10
EAGAIN = 11
GAI_WAIT = 0
GAI_NOWAIT = 1
EAI_BADFLAGS = -1 -- Invalid value for `ai_flags' field.
EAI_NONAME = -2 -- NAME or SERVICE is unknown.
EAI_AGAIN = -3 -- Temporary failure in name resolution.
EAI_FAIL = -4 -- Non-recoverable failure in name res.
EAI_FAMILY = -6 -- `ai_family' not supported.
EAI_SOCKTYPE = -7 -- `ai_socktype' not supported.
EAI_SERVICE = -8 -- SERVICE not supported for `ai_socktype'.
EAI_MEMORY = -10 -- Memory allocation failure.
EAI_SYSTEM = -11 -- System error returned in `errno'.
EAI_OVERFLOW = -12 -- Argument buffer overflow.
EAI_NODATA = -5 -- No address associated with NAME.
EAI_ADDRFAMILY = -9 -- Address family for NAME not supported.
EAI_INPROGRESS = -100 -- Processing request in progress.
EAI_CANCELED = -101 -- Request canceled.
EAI_NOTCANCELED = -102 -- Request not canceled.
EAI_ALLDONE = -103 -- All requests done.
EAI_INTR = -104 -- Interrupted by a signal.
EAI_IDN_ENCODE = -105 -- IDN encoding failed.
NI_MAXSERV = 32
NI_MAXHOST = 1025
NI_NUMERICHOST = 1
NI_NUMERICSERV = 2
NI_NOFQDN = 4
NI_NAMEREQD = 8
NI_DGRAM = 16
local function addrinfo_to_string ( sockaddr , addr_len )
local host_len = NI_MAXHOST or 1025
local host = ffi.new ( "char[?]" , host_len )
local serv_len = NI_MAXSERV or 32
local serv = ffi.new ( "char[?]" , serv_len )
local flags = bit.bor ( NI_NUMERICHOST , NI_NUMERICSERV )
local err = ffi.C.getnameinfo ( sockaddr , addr_len , host , host_len , serv , serv_len , flags )
if err ~= 0 then
error ( ffi.string ( ffi.C.gai_strerror ( err ) ) )
end
return ffi.string ( host ) , ffi.string ( serv )
end
local signum = ffi.C.__libc_current_sigrtmin()
local mask = ffi.new ( "sigset_t[1]" )
ffi.C.sigemptyset ( mask )
ffi.C.sigaddset ( mask, signum )
if ffi.C.sigprocmask ( SIG_BLOCK, mask, nil ) == -1 then
error ( ffi.string ( ffi.C.strerror( ffi.errno() ) ) )
end
for i=1,1e3 do
local sfd = ffi.C.signalfd ( -1, mask, 0 )
if sfd == -1 then
error ( ffi.string ( ffi.C.strerror( ffi.errno() ) ) )
end
local list = ffi.new ( "struct gaicb*[?]",n )
for j=1,n do
local a = ffi.cast ( "struct gaicb*" , ffi.C.calloc ( 1 , ffi.sizeof("struct gaicb") ) )
if a == ffi.NULL then error("No Memory") end
a[0].ar_name = tquery[j]
list[j-1] = a
end
local sigevent = ffi.new ( "struct sigevent" )
sigevent.sigev_notify = ffi.C.SIGEV_SIGNAL
sigevent.sigev_signo = signum
sigevent.sigev_value.sival_ptr = list
local r = anl.getaddrinfo_a ( GAI_NOWAIT, list , n , sigevent )
if r ~= 0 then
error ( ffi.string ( ffi.C.strerror ( r ) ) )
end
local info = ffi.new ( "struct signalfd_siginfo[1]" )
local r = ffi.C.read ( sfd , info, ffi.sizeof(info) )
if r == -1 then
error ( ffi.string ( ffi.C.strerror ( ffi.errno() ) ) )
end
assert ( r == ffi.sizeof( info ) )
assert ( info[0].ssi_code == ffi.C.SI_ASYNCNL )
local list = ffi.cast ( "struct gaicb**" , info[0].ssi_ptr ) --t[ info[0].ssi_int ]
for j=1,n do
local r = anl.gai_error( list[j-1] )
if r ~= 0 then
print(string.format("FAILURE: %30s: %s", ffi.string( list[j-1].ar_name ), ffi.string ( anl.gai_strerror(r) ) ) )
else
print(string.format("SUCCESS: %30s: %s %s", ffi.string ( list[j-1].ar_name ), addrinfo_to_string ( list[j-1].ar_result.ai_addr, list[j-1].ar_result.ai_addrlen ) ) )
end
ffi.C.free(list[j-1])
end
io.stdout:write("\n")
end
print("DONE")
local err = anl.gai_cancel(nil)
if err ~= EAI_ALLDONE then
error ( anl.gai_strerror ( err ) )
end
print("And canceled")