JDK-4801882 : (so) ServerSocketChannel.socket().accept() throws NPE if channel is non-blocking
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.nio
  • Affected Version: 1.4.0,1.4.1
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic,linux
  • CPU: generic,x86
  • Submitted: 2003-01-10
  • Updated: 2003-04-10
  • Resolved: 2003-04-10
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availabitlity Release.

To download the current JDK release, click here.
Other
5.0 tigerFixed
Related Reports
Relates :  
Description

Name: nt126004			Date: 01/10/2003


FULL PRODUCT VERSION :
java version "1.4.1_01"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.1_01-b01)
Java HotSpot (TM) Client VM, (build 1.4.1_01-b01, mixed mode)


FULL OPERATING SYSTEM VERSION :
Mandrake Linux 8.1
Kernel 2.4.18-6mdk

(May exist on other Linux OSs and Windows, too)


A DESCRIPTION OF THE PROBLEM :
When calling accept() on a ServerSocket object obtained a
ServerSocketChannel object that's configured as non-
blocking, and there is no incoming connection at the time
when accept() is called, then a NullPointer will be thrown
from the underlying sun.nio.ch.ServerSocketAdaptor.accept()
method, whereas according to the javadoc, an
IllegalBlockingModeException should have been thrown
instead.

What makes it even more confusing is, the java doc on
ServerSocket.accept() seems to suggest that if the socket
has an associated channel and the channel is in non-
blocking mode, then calling ServerSocket.accept() should
always throw IllegalBlockingModeException. But the fact is,
if at the time accept() is called, there is a new client
connection, then accept() will return the new socket
connection, instead of throwing the exception. This
behavior makes the result of accept() when there is
existing connection vs. there is not "asymmetric".

If it is absolutely forbidden to call the ServerSocket's
accept() method when the socket has a channel in
nonblocking mode, then IllegalBlockingModeException should
be thrown regardless of whether there is a connection or
not.
If ServerSocket.accept() will return the new connection
instead of throwing the exception, then maybe it should
return null if there's no new connection, instead of
throwing the exception.


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Here's a code snippet that uses non-blocking
serversocket and uses polling to detect new client
connection to port 5555 on server, which will expose the
problem:
---------code starts-----
// create a non-blocking server socket on 5555
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocket ss = ssc.socket();
InetSocketAddress isa = new InetSocketAddress(5555);
ss.bind(5555);

// loop and detect incoming using polling
while (true) {
  Socket newSocket = ss.accept(); // null pointer problem
  if (newSocket != null) {
    System.out.println("Connection from " + newSocket);
  }
  try {
    Thread.sleep(100);
  } catch (InterruptedException e) {}
}
------code ends-----

2. Here's the code that shows the behavior of ss.accept()
when there is a connection

// create a non-blocking server socket on 5555, same as 1
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ServerSocket ss = ssc.socket();
InetSocketAddress isa = new InetSocketAddress(5555);
ss.bind(5555);

// use a selector to guarantee an existing conn when accept
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);

// loop and monitor
while (true) {
  int numKeys = selector.select();
  if (numKeys > 0) {
    Set skeys = selector.selectedKeys();
    Iterator it = skeys.iterator();
    while (it.hasNext()) {
      SelectionKey rsk = (SelectionKey)it.next();
      if (rsk.isAcceptable()) {
        Socket newSocket = ss.accept();// no prob here
        System.out.println("Connection from "+newSocket);
      }
      selector.selectedKeys().remove(rsk);
    }
  }
}

EXPECTED VERSUS ACTUAL BEHAVIOR :
The only difference between the 2
   Socket newSocket = ss.accept();
in 1) vs. 2) is in 1) there may not be a new client conn
when it's called, but in 2) there's guaranteed to be one.
So, although 2) uses Selector, it really just demonstrates
the behavior of a nonblocking ServerSocket.accept() when a
new conn is available.

The expected behavior for a nonblocking ServerSocket.accept
() is to return the new socket connection if there is one,
or null if not. Not to throw nullpointer.
Or, if ServerSocket.accept() cannot be used when it has an
associated channel in non-blocking mode, then throw
IllegalBlockingModeException for both cases.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
java.lang.NullPointerException
  at sun.nio.ch.ServerSocketAdaptor.accept(ServerSocketAdaptor.java:86)
... (user code where ServerSocket.accept() is called)

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
see Description
---------- END SOURCE ----------

CUSTOMER WORKAROUND :
When polling, use ServerSocketChannel's accept() instead.
(Review ID: 179482) 
======================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: tiger FIXED IN: tiger INTEGRATED IN: tiger tiger-b05
2004-06-14

EVALUATION An IllegalBlockingModeException should always be thrown in this case. -- ###@###.### 2003/1/10
176-11-01 0