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

Comparing AnyEvent/lib/AnyEvent/Util.pm (file contents):
Revision 1.5 by root, Sun Apr 27 20:17:46 2008 UTC vs.
Revision 1.13 by root, Sat May 17 19:39:33 2008 UTC

21 21
22use strict; 22use strict;
23 23
24no warnings "uninitialized"; 24no warnings "uninitialized";
25 25
26use Errno;
26use Socket (); 27use Socket ();
28use IO::Socket::INET ();
27 29
28use AnyEvent; 30use AnyEvent;
29 31
30use base 'Exporter'; 32use base 'Exporter';
31 33
86my $has_ev_adns; 88my $has_ev_adns;
87 89
88sub has_ev_adns { 90sub has_ev_adns {
89 ($has_ev_adns ||= do { 91 ($has_ev_adns ||= do {
90 my $model = AnyEvent::detect; 92 my $model = AnyEvent::detect;
91 (($model eq "AnyEvent::Impl::CoroEV" or $model eq "AnyEvent::Impl::EV")
92 && eval { local $SIG{__DIE__}; require EV::ADNS }) 93 ($model eq "AnyEvent::Impl::EV" && eval { local $SIG{__DIE__}; require EV::ADNS })
93 ? 2 : 1 # so that || always detects as true 94 ? 2 : 1 # so that || always detects as true
94 }) - 1 # 2 => true, 1 => false 95 }) - 1 # 2 => true, 1 => false
95} 96}
96 97
97=item AnyEvent::Util::inet_aton $name_or_address, $cb->($binary_address_or_undef) 98=item AnyEvent::Util::inet_aton $name_or_address, $cb->($binary_address_or_undef)
104sub inet_aton { 105sub inet_aton {
105 my ($name, $cb) = @_; 106 my ($name, $cb) = @_;
106 107
107 if (&dotted_quad) { 108 if (&dotted_quad) {
108 $cb->(Socket::inet_aton $name); 109 $cb->(Socket::inet_aton $name);
110 } elsif ($name eq "localhost") { # rfc2606 et al.
111 $cb->(v127.0.0.1);
109 } elsif (&has_ev_adns) { 112 } elsif (&has_ev_adns) {
110 EV::ADNS::submit ($name, &EV::ADNS::r_addr, 0, sub { 113 EV::ADNS::submit ($name, &EV::ADNS::r_addr, 0, sub {
111 my (undef, undef, @a) = @_; 114 my (undef, undef, @a) = @_;
112 $cb->(@a ? Socket::inet_aton $a[0] : undef); 115 $cb->(@a ? Socket::inet_aton $a[0] : undef);
113 }); 116 });
114 } else { 117 } else {
115 _do_asy $cb, sub { Socket::inet_aton $_[0] }, @_; 118 _do_asy $cb, sub { Socket::inet_aton $_[0] }, @_;
116 } 119 }
117} 120}
118 121
122=item AnyEvent::Util::fh_nonblocking $fh, $nonblocking
123
124Sets the blocking state of the given filehandle (true == nonblocking,
125false == blocking). Uses fcntl on anything sensible and ioctl FIONBIO on
126broken (i.e. windows) platforms.
127
128=cut
129
130sub fh_nonblocking($$) {
131 my ($fh, $nb) = @_;
132
133 require Fcntl;
134
135 if ($^O eq "MSWin32") {
136 $nb = (! ! $nb) + 0;
137 ioctl $fh, 0x8004667e, \$nb; # FIONBIO
138 } else {
139 fcntl $fh, &Fcntl::F_SETFL, $nb ? &Fcntl::O_NONBLOCK : 0;
140 }
141}
142
143sub AnyEvent::Util::Guard::DESTROY {
144 ${$_[0]}->();
145}
146
147=item $guard = AnyEvent::Util::guard { CODE }
148
149This function creates a special object that, when called, will execute the
150code block.
151
152This is often handy in continuation-passing style code to clean up some
153resource regardless of where you break out of a process.
154
155=cut
156
157sub guard(&) {
158 bless \(my $cb = shift), AnyEvent::Util::Guard::
159}
160
161=item my $guard = AnyEvent::Util::tcp_connect $host, $port, $connect_cb[, $prepare_cb]
162
163This is a convenience function that creates a tcp socket and makes a 100%
164non-blocking connect to the given C<$host> (which can be a hostname or a
165textual IP address) and C<$port>.
166
167Unless called in void context, it returns a guard object that will
168automatically abort connecting when it gets destroyed (it does not do
169anything to the socket after the conenct was successful).
170
171If the connect is successful, then the C<$connect_cb> will be invoked with
172the socket filehandle (in non-blocking mode) as first and the peer host
173(as a textual IP address) and peer port as second and third arguments,
174respectively.
175
176If the connect is unsuccessful, then the C<$connect_cb> will be invoked
177without any arguments and C<$!> will be set appropriately (with C<ENXIO>
178indicating a dns resolution failure).
179
180The filehandle is suitable to be plugged into L<AnyEvent::Handle>, but can
181be used as a normal perl file handle as well.
182
183Sometimes you need to "prepare" the socket before connecting, for example,
184to C<bind> it to some port, or you want a specific connect timeout that
185is lower than your kernel's default timeout. In this case you can specify
186a second callback, C<$prepare_cb>. It will be called with the file handle
187in not-yet-connected state as only argument and must return the connection
188timeout value (or C<0>, C<undef> or the empty list to indicate the default
189timeout is to be used).
190
191Note that the socket could be either a IPv4 TCP socket or an IPv6 tcp
192socket (although only IPv4 is currently supported by this module).
193
194Simple Example: connect to localhost on port 22.
195
196 AnyEvent::Util::tcp_connect localhost => 22, sub {
197 my $fh = shift
198 or die "unable to connect: $!";
199 # do something
200 };
201
202Complex Example: connect to www.google.com on port 80 and make a simple
203GET request without much error handling. Also limit the connection timeout
204to 15 seconds.
205
206 AnyEvent::Util::tcp_connect "www.google.com", 80,
207 sub {
208 my ($fh) = @_
209 or die "unable to connect: $!";
210
211 my $handle; # avoid direct assignment so on_eof has it in scope.
212 $handle = new AnyEvent::Handle
213 fh => $fh,
214 on_eof => sub {
215 undef $handle; # keep it alive till eof
216 warn "done.\n";
217 };
218
219 $handle->push_write ("GET / HTTP/1.0\015\012\015\012");
220
221 $handle->push_read_line ("\015\012\015\012", sub {
222 my ($handle, $line) = @_;
223
224 # print response header
225 print "HEADER\n$line\n\nBODY\n";
226
227 $handle->on_read (sub {
228 # print response body
229 print $_[0]->rbuf;
230 $_[0]->rbuf = "";
231 });
232 });
233 }, sub {
234 my ($fh) = @_;
235 # could call $fh->bind etc. here
236
237 15
238 };
239
240=cut
241
242sub tcp_connect($$$;$) {
243 my ($host, $port, $connect, $prepare) = @_;
244
245 # see http://cr.yp.to/docs/connect.html for some background
246
247 my %state = ( fh => undef );
248
249 # name resolution
250 inet_aton $host, sub {
251 return unless exists $state{fh};
252
253 my $ipn = shift
254 or do {
255 %state = ();
256 $! = &Errno::ENXIO;
257 return $connect->();
258 };
259
260 # socket creation
261 socket $state{fh}, &Socket::AF_INET, &Socket::SOCK_STREAM, 0
262 or do {
263 %state = ();
264 return $connect->();
265 };
266
267 fh_nonblocking $state{fh}, 1;
268
269 # prepare and optional timeout
270 if ($prepare) {
271 my $timeout = $prepare->($state{fh});
272
273 $state{to} = AnyEvent->timer (after => $timeout, cb => sub {
274 %state = ();
275 $! = &Errno::ETIMEDOUT;
276 $connect->();
277 }) if $timeout;
278 }
279
280 # called when the connect was successful, which,
281 # in theory, could be the case immediately (but never is in practise)
282 my $connected = sub {
283 my $fh = delete $state{fh};
284 %state = ();
285
286 # we are connected, or maybe there was an error
287 if (my $sin = getpeername $fh) {
288 my ($port, $host) = Socket::unpack_sockaddr_in $sin;
289 $connect->($fh, (Socket::inet_ntoa $host), $port);
290 } else {
291 # dummy read to fetch real error code
292 sysread $fh, my $buf, 1;
293 $connect->();
294 }
295 };
296
297 # now connect
298 if (connect $state{fh}, Socket::pack_sockaddr_in $port, $ipn) {
299 $connected->();
300 } elsif ($! == &Errno::EINPROGRESS || $! == &Errno::EWOULDBLOCK) { # EINPROGRESS is POSIX
301 $state{ww} = AnyEvent->io (fh => $state{fh}, poll => 'w', cb => $connected);
302 } else {
303 %state = ();
304 $connect->();
305 }
306 };
307
308 defined wantarray
309 ? guard { %state = () } # break any circular dependencies and unregister watchers
310 : ()
311}
312
313=item $guard = AnyEvent::Util::tcp_server $host, $port, $accept_cb[, $prepare_cb]
314
315Create and bind a tcp socket to the given host (any IPv4 host if undef,
316otherwise it must be an IPv4 or IPv6 address) and port (or an ephemeral
317port if given as zero or undef), set the SO_REUSEADDR flag and call
318C<listen>.
319
320For each new connection that could be C<accept>ed, call the C<$accept_cb>
321with the filehandle (in non-blocking mode) as first and the peer host and
322port as second and third arguments (see C<tcp_connect> for details).
323
324Croaks on any errors.
325
326If called in non-void context, then this function returns a guard object
327whose lifetime it tied to the tcp server: If the object gets destroyed,
328the server will be stopped (but existing accepted connections will
329continue).
330
331If you need more control over the listening socket, you can provide a
332C<$prepare_cb>, which is called just before the C<listen ()> call, with
333the listen file handle as first argument.
334
335It should return the length of the listen queue (or C<0> for the default).
336
337Example: bind on tcp port 8888 on the local machine and tell each client
338to go away.
339
340 AnyEvent::Util::tcp_server undef, 8888, sub {
341 my ($fh, $host, $port) = @_;
342
343 syswrite $fh, "The internet is full, $host:$port. Go away!\015\012";
344 };
345
346=cut
347
348sub tcp_server($$$;$) {
349 my ($host, $port, $accept, $prepare) = @_;
350
351 my %state;
352
353 socket $state{fh}, &Socket::AF_INET, &Socket::SOCK_STREAM, 0
354 or Carp::croak "socket: $!";
355
356 setsockopt $state{fh}, &Socket::SOL_SOCKET, &Socket::SO_REUSEADDR, 1
357 or Carp::croak "so_reuseaddr: $!";
358
359 bind $state{fh}, Socket::pack_sockaddr_in $port, Socket::inet_aton ($host || "0.0.0.0")
360 or Carp::croak "bind: $!";
361
362 fh_nonblocking $state{fh}, 1;
363
364 my $len = ($prepare && $prepare->($state{fh})) || 128;
365
366 listen $state{fh}, $len
367 or Carp::croak "listen: $!";
368
369 $state{aw} = AnyEvent->io (fh => $state{fh}, poll => 'r', cb => sub {
370 # this closure keeps $state alive
371 while (my $peer = accept my $fh, $state{fh}) {
372 fh_nonblocking $fh, 1; # POSIX requires inheritance, the outside world does not
373 my ($port, $host) = Socket::unpack_sockaddr_in $peer;
374 $accept->($fh, (Socket::inet_ntoa $host), $port);
375 }
376 });
377
378 defined wantarray
379 ? guard { %state = () } # clear fh and watcher, which breaks the circular dependency
380 : ()
381}
382
1191; 3831;
120 384
121=back 385=back
122 386
123=head1 AUTHOR 387=head1 AUTHOR

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines