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