CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-com-kohlschutter-junixsocket--junixsocket-core

Java Unix Domain Socket implementation providing AF_UNIX, AF_TIPC, AF_VSOCK, and AF_SYSTEM socket support with traditional and NIO APIs

Pending
Overview
Eval results
Files

exceptions.mddocs/

Exception Handling

Comprehensive exception hierarchy providing detailed error information for robust socket error handling and debugging in Unix Domain Socket operations.

Capabilities

AFException

Base exception class for all AF socket-related errors, extending IOException to integrate with standard Java I/O exception handling.

/**
 * Base exception class for AF socket operations
 */
public class AFException extends IOException {
    
    /**
     * Creates a new AFException with the specified message
     * @param message The error message
     */
    public AFException(String message);
    
    /**
     * Creates a new AFException with message and cause
     * @param message The error message
     * @param cause The underlying cause
     */
    public AFException(String message, Throwable cause);
    
    /**
     * Creates a new AFException with the specified cause
     * @param cause The underlying cause
     */
    public AFException(Throwable cause);
    
    // Error information
    public String getMessage();
    public Throwable getCause();
    public String getLocalizedMessage();
    
    // Stack trace information
    public StackTraceElement[] getStackTrace();
    public void printStackTrace();
    public void printStackTrace(PrintStream s);
    public void printStackTrace(PrintWriter s);
}

Usage Examples:

import org.newsclub.net.unix.*;

try {
    AFUNIXSocket socket = AFUNIXSocket.connectTo(AFUNIXSocketAddress.of("/nonexistent/path.sock"));
} catch (AFException e) {
    System.err.println("AF Socket error: " + e.getMessage());
    
    // Check for specific causes
    Throwable cause = e.getCause();
    if (cause instanceof FileNotFoundException) {
        System.err.println("Socket file not found");
    } else if (cause instanceof SecurityException) {
        System.err.println("Permission denied");
    }
    
    // Log full stack trace for debugging
    e.printStackTrace();
}

Socket State Exceptions

Exceptions related to socket state and lifecycle management.

/**
 * Exception thrown when operating on closed sockets
 */
public class SocketClosedException extends SocketException {
    public SocketClosedException();
    public SocketClosedException(String msg);
    public SocketClosedException(String msg, Throwable cause);
}

/**
 * Exception thrown when socket address is unavailable
 */
public class AddressUnavailableSocketException extends SocketException {
    public AddressUnavailableSocketException();
    public AddressUnavailableSocketException(String msg);
    public AddressUnavailableSocketException(String msg, Throwable cause);
}

/**
 * Exception thrown when connection is refused
 */
public class ConnectionRefusedSocketException extends SocketException {
    public ConnectionRefusedSocketException();
    public ConnectionRefusedSocketException(String msg);
    public ConnectionRefusedSocketException(String msg, Throwable cause);
}

Usage Examples:

// Socket state validation
public void performSocketOperation(AFUNIXSocket socket) throws IOException {
    try {
        if (socket.isClosed()) {
            throw new SocketClosedException("Socket is already closed");
        }
        
        // Perform operation
        OutputStream os = socket.getOutputStream();
        os.write("data".getBytes());
        
    } catch (SocketClosedException e) {
        System.err.println("Cannot operate on closed socket: " + e.getMessage());
        throw e;
    }
}

// Address availability check
public AFUNIXServerSocket createServer(File socketFile) throws IOException {
    try {
        AFUNIXSocketAddress address = AFUNIXSocketAddress.of(socketFile);
        AFUNIXServerSocket server = AFUNIXServerSocket.newInstance();
        server.bind(address);
        return server;
        
    } catch (AddressUnavailableSocketException e) {
        System.err.println("Socket address unavailable: " + socketFile);
        
        // Try to clean up and retry
        if (socketFile.exists() && socketFile.delete()) {
            System.out.println("Cleaned up stale socket file, retrying...");
            return createServer(socketFile);
        }
        throw e;
    }
}

// Connection handling
public void connectWithRetry(AFUNIXSocketAddress address, int maxRetries) throws IOException {
    int attempts = 0;
    
    while (attempts < maxRetries) {
        try {
            AFUNIXSocket socket = AFUNIXSocket.connectTo(address);
            System.out.println("Connected successfully");
            return;
            
        } catch (ConnectionRefusedSocketException e) {
            attempts++;
            System.err.println("Connection refused, attempt " + attempts + "/" + maxRetries);
            
            if (attempts >= maxRetries) {
                throw new IOException("Failed to connect after " + maxRetries + " attempts", e);
            }
            
            try {
                Thread.sleep(1000 * attempts); // Exponential backoff
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                throw new IOException("Connection interrupted", ie);
            }
        }
    }
}

Communication Exceptions

Exceptions related to data transmission and socket communication errors.

/**
 * Exception thrown when pipe is broken during communication
 */
public class BrokenPipeSocketException extends SocketException {
    public BrokenPipeSocketException();
    public BrokenPipeSocketException(String msg);
    public BrokenPipeSocketException(String msg, Throwable cause);
}

/**
 * Exception thrown when connection is reset by peer
 */
public class ConnectionResetSocketException extends SocketException {
    public ConnectionResetSocketException();
    public ConnectionResetSocketException(String msg);
    public ConnectionResetSocketException(String msg, Throwable cause);
}

/**
 * Exception thrown when socket times out
 */
public class SocketTimeoutException extends InterruptedIOException {
    public SocketTimeoutException();
    public SocketTimeoutException(String msg);
    public SocketTimeoutException(String msg, Throwable cause);
}

Usage Examples:

// Robust data transmission
public void sendDataWithErrorHandling(AFUNIXSocket socket, byte[] data) throws IOException {
    try {
        OutputStream os = socket.getOutputStream();
        os.write(data);
        os.flush();
        
    } catch (BrokenPipeSocketException e) {
        System.err.println("Broken pipe - peer closed connection: " + e.getMessage());
        
        // Clean up resources
        try {
            socket.close();
        } catch (IOException closeEx) {
            e.addSuppressed(closeEx);
        }
        throw e;
        
    } catch (ConnectionResetSocketException e) {
        System.err.println("Connection reset by peer: " + e.getMessage());
        
        // Log connection reset and clean up
        logConnectionReset(socket, e);
        throw e;
    }
}

// Timeout handling
public String readWithTimeout(AFUNIXSocket socket, int timeoutMs) throws IOException {
    try {
        socket.setSoTimeout(timeoutMs);
        
        InputStream is = socket.getInputStream();
        byte[] buffer = new byte[1024];
        int bytesRead = is.read(buffer);
        
        if (bytesRead > 0) {
            return new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
        }
        return null;
        
    } catch (SocketTimeoutException e) {
        System.err.println("Read timeout after " + timeoutMs + "ms: " + e.getMessage());
        
        // Decide whether to retry or fail
        if (shouldRetryAfterTimeout(socket)) {
            return readWithTimeout(socket, timeoutMs * 2); // Double timeout and retry
        }
        throw e;
        
    } finally {
        // Reset timeout
        socket.setSoTimeout(0);
    }
}

private boolean shouldRetryAfterTimeout(AFUNIXSocket socket) {
    return socket.isConnected() && !socket.isClosed();
}

private void logConnectionReset(AFUNIXSocket socket, ConnectionResetSocketException e) {
    try {
        AFUNIXSocketAddress localAddr = (AFUNIXSocketAddress) socket.getLocalSocketAddress();
        AFUNIXSocketAddress remoteAddr = (AFUNIXSocketAddress) socket.getRemoteSocketAddress();
        
        System.err.println("Connection reset - Local: " + localAddr + ", Remote: " + remoteAddr);
    } catch (Exception ex) {
        System.err.println("Connection reset - Unable to get socket addresses");
    }
}

System and Platform Exceptions

Exceptions related to system-level errors and platform-specific issues.

/**
 * Exception thrown when device or resource is not found
 */
public class NoSuchDeviceSocketException extends SocketException {
    public NoSuchDeviceSocketException();
    public NoSuchDeviceSocketException(String msg);
    public NoSuchDeviceSocketException(String msg, Throwable cause);
}

/**
 * Exception thrown when operation is not supported
 */
public class OperationNotSupportedSocketException extends SocketException {
    public OperationNotSupportedSocketException();
    public OperationNotSupportedSocketException(String msg);
    public OperationNotSupportedSocketException(String msg, Throwable cause);
}

/**
 * Exception thrown when invalid argument is provided
 */
public class InvalidArgumentSocketException extends SocketException {
    public InvalidArgumentSocketException();
    public InvalidArgumentSocketException(String msg);
    public InvalidArgumentSocketException(String msg, Throwable cause);
}

Usage Examples:

// Platform capability checking
public void performPlatformSpecificOperation(AFUNIXSocket socket) throws IOException {
    try {
        // Attempt platform-specific operation (e.g., peer credentials)
        PeerCredentials credentials = socket.getPeerCredentials();
        System.out.println("Peer PID: " + credentials.getPid());
        
    } catch (OperationNotSupportedSocketException e) {
        System.err.println("Peer credentials not supported on this platform: " + e.getMessage());
        
        // Fall back to alternative approach
        performAlternativeAuthentication(socket);
        
    } catch (NoSuchDeviceSocketException e) {
        System.err.println("Required device not available: " + e.getMessage());
        throw new IOException("Platform requirements not met", e);
    }
}

// Argument validation
public void configureSocket(AFUNIXSocket socket, Map<String, Object> options) throws IOException {
    try {
        for (Map.Entry<String, Object> option : options.entrySet()) {
            applySocketOption(socket, option.getKey(), option.getValue());
        }
        
    } catch (InvalidArgumentSocketException e) {
        System.err.println("Invalid socket configuration: " + e.getMessage());
        
        // Log configuration details for debugging
        System.err.println("Configuration options: " + options);
        throw new IllegalArgumentException("Socket configuration failed", e);
    }
}

private void applySocketOption(AFUNIXSocket socket, String optionName, Object value) throws IOException {
    switch (optionName.toLowerCase()) {
        case "timeout":
            if (!(value instanceof Integer)) {
                throw new InvalidArgumentSocketException("Timeout must be an integer");
            }
            socket.setSoTimeout((Integer) value);
            break;
            
        case "keepalive":
            if (!(value instanceof Boolean)) {
                throw new InvalidArgumentSocketException("KeepAlive must be a boolean");
            }
            socket.setKeepAlive((Boolean) value);
            break;
            
        default:
            throw new InvalidArgumentSocketException("Unknown socket option: " + optionName);
    }
}

private void performAlternativeAuthentication(AFUNIXSocket socket) {
    // Alternative authentication mechanism
    System.out.println("Using alternative authentication method");
}

Exception Handling Patterns

Comprehensive Error Handling

// Complete error handling pattern for socket operations
public class RobustSocketClient {
    private static final int MAX_RETRIES = 3;
    private static final int RETRY_DELAY_MS = 1000;
    
    public void performRobustOperation(File socketFile, byte[] data) throws IOException {
        AFUNIXSocketAddress address = AFUNIXSocketAddress.of(socketFile);
        IOException lastException = null;
        
        for (int attempt = 1; attempt <= MAX_RETRIES; attempt++) {
            try {
                performSingleOperation(address, data);
                return; // Success
                
            } catch (AddressUnavailableSocketException e) {
                System.err.println("Attempt " + attempt + ": Address unavailable - " + e.getMessage());
                lastException = e;
                
                if (attempt == MAX_RETRIES) {
                    throw new IOException("Socket server appears to be down", e);
                }
                
            } catch (ConnectionRefusedSocketException e) {
                System.err.println("Attempt " + attempt + ": Connection refused - " + e.getMessage());
                lastException = e;
                
                if (attempt == MAX_RETRIES) {
                    throw new IOException("Server not accepting connections", e);
                }
                
            } catch (BrokenPipeSocketException | ConnectionResetSocketException e) {
                System.err.println("Attempt " + attempt + ": Connection lost - " + e.getMessage());
                lastException = e;
                
                // Don't retry on connection loss
                throw new IOException("Connection lost during operation", e);
                
            } catch (SocketTimeoutException e) {
                System.err.println("Attempt " + attempt + ": Operation timed out - " + e.getMessage());
                lastException = e;
                
                if (attempt == MAX_RETRIES) {
                    throw new IOException("Operation timed out after " + MAX_RETRIES + " attempts", e);
                }
                
            } catch (OperationNotSupportedSocketException e) {
                // Don't retry unsupported operations
                throw new IOException("Operation not supported on this platform", e);
                
            } catch (AFException e) {
                System.err.println("Attempt " + attempt + ": AF socket error - " + e.getMessage());
                lastException = e;
                
                if (attempt == MAX_RETRIES) {
                    throw new IOException("Socket operation failed", e);
                }
            }
            
            if (attempt < MAX_RETRIES) {
                try {
                    Thread.sleep(RETRY_DELAY_MS * attempt); // Progressive delay
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt();
                    throw new IOException("Operation interrupted", ie);
                }
            }
        }
        
        throw new IOException("All retry attempts failed", lastException);
    }
    
    private void performSingleOperation(AFUNIXSocketAddress address, byte[] data) throws IOException {
        try (AFUNIXSocket socket = AFUNIXSocket.connectTo(address)) {
            socket.setSoTimeout(5000); // 5 second timeout
            
            // Send data
            OutputStream os = socket.getOutputStream();
            os.write(data);
            os.flush();
            
            // Read response
            InputStream is = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int bytesRead = is.read(buffer);
            
            if (bytesRead > 0) {
                String response = new String(buffer, 0, bytesRead, StandardCharsets.UTF_8);
                System.out.println("Received: " + response);
            }
        }
    }
}

Exception Classification and Recovery

// Exception classification for different recovery strategies
public class ExceptionHandler {
    
    public enum ErrorSeverity {
        RECOVERABLE,     // Can retry
        TRANSIENT,       // May recover after delay
        PERMANENT,       // Don't retry
        FATAL           // Should terminate
    }
    
    public static ErrorSeverity classifyException(Exception e) {
        if (e instanceof SocketClosedException) {
            return ErrorSeverity.PERMANENT;
        } else if (e instanceof AddressUnavailableSocketException) {
            return ErrorSeverity.TRANSIENT;
        } else if (e instanceof ConnectionRefusedSocketException) {
            return ErrorSeverity.TRANSIENT;
        } else if (e instanceof BrokenPipeSocketException) {
            return ErrorSeverity.PERMANENT;
        } else if (e instanceof ConnectionResetSocketException) {
            return ErrorSeverity.PERMANENT;
        } else if (e instanceof SocketTimeoutException) {
            return ErrorSeverity.RECOVERABLE;
        } else if (e instanceof OperationNotSupportedSocketException) {
            return ErrorSeverity.FATAL;
        } else if (e instanceof InvalidArgumentSocketException) {
            return ErrorSeverity.FATAL;
        } else if (e instanceof AFException) {
            return ErrorSeverity.TRANSIENT;
        }
        return ErrorSeverity.PERMANENT;
    }
    
    public static boolean shouldRetry(Exception e, int attemptCount, int maxAttempts) {
        if (attemptCount >= maxAttempts) {
            return false;
        }
        
        ErrorSeverity severity = classifyException(e);
        return severity == ErrorSeverity.RECOVERABLE || severity == ErrorSeverity.TRANSIENT;
    }
    
    public static long getRetryDelay(Exception e, int attemptCount) {
        ErrorSeverity severity = classifyException(e);
        
        switch (severity) {
            case RECOVERABLE:
                return Math.min(1000L * (1L << attemptCount), 30000L); // Exponential backoff, max 30s
            case TRANSIENT:
                return Math.min(2000L * attemptCount, 10000L); // Linear backoff, max 10s
            default:
                return 0L;
        }
    }
}

Logging and Monitoring

// Exception logging for monitoring and debugging
public class SocketExceptionLogger {
    private static final Logger logger = LoggerFactory.getLogger(SocketExceptionLogger.class);
    
    public static void logException(Exception e, AFUNIXSocket socket, String operation) {
        Map<String, Object> context = new HashMap<>();
        context.put("operation", operation);
        context.put("exception_type", e.getClass().getSimpleName());
        context.put("exception_message", e.getMessage());
        
        try {
            if (socket != null) {
                context.put("socket_closed", socket.isClosed());
                context.put("socket_connected", socket.isConnected());
                context.put("socket_bound", socket.isBound());
                
                if (socket.getLocalSocketAddress() != null) {
                    context.put("local_address", socket.getLocalSocketAddress().toString());
                }
                if (socket.getRemoteSocketAddress() != null) {
                    context.put("remote_address", socket.getRemoteSocketAddress().toString());
                }
            }
        } catch (Exception ex) {
            context.put("socket_info_error", ex.getMessage());
        }
        
        ExceptionHandler.ErrorSeverity severity = ExceptionHandler.classifyException(e);
        context.put("error_severity", severity.toString());
        
        // Log based on severity
        switch (severity) {
            case FATAL:
                logger.error("Fatal socket error: {}", context, e);
                break;
            case PERMANENT:
                logger.warn("Permanent socket error: {}", context, e);
                break;
            case TRANSIENT:
                logger.info("Transient socket error: {}", context);
                break;
            case RECOVERABLE:
                logger.debug("Recoverable socket error: {}", context);
                break;
        }
    }
}

Install with Tessl CLI

npx tessl i tessl/maven-com-kohlschutter-junixsocket--junixsocket-core

docs

addressing.md

capabilities.md

datagram-sockets.md

exceptions.md

file-descriptors.md

index.md

nio-channels.md

rmi.md

socket-pairs.md

unix-sockets.md

utilities.md

tile.json