line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# You may distribute under the terms of either the GNU General Public License |
2
|
|
|
|
|
|
|
# or the Artistic License (the same terms as Perl itself) |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# (C) Paul Evans, 2007-2021 -- leonerd@leonerd.org.uk |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
package IO::Async::Resolver; |
7
|
|
|
|
|
|
|
|
8
|
7
|
|
|
7
|
|
1408
|
use strict; |
|
7
|
|
|
|
|
17
|
|
|
7
|
|
|
|
|
261
|
|
9
|
7
|
|
|
7
|
|
37
|
use warnings; |
|
7
|
|
|
|
|
14
|
|
|
7
|
|
|
|
|
214
|
|
10
|
7
|
|
|
7
|
|
46
|
use base qw( IO::Async::Function ); |
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
3958
|
|
11
|
|
|
|
|
|
|
|
12
|
|
|
|
|
|
|
our $VERSION = '0.801'; |
13
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
# Socket 2.006 fails to getaddrinfo() AI_NUMERICHOST properly on MSWin32 |
15
|
7
|
|
|
|
|
610
|
use Socket 2.007 qw( |
16
|
|
|
|
|
|
|
AI_NUMERICHOST AI_PASSIVE |
17
|
|
|
|
|
|
|
NI_NUMERICHOST NI_NUMERICSERV NI_DGRAM |
18
|
|
|
|
|
|
|
EAI_NONAME |
19
|
7
|
|
|
7
|
|
57
|
); |
|
7
|
|
|
|
|
176
|
|
20
|
|
|
|
|
|
|
|
21
|
7
|
|
|
7
|
|
63
|
use IO::Async::Metrics '$METRICS'; |
|
7
|
|
|
|
|
16
|
|
|
7
|
|
|
|
|
54
|
|
22
|
7
|
|
|
7
|
|
46
|
use IO::Async::OS; |
|
7
|
|
|
|
|
34
|
|
|
7
|
|
|
|
|
457
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Try to use HiRes alarm, but we don't strictly need it. |
25
|
|
|
|
|
|
|
# MSWin32 doesn't implement it |
26
|
|
|
|
|
|
|
BEGIN { |
27
|
7
|
|
|
7
|
|
57
|
require Time::HiRes; |
28
|
7
|
50
|
|
|
|
17
|
eval { Time::HiRes::alarm(0) } and Time::HiRes->import( qw( alarm ) ); |
|
7
|
|
|
|
|
300
|
|
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
|
31
|
7
|
|
|
7
|
|
46
|
use Carp; |
|
7
|
|
|
|
|
13
|
|
|
7
|
|
|
|
|
21189
|
|
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
my $started = 0; |
34
|
|
|
|
|
|
|
my %METHODS; |
35
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
=head1 NAME |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
C - performing name resolutions asynchronously |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
=head1 SYNOPSIS |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
This object is used indirectly via an L: |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
use IO::Async::Loop; |
45
|
|
|
|
|
|
|
my $loop = IO::Async::Loop->new; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
my @results = $loop->resolver->getaddrinfo( |
48
|
|
|
|
|
|
|
host => "www.example.com", |
49
|
|
|
|
|
|
|
service => "http", |
50
|
|
|
|
|
|
|
)->get; |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
foreach my $addr ( @results ) { |
53
|
|
|
|
|
|
|
printf "http://www.example.com can be reached at " . |
54
|
|
|
|
|
|
|
"socket(%d,%d,%d) + connect('%v02x')\n", |
55
|
|
|
|
|
|
|
@{$addr}{qw( family socktype protocol addr )}; |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
my @pwent = $loop->resolve( type => 'getpwuid', data => [ $< ] )->get; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
print "My passwd ent: " . join( "|", @pwent ) . "\n"; |
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head1 DESCRIPTION |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
This module extends an L to use the system's name resolver |
65
|
|
|
|
|
|
|
functions asynchronously. It provides a number of named resolvers, each one |
66
|
|
|
|
|
|
|
providing an asynchronous wrapper around a single resolver function. |
67
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
Because the system may not provide asynchronous versions of its resolver |
69
|
|
|
|
|
|
|
functions, this class is implemented using a L object |
70
|
|
|
|
|
|
|
that wraps the normal (blocking) functions. In this case, name resolutions |
71
|
|
|
|
|
|
|
will be performed asynchronously from the rest of the program, but will likely |
72
|
|
|
|
|
|
|
be done by a single background worker process, so will be processed in the |
73
|
|
|
|
|
|
|
order they were requested; a single slow lookup will hold up the queue of |
74
|
|
|
|
|
|
|
other requests behind it. To mitigate this, multiple worker processes can be |
75
|
|
|
|
|
|
|
used; see the C argument to the constructor. |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
The C parameter for the underlying L object |
78
|
|
|
|
|
|
|
is set to a default of 30 seconds, and C is set to 0. This |
79
|
|
|
|
|
|
|
ensures that there are no spare processes sitting idle during the common case |
80
|
|
|
|
|
|
|
of no outstanding requests. |
81
|
|
|
|
|
|
|
|
82
|
|
|
|
|
|
|
=cut |
83
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
sub _init |
85
|
|
|
|
|
|
|
{ |
86
|
6
|
|
|
6
|
|
28
|
my $self = shift; |
87
|
6
|
|
|
|
|
15
|
my ( $params ) = @_; |
88
|
6
|
|
|
|
|
41
|
$self->SUPER::_init( @_ ); |
89
|
|
|
|
|
|
|
|
90
|
6
|
|
|
|
|
15
|
$params->{module} = __PACKAGE__; |
91
|
6
|
|
|
|
|
13
|
$params->{func} = "_resolve"; |
92
|
|
|
|
|
|
|
|
93
|
6
|
|
|
|
|
14
|
$params->{idle_timeout} = 30; |
94
|
6
|
|
|
|
|
8
|
$params->{min_workers} = 0; |
95
|
|
|
|
|
|
|
|
96
|
6
|
|
|
|
|
21
|
$started = 1; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
sub _resolve |
100
|
|
|
|
|
|
|
{ |
101
|
0
|
|
|
0
|
|
0
|
my ( $type, $timeout, @data ) = @_; |
102
|
|
|
|
|
|
|
|
103
|
0
|
0
|
|
|
|
0
|
if( my $code = $METHODS{$type} ) { |
104
|
0
|
|
|
0
|
|
0
|
local $SIG{ALRM} = sub { die "Timed out\n" }; |
|
0
|
|
|
|
|
0
|
|
105
|
|
|
|
|
|
|
|
106
|
0
|
|
|
|
|
0
|
alarm( $timeout ); |
107
|
0
|
|
|
|
|
0
|
my @ret = eval { $code->( @data ) }; |
|
0
|
|
|
|
|
0
|
|
108
|
0
|
|
|
|
|
0
|
alarm( 0 ); |
109
|
|
|
|
|
|
|
|
110
|
0
|
0
|
|
|
|
0
|
die $@ if $@; |
111
|
0
|
|
|
|
|
0
|
return @ret; |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
else { |
114
|
0
|
|
|
|
|
0
|
die "Unrecognised resolver request '$type'"; |
115
|
|
|
|
|
|
|
} |
116
|
|
|
|
|
|
|
} |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
sub debug_printf_call |
119
|
|
|
|
|
|
|
{ |
120
|
15
|
|
|
15
|
0
|
22
|
my $self = shift; |
121
|
15
|
|
|
|
|
43
|
my ( $type, undef, @data ) = @_; |
122
|
|
|
|
|
|
|
|
123
|
15
|
|
|
|
|
28
|
my $arg0; |
124
|
15
|
100
|
|
|
|
48
|
if( $type eq "getaddrinfo" ) { |
|
|
100
|
|
|
|
|
|
125
|
5
|
|
|
|
|
39
|
my %args = @data; |
126
|
5
|
|
|
|
|
30
|
$arg0 = sprintf "%s:%s", @args{qw( host service )}; |
127
|
|
|
|
|
|
|
} |
128
|
|
|
|
|
|
|
elsif( $type eq "getnameinfo" ) { |
129
|
|
|
|
|
|
|
# cheat |
130
|
3
|
|
|
|
|
11
|
$arg0 = sprintf "%s:%s", ( Socket::getnameinfo( $data[0], NI_NUMERICHOST|NI_NUMERICSERV ) )[1,2]; |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
else { |
133
|
7
|
|
|
|
|
14
|
$arg0 = $data[0]; |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
15
|
|
|
|
|
150
|
$self->debug_printf( "CALL $type $arg0" ); |
137
|
|
|
|
|
|
|
} |
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
sub debug_printf_result |
140
|
|
|
|
|
|
|
{ |
141
|
14
|
|
|
14
|
0
|
20
|
my $self = shift; |
142
|
14
|
|
|
|
|
32
|
my ( @result ) = @_; |
143
|
14
|
|
|
|
|
61
|
$self->debug_printf( "RESULT n=" . scalar @result ); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
=head1 METHODS |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
The following methods documented with a trailing call to C<< ->get >> return |
149
|
|
|
|
|
|
|
L instances. |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=cut |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
=head2 resolve |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
@result = $loop->resolve( %params )->get |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
Performs a single name resolution operation, as given by the keys in the hash. |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
The C<%params> hash keys the following keys: |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=over 8 |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
=item type => STRING |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
Name of the resolution operation to perform. See BUILT-IN RESOLVERS for the |
166
|
|
|
|
|
|
|
list of available operations. |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=item data => ARRAY |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Arguments to pass to the resolver function. Exact meaning depends on the |
171
|
|
|
|
|
|
|
specific function chosen by the C; see BUILT-IN RESOLVERS. |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
=item timeout => NUMBER |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
Optional. Timeout in seconds, after which the resolver operation will abort |
176
|
|
|
|
|
|
|
with a timeout exception. If not supplied, a default of 10 seconds will apply. |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
=back |
179
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
On failure, the fail category name is C; the details give the |
181
|
|
|
|
|
|
|
individual resolver function name (e.g. C), followed by other |
182
|
|
|
|
|
|
|
error details specific to the resolver in question. |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
->fail( $message, resolve => $type => @details ) |
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
=head2 resolve (void) |
187
|
|
|
|
|
|
|
|
188
|
|
|
|
|
|
|
$resolver->resolve( %params ) |
189
|
|
|
|
|
|
|
|
190
|
|
|
|
|
|
|
When not returning a future, additional parameters can be given containing the |
191
|
|
|
|
|
|
|
continuations to invoke on success or failure: |
192
|
|
|
|
|
|
|
|
193
|
|
|
|
|
|
|
=over 8 |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
=item on_resolved => CODE |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
A continuation that is invoked when the resolver function returns a successful |
198
|
|
|
|
|
|
|
result. It will be passed the array returned by the resolver function. |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
$on_resolved->( @result ) |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
=item on_error => CODE |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
A continuation that is invoked when the resolver function fails. It will be |
205
|
|
|
|
|
|
|
passed the exception thrown by the function. |
206
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
=back |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
=cut |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub resolve |
212
|
|
|
|
|
|
|
{ |
213
|
15
|
|
|
15
|
1
|
15102
|
my $self = shift; |
214
|
15
|
|
|
|
|
89
|
my %args = @_; |
215
|
|
|
|
|
|
|
|
216
|
15
|
|
|
|
|
32
|
my $type = $args{type}; |
217
|
15
|
50
|
|
|
|
38
|
defined $type or croak "Expected 'type'"; |
218
|
|
|
|
|
|
|
|
219
|
15
|
100
|
|
|
|
37
|
if( $type eq "getaddrinfo_hash" ) { |
220
|
1
|
|
|
|
|
5
|
$type = "getaddrinfo"; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
15
|
50
|
|
|
|
35
|
exists $METHODS{$type} or croak "Expected 'type' to be an existing resolver method, got '$type'"; |
224
|
|
|
|
|
|
|
|
225
|
15
|
|
|
|
|
25
|
my $on_resolved; |
226
|
15
|
100
|
|
|
|
48
|
if( $on_resolved = $args{on_resolved} ) { |
|
|
50
|
|
|
|
|
|
227
|
7
|
50
|
|
|
|
17
|
ref $on_resolved or croak "Expected 'on_resolved' to be a reference"; |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
elsif( !defined wantarray ) { |
230
|
0
|
|
|
|
|
0
|
croak "Expected 'on_resolved' or to return a Future"; |
231
|
|
|
|
|
|
|
} |
232
|
|
|
|
|
|
|
|
233
|
15
|
|
|
|
|
24
|
my $on_error; |
234
|
15
|
100
|
|
|
|
36
|
if( $on_error = $args{on_error} ) { |
|
|
50
|
|
|
|
|
|
235
|
7
|
50
|
|
|
|
14
|
ref $on_error or croak "Expected 'on_error' to be a reference"; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
elsif( !defined wantarray ) { |
238
|
0
|
|
|
|
|
0
|
croak "Expected 'on_error' or to return a Future"; |
239
|
|
|
|
|
|
|
} |
240
|
|
|
|
|
|
|
|
241
|
15
|
|
50
|
|
|
59
|
my $timeout = $args{timeout} || 10; |
242
|
|
|
|
|
|
|
|
243
|
15
|
100
|
|
|
|
72
|
$METRICS and $METRICS->inc_counter( resolver_lookups => [ type => $type ] ); |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
my $future = $self->call( |
246
|
15
|
|
|
|
|
71
|
args => [ $type, $timeout, @{$args{data}} ], |
247
|
|
|
|
|
|
|
)->else( sub { |
248
|
1
|
|
|
1
|
|
34
|
my ( $message, @detail ) = @_; |
249
|
1
|
50
|
|
|
|
6
|
$METRICS and $METRICS->inc_counter( resolver_failures => [ type => $type ] ); |
250
|
1
|
|
|
|
|
99
|
Future->fail( $message, resolve => $type => @detail ); |
251
|
15
|
|
|
|
|
1286
|
}); |
252
|
|
|
|
|
|
|
|
253
|
15
|
100
|
|
|
|
620
|
$future->on_done( $on_resolved ) if $on_resolved; |
254
|
15
|
100
|
|
|
|
169
|
$future->on_fail( $on_error ) if $on_error; |
255
|
|
|
|
|
|
|
|
256
|
15
|
100
|
|
|
|
270
|
return $future if defined wantarray; |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
# Caller is not going to keep hold of the Future, so we have to ensure it |
259
|
|
|
|
|
|
|
# stays alive somehow |
260
|
7
|
|
|
0
|
|
24
|
$self->adopt_future( $future->else( sub { Future->done } ) ); |
|
0
|
|
|
|
|
0
|
|
261
|
|
|
|
|
|
|
} |
262
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
=head2 getaddrinfo |
264
|
|
|
|
|
|
|
|
265
|
|
|
|
|
|
|
@addrs = $resolver->getaddrinfo( %args )->get |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
A shortcut wrapper around the C resolver, taking its arguments in |
268
|
|
|
|
|
|
|
a more convenient form. |
269
|
|
|
|
|
|
|
|
270
|
|
|
|
|
|
|
=over 8 |
271
|
|
|
|
|
|
|
|
272
|
|
|
|
|
|
|
=item host => STRING |
273
|
|
|
|
|
|
|
|
274
|
|
|
|
|
|
|
=item service => STRING |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
The host and service names to look up. At least one must be provided. |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=item family => INT or STRING |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=item socktype => INT or STRING |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
=item protocol => INT |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
Hint values used to filter the results. |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
=item flags => INT |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
Flags to control the C function. See the C constants in |
289
|
|
|
|
|
|
|
L's C function for more detail. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
=item passive => BOOL |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
If true, sets the C flag. This is provided as a convenience to |
294
|
|
|
|
|
|
|
avoid the caller from having to import the C constant from |
295
|
|
|
|
|
|
|
C. |
296
|
|
|
|
|
|
|
|
297
|
|
|
|
|
|
|
=item timeout => NUMBER |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
Time in seconds after which to abort the lookup with a C exception |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
=back |
302
|
|
|
|
|
|
|
|
303
|
|
|
|
|
|
|
On success, the future will yield the result as a list of HASH references; |
304
|
|
|
|
|
|
|
each containing one result. Each result will contain fields called C, |
305
|
|
|
|
|
|
|
C, C and C. If requested by C then the |
306
|
|
|
|
|
|
|
C field will also be present. |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
On failure, the detail field will give the error number, which should match |
309
|
|
|
|
|
|
|
one of the C constants. |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
->fail( $message, resolve => getaddrinfo => $eai_errno ) |
312
|
|
|
|
|
|
|
|
313
|
|
|
|
|
|
|
As a specific optimisation, this method will try to perform a lookup of |
314
|
|
|
|
|
|
|
numeric values synchronously, rather than asynchronously, if it looks likely |
315
|
|
|
|
|
|
|
to succeed. |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
Specifically, if the service name is entirely numeric, and the hostname looks |
318
|
|
|
|
|
|
|
like an IPv4 or IPv6 string, a synchronous lookup will first be performed |
319
|
|
|
|
|
|
|
using the C flag. If this gives an C error, then |
320
|
|
|
|
|
|
|
the lookup is performed asynchronously instead. |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=head2 getaddrinfo (void) |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
$resolver->getaddrinfo( %args ) |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
When not returning a future, additional parameters can be given containing the |
327
|
|
|
|
|
|
|
continuations to invoke on success or failure: |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
=over 8 |
330
|
|
|
|
|
|
|
|
331
|
|
|
|
|
|
|
=item on_resolved => CODE |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
Callback which is invoked after a successful lookup. |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
$on_resolved->( @addrs ) |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
=item on_error => CODE |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
Callback which is invoked after a failed lookup, including for a timeout. |
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
$on_error->( $exception ) |
342
|
|
|
|
|
|
|
|
343
|
|
|
|
|
|
|
=back |
344
|
|
|
|
|
|
|
|
345
|
|
|
|
|
|
|
=cut |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
sub getaddrinfo |
348
|
|
|
|
|
|
|
{ |
349
|
16
|
|
|
16
|
1
|
8075
|
my $self = shift; |
350
|
16
|
|
|
|
|
76
|
my %args = @_; |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
$args{on_resolved} or defined wantarray or |
353
|
16
|
50
|
66
|
|
|
96
|
croak "Expected 'on_resolved' or to return a Future"; |
354
|
|
|
|
|
|
|
|
355
|
|
|
|
|
|
|
$args{on_error} or defined wantarray or |
356
|
16
|
50
|
66
|
|
|
90
|
croak "Expected 'on_error' or to return a Future"; |
357
|
|
|
|
|
|
|
|
358
|
16
|
|
100
|
|
|
58
|
my $host = $args{host} || ""; |
359
|
16
|
100
|
|
|
|
36
|
my $service = $args{service}; defined $service or $service = ""; |
|
16
|
|
|
|
|
52
|
|
360
|
16
|
|
50
|
|
|
72
|
my $flags = $args{flags} || 0; |
361
|
|
|
|
|
|
|
|
362
|
16
|
100
|
|
|
|
38
|
$flags |= AI_PASSIVE if $args{passive}; |
363
|
|
|
|
|
|
|
|
364
|
16
|
100
|
|
|
|
100
|
$args{family} = IO::Async::OS->getfamilybyname( $args{family} ) if defined $args{family}; |
365
|
16
|
50
|
|
|
|
99
|
$args{socktype} = IO::Async::OS->getsocktypebyname( $args{socktype} ) if defined $args{socktype}; |
366
|
|
|
|
|
|
|
|
367
|
|
|
|
|
|
|
# Clear any other existing but undefined hints |
368
|
16
|
|
66
|
|
|
110
|
defined $args{$_} or delete $args{$_} for keys %args; |
369
|
|
|
|
|
|
|
|
370
|
|
|
|
|
|
|
# It's likely this will succeed with AI_NUMERICHOST if host contains only |
371
|
|
|
|
|
|
|
# [\d.] (IPv4) or [[:xdigit:]:] (IPv6) |
372
|
|
|
|
|
|
|
# Technically we should pass AI_NUMERICSERV but not all platforms support |
373
|
|
|
|
|
|
|
# it, but since we're checking service contains only \d we should be fine. |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
# These address tests don't have to be perfect as if it fails we'll get |
376
|
|
|
|
|
|
|
# EAI_NONAME and just try it asynchronously anyway |
377
|
16
|
100
|
100
|
|
|
233
|
if( ( $host =~ m/^[\d.]+$/ or $host =~ m/^[[:xdigit:]:]$/ or $host eq "" ) and |
|
|
|
66
|
|
|
|
|
378
|
|
|
|
|
|
|
$service =~ m/^\d*$/ ) { |
379
|
|
|
|
|
|
|
|
380
|
12
|
|
|
|
|
558
|
my ( $err, @results ) = Socket::getaddrinfo( $host, $service, |
381
|
|
|
|
|
|
|
{ %args, flags => $flags | AI_NUMERICHOST } |
382
|
|
|
|
|
|
|
); |
383
|
|
|
|
|
|
|
|
384
|
12
|
50
|
|
|
|
224
|
if( !$err ) { |
|
|
0
|
|
|
|
|
|
385
|
12
|
|
|
|
|
45
|
my $future = $self->loop->new_future->done( @results ); |
386
|
12
|
100
|
|
|
|
525
|
$future->on_done( $args{on_resolved} ) if $args{on_resolved}; |
387
|
12
|
|
|
|
|
137
|
return $future; |
388
|
|
|
|
|
|
|
} |
389
|
|
|
|
|
|
|
elsif( $err == EAI_NONAME ) { |
390
|
|
|
|
|
|
|
# fallthrough to async case |
391
|
|
|
|
|
|
|
} |
392
|
|
|
|
|
|
|
else { |
393
|
0
|
|
|
|
|
0
|
my $future = $self->loop->new_future->fail( $err, resolve => getaddrinfo => $err+0 ); |
394
|
0
|
0
|
|
|
|
0
|
$future->on_fail( $args{on_error} ) if $args{on_error}; |
395
|
0
|
|
|
|
|
0
|
return $future; |
396
|
|
|
|
|
|
|
} |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
my $future = $self->resolve( |
400
|
|
|
|
|
|
|
type => "getaddrinfo", |
401
|
|
|
|
|
|
|
data => [ |
402
|
|
|
|
|
|
|
host => $host, |
403
|
|
|
|
|
|
|
service => $service, |
404
|
|
|
|
|
|
|
flags => $flags, |
405
|
12
|
100
|
|
|
|
63
|
map { exists $args{$_} ? ( $_ => $args{$_} ) : () } qw( family socktype protocol ), |
406
|
|
|
|
|
|
|
], |
407
|
|
|
|
|
|
|
timeout => $args{timeout}, |
408
|
4
|
|
|
|
|
21
|
); |
409
|
|
|
|
|
|
|
|
410
|
4
|
100
|
|
|
|
32
|
$future->on_done( $args{on_resolved} ) if $args{on_resolved}; |
411
|
4
|
100
|
|
|
|
45
|
$future->on_fail( $args{on_error} ) if $args{on_error}; |
412
|
|
|
|
|
|
|
|
413
|
4
|
100
|
|
|
|
107
|
return $future if defined wantarray; |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
# Caller is not going to keep hold of the Future, so we have to ensure it |
416
|
|
|
|
|
|
|
# stays alive somehow |
417
|
1
|
|
|
0
|
|
15
|
$self->adopt_future( $future->else( sub { Future->done } ) ); |
|
0
|
|
|
|
|
0
|
|
418
|
|
|
|
|
|
|
} |
419
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
=head2 getnameinfo |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
( $host, $service ) = $resolver->getnameinfo( %args )->get |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
A shortcut wrapper around the C resolver, taking its arguments in |
425
|
|
|
|
|
|
|
a more convenient form. |
426
|
|
|
|
|
|
|
|
427
|
|
|
|
|
|
|
=over 8 |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
=item addr => STRING |
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
The packed socket address to look up. |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=item flags => INT |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Flags to control the C function. See the C constants in |
436
|
|
|
|
|
|
|
L's C for more detail. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
=item numerichost => BOOL |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=item numericserv => BOOL |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
=item dgram => BOOL |
443
|
|
|
|
|
|
|
|
444
|
|
|
|
|
|
|
If true, set the C, C or C flags. |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=item numeric => BOOL |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
If true, sets both C and C flags. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
=item timeout => NUMBER |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
Time in seconds after which to abort the lookup with a C exception |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=back |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
On failure, the detail field will give the error number, which should match |
457
|
|
|
|
|
|
|
one of the C constants. |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
->fail( $message, resolve => getnameinfo => $eai_errno ) |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
As a specific optimisation, this method will try to perform a lookup of |
462
|
|
|
|
|
|
|
numeric values synchronously, rather than asynchronously, if both the |
463
|
|
|
|
|
|
|
C and C flags are given. |
464
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=head2 getnameinfo (void) |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
$resolver->getnameinfo( %args ) |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
When not returning a future, additional parameters can be given containing the |
470
|
|
|
|
|
|
|
continuations to invoke on success or failure: |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
=over 8 |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
=item on_resolved => CODE |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
Callback which is invoked after a successful lookup. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
$on_resolved->( $host, $service ) |
479
|
|
|
|
|
|
|
|
480
|
|
|
|
|
|
|
=item on_error => CODE |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
Callback which is invoked after a failed lookup, including for a timeout. |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
$on_error->( $exception ) |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
=back |
487
|
|
|
|
|
|
|
|
488
|
|
|
|
|
|
|
=cut |
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
sub getnameinfo |
491
|
|
|
|
|
|
|
{ |
492
|
5
|
|
|
5
|
1
|
5194
|
my $self = shift; |
493
|
5
|
|
|
|
|
28
|
my %args = @_; |
494
|
|
|
|
|
|
|
|
495
|
|
|
|
|
|
|
$args{on_resolved} or defined wantarray or |
496
|
5
|
50
|
66
|
|
|
26
|
croak "Expected 'on_resolved' or to return a Future"; |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
$args{on_error} or defined wantarray or |
499
|
5
|
50
|
66
|
|
|
21
|
croak "Expected 'on_error' or to return a Future"; |
500
|
|
|
|
|
|
|
|
501
|
5
|
|
50
|
|
|
30
|
my $flags = $args{flags} || 0; |
502
|
|
|
|
|
|
|
|
503
|
5
|
50
|
|
|
|
16
|
$flags |= NI_NUMERICHOST if $args{numerichost}; |
504
|
5
|
50
|
|
|
|
11
|
$flags |= NI_NUMERICSERV if $args{numericserv}; |
505
|
5
|
50
|
|
|
|
13
|
$flags |= NI_DGRAM if $args{dgram}; |
506
|
|
|
|
|
|
|
|
507
|
5
|
100
|
|
|
|
10
|
$flags |= NI_NUMERICHOST|NI_NUMERICSERV if $args{numeric}; |
508
|
|
|
|
|
|
|
|
509
|
5
|
100
|
|
|
|
15
|
if( $flags & (NI_NUMERICHOST|NI_NUMERICSERV) ) { |
510
|
|
|
|
|
|
|
# This is a numeric-only lookup that can be done synchronously |
511
|
2
|
|
|
|
|
8
|
my ( $err, $host, $service ) = Socket::getnameinfo( $args{addr}, $flags ); |
512
|
|
|
|
|
|
|
|
513
|
2
|
50
|
|
|
|
48
|
if( $err ) { |
514
|
0
|
|
|
|
|
0
|
my $future = $self->loop->new_future->fail( $err, resolve => getnameinfo => $err+0 ); |
515
|
0
|
0
|
|
|
|
0
|
$future->on_fail( $args{on_error} ) if $args{on_error}; |
516
|
0
|
|
|
|
|
0
|
return $future; |
517
|
|
|
|
|
|
|
} |
518
|
|
|
|
|
|
|
else { |
519
|
2
|
|
|
|
|
8
|
my $future = $self->loop->new_future->done( $host, $service ); |
520
|
2
|
100
|
|
|
|
74
|
$future->on_done( $args{on_resolved} ) if $args{on_resolved}; |
521
|
2
|
|
|
|
|
28
|
return $future; |
522
|
|
|
|
|
|
|
} |
523
|
|
|
|
|
|
|
} |
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
my $future = $self->resolve( |
526
|
|
|
|
|
|
|
type => "getnameinfo", |
527
|
|
|
|
|
|
|
data => [ $args{addr}, $flags ], |
528
|
|
|
|
|
|
|
timeout => $args{timeout}, |
529
|
|
|
|
|
|
|
)->transform( |
530
|
3
|
|
|
3
|
|
313
|
done => sub { @{ $_[0] } }, # unpack the ARRAY ref |
|
3
|
|
|
|
|
10
|
|
531
|
3
|
|
|
|
|
15
|
); |
532
|
|
|
|
|
|
|
|
533
|
3
|
100
|
|
|
|
115
|
$future->on_done( $args{on_resolved} ) if $args{on_resolved}; |
534
|
3
|
100
|
|
|
|
41
|
$future->on_fail( $args{on_error} ) if $args{on_error}; |
535
|
|
|
|
|
|
|
|
536
|
3
|
100
|
|
|
|
37
|
return $future if defined wantarray; |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
# Caller is not going to keep hold of the Future, so we have to ensure it |
539
|
|
|
|
|
|
|
# stays alive somehow |
540
|
1
|
|
|
0
|
|
30
|
$self->adopt_future( $future->else( sub { Future->done } ) ); |
|
0
|
|
|
|
|
0
|
|
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
=head1 FUNCTIONS |
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
=cut |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=head2 register_resolver( $name, $code ) |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
Registers a new named resolver function that can be called by the C |
550
|
|
|
|
|
|
|
method. All named resolvers must be registered before the object is |
551
|
|
|
|
|
|
|
constructed. |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
=over 8 |
554
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
=item $name |
556
|
|
|
|
|
|
|
|
557
|
|
|
|
|
|
|
The name of the resolver function; must be a plain string. This name will be |
558
|
|
|
|
|
|
|
used by the C argument to the C method, to identify it. |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=item $code |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
A CODE reference to the resolver function body. It will be called in list |
563
|
|
|
|
|
|
|
context, being passed the list of arguments given in the C argument to |
564
|
|
|
|
|
|
|
the C method. The returned list will be passed to the |
565
|
|
|
|
|
|
|
C callback. If the code throws an exception at call time, it will |
566
|
|
|
|
|
|
|
be passed to the C continuation. If it returns normally, the list of |
567
|
|
|
|
|
|
|
values it returns will be passed to C. |
568
|
|
|
|
|
|
|
|
569
|
|
|
|
|
|
|
=back |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
=cut |
572
|
|
|
|
|
|
|
|
573
|
|
|
|
|
|
|
# Plain function, not a method |
574
|
|
|
|
|
|
|
sub register_resolver |
575
|
|
|
|
|
|
|
{ |
576
|
105
|
|
|
105
|
1
|
175
|
my ( $name, $code ) = @_; |
577
|
|
|
|
|
|
|
|
578
|
105
|
50
|
|
|
|
202
|
croak "Cannot register new resolver methods once the resolver has been started" if $started; |
579
|
|
|
|
|
|
|
|
580
|
105
|
50
|
|
|
|
196
|
croak "Already have a resolver method called '$name'" if exists $METHODS{$name}; |
581
|
105
|
|
|
|
|
188
|
$METHODS{$name} = $code; |
582
|
|
|
|
|
|
|
} |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
=head1 BUILT-IN RESOLVERS |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
The following resolver names are implemented by the same-named perl function, |
587
|
|
|
|
|
|
|
taking and returning a list of values exactly as the perl function does: |
588
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
getpwnam getpwuid |
590
|
|
|
|
|
|
|
getgrnam getgrgid |
591
|
|
|
|
|
|
|
getservbyname getservbyport |
592
|
|
|
|
|
|
|
gethostbyname gethostbyaddr |
593
|
|
|
|
|
|
|
getnetbyname getnetbyaddr |
594
|
|
|
|
|
|
|
getprotobyname getprotobynumber |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
=cut |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
# Now register the inbuilt methods |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
register_resolver getpwnam => sub { my @r = getpwnam( $_[0] ) or die "$!\n"; @r }; |
601
|
|
|
|
|
|
|
register_resolver getpwuid => sub { my @r = getpwuid( $_[0] ) or die "$!\n"; @r }; |
602
|
|
|
|
|
|
|
|
603
|
|
|
|
|
|
|
register_resolver getgrnam => sub { my @r = getgrnam( $_[0] ) or die "$!\n"; @r }; |
604
|
|
|
|
|
|
|
register_resolver getgrgid => sub { my @r = getgrgid( $_[0] ) or die "$!\n"; @r }; |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
register_resolver getservbyname => sub { my @r = getservbyname( $_[0], $_[1] ) or die "$!\n"; @r }; |
607
|
|
|
|
|
|
|
register_resolver getservbyport => sub { my @r = getservbyport( $_[0], $_[1] ) or die "$!\n"; @r }; |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
register_resolver gethostbyname => sub { my @r = gethostbyname( $_[0] ) or die "$!\n"; @r }; |
610
|
|
|
|
|
|
|
register_resolver gethostbyaddr => sub { my @r = gethostbyaddr( $_[0], $_[1] ) or die "$!\n"; @r }; |
611
|
|
|
|
|
|
|
|
612
|
|
|
|
|
|
|
register_resolver getnetbyname => sub { my @r = getnetbyname( $_[0] ) or die "$!\n"; @r }; |
613
|
|
|
|
|
|
|
register_resolver getnetbyaddr => sub { my @r = getnetbyaddr( $_[0], $_[1] ) or die "$!\n"; @r }; |
614
|
|
|
|
|
|
|
|
615
|
|
|
|
|
|
|
register_resolver getprotobyname => sub { my @r = getprotobyname( $_[0] ) or die "$!\n"; @r }; |
616
|
|
|
|
|
|
|
register_resolver getprotobynumber => sub { my @r = getprotobynumber( $_[0] ) or die "$!\n"; @r }; |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
=pod |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
The following three resolver names are implemented using the L module. |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
getaddrinfo |
623
|
|
|
|
|
|
|
getaddrinfo_array |
624
|
|
|
|
|
|
|
getnameinfo |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
The C resolver takes arguments in a hash of name/value pairs and |
627
|
|
|
|
|
|
|
returns a list of hash structures, as the C function |
628
|
|
|
|
|
|
|
does. For neatness it takes all its arguments as named values; taking the host |
629
|
|
|
|
|
|
|
and service names from arguments called C and C respectively; |
630
|
|
|
|
|
|
|
all the remaining arguments are passed into the hints hash. This name is also |
631
|
|
|
|
|
|
|
aliased as simply C. |
632
|
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
The C resolver behaves more like the C version of |
634
|
|
|
|
|
|
|
the function. It takes hints in a flat list, and mangles the result of the |
635
|
|
|
|
|
|
|
function, so that the returned value is more useful to the caller. It splits |
636
|
|
|
|
|
|
|
up the list of 5-tuples into a list of ARRAY refs, where each referenced array |
637
|
|
|
|
|
|
|
contains one of the tuples of 5 values. |
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
As an extra convenience to the caller, both resolvers will also accept plain |
640
|
|
|
|
|
|
|
string names for the C argument, converting C and possibly |
641
|
|
|
|
|
|
|
C into the appropriate C value, and for the C argument, |
642
|
|
|
|
|
|
|
converting C, C or C into the appropriate C value. |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
The C resolver returns its result in the same form as C. |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
Because this module simply uses the system's C resolver, it will |
647
|
|
|
|
|
|
|
be fully IPv6-aware if the underlying platform's resolver is. This allows |
648
|
|
|
|
|
|
|
programs to be fully IPv6-capable. |
649
|
|
|
|
|
|
|
|
650
|
|
|
|
|
|
|
=cut |
651
|
|
|
|
|
|
|
|
652
|
|
|
|
|
|
|
register_resolver getaddrinfo => sub { |
653
|
|
|
|
|
|
|
my %args = @_; |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
my $host = delete $args{host}; |
656
|
|
|
|
|
|
|
my $service = delete $args{service}; |
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
$args{family} = IO::Async::OS->getfamilybyname( $args{family} ) if defined $args{family}; |
659
|
|
|
|
|
|
|
$args{socktype} = IO::Async::OS->getsocktypebyname( $args{socktype} ) if defined $args{socktype}; |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
# Clear any other existing but undefined hints |
662
|
|
|
|
|
|
|
defined $args{$_} or delete $args{$_} for keys %args; |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
my ( $err, @addrs ) = Socket::getaddrinfo( $host, $service, \%args ); |
665
|
|
|
|
|
|
|
|
666
|
|
|
|
|
|
|
die [ "$err", $err+0 ] if $err; |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
return @addrs; |
669
|
|
|
|
|
|
|
}; |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
register_resolver getaddrinfo_array => sub { |
672
|
|
|
|
|
|
|
my ( $host, $service, $family, $socktype, $protocol, $flags ) = @_; |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
$family = IO::Async::OS->getfamilybyname( $family ); |
675
|
|
|
|
|
|
|
$socktype = IO::Async::OS->getsocktypebyname( $socktype ); |
676
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
my %hints; |
678
|
|
|
|
|
|
|
$hints{family} = $family if defined $family; |
679
|
|
|
|
|
|
|
$hints{socktype} = $socktype if defined $socktype; |
680
|
|
|
|
|
|
|
$hints{protocol} = $protocol if defined $protocol; |
681
|
|
|
|
|
|
|
$hints{flags} = $flags if defined $flags; |
682
|
|
|
|
|
|
|
|
683
|
|
|
|
|
|
|
my ( $err, @addrs ) = Socket::getaddrinfo( $host, $service, \%hints ); |
684
|
|
|
|
|
|
|
|
685
|
|
|
|
|
|
|
die [ "$err", $err+0 ] if $err; |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
# Convert the @addrs list into a list of ARRAY refs of 5 values each |
688
|
|
|
|
|
|
|
return map { |
689
|
|
|
|
|
|
|
[ $_->{family}, $_->{socktype}, $_->{protocol}, $_->{addr}, $_->{canonname} ] |
690
|
|
|
|
|
|
|
} @addrs; |
691
|
|
|
|
|
|
|
}; |
692
|
|
|
|
|
|
|
|
693
|
|
|
|
|
|
|
register_resolver getnameinfo => sub { |
694
|
|
|
|
|
|
|
my ( $addr, $flags ) = @_; |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
my ( $err, $host, $service ) = Socket::getnameinfo( $addr, $flags || 0 ); |
697
|
|
|
|
|
|
|
|
698
|
|
|
|
|
|
|
die [ "$err", $err+0 ] if $err; |
699
|
|
|
|
|
|
|
|
700
|
|
|
|
|
|
|
return [ $host, $service ]; |
701
|
|
|
|
|
|
|
}; |
702
|
|
|
|
|
|
|
|
703
|
|
|
|
|
|
|
=head1 EXAMPLES |
704
|
|
|
|
|
|
|
|
705
|
|
|
|
|
|
|
The following somewhat contrieved example shows how to implement a new |
706
|
|
|
|
|
|
|
resolver function. This example just uses in-memory data, but a real function |
707
|
|
|
|
|
|
|
would likely make calls to OS functions to provide an answer. In traditional |
708
|
|
|
|
|
|
|
Unix style, a pair of functions are provided that each look up the entity by |
709
|
|
|
|
|
|
|
either type of key, where both functions return the same type of list. This is |
710
|
|
|
|
|
|
|
purely a convention, and is in no way required or enforced by the |
711
|
|
|
|
|
|
|
L itself. |
712
|
|
|
|
|
|
|
|
713
|
|
|
|
|
|
|
@numbers = qw( zero one two three four |
714
|
|
|
|
|
|
|
five six seven eight nine ); |
715
|
|
|
|
|
|
|
|
716
|
|
|
|
|
|
|
register_resolver getnumberbyindex => sub { |
717
|
|
|
|
|
|
|
my ( $index ) = @_; |
718
|
|
|
|
|
|
|
die "Bad index $index" unless $index >= 0 and $index < @numbers; |
719
|
|
|
|
|
|
|
return ( $index, $numbers[$index] ); |
720
|
|
|
|
|
|
|
}; |
721
|
|
|
|
|
|
|
|
722
|
|
|
|
|
|
|
register_resolver getnumberbyname => sub { |
723
|
|
|
|
|
|
|
my ( $name ) = @_; |
724
|
|
|
|
|
|
|
foreach my $index ( 0 .. $#numbers ) { |
725
|
|
|
|
|
|
|
return ( $index, $name ) if $numbers[$index] eq $name; |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
die "Bad name $name"; |
728
|
|
|
|
|
|
|
}; |
729
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
=head1 AUTHOR |
731
|
|
|
|
|
|
|
|
732
|
|
|
|
|
|
|
Paul Evans |
733
|
|
|
|
|
|
|
|
734
|
|
|
|
|
|
|
=cut |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
0x55AA; |