Problem with SelectionKey OP_CONNECT

Stanley Brown stanley.brown@zimmer.com
Thu Sep 16 21:41:00 GMT 2004


Hello,

I have noticed a difference between gcj and Sun's implementation of NIO 
socket channels.  GCJ is not setting the readyOps when a socket is 
connectable.  I wrote an example program to illustrate the problem:
-------------------------
import java.net.InetSocketAddress;
import java.nio.channels.*;
import java.util.Iterator;

public class TestConnect
{
    public TestConnect()
    {
        try
        {
            Selector selector = Selector.open();
            SocketChannel channel = SocketChannel.open();
            channel.configureBlocking(false);
            channel.connect(new InetSocketAddress("gcc.gnu.org", 80));
            channel.register(selector, SelectionKey.OP_CONNECT);
           
            while (true)
            {
                selector.select();
                Iterator it = selector.selectedKeys().iterator();
       
                while (it.hasNext())
                {
                    SelectionKey selKey = (SelectionKey)it.next();
                   
                    if (selKey.isConnectable())
                    {
                        System.out.println("Connection ready");
                        System.exit(0);
                    }
                }
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
        }
    }
   
    public static void main(String[] args)
    {
        new TestConnect();
    }
}
-------------------------

Looking at the SelectorImpl.select(long) method I noticed that there is 
a section commented out that would add OP_CONNECT if the channel is not 
connected and the fd is in the write array.  I put it back in like such:

-------------------------
                      if (key.getNativeFD() == write[i])
                      {
                        if (key.channel() instanceof SocketChannel)
                        {
                            if ( 
((SocketChannel)key.channel()).isConnected ())
                            {
                                ops = ops | SelectionKey.OP_WRITE;
                            }
                            else
                            {
                                ops = ops | SelectionKey.OP_CONNECT;
                            }
                        }
                        else
                        {
                            ops = ops | SelectionKey.OP_WRITE;
                        }
                     }
-------------------------

The problem, I believe, is that the SocketChannelImpl.isConnected() 
returns true on a non-blocking socket even if the finishConnect() has 
not been called.  So I modified it:

68d67
<   private boolean connected;
150,152d148
<            
<             connected = true;
<            
195d190
<         connected = true;
203d197
<         connected = true;
212,214c206
<     if (connected)
<         connected = socket.isConnected();
<     return connected;
---
 >     return socket.isConnected();

What I basically did was add a "connected" boolean flag.  connect() for 
blocking sockets can set this flag to true.  Non-blocking sockets can 
only toggle this by calling finishConnect().  isConnected() will only 
check the status of the actual socket if the flag is true, otherwise 
always return false.

Does anyone see a problem with this?  It seems to work fine.

I am using Mohan's gcc (GCC) 3.5.0 20040629 (experimental) on Windows XP SP1



More information about the Java mailing list