NAME EV::cares - high-performance async DNS resolver using c-ares and EV SYNOPSIS use EV; use EV::cares qw(:status :types); my $r = EV::cares->new( servers => ['8.8.8.8', '1.1.1.1'], timeout => 5, tries => 3, ); # simple A + AAAA resolve $r->resolve('example.com', sub { my ($status, @addrs) = @_; if ($status == ARES_SUCCESS) { print "resolved: @addrs\n"; } else { warn "failed: " . EV::cares::strerror($status) . "\n"; } }); # auto-parsed DNS search $r->search('example.com', T_MX, sub { my ($status, @mx) = @_; printf "MX %d %s\n", $_->{priority}, $_->{host} for @mx; }); # raw DNS query $r->query('example.com', C_IN, T_A, sub { my ($status, $buf) = @_; # $buf is the raw DNS response packet }); EV::run; DESCRIPTION EV::cares integrates the c-ares asynchronous DNS library directly with the EV event loop at the C level. Socket I/O and timer management happen entirely in XS with zero Perl-level event processing overhead. Multiple queries run concurrently. c-ares handles server rotation, retries, timeouts, and search-domain appending. Requires c-ares >= 1.22.0 (provided automatically by Alien::cares). CONSTRUCTOR new my $r = EV::cares->new(%opts); All options are optional. servers => \@addrs | "addr1,addr2,..." DNS server addresses. Default: system resolv.conf servers. timeout => $seconds Per-try timeout (fractional seconds). maxtimeout => $seconds Maximum total timeout across all tries. tries => $n Number of query attempts. ndots => $n Threshold for treating a name as absolute (skip search suffixes). flags => $flags Bitmask of "ARES_FLAG_*" constants. lookups => $string Lookup order: "b" for DNS, "f" for /etc/hosts. rotate => 1 Round-robin among servers. tcp_port => $port udp_port => $port Non-standard DNS port. ednspsz => $bytes EDNS0 UDP payload size. resolvconf => $path Path to an alternative resolv.conf. hosts_file => $path Path to an alternative hosts file. udp_max_queries => $n Max queries per UDP connection before reconnect. qcache => $max_ttl Enable query result cache; $max_ttl is the upper TTL bound in seconds. 0 disables the cache. QUERY METHODS Every query method takes a callback as the last argument. The first argument to the callback is always a status code ("ARES_SUCCESS" on success). resolve $r->resolve($name, sub { my ($status, @addrs) = @_ }); Resolves $name via "ares_getaddrinfo" with "AF_UNSPEC", returning both IPv4 and IPv6 address strings. getaddrinfo $r->getaddrinfo($node, $service, \%hints, $cb); Full getaddrinfo. $service and "\%hints" may be "undef". Hint keys: "family", "socktype", "protocol", "flags" ("ARES_AI_*"). Callback receives "($status, @ip_strings)". search $r->search($name, $type, sub { my ($status, @records) = @_ }); DNS search (appends search domains from resolv.conf), always using "C_IN" class. Results are auto-parsed based on $type: T_A, T_AAAA ($status, @ip_strings) T_MX ($status, @{ {priority, host} }) T_SRV ($status, @{ {priority, weight, port, target} }) T_TXT ($status, @strings) T_NS ($status, @hostnames) T_SOA ($status, {mname, rname, serial, refresh, retry, expire, minttl}) T_PTR ($status, @hostnames) T_NAPTR ($status, @{ {order, preference, flags, service, regexp, replacement} }) T_CAA ($status, @{ {critical, property, value} }) T_CNAME etc. ($status, $raw_buffer) query $r->query($name, $class, $type, sub { my ($status, $buf) = @_ }); Raw DNS query without search-domain appending. Returns the unmodified DNS response packet. gethostbyname $r->gethostbyname($name, $family, sub { my ($status, @addrs) = @_ }); Legacy resolver. $family is "AF_INET" or "AF_INET6". reverse $r->reverse($ip, sub { my ($status, @hostnames) = @_ }); Reverse DNS (PTR) lookup for an IPv4 or IPv6 address string. getnameinfo $r->getnameinfo($packed_sockaddr, $flags, sub { my ($status, $node, $service) = @_; }); Full getnameinfo. $packed_sockaddr comes from "pack_sockaddr_in" in Socket or "pack_sockaddr_in6" in Socket. $flags is a bitmask of "ARES_NI_*" constants. CHANNEL METHODS cancel Cancel all pending queries. Each outstanding callback fires with "ARES_ECANCELLED". set_servers $r->set_servers('8.8.8.8', '1.1.1.1'); Replace the DNS server list. servers my $csv = $r->servers; # "8.8.8.8,1.1.1.1" Returns the current server list as a comma-separated string. set_local_dev $r->set_local_dev('eth0'); Bind outgoing queries to a network device. set_local_ip4 $r->set_local_ip4('192.168.1.100'); Bind outgoing queries to a local IPv4 address. set_local_ip6 $r->set_local_ip6('::1'); Bind outgoing queries to a local IPv6 address. active_queries my $n = $r->active_queries; Returns the number of outstanding queries. reinit $r->reinit; Re-read system DNS configuration (resolv.conf, hosts file) without destroying the channel. Useful for long-running daemons where the resolver configuration may change at runtime. destroy $r->destroy; Explicitly release the c-ares channel and stop all watchers. Pending callbacks fire with "ARES_ECANCELLED" or "ARES_EDESTRUCTION". Safe to call from within a callback. Also called automatically when the object is garbage-collected. FUNCTIONS strerror my $msg = EV::cares::strerror($status); my $msg = EV::cares->strerror($status); # also works Returns a human-readable string for a status code. lib_version my $ver = EV::cares::lib_version(); # e.g. "1.34.6" Returns the c-ares library version string. CALLBACK SAFETY Callbacks are invoked from within "ares_process_fd", called from EV I/O and timer watchers. Exceptions thrown inside callbacks are caught ("G_EVAL") and emitted as warnings; they do not propagate to the caller. It is safe to call "cancel", "destroy", or "undef" the resolver from within a callback. Remaining pending queries will receive "ARES_ECANCELLED". Lookups that use only local sources ("lookups => 'f'") may complete synchronously during the initiating method call. EXPORT TAGS :status ARES_SUCCESS ARES_ENODATA ARES_ETIMEOUT ... :types T_A T_AAAA T_MX T_SRV T_TXT T_NS T_SOA ... :classes C_IN C_CHAOS C_HS C_ANY :flags ARES_FLAG_USEVC ARES_FLAG_EDNS ARES_FLAG_DNS0x20 ... :ai ARES_AI_CANONNAME ARES_AI_ADDRCONFIG ARES_AI_NOSORT ... :ni ARES_NI_NOFQDN ARES_NI_NUMERICHOST ... :families AF_INET AF_INET6 AF_UNSPEC :all all of the above SEE ALSO EV, Alien::cares, AUTHOR vividsnow LICENSE This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.