AnyEvent
view release on metacpan or search on metacpan
lib/AnyEvent/Handle.pm view on Meta::CPAN
while (length $self->{_tls_wbuf}) {
if (($tmp = Net::SSLeay::write ($self->{tls}, $self->{_tls_wbuf})) <= 0) {
$tmp = Net::SSLeay::get_error ($self->{tls}, $tmp);
return $self->_tls_error ($tmp)
if $tmp != $ERROR_WANT_READ
&& ($tmp != $ERROR_SYSCALL || $!);
last;
}
substr $self->{_tls_wbuf}, 0, $tmp, "";
}
while (defined ($tmp = Net::SSLeay::read ($self->{tls}))) {
unless (length $tmp) {
$self->{_on_starttls}
and (delete $self->{_on_starttls})->($self, undef, "EOF during handshake"); # ???
&_freetls;
if ($self->{on_stoptls}) {
$self->{on_stoptls}($self);
return;
} else {
# let's treat SSL-eof as we treat normal EOF
delete $self->{_rw};
$self->{_eof} = 1;
}
}
$self->{_tls_rbuf} .= $tmp;
$self->_drain_rbuf;
$self->{tls} or return; # tls session might have gone away in callback
}
$tmp = Net::SSLeay::get_error ($self->{tls}, -1); # -1 is not neccessarily correct, but Net::SSLeay doesn't tell us
return $self->_tls_error ($tmp)
if $tmp != $ERROR_WANT_READ
&& ($tmp != $ERROR_SYSCALL || $!);
while (length ($tmp = Net::SSLeay::BIO_read ($self->{_wbio}))) {
$self->{wbuf} .= $tmp;
$self->_drain_wbuf;
$self->{tls} or return; # tls session might have gone away in callback
}
$self->{_on_starttls}
and Net::SSLeay::state ($self->{tls}) == Net::SSLeay::ST_OK ()
and (delete $self->{_on_starttls})->($self, 1, "TLS/SSL connection established");
}
=item $handle->starttls ($tls[, $tls_ctx])
Instead of starting TLS negotiation immediately when the AnyEvent::Handle
object is created, you can also do that at a later time by calling
C<starttls>. See the C<tls> constructor argument for general info.
Starting TLS is currently an asynchronous operation - when you push some
write data and then call C<< ->starttls >> then TLS negotiation will start
immediately, after which the queued write data is then sent. This might
change in future versions, so best make sure you have no outstanding write
data when calling this method.
The first argument is the same as the C<tls> constructor argument (either
C<"connect">, C<"accept"> or an existing Net::SSLeay object).
The second argument is the optional C<AnyEvent::TLS> object that is used
when AnyEvent::Handle has to create its own TLS connection object, or
a hash reference with C<< key => value >> pairs that will be used to
construct a new context.
The TLS connection object will end up in C<< $handle->{tls} >>, the TLS
context in C<< $handle->{tls_ctx} >> after this call and can be used or
changed to your liking. Note that the handshake might have already started
when this function returns.
Due to bugs in OpenSSL, it might or might not be possible to do multiple
handshakes on the same stream. It is best to not attempt to use the
stream after stopping TLS.
This method may invoke callbacks (and therefore the handle might be
destroyed after it returns).
=cut
our %TLS_CACHE; #TODO not yet documented, should we?
sub starttls {
my ($self, $tls, $ctx) = @_;
Carp::croak "It is an error to call starttls on an AnyEvent::Handle object while TLS is already active, caught"
if $self->{tls};
unless (defined $AnyEvent::TLS::VERSION) {
eval {
require Net::SSLeay;
require AnyEvent::TLS;
1
} or return $self->_error (Errno::EPROTO, 1, "TLS support not available on this system");
}
$self->{tls} = $tls;
$self->{tls_ctx} = $ctx if @_ > 2;
return unless $self->{fh};
$ERROR_SYSCALL = Net::SSLeay::ERROR_SYSCALL ();
$ERROR_WANT_READ = Net::SSLeay::ERROR_WANT_READ ();
$tls = delete $self->{tls};
$ctx = $self->{tls_ctx};
local $Carp::CarpLevel = 1; # skip ourselves when creating a new context or session
if ("HASH" eq ref $ctx) {
if ($ctx->{cache}) {
my $key = $ctx+0;
$ctx = $TLS_CACHE{$key} ||= new AnyEvent::TLS %$ctx;
} else {
$ctx = new AnyEvent::TLS %$ctx;
}
}
$self->{tls_ctx} = $ctx || TLS_CTX ();
$self->{tls} = $tls = $self->{tls_ctx}->_get_session ($tls, $self, $self->{peername});
# basically, this is deep magic (because SSL_read should have the same issues)
# but the openssl maintainers basically said: "trust us, it just works".
# (unfortunately, we have to hardcode constants because the abysmally misdesigned
# and mismaintained ssleay-module didn't offer them for a decade or so).
# http://www.mail-archive.com/openssl-dev@openssl.org/msg22420.html
#
# in short: this is a mess.
#
# note that we do not try to keep the length constant between writes as we are required to do.
# we assume that most (but not all) of this insanity only applies to non-blocking cases,
# and we drive openssl fully in blocking mode here. Or maybe we don't - openssl seems to
# have identity issues in that area.
lib/AnyEvent/Handle.pm view on Meta::CPAN
=item I C<undef> the AnyEvent::Handle reference inside my callback and
still get further invocations!
That's because AnyEvent::Handle keeps a reference to itself when handling
read or write callbacks.
It is only safe to "forget" the reference inside EOF or error callbacks,
from within all other callbacks, you need to explicitly call the C<<
->destroy >> method.
=item Why is my C<on_eof> callback never called?
Probably because your C<on_error> callback is being called instead: When
you have outstanding requests in your read queue, then an EOF is
considered an error as you clearly expected some data.
To avoid this, make sure you have an empty read queue whenever your handle
is supposed to be "idle" (i.e. connection closes are O.K.). You can set
an C<on_read> handler that simply pushes the first read requests in the
queue.
See also the next question, which explains this in a bit more detail.
=item How can I serve requests in a loop?
Most protocols consist of some setup phase (authentication for example)
followed by a request handling phase, where the server waits for requests
and handles them, in a loop.
There are two important variants: The first (traditional, better) variant
handles requests until the server gets some QUIT command, causing it to
close the connection first (highly desirable for a busy TCP server). A
client dropping the connection is an error, which means this variant can
detect an unexpected detection close.
To handle this case, always make sure you have a non-empty read queue, by
pushing the "read request start" handler on it:
# we assume a request starts with a single line
my @start_request; @start_request = (line => sub {
my ($hdl, $line) = @_;
... handle request
# push next request read, possibly from a nested callback
$hdl->push_read (@start_request);
});
# auth done, now go into request handling loop
# now push the first @start_request
$hdl->push_read (@start_request);
By always having an outstanding C<push_read>, the handle always expects
some data and raises the C<EPIPE> error when the connction is dropped
unexpectedly.
The second variant is a protocol where the client can drop the connection
at any time. For TCP, this means that the server machine may run out of
sockets easier, and in general, it means you cannot distinguish a protocl
failure/client crash from a normal connection close. Nevertheless, these
kinds of protocols are common (and sometimes even the best solution to the
problem).
Having an outstanding read request at all times is possible if you ignore
C<EPIPE> errors, but this doesn't help with when the client drops the
connection during a request, which would still be an error.
A better solution is to push the initial request read in an C<on_read>
callback. This avoids an error, as when the server doesn't expect data
(i.e. is idly waiting for the next request, an EOF will not raise an
error, but simply result in an C<on_eof> callback. It is also a bit slower
and simpler:
# auth done, now go into request handling loop
$hdl->on_read (sub {
my ($hdl) = @_;
# called each time we receive data but the read queue is empty
# simply start read the request
$hdl->push_read (line => sub {
my ($hdl, $line) = @_;
... handle request
# do nothing special when the request has been handled, just
# let the request queue go empty.
});
});
=item I get different callback invocations in TLS mode/Why can't I pause
reading?
Unlike, say, TCP, TLS connections do not consist of two independent
communication channels, one for each direction. Or put differently, the
read and write directions are not independent of each other: you cannot
write data unless you are also prepared to read, and vice versa.
This means that, in TLS mode, you might get C<on_error> or C<on_eof>
callback invocations when you are not expecting any read data - the reason
is that AnyEvent::Handle always reads in TLS mode.
During the connection, you have to make sure that you always have a
non-empty read-queue, or an C<on_read> watcher. At the end of the
connection (or when you no longer want to use it) you can call the
C<destroy> method.
=item How do I read data until the other side closes the connection?
If you just want to read your data into a perl scalar, the easiest way
to achieve this is by setting an C<on_read> callback that does nothing,
clearing the C<on_eof> callback and in the C<on_error> callback, the data
will be in C<$_[0]{rbuf}>:
$handle->on_read (sub { });
$handle->on_eof (undef);
$handle->on_error (sub {
my $data = delete $_[0]{rbuf};
});
Note that this example removes the C<rbuf> member from the handle object,
( run in 0.636 second using v1.01-cache-2.11-cpan-39bf76dae61 )