ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent/lib/AnyEvent/Socket.pm
Revision: 1.5
Committed: Mon Apr 28 09:27:47 2008 UTC (16 years, 2 months ago) by elmex
Branch: MAIN
CVS Tags: rel-3_41, rel-3_4
Changes since 1.4: +1 -1 lines
Log Message:
disabled warnings

File Contents

# User Rev Content
1 elmex 1.1 package AnyEvent::Socket;
2    
3 elmex 1.5 no warnings;
4 elmex 1.1 use strict;
5    
6     use Carp;
7     use Errno qw/ENXIO ETIMEDOUT/;
8     use Socket;
9     use IO::Socket::INET;
10     use AnyEvent;
11     use AnyEvent::Util;
12     use AnyEvent::Handle;
13    
14     our @ISA = qw/AnyEvent::Handle/;
15    
16     =head1 NAME
17    
18     AnyEvent::Socket - Connecting sockets for non-blocking I/O
19    
20     =head1 SYNOPSIS
21    
22     use AnyEvent;
23     use AnyEvent::Socket;
24    
25     my $cv = AnyEvent->condvar;
26    
27     my $ae_sock =
28     AnyEvent::Socket->new (
29     PeerAddr => "www.google.de:80",
30     on_eof => sub { $cv->broadcast },
31     on_connect => sub {
32     my ($ae_sock, $error) = @_;
33     if ($error) {
34     warn "couldn't connect: $!";
35     return;
36     } else {
37     print "connected to ".$ae_sock->fh->peerhost.":".$ae_sock->fh->peerport."\n";
38     }
39    
40     $ae_sock->on_read (sub {
41     my ($ae_sock) = @_;
42     print "got data: [".${$ae_sock->rbuf}."]\n";
43     $ae_sock->rbuf = '';
44     });
45    
46     $ae_sock->write ("GET / HTTP/1.0\015\012\015\012");
47     }
48     );
49    
50     $cv->wait;
51    
52     =head1 DESCRIPTION
53    
54 elmex 1.2 L<AnyEvent::Socket> provides method to connect sockets and accept clients
55     on listening sockets.
56    
57     =head1 EXAMPLES
58    
59 elmex 1.3 See the C<eg/> directory of the L<AnyEvent> distribution for examples and also
60     the tests in C<t/handle/> can be helpful.
61 elmex 1.2
62 elmex 1.1 =head1 METHODS
63    
64     =over 4
65    
66     =item B<new (%args)>
67    
68     The constructor gets the same arguments as the L<IO::Socket::INET> constructor.
69     Except that blocking will always be disabled and the hostname lookup is done by
70 elmex 1.2 L<AnyEvent::Util::inet_aton> before the socket (currently a L<IO::Socket::INET> instance)
71     is created.
72    
73     Additionally you can set the callbacks that can be set in the L<AnyEvent::Handle>
74     constructor and these:
75    
76     =over 4
77    
78     =item on_connect => $cb
79    
80     Installs a connect callback, that will be called when the name was successfully
81     resolved and the connection was successfully established or an error occured in
82     the lookup or connect.
83    
84     The first argument to the callback C<$cb> will be the L<AnyEvent::Socket> itself
85     and the second is either a true value in case an error occured or undef.
86     The variable C<$!> will be set to one of these values:
87    
88     =over 4
89    
90     =item ENXIO
91    
92     When the DNS lookup failed.
93    
94     =item ETIMEDOUT
95 elmex 1.1
96 elmex 1.2 When the connect timed out.
97    
98     =item *
99    
100     Or any other errno as set by L<IO::Socket::INET> when it's constructor
101     failed or the connection couldn't be established for any other reason.
102    
103     =back
104    
105     =item on_accept
106    
107     This sets the C<on_accept> callback by calling the C<on_accept> method.
108     See also below.
109    
110     =back
111 elmex 1.1
112     =cut
113    
114     sub new {
115     my $this = shift;
116     my $class = ref($this) || $this;
117     my %args = @_;
118     my %self_args;
119    
120     $self_args{$_} = delete $args{$_}
121     for grep { /^on_/ } keys %args;
122    
123     my $self = $class->SUPER::new (%self_args);
124     $self->{sock_args} = \%args;
125    
126     if (exists $args{PeerAddr} || exists $args{PeerHost}) {
127     $self->{on_connect} ||= sub {
128     Carp::croak "Couldn't connect to $args{PeerHost}:$args{PeerPort}: $!"
129     if $_[1];
130     };
131     $self->_connect;
132     }
133    
134     if ($self->{on_accept}) {
135     $self->on_accept ($self->{on_accept});
136     }
137    
138     return $self
139     }
140    
141     sub _connect {
142     my ($self) = @_;
143    
144     if (defined $self->{sock_args}->{Listen}) {
145     Carp::croak "connect can be done on a socket that has 'Listen' set!";
146     }
147    
148     if ($self->{sock_args}->{PeerAddr} =~ /^([^:]+)(?::(\d+))?$/) {
149     $self->{sock_args}->{PeerHost} = $1;
150     $self->{sock_args}->{PeerPort} = $2 if defined $2;
151     delete $self->{sock_args}->{PeerAddr};
152    
153     $self->_lookup ($1);
154     return;
155    
156     } elsif (my $h = $self->{sock_args}->{PeerHost}) {
157     $self->_lookup ($h);
158     return;
159    
160     } else {
161     Carp::croak "no PeerAddr or PeerHost provided!";
162     }
163     }
164    
165 elmex 1.2 =item B<on_accept ($cb)>
166    
167     When the socket is run in listening mode (the C<Listen> argument of the socket
168     is set) this callback will be called when a new client connected.
169     The first argument to the callback will be the L<AnyEvent::Socket> object itself,
170     the second the L<AnyEvent::Handle> of the client socket and the third
171     is the peer address (depending on what C<accept> of L<IO::Socket> gives you>).
172    
173     =cut
174    
175 elmex 1.1 sub on_accept {
176     my ($self, $cb) = @_;
177    
178     unless (defined $self->{sock_args}->{Listen}) {
179     $self->{sock_args}->{Listen} = 10;
180     }
181    
182     $self->{fh} =
183     IO::Socket::INET->new (%{$self->{sock_args}}, Blocking => 0)
184     or Carp::croak ("couldn't create listening socket: $!");
185    
186     $self->{list_w} =
187     AnyEvent->io (poll => 'r', fh => $self->{fh}, cb => sub {
188     my ($new_sock, $paddr) = $self->{fh}->accept ();
189     unless ($new_sock) {
190     $cb->($self);
191     delete $self->{list_w};
192     return;
193     }
194     my $ae_hdl = AnyEvent::Handle->new (fh => $new_sock);
195     $cb->($self, $ae_hdl, $paddr);
196     });
197     }
198    
199     sub _lookup {
200     my ($self, $host) = @_;
201    
202     AnyEvent::Util::inet_aton ($host, sub {
203     my ($addr) = @_;
204    
205     if ($addr) {
206     $self->{sock_args}->{PeerHost} = inet_ntoa $addr;
207     $self->_real_connect;
208    
209     } else {
210     $! = ENXIO;
211     $self->{on_connect}->($self, 1);
212     }
213     });
214     }
215    
216     sub _real_connect {
217     my ($self) = @_;
218    
219     if (defined $self->{sock_args}->{Timeout}) {
220     $self->{dns_tmout} =
221     AnyEvent->timer (after => $self->{sock_args}->{Timeout}, cb => sub {
222     $! = ETIMEDOUT;
223     $self->{on_connect}->($self, 1);
224     });
225     }
226    
227     $self->{fh} = IO::Socket::INET->new (%{$self->{sock_args}}, Blocking => 0);
228     unless ($self->{fh}) {
229     $self->{on_connect}->($self, 1);
230     return;
231     }
232    
233     $self->{con_w} =
234     AnyEvent->io (poll => 'w', fh => $self->{fh}, cb => sub {
235     delete $self->{con_w};
236    
237     if ($! = $self->{fh}->sockopt (SO_ERROR)) {
238     $self->{on_connect}->($self, 1);
239    
240     } else {
241     $self->{on_connect}->($self);
242     }
243     });
244     }
245    
246     =back
247    
248     =head1 AUTHOR
249    
250     Robin Redeker, C<< <elmex at ta-sa.org> >>
251    
252     =cut
253    
254     1; # End of AnyEvent