AnyEvent-FDpasser

 view release on metacpan or  search on metacpan

README.pod  view on Meta::CPAN

=item $passer_fh = AnyEvent::FDpasser::fdpasser_accept($listener_fh)

Given a listener filehandle created with L<AnyEvent::FDpasser::fdpasser_server>, this function accepts and creates a new filehandle suitable for creating an FDpasser object. It is portable between BSD systems where it uses the socket C<accept(2)> sys...

=item $passer_fh = AnyEvent::FDpasser::fdpasser_connect($path)

This function connects to a listening node on the filesystem created with L<AnyEvent::FDpasser::fdpasser_server> and returns a new filehandle suitable for creating an FDpasser object. It is portable between BSD systems where it uses the socket C<conn...

=back




=head1 NOTES

=head2 Userspace buffers

Because the underlying operations only transfer file descriptors, it is undefined whether any data in userspace buffers like IO::Handle or AnyEvent::Handle will have been written to the file descriptor at the time it is transfered. You should always ...

You should remove all IO watchers associated with the descriptor before initiating the transfer because after the descriptor is transfered it will be closed and watchers should always be destroyed before closing their respective filehandles. Also, if...


=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).


=head2 Bidirectional

A passer is bidirectional and can be used to both send and receive descriptors, even simultaneously.

There are tests (basic_socketpair.t and basic_filesystem.t) to verify this.


=head2 Non-blocking

A process may initiate push_recv_fh on a passer and this process will not block while it is waiting for the other end to call push_send_fh (and vice versa).

There are tests (recv_before_send.t and send_before_recv.t) to verify this.


=head2 FIFO ordering

The order descriptors are sent with push_send_fh is the same order that they are received on at the other end with push_recv_fh.

There is a test (buffer_exercise.t) to verify this and some other basic buffering properties.


=head2 Preserves blocking status

After a fork, the non-blocking status of a descriptor is preserved so if you are doing a socketpair followed by a fork it is acceptable to set the non-blocking status of both descriptors in the parent.

Also, the non-blocking status of a descriptor passed with this module is preserved after it is passed so it is not necessary to reset nonblocking status on descriptors.

There is a test (non_blocking_fhs.t) to verify this and some other assumptions for any given system.


=head2 Passing passers

Passing a descriptor and then using this descriptor as an argument to the existing_fh mode of this module to construct another passer is supported.

There is a test (send_passer_over_passer.t) to verify this assumption for any given system.


=head2 Descriptor table full

Even when the descriptor table fills up intermittently, no descriptors being passed should be lost.

There is a test (full_descriptor_table.t) to verify this.






=head1 SEE ALSO



( run in 0.543 second using v1.01-cache-2.11-cpan-39bf76dae61 )