AnyEvent-FDpasser

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

    AnyEvent documentation).

    Creating a passer object before forking is fine since doing this doesn't
    install any AnyEvent watchers. Also, using the filesystem with "AF_UNIX"
    sockets (or more portably, "fdpasser_server", "fdpasser_accept", and
    "fdpasser_connect") obviates the need to worry about forking.

  Control channels
    A useful design is to have a "control channel" associated with each
    passer that sends over data related to file descriptors being passed. As
    long as the control channel is a synchronised and ordered queue of
    messages, each message can indicate how many descriptors it is sending
    along on the FDpasser channel.

    With both the BSD and SysV APIs it is possible to use the passer
    filehandle to transfer control data but this module does not support
    this in order to keep the API simple. However, instead you can use a
    separate socket connection as your control channel. How to synchronize
    passers and control channels? One way is to connect to a passer server
    and pass the control channel socket in as the first file descriptor.

  Portability
    In order to use the SysV interface, set the "FDPASSER_SYSV" environment
    variable when running "Makefile.PL":

        $ FDPASSER_SYSV=1 perl Makefile.PL

    Currently the default is to always use the BSD interface. It will

README  view on Meta::CPAN

    and "ioctl" system calls used to implement descriptor passing can fail
    unexpectedly. Failing to create a descriptor is especially bad when
    transfering descriptors since the outcome is not well specified. Linux
    doesn't even mention this possible failure mode in the recvmsg() man
    page. BSD manuals indicate that EMSGSIZE will be returned and any
    descriptors in transit will be closed. If a descriptor is closed it can
    never be delivered to the application, even if the full descriptor table
    problem clears up.

    So what should we do? We could silently ignore it when a descriptor
    fails to transfer, but then we run the risk of desynchronising the
    descriptor stream. Another possibility is indicating to the application
    that this descriptor has failed to transfer and is now lost forever.
    Unfortunately this complicates the error handling an application must
    do, especially if the descriptor is linked to other descriptors which
    must then be received and (if they make it) closed. Finally, we could
    just give up, call the on_error callback, destory the passer object and
    punt the problem back to the application.

    None of the above "solutions" are very appealing so this module uses a
    trick known as the "close-dup slot reservation" trick. Actually I just

README  view on Meta::CPAN

    descriptor, receive the descriptor from the sending process, and then
    attempt to dup another descriptor. Because we just cleared a descriptor
    table entry, there should always be a free descriptor to create.

    If duping fails, we stop trying to receive any further descriptors and
    instead retry at regular intervals (while not interrupting the event
    loop). Hopefully eventually the full descriptor table issue will clear
    up and we will be able to resume receiving descriptors.

    Note that a descriptor could be created between closing and receiving if
    your program uses asynchronous signal handlers or threads that create
    descriptors, so don't do that. Signals that are handled synchronously
    (like normal AnyEvent signal watchers) are fine.

    This trick is similar to a trick described in Marc Lehmann's libev POD
    document, section "special problem of accept()ing when you can't,"
    although the purpose of employing the trick in this module is somewhat
    different.

TESTS AND SYSTEM ASSUMPTIONS
    All the following tests should work with BSD4.4, BSD4.3, and SysV
    interfaces (where available).

README.pod  view on Meta::CPAN


=head2 Forking

This module itself never calls C<fork()>, but many use-cases of this module involve the application program forking. All the usual things you must worry about when forking an AnyEvent application also apply to this module. In particular, you should e...

Creating a passer object before forking is fine since doing this doesn't install any AnyEvent watchers. Also, using the filesystem with C<AF_UNIX> sockets (or more portably, C<fdpasser_server>, C<fdpasser_accept>, and C<fdpasser_connect>) obviates th...


=head2 Control channels

A useful design is to have a "control channel" associated with each passer that sends over data related to file descriptors being passed. As long as the control channel is a synchronised and ordered queue of messages, each message can indicate how ma...

With both the BSD and SysV APIs it is possible to use the passer filehandle to transfer control data but this module does not support this in order to keep the API simple. However, instead you can use a separate socket connection as your control chan...


=head2 Portability

In order to use the SysV interface, set the C<FDPASSER_SYSV> environment variable when running C<Makefile.PL>:

    $ FDPASSER_SYSV=1 perl Makefile.PL

Currently the default is to always use the BSD interface. It will attempt to figure out which interface is appropriate (BSD4.4 or BSD4.3). Currently Solaris uses 4.3 and everything else uses 4.4. Patches and/or portability reports are welcome.



=head1 FULL DESCRIPTOR TABLES

Any system call that creates new descriptors in your process can fail because your process has exceed its NOFILE resource limit. Also, it can fail because the system has run out of resources and can't handle new files or (more likely on modern system...

In order to pass a file descriptor between processes, a new descriptor needs to be allocated in the receiving process. Therefore, the C<recvmsg> and C<ioctl> system calls used to implement descriptor passing can fail unexpectedly. Failing to create a...

So what should we do? We could silently ignore it when a descriptor fails to transfer, but then we run the risk of desynchronising the descriptor stream. Another possibility is indicating to the application that this descriptor has failed to transfer...

None of the above "solutions" are very appealing so this module uses a trick known as the "close-dup slot reservation" trick. Actually I just made that name up now but it sounds pretty cool don't you think? The idea is that when the passer object is ...

When it comes time to receive a descriptor, we close the sentinel descriptor, receive the descriptor from the sending process, and then attempt to dup another descriptor. Because we just cleared a descriptor table entry, there should always be a free...

If duping fails, we stop trying to receive any further descriptors and instead retry at regular intervals (while not interrupting the event loop). Hopefully eventually the full descriptor table issue will clear up and we will be able to resume receiv...

Note that a descriptor could be created between closing and receiving if your program uses asynchronous signal handlers or threads that create descriptors, so don't do that. Signals that are handled synchronously (like normal AnyEvent signal watchers...

This trick is similar to a trick described in Marc Lehmann's libev POD document, section "special problem of accept()ing when you can't," although the purpose of employing the trick in this module is somewhat different.




=head1 TESTS AND SYSTEM ASSUMPTIONS

All the following tests should work with BSD4.4, BSD4.3, and SysV interfaces (where available).

lib/AnyEvent/FDpasser.pm  view on Meta::CPAN


    my $rv = recv_fd(fileno($self->{fh}));

    if ($rv == -1) {
      if ($!{EAGAIN} || $!{EWOULDBLOCK} || $!{EINTR}) {
        ## Spurious ready notification or signal: put the cb back on the queue
        unshift @{$self->{ibuf}}, $cb;
      } elsif ($!{EMSGSIZE} || $!{EMFILE} || $!{ENFILE}) {
        ## File descriptor table is full. This should be very unlikely given the close+duping
        ## technique used to detect this. In this case the descriptor stream may be
        ## desynchronised and we must shutdown the passer.

        my $err = $!;

        carp "AnyEvent::FDpasser - file descriptor table full, closing passer: $!";

        $self->error($err);
      } else {
        ## Unknown error
        $self->error($!);
      }

lib/AnyEvent/FDpasser.pm  view on Meta::CPAN


=head2 Forking

This module itself never calls C<fork()>, but many use-cases of this module involve the application program forking. All the usual things you must worry about when forking an AnyEvent application also apply to this module. In particular, you should e...

Creating a passer object before forking is fine since doing this doesn't install any AnyEvent watchers. Also, using the filesystem with C<AF_UNIX> sockets (or more portably, C<fdpasser_server>, C<fdpasser_accept>, and C<fdpasser_connect>) obviates th...


=head2 Control channels

A useful design is to have a "control channel" associated with each passer that sends over data related to file descriptors being passed. As long as the control channel is a synchronised and ordered queue of messages, each message can indicate how ma...

With both the BSD and SysV APIs it is possible to use the passer filehandle to transfer control data but this module does not support this in order to keep the API simple. However, instead you can use a separate socket connection as your control chan...


=head2 Portability

In order to use the SysV interface, set the C<FDPASSER_SYSV> environment variable when running C<Makefile.PL>:

    $ FDPASSER_SYSV=1 perl Makefile.PL

Currently the default is to always use the BSD interface. It will attempt to figure out which interface is appropriate (BSD4.4 or BSD4.3). Currently Solaris uses 4.3 and everything else uses 4.4. Patches and/or portability reports are welcome.



=head1 FULL DESCRIPTOR TABLES

Any system call that creates new descriptors in your process can fail because your process has exceed its NOFILE resource limit. Also, it can fail because the system has run out of resources and can't handle new files or (more likely on modern system...

In order to pass a file descriptor between processes, a new descriptor needs to be allocated in the receiving process. Therefore, the C<recvmsg> and C<ioctl> system calls used to implement descriptor passing can fail unexpectedly. Failing to create a...

So what should we do? We could silently ignore it when a descriptor fails to transfer, but then we run the risk of desynchronising the descriptor stream. Another possibility is indicating to the application that this descriptor has failed to transfer...

None of the above "solutions" are very appealing so this module uses a trick known as the "close-dup slot reservation" trick. Actually I just made that name up now but it sounds pretty cool don't you think? The idea is that when the passer object is ...

When it comes time to receive a descriptor, we close the sentinel descriptor, receive the descriptor from the sending process, and then attempt to dup another descriptor. Because we just cleared a descriptor table entry, there should always be a free...

If duping fails, we stop trying to receive any further descriptors and instead retry at regular intervals (while not interrupting the event loop). Hopefully eventually the full descriptor table issue will clear up and we will be able to resume receiv...

Note that a descriptor could be created between closing and receiving if your program uses asynchronous signal handlers or threads that create descriptors, so don't do that. Signals that are handled synchronously (like normal AnyEvent signal watchers...

This trick is similar to a trick described in Marc Lehmann's libev POD document, section "special problem of accept()ing when you can't," although the purpose of employing the trick in this module is somewhat different.




=head1 TESTS AND SYSTEM ASSUMPTIONS

All the following tests should work with BSD4.4, BSD4.3, and SysV interfaces (where available).



( run in 0.294 second using v1.01-cache-2.11-cpan-0d8aa00de5b )