… | |
… | |
644 | |
644 | |
645 | resolve_sockaddr "google.com", "http", 0, undef, undef, sub { ... }; |
645 | resolve_sockaddr "google.com", "http", 0, undef, undef, sub { ... }; |
646 | |
646 | |
647 | =cut |
647 | =cut |
648 | |
648 | |
649 | our %HOSTS; |
649 | our %HOSTS; # $HOSTS{$nodename}[$ipv6] = [@aliases...] |
|
|
650 | our @HOSTS_CHECKING; # callbacks to call when hosts have been loaded |
650 | our $HOSTS; |
651 | our $HOSTS_MTIME; |
651 | |
652 | |
652 | if ( |
|
|
653 | open my $fh, "<", |
|
|
654 | length $ENV{PERL_ANYEVENT_HOSTS} ? $ENV{PERL_ANYEVENT_HOSTS} |
|
|
655 | : AnyEvent::WIN32 ? "$ENV{SystemRoot}/system32/drivers/etc/hosts" |
|
|
656 | : "/etc/hosts" |
|
|
657 | ) { |
|
|
658 | local $/; |
|
|
659 | binmode $fh; |
|
|
660 | $HOSTS = <$fh>; |
|
|
661 | } else { |
|
|
662 | $HOSTS = ""; |
|
|
663 | } |
|
|
664 | |
|
|
665 | sub _parse_hosts() { |
653 | sub _parse_hosts($) { |
666 | #%HOSTS = (); |
654 | %HOSTS = (); |
667 | |
655 | |
668 | for (split /\n/, $HOSTS) { |
656 | for (split /\n/, $_[0]) { |
669 | s/#.*$//; |
657 | s/#.*$//; |
670 | s/^[ \t]+//; |
658 | s/^[ \t]+//; |
671 | y/A-Z/a-z/; |
659 | y/A-Z/a-z/; |
672 | |
660 | |
673 | my ($addr, @aliases) = split /[ \t]+/; |
661 | my ($addr, @aliases) = split /[ \t]+/; |
… | |
… | |
679 | } elsif (my $ip = parse_ipv6 $addr) { |
667 | } elsif (my $ip = parse_ipv6 $addr) { |
680 | push @{ $HOSTS{$_}[1] }, $ip |
668 | push @{ $HOSTS{$_}[1] }, $ip |
681 | for @aliases; |
669 | for @aliases; |
682 | } |
670 | } |
683 | } |
671 | } |
|
|
672 | } |
684 | |
673 | |
685 | undef $HOSTS; |
674 | # helper function - unless dns delivered results, check and parse hosts, then clal continuation code |
|
|
675 | sub _load_hosts_unless(&$@) { |
|
|
676 | my ($cont, $cv, @dns) = @_; |
|
|
677 | |
|
|
678 | if (@dns) { |
|
|
679 | $cv->end; |
|
|
680 | } else { |
|
|
681 | my $etc_hosts = length $ENV{PERL_ANYEVENT_HOSTS} ? $ENV{PERL_ANYEVENT_HOSTS} |
|
|
682 | : AnyEvent::WIN32 ? "$ENV{SystemRoot}/system32/drivers/etc/hosts" |
|
|
683 | : "/etc/hosts"; |
|
|
684 | |
|
|
685 | push @HOSTS_CHECKING, sub { |
|
|
686 | $cont->(); |
|
|
687 | $cv->end; |
|
|
688 | }; |
|
|
689 | |
|
|
690 | unless ($#HOSTS_CHECKING) { |
|
|
691 | # we are not the first, so we actually have to do the work |
|
|
692 | require AnyEvent::IO; |
|
|
693 | |
|
|
694 | AnyEvent::IO::aio_stat ($etc_hosts, sub { |
|
|
695 | if ((stat _)[9] ne $HOSTS_MTIME) { |
|
|
696 | AE::log 8 => "(re)loading $etc_hosts."; |
|
|
697 | $HOSTS_MTIME = (stat _)[9]; |
|
|
698 | # we might load a newer version of hosts,but that's a harmless race, |
|
|
699 | # as the next call will just load it again. |
|
|
700 | AnyEvent::IO::aio_load ($etc_hosts, sub { |
|
|
701 | _parse_hosts $_[0]; |
|
|
702 | (shift @HOSTS_CHECKING)->() while @HOSTS_CHECKING; |
|
|
703 | }); |
|
|
704 | } else { |
|
|
705 | (shift @HOSTS_CHECKING)->() while @HOSTS_CHECKING; |
|
|
706 | } |
|
|
707 | }); |
|
|
708 | } |
|
|
709 | } |
686 | } |
710 | } |
687 | |
711 | |
688 | sub resolve_sockaddr($$$$$$) { |
712 | sub resolve_sockaddr($$$$$$) { |
689 | my ($node, $service, $proto, $family, $type, $cb) = @_; |
713 | my ($node, $service, $proto, $family, $type, $cb) = @_; |
690 | |
714 | |
… | |
… | |
767 | AnyEvent::DNS::a $node, sub { |
791 | AnyEvent::DNS::a $node, sub { |
768 | push @res, [$idx, "ipv4", [AF_INET , $type, $proton, pack_sockaddr $port, parse_ipv4 $_]] |
792 | push @res, [$idx, "ipv4", [AF_INET , $type, $proton, pack_sockaddr $port, parse_ipv4 $_]] |
769 | for @_; |
793 | for @_; |
770 | |
794 | |
771 | # dns takes precedence over hosts |
795 | # dns takes precedence over hosts |
|
|
796 | _load_hosts_unless { |
772 | push @res, |
797 | push @res, |
773 | map [$idx, "ipv4", [AF_INET , $type, $proton, pack_sockaddr $port, $_]], |
798 | map [$idx, "ipv4", [AF_INET , $type, $proton, pack_sockaddr $port, $_]], |
774 | @{ $hosts->[0] } |
799 | @{ $HOSTS{$node}[0] }; |
775 | unless @_; |
|
|
776 | |
|
|
777 | $cv->end; |
800 | } $cv, @_; |
778 | }; |
801 | }; |
779 | } |
802 | } |
780 | |
803 | |
781 | # aaaa records |
804 | # aaaa records |
782 | if ($family != 4) { |
805 | if ($family != 4) { |
783 | $cv->begin; |
806 | $cv->begin; |
784 | AnyEvent::DNS::aaaa $node, sub { |
807 | AnyEvent::DNS::aaaa $node, sub { |
785 | push @res, [$idx, "ipv6", [AF_INET6, $type, $proton, pack_sockaddr $port, parse_ipv6 $_]] |
808 | push @res, [$idx, "ipv6", [AF_INET6, $type, $proton, pack_sockaddr $port, parse_ipv6 $_]] |
786 | for @_; |
809 | for @_; |
787 | |
810 | |
|
|
811 | _load_hosts_unless { |
788 | push @res, |
812 | push @res, |
789 | map [$idx + 0.5, "ipv6", [AF_INET6, $type, $proton, pack_sockaddr $port, $_]], |
813 | map [$idx + 0.5, "ipv6", [AF_INET6, $type, $proton, pack_sockaddr $port, $_]], |
790 | @{ $hosts->[1] } |
814 | @{ $HOSTS{$node}[1] } |
791 | unless @_; |
|
|
792 | |
|
|
793 | $cv->end; |
815 | } $cv, @_; |
794 | }; |
816 | }; |
795 | } |
817 | } |
796 | } |
818 | } |
797 | } |
819 | } |
798 | $cv->end; |
820 | $cv->end; |
799 | }; |
821 | }; |
800 | |
822 | |
801 | $node = AnyEvent::Util::idn_to_ascii $node |
823 | $node = AnyEvent::Util::idn_to_ascii $node |
802 | if $node =~ /[^\x00-\x7f]/; |
824 | if $node =~ /[^\x00-\x7f]/; |
803 | |
|
|
804 | # parse hosts |
|
|
805 | if (defined $HOSTS) { |
|
|
806 | _parse_hosts; |
|
|
807 | undef &_parse_hosts; |
|
|
808 | } |
|
|
809 | |
825 | |
810 | # try srv records, if applicable |
826 | # try srv records, if applicable |
811 | if ($node eq "localhost") { |
827 | if ($node eq "localhost") { |
812 | $resolve->(["127.0.0.1", $port], ["::1", $port]); |
828 | $resolve->(["127.0.0.1", $port], ["::1", $port]); |
813 | } elsif (defined $service && !parse_address $node) { |
829 | } elsif (defined $service && !parse_address $node) { |
… | |
… | |
924 | AE::log error => $_[2]; |
940 | AE::log error => $_[2]; |
925 | $_[0]->destroy; |
941 | $_[0]->destroy; |
926 | }, |
942 | }, |
927 | on_eof => sub { |
943 | on_eof => sub { |
928 | $handle->destroy; # destroy handle |
944 | $handle->destroy; # destroy handle |
929 | AE::log info => "done."; |
945 | AE::log info => "Done."; |
930 | }; |
946 | }; |
931 | |
947 | |
932 | $handle->push_write ("GET / HTTP/1.0\015\012\015\012"); |
948 | $handle->push_write ("GET / HTTP/1.0\015\012\015\012"); |
933 | |
949 | |
934 | $handle->push_read (line => "\015\012\015\012", sub { |
950 | $handle->push_read (line => "\015\012\015\012", sub { |
… | |
… | |
1114 | my ($fh, $host, $port) = @_; |
1130 | my ($fh, $host, $port) = @_; |
1115 | |
1131 | |
1116 | syswrite $fh, "The internet is full, $host:$port. Go away!\015\012"; |
1132 | syswrite $fh, "The internet is full, $host:$port. Go away!\015\012"; |
1117 | }, sub { |
1133 | }, sub { |
1118 | my ($fh, $thishost, $thisport) = @_; |
1134 | my ($fh, $thishost, $thisport) = @_; |
1119 | AE::log info => "bound to $thishost, port $thisport"; |
1135 | AE::log info => "Bound to $thishost, port $thisport."; |
1120 | }; |
1136 | }; |
1121 | |
1137 | |
1122 | Example: bind a server on a unix domain socket. |
1138 | Example: bind a server on a unix domain socket. |
1123 | |
1139 | |
1124 | tcp_server "unix/", "/tmp/mydir/mysocket", sub { |
1140 | tcp_server "unix/", "/tmp/mydir/mysocket", sub { |
… | |
… | |
1244 | harmful in general. |
1260 | harmful in general. |
1245 | |
1261 | |
1246 | =head1 AUTHOR |
1262 | =head1 AUTHOR |
1247 | |
1263 | |
1248 | Marc Lehmann <schmorp@schmorp.de> |
1264 | Marc Lehmann <schmorp@schmorp.de> |
1249 | http://home.schmorp.de/ |
1265 | http://anyevent.schmorp.de |
1250 | |
1266 | |
1251 | =cut |
1267 | =cut |
1252 | |
1268 | |
1253 | 1 |
1269 | 1 |
1254 | |
1270 | |