Guillaume Nodet wrote:
I've just spotted that the acceptor is not correctly disposed.
I've managed to get the test running succesfully by adding the
following code just after server.suspend()

        for (Listener listener :
server.getServerContext().getListeners().values()) {
            if (listener instanceof NioListener) {
                Field field = listener.getClass().getDeclaredField("acceptor");
                field.setAccessible(true);
                NioSocketAcceptor acceptor = (NioSocketAcceptor)
field.get(listener);
                Method method =
AbstractPollingIoAcceptor.class.getDeclaredMethod("dispose0");
                method.setAccessible(true);
                method.invoke(acceptor);
            }
        }

Which is about callling the dispose0() method of the NioSocketAcceptor.
This method looks like:

    protected IoFuture dispose0() throws Exception {
        unbind();
        if (!disposalFuture.isDone()) {
            startupAcceptor();
            wakeup();
        }
        return disposalFuture;
    }

So I guess what we're missing is a call to:
            startupAcceptor();
            wakeup();
somewhere.
I'm not too familiar with mina internals, so I'm not sure where this
methods should be called or if it makes any sense to call those after
an unbind.
The problem is that when you do an acceptor.unbind(), here is what MINA does :

acceptor.unbind() -->
 unbind(getLocalAddresses()) -->
   unbind0(localAddressesCopy) with

protected final void unbind0(List<? extends SocketAddress> localAddresses)
           throws Exception {
       AcceptorOperationFuture future = new AcceptorOperationFuture(
               localAddresses);

       cancelQueue.add(future);
       startupAcceptor();
       wakeup();
       ...

There is obviously something wrong somewhere, if you consider the following test :
org.apache.mina.transport.AbstractBindTest

   public void testUnbindDisconnectsClients() throws Exception {
       bind(true);
       IoConnector connector = newConnector();
       IoSession[] sessions = new IoSession[5];
       connector.setHandler(new IoHandlerAdapter());

       // Create 5 sessions, and write when established
       for (int i = 0; i < sessions.length; i++) {
ConnectFuture future = connector.connect(createSocketAddress(port));
           future.awaitUninterruptibly();
           sessions[i] = future.getSession();
           Assert.assertTrue(sessions[i].isConnected());
Assert.assertTrue(sessions[i].write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());
       }

       // Wait for the server side sessions to be created.
       Thread.sleep(500);

Collection<IoSession> managedSessions = acceptor.getManagedSessions().values();
       Assert.assertEquals(5, managedSessions.size());

       // Now unbind
       acceptor.unbind();

       // Wait for the accessor to unbind
       Thread.sleep(500);

       // The session must have been closed
       Assert.assertEquals(0, managedSessions.size());
       for (IoSession element : managedSessions) {
           Assert.assertFalse(element.isConnected());
       }

       // And now, try to create a session on a unbound acceptor !!!
       ConnectFuture future = connector.connect(createSocketAddress(port));
       future.awaitUninterruptibly();
       IoSession session = future.getSession();
       Assert.assertTrue(session.isConnected());
Assert.assertTrue(session.write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten());

       // Wait for the server side sessions to be created.
       Thread.sleep(500);

       managedSessions = acceptor.getManagedSessions().values();
       Assert.assertEquals(1, managedSessions.size());
   }


On Linux, this tests passes, all lights green !

--
--
cordialement, regards,
Emmanuel Lécharny
www.iktek.com
directory.apache.org


Reply via email to