ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/DNS.pm
(Generate patch)

Comparing AnyEvent/lib/AnyEvent/DNS.pm (file contents):
Revision 1.36 by root, Wed May 28 21:07:07 2008 UTC vs.
Revision 1.39 by root, Thu May 29 03:45:37 2008 UTC

33 33
34use Socket qw(AF_INET SOCK_DGRAM SOCK_STREAM); 34use Socket qw(AF_INET SOCK_DGRAM SOCK_STREAM);
35 35
36use AnyEvent (); 36use AnyEvent ();
37use AnyEvent::Handle (); 37use AnyEvent::Handle ();
38use AnyEvent::Util qw(AF_INET6);
39
40our $VERSION = '1.0';
38 41
39our @DNS_FALLBACK = (v208.67.220.220, v208.67.222.222); 42our @DNS_FALLBACK = (v208.67.220.220, v208.67.222.222);
40 43
41=item AnyEvent::DNS::a $domain, $cb->(@addrs) 44=item AnyEvent::DNS::a $domain, $cb->(@addrs)
42 45
89 92
90Tries to resolve the given domain and passes all resource records found to 93Tries to resolve the given domain and passes all resource records found to
91the callback. 94the callback.
92 95
93=cut 96=cut
97
98sub MAX_PKT() { 4096 } # max packet size we advertise and accept
99
100sub DOMAIN_PORT() { 53 } # if this changes drop me a note
94 101
95sub resolver; 102sub resolver;
96 103
97sub a($$) { 104sub a($$) {
98 my ($domain, $cb) = @_; 105 my ($domain, $cb) = @_;
147 my ($ip, $cb) = @_; 154 my ($ip, $cb) = @_;
148 155
149 $ip = AnyEvent::Socket::parse_address ($ip) 156 $ip = AnyEvent::Socket::parse_address ($ip)
150 or return $cb->(); 157 or return $cb->();
151 158
152 if (4 == length $ip) { 159 my $af = AnyEvent::Socket::address_family ($ip);
160
161 if ($af == AF_INET) {
153 $ip = join ".", (reverse split /\./, $ip), "in-addr.arpa."; 162 $ip = join ".", (reverse split /\./, $ip), "in-addr.arpa.";
163 } elsif ($af == AF_INET6) {
164 $ip = join ".", (reverse split //, unpack "H*", $ip), "ip6.arpa.";
154 } else { 165 } else {
155 $ip = join ".", (reverse split //, unpack "H*", $ip), "ip6.arpa."; 166 return $cb->();
156 } 167 }
157 168
158 resolver->resolve ($ip => "ptr", sub { 169 resolver->resolve ($ip => "ptr", sub {
159 $cb->(map $_->[3], @_); 170 $cb->(map $_->[3], @_);
160 }); 171 });
336 (join "", map _enc_qd, @{ $req->{qd} || [] }), 347 (join "", map _enc_qd, @{ $req->{qd} || [] }),
337 (join "", map _enc_rr, @{ $req->{an} || [] }), 348 (join "", map _enc_rr, @{ $req->{an} || [] }),
338 (join "", map _enc_rr, @{ $req->{ns} || [] }), 349 (join "", map _enc_rr, @{ $req->{ns} || [] }),
339 (join "", map _enc_rr, @{ $req->{ar} || [] }), 350 (join "", map _enc_rr, @{ $req->{ar} || [] }),
340 351
341 ($EDNS0 ? pack "C nnNn", 0, 41, 4096, 0, 0 : "") # EDNS0, 4kiB udp payload size 352 ($EDNS0 ? pack "C nnNn", 0, 41, MAX_PKT, 0, 0 : "") # EDNS0, 4kiB udp payload size
342} 353}
343 354
344our $ofs; 355our $ofs;
345our $pkt; 356our $pkt;
346 357
587=cut 598=cut
588 599
589sub new { 600sub new {
590 my ($class, %arg) = @_; 601 my ($class, %arg) = @_;
591 602
603 # try to create a ipv4 and an ipv6 socket
604 # only fail when we cnanot create either
605
592 socket my $fh, AF_INET, &Socket::SOCK_DGRAM, 0 606 socket my $fh4, AF_INET , &Socket::SOCK_DGRAM, 0;
593 or Carp::croak "socket: $!"; 607 socket my $fh6, AF_INET6, &Socket::SOCK_DGRAM, 0;
594 608
595 AnyEvent::Util::fh_nonblocking $fh, 1; 609 $fh4 || $fh6
610 or Carp::croak "unable to create either an IPv6 or an IPv4 socket";
596 611
597 my $self = bless { 612 my $self = bless {
598 server => [], 613 server => [],
599 timeout => [2, 5, 5], 614 timeout => [2, 5, 5],
600 search => [], 615 search => [],
601 ndots => 1, 616 ndots => 1,
602 max_outstanding => 10, 617 max_outstanding => 10,
603 reuse => 300, # reuse id's after 5 minutes only, if possible 618 reuse => 300, # reuse id's after 5 minutes only, if possible
604 %arg, 619 %arg,
605 fh => $fh,
606 reuse_q => [], 620 reuse_q => [],
607 }, $class; 621 }, $class;
608 622
609 # search should default to gethostname's domain 623 # search should default to gethostname's domain
610 # but perl lacks a good posix module 624 # but perl lacks a good posix module
611 625
612 Scalar::Util::weaken (my $wself = $self); 626 Scalar::Util::weaken (my $wself = $self);
627
628 if ($fh4) {
629 AnyEvent::Util::fh_nonblocking $fh4, 1;
630 $self->{fh4} = $fh4;
613 $self->{rw} = AnyEvent->io (fh => $fh, poll => "r", cb => sub { $wself->_recv }); 631 $self->{rw4} = AnyEvent->io (fh => $fh4, poll => "r", cb => sub {
632 if (my $peer = recv $fh4, my $pkt, MAX_PKT, 0) {
633 $wself->_recv ($pkt, $peer);
634 }
635 });
636 }
637
638 if ($fh6) {
639 $self->{fh6} = $fh6;
640 AnyEvent::Util::fh_nonblocking $fh6, 1;
641 $self->{rw6} = AnyEvent->io (fh => $fh6, poll => "r", cb => sub {
642 if (my $peer = recv $fh6, my $pkt, MAX_PKT, 0) {
643 $wself->_recv ($pkt, $peer);
644 }
645 });
646 }
614 647
615 $self->_compile; 648 $self->_compile;
616 649
617 $self 650 $self
618} 651}
741} 774}
742 775
743sub _compile { 776sub _compile {
744 my $self = shift; 777 my $self = shift;
745 778
746 # we currently throw away all ipv6 nameservers, we do not yet support those
747
748 my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }]; 779 my %search; $self->{search} = [grep 0 < length, grep !$search{$_}++, @{ $self->{search} }];
749 my %server; $self->{server} = [grep 4 == length, grep !$server{$_}++, @{ $self->{server} }]; 780 my %server; $self->{server} = [grep 0 < length, grep !$server{$_}++, @{ $self->{server} }];
750 781
751 unless (@{ $self->{server} }) { 782 unless (@{ $self->{server} }) {
752 # use 127.0.0.1 by default, and one opendns nameserver as fallback 783 # use 127.0.0.1 by default, and one opendns nameserver as fallback
753 $self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]]; 784 $self->{server} = [v127.0.0.1, $DNS_FALLBACK[rand @DNS_FALLBACK]];
754 } 785 }
777 $NOW = time; 808 $NOW = time;
778 $id->[1]->($res); 809 $id->[1]->($res);
779} 810}
780 811
781sub _recv { 812sub _recv {
782 my ($self) = @_; 813 my ($self, $pkt, $peer) = @_;
783 814
784 # we ignore errors (often one gets port unreachable, but there is 815 # we ignore errors (often one gets port unreachable, but there is
785 # no good way to take advantage of that. 816 # no good way to take advantage of that.
786 while (my $peer = recv $self->{fh}, my $res, 4096, 0) { 817
787 my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer); 818 my ($port, $host) = AnyEvent::Socket::unpack_sockaddr ($peer);
788 819
789 return unless $port == 53 && grep $_ eq $host, @{ $self->{server} }; 820 return unless $port == 53 && grep $_ eq $host, @{ $self->{server} };
790 821
791 $self->_feed ($res); 822 $self->_feed ($pkt);
792 }
793} 823}
794 824
795sub _free_id { 825sub _free_id {
796 my ($self, $id, $timeout) = @_; 826 my ($self, $id, $timeout) = @_;
797 827
833 }), sub { 863 }), sub {
834 my ($res) = @_; 864 my ($res) = @_;
835 865
836 if ($res->{tc}) { 866 if ($res->{tc}) {
837 # success, but truncated, so use tcp 867 # success, but truncated, so use tcp
838 AnyEvent::Socket::tcp_connect ((Socket::inet_ntoa $server), 53, sub { 868 AnyEvent::Socket::tcp_connect (AnyEvent::Socket::format_address ($server), DOMAIN_PORT, sub {
839 my ($fh) = @_ 869 my ($fh) = @_
840 or return &$do_retry; 870 or return &$do_retry;
841 871
842 my $handle = new AnyEvent::Handle 872 my $handle = new AnyEvent::Handle
843 fh => $fh, 873 fh => $fh,
860 # success 890 # success
861 $self->_free_id ($req->[2], $retry > 1); 891 $self->_free_id ($req->[2], $retry > 1);
862 undef $do_retry; return $req->[1]->($res); 892 undef $do_retry; return $req->[1]->($res);
863 } 893 }
864 }]; 894 }];
895
896 my $sa = AnyEvent::Socket::pack_sockaddr (DOMAIN_PORT, $server);
865 897
866 send $self->{fh}, $req->[0], 0, AnyEvent::Socket::pack_sockaddr (53, $server); 898 my $fh = AF_INET == Socket::sockaddr_family ($sa)
899 ? $self->{fh4} : $self->{fh6}
900 or return &$do_retry;
901
902 send $fh, $req->[0], 0, $sa;
867 }; 903 };
868 904
869 &$do_retry; 905 &$do_retry;
870} 906}
871 907

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines