Top Description Inners Fields Constructors Methods
org.newsclub.net.unix

public final Class FileDescriptorCast

extends Object
implements FileDescriptorAccess
Class Inheritance
All Implemented Interfaces
org.newsclub.net.unix.FileDescriptorAccess
Annotations
@SuppressWarnings:PMD.CouplingBetweenObjects
Imports
java.io.Closeable, .FileDescriptor, .FileInputStream, .FileOutputStream, .IOException, .InputStream, java.lang.ProcessBuilder.Redirect, java.net.DatagramSocket, .ServerSocket, .Socket, java.nio.channels.DatagramChannel, .FileChannel, .ReadableByteChannel, .ServerSocketChannel, .SocketChannel, .WritableByteChannel, java.nio.channels.spi.AbstractSelectableChannel, java.util.Collections, .HashMap, .Map, .Objects, .Set, org.eclipse.jdt.annotation.NonNull, com.kohlschutter.annotations.compiletime.SuppressFBWarnings

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

Nested and Inner Type Summary

Modifier and TypeClass and Description
private static interface
private abstract static class
private static interface
private static class

Field Summary

Modifier and TypeField and Description
private final FileDescriptorCast.CastingProviderMap
private static final int
private static final int
private static final AFFunction<FileDescriptor, FileInputStream>
private static final int
private final FileDescriptor
private static final FileDescriptorCast.CastingProviderMap
private static final FileDescriptorCast.CastingProviderMap
private int
private static final Map<Class<?>, FileDescriptorCast.CastingProviderMap>
private int

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
public <
The desired type.
K
>
@NonNull K

Returns:

s An instance of the desired type.
as
(Class<K>
The class of the desired type.
desiredType
)

Casts this instance to the desired type.

public Set<Class<?>>

Returns:

The collection of available types.
availableTypes
()

Returns a collection of available types this instance can be cast to (using as(Class)).

public static FileDescriptorCast

Returns:

The FileDescriptorCast instance.
duplicating
(FileDescriptor
The file descriptor to duplicate.
fdObj
)

Creates a FileDescriptorCast using a duplicate of the given file descriptor.

private static int
public FileDescriptor
public boolean

Returns:

true if the cast can be made.
isAvailable
(Class<?>
The class of the desired type.
desiredType
)

Checks if the instance can be cast as the given desired type (using as(Class)).

private static <S extends AFSocket<?>> S
reconfigure(boolean isChannel, S socket)

private static <S extends AFServerSocket<?>> S
reconfigure(boolean isChannel, S socket)

private static <S extends AFDatagramSocket<?>> S
reconfigure(boolean isChannel, S socket)

private static <
The type.
S extends AFSomeSocketChannel
>
void
reconfigure(boolean
The desired cast type (socket=set to blocking, or channel=preserve state).
isChannel
,
S
The channel.
socketChannel
)

Reconfigures the Java-side of the socket/socket channel such that its state is compatible with the native socket's state.

private static <S extends AFSomeSocketChannel> void
private static <S extends AFSomeSocketChannel> void
reconfigureSetBlocking(S socketChannel)

private static void
pack-priv static <A extends AFSocketAddress> void
private static void
registerGenericSocketSupport()

Add support for otherwise unsupported sockets.

private static void
public static FileDescriptorCast

Returns:

The FileDescriptorCast instance.
unsafeUsing
(int
The system-native file descriptor value.
fd
)

Creates a FileDescriptorCast using the given native file descriptor value.

public static FileDescriptorCast

Returns:

The FileDescriptorCast instance.
using
(FileDescriptor
The file descriptor.
fdObj
)

Creates a FileDescriptorCast using the given file descriptor.

public FileDescriptorCast

Returns:

This instance.
withLocalPort
(int
The port to assign to (must be >= 0).
port
)

Registers the given port number as the "local port" for this file descriptor.

public FileDescriptorCast

Returns:

This instance.
withRemotePort
(int
The port to assign to (must be >= 0).
port
)

Registers the given port number as the "remote port" for this file descriptor.

Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

cpmback to summary
private final FileDescriptorCast.CastingProviderMap cpm
FD_ERRback to summary
private static final int FD_ERR
FD_INback to summary
private static final int FD_IN
FD_IS_PROVIDERback to summary
private static final AFFunction<FileDescriptor, FileInputStream> FD_IS_PROVIDER
FD_OUTback to summary
private static final int FD_OUT
fdObjback to summary
private final FileDescriptor fdObj
GLOBAL_PROVIDERSback to summary
private static final FileDescriptorCast.CastingProviderMap GLOBAL_PROVIDERS
GLOBAL_PROVIDERS_FINALback to summary
private static final FileDescriptorCast.CastingProviderMap GLOBAL_PROVIDERS_FINAL
localPortback to summary
private int localPort
PRIMARY_TYPE_PROVIDERS_MAPback to summary
private static final Map<Class<?>, FileDescriptorCast.CastingProviderMap> PRIMARY_TYPE_PROVIDERS_MAP
remotePortback to summary
private int remotePort

Constructor Detail

FileDescriptorCastback to summary
private FileDescriptorCast(FileDescriptor fdObj, FileDescriptorCast.CastingProviderMap cpm)

Method Detail

asback to summary
public <K> @NonNull K as(Class<K> desiredType) throws IOException

Casts this instance to the desired type.

Parameters
<K>
The desired type.
desiredType:Class<K>

The class of the desired type.

Returns:@NonNull K

s An instance of the desired type.

Annotations
@SuppressWarnings:PMD.ShortMethodName
Exceptions
IOException:
if there was a problem while casting.
ClassCastException:
if the cast cannot be legally made.
See Also
availableTypes(), isAvailable(Class)
availableTypesback to summary
public Set<Class<?>> availableTypes()

Returns a collection of available types this instance can be cast to (using as(Class)).

Returns:Set<Class<?>>

The collection of available types.

duplicatingback to summary
public static FileDescriptorCast duplicating(FileDescriptor fdObj) throws IOException

Creates a FileDescriptorCast 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) over using(FileDescriptor) is that neither implicit garbage collection nor an explicit call to Closeable#close() on a resource owning the original FileDescriptor affects the availability of the resource from the target of the cast.

Parameters
fdObj:FileDescriptor

The file descriptor to duplicate.

Returns:FileDescriptorCast

The FileDescriptorCast instance.

Exceptions
IOException:
on error, especially if the given file descriptor is invalid or unsupported, or if duplicating fails or is unsupported.
getFdIfPossibleback to summary
private static int getFdIfPossible(FileDescriptor fd)
getFileDescriptorback to summary
public FileDescriptor getFileDescriptor()

Implements org.newsclub.net.unix.FileDescriptorAccess.getFileDescriptor.

Doc from org.newsclub.net.unix.FileDescriptorAccess.getFileDescriptor.

Returns the corresponding FileDescriptor.

Returns:FileDescriptor

The corresponding FileDescriptor.

Annotations
@Override
@SuppressFBWarnings:EI_EXPOSE_REP
isAvailableback to summary
public boolean isAvailable(Class<?> desiredType) throws IOException

Checks if the instance can be cast as the given desired type (using as(Class)).

Parameters
desiredType:Class<?>

The class of the desired type.

Returns:boolean

true if the cast can be made.

Exceptions
IOException:
on error.
See Also
as(Class)
reconfigureback to summary
private static <S extends AFSocket<?>> S reconfigure(boolean isChannel, S socket) throws IOException
Annotations
@SuppressWarnings:null
reconfigureback to summary
private static <S extends AFServerSocket<?>> S reconfigure(boolean isChannel, S socket) throws IOException
Annotations
@SuppressWarnings:null
reconfigureback to summary
private static <S extends AFDatagramSocket<?>> S reconfigure(boolean isChannel, S socket) throws IOException
Annotations
@SuppressWarnings:null
reconfigureback to summary
private static <S extends AFSomeSocketChannel> void reconfigure(boolean isChannel, S socketChannel) throws IOException

Reconfigures the Java-side of the socket/socket channel such that its state is compatible with the native socket's state. This is necessary to properly configure blocking/non-blocking state, as that is cached on the Java side.

If isChannel is false, then we want to cast to a Socket, DatagramSocket or ServerSocket, which means blocking I/O is desired. If the underlying native socket is configured non-blocking, we need to reset the state to "blocking" accordingly.

If isChannel is true, then we want to cast to a SocketChannel, DatagramChannel or ServerSocketChannel, in which case the blocking state should be preserved, if possible. It is then up to the user to check blocking state via AbstractSelectableChannel#isBlocking() prior to using the socket.

Note that on Windows, it may be impossible to query the blocking state from an external socket, so the state is always forcibly set to "blocking".

Parameters
<S>
The type.
isChannel:boolean

The desired cast type (socket=set to blocking, or channel=preserve state).

socketChannel:S

The channel.

Exceptions
IOException:
on error.
reconfigureKeepBlockingStateback to summary
private static <S extends AFSomeSocketChannel> void reconfigureKeepBlockingState(S socketChannel) throws IOException
reconfigureSetBlockingback to summary
private static <S extends AFSomeSocketChannel> void reconfigureSetBlocking(S socketChannel) throws IOException
registerCastingProvidersback to summary
private static void registerCastingProviders(Class<?> primaryType, FileDescriptorCast.CastingProviderMap cpm)
registerCastingProvidersback to summary
pack-priv static <A extends AFSocketAddress> void registerCastingProviders(AFAddressFamilyConfig<A> config)
registerGenericSocketSupportback to summary
private static void registerGenericSocketSupport()

Add support for otherwise unsupported sockets.

triggerInitback to summary
private static void triggerInit()
unsafeUsingback to summary
public static FileDescriptorCast unsafeUsing(int fd) throws IOException

Creates a FileDescriptorCast using the given native file descriptor value.

This method is inherently unsafe as it may

  1. make assumptions on the internal system representation of a file descriptor (which differs between Windows and Unix, for example).
  2. provide access to resources that are otherwise not accessible

Note that attempts are made to reuse FileDescriptor#in, FileDescriptor#out, and FileDescriptor#err, respectively.

Parameters
fd:int

The system-native file descriptor value.

Returns:FileDescriptorCast

The FileDescriptorCast instance.

Annotations
@Unsafe
Exceptions
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.
usingback to summary
public static FileDescriptorCast using(FileDescriptor fdObj) throws IOException

Creates a FileDescriptorCast 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 referenced FileDescriptor, thereby resulting in premature connection losses, etc. See duplicating(FileDescriptor) for a solution to this problem.

Parameters
fdObj:FileDescriptor

The file descriptor.

Returns:FileDescriptorCast

The FileDescriptorCast instance.

Exceptions
IOException:
on error, especially if the given file descriptor is invalid or unsupported.
withLocalPortback to summary
public FileDescriptorCast withLocalPort(int port)

Registers the given port number as the "local port" for this file descriptor.

Important Note

This only changes the state of this instance. The actual file descriptor is not affected.

Parameters
port:int

The port to assign to (must be >= 0).

Returns:FileDescriptorCast

This instance.

withRemotePortback to summary
public FileDescriptorCast withRemotePort(int port)

Registers the given port number as the "remote port" for this file descriptor.

Important Note

This only changes the state of this instance. The actual file descriptor is not affected.

Parameters
port:int

The port to assign to (must be >= 0).

Returns:FileDescriptorCast

This instance.

org.newsclub.net.unix back to summary

private Interface FileDescriptorCast.CastingProvider<T>

Annotations
@FunctionalInterface

Method Summary

Modifier and TypeMethod and Description
public T
provideAs(FileDescriptorCast fdc, Class<? super T> desiredType)

Method Detail

provideAsback to summary
public T provideAs(FileDescriptorCast fdc, Class<? super T> desiredType) throws IOException
org.newsclub.net.unix back to summary

private abstract Class FileDescriptorCast.CastingProviderMap

extends Object
Class Inheritance

Field Summary

Modifier and TypeField and Description
private final Set<Class<?>>
private final Map<Class<?>, FileDescriptorCast.CastingProvider<?>>

Constructor Summary

AccessConstructor and Description
protected

Method Summary

Modifier and TypeMethod and Description
protected final <T> void
private void
protected abstract void
protected final void
public <T> FileDescriptorCast.CastingProvider<? extends T>
get(Class<T> desiredType)

protected void
protected void
Inherited from java.lang.Object:
cloneequalsfinalizegetClasshashCodenotifynotifyAlltoStringwaitwaitwait

Field Detail

classesback to summary
private final Set<Class<?>> classes
providersback to summary
private final Map<Class<?>, FileDescriptorCast.CastingProvider<?>> providers

Constructor Detail

CastingProviderMapback to summary
protected CastingProviderMap()
Annotations
@SuppressWarnings:PMD.ConstructorCallsOverridableMethod

Method Detail

addProviderback to summary
protected final <T> void addProvider(Class<T> type, FileDescriptorCast.CastingProvider<?> cp)
addProvider0back to summary
private void addProvider0(Class<?> type, FileDescriptorCast.CastingProvider<?> cp)
addProvidersback to summary
protected abstract void addProviders()
addProvidersback to summary
protected final void addProviders(FileDescriptorCast.CastingProviderMap other)
getback to summary
public <T> FileDescriptorCast.CastingProvider<? extends T> get(Class<T> desiredType)
Annotations
@SuppressWarnings:unchecked
registerGenericDatagramSocketProvidersback to summary
protected void registerGenericDatagramSocketProviders()
Annotations
@SuppressWarnings:null
registerGenericSocketProvidersback to summary
protected void registerGenericSocketProviders()
Annotations
@SuppressWarnings:null
org.newsclub.net.unix back to summary

private Interface FileDescriptorCast.CastingProviderSocketOrChannel<T>

Annotations
@FunctionalInterface

Method Summary

Modifier and TypeMethod and Description
public T
provideAs(FileDescriptorCast fdc, Class<? super T> desiredType, boolean isChannel)

Method Detail

provideAsback to summary
public T provideAs(FileDescriptorCast fdc, Class<? super T> desiredType, boolean isChannel) throws IOException
org.newsclub.net.unix back to summary

private final Class FileDescriptorCast.LenientFileInputStream

extends FileInputStream
Class Inheritance

Constructor Summary

AccessConstructor and Description
private

Method Summary

Modifier and TypeMethod and Description
public int
available()

Overrides java.io.FileInputStream.available.

Returns an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream.

Inherited from java.io.FileInputStream:
closegetChannelgetFDreadreadreadreadAllBytesreadNBytesskiptransferTo

Constructor Detail

LenientFileInputStreamback to summary
private LenientFileInputStream(FileDescriptor fdObj)

Method Detail

availableback to summary
public int available() throws IOException

Overrides java.io.FileInputStream.available.

Doc from java.io.FileInputStream.available.

Returns an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream without blocking by the next invocation of a method for this input stream. Returns 0 when the file position is beyond EOF. The next invocation might be the same thread or another thread. A single read or skip of this many bytes will not block, but may read or skip fewer bytes.

In some cases, a non-blocking read (or skip) may appear to be blocked when it is merely slow, for example when reading large files over slow networks.

Returns:int

an estimate of the number of remaining bytes that can be read (or skipped over) from this input stream without blocking.

Annotations
@Override
Exceptions
IOException:
if this file input stream has been closed by calling close or an I/O error occurs.