This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Patch: RFT/RFC PR libgcj/15430 (read keeps blocking after socketclosed).
- From: David Daney <ddaney at avtrex dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: Wed, 09 Nov 2005 11:20:07 -0800
- Subject: Patch: RFT/RFC PR libgcj/15430 (read keeps blocking after socketclosed).
As I suggested in the PR I added a call to shutdown in the socket close
code.
I am currently running the testsuite, but I don't think there is a test
case for this PR so someone should verify that this actually does
something. But it successfully compiles so why wouldn't it work?
David Daney.
2005-11-09 David Daney <ddaney@avtrex.com>
PR libgcj/15430
* gnu/java/net/natPlainSocketImplPosix.cc (close): Call shutdown before
closing.
(read()): Call read_helper with proper parameters.
(read(buffer, int, int)): Likewise.
(read_helper): Pass pointer to the PlainSocketImpl, remove native_fd
and timeout parameters. Make prototype to match. Use
pointer to PlainSocketImpl to access members. Handle case where socket
was closed.
Index: gnu/java/net/natPlainSocketImplPosix.cc
===================================================================
--- gnu/java/net/natPlainSocketImplPosix.cc (revision 106701)
+++ gnu/java/net/natPlainSocketImplPosix.cc (working copy)
@@ -294,7 +294,11 @@
// Avoid races from asynchronous finalization.
JvSynchronize sync (this);
- // should we use shutdown here? how would that effect so_linger?
+ // Should we use shutdown here? Yes.
+ // How would that effect so_linger? Uncertain.
+ ::shutdown (native_fd, 2);
+ // Ignore errors in shutdown as we are closing and all the same
+ // errors are handled in the close.
int res = _Jv_close (native_fd);
if (res == -1)
@@ -371,7 +375,8 @@
}
static jint
-read_helper (jint native_fd, jint timeout, jbyte *bytes, jint count);
+read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
+ jbyte *bytes, jint count);
// Read a single byte from the socket.
jint
@@ -379,7 +384,7 @@
{
jbyte data;
- if (read_helper (this$0->native_fd, this$0->timeout, &data, 1) == 1)
+ if (read_helper (this$0, &data, 1) == 1)
return data & 0xFF;
return -1;
@@ -387,8 +392,9 @@
// Read count bytes into the buffer, starting at offset.
jint
-gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer, jint offset,
- jint count)
+gnu::java::net::PlainSocketImpl$SocketInputStream::read(jbyteArray buffer,
+ jint offset,
+ jint count)
{
if (! buffer)
throw new ::java::lang::NullPointerException;
@@ -398,12 +404,13 @@
if (offset < 0 || count < 0 || offset + count > bsize)
throw new ::java::lang::ArrayIndexOutOfBoundsException;
- return read_helper (this$0->native_fd, this$0->timeout,
+ return read_helper (this$0,
elements (buffer) + offset * sizeof (jbyte), count);
}
static jint
-read_helper (jint native_fd, jint timeout, jbyte *bytes, jint count)
+read_helper (gnu::java::net::PlainSocketImpl *soc_impl,
+ jbyte *bytes, jint count)
{
// If zero bytes were requested, short circuit so that recv
// doesn't signal EOF.
@@ -411,19 +418,22 @@
return 0;
// Do timeouts via select.
- if (timeout > 0 && native_fd >= 0 && native_fd < FD_SETSIZE)
+ if (soc_impl->timeout > 0
+ && soc_impl->native_fd >= 0
+ && soc_impl->native_fd < FD_SETSIZE)
{
// Create the file descriptor set.
fd_set read_fds;
FD_ZERO (&read_fds);
- FD_SET (native_fd, &read_fds);
+ FD_SET (soc_impl->native_fd, &read_fds);
// Create the timeout struct based on our internal timeout value.
struct timeval timeout_value;
- timeout_value.tv_sec = timeout / 1000;
- timeout_value.tv_usec =(timeout % 1000) * 1000;
+ timeout_value.tv_sec = soc_impl->timeout / 1000;
+ timeout_value.tv_usec =(soc_impl->timeout % 1000) * 1000;
// Select on the fds.
int sel_retval =
- _Jv_select (native_fd + 1, &read_fds, NULL, NULL, &timeout_value);
+ _Jv_select (soc_impl->native_fd + 1,
+ &read_fds, NULL, NULL, &timeout_value);
// We're only interested in the 0 return.
// error returns still require us to try to read
// the socket to see what happened.
@@ -437,10 +447,20 @@
}
// Read the socket.
- int r = ::recv (native_fd, (char *) bytes, count, 0);
+ int r = ::recv (soc_impl->native_fd, (char *) bytes, count, 0);
- if (r == 0)
- return -1;
+ if (r == 0) {
+ // Avoid races from asynchronous close().
+ JvSynchronize sync (soc_impl);
+ if (soc_impl->native_fd == -1) {
+ // Socket was closed while blocked in recv.
+ ::java::net::SocketException *se =
+ new ::java::net::SocketException (JvNewStringUTF ("Socket Closed"));
+ throw se;
+ }
+ else
+ return -1;
+ }
if (::java::lang::Thread::interrupted())
{