Class: Cares
- Inherits:
-
Object
- Object
- Cares
- Defined in:
- ext/cares.c,
ext/cares.c
Overview
Overview
Ruby/Cares is a C extension to the c-ares library. It performs DNS requests and name resolving asynchronously.
Example
Below follows a simple example. See Cares’ methods documentations for details valid parameters.
require 'cares'
require 'socket'
# Create new Cares instance
cares = Cares.new(:timeout => 3)
#
# Set up three DNS requests.
#
cares.gethostbyname('www.rubyforge.org', Socket::AF_INET) do |name, aliases, family, *addrs|
puts "[-] Cares#gethostbyname:"
puts " #{domain}:"
puts " canonical name: #{name}"
puts " aliases: #{aliases.join(', ')}"
puts " addresses: #{addrs.join(', ')}"
puts
end
cares.gethostbyaddr('205.234.109.18', Socket::AF_INET) do |name, *rest|
puts "[-] Cares#gethostbyaddr:"
puts " #{addr}:"
puts " name: #{name}"
puts
end
cares.getnameinfo(:addr => '205.234.109.18') do |name, service|
puts "[-] Cares#getnameinfo:"
puts " #{addr}:"
puts " name: #{name}"
puts
end
# Wait for responses and yield the blocks passed to each of the
# methods calls above.
cares.select_loop
Defined Under Namespace
Instance Method Summary collapse
-
#gethostbyaddr(addr, family) {|name, aliases, family, *addrs| ... } ⇒ Object
Performs a reverse DNS query on
addr
. -
#gethostbyname(name, family) {|cname, aliases, family, *addrs| ... } ⇒ Object
Performs a DNS lookup on
name
, for addresses of familyfamily
. -
#getnameinfo(nameservice) {|name, service| ... } ⇒ Object
Performs a protocol-independent reverse lookup on the host and/or service names specified on the
nameservice
hash. -
#initialize(*args) ⇒ Object
constructor
Creates a new
Cares
object. -
#select_loop(timeout = nil) ⇒ nil
Handles the input/output and timeout associated witht the queries made from the name and address lookup methods.
Constructor Details
#new([options]) ⇒ Object #new([options]) {|socket, read, write| ... } ⇒ Object
Creates a new Cares
object. The options
hash accepts the following keys:
-
:flags
Flags controlling the behaviour of the resolver. See below for a description os the possible flags. -
:timeout
The number of seconds each name server is given to respond to a query on the first try. For further queries, the timeout scales nearly with the provided value. The default is 5 seconds. -
:tries
The number of times the resolver will try to contact each name server before giving up. The default is 4 tries. -
:ndots
The number of dots that must be present in a domain name for it to be queried “as is”, prior to querying with the default domain extensions appended. The default is 1, unless set otherwise in resolv.conf or theRES_OPTIONS
environment variable. -
:udp_port
The port to use for UDP queries. The default is 53. -
:tcp_port
The port to use for TCP queries. The default is 53. -
:servers
An array of IP addresses to be used as the servers to be contacted, instead of the ones found in resolv.conf or the local name daemon. -
:domains
An array of domains to be searched, instead of the ones specified in resolv.conf or the machine hostname. -
:lookups
The lookups to perform for host queries. It should be a string of the characters b or f, where b indicates a DNS lookup, and f indicates a hosts file lookup.
The :flags
option is a bitwise-or of values from the list below:
-
Cares::Init::USEVC
Always use TCP queries. Normally, TCP is only used if a UDP query returns a truncated result. -
Cares::Init::PRIMARY
Only query the first server in the server list. -
Cares::Init::IGNTC
If a truncated response to an UDP query is received, do not fall back to TCP; simply continue with the truncated response. -
Cares::Init::NORECURSE
Do not set the “recursion desired” bit on outgoing queries. -
Cares::Init::STAYOPEN
Do not close the communication sockets when the number of active queries drops to zero. -
Cares::Init::NOSEARCH
Do not use the default search domains; only query hostnames as-is or as aliases. -
Cares::Init::NOALIASES
Do not honor theHOSTALIASES
environment variable, which specifies a file of hostname translations. -
Cares::Init::NOCHECKRESP
Do not discard responses with theSERVFAIL
,NOTIMP
, orREFUSED
response codes or responses whose questions don’t match the questions in the request.
If a block is given, it’ll be called when a socket used in name resolving has its state changed. The block takes three arguments. The first one is the Socket
object, the the other two are boolean values indicating if the socket should listen for read and/or write events, respectively.
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'ext/cares.c', line 349
static VALUE
rb_cares_init(int argc, VALUE *argv, VALUE self)
{
int status, optmask;
ares_channel *chp;
struct ares_options ao;
VALUE opts;
Data_Get_Struct(self, ares_channel, chp);
rb_scan_args(argc, argv, "01", &opts);
if (NIL_P(opts) && !rb_block_given_p()) {
status = ares_init(chp);
if (status != ARES_SUCCESS)
raise_error(status);
return(self);
}
optmask = set_init_opts(opts, &ao);
status = ares_init_options(chp, &ao, optmask);
if (status != ARES_SUCCESS)
raise_error(status);
return(self);
}
|
Instance Method Details
#gethostbyaddr(addr, family) {|name, aliases, family, *addrs| ... } ⇒ Object
Performs a reverse DNS query on addr
. for addresses of family family
. The family
argument is either Socket::AF_INET
or Socket::AF_INET6
. The results are passed as arguments to the block:
-
name
:addr
‘s name. -
aliases
: array of aliases. -
family
: address family. -
*addrs
: array containingname
‘s addresses.
449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
# File 'ext/cares.c', line 449
static VALUE
rb_cares_gethostbyaddr(VALUE self, VALUE addr, VALUE family)
{
char *caddr;
int cfamily;
ares_channel *chp;
if (!rb_block_given_p())
rb_raise(rb_eArgError, "gethostbyaddr: block needed");
Data_Get_Struct(self, ares_channel, chp);
cfamily = NUM2INT(family);
caddr = StringValuePtr(addr);
switch (cfamily) {
case AF_INET: {
struct in_addr in;
if (inet_pton(cfamily, caddr, &in) != 1)
rb_sys_fail("gethostbyaddr");
ares_gethostbyaddr(*chp, &in, sizeof(in), cfamily,
host_callback, (void *)rb_block_proc());
break;
}
case AF_INET6: {
struct in6_addr in6;
if (inet_pton(cfamily, caddr, &in6) != 1)
rb_sys_fail("gethostbyaddr");
ares_gethostbyaddr(*chp, &in6, sizeof(in6), cfamily,
host_callback, (void *)rb_block_proc());
break;
}
default:
rb_raise(cNotImpError, "gethostbyaddr: invalid address family");
}
return(self);
}
|
#gethostbyname(name, family) {|cname, aliases, family, *addrs| ... } ⇒ Object
Performs a DNS lookup on name
, for addresses of family family
. The family
argument is either Socket::AF_INET
or Socket::AF_INET6
. The results are passed as arguments to the block:
-
cname
:name
‘s canonical name. -
aliases
: array of aliases. -
family
: address family. -
*addrs
: array containingname
‘s addresses.
421 422 423 424 425 426 427 428 429 430 431 432 433 |
# File 'ext/cares.c', line 421
static VALUE
rb_cares_gethostbyname(VALUE self, VALUE host, VALUE family)
{
ares_channel *chp;
if (!rb_block_given_p())
rb_raise(rb_eArgError, "gethostbyname: block needed");
Data_Get_Struct(self, ares_channel, chp);
ares_gethostbyname(*chp, StringValuePtr(host), NUM2INT(family),
host_callback, (void *)rb_block_proc());
return(self);
}
|
#getnameinfo(nameservice) {|name, service| ... } ⇒ Object
Performs a protocol-independent reverse lookup on the host and/or service names specified on the nameservice
hash. The valid keys are:
-
:addr
: IPv4 or IPv6 address. -
:service
: Service name.
The lookup results are passed as parameters to the block.
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 |
# File 'ext/cares.c', line 517
static VALUE
rb_cares_getnameinfo(VALUE self, VALUE info)
{
int cflags;
socklen_t sslen;
struct sockaddr_storage ss;
ares_channel *chp;
VALUE vaddr, vport, vflags;
Data_Get_Struct(self, ares_channel, chp);
vflags = rb_hash_aref(info, ID2SYM(rb_intern("flags")));
if (!NIL_P(vflags))
cflags = NUM2INT(vflags);
else
cflags = 0;
sslen = 0;
ss.ss_family = AF_INET;
vaddr = rb_hash_aref(info, ID2SYM(rb_intern("addr")));
if (!NIL_P(vaddr)) {
char *caddr = StringValuePtr(vaddr);
struct sockaddr_in *sinp;
struct sockaddr_in6 *sin6p;
sinp = (struct sockaddr_in *)&ss;
sin6p = (struct sockaddr_in6 *)&ss;
cflags |= ARES_NI_LOOKUPHOST;
if (inet_pton(AF_INET, caddr, &sinp->sin_addr) == 1) {
sslen = sizeof(struct sockaddr_in);
} else if (inet_pton(AF_INET6, caddr, &sin6p->sin6_addr) == 1) {
ss.ss_family = AF_INET6;
sslen = sizeof(struct sockaddr_in6);
} else {
rb_raise(cNotImpError,
"getnameinfo: invalid address family");
}
}
vport = rb_hash_aref(info, ID2SYM(rb_intern("port")));
if (!NIL_P(vport)) {
u_short cport = htons(NUM2UINT(vport));
cflags |= ARES_NI_LOOKUPSERVICE;
switch (ss.ss_family) {
case AF_INET:
((struct sockaddr_in *)&ss)->sin_port = cport;
sslen = sizeof(struct sockaddr_in);
break;
case AF_INET6:
((struct sockaddr_in6 *)&ss)->sin6_port = cport;
sslen = sizeof(struct sockaddr_in6);
break;
}
}
ares_getnameinfo(*chp, (struct sockaddr *)&ss, sslen, cflags,
nameinfo_callback, (void *)rb_block_proc());
return(self);
}
|
#select_loop(timeout = nil) ⇒ nil
Handles the input/output and timeout associated witht the queries made from the name and address lookup methods. The block passed to each of those methods is yielded when the event is processed.
The timeout
hash accepts the following keys:
-
:seconds
: Timeout in seconds. -
:useconds
: Timeout in microseconds.
593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 |
# File 'ext/cares.c', line 593
static VALUE
rb_cares_select_loop(int argc, VALUE *argv, VALUE self)
{
int nfds;
fd_set read, write;
struct timeval *tvp, tv;
struct timeval *maxtvp, maxtv;
ares_channel *chp;
VALUE timeout;
rb_scan_args(argc, argv, "01", &timeout);
maxtvp = NULL;
if (!NIL_P(timeout)) {
VALUE secs, usecs;
secs = rb_hash_aref(timeout, ID2SYM(rb_intern("seconds")));
if (!NIL_P(secs))
maxtv.tv_sec = NUM2LONG(secs);
usecs = rb_hash_aref(timeout, ID2SYM(rb_intern("useconds")));
if (!NIL_P(usecs))
maxtv.tv_usec = NUM2LONG(usecs);
if (!NIL_P(secs) || !NIL_P(usecs))
maxtvp = &maxtv;
}
Data_Get_Struct(self, ares_channel, chp);
for (;;) {
FD_ZERO(&read);
FD_ZERO(&write);
nfds = ares_fds(*chp, &read, &write);
if (nfds == 0)
break;
tvp = ares_timeout(*chp, maxtvp, &tv);
rb_thread_select(nfds, &read, &write, NULL, tvp);
ares_process(*chp, &read, &write);
}
return(Qnil);
}
|