File Coverage

blib/lib/AnyEvent/CacheDNS.pm
Criterion Covered Total %
statement 41 45 91.1
branch 11 22 50.0
condition 5 14 35.7
subroutine 8 8 100.0
pod 2 2 100.0
total 67 91 73.6


line stmt bran cond sub pod time code
1             package AnyEvent::CacheDNS;
2              
3 1     1   44478 use strict;
  1         3  
  1         39  
4 1     1   7 use warnings;
  1         1  
  1         33  
5 1     1   5 use base 'AnyEvent::DNS';
  1         10  
  1         1032  
6              
7 1     1   36201 use Data::Dumper;
  1         11928  
  1         569  
8              
9             our $VERSION = '0.08';
10              
11             # Detect AnyEvent >= 6.0.1
12             my $IS_AE_6X = version->can("parse")
13             ? version->parse(AnyEvent->VERSION()) >= version->parse('v6.0.1')
14             : AnyEvent->VERSION !~ /^ (?: [0-5]\. | 6\.0(?:\.0)? $ )/x;
15              
16             # Default TTL for AnyEvent < 6.0.1
17             my $DEFAULT_TTL = undef;
18              
19             sub import {
20 1     1   7 my $package = shift;
21 1         2 my @options = @_;
22              
23 1         4 while (@options) {
24 1         2 my $key = shift @options;
25 1 50       3 if ($key eq ':register') {
26 1         2 $package->register();
27             }
28             }
29             }
30              
31              
32             sub resolve {
33 2     2 1 1445 my $cb = pop @_;
34 2         6 my ($self, $qname, $qtype, %opt) = @_;
35              
36             # If we have the value cached then we serve it from there
37 2   100     18 my $cache = $self->{_cache}{$qtype} ||= {};
38 2 100       9 if (exists $cache->{$qname}) {
39 1         3 my $response = $cache->{$qname};
40 1 50       7 $cb->($response ? ($response) : ());
41 1         17 return;
42             }
43              
44             # Perform a request and cache the value
45             $self->SUPER::resolve(
46             $qname,
47             $qtype,
48             %opt,
49             sub{
50             # Note that it could be possible that multiple DNS request are done
51             # for a new qname. For instance if an application is doing multiple
52             # concurrent HTTP request to the same host then there will be at
53             # least one DNS request per HTTP request. That's why we only cache
54             # the results of the first DNS request that's successful.
55 1 50 33 1   106402 $cache->{$qname} ||= @_ ? $_[0] : undef;
56              
57             # Respect TTL and be backwards compatible with AnyEvent < 6.x
58 1 50 33     21 my $ttl = defined $DEFAULT_TTL
    50 50        
59             ? $DEFAULT_TTL
60             : ($IS_AE_6X && @_ ? int($_[0]->[3] || 0) : 0)
61             ;
62              
63 1 50       6 if ($ttl > 0) {
64             # Create expire timer
65 1         2 my $wt;
66             $wt = AE::timer($ttl, 0, sub {
67 0         0 $wt = undef;
68 0         0 delete($cache->{$qname});
69 1         17 });
70             }
71              
72 1         10 $cb->(@_);
73             }
74 1         18 );
75             }
76              
77              
78             sub register {
79 1     1 1 2 my $class = shift;
80              
81 1         2 my @args = (
82             untaint => 1,
83             );
84              
85 1         1 my $key = 'PERL_ANYEVENT_MAX_OUTSTANDING_DNS';
86 1 50 0     4 push @args, max_outstanding => $ENV{$key} * 1 || 1 if exists $ENV{$key};
87              
88 1         9 my $resolver = $class->new(@args);
89              
90 1 50       5275 if (exists $ENV{PERL_ANYEVENT_RESOLV_CONF}) {
91 0         0 my $conf = $ENV{PERL_ANYEVENT_RESOLV_CONF};
92 0 0       0 $resolver->_parse_resolv_conf_file($conf) if length $conf;
93             }
94             else {
95 1         8 $resolver->os_config();
96             }
97              
98 1 50 0     3758 $DEFAULT_TTL = abs(int($ENV{PERL_ANYEVENT_DNS_TTL} || 0)) if exists $ENV{PERL_ANYEVENT_DNS_TTL};
99              
100 1         34 $AnyEvent::DNS::RESOLVER = $resolver;
101             }
102              
103              
104             1;
105              
106             =head1 NAME
107              
108             AnyEvent::CacheDNS - Simple DNS resolver with caching
109              
110             =head1 SYNOPSIS
111              
112             use AnyEvent;
113             use AnyEvent::HTTP;
114            
115             # Register our DNS resolver as the default resolver
116             use AnyEvent::CacheDNS ':register';
117            
118             # Use AnyEvent as ususal
119             my $cond = AnyEvent->condvar;
120             http_get "http://search.cpan.org/", sub { $cond->send(); };
121             $cond->recv();
122              
123             =head1 DESCRIPTION
124              
125             This module provides a very simple DNS resolver that caches its results and can
126             improve the connection times to remote hosts.
127              
128             =head1 Import
129              
130             It's possible to register the this class as AnyEvent's main DNS resolver by
131             passing the tag C<:register> in the C statement.
132              
133             =head1 METHODS
134              
135             =head2 register
136              
137             Registers a new DNS cache instance as AnyEvent's global DNS resolver.
138              
139             =head2 ENVIRONMENT
140              
141             =over
142              
143             =item C
144              
145             The effect of setting this variable differs depending on L version.
146              
147             =over
148              
149             =item AnyEvent 5.x
150              
151             Default DNS response record cache TTL for older AnyEvent versions.
152             L <= 6.x doesn't report record TTL and records get
153             cached for infinite amount of time, therefore running programs won't
154             detect if cached DNS records have changed.
155              
156             B: Setting this variable to C<0> disables purging records from
157             cache.
158              
159             =item AnyEvent 6.x
160              
161             Newer versions of AnyEvent report DNS record TTL so records will be
162             purged from the cache after B TTL expires. Setting this variable to any
163             positive integer B the TTL for all records to the specified
164             value, setting variable to C<0> disables purging records from the cache.
165              
166             =back
167              
168             =back
169              
170             =head1 AUTHOR
171              
172             Emmanuel Rodriguez
173              
174             =head1 COPYRIGHT
175              
176             (C) 2011 Emmanuel Rodriguez - All Rights Reserved.
177              
178             =cut