- All Implemented Interfaces:
FileDescriptorAccess
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
- 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. - You may lose Java port information for
AFSocketAddress
implementations that do not encode this information directly (such asAFUNIXSocketAddress
andAFTIPCSocketAddress
). - The "blocking" state of a socket may be forcibly changed to "blocking" when performing the
cast, especially when casting to
Socket
,DatagramSocket
orServerSocket
and any of their subclasses where "blocking" is the expected state. - When calling
using(FileDescriptor)
for aFileDescriptor
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 sharedFileDescriptor
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. - 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). - The same restrictions as for
using(FileDescriptor)
apply tounsafeUsing(int)
as well.
- Author:
- Christian Kohlschütter
-
Method Summary
Modifier and TypeMethodDescription<K> @NonNull K
Casts this instance to the desired type.Returns a collection of available types this instance can be cast to (usingas(Class)
).static FileDescriptorCast
duplicating
(FileDescriptor fdObj) Creates aFileDescriptorCast
using a duplicate of the given file descriptor.Returns the correspondingFileDescriptor
.boolean
isAvailable
(Class<?> desiredType) Checks if the instance can be cast as the given desired type (usingas(Class)
).static FileDescriptorCast
unsafeUsing
(int fd) Creates aFileDescriptorCast
using the given native file descriptor value.static FileDescriptorCast
using
(FileDescriptor fdObj) Creates aFileDescriptorCast
using the given file descriptor.withLocalPort
(int port) Registers the given port number as the "local port" for this file descriptor.withRemotePort
(int port) Registers the given port number as the "remote port" for this file descriptor.
-
Method Details
-
using
Creates aFileDescriptorCast
using the given file descriptor.Note that if any resource that also references this
FileDescriptor
is garbage-collected, the cleanup for that object may close the referencedFileDescriptor
, thereby resulting in premature connection losses, etc. Seeduplicating(FileDescriptor)
for a solution to this problem.- Parameters:
fdObj
- The file descriptor.- Returns:
- The
FileDescriptorCast
instance. - Throws:
IOException
- on error, especially if the given file descriptor is invalid or unsupported.
-
duplicating
Creates aFileDescriptorCast
using a duplicate of the given file descriptor.Duplicating a file descriptor is performed at the system-level, which means an additional file descriptor pointing to the same resource as the original is created by the operating system.
The advantage of using
duplicating(FileDescriptor)
overusing(FileDescriptor)
is that neither implicit garbage collection nor an explicit call toCloseable.close()
on a resource owning the originalFileDescriptor
affects the availability of the resource from the target of the cast.- Parameters:
fdObj
- The file descriptor to duplicate.- Returns:
- The
FileDescriptorCast
instance. - Throws:
IOException
- on error, especially if the given file descriptor is invalid or unsupported, or if duplicating fails or is unsupported.
-
unsafeUsing
Creates aFileDescriptorCast
using the given native file descriptor value.This method is inherently unsafe as it may
- make assumptions on the internal system representation of a file descriptor (which differs between Windows and Unix, for example).
- provide access to resources that are otherwise not accessible
Note that attempts are made to reuse
FileDescriptor.in
,FileDescriptor.out
, andFileDescriptor.err
, respectively.- Parameters:
fd
- The system-native file descriptor value.- Returns:
- The
FileDescriptorCast
instance. - Throws:
IOException
- on error, especially if the given file descriptor is invalid or unsupported, or when "unsafe" operations are unavailable or manually disabled for the current environment.
-
withLocalPort
Registers the given port number as the "local port" for this file descriptor. Important: This only changes the state of this instance. The actual file descriptor is not affected.- Parameters:
port
- The port to assign to (must be >= 0).- Returns:
- This instance.
-
withRemotePort
Registers the given port number as the "remote port" for this file descriptor. Important: This only changes the state of this instance. The actual file descriptor is not affected.- Parameters:
port
- The port to assign to (must be >= 0).- Returns:
- This instance.
-
as
Casts this instance to the desired type.- Type Parameters:
K
- The desired type.- Parameters:
desiredType
- The class of the desired type.- Returns:
- s An instance of the desired type.
- Throws:
IOException
- if there was a problem while casting.ClassCastException
- if the cast cannot be legally made.- See Also:
-
isAvailable
Checks if the instance can be cast as the given desired type (usingas(Class)
).- Parameters:
desiredType
- The class of the desired type.- Returns:
true
if the cast can be made.- Throws:
IOException
- on error.- See Also:
-
availableTypes
-
getFileDescriptor
Description copied from interface:FileDescriptorAccess
Returns the correspondingFileDescriptor
.- Specified by:
getFileDescriptor
in interfaceFileDescriptorAccess
- Returns:
- The corresponding
FileDescriptor
.
-