Torsten Förtsch

NAME

IO::Handle::Record - IO::Handle extension to pass perl data structures

SYNOPSIS

 use IO::Socket::UNIX;
 use IO::Handle::Record;

 ($p, $c)=IO::Socket::UNIX->socketpair( AF_UNIX,
                                        SOCK_STREAM,
                                        PF_UNSPEC );
 while( !defined( $pid=fork ) ) {sleep 1}

 if( $pid ) {
   close $c; undef $c;

   $p->fds_to_send=[\*STDIN, \*STDOUT];
   $p->record_opts={send_CODE=>1};
   $p->write_record( {a=>'b', c=>'d'},
                     sub { $_[0]+$_[1] },
                     [qw/this is a test/] );
 } else {
   close $p; undef $p;

   $c->record_opts={receive_CODE=>sub {eval $_[0]}};
   ($hashref, $coderef, $arrayref)=$c->read_record;
   readline $c->received_fds->[0];       # reads from the parent's STDIN
 }

DESCRIPTION

IO::Handle::Record extends the IO::Handle class. Since many classes derive from IO::Handle these extensions can be used with IO::File, IO::Socket, IO::Pipe, etc.

The methods provided read and write lists of perl data structures. They can pass anything that can be serialized with Storable even subroutines between processes.

The following methods are added:

$handle->record_opts

This lvalue method expects a hash reference with options as parameter. The send_CODE and receive_CODE options correspond to localized versions of $Storable::Deparse and $Storable::Eval respectively. Using them Perl code can be passed over a connection. See the Storable manpage for further information.

Further, setting forgive_me sets $Storable::forgive_me before freeze()ing anything. That way GLOB values are stored as strings.

In a few cases IO::Handle::Record passes binary data over the connection. Normally network byte order is used there. You can save a few CPU cycles if you set the local_encoding option to true. In this case the byte order of the local machine is used.

Example:

 $handle->record_opts={send_CODE=>1, receive_CODE=>1, local_encoding=>1};
$handle->fds_to_send=\@fds

Called before write_record sets a list of file handles that are passed to the other end of a UNIX domain stream socket. The next write_record transfers them as open files. So the other process can read or write to them.

@fds=@{$handle->received_fds}

This is the counterpart to fds_to_send. After a successful read_record the receiving process can fetch the transferred handles from this list. The handles are GLOBs blessed to one of:

* IO::File
* IO::Dir
* IO::Pipe
* IO::Socket::UNIX
* IO::Socket::INET
* IO::Socket::INET6
* IO::Handle

according to their type. IO::Handle is used as kind of catchall type. Open devices are received as such. IO::Handle::Record does not load all of these modules. That's up to you.

$handle->write_record(@data)

writes a list of perl data structures.

write_record returns 1 if the record has been transmitted. undef is returned if $handle is non blocking and a EAGAIN condition is met. In this case reinvoke the operation without parameters (just $handle->write_record) when the handle becomes ready. Otherwise it throws an exception IO::Handle::Record: syswrite error. Check $! in this case.

EINTR is handled internally.

Example:

 $handle->write_record( [1,2],
                        sub {$_[0]+$_[1]},
                        { list=>[1,2,3],
                          hash=>{a=>'b'},
                          code=>sub {print "test\n";} } );
@data=$handle->read_record

reads one record of perl data structures.

On success it returns the record as list. An empty list is returned if $handle is in non blocking mode and not enough data has been read. Check $!==EAGAIN to catch this condition. When the handle becomes ready just repeat the operation to read the next data chunk. If a complete record has arrived it is returned.

On EOF an empty list is returned. To distinguish this from the non blocking empty list return check $handle->end_of_input.

EINTR is handled internally.

Example:

 ($array, $sub, $hash)=$handle->read_record;
$handle->end_of_input

When an end of file condition is read this is set to true.

($pid, $uid, $gid)=$handle->peercred

ONLY FOR UNIX DOMAIN SOCKETS ON LINUX

Return the PID, eUID and eGID of the peer at the time of the connect.

$handle->read_buffer
$handle->expected
$handle->expect_fds
$handle->_received_fds
$handle->write_buffer
$handle->written

these methods are used internally to provide a read and write buffer for non blocking operations.

Exceptions

  • IO::Handle::Record: sysread

    thrown in read_record. Check $! for more information.

  • IO::Handle::Record: premature end of file

    thrown in read_record on end of file if according to the internal protocol more input is expected.

  • IO::Handle::Record: busy

    thrown in write_record if a non-blocking write is not yet finished. There may be only one write operation at a time. If that hits you organise a queue.

  • IO::Handle::Record: syswrite

    thrown in write_record on an error of the underlying transport method. Check $! for more information.

  • Other exceptions

    thrown in read_record and write_record if something cannot be encoded or decoded by the Storable module. If that hits you the Storable module at one side is probably too old.

EXPORT

None.

Data Transfer Format

The Perl data is serialized using Storable::freeze or Storable::nfreeze. Storable::freeze is used if the local_encoding option is set, Storable::nfreeze otherwise.

The length in bytes of this data chunk and the number of file handles that are passed along with the data are then each pack()ed as a 4 byte binary value using the L or N template. L is used of local_encoding is in effect.

If there are file descriptors to be passed they are sent by a separate sendmsg call along with 2 length fields only.

Both fields is the prepended to the data chunk:

 +-----------------+------------------------+
 | data length (N) | number of file handles |
 | 4 bytes         | 4 bytes                |
 +-----------------+------------------------+
 |                                          |
 |                                          |
 |                                          |
 |                                          |
 |                   data                   |
 |                                          |
 |                 N bytes                  |
 |                                          |
 |                                          |
 |                                          |
 |                                          |
 |                                          |
 +------------------------------------------+

WARNING: The transfer format has changed in version 0.07 (never made it to CPAN) and again in version 0.08.

TODO

* compression
* credential passing over UNIX domain sockets

SEE ALSO

IO::Handle

AUTHOR

Torsten Foertsch, <torsten.foertsch@gmx.net<gt>

COPYRIGHT AND LICENSE

Copyright (C) 2005-2009 by Torsten Foertsch

This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.