United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-4801882 : (so) ServerSocketChannel.socket().accept() throws NPE if channel is non-blocking

Details
Type:
Bug
Submit Date:
2003-01-10
Status:
Resolved
Updated Date:
2003-04-10
Project Name:
JDK
Resolved Date:
2003-04-10
Component:
core-libs
OS:
linux,generic
Sub-Component:
java.nio
CPU:
x86,generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
1.4.0,1.4.1
Fixed Versions:
5.0 (tiger)

Related Reports
Relates:

Sub Tasks

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



Hardware and Software, Engineered to Work Together