Comments (9)
An exception would indeed be appropriate here. Can you put together an example test case that shows the problem? I think it would be fine to use jnr-unixsocket as both the client and server for such a test.
from jnr-unixsocket.
I notice that our logic for getting the OutputStream does check for connectedness:
jnr-unixsocket/src/main/java/jnr/unixsocket/UnixSocket.java
Lines 123 to 130 in 1650e10
That doesn't help raising errors when the connection gets closed while in use, though.
from jnr-unixsocket.
So this might be part of the problem:
jnr-unixsocket/src/main/java/jnr/unixsocket/UnixSocketChannel.java
Lines 157 to 162 in 1650e10
As you see here, we do not check the associate file descriptor to see if it is still connected, and instead assume that if our internal logic says we are connected, we are connected.
Checking the file descriptor for openness or connectedness every time we read or write may be unreasonable, though, so we should also handle errors during read or write by raising an appropriate error (and if it is a closed socket, we probably should mark ourselves closed too).
It would be helpful if you can provide a complete example that shows what you expect to happen.
from jnr-unixsocket.
Thank you for your first analysis @headius. Unfortunately I cannot help you about the implementation, I'm not a Java guy 😊
I'm actually only talking about the client part, which looks like in my tests :
public class UnixClient {
public static void main(String[] args) throws IOException, InterruptedException {
String next = "Init";
BufferedReader consoleReader = new BufferedReader(new InputStreamReader(System.in));
java.io.File path = new java.io.File("/tmp/unix.sock");
UnixSocketAddress address = new UnixSocketAddress(path);
UnixSocketChannel channel = null;
try {
channel = UnixSocketChannel.open(address);
} catch (Exception e) {
System.out.println("Unix sock connection failed");
return;
}
System.out.println("connected to " + channel.getRemoteSocketAddress());
// output
OutputStream os = Channels.newOutputStream(channel);
PrintWriter w = new PrintWriter(os);
// input
InputStreamReader r = new InputStreamReader(Channels.newInputStream(channel));
BufferedReader in = new BufferedReader(r);
while (next != null) {
w.println("Test");
w.flush();
System.out.println("Write error: " + w.checkError());
String result = in.readLine();
System.out.println("read from server: " + result);
System.out.println("Continue ?");
next = consoleReader.readLine();
}
System.exit(0);
}
}
The server part can be anything. I've tested with a Python code but it can be any server listening on Unix socket and replying to messages on that socket. You can even mock a simple server with the tool Socat :
socat UNIX-LISTEN:/tmp/unix.sock -
Basically if you start the server and the client, everything is fine. Then if you shutdown the server, the client can continue to call the functions readline() and println() on the input/output stream without any exception while the underlying socket is actually closed. I would have expected to get an exception while trying to red/write on a stream where the underlying FD is actually closed.
from jnr-unixsocket.
Thank you for the example! This should be sufficient for me to reproduce the problem locally.
from jnr-unixsocket.
Findings from debugging the example client.
- Confirmed that no errors are raised and it keeps reading and writing nothing without errors.
- When blocked on read and the server is closed, the native read call returns 0. This is interpreted as EOF and returned into the Java classes as -1, the Java indicator of EOF. A -1 here would indicate an error, but apparently the server going away during a blocking read is not considered an error state. I will not dig into the read side for now.
- When attempting to write after the server has been terminated, the return value from the native write call is indeed -1 and the errno is EPIPE. This is raised as a NativeException from the Common class. The exception bubbles out until it reaches code in the JDK PrintWriter, which swallows the error and sets the "trouble" field to true. This is what you get when you call
checkError
. - The JavaDoc for PrintWriter includes this section:
Methods in this class never throw I/O exceptions, although some of its
constructors may. The client may inquire as to whether any errors have
occurred by invoking checkError().
Long story short, it seems like the jnr-unixsocket classes are actually working right, but PrintWriter apparently silences most errors that bubble out from the stream it wraps.
from jnr-unixsocket.
Actually there may be one thing we can do better here: close the channel when we get an EPIPE from read or write.
I tried to find some evidence of this in the JDK classes, like SocketChannelImpl, but the logic is rather tangled. There are checks to see if the last operation completed successfully, but they don't appear to change the open/closed status of the channel.
Regardless, I think you would still see the same behavior if we marked the channel as closed, since per doco the PrintWriter class will never raise an IO exception.
from jnr-unixsocket.
Still not sure the best way to handle this. Even the Java classes seem to trip a bit over closed pipes and sockets.
I was playing with this patch, perhaps it gets us close enough to handling this?
diff --git a/src/main/java/jnr/unixsocket/impl/Common.java b/src/main/java/jnr/unixsocket/impl/Common.java
index 9b1dd55..72e8042 100644
--- a/src/main/java/jnr/unixsocket/impl/Common.java
+++ b/src/main/java/jnr/unixsocket/impl/Common.java
@@ -20,6 +20,7 @@ package jnr.unixsocket.impl;
import java.io.IOException;
import java.nio.ByteBuffer;
+import java.nio.channels.ClosedChannelException;
import jnr.constants.platform.Errno;
import jnr.enxio.channels.Native;
@@ -115,8 +116,12 @@ final class Common {
case EWOULDBLOCK:
src.position(src.position()-r);
return 0;
- default:
- throw new NativeException(Native.getLastErrorString(), lastError);
+
+ case EPIPE:
+ throw new ClosedChannelException();
+
+ default:
+ throw new NativeException(Native.getLastErrorString(), lastError);
}
}
from jnr-unixsocket.
This did not happen in 0.39.9 due to other priorities.
from jnr-unixsocket.
Related Issues (20)
- unit test BasicFunctionalityTest stalls when run with JDK 17 in M1 Mac HOT 1
- application run failed while built with native-image HOT 1
- Allow Setting Socket Type on Creation HOT 1
- jnr-unixsocket v0.23 and above forces osgi.ee;filter:="(&(osgi.e e=JavaSE)(version=9.0))" HOT 3
- Read response from server, Unix Datagram socket HOT 1
- Implement sendmsg to pass control messages HOT 1
- After channel close, read and write calls were using recycled file descriptor HOT 2
- UnixServer example doesn't work on Mac with either nc or socat HOT 8
- java.lang.UnsatisfiedLinkError: ÕҲ »µ½ ָ¶¨µ HOT 6
- Null PollSelectionKey attachment causes IllegalStateException in jetty HOT 1
- Support for AIX v7.2 64-bit
- Found interface org.objectweb.asm.ClassVisitor, but class was expected HOT 2
- Smoke test fails sporadically on MacOS
- on ppc64le credentials are wrongly parsed/obtained HOT 3
- Solaris can't set socket options HOT 11
- UnixServerSocketChannel extending java.nio.channels.ServerSocketChannel
- Support for M1 Mac? HOT 4
- UnixClient fails sporadically on Darwin HOT 1
- Datagram support HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jnr-unixsocket.