$proto ||= "tcp";
$type ||= $proto eq "udp" ? SOCK_DGRAM : SOCK_STREAM;
my $proton = (getprotobyname $proto)[2]
or Carp::croak "$proto: protocol unknown";
my $port;
if ($service =~ /^(\S+)=(\d+)$/) {
($service, $port) = ($1, $2);
} elsif ($service =~ /^\d+$/) {
($service, $port) = (undef, $service);
} else {
$port = (getservbyname $service, $proto)[2]
or Carp::croak "$service/$proto: service unknown";
}
my @target = [$node, $port];
# resolve a records / provide sockaddr structures
my $resolve = sub {
my @res;
my $cv = AnyEvent->condvar (cb => sub {
$cb->(
map $_->[2],
sort {
$AnyEvent::PROTOCOL{$b->[1]} <=> $AnyEvent::PROTOCOL{$a->[1]}
or $a->[0] <=> $b->[0]
}
@res
)
});
$cv->begin;
for my $idx (0 .. $#target) {
my ($node, $port) = @{ $target[$idx] };
if (my $noden = parse_address $node) {
my $af = address_family $noden;
if ($af == AF_INET && $family != 6) {
push @res, [$idx, "ipv4", [AF_INET, $type, $proton,
pack_sockaddr $port, $noden]]
}
if ($af == AF_INET6 && $family != 4) {
push @res, [$idx, "ipv6", [AF_INET6, $type, $proton,
pack_sockaddr $port, $noden]]
}
} else {
# ipv4
if ($family != 6) {
$cv->begin;
AnyEvent::DNS::a $node, sub {
push @res, [$idx, "ipv4", [AF_INET, $type, $proton,
pack_sockaddr $port, parse_ipv4 $_]]
for @_;
$cv->end;
};
}
# ipv6
if ($family != 4) {
$cv->begin;
AnyEvent::DNS::aaaa $node, sub {
push @res, [$idx, "ipv6", [AF_INET6, $type, $proton,
pack_sockaddr $port, parse_ipv6 $_]]
for @_;
$cv->end;
};
}
}
}
$cv->end;
};
# try srv records, if applicable
if ($node eq "localhost") {
@target = (["127.0.0.1", $port], ["::1", $port]);
&$resolve;
} elsif (defined $service && !parse_address $node) {
AnyEvent::DNS::srv $service, $proto, $node, sub {
my (@srv) = @_;
# no srv records, continue traditionally
@srv
or return &$resolve;
# the only srv record has "." ("" here) => abort
$srv[0][2] ne "" || $#srv
or return $cb->();
# use srv records then
@target = map ["$_->[3].", $_->[2]],
grep $_->[3] ne ".",
@srv;
&$resolve;
};
} else {
=5= |