NAME
AnyEvent::PacketReader - Read packets from a socket
SYNOPSIS
use AnyEvent::PacketReader;
my $watcher = packet_reader $fh, 'N', sub { warn "packet read: $_[0]\n" };
DESCRIPTION
*********************************************************
*** This is a very early release, anything may change ***
*********************************************************
This module allows to read packets from a socket easily.
The kind of packets that can be read are those composed by a header and a body whose size is determined by a field in the header plus some optional offset adjustment.
A unpack
style template is used to define the packet header size, how to parse the body size and the optional body offset.
Unpack templates
The templates used to determine the header size, size slot offset and encoding and body offset are a subset of those accepted by pack
:
The basic templates are those composed just by one of the following integer packers that define how to extract the value of the length slot from the header:
n v N V W S S< S> L L< L> Q Q< Q>
The "<" and ">" modifiers indicate the endianess of the type. Note also that the Q
packer is only supported on perls built with 64bit integer support.
In order to indicate an offset for the size slot, the packer can be prefixed by a particle of the form x$offset
(xxx...
is also a valid variation).
To indicate that more bytes follow in the header after the size slot, a x$offset
particle can also be included after. Alternatively a @!$offset
particle can be used to indicate an absolute offset for the body.
For instance, the three equivalent templates below can be used to read packets with a 24bytes header where the body length is at offset 4 encoded in 4 bytes as a 32bits integer in network order.
x4Nx16
xxxxNxxxxxxxxxxxxxxxx
x4N@!24
Probably, the most common usage of the @!$offset
particle is to indicate that the value from the length slot includes the header length (@!0
).
Some samples for real protocols will hopefully make things easier to understand:
- SFTP
-
SFTP protocol packets start by a 4byte length field followed by the packet load.
+=====================================+ | SFTP packet | +=====================================+ | Length | Type | Data payload | +-------------+------+----------------+ | <-4 bytes-> | <----Length bytes---> | +-------------+-----------------------+ The template to use in that case is C<N>.
(see also http://en.wikipedia.org/wiki/SSH_File_Transfer_Protocol)
- SMPP
-
SMPP protocol packets start by a 4byte slot containing the total length of the packet including the length slot itself.
+=================================================+ | SMPP packet | +=================================================+ | Length | Id | Status | Sequence | PDU Body | +-------------+----+--------+----------+----------+ | <-4 bytes-> | | |-------------+ | | <-------------------Length bytes------------> | +-------------------------------------------------+
The template in that case is
N@!0
. TheN
extracts a 32bit integer in network order from the packet and the@!0
sets the body offset at 0.The following code will dump the SMPP packets arriving at the socket
$socket
:my $w = packet_reader $socket, 'N@!0', sub { if (defined $_[0]) { hexdump($_[0]); } else { warn "some error happened: $!" } };
(see also http://en.wikipedia.org/wiki/Short_Message_Peer-to-Peer)
- IPv4
-
On IPv4 packet, the length slot starts at offset 2 and is encoded as a 16bit integer in network order. In that case the length is inclusive of the packet header.
+=========================================================+ | IPv4 packet | +=========================================================+ | Version | IHL | DSCP | ECN | Total length | ... | Data | +---------+-----+------+-----+---------------+-----+------+ | <---------2 bytes--------> | <--2 bytes--> | | |----------------------------+---------------+ | | <-----------------------Length bytes----------------> | +---------------------------------------------------------+
The template for reading IPv4 packets is
xxn@!0
.(see also http://en.wikipedia.org/wiki/Ipv4)
Export
The module exports the following subroutine:
- $watcher = packet_reader $socket, $template, $max_packet_len, $cb
-
This subroutine creates a new packet reader object that will keep calling the given callback
$cb
every time a new packet arrives at the socket/pipe until an error happens or the returned watcher goes out of scope.Both the
$template
and$max_packet
arguments are optional and can be omited. The default template isN
and the default maximum packet size is 1_000_000.The callback is called with the full packet as its first argument.
If some error happens while reading from the socket the callback is called with and undef value. The cause of the problem can be obtained from
$!
.Some specific errors generated by the module are as follows:
- EPIPE
-
The socket has been closed at the other side (actually, just the reading direction, it may still be possible to write to the socket).
The packet exceeds the maximum allowed packet size.
Unable to extract the packet size from the header or the size extracted is not consistent (i.e. the resulting total packet size is smaller than the part of the header already read).
SEE ALSO
AnyEvent, AnyEvent::Socket, AnyEvent::PacketForwarder.
AUTHOR
Salvador Fandiño, <sfandino@yahoo.com>
COPYRIGHT AND LICENSE
Copyright (C) 2013 by Qindel Formación y Servicios S.L.
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself, either Perl version 5.14.2 or, at your option, any later version of Perl 5 you may have available.
3 POD Errors
The following errors were encountered while parsing the POD:
- Around line 382:
=back doesn't take any parameters, but you said =back EMSGSIZE
- Around line 386:
=back doesn't take any parameters, but you said =back EBADMSG
- Around line 392:
=back without =over