Java Unix Domain Socket implementation providing AF_UNIX, AF_TIPC, AF_VSOCK, and AF_SYSTEM socket support with traditional and NIO APIs
—
Advanced Unix Domain Socket features including file descriptor passing, peer credentials, and ancillary message handling for sophisticated inter-process communication scenarios.
import java.io.*;
import java.net.*;
import org.newsclub.net.unix.AFUNIXSocket;
import org.newsclub.net.unix.AFUNIXSocketChannel;
import org.newsclub.net.unix.AFUNIXSocketCredentials;
import org.newsclub.net.unix.AFUNIXSocketExtensions;
import org.newsclub.net.unix.AFSocketCapability;
import org.newsclub.net.unix.FileDescriptorAccess;Interface defining advanced Unix Domain Socket extensions beyond the standard Socket API, including file descriptor passing and credential access.
/**
* Advanced Unix Domain Socket extensions interface
*/
public interface AFUNIXSocketExtensions {
/**
* Gets file descriptors received via ancillary messages
* File descriptors are received automatically with regular data
* @return Array of received file descriptors, never null
* @throws IOException if retrieval fails
*/
FileDescriptor[] getReceivedFileDescriptors() throws IOException;
/**
* Clears the queue of received file descriptors
* Should be called after processing received file descriptors
*/
void clearReceivedFileDescriptors();
/**
* Sets file descriptors to be sent via ancillary messages
* File descriptors will be sent with the next write operation
* @param fds File descriptors to send (can be empty to clear)
* @throws IOException if setting fails
*/
void setOutboundFileDescriptors(FileDescriptor... fds) throws IOException;
/**
* Checks if outbound file descriptors are pending
* @return true if file descriptors are queued for sending
*/
boolean hasOutboundFileDescriptors();
/**
* Gets credentials of the peer process
* @return Peer credentials information
* @throws IOException if retrieval fails or not supported
*/
AFUNIXSocketCredentials getPeerCredentials() throws IOException;
}Usage Examples:
import java.io.*;
import java.nio.charset.StandardCharsets;
import org.newsclub.net.unix.*;
// Server: Receiving file descriptors
File serverSocket = new File("/tmp/fd-server.sock");
try (AFUNIXServerSocket server = AFUNIXServerSocket.bindOn(AFUNIXSocketAddress.of(serverSocket))) {
System.out.println("Server waiting for connections...");
try (AFUNIXSocket clientSocket = server.accept()) {
System.out.println("Client connected");
// Read regular data and file descriptors
InputStream is = clientSocket.getInputStream();
byte[] buffer = new byte[1024];
int bytesRead = is.read(buffer);
String message = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
System.out.println("Received message: " + message);
// Check for received file descriptors
FileDescriptor[] receivedFds = clientSocket.getReceivedFileDescriptors();
System.out.println("Received " + receivedFds.length + " file descriptors");
for (int i = 0; i < receivedFds.length; i++) {
// Use the received file descriptor
try (FileInputStream fis = new FileInputStream(receivedFds[i])) {
byte[] fileBuffer = new byte[1024];
int fileBytes = fis.read(fileBuffer);
String fileContent = new String(fileBuffer, 0, fileBytes, StandardCharsets.UTF_8);
System.out.println("Content from FD " + i + ": " + fileContent);
}
}
// Clear received file descriptors after processing
clientSocket.clearReceivedFileDescriptors();
// Get peer credentials
AFUNIXSocketCredentials peerCreds = clientSocket.getPeerCredentials();
System.out.println("Peer process ID: " + peerCreds.getPid());
System.out.println("Peer user ID: " + peerCreds.getUid());
System.out.println("Peer group ID: " + peerCreds.getGid());
}
}
// Client: Sending file descriptors
File clientSocket = new File("/tmp/fd-client.sock");
try (AFUNIXSocket socket = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of(serverSocket))) {
// Create a temporary file to send
File tempFile = File.createTempFile("test", ".txt");
try (FileWriter writer = new FileWriter(tempFile)) {
writer.write("Hello from shared file!");
}
// Open file descriptor to send
FileInputStream fileInput = new FileInputStream(tempFile);
FileDescriptor fd = fileInput.getFD();
// Set file descriptor to be sent
socket.setOutboundFileDescriptors(fd);
// Send regular data (file descriptor will be sent automatically)
OutputStream os = socket.getOutputStream();
os.write("Sending file descriptor".getBytes(StandardCharsets.UTF_8));
os.flush();
System.out.println("File descriptor sent with message");
// Clean up
fileInput.close();
tempFile.delete();
}Container for Unix Domain Socket peer credentials, providing access to peer process information for authentication and authorization.
/**
* Unix Domain Socket peer credentials
*/
public final class AFUNIXSocketCredentials {
/**
* Gets the process ID of the peer
* @return Process ID (PID)
*/
public long getPid();
/**
* Gets the user ID of the peer process
* @return User ID (UID)
*/
public long getUid();
/**
* Gets the primary group ID of the peer process
* @return Primary group ID (GID)
*/
public long getGid();
/**
* Gets all group IDs of the peer process
* @return Array of all group IDs
*/
public long[] getGids();
/**
* Gets the UUID of the peer process (if available)
* @return Process UUID or null
*/
public String getUUID();
/**
* Creates credentials for the current process
* @return Current process credentials
*/
public static AFUNIXSocketCredentials current();
/**
* Gets remote peer credentials from RMI context
* Used in RMI scenarios to identify the calling process
* @return Remote peer credentials or null
*/
public static AFUNIXSocketCredentials remotePeerCredentials();
/**
* String representation of credentials
* @return Human-readable credential information
*/
public String toString();
}Usage Examples:
import org.newsclub.net.unix.*;
// Authentication server using peer credentials
File authServerSocket = new File("/tmp/auth-server.sock");
try (AFUNIXServerSocket server = AFUNIXServerSocket.bindOn(AFUNIXSocketAddress.of(authServerSocket))) {
while (true) {
try (AFUNIXSocket client = server.accept()) {
// Get peer credentials for authentication
AFUNIXSocketCredentials peerCreds = client.getPeerCredentials();
System.out.println("Connection from:");
System.out.println(" PID: " + peerCreds.getPid());
System.out.println(" UID: " + peerCreds.getUid());
System.out.println(" GID: " + peerCreds.getGid());
// Simple authorization check
if (peerCreds.getUid() == 0) {
System.out.println("Root user detected - full access granted");
client.getOutputStream().write("ADMIN_ACCESS".getBytes());
} else if (peerCreds.getUid() == getCurrentUserId()) {
System.out.println("Same user - standard access granted");
client.getOutputStream().write("USER_ACCESS".getBytes());
} else {
System.out.println("Different user - access denied");
client.getOutputStream().write("ACCESS_DENIED".getBytes());
}
client.getOutputStream().flush();
}
}
}
// Check group memberships
AFUNIXSocketCredentials currentCreds = AFUNIXSocketCredentials.current();
long[] groups = currentCreds.getGids();
System.out.println("Current process belongs to " + groups.length + " groups:");
for (long gid : groups) {
System.out.println(" GID: " + gid);
}Utility class for advanced file descriptor operations and access to native file descriptor values.
/**
* Utility class for file descriptor access and operations
*/
public final class FileDescriptorAccess {
/**
* Gets the native file descriptor value from a FileDescriptor
* @param fd The FileDescriptor instance
* @return Native file descriptor number
* @throws IOException if access fails
*/
public static int getFileDescriptor(FileDescriptor fd) throws IOException;
/**
* Gets the file descriptor from an AFSocket
* @param socket The socket instance
* @return Socket's file descriptor
* @throws IOException if access fails
*/
public static FileDescriptor getFileDescriptor(AFSocket socket) throws IOException;
/**
* Checks if a file descriptor is valid
* @param fd The FileDescriptor to check
* @return true if the file descriptor is valid
*/
public static boolean isValid(FileDescriptor fd);
/**
* Creates a FileDescriptor from a native file descriptor number
* @param fdNum Native file descriptor number
* @return FileDescriptor instance
* @throws IOException if creation fails
*/
public static FileDescriptor fromNative(int fdNum) throws IOException;
}Usage Examples:
import org.newsclub.net.unix.*;
// File descriptor introspection
try (AFUNIXSocket socket = AFUNIXSocket.newInstance()) {
socket.connect(AFUNIXSocketAddress.of(new File("/tmp/test.sock")));
// Get the socket's file descriptor
FileDescriptor socketFd = FileDescriptorAccess.getFileDescriptor(socket);
int nativeFd = FileDescriptorAccess.getFileDescriptor(socketFd);
System.out.println("Socket file descriptor: " + nativeFd);
System.out.println("File descriptor valid: " + FileDescriptorAccess.isValid(socketFd));
// Create file descriptor for stdout
FileDescriptor stdoutFd = FileDescriptorAccess.fromNative(1);
socket.setOutboundFileDescriptors(stdoutFd);
// Send message with stdout file descriptor
socket.getOutputStream().write("Check your terminal!".getBytes());
socket.getOutputStream().flush();
}Check for file descriptor and credential support before using advanced features:
/**
* Capability constants for file descriptor features
*/
public enum AFSocketCapability {
/** File descriptor passing support */
CAPABILITY_FILE_DESCRIPTORS,
/** Peer credential support */
CAPABILITY_PEER_CREDENTIALS,
/** Ancillary message support */
CAPABILITY_ANCILLARY_MESSAGES
}Feature Detection Examples:
import org.newsclub.net.unix.*;
public class FeatureDetection {
public static void main(String[] args) {
System.out.println("Advanced Unix Socket Features:");
if (AFSocketCapability.CAPABILITY_FILE_DESCRIPTORS.isSupported()) {
System.out.println("✓ File descriptor passing available");
demonstrateFileDescriptorPassing();
} else {
System.out.println("✗ File descriptor passing not supported");
}
if (AFSocketCapability.CAPABILITY_PEER_CREDENTIALS.isSupported()) {
System.out.println("✓ Peer credentials available");
demonstratePeerCredentials();
} else {
System.out.println("✗ Peer credentials not supported");
}
if (AFSocketCapability.CAPABILITY_ANCILLARY_MESSAGES.isSupported()) {
System.out.println("✓ Ancillary messages available");
} else {
System.out.println("✗ Ancillary messages not supported");
}
}
private static void demonstrateFileDescriptorPassing() {
// File descriptor passing implementation
System.out.println(" → File descriptor passing is fully functional");
}
private static void demonstratePeerCredentials() {
// Peer credentials implementation
AFUNIXSocketCredentials current = AFUNIXSocketCredentials.current();
System.out.println(" → Current process PID: " + current.getPid());
System.out.println(" → Current process UID: " + current.getUid());
}
}When using file descriptor passing and peer credentials:
// Safe file descriptor handling
FileDescriptor[] receivedFds = socket.getReceivedFileDescriptors();
for (FileDescriptor fd : receivedFds) {
if (FileDescriptorAccess.isValid(fd)) {
try {
// Use the file descriptor
processFileDescriptor(fd);
} finally {
// Ensure proper cleanup
try {
// Close if it's a file we opened
if (fd != FileDescriptor.in && fd != FileDescriptor.out && fd != FileDescriptor.err) {
// Close safely
}
} catch (Exception e) {
// Log but don't fail
}
}
}
}
socket.clearReceivedFileDescriptors();Install with Tessl CLI
npx tessl i tessl/maven-com-kohlschutter-junixsocket--junixsocket-core