Class FileDescriptorCast

java.lang.Object
org.newsclub.net.unix.FileDescriptorCast
All Implemented Interfaces:
FileDescriptorAccess

public final class FileDescriptorCast extends Object implements FileDescriptorAccess
Provides object-oriented access to file descriptors via InputStream, Socket, etc., depending on the file descriptor type.

Typical usage:


 FileDescriptor fd;

 // succeeds if fd refers to an AF_UNIX stream socket
 AFUNIXSocket socket = FileDescriptorCast.using(fd).as(AFUNIXSocket.class);

 // succeeds if fd refers to an AF_UNIX datagram socket
 AFUNIXDatagramChannel channel = FileDescriptorCast.using(fd).as(AFUNIXDatagramChannel.class);

 // always succeeds
 InputStream in = FileDescriptorCast.using(fd).as(InputStream.class);
 OutputStream in = FileDescriptorCast.using(fd).as(OutputStream.class);
 

Important notes

  1. On some platforms (e.g., Solaris, Illumos) you may need to re-apply a read timeout (e.g., using Socket.setSoTimeout(int)) after obtaining the socket.
  2. You may lose Java port information for AFSocketAddress implementations that do not encode this information directly (such as AFUNIXSocketAddress and AFTIPCSocketAddress).
  3. The "blocking" state of a socket may be forcibly changed to "blocking" when performing the cast, especially when casting to Socket, DatagramSocket or ServerSocket and any of their subclasses where "blocking" is the expected state.
  4. When calling using(FileDescriptor) for a FileDescriptor obtained from another socket or other resource in the same JVM (i.e., not from another process), especially for sockets provided by junixsocket itself, there is a chance that the garbage collector may clean up the original socket at an opportune moment, thereby closing the resource underlying the shared FileDescriptor prematurely.

    This is considered an edge-case, and deliberately not handled automatically for performance and portability reasons: We would have to do additional reference counting on all FileDescriptor instances, either through patching FileCleanable or a shared data structure.

    The issue can be prevented by keeping a reference to the original object, such as keeping it in an enclosing try-with-resources block or as a member variable, for example. Alternatively, using a "duplicate" file descriptor (via duplicating(FileDescriptor)) circumvents this problem, at the cost of using additional system resources.

  5. As a consequence of the previous point: For using(FileDescriptor): when casting file descriptors that belong to a junixsocket-controlled sockets, the target socket is configured in a way such that garbage collection will not automatically close the target's underlying file descriptor (but still potentially any file descriptors received from other processes via ancillary messages).
  6. The same restrictions as for using(FileDescriptor) apply to unsafeUsing(int) as well.
Author:
Christian Kohlschütter