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 |