}
=item $resolver->max_outstanding ($nrequests)
Sets the maximum number of outstanding requests to C<$nrequests>. See the
C<max_outstanding> constructor argument.
=cut
sub max_outstanding {
my ($self, $max) = @_;
$self->{max_outstanding} = $max;
$self->_scheduler;
}
sub _compile {
my $self = shift;
my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
my %server; $self->{server} = [grep 0 < length, grep !$server{$_}++, @{ $self->{server} }];
unless (@{ $self->{server} }) {
# use 127.0.0.1 by default, and one opendns nameserver as fallback
$self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]];
}
my @retry;
for my $timeout (@{ $self->{timeout} }) {
for my $server (@{ $self->{server} }) {
push @retry, [$server, $timeout];
}
}
$self->{retry} = \@retry;
}
sub _feed {
my ($self, $res) = @_;
$res = dns_unpack $res
or return;
my $id = $self->{id}{$res->{id}};
return unless ref $id;
$NOW = time;
$id->[1]->($res);
}
sub _recv {
my ($self, $pkt, $peer) = @_;
# we ignore errors (often one gets port unreachable, but there is
# no good way to take advantage of that.
my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
return unless $port == 53 && grep $_ eq $host, @{ $self->{server} };
$self->_feed ($pkt);
}
sub _free_id {
my ($self, $id, $timeout) = @_;
if ($timeout) {
# we need to block the id for a while
$self->{id}{$id} = 1;
push @{ $self->{reuse_q} }, [$NOW + $self->{reuse}, $id];
} else {
# we can quickly recycle the id
delete $self->{id}{$id};
}
--$self->{outstanding};
$self->_scheduler;
}
# execute a single request, involves sending it with timeouts to multiple servers
sub _exec {
my ($self, $req) = @_;
my $retry; # of retries
my $do_retry;
$do_retry = sub {
my $retry_cfg = $self->{retry}[$retry++]
or do {
# failure
$self->_free_id ($req->[2], $retry > 1);
undef $do_retry; return $req->[1]->();
};
my ($server, $timeout) = @$retry_cfg;
$self->{id}{$req->[2]} = [AnyEvent->timer (after => $timeout, cb => sub {
$NOW = time;
=10= |