EV-cares
view release on metacpan or search on metacpan
CONST_IV(stash, T_TXT);
CONST_IV(stash, T_AAAA);
CONST_IV(stash, T_SRV);
CONST_IV(stash, T_NAPTR);
CONST_IV(stash, T_DS);
CONST_IV(stash, T_RRSIG);
CONST_IV(stash, T_DNSKEY);
CONST_IV(stash, T_TLSA);
CONST_IV(stash, T_SVCB);
CONST_IV(stash, T_HTTPS);
CONST_IV(stash, T_CAA);
CONST_IV(stash, T_ANY);
/* DNS classes */
CONST_IV(stash, C_IN);
CONST_IV(stash, C_CHAOS);
CONST_IV(stash, C_HS);
CONST_IV(stash, C_ANY);
/* channel flags */
CONST_IV(stash, ARES_FLAG_USEVC);
CONST_IV(stash, ARES_FLAG_PRIMARY);
CONST_IV(stash, ARES_FLAG_IGNTC);
CONST_IV(stash, ARES_FLAG_NORECURSE);
CONST_IV(stash, ARES_FLAG_STAYOPEN);
CONST_IV(stash, ARES_FLAG_NOSEARCH);
CONST_IV(stash, ARES_FLAG_NOALIASES);
CONST_IV(stash, ARES_FLAG_NOCHECKRESP);
CONST_IV(stash, ARES_FLAG_EDNS);
CONST_IV(stash, ARES_FLAG_NO_DFLT_SVR);
CONST_IV(stash, ARES_FLAG_DNS0x20);
/* addrinfo hint flags */
CONST_IV(stash, ARES_AI_CANONNAME);
CONST_IV(stash, ARES_AI_NUMERICHOST);
CONST_IV(stash, ARES_AI_PASSIVE);
CONST_IV(stash, ARES_AI_NUMERICSERV);
CONST_IV(stash, ARES_AI_V4MAPPED);
CONST_IV(stash, ARES_AI_ALL);
CONST_IV(stash, ARES_AI_ADDRCONFIG);
CONST_IV(stash, ARES_AI_NOSORT);
/* nameinfo flags */
CONST_IV(stash, ARES_NI_NOFQDN);
CONST_IV(stash, ARES_NI_NUMERICHOST);
CONST_IV(stash, ARES_NI_NAMEREQD);
CONST_IV(stash, ARES_NI_NUMERICSERV);
CONST_IV(stash, ARES_NI_DGRAM);
CONST_IV(stash, ARES_NI_TCP);
CONST_IV(stash, ARES_NI_UDP);
/* address families */
CONST_IV(stash, AF_INET);
CONST_IV(stash, AF_INET6);
CONST_IV(stash, AF_UNSPEC);
}
}
void
new(class, ...)
PPCODE:
{
const char *class_name = SvPV_nolen(ST(0));
ev_cares_t *self;
struct ares_options opts;
int optmask = 0;
int status, i;
const char *servers = NULL;
struct ev_loop *loop_ptr = EV_DEFAULT;
SV *loop_sv = NULL;
if ((items - 1) % 2 != 0)
croak("EV::cares::new: odd number of arguments");
memset(&opts, 0, sizeof(opts));
for (i = 1; i < items; i += 2) {
const char *key = SvPV_nolen(ST(i));
SV *val = ST(i + 1);
if (strEQ(key, "loop")) {
if (SvOK(val)) {
if (!SvROK(val) || !sv_derived_from(val, "EV::Loop"))
croak("EV::cares::new: 'loop' must be an EV::Loop instance");
/* SvIV (not SvIVX) so any get-magic on the inner SV is
honoured before extracting the loop pointer. */
loop_ptr = INT2PTR(struct ev_loop *, SvIV(SvRV(val)));
loop_sv = val; /* refcount bumped after struct alloc */
}
}
else if (strEQ(key, "timeout")) {
opts.timeout = (int)(SvNV(val) * 1000);
optmask |= ARES_OPT_TIMEOUTMS;
}
else if (strEQ(key, "tries")) {
opts.tries = SvIV(val);
optmask |= ARES_OPT_TRIES;
}
else if (strEQ(key, "ndots")) {
opts.ndots = SvIV(val);
optmask |= ARES_OPT_NDOTS;
}
else if (strEQ(key, "flags")) {
opts.flags = SvIV(val);
optmask |= ARES_OPT_FLAGS;
}
else if (strEQ(key, "lookups")) {
opts.lookups = SvPV_nolen(val); /* c-ares copies internally */
optmask |= ARES_OPT_LOOKUPS;
}
else if (strEQ(key, "tcp_port")) {
opts.tcp_port = (unsigned short)SvUV(val);
optmask |= ARES_OPT_TCP_PORT;
}
else if (strEQ(key, "udp_port")) {
opts.udp_port = (unsigned short)SvUV(val);
optmask |= ARES_OPT_UDP_PORT;
}
else if (strEQ(key, "servers")) {
if (SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVAV) {
AV *av = (AV *)SvRV(val);
else if (family == AF_INET6) min_len = sizeof(struct sockaddr_in6);
else croak("EV::cares::getnameinfo: unsupported sockaddr family %d "
"(need AF_INET or AF_INET6)", (int)family);
if (len < min_len)
croak("EV::cares::getnameinfo: sockaddr too short for %s (%d bytes)",
family == AF_INET6 ? "AF_INET6" : "AF_INET", (int)len);
req = new_req(aTHX_ self, cb);
ARES_CALL_BEGIN(self);
ares_getnameinfo(self->channel, (const struct sockaddr *)&ss,
(ares_socklen_t)len, flags, nameinfo_cb, req);
ARES_CALL_END(self);
}
void
cancel(self)
EV::cares self
CODE:
REQUIRE_LIVE(self);
ARES_CALL_BEGIN(self);
ares_cancel(self->channel);
ARES_CALL_END(self);
void
set_servers(self, ...)
EV::cares self
CODE:
{
SV *csv;
int rc, i;
REQUIRE_LIVE(self);
if (items <= 1)
croak("EV::cares::set_servers: requires at least one server address");
/* accept either a single arrayref or a flat list, mirroring `new(servers => ...)` */
if (items == 2 && SvROK(ST(1)) && SvTYPE(SvRV(ST(1))) == SVt_PVAV) {
AV *av = (AV *)SvRV(ST(1));
if (av_len(av) < 0)
croak("EV::cares::set_servers: empty arrayref");
csv = av_to_csv(aTHX_ av);
} else {
csv = sv_2mortal(newSVpvs(""));
for (i = 1; i < items; i++) {
if (SvROK(ST(i)))
croak("EV::cares::set_servers: arg %d is a reference; "
"use the arrayref form for {host,port} hashrefs", i);
if (i > 1) sv_catpvs(csv, ",");
sv_catsv(csv, ST(i));
}
}
rc = ares_set_servers_csv(self->channel, SvPV_nolen(csv));
if (rc != ARES_SUCCESS)
croak("EV::cares::set_servers: %s", ares_strerror(rc));
}
void
servers(self)
EV::cares self
PPCODE:
{
char *csv;
REQUIRE_LIVE(self);
csv = ares_get_servers_csv(self->channel);
if (!csv) croak("EV::cares::servers: ares_get_servers_csv failed");
mXPUSHp(csv, strlen(csv));
ares_free_string(csv);
}
void
set_local_dev(self, dev)
EV::cares self
const char *dev
CODE:
REQUIRE_LIVE(self);
ares_set_local_dev(self->channel, dev);
void
set_local_ip4(self, ip)
EV::cares self
const char *ip
CODE:
{
struct in_addr addr;
REQUIRE_LIVE(self);
if (inet_pton(AF_INET, ip, &addr) != 1)
croak("EV::cares::set_local_ip4: invalid IPv4 address: %s", ip);
ares_set_local_ip4(self->channel, ntohl(addr.s_addr));
}
void
set_local_ip6(self, ip)
EV::cares self
const char *ip
CODE:
{
struct in6_addr addr;
REQUIRE_LIVE(self);
if (inet_pton(AF_INET6, ip, &addr) != 1)
croak("EV::cares::set_local_ip6: invalid IPv6 address: %s", ip);
ares_set_local_ip6(self->channel, (const unsigned char *)&addr);
}
int
active_queries(self)
EV::cares self
CODE:
RETVAL = self->active_queries;
OUTPUT:
RETVAL
int
last_query_timeouts(self)
EV::cares self
CODE:
RETVAL = self->last_timeouts;
OUTPUT:
RETVAL
int
( run in 0.942 second using v1.01-cache-2.11-cpan-5511b514fd6 )