1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
use strict;
use warnings;
use Test::More tests => 31;
use Socket qw(:addrinfo AF_INET SOCK_STREAM IPPROTO_TCP unpack_sockaddr_in inet_aton);
my ( $err, @res );
( $err, @res ) = getaddrinfo( "127.0.0.1", "80", { socktype => SOCK_STREAM } );
cmp_ok( $err, "==", 0, '$err == 0 for host=127.0.0.1/service=80/socktype=STREAM' );
cmp_ok( $err, "eq", "", '$err eq "" for host=127.0.0.1/service=80/socktype=STREAM' );
is( scalar @res, 1,
'@res has 1 result' );
is( $res[0]->{family}, AF_INET,
'$res[0] family is AF_INET' );
is( $res[0]->{socktype}, SOCK_STREAM,
'$res[0] socktype is SOCK_STREAM' );
ok( $res[0]->{protocol} == 0 || $res[0]->{protocol} == IPPROTO_TCP,
'$res[0] protocol is 0 or IPPROTO_TCP' );
ok( defined $res[0]->{addr},
'$res[0] addr is defined' );
if (length $res[0]->{addr}) {
is_deeply( [ unpack_sockaddr_in $res[0]->{addr} ],
[ 80, inet_aton( "127.0.0.1" ) ],
'$res[0] addr is {"127.0.0.1", 80}' );
} else {
fail( '$res[0] addr is empty: check $socksizetype' );
}
# Check actual IV integers work just as well as PV strings
( $err, @res ) = getaddrinfo( "127.0.0.1", 80, { socktype => SOCK_STREAM } );
cmp_ok( $err, "==", 0, '$err == 0 for host=127.0.0.1/service=80/socktype=STREAM' );
is_deeply( [ unpack_sockaddr_in $res[0]->{addr} ],
[ 80, inet_aton( "127.0.0.1" ) ],
'$res[0] addr is {"127.0.0.1", 80}' );
( $err, @res ) = getaddrinfo( "127.0.0.1", "" );
cmp_ok( $err, "==", 0, '$err == 0 for host=127.0.0.1' );
# Might get more than one; e.g. different socktypes
ok( scalar @res > 0, '@res has results' );
( $err, @res ) = getaddrinfo( "127.0.0.1", undef );
cmp_ok( $err, "==", 0, '$err == 0 for host=127.0.0.1/service=undef' );
# Test GETMAGIC
{
"127.0.0.1" =~ /(.+)/;
( $err, @res ) = getaddrinfo($1, undef);
cmp_ok( $err, "==", 0, '$err == 0 for host=$1' );
ok( scalar @res > 0, '@res has results' );
is( (unpack_sockaddr_in $res[0]->{addr})[1],
inet_aton( "127.0.0.1" ),
'$res[0] addr is {"127.0.0.1", ??}' );
}
( $err, @res ) = getaddrinfo( "", "80", { family => AF_INET, socktype => SOCK_STREAM, protocol => IPPROTO_TCP } );
cmp_ok( $err, "==", 0, '$err == 0 for service=80/family=AF_INET/socktype=STREAM/protocol=IPPROTO_TCP' );
is( scalar @res, 1, '@res has 1 result' );
# Just pick the first one
is( $res[0]->{family}, AF_INET,
'$res[0] family is AF_INET' );
is( $res[0]->{socktype}, SOCK_STREAM,
'$res[0] socktype is SOCK_STREAM' );
ok( $res[0]->{protocol} == 0 || $res[0]->{protocol} == IPPROTO_TCP,
'$res[0] protocol is 0 or IPPROTO_TCP' );
# Now some tests of a few well-known internet hosts
my $goodhost = "cpan.perl.org";
SKIP: {
skip "Resolver has no answer for $goodhost", 2 unless gethostbyname( $goodhost );
( $err, @res ) = getaddrinfo( "cpan.perl.org", "ftp", { socktype => SOCK_STREAM } );
cmp_ok( $err, "==", 0, '$err == 0 for host=cpan.perl.org/service=ftp/socktype=STREAM' );
# Might get more than one; e.g. different families
ok( scalar @res > 0, '@res has results' );
}
# Now something I hope doesn't exist - we put it in a known-missing TLD
my $missinghost = "TbK4jM2M0OS.lm57DWIyu4i";
# Some CPAN testing machines seem to have wildcard DNS servers that reply to
# any request. We'd better check for them
SKIP: {
skip "Resolver has an answer for $missinghost", 1 if gethostbyname( $missinghost );
# Some OSes return $err == 0 but no results
( $err, @res ) = getaddrinfo( $missinghost, "ftp", { socktype => SOCK_STREAM } );
ok( $err != 0 || ( $err == 0 && @res == 0 ),
'$err != 0 or @res == 0 for host=TbK4jM2M0OS.lm57DWIyu4i/service=ftp/socktype=SOCK_STREAM' );
if( @res ) {
# Diagnostic that might help
while( my $r = shift @res ) {
diag( "family=$r->{family} socktype=$r->{socktype} protocol=$r->{protocol} addr=[" . length( $r->{addr} ) . " bytes]" );
diag( " addr=" . join( ", ", map { sprintf '0x%02x', ord $_ } split m//, $r->{addr} ) );
}
}
}
# Numeric addresses with AI_NUMERICHOST should pass (RT95758)
AI_NUMERICHOST: {
# Here we need a port that is open to the world. Not all places have all
# the ports. For example Solaris by default doesn't have http/80 in
# /etc/services, and that would fail. Let's try a couple of commonly open
# ports, and hope one of them will succeed. Conversely this means that
# sometimes this will fail.
#
# An alternative method would be to manually parse /etc/services and look
# for enabled services but that's kind of yuck, too.
my @port = (80, 7, 22, 25, 88, 123, 110, 389, 443, 445, 873, 2049, 3306);
foreach my $port ( @port ) {
( $err, @res ) = getaddrinfo( "127.0.0.1", $port, { flags => AI_NUMERICHOST, socktype => SOCK_STREAM } );
if( $err == 0 ) {
ok( $err == 0, "\$err == 0 for 127.0.0.1/$port/flags=AI_NUMERICHOST" );
last AI_NUMERICHOST;
}
}
fail( "$err for 127.0.0.1/$port[-1]/flags=AI_NUMERICHOST (failed for ports @port)" );
}
# Now check that names with AI_NUMERICHOST fail
SKIP: {
skip "Resolver has no answer for $goodhost", 1 unless gethostbyname( $goodhost );
( $err, @res ) = getaddrinfo( $goodhost, "ftp", { flags => AI_NUMERICHOST, socktype => SOCK_STREAM } );
ok( $err != 0, "\$err != 0 for host=$goodhost/service=ftp/flags=AI_NUMERICHOST/socktype=SOCK_STREAM" );
}
# Some sanity checking on the hints hash
ok( defined eval { getaddrinfo( "127.0.0.1", "80", undef ); 1 },
'getaddrinfo() with undef hints works' );
ok( !defined eval { getaddrinfo( "127.0.0.1", "80", "hints" ); 1 },
'getaddrinfo() with string hints dies' );
ok( !defined eval { getaddrinfo( "127.0.0.1", "80", [] ); 1 },
'getaddrinfo() with ARRAY hints dies' );
# Ensure it doesn't segfault if args are missing
( $err, @res ) = getaddrinfo();
ok( defined $err, '$err defined for getaddrinfo()' );
( $err, @res ) = getaddrinfo( "127.0.0.1" );
ok( defined $err, '$err defined for getaddrinfo("127.0.0.1")' );
|