From 8125664b9b0d58e5c6598cbf382da3a096059b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Kohlschu=CC=88tter?= Date: Mon, 8 Jul 2024 15:22:55 +0200 Subject: [PATCH] Fix not connected/bound error handling for Channels On Linux, we may need to cast InvalidArgumentSocketException to NotYetBoundException/NotYetConnectedException. --- .../net/unix/AFSomeSocketChannel.java | 5 ++-- .../net/unix/InterruptibleChannelUtil.java | 28 +++++++++++++------ .../net/unix/jep380/SocketChannelTest.java | 1 - 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSomeSocketChannel.java b/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSomeSocketChannel.java index d73982b8a..d6dc9cf12 100644 --- a/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSomeSocketChannel.java +++ b/junixsocket-common/src/main/java/org/newsclub/net/unix/AFSomeSocketChannel.java @@ -17,9 +17,9 @@ */ package org.newsclub.net.unix; -import java.io.Closeable; import java.io.IOException; import java.nio.channels.DatagramChannel; +import java.nio.channels.InterruptibleChannel; import java.nio.channels.SelectableChannel; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; @@ -33,7 +33,8 @@ * @see AFServerSocketChannel * @see AFDatagramChannel */ -public interface AFSomeSocketChannel extends Closeable, FileDescriptorAccess, AFSomeSocketThing { +public interface AFSomeSocketChannel extends InterruptibleChannel, FileDescriptorAccess, + AFSomeSocketThing { /** * Checks if the channel is configured blocking. The result may be cached, and therefore not * invoke native code to check if the underlying socket is actually configured that way. diff --git a/junixsocket-common/src/main/java/org/newsclub/net/unix/InterruptibleChannelUtil.java b/junixsocket-common/src/main/java/org/newsclub/net/unix/InterruptibleChannelUtil.java index f04c44bde..aea10314f 100644 --- a/junixsocket-common/src/main/java/org/newsclub/net/unix/InterruptibleChannelUtil.java +++ b/junixsocket-common/src/main/java/org/newsclub/net/unix/InterruptibleChannelUtil.java @@ -24,8 +24,7 @@ import java.nio.channels.NotYetBoundException; import java.nio.channels.NotYetConnectedException; import java.nio.channels.spi.AbstractInterruptibleChannel; - -import org.eclipse.jdt.annotation.NonNull; +import java.util.Objects; /** * Helper methods when working with {@link AbstractInterruptibleChannel} subclasses. @@ -53,8 +52,8 @@ interface EndMethod { * @param exception An optional exception that was caught in the try-catch-finally block. * @throws AsynchronousCloseException on error. */ - static void endInterruptable(AbstractInterruptibleChannel channel, EndMethod end, - boolean complete, Exception exception) throws AsynchronousCloseException { + static void endInterruptable(AFSomeSocketChannel channel, EndMethod end, boolean complete, + Exception exception) throws AsynchronousCloseException { if (!complete) { if (exception instanceof ClosedChannelException) { // we already have caught a valid exception; we don't need to throw one from within "end" @@ -68,8 +67,8 @@ static void endInterruptable(AbstractInterruptibleChannel channel, EndMethod end } } - private static T closeAndThrow(AbstractInterruptibleChannel channel, - @NonNull T exc) { + private static T closeAndThrow(AFSomeSocketChannel channel, T exc) { + Objects.requireNonNull(exc); if (channel.isOpen()) { try { channel.close(); @@ -99,14 +98,27 @@ static IOException ioExceptionOrThrowRuntimeException(Exception exception) { * @param e The exception * @return The exception. */ - @SuppressWarnings("null") - static Exception handleException(AbstractInterruptibleChannel channel, IOException e) { + @SuppressWarnings("PMD.CognitiveComplexity") + static Exception handleException(AFSomeSocketChannel channel, IOException e) { if (e instanceof NotConnectedSocketException) { return (NotYetConnectedException) new NotYetConnectedException().initCause(e); } else if (e instanceof NotBoundSocketException) { return (NotYetBoundException) new NotYetBoundException().initCause(e); } + if (e instanceof InvalidArgumentSocketException) { + if (channel instanceof AFServerSocketChannel) { + AFServerSocketChannel sc = (AFServerSocketChannel) channel; + if (!sc.socket().isBound()) { + return (NotYetBoundException) new NotYetBoundException().initCause(e); + } + } else if (channel instanceof AFSocketChannel) { + if (!((AFSocketChannel) channel).socket().isConnected()) { + return (NotYetConnectedException) new NotYetConnectedException().initCause(e); + } + } + } + if (e instanceof SocketClosedException || e instanceof ClosedChannelException || e instanceof BrokenPipeSocketException) { Thread t = Thread.currentThread(); diff --git a/junixsocket-common/src/test/java/org/newsclub/net/unix/jep380/SocketChannelTest.java b/junixsocket-common/src/test/java/org/newsclub/net/unix/jep380/SocketChannelTest.java index c8a3f7b51..a082353a5 100644 --- a/junixsocket-common/src/test/java/org/newsclub/net/unix/jep380/SocketChannelTest.java +++ b/junixsocket-common/src/test/java/org/newsclub/net/unix/jep380/SocketChannelTest.java @@ -62,5 +62,4 @@ protected void cleanupTestBindNull(ServerSocketChannel sc, SocketAddress addr) Path p = Paths.get(addr.toString()); Files.delete(p); } - }