[jboss-remoting-commits] JBoss Remoting SVN: r5772 - in remoting3/trunk/jboss-remoting/src: main/java/org/jboss/remoting3/remote and 4 other directories.

jboss-remoting-commits at lists.jboss.org jboss-remoting-commits at lists.jboss.org
Sun Feb 28 16:14:07 EST 2010


Author: david.lloyd at jboss.com
Date: 2010-02-28 16:14:06 -0500 (Sun, 28 Feb 2010)
New Revision: 5772

Added:
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractClientMessageHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractMessageHandler.java
Modified:
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemotingOptions.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientAuthenticationHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientGreetingHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientOpenListener.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/InboundRequestInputHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/OutboundRequestHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnection.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnectionHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteMessageHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteProtocol.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/SaslUtils.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerAuthenticationHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerGreetingHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerInitialAuthenticationHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerOpenListener.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/security/SimpleClientCallbackHandler.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractHandleableCloseable.java
   remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderContext.java
   remoting3/trunk/jboss-remoting/src/test/java/org/jboss/remoting3/test/RemoteTestCase.java
   remoting3/trunk/jboss-remoting/src/test/resources/remoting.properties
Log:
Make sure DIGEST-MD5 and CRAM-MD5 both work

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/EndpointImpl.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -534,10 +534,19 @@
     }
 
     public IoFuture<? extends Connection> connect(final URI destination, final OptionMap connectOptions) throws IOException {
-        return connect(destination, connectOptions, new SimpleClientCallbackHandler(connectOptions.get(RemotingOptions.AUTH_USER_NAME), connectOptions.get(RemotingOptions.AUTH_REALM), null));
+        final String uriUserInfo = destination.getUserInfo();
+        final OptionMap finalMap;
+        if (uriUserInfo != null) {
+            final OptionMap.Builder builder = OptionMap.builder().addAll(connectOptions);
+            builder.set(RemotingOptions.AUTH_USER_NAME, uriUserInfo);
+            finalMap = builder.getMap();
+        } else {
+            finalMap = connectOptions;
+        }
+        return doConnect(destination, connectOptions, new SimpleClientCallbackHandler(finalMap.get(RemotingOptions.AUTH_USER_NAME), finalMap.get(RemotingOptions.AUTH_REALM), null));
     }
 
-    public IoFuture<? extends Connection> connect(final URI destination, final OptionMap connectOptions, final CallbackHandler callbackHandler) throws IOException {
+    private IoFuture<? extends Connection> doConnect(final URI destination, final OptionMap connectOptions, final CallbackHandler callbackHandler) throws IOException {
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(CONNECT_PERM);
@@ -556,10 +565,28 @@
         return futureResult.getIoFuture();
     }
 
+    public IoFuture<? extends Connection> connect(final URI destination, final OptionMap connectOptions, final CallbackHandler callbackHandler) throws IOException {
+        final String uriUserInfo = destination.getUserInfo();
+        final OptionMap finalMap;
+        if (uriUserInfo != null) {
+            final OptionMap.Builder builder = OptionMap.builder().addAll(connectOptions);
+            builder.set(RemotingOptions.AUTH_USER_NAME, uriUserInfo);
+            finalMap = builder.getMap();
+        } else {
+            finalMap = connectOptions;
+        }
+        return doConnect(destination, finalMap, callbackHandler);
+    }
+
     public IoFuture<? extends Connection> connect(final URI destination, final OptionMap connectOptions, final String userName, final String realmName, final char[] password) throws IOException {
-        final String actualUserName = userName != null ? userName : connectOptions.get(RemotingOptions.AUTH_USER_NAME);
+        final String uriUserInfo = destination.getUserInfo();
+        final String actualUserName = userName != null ? userName : uriUserInfo != null ? uriUserInfo : connectOptions.get(RemotingOptions.AUTH_USER_NAME);
         final String actualUserRealm = realmName != null ? realmName : connectOptions.get(RemotingOptions.AUTH_REALM);
-        return connect(destination, connectOptions, new SimpleClientCallbackHandler(actualUserName, actualUserRealm, password));
+        final OptionMap.Builder builder = OptionMap.builder().addAll(connectOptions);
+        if (actualUserName != null) builder.set(RemotingOptions.AUTH_USER_NAME, actualUserName);
+        if (actualUserRealm != null) builder.set(RemotingOptions.AUTH_REALM, actualUserRealm);
+        final OptionMap finalMap = builder.getMap();
+        return doConnect(destination, finalMap, new SimpleClientCallbackHandler(actualUserName, actualUserRealm, password));
     }
 
     public ConnectionProviderRegistration addConnectionProvider(final String uriScheme, final ConnectionProviderFactory providerFactory) {
@@ -695,6 +722,10 @@
         public <T> T getProtocolServiceProvider(final ProtocolServiceType<T> serviceType, final String name) {
             return getMapFor(serviceType).get(name);
         }
+
+        public String getEndpointName() {
+            return getName();
+        }
     }
 
     private class ConnectionProviderRegistrationImpl extends AbstractHandleableCloseable<Registration> implements ConnectionProviderRegistration {

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemotingOptions.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemotingOptions.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/RemotingOptions.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -143,9 +143,4 @@
      * Specify the name of a preregistered server authentication provider to use.
      */
     public static final Option<String> AUTHENTICATION_PROVIDER = Option.simple(RemotingOptions.class, "AUTHENTICATION_PROVIDER", String.class);
-
-    /**
-     * Specify a set of SASL server mechanisms to allow.  If not specified, no mechanisms will be excluded.
-     */
-    public static final Option<Sequence<String>> SASL_SERVER_MECHANISMS = Option.sequence(RemotingOptions.class, "SASL_SERVER_MECHANISMS", String.class);
 }

Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractClientMessageHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractClientMessageHandler.java	                        (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractClientMessageHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -0,0 +1,41 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3.remote;
+
+import java.io.IOException;
+import org.jboss.remoting3.spi.ConnectionHandlerFactory;
+import org.jboss.xnio.Result;
+
+abstract class AbstractClientMessageHandler extends AbstractMessageHandler {
+    private final Result<ConnectionHandlerFactory> result;
+
+    protected AbstractClientMessageHandler(final RemoteConnection remoteConnection, final Result<ConnectionHandlerFactory> result) {
+        super(remoteConnection);
+        this.result = result;
+    }
+
+    public void handleException(final IOException e) {
+        result.setException(e);
+        super.handleException(e);
+    }
+}

Added: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractMessageHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractMessageHandler.java	                        (rev 0)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/AbstractMessageHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -0,0 +1,50 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2010, JBoss Inc., and individual contributors as indicated
+ * by the @authors tag. See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.remoting3.remote;
+
+import java.io.IOException;
+import org.jboss.xnio.IoUtils;
+import org.jboss.xnio.channels.MessageHandler;
+
+abstract class AbstractMessageHandler implements MessageHandler {
+    protected final RemoteConnection remoteConnection;
+
+    protected AbstractMessageHandler(final RemoteConnection remoteConnection) {
+        this.remoteConnection = remoteConnection;
+    }
+
+    public void handleEof() {
+        try {
+            remoteConnection.getChannel().shutdownReads();
+        } catch (IOException e) {
+            RemoteConnectionHandler.log.trace(e, "Failed to shut down reads for %s", remoteConnection);
+        }
+        remoteConnection.readDone();
+        IoUtils.safeClose(remoteConnection);
+    }
+
+    public void handleException(final IOException e) {
+        RemoteConnectionHandler.log.trace(e, "Received exception from %s", remoteConnection);
+        IoUtils.safeClose(remoteConnection);
+    }
+}

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientAuthenticationHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientAuthenticationHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientAuthenticationHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -22,7 +22,6 @@
 
 package org.jboss.remoting3.remote;
 
-import java.io.EOFException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import org.jboss.marshalling.MarshallerFactory;
@@ -35,18 +34,18 @@
 import org.jboss.xnio.Buffers;
 import org.jboss.xnio.IoUtils;
 import org.jboss.xnio.Result;
-import org.jboss.xnio.channels.MessageHandler;
 
 import javax.security.sasl.SaslClient;
 import javax.security.sasl.SaslException;
 
-final class ClientAuthenticationHandler implements MessageHandler {
+final class ClientAuthenticationHandler extends AbstractClientMessageHandler {
 
     private final RemoteConnection remoteConnection;
     private final SaslClient saslClient;
     private final Result<ConnectionHandlerFactory> factoryResult;
 
-    public ClientAuthenticationHandler(final RemoteConnection remoteConnection, final SaslClient saslClient, final Result<ConnectionHandlerFactory> factoryResult) {
+    ClientAuthenticationHandler(final RemoteConnection remoteConnection, final SaslClient saslClient, final Result<ConnectionHandlerFactory> factoryResult) {
+        super(remoteConnection, factoryResult);
         this.remoteConnection = remoteConnection;
         this.saslClient = saslClient;
         this.factoryResult = factoryResult;
@@ -55,54 +54,92 @@
     public void handleMessage(final ByteBuffer buffer) {
         final byte msgType = buffer.get();
         switch (msgType) {
-            case RemoteProtocol.AUTH_CHALLENGE:
-            case RemoteProtocol.AUTH_COMPLETE: {
+            case RemoteProtocol.AUTH_CHALLENGE: {
+                RemoteConnectionHandler.log.trace("Received challenge message");
+                final boolean clientComplete = saslClient.isComplete();
+                if (clientComplete) {
+                    RemoteConnectionHandler.log.trace("Received extra auth challenge message on %s after completion", remoteConnection);
+                    factoryResult.setException(new SaslException("Received extra auth message after completion"));
+                    IoUtils.safeClose(remoteConnection);
+                    return;
+                }
                 final byte[] response;
+                final byte[] challenge = Buffers.take(buffer, buffer.remaining());
                 try {
-                    response = saslClient.evaluateChallenge(Buffers.take(buffer, buffer.remaining()));
+                    response = saslClient.evaluateChallenge(challenge);
+                    if (msgType == RemoteProtocol.AUTH_COMPLETE && response != null && response.length > 0) {
+                        RemoteConnectionHandler.log.trace("Received extra auth message on %s", remoteConnection);
+                        factoryResult.setException(new SaslException("Received extra auth message after completion"));
+                        IoUtils.safeClose(remoteConnection);
+                        return;
+                    }
                 } catch (SaslException e) {
-                    // todo log it
+                    RemoteConnectionHandler.log.trace(e, "Authentication error");
                     factoryResult.setException(e);
+                    try {
+                        remoteConnection.shutdownWritesBlocking();
+                    } catch (IOException e1) {
+                        RemoteConnectionHandler.log.trace(e, "Unable to shut down writes");
+                    }
+                    return;
+                }
+                try {
+                    RemoteConnectionHandler.log.trace("Sending SASL response");
+                    remoteConnection.sendAuthMessage(RemoteProtocol.AUTH_RESPONSE, response);
+                } catch (IOException e) {
+                    factoryResult.setException(e);
+                    RemoteConnectionHandler.log.trace("Failed to send auth response message on %s", remoteConnection);
                     IoUtils.safeClose(remoteConnection);
                     return;
                 }
-                if (msgType == RemoteProtocol.AUTH_COMPLETE) {
-                    if ((response != null || response.length > 0)) {
-                        // todo log extraneous message
+                return;
+            }
+            case RemoteProtocol.AUTH_COMPLETE: {
+                RemoteConnectionHandler.log.trace("Received auth complete message");
+                final boolean clientComplete = saslClient.isComplete();
+                final byte[] challenge = Buffers.take(buffer, buffer.remaining());
+                if (! clientComplete) try {
+                    final byte[] response = saslClient.evaluateChallenge(challenge);
+                    if (response != null && response.length > 0) {
+                        RemoteConnectionHandler.log.trace("Received extra auth message on %s", remoteConnection);
+                        factoryResult.setException(new SaslException("Received extra auth message after completion"));
                         IoUtils.safeClose(remoteConnection);
                         return;
                     }
-                    // auth complete.
-                    factoryResult.setResult(new ConnectionHandlerFactory() {
-                        public ConnectionHandler createInstance(final ConnectionHandlerContext connectionContext) {
-                            // this happens immediately.
-                            final MarshallerFactory marshallerFactory = Marshalling.getMarshallerFactory("river");
-                            final MarshallingConfiguration marshallingConfiguration = new MarshallingConfiguration();
-                            final RemoteConnectionHandler connectionHandler = new RemoteConnectionHandler(connectionContext, remoteConnection, marshallerFactory, marshallingConfiguration);
-                            remoteConnection.addCloseHandler(new CloseHandler<Object>() {
-                                public void handleClose(final Object closed) {
-                                    IoUtils.safeClose(connectionHandler);
-                                }
-                            });
-                            remoteConnection.setMessageHandler(new RemoteMessageHandler(connectionHandler, remoteConnection));
-                            return connectionHandler;
-                        }
-                    });
+                    if (! saslClient.isComplete()) {
+                        RemoteConnectionHandler.log.trace("Client not complete after processing auth complete message on %s", remoteConnection);
+                        factoryResult.setException(new SaslException("Client not complete after processing auth complete message"));
+                        IoUtils.safeClose(remoteConnection);
+                        return;
+                    }
+                } catch (SaslException e) {
+                    RemoteConnectionHandler.log.trace(e, "Authentication error");
+                    factoryResult.setException(e);
+                    try {
+                        remoteConnection.shutdownWritesBlocking();
+                    } catch (IOException e1) {
+                        RemoteConnectionHandler.log.trace(e, "Unable to shut down writes");
+                    }
                     return;
                 }
-                break;
+                // auth complete.
+                factoryResult.setResult(new ConnectionHandlerFactory() {
+                    public ConnectionHandler createInstance(final ConnectionHandlerContext connectionContext) {
+                        // this happens immediately.
+                        final MarshallerFactory marshallerFactory = Marshalling.getMarshallerFactory("river");
+                        final MarshallingConfiguration marshallingConfiguration = new MarshallingConfiguration();
+                        final RemoteConnectionHandler connectionHandler = new RemoteConnectionHandler(connectionContext, remoteConnection, marshallerFactory, marshallingConfiguration);
+                        remoteConnection.addCloseHandler(new CloseHandler<Object>() {
+                            public void handleClose(final Object closed) {
+                                IoUtils.safeClose(connectionHandler);
+                            }
+                        });
+                        remoteConnection.setMessageHandler(new RemoteMessageHandler(connectionHandler, remoteConnection));
+                        return connectionHandler;
+                    }
+                });
+                return;
             }
         }
     }
-
-    public void handleEof() {
-        factoryResult.setException(new EOFException("End of file on input"));
-        IoUtils.safeClose(remoteConnection);
-    }
-
-    public void handleException(final IOException e) {
-        // todo log it
-        factoryResult.setException(e);
-        IoUtils.safeClose(remoteConnection);
-    }
 }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientGreetingHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientGreetingHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientGreetingHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -22,7 +22,6 @@
 
 package org.jboss.remoting3.remote;
 
-import java.io.EOFException;
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
@@ -31,23 +30,21 @@
 import org.jboss.remoting3.RemotingOptions;
 import org.jboss.remoting3.spi.ConnectionHandlerFactory;
 import org.jboss.xnio.Buffers;
-import org.jboss.xnio.IoUtils;
-import org.jboss.xnio.Option;
 import org.jboss.xnio.OptionMap;
 import org.jboss.xnio.Result;
-import org.jboss.xnio.channels.MessageHandler;
 
 import javax.security.auth.callback.CallbackHandler;
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslClient;
 import javax.security.sasl.SaslException;
 
-final class ClientGreetingHandler implements MessageHandler {
+final class ClientGreetingHandler extends AbstractClientMessageHandler {
     private final RemoteConnection connection;
     private final Result<ConnectionHandlerFactory> factoryResult;
     private final CallbackHandler callbackHandler;
 
-    public ClientGreetingHandler(final RemoteConnection connection, final Result<ConnectionHandlerFactory> factoryResult, final CallbackHandler callbackHandler) {
+    ClientGreetingHandler(final RemoteConnection connection, final Result<ConnectionHandlerFactory> factoryResult, final CallbackHandler callbackHandler) {
+        super(connection, factoryResult);
         this.connection = connection;
         this.factoryResult = factoryResult;
         this.callbackHandler = callbackHandler;
@@ -55,6 +52,7 @@
 
     public void handleMessage(final ByteBuffer buffer) {
         List<String> saslMechs = new ArrayList<String>();
+        String remoteEndpointName = "endpoint";
         switch (buffer.get()) {
             case RemoteProtocol.GREETING: {
                 while (buffer.hasRemaining()) {
@@ -71,6 +69,10 @@
                             saslMechs.add(Buffers.getModifiedUtf8(Buffers.slice(buffer, len)));
                             break;
                         }
+                        case RemoteProtocol.GREETING_ENDPOINT_NAME: {
+                            remoteEndpointName = Buffers.getModifiedUtf8(Buffers.slice(buffer, len));
+                            break;
+                        }
                         default: {
                             // unknown, skip it for forward compatibility.
                             Buffers.skip(buffer, len);
@@ -81,37 +83,49 @@
                 // OK now send our authentication request
                 final OptionMap optionMap = connection.getOptionMap();
                 final String userName = optionMap.get(RemotingOptions.AUTH_USER_NAME);
-                final String hostName = connection.getChannel().getPeerAddress().getHostName();
                 final Map<String, ?> propertyMap = SaslUtils.createPropertyMap(optionMap);
                 final SaslClient saslClient;
                 try {
-                    saslClient = Sasl.createSaslClient(saslMechs.toArray(new String[saslMechs.size()]), userName == null ? "anonymous" : userName, "remote", hostName, propertyMap, callbackHandler);
+                    saslClient = Sasl.createSaslClient(saslMechs.toArray(new String[saslMechs.size()]), userName, "remote", remoteEndpointName, propertyMap, callbackHandler);
                 } catch (SaslException e) {
                     factoryResult.setException(e);
-                    // todo log exception @ error
-                    // todo send "goodbye" & close
-                    IoUtils.safeClose(connection);
+                    RemoteConnectionHandler.log.trace(e, "Client connect authentication error");
+                    try {
+                        remoteConnection.shutdownWritesBlocking();
+                    } catch (IOException e1) {
+                        RemoteConnectionHandler.log.trace(e1, "Failed to shutdown writes on %s", remoteConnection);
+                    }
                     return;
                 }
+                final String mechanismName = saslClient.getMechanismName();
+                RemoteConnectionHandler.log.trace("Sasl mechanism selected: %s", mechanismName);
+                final ByteBuffer outBuf = connection.allocate();
+                try {
+                    outBuf.putInt(0);
+                    outBuf.put(RemoteProtocol.AUTH_REQUEST);
+                    Buffers.putModifiedUtf8(outBuf, mechanismName);
+                    outBuf.flip();
+                    connection.sendBlocking(outBuf);
+                    connection.flushBlocking();
+                } catch (IOException e) {
+                    RemoteConnectionHandler.log.trace(e, "Failed to send auth request on %s", remoteConnection);
+                    factoryResult.setException(e);
+                    return;
+                } finally {
+                    connection.free(outBuf);
+                }
                 connection.setMessageHandler(new ClientAuthenticationHandler(connection, saslClient, factoryResult));
                 return;
             }
             default: {
-                // todo log invalid greeting
-                IoUtils.safeClose(connection);
+                RemoteConnectionHandler.log.warn("Received invalid greeting packet on %s", remoteConnection);
+                try {
+                    remoteConnection.shutdownWritesBlocking();
+                } catch (IOException e1) {
+                    RemoteConnectionHandler.log.trace(e1, "Failed to shutdown writes on %s", remoteConnection);
+                }
                 return;
             }
         }
     }
-
-    public void handleEof() {
-        factoryResult.setException(new EOFException("End of file on input"));
-        IoUtils.safeClose(connection);
-    }
-
-    public void handleException(final IOException e) {
-        // todo log it
-        factoryResult.setException(e);
-        IoUtils.safeClose(connection);
-    }
 }
\ No newline at end of file

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientOpenListener.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientOpenListener.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ClientOpenListener.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -43,7 +43,7 @@
     private final Result<ConnectionHandlerFactory> factoryResult;
     private final CallbackHandler callbackHandler;
 
-    public ClientOpenListener(final OptionMap optionMap, final ConnectionProviderContext connectionProviderContext, final Result<ConnectionHandlerFactory> factoryResult, final CallbackHandler callbackHandler) {
+    ClientOpenListener(final OptionMap optionMap, final ConnectionProviderContext connectionProviderContext, final Result<ConnectionHandlerFactory> factoryResult, final CallbackHandler callbackHandler) {
         this.optionMap = optionMap;
         this.connectionProviderContext = connectionProviderContext;
         this.factoryResult = factoryResult;
@@ -60,24 +60,39 @@
 
         // Send client greeting packet...
         final ByteBuffer buffer = connection.allocate();
-        try {
-            // length placeholder
-            buffer.putInt(0);
-            // version ID
-            GreetingUtils.writeByte(buffer, RemoteProtocol.GREETING_VERSION, RemoteProtocol.VERSION);
-            // that's it!
-            buffer.flip();
-            connection.sendBlocking(buffer);
-        } catch (IOException e1) {
-            // todo log it
-            factoryResult.setException(e1);
-            IoUtils.safeClose(connection);
-        } finally {
-            connection.free(buffer);
-        }
+        // length placeholder
+        buffer.putInt(0);
+        // version ID
+        GreetingUtils.writeByte(buffer, RemoteProtocol.GREETING_VERSION, RemoteProtocol.VERSION);
+        // that's it!
+        buffer.flip();
+        buffer.putInt(0, buffer.remaining() - 4);
+        channel.getWriteSetter().set(new ChannelListener<ConnectedStreamChannel<InetSocketAddress>>() {
+            public void handleEvent(final ConnectedStreamChannel<InetSocketAddress> channel) {
+                for (;;) {
+                    while (buffer.hasRemaining()) {
+                        final int res;
+                        try {
+                            res = channel.write(buffer);
+                        } catch (IOException e1) {
+                            IoUtils.safeClose(connection);
+                            connection.free(buffer);
+                            return;
+                        }
+                        if (res == 0) {
+                            channel.resumeWrites();
+                            return;
+                        }
+                    }
+                    connection.free(buffer);
+                    channel.resumeReads();
+                    return;
+                }
+            }
+        });
 
         connection.setMessageHandler(new ClientGreetingHandler(connection, factoryResult, callbackHandler));
-        // start up the read cycle
-        channel.resumeReads();
+        // and send the greeting
+        channel.resumeWrites();
     }
 }
\ No newline at end of file

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/InboundRequestInputHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/InboundRequestInputHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/InboundRequestInputHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -56,7 +56,7 @@
     }
 
     public void close() throws IOException {
-        // todo: stream was closed, no action needed
+        // no operation
     }
 
     public String toString() {

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/OutboundRequestHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/OutboundRequestHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/OutboundRequestHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -81,7 +81,7 @@
             try {
                 connectionHandler.getRemoteConnection().sendBlocking(buf);
             } catch (IOException e1) {
-                // todo log it
+                RemoteConnectionHandler.log.trace("Send failed: %s", e1);
             }
         }
         return outboundRequest;

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnection.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnection.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnection.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -34,17 +34,16 @@
 import org.jboss.xnio.OptionMap;
 import org.jboss.xnio.Pool;
 import org.jboss.xnio.channels.Channels;
-import org.jboss.xnio.channels.ConnectedChannel;
 import org.jboss.xnio.channels.ConnectedStreamChannel;
 import org.jboss.xnio.channels.MessageHandler;
 
-import javax.security.auth.callback.CallbackHandler;
-
 final class RemoteConnection extends AbstractHandleableCloseable<RemoteConnection> implements Closeable {
     private final ConnectedStreamChannel<InetSocketAddress> channel;
     private final Pool<ByteBuffer> bufferPool = Buffers.createHeapByteBufferAllocator(4096);
     private final MessageHandler.Setter messageHandlerSetter;
     private final OptionMap optionMap;
+    private boolean readDone;
+    private final Object writeLock = new Object();
 
     RemoteConnection(final Executor executor, final ConnectedStreamChannel<InetSocketAddress> channel, final OptionMap optionMap) {
         super(executor);
@@ -53,7 +52,28 @@
         this.optionMap = optionMap;
     }
 
-    public void close() throws IOException {
+    protected void closeAction() throws IOException {
+        synchronized (writeLock) {
+            try {
+                shutdownWritesBlocking();
+            } catch (IOException e) {
+                readDone = true;
+                writeLock.notifyAll();
+                IoUtils.safeClose(channel);
+                return;
+            }
+            while (! readDone) {
+                try {
+                    writeLock.wait();
+                } catch (InterruptedException e) {
+                    readDone = true;
+                    writeLock.notifyAll();
+                    IoUtils.safeClose(channel);
+                    Thread.currentThread().interrupt();
+                    throw new InterruptedIOException();
+                }
+            }
+        }
         channel.close();
     }
 
@@ -61,7 +81,7 @@
         return optionMap;
     }
 
-    ConnectedChannel<InetSocketAddress> getChannel() {
+    ConnectedStreamChannel<InetSocketAddress> getChannel() {
         return channel;
     }
 
@@ -93,54 +113,60 @@
     }
 
     void sendBlockingNoClose(final ByteBuffer buffer) throws IOException {
-        buffer.putInt(0, buffer.remaining() - 4);
-        boolean intr = false;
-        try {
-            while (buffer.hasRemaining()) {
-                if (channel.write(buffer) == 0) {
-                    try {
-                        channel.awaitWritable();
-                    } catch (InterruptedIOException e) {
-                        intr = Thread.interrupted();
+        synchronized (writeLock) {
+            buffer.putInt(0, buffer.remaining() - 4);
+            boolean intr = false;
+            try {
+                while (buffer.hasRemaining()) {
+                    if (channel.write(buffer) == 0) {
+                        try {
+                            channel.awaitWritable();
+                        } catch (InterruptedIOException e) {
+                            intr = Thread.interrupted();
+                        }
                     }
                 }
+            } finally {
+                if (intr) Thread.currentThread().interrupt();
             }
-        } finally {
-            if (intr) Thread.currentThread().interrupt();
         }
     }
 
     void flushBlocking() throws IOException {
-        try {
-            while (! channel.flush()) {
-                channel.awaitWritable();
+        synchronized (writeLock) {
+            try {
+                while (! channel.flush()) {
+                    channel.awaitWritable();
+                }
+            } catch (IOException e) {
+                IoUtils.safeClose(this);
+                throw e;
+            } catch (RuntimeException e) {
+                IoUtils.safeClose(this);
+                throw e;
+            } catch (Error e) {
+                IoUtils.safeClose(this);
+                throw e;
             }
-        } catch (IOException e) {
-            IoUtils.safeClose(this);
-            throw e;
-        } catch (RuntimeException e) {
-            IoUtils.safeClose(this);
-            throw e;
-        } catch (Error e) {
-            IoUtils.safeClose(this);
-            throw e;
         }
     }
 
     void shutdownWritesBlocking() throws IOException {
-        try {
-            while (! channel.shutdownWrites()) {
-                channel.awaitWritable();
+        synchronized (writeLock) {
+            try {
+                while (! channel.shutdownWrites()) {
+                    channel.awaitWritable();
+                }
+            } catch (IOException e) {
+                IoUtils.safeClose(channel);
+                throw e;
+            } catch (RuntimeException e) {
+                IoUtils.safeClose(channel);
+                throw e;
+            } catch (Error e) {
+                IoUtils.safeClose(channel);
+                throw e;
             }
-        } catch (IOException e) {
-            IoUtils.safeClose(this);
-            throw e;
-        } catch (RuntimeException e) {
-            IoUtils.safeClose(this);
-            throw e;
-        } catch (Error e) {
-            IoUtils.safeClose(this);
-            throw e;
         }
     }
 
@@ -175,4 +201,13 @@
     void shutdownReads() throws IOException {
         channel.shutdownReads();
     }
+
+    void readDone() {
+        synchronized (writeLock) {
+            readDone = true;
+            writeLock.notifyAll();
+        }
+    }
+
+
 }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnectionHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnectionHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteConnectionHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -31,6 +31,7 @@
 import org.jboss.marshalling.util.IntKeyMap;
 import org.jboss.remoting3.IndeterminateOutcomeException;
 import org.jboss.remoting3.ServiceOpenException;
+import org.jboss.remoting3.spi.AbstractHandleableCloseable;
 import org.jboss.remoting3.spi.ConnectionHandler;
 import org.jboss.remoting3.spi.ConnectionHandlerContext;
 import org.jboss.remoting3.spi.RequestHandler;
@@ -41,10 +42,9 @@
 import org.jboss.xnio.IoUtils;
 import org.jboss.xnio.Pool;
 import org.jboss.xnio.Result;
-import org.jboss.xnio.channels.Channels;
 import org.jboss.xnio.log.Logger;
 
-final class RemoteConnectionHandler implements ConnectionHandler {
+final class RemoteConnectionHandler extends AbstractHandleableCloseable<RemoteConnectionHandler> implements ConnectionHandler {
 
     static final Logger log = Logger.getLogger("org.jboss.remoting.remote");
 
@@ -67,6 +67,7 @@
     private final AtomicBoolean closed = new AtomicBoolean();
 
     public RemoteConnectionHandler(final ConnectionHandlerContext connectionContext, final RemoteConnection remoteConnection, final MarshallerFactory marshallerFactory, final MarshallingConfiguration marshallingConfiguration) {
+        super(connectionContext.getConnectionProviderContext().getExecutor());
         this.connectionContext = connectionContext;
         this.remoteConnection = remoteConnection;
         this.marshallerFactory = marshallerFactory;
@@ -107,35 +108,33 @@
         throw new UnsupportedOperationException();
     }
 
-    public void close() throws IOException {
-        if (! closed.getAndSet(true)) {
-            try {
-                remoteConnection.close();
-            } finally {
-                // other actions here
-                for (IntKeyMap.Entry<OutboundClient> entry : outboundClients) {
-                    final OutboundClient outboundClient = entry.getValue();
-                    synchronized (outboundClient) {
-                        IoUtils.safeClose(outboundClient.getRequestHandler());
-                    }
+    protected void closeAction() throws IOException {
+        try {
+            remoteConnection.close();
+        } finally {
+            // other actions here
+            for (IntKeyMap.Entry<OutboundClient> entry : outboundClients) {
+                final OutboundClient outboundClient = entry.getValue();
+                synchronized (outboundClient) {
+                    IoUtils.safeClose(outboundClient.getRequestHandler());
                 }
-                for (IntKeyMap.Entry<InboundClient> entry : inboundClients) {
-                    final InboundClient inboundClient = entry.getValue();
-                    synchronized (inboundClient) {
-                        IoUtils.safeClose(inboundClient.getHandler());
-                    }
+            }
+            for (IntKeyMap.Entry<InboundClient> entry : inboundClients) {
+                final InboundClient inboundClient = entry.getValue();
+                synchronized (inboundClient) {
+                    IoUtils.safeClose(inboundClient.getHandler());
                 }
-                for (IntKeyMap.Entry<OutboundRequest> entry : outboundRequests) {
-                    final OutboundRequest outboundRequest = entry.getValue();
-                    synchronized (outboundRequest) {
-                        SpiUtils.safeHandleException(outboundRequest.getInboundReplyHandler(), new IndeterminateOutcomeException("Connection closed"));
-                    }
+            }
+            for (IntKeyMap.Entry<OutboundRequest> entry : outboundRequests) {
+                final OutboundRequest outboundRequest = entry.getValue();
+                synchronized (outboundRequest) {
+                    SpiUtils.safeHandleException(outboundRequest.getInboundReplyHandler(), new IndeterminateOutcomeException("Connection closed"));
                 }
-                for (IntKeyMap.Entry<InboundRequest> entry : inboundRequests) {
-                    final InboundRequest inboundRequest = entry.getValue();
-                    synchronized (inboundRequest) {
-                        inboundRequest.getCancellable().cancel();
-                    }
+            }
+            for (IntKeyMap.Entry<InboundRequest> entry : inboundRequests) {
+                final InboundRequest inboundRequest = entry.getValue();
+                synchronized (inboundRequest) {
+                    inboundRequest.getCancellable().cancel();
                 }
             }
         }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteMessageHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteMessageHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteMessageHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -38,12 +38,13 @@
 import org.jboss.xnio.OptionMap;
 import org.jboss.xnio.Pool;
 
-final class RemoteMessageHandler implements org.jboss.xnio.channels.MessageHandler {
+final class RemoteMessageHandler extends AbstractMessageHandler implements org.jboss.xnio.channels.MessageHandler {
 
     private final RemoteConnection connection;
     private final RemoteConnectionHandler remoteConnectionHandler;
 
     RemoteMessageHandler(final RemoteConnectionHandler remoteConnectionHandler, final RemoteConnection connection) {
+        super(connection);
         this.remoteConnectionHandler = remoteConnectionHandler;
         this.connection = connection;
     }
@@ -309,12 +310,4 @@
             }
         }
     }
-
-    public void handleEof() {
-        IoUtils.safeClose(remoteConnectionHandler);
-    }
-
-    public void handleException(final IOException e) {
-        IoUtils.safeClose(remoteConnectionHandler);
-    }
 }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteProtocol.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteProtocol.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/RemoteProtocol.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -66,6 +66,7 @@
 
     static final byte GREETING_VERSION = 0;   // sent by client & server
     static final byte GREETING_SASL_MECH = 1; // sent by server
+    static final byte GREETING_ENDPOINT_NAME = 2; // sent by client & server
 
     /**
      * Create an instance of the connection provider for the "remote" protocol.

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/SaslUtils.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/SaslUtils.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/SaslUtils.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -68,15 +68,20 @@
     }
 
     private static void addQopList(OptionMap optionMap, Option<Sequence<SaslQop>> option, Map<String, Object> map, String propName) {
-        final Sequence<SaslQop> seq = optionMap.get(option);
+        final Sequence<SaslQop> value = optionMap.get(option);
+        if (value == null) return;
+        final Sequence<SaslQop> seq = value;
         final StringBuilder builder = new StringBuilder();
         final Iterator<SaslQop> iterator = seq.iterator();
-        while (iterator.hasNext()) {
+        if (!iterator.hasNext()) {
+            return;
+        } else do {
             builder.append(iterator.next());
             if (iterator.hasNext()) {
                 builder.append(',');
             }
-        }
+        } while (iterator.hasNext());
+        map.put(propName, builder.toString());
     }
 
     private static final Set<String> SECURE_QOP;

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerAuthenticationHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerAuthenticationHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerAuthenticationHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -34,17 +34,17 @@
 import org.jboss.remoting3.spi.ConnectionProviderContext;
 import org.jboss.xnio.Buffers;
 import org.jboss.xnio.IoUtils;
-import org.jboss.xnio.channels.MessageHandler;
 
 import javax.security.sasl.SaslException;
 import javax.security.sasl.SaslServer;
 
-final class ServerAuthenticationHandler implements MessageHandler {
+final class ServerAuthenticationHandler extends AbstractMessageHandler {
     private final RemoteConnection remoteConnection;
     private final SaslServer saslServer;
     private final ConnectionProviderContext connectionProviderContext;
 
     ServerAuthenticationHandler(final RemoteConnection remoteConnection, final SaslServer saslServer, final ConnectionProviderContext connectionProviderContext) {
+        super(remoteConnection);
         this.saslServer = saslServer;
         this.remoteConnection = remoteConnection;
         this.connectionProviderContext = connectionProviderContext;
@@ -53,17 +53,20 @@
     public void handleMessage(final ByteBuffer buffer) {
         switch (buffer.get()) {
             case RemoteProtocol.AUTH_RESPONSE: {
+                RemoteConnectionHandler.log.trace("Received SASL response");
                 final byte[] challenge;
                 try {
                     try {
                         challenge = saslServer.evaluateResponse(Buffers.take(buffer, buffer.remaining()));
                     } catch (SaslException e) {
-                        // todo log it
+                        RemoteConnectionHandler.log.trace(e, "Server authentication failed");
                         remoteConnection.sendAuthReject("Authentication failed");
+                        remoteConnection.flushBlocking();
                         return;
                     }
                     final boolean complete = saslServer.isComplete();
                     if (complete) {
+                        RemoteConnectionHandler.log.trace("Sending SASL complete");
                         remoteConnection.sendAuthMessage(RemoteProtocol.AUTH_COMPLETE, challenge);
                         connectionProviderContext.accept(new ConnectionHandlerFactory() {
                             public ConnectionHandler createInstance(final ConnectionHandlerContext connectionContext) {
@@ -80,15 +83,17 @@
                             }
                         });
                     } else {
+                        RemoteConnectionHandler.log.trace("Sending subsequent SASL challenge");
                         remoteConnection.sendAuthMessage(RemoteProtocol.AUTH_CHALLENGE, challenge);
                     }
                 } catch (IOException e) {
-                    // todo log it; close channel
+                    RemoteConnectionHandler.log.trace(e, "Failed to send auth message");
                     IoUtils.safeClose(remoteConnection);
                 }
+                break;
             }
             default: {
-                // todo log invalid msg
+                RemoteConnectionHandler.log.warn("Server received invalid message on %s", remoteConnection);
                 IoUtils.safeClose(remoteConnection);
             }
         }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerGreetingHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerGreetingHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerGreetingHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -30,16 +30,16 @@
 import org.jboss.remoting3.spi.ConnectionProviderContext;
 import org.jboss.xnio.Buffers;
 import org.jboss.xnio.IoUtils;
-import org.jboss.xnio.channels.MessageHandler;
 
-final class ServerGreetingHandler implements MessageHandler {
+final class ServerGreetingHandler extends AbstractMessageHandler {
     private final RemoteConnection connection;
     private final ConnectionProviderContext connectionProviderContext;
     private final Set<String> saslMechs;
     private final ServerAuthenticationProvider provider;
     private final Map<String, Object> propertyMap;
 
-    public ServerGreetingHandler(final RemoteConnection connection, final ConnectionProviderContext connectionProviderContext, final Set<String> saslMechs, final ServerAuthenticationProvider provider, final Map<String, Object> propertyMap) {
+    ServerGreetingHandler(final RemoteConnection connection, final ConnectionProviderContext connectionProviderContext, final Set<String> saslMechs, final ServerAuthenticationProvider provider, final Map<String, Object> propertyMap) {
+        super(connection);
         this.connection = connection;
         this.connectionProviderContext = connectionProviderContext;
         this.saslMechs = saslMechs;
@@ -71,18 +71,9 @@
                 return;
             }
             default: {
-                // todo log invalid greeting
+                RemoteConnectionHandler.log.warn("Server received invalid greeting message");
                 IoUtils.safeClose(connection);
             }
         }
     }
-
-    public void handleEof() {
-        IoUtils.safeClose(connection);
-    }
-
-    public void handleException(final IOException e) {
-        // todo log it
-        IoUtils.safeClose(connection);
-    }
 }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerInitialAuthenticationHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerInitialAuthenticationHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerInitialAuthenticationHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -26,26 +26,27 @@
 import java.nio.ByteBuffer;
 import java.util.Map;
 import java.util.Set;
+import org.jboss.remoting3.RemotingOptions;
 import org.jboss.remoting3.security.ServerAuthenticationProvider;
 import org.jboss.remoting3.spi.ConnectionProviderContext;
 import org.jboss.xnio.Buffers;
 import org.jboss.xnio.IoUtils;
-import org.jboss.xnio.channels.MessageHandler;
 
 import javax.security.sasl.Sasl;
 import javax.security.sasl.SaslServer;
 
-final class ServerInitialAuthenticationHandler implements MessageHandler {
+final class ServerInitialAuthenticationHandler extends AbstractMessageHandler {
     private final RemoteConnection remoteConnection;
     private final Map<String, ?> saslPropertyMap;
-    private final Set<String> allowedMechsMap;
+    private final Set<String> allowedMechs;
     private final ServerAuthenticationProvider authenticationProvider;
     private final ConnectionProviderContext connectionProviderContext;
 
-    ServerInitialAuthenticationHandler(final RemoteConnection remoteConnection, final Map<String, ?> saslPropertyMap, final Set<String> allowedMechsMap, final ServerAuthenticationProvider authenticationProvider, final ConnectionProviderContext connectionProviderContext) {
+    ServerInitialAuthenticationHandler(final RemoteConnection remoteConnection, final Map<String, ?> saslPropertyMap, final Set<String> allowedMechs, final ServerAuthenticationProvider authenticationProvider, final ConnectionProviderContext connectionProviderContext) {
+        super(remoteConnection);
         this.remoteConnection = remoteConnection;
         this.saslPropertyMap = saslPropertyMap;
-        this.allowedMechsMap = allowedMechsMap;
+        this.allowedMechs = allowedMechs;
         this.authenticationProvider = authenticationProvider;
         this.connectionProviderContext = connectionProviderContext;
     }
@@ -56,37 +57,29 @@
                 try {
                     // mech name
                     final String name = Buffers.getModifiedUtf8(buffer);
-                    if (allowedMechsMap.contains(name)) {
-                        final SaslServer server = Sasl.createSaslServer(name, "remote", remoteConnection.getChannel().getLocalAddress().getHostName(), saslPropertyMap, authenticationProvider.getCallbackHandler());
+                    if (allowedMechs.contains(name)) {
+                        RemoteConnectionHandler.log.trace("Selected SASL mechanism %s", name);
+                        final String realm = connectionProviderContext.getEndpointName();
+                        final SaslServer server = Sasl.createSaslServer(name, "remote", realm, saslPropertyMap, authenticationProvider.getCallbackHandler());
                         remoteConnection.setMessageHandler(new ServerAuthenticationHandler(remoteConnection, server, connectionProviderContext));
-                        remoteConnection.sendAuthMessage(RemoteProtocol.AUTH_CHALLENGE, SaslUtils.EMPTY);
+                        RemoteConnectionHandler.log.trace("Sending initial challenge");
+                        remoteConnection.sendAuthMessage(RemoteProtocol.AUTH_CHALLENGE, server.evaluateResponse(SaslUtils.EMPTY));
                         return;
                     } else {
+                        RemoteConnectionHandler.log.trace("Rejected invalid SASL mechanism %s", name);
                         remoteConnection.sendAuthReject("Invalid mechanism name");
                         return;
                     }
                 } catch (IOException e) {
                     IoUtils.safeClose(remoteConnection);
-                    // todo log it
+                    RemoteConnectionHandler.log.trace("Failed to send auth message: %s", e);
                     return;
                 }
             }
             default: {
-                // todo log invalid msg
+                RemoteConnectionHandler.log.warn("Server received invalid auth request message");
                 IoUtils.safeClose(remoteConnection);
             }
         }
     }
-
-    public void handleEof() {
-        try {
-            remoteConnection.shutdownReads();
-        } catch (IOException e) {
-            // todo log it
-        }
-    }
-
-    public void handleException(final IOException e) {
-        // todo log it
-    }
 }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerOpenListener.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerOpenListener.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/remote/ServerOpenListener.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -63,7 +63,7 @@
         final RemoteConnection connection = new RemoteConnection(connectionProviderContext.getExecutor(), channel, optionMap);
 
         // Calculate available server mechanisms
-        final Sequence<String> mechs = optionMap.get(RemotingOptions.SASL_SERVER_MECHANISMS);
+        final Sequence<String> mechs = optionMap.get(Options.SASL_MECHANISMS);
         final Set<String> includes = mechs != null ? new HashSet<String>(mechs) : null;
         final Set<String> serverMechanisms = new LinkedHashSet<String>();
         final Map<String, Object> propertyMap = SaslUtils.createPropertyMap(optionMap);
@@ -79,24 +79,42 @@
 
         // Send server greeting packet...
         final ByteBuffer buffer = connection.allocate();
-        try {
-            // length placeholder
-            buffer.putInt(0);
-            // version ID
-            GreetingUtils.writeByte(buffer, RemoteProtocol.GREETING_VERSION, RemoteProtocol.VERSION);
-            // SASL server mechs
-            for (String name : serverMechanisms) {
-                GreetingUtils.writeString(buffer, RemoteProtocol.GREETING_SASL_MECH, name);
+        // length placeholder
+        buffer.putInt(0);
+        // version ID
+        GreetingUtils.writeByte(buffer, RemoteProtocol.GREETING_VERSION, RemoteProtocol.VERSION);
+        // SASL server mechs
+        for (String name : serverMechanisms) {
+            GreetingUtils.writeString(buffer, RemoteProtocol.GREETING_SASL_MECH, name);
+            RemoteConnectionHandler.log.trace("Offering SASL mechanism %s", name);
+        }
+        GreetingUtils.writeString(buffer, RemoteProtocol.GREETING_ENDPOINT_NAME, connectionProviderContext.getEndpointName());
+        // that's it!
+        buffer.flip();
+        buffer.putInt(0, buffer.remaining() - 4);
+        channel.getWriteSetter().set(new ChannelListener<ConnectedStreamChannel<InetSocketAddress>>() {
+            public void handleEvent(final ConnectedStreamChannel<InetSocketAddress> channel) {
+                for (;;) {
+                    while (buffer.hasRemaining()) {
+                        final int res;
+                        try {
+                            res = channel.write(buffer);
+                        } catch (IOException e1) {
+                            IoUtils.safeClose(connection);
+                            connection.free(buffer);
+                            return;
+                        }
+                        if (res == 0) {
+                            channel.resumeWrites();
+                            return;
+                        }
+                    }
+                    connection.free(buffer);
+                    channel.resumeReads();
+                    return;
+                }
             }
-            // that's it!
-            buffer.flip();
-            connection.sendBlocking(buffer);
-        } catch (Exception e1) {
-            // todo log it
-            IoUtils.safeClose(connection);
-        } finally {
-            connection.free(buffer);
-        }
+        });
         final String authProvider = optionMap.get(RemotingOptions.AUTHENTICATION_PROVIDER);
         if (authProvider == null) {
             // todo log no valid auth provider
@@ -108,7 +126,7 @@
             IoUtils.safeClose(connection);
         }
         connection.setMessageHandler(new ServerGreetingHandler(connection, connectionProviderContext, serverMechanisms, provider, propertyMap));
-        // start up the read cycle
-        channel.resumeReads();
+        // and send the greeting
+        channel.resumeWrites();
     }
 }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/security/SimpleClientCallbackHandler.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/security/SimpleClientCallbackHandler.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/security/SimpleClientCallbackHandler.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -71,12 +71,28 @@
      */
     public void handle(final Callback[] callbacks) throws UnsupportedCallbackException {
         MAIN: for (Callback callback : callbacks) {
-            if (callback instanceof NameCallback && actualUserName != null) {
+            if (callback instanceof NameCallback) {
                 final NameCallback nameCallback = (NameCallback) callback;
-                nameCallback.setName(actualUserName);
-            } else if (callback instanceof RealmCallback && actualUserRealm != null) {
+                final String defaultName = nameCallback.getDefaultName();
+                log.trace("User name requested; prompt '%s', default is '%s', ours is '%s'", nameCallback.getPrompt(), defaultName, actualUserName);
+                if (actualUserName == null) {
+                    if (defaultName != null) {
+                        nameCallback.setName(defaultName);
+                    }
+                } else {
+                    nameCallback.setName(actualUserName);
+                }
+            } else if (callback instanceof RealmCallback) {
                 final RealmCallback realmCallback = (RealmCallback) callback;
-                realmCallback.setText(actualUserRealm);
+                final String defaultRealm = realmCallback.getDefaultText();
+                log.trace("Realm requested; prompt '%s', default is '%s', ours is '%s'", realmCallback.getPrompt(), defaultRealm, actualUserRealm);
+                if (actualUserRealm == null) {
+                    if (defaultRealm != null) {
+                        realmCallback.setText(defaultRealm);
+                    }
+                } else {
+                    realmCallback.setText(actualUserRealm);
+                }
             } else if (callback instanceof RealmChoiceCallback && actualUserRealm != null) {
                 final RealmChoiceCallback realmChoiceCallback = (RealmChoiceCallback) callback;
                 final String[] choices = realmChoiceCallback.getChoices();

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractHandleableCloseable.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractHandleableCloseable.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/AbstractHandleableCloseable.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -23,6 +23,7 @@
 package org.jboss.remoting3.spi;
 
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.IdentityHashMap;
@@ -49,9 +50,16 @@
     private final StackTraceElement[] backtrace;
 
     private final Object closeLock = new Object();
-    private boolean closed;
+    private Thread closingThread;
+    private State state = State.OPEN;
     private Map<Key, CloseHandler<? super T>> closeHandlers = null;
 
+    enum State {
+        OPEN,
+        CLOSING,
+        CLOSED,
+    }
+
     static {
         boolean b = false;
         try {
@@ -87,7 +95,7 @@
      */
     protected boolean isOpen() {
         synchronized (closeLock) {
-            return ! closed;
+            return state == State.OPEN;
         }
     }
 
@@ -104,12 +112,32 @@
     public void close() throws IOException {
         final Map<Key, CloseHandler<? super T>> closeHandlers;
         synchronized (closeLock) {
-            if (closed) {
-                return;
+            switch (state) {
+                case OPEN: {
+                    state = State.CLOSING;
+                    closingThread = Thread.currentThread();
+                    closeHandlers = this.closeHandlers;
+                    this.closeHandlers = null;
+                    break;
+                }
+                case CLOSING: {
+                    if (Thread.currentThread() != closingThread) {
+                        while (state != State.CLOSED) {
+                            try {
+                                closeLock.wait();
+                            } catch (InterruptedException e) {
+                                Thread.currentThread().interrupt();
+                                throw new InterruptedIOException("Close interrupted");
+                            }
+                        }
+                    } else {
+                        // reentrant close always goes through unblocked
+                    }
+                    return;
+                }
+                case CLOSED: return;
+                default: throw new IllegalStateException();
             }
-            closed = true;
-            closeHandlers = this.closeHandlers;
-            this.closeHandlers = null;
         }
         if (closeHandlers != null) {
             log.trace("Closed %s", this);
@@ -119,7 +147,15 @@
                 }
             }
         }
-        closeAction();
+        try {
+            closeAction();
+        } finally {
+            synchronized (closeLock) {
+                state = State.CLOSED;
+                closingThread = null;
+                closeLock.notifyAll();
+            }
+        }
     }
 
     /**
@@ -130,7 +166,7 @@
             throw new NullPointerException("handler is null");
         }
         synchronized (closeLock) {
-            if (! closed) {
+            if (state == State.OPEN) {
                 final Key key = new KeyImpl<T>(this);
                 final Map<Key, CloseHandler<? super T>> closeHandlers = this.closeHandlers;
                 if (closeHandlers == null) {
@@ -215,7 +251,7 @@
      */
     protected void checkOpen() throws NotOpenException {
         synchronized (closeLock) {
-            if (closed) {
+            if (state != State.OPEN) {
                 throw new NotOpenException(toString() + " is not open");
             }
         }

Modified: remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderContext.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderContext.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/main/java/org/jboss/remoting3/spi/ConnectionProviderContext.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -66,4 +66,11 @@
      * @return the provider, or {@code null} if none was matched
      */
     <T> T getProtocolServiceProvider(ProtocolServiceType<T> serviceType, String name);
+
+    /**
+     * Get the endpoint's name.
+     *
+     * @return the endpoint name
+     */
+    String getEndpointName();
 }

Modified: remoting3/trunk/jboss-remoting/src/test/java/org/jboss/remoting3/test/RemoteTestCase.java
===================================================================
--- remoting3/trunk/jboss-remoting/src/test/java/org/jboss/remoting3/test/RemoteTestCase.java	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/test/java/org/jboss/remoting3/test/RemoteTestCase.java	2010-02-28 21:14:06 UTC (rev 5772)
@@ -37,6 +37,7 @@
 import org.jboss.xnio.IoFuture;
 import org.jboss.xnio.IoUtils;
 import org.jboss.xnio.OptionMap;
+import org.jboss.xnio.Options;
 import org.jboss.xnio.Xnio;
 import org.jboss.xnio.channels.BoundChannel;
 import org.jboss.xnio.channels.ConnectedStreamChannel;
@@ -49,6 +50,7 @@
 import javax.security.auth.callback.PasswordCallback;
 import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.security.sasl.AuthenticationException;
+import javax.security.sasl.AuthorizeCallback;
 import javax.security.sasl.RealmCallback;
 
 @Test(suiteName = "Remote tests")
@@ -66,7 +68,11 @@
                             for (Callback callback : callbacks) {
                                 if (callback instanceof NameCallback) {
                                     final NameCallback nameCallback = (NameCallback) callback;
-                                    if (! nameCallback.getName().equals("user")) {
+                                    final String defaultName = nameCallback.getDefaultName();
+                                    if (defaultName != null) {
+                                        nameCallback.setName(defaultName);
+                                    }
+                                    if (!"user".equals(nameCallback.getName())) {
                                         throw new AuthenticationException("Invalid user name");
                                     }
                                 } else if (callback instanceof PasswordCallback) {
@@ -74,8 +80,11 @@
                                     passwordCallback.setPassword("password".toCharArray());
                                 } else if (callback instanceof RealmCallback) {
                                     // allow
+                                } else if (callback instanceof AuthorizeCallback) {
+                                    final AuthorizeCallback authorizeCallback = (AuthorizeCallback) callback;
+                                    authorizeCallback.setAuthorized(authorizeCallback.getAuthenticationID().equals(authorizeCallback.getAuthorizationID()));
                                 } else {
-                                    throw new UnsupportedCallbackException(callback);
+                                    throw new UnsupportedCallbackException(callback, "Callback not supported: " + callback);
                                 }
                             }
                         }
@@ -89,14 +98,14 @@
 
     protected Connection getConnection() throws IOException {
         final NetworkServerProvider provider = endpoint.getConnectionProviderInterface("remote", NetworkServerProvider.class);
-        final ChannelListener<ConnectedStreamChannel<InetSocketAddress>> listener = provider.getServerListener(OptionMap.builder().set(RemotingOptions.AUTHENTICATION_PROVIDER, "test").getMap());
+        final ChannelListener<ConnectedStreamChannel<InetSocketAddress>> listener = provider.getServerListener(OptionMap.builder().set(RemotingOptions.AUTHENTICATION_PROVIDER, "test").setSequence(Options.SASL_MECHANISMS, "DIGEST-MD5").getMap());
         final Xnio xnio = Xnio.getInstance();
         try {
-            final AcceptingServer<InetSocketAddress, ?, ?> server = xnio.createSslTcpServer(listener, OptionMap.EMPTY);
-//            final AcceptingServer<InetSocketAddress, ?, ?> server = xnio.createTcpServer(listener, OptionMap.EMPTY);
+//            final AcceptingServer<InetSocketAddress, ?, ?> server = xnio.createSslTcpServer(listener, OptionMap.EMPTY);
+            final AcceptingServer<InetSocketAddress, ?, ?> server = xnio.createTcpServer(listener, OptionMap.EMPTY);
             final IoFuture<? extends BoundChannel<InetSocketAddress>> future = server.bind(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 0));
             final InetSocketAddress localAddress = future.get().getLocalAddress();
-            final Connection connection = endpoint.connect(new URI("remote", null, localAddress.getAddress().getHostAddress(), localAddress.getPort(), null, null, null), OptionMap.EMPTY, "user", "realm", "password".toCharArray()).get();
+            final Connection connection = endpoint.connect(new URI("remote", null, localAddress.getAddress().getHostAddress(), localAddress.getPort(), null, null, null), OptionMap.EMPTY, "user", null, "password".toCharArray()).get();
             connection.addCloseHandler(new CloseHandler<Connection>() {
                 public void handleClose(final Connection closed) {
                     IoUtils.safeClose(server);

Modified: remoting3/trunk/jboss-remoting/src/test/resources/remoting.properties
===================================================================
--- remoting3/trunk/jboss-remoting/src/test/resources/remoting.properties	2010-02-28 15:51:38 UTC (rev 5771)
+++ remoting3/trunk/jboss-remoting/src/test/resources/remoting.properties	2010-02-28 21:14:06 UTC (rev 5772)
@@ -20,4 +20,4 @@
 # 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 #
 
-#remote.ssl.enable=false
+remote.ssl.enable=false



More information about the jboss-remoting-commits mailing list