You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by ng...@apache.org on 2011/01/03 11:17:13 UTC

svn commit: r1054572 - in /mina/vysper/branches/s2s/server: core-inttest/ core-inttest/src/test/java/org/apache/vysper/xmpp/server/ core-inttest/src/test/java/org/apache/vysper/xmpp/server/s2s/ core-inttest/src/test/resources/ core/src/main/java/org/ap...

Author: ngn
Date: Mon Jan  3 10:17:12 2011
New Revision: 1054572

URL: http://svn.apache.org/viewvc?rev=1054572&view=rev
Log:
Refactoring XMPPServerConnector to use stanza handlers
Adding integration test case runner (for manual use)

Added:
    mina/vysper/branches/s2s/server/core-inttest/src/test/java/org/apache/vysper/xmpp/server/
    mina/vysper/branches/s2s/server/core-inttest/src/test/java/org/apache/vysper/xmpp/server/s2s/
    mina/vysper/branches/s2s/server/core-inttest/src/test/java/org/apache/vysper/xmpp/server/s2s/S2SIntegrationTestCase.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/FeaturesHandler.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/TlsProceedHandler.java
    mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandlerTestCase.java
    mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTestCase.java
      - copied, changed from r1054458, mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTest.java
    mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/server/s2s/Server2Server.java
Removed:
    mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTest.java
Modified:
    mina/vysper/branches/s2s/server/core-inttest/   (props changed)
    mina/vysper/branches/s2s/server/core-inttest/src/test/resources/log4j.properties
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/StreamStartHandler.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbResultHandler.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandler.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/ProtocolWorker.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/EncryptedProtocolWorker.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/StartedProtocolWorker.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnector.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnectorRegistry.java
    mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/XMPPServerConnectorRegistry.java

Propchange: mina/vysper/branches/s2s/server/core-inttest/
------------------------------------------------------------------------------
--- svn:ignore (original)
+++ svn:ignore Mon Jan  3 10:17:12 2011
@@ -2,3 +2,4 @@
 target
 .classpath
 .project
+s2s-jabber.org.properties

Added: mina/vysper/branches/s2s/server/core-inttest/src/test/java/org/apache/vysper/xmpp/server/s2s/S2SIntegrationTestCase.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core-inttest/src/test/java/org/apache/vysper/xmpp/server/s2s/S2SIntegrationTestCase.java?rev=1054572&view=auto
==============================================================================
--- mina/vysper/branches/s2s/server/core-inttest/src/test/java/org/apache/vysper/xmpp/server/s2s/S2SIntegrationTestCase.java (added)
+++ mina/vysper/branches/s2s/server/core-inttest/src/test/java/org/apache/vysper/xmpp/server/s2s/S2SIntegrationTestCase.java Mon Jan  3 10:17:12 2011
@@ -0,0 +1,210 @@
+package org.apache.vysper.xmpp.server.s2s;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.util.Properties;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.vysper.mina.TCPEndpoint;
+import org.apache.vysper.storage.StorageProviderRegistry;
+import org.apache.vysper.storage.inmemory.MemoryStorageProviderRegistry;
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.addressing.EntityImpl;
+import org.apache.vysper.xmpp.authorization.AccountCreationException;
+import org.apache.vysper.xmpp.authorization.AccountManagement;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.XMPPServer;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.XMPPException;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class S2SIntegrationTestCase extends TestCase {
+
+    public static Test suite() {
+        File testsDir = new File(".");
+        File[] testFiles = testsDir.listFiles(new FilenameFilter() {
+            public boolean accept(File arg0, String name) {
+                return name.startsWith("s2s-");
+            }
+        });
+        
+        TestSuite suite = new TestSuite("S2S integration tests");
+        for(File testFile : testFiles) {
+            try {
+                suite.addTest(new S2SIntegrationTestCase(testFile));
+            } catch (IOException e) {
+                fail(e.getMessage());
+            }
+        }
+        return suite;
+    }
+    
+    private File testFile;
+    private Properties config = new Properties();
+    
+    public S2SIntegrationTestCase(File testFile) throws IOException {
+        this.testFile = testFile;
+        config.load(new FileInputStream(testFile));
+    }
+
+    @Override
+    public String getName() {
+        return testFile.getName();
+    }
+
+    protected void runTest() throws Throwable {
+        Entity localServer = EntityImpl.parseUnchecked(config.getProperty("local.server"));
+        String localConnect = config.getProperty("local.connect", localServer.getFullQualifiedName());
+        Entity localUser = EntityImpl.parseUnchecked(config.getProperty("local.user"));
+        String localPassword = "password";
+        Entity remoteServer = EntityImpl.parseUnchecked(config.getProperty("remote.server"));
+        Entity remoteUser = EntityImpl.parseUnchecked(config.getProperty("remote.user"));
+        String remotePassword = config.getProperty("remote.password");
+
+        String keystorePath = config.getProperty("keystore.path");
+        String keystorePassword = config.getProperty("keystore.password");
+        
+        XMPPServer server = createLocalServer(localServer, localUser, localPassword, keystorePath, keystorePassword);
+        
+        Thread.sleep(2000);
+
+        System.out.println();
+        System.out.println();
+        System.out.println("Connecting local client");
+        System.out.println();
+        System.out.println();
+        
+        LinkedBlockingQueue<Packet> localClientPackages = new LinkedBlockingQueue<Packet>();
+        LinkedBlockingQueue<Packet> remoteClientPackages = new LinkedBlockingQueue<Packet>();
+        
+        XMPPConnection localClient = connectClient(localConnect, localUser, localPassword, keystorePath, keystorePassword, localClientPackages);
+
+        System.out.println();
+        System.out.println();
+        System.out.println("Connecting remote client");
+        System.out.println();
+        System.out.println();
+
+        XMPPConnection remoteClient = connectClient(remoteServer.getDomain(), remoteUser, remotePassword, keystorePath, keystorePassword, remoteClientPackages);
+
+        Thread.sleep(3000);
+
+        System.out.println();
+        System.out.println();
+        System.out.println("Sending message from local to remote");
+        System.out.println();
+        System.out.println();
+
+        remoteClientPackages.clear();
+        Message msg = new Message(remoteUser.getFullQualifiedName());
+        msg.setBody("Hello world");
+        
+        localClient.sendPacket(msg);
+        
+        Packet packet = remoteClientPackages.poll(15000, TimeUnit.MILLISECONDS);
+        if(packet != null && packet instanceof Message) {
+            System.out.println("!!!!!!" + ((Message)packet).getBody());
+        } else {
+            fail("Message not received by remote client");
+        }
+
+        Thread.sleep(3000);
+
+        System.out.println();
+        System.out.println();
+        System.out.println("Sending message from remote to local");
+        System.out.println();
+        System.out.println();
+
+        localClientPackages.clear();
+        msg = new Message(localUser.getFullQualifiedName());
+        msg.setBody("Hello world");
+        
+        remoteClient.sendPacket(msg);
+        
+        packet = localClientPackages.poll(15000, TimeUnit.MILLISECONDS);
+        if(packet != null && packet instanceof Message) {
+            System.out.println("!!!!!!" + ((Message)packet).getBody());
+        } else {
+            fail("Message not received by local client");
+        }
+        
+        Thread.sleep(15000);
+        System.out.println();
+        System.out.println();
+        System.out.println("Closing down");
+        System.out.println();
+        System.out.println();
+
+        remoteClient.disconnect();
+        localClient.disconnect();
+        
+        Thread.sleep(5000);
+        
+        server.stop();
+    }
+
+    private XMPPConnection connectClient(String host, Entity user, String password, String keystorePath, String keystorePassword, final LinkedBlockingQueue<Packet> packageQueue)
+            throws XMPPException {
+        ConnectionConfiguration connectionConfiguration = new ConnectionConfiguration(host, 5222);
+        connectionConfiguration.setKeystorePath(keystorePath);
+        connectionConfiguration.setTruststorePath(keystorePath);
+        connectionConfiguration.setTruststorePassword(keystorePassword);
+        XMPPConnection client = new XMPPConnection(connectionConfiguration);
+
+        client.connect();
+        client.login(user.getNode(), password);
+        client.addPacketListener(new PacketListener() {
+            public void processPacket(Packet packet) {
+                System.out.println("# " + packet);
+                packageQueue.add(packet);
+            }
+        }, new PacketFilter() {
+            public boolean accept(Packet arg0) {
+                return true;
+            }
+        });
+
+        
+        return client;
+    }
+
+    private XMPPServer createLocalServer(Entity localServer, Entity localUser, String password, String keystorePath,
+            String keystorePassword) throws AccountCreationException, FileNotFoundException, Exception {
+        XMPPServer server = new XMPPServer(localServer.getDomain());
+
+        StorageProviderRegistry providerRegistry = new MemoryStorageProviderRegistry();
+        final AccountManagement accountManagement = (AccountManagement) providerRegistry
+        .retrieve(AccountManagement.class);
+
+        if (!accountManagement.verifyAccountExists(localUser)) {
+            accountManagement.addUser(localUser.getFullQualifiedName(), password);
+        }
+
+        // S2S endpoint
+        TCPEndpoint s2sEndpoint = new TCPEndpoint();
+        s2sEndpoint.setPort(5269);
+        server.addEndpoint(s2sEndpoint);
+        
+        // C2S endpoint
+        server.addEndpoint(new TCPEndpoint());
+        
+        server.setStorageProviderRegistry(providerRegistry);
+        server.setTLSCertificateInfo(new File(keystorePath), keystorePassword);
+        
+        server.start();
+        return server;
+    }
+}

Modified: mina/vysper/branches/s2s/server/core-inttest/src/test/resources/log4j.properties
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core-inttest/src/test/resources/log4j.properties?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core-inttest/src/test/resources/log4j.properties (original)
+++ mina/vysper/branches/s2s/server/core-inttest/src/test/resources/log4j.properties Mon Jan  3 10:17:12 2011
@@ -15,7 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 
-log4j.rootLogger=DEBUG, C
+log4j.rootLogger=INFO, C
 
 log4j.logger.org.apache.vysper.mina.XmppIoHandlerAdapter=WARN,C
 log4j.logger.org.apache.mina.filter.executor.ExecutorFilter=WARN,C

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/StreamStartHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/StreamStartHandler.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/StreamStartHandler.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/core/base/handler/StreamStartHandler.java Mon Jan  3 10:17:12 2011
@@ -130,9 +130,8 @@ public class StreamStartHandler implemen
             // RFC3920: 'to' attribute SHOULD be used by the initiating entity
             String toValue = stanza.getAttributeValue("to");
             if (toValue != null) {
-                EntityImpl toEntity = null;
                 try {
-                    toEntity = EntityImpl.parse(toValue);
+                    EntityImpl.parse(toValue);
                 } catch (EntityFormatException e) {
                     return new ResponseStanzaContainerImpl(ServerErrorResponses.getInstance().getStreamError(
                             StreamErrorCondition.IMPROPER_ADDRESSING, sessionContext.getXMLLang(),
@@ -145,7 +144,7 @@ public class StreamStartHandler implemen
                 // TODO RFC3920: 'from' attribute SHOULD be silently ignored by the receiving entity
                 // TODO RFC3920bis: 'from' attribute SHOULD be not ignored by the receiving entity and used as 'to' in responses
             }
-            responseStanza = new ServerResponses().getStreamOpener(clientCall, sessionContext.getServerJID(),
+            responseStanza = new ServerResponses().getStreamOpenerForClient(sessionContext.getServerJID(),
                     responseVersion, sessionContext);
         } else if (serverCall) {
             // RFC3920: 'from' attribute SHOULD be used by the receiving entity
@@ -162,8 +161,8 @@ public class StreamStartHandler implemen
             
             // TODO set version correctly
             responseVersion = XMPPVersion.VERSION_1_0;
-            responseStanza = new ServerResponses().getStreamOpener(clientCall, sessionContext.getServerJID(),
-                    responseVersion, sessionContext);
+            responseStanza = new ServerResponses().getStreamOpenerForServerAcceptor(sessionContext.getServerJID(),
+                    responseVersion, sessionContext, serverRuntimeContext.getSslContext() != null);
         } else {
             String descriptiveText = "one of the two namespaces must be present: " + NamespaceURIs.JABBER_CLIENT
                     + " or " + NamespaceURIs.JABBER_SERVER;

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbResultHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbResultHandler.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbResultHandler.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbResultHandler.java Mon Jan  3 10:17:12 2011
@@ -29,9 +29,12 @@ import org.apache.vysper.xmpp.protocol.S
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.server.SessionState;
 import org.apache.vysper.xmpp.server.s2s.XMPPServerConnector;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 /**
  *
@@ -39,6 +42,9 @@ import org.apache.vysper.xmpp.stanza.Sta
  */
 public class DbResultHandler implements StanzaHandler {
     
+    private static final Logger LOG = LoggerFactory.getLogger(DbResultHandler.class);
+
+    
     public String getName() {
         return "result";
     }
@@ -64,6 +70,7 @@ public class DbResultHandler implements 
         String type = stanza.getAttributeValue("type");
         
         if(type == null) {
+            // acting as the Receiving server
             // start of dailback, respond
             String streamId = sessionContext.getSessionId();
             String dailbackId = stanza.getInnerText().getText();
@@ -97,6 +104,14 @@ public class DbResultHandler implements 
                 return new ResponseStanzaContainerImpl(builder.build());
             }
         } else {
+            // acting as the Originating server
+            // receiving the result from the Receiving server
+            if("valid".equals(type)) {
+                sessionStateHolder.setState(SessionState.AUTHENTICATED);
+                Entity receiving = EntityImpl.parseUnchecked(stanza.getAttributeValue("from"));
+                LOG.info("XMPP server connector to {} authenticated using dialback", receiving);
+            } 
+
             return null;
         }
     }

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandler.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandler.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandler.java Mon Jan  3 10:17:12 2011
@@ -29,6 +29,8 @@ import org.apache.vysper.xmpp.protocol.S
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.server.SessionState;
+import org.apache.vysper.xmpp.server.s2s.XMPPServerConnector;
 import org.apache.vysper.xmpp.stanza.Stanza;
 import org.apache.vysper.xmpp.stanza.StanzaBuilder;
 
@@ -55,35 +57,66 @@ public class DbVerifyHandler implements 
     }
 
     public boolean isSessionRequired() {
-        return false;
+        return true;
     }
 
     public ResponseStanzaContainer execute(Stanza stanza, ServerRuntimeContext serverRuntimeContext,
             boolean isOutboundStanza, SessionContext sessionContext, SessionStateHolder sessionStateHolder) {
         
         String type = stanza.getAttributeValue("type");
+        String id = stanza.getAttributeValue("id");
         Entity receiving = EntityImpl.parseUnchecked(stanza.getAttributeValue("from"));
         Entity originating = serverRuntimeContext.getServerEnitity();
-        
         if(type == null) {
-            // ask for verification
+            // acting as a Authoritative server
+            // getting asked for verification from the Receiving server
             String dailbackId = stanza.getInnerText().getText();
-            String streamId = stanza.getAttributeValue("id");
             
             StanzaBuilder builder = new StanzaBuilder("verify", NamespaceURIs.JABBER_SERVER_DIALBACK, "db");
             builder.addAttribute("from", originating.getDomain());
             builder.addAttribute("to", receiving.getDomain());
-            builder.addAttribute("id", streamId);
+            builder.addAttribute("id", id);
             
-            if(dailbackIdGenerator.verify(dailbackId, receiving, originating, streamId)) {
+            if(dailbackIdGenerator.verify(dailbackId, receiving, originating, id)) {
                 builder.addAttribute("type", "valid");
             } else {
                 builder.addAttribute("type", "invalid");
             }
-            
             return new ResponseStanzaContainerImpl(builder.build());
         } else {
-            throw new RuntimeException("Unexpected stanza");
+            // acting as a Receiving server
+            // getting a response from the Authoritative server
+            SessionStateHolder dialbackSessionStateHolder = (SessionStateHolder) sessionContext.getAttribute("DIALBACK_SESSION_STATE_HOLDER");
+            SessionContext dialbackSessionContext = (SessionContext) sessionContext.getAttribute("DIALBACK_SESSION_CONTEXT");
+
+//            XMPPServerConnector connector = serverRuntimeContext.getServerConnectorRegistry().getConnectorBySessionId(id);
+            
+//            if(connector != null) {
+//                SessionStateHolder dialbackSessionStateHolder = connector.getSessionStateHolder();
+//                SessionContext dialbackSessionContext = connector.getSessionContext();
+    
+                
+                Entity otherServer = sessionContext.getInitiatingEntity();
+                String resultType = "invalid";
+                // dialbackSessionContext must be non-null or someone is trying to send this stanza in the wrong state
+                if("valid".equals(type)) {
+                    dialbackSessionStateHolder.setState(SessionState.AUTHENTICATED);
+                    dialbackSessionContext.setInitiatingEntity(otherServer);
+                    resultType = "valid";
+                }
+                
+                // <db:result xmlns:db="jabber:server:dialback" to="xmpp.protocol7.com" from="jabber.org" type="valid"></db:result>
+                StanzaBuilder builder = new StanzaBuilder("result", NamespaceURIs.JABBER_SERVER_DIALBACK, "db");
+                builder.addAttribute("from", originating.getDomain());
+                builder.addAttribute("to", otherServer.getDomain());
+                builder.addAttribute("type", resultType);
+    
+                dialbackSessionContext.write(builder.build());
+//            }
+            
+            // close this session as we are now done checking dialback
+            sessionContext.close();
+            return null;
         }
     }
 }

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/ProtocolWorker.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/ProtocolWorker.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/ProtocolWorker.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/ProtocolWorker.java Mon Jan  3 10:17:12 2011
@@ -135,13 +135,13 @@ public class ProtocolWorker implements S
                 
                 Entity to = stanza.getTo();
                 if(to == null) {
-                    // TODO what's the appropriate error?
+                    // TODO what's the appropriate error? StreamErrorCondition.IMPROPER_ADDRESSING?
                     Stanza errorStanza = ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.BAD_REQUEST,
                             coreStanza, StanzaErrorType.MODIFY, "Missing to attribute", null, null);
                     ResponseWriter.writeResponse(sessionContext, errorStanza);
                     return;                    
                 } else if(!to.getDomain().equals(serverRuntimeContext.getServerEnitity().getDomain())) {
-                    // TODO what's the appropriate error?
+                    // TODO what's the appropriate error? StreamErrorCondition.IMPROPER_ADDRESSING?
                     Stanza errorStanza = ServerErrorResponses.getInstance().getStanzaError(StanzaErrorCondition.BAD_REQUEST,
                             coreStanza, StanzaErrorType.MODIFY, "Invalid to attribute", null, null);
                     ResponseWriter.writeResponse(sessionContext, errorStanza);

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/EncryptedProtocolWorker.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/EncryptedProtocolWorker.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/EncryptedProtocolWorker.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/EncryptedProtocolWorker.java Mon Jan  3 10:17:12 2011
@@ -23,6 +23,7 @@ import org.apache.vysper.xmpp.modules.co
 import org.apache.vysper.xmpp.modules.core.base.handler.XMLPrologHandler;
 import org.apache.vysper.xmpp.modules.core.sasl.handler.AbstractSASLHandler;
 import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DbResultHandler;
+import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DbVerifyHandler;
 import org.apache.vysper.xmpp.protocol.ResponseWriter;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
 import org.apache.vysper.xmpp.protocol.StanzaHandler;
@@ -44,6 +45,7 @@ public class EncryptedProtocolWorker ext
     @Override
     protected boolean checkState(SessionContext sessionContext, SessionStateHolder sessionStateHolder, Stanza stanza,
             StanzaHandler stanzaHandler) {
+        
         if (stanzaHandler instanceof StreamStartHandler)
             return true;
         if (stanzaHandler instanceof AbstractSASLHandler)
@@ -52,6 +54,8 @@ public class EncryptedProtocolWorker ext
             return true; // PSI client sends that. 
         if (sessionContext.isServerToServer() && stanzaHandler instanceof DbResultHandler)
             return true;
+        if (sessionContext.isServerToServer() && stanzaHandler instanceof DbVerifyHandler)
+            return true;
         ResponseWriter.writeUnsupportedStanzaError(sessionContext);
         return false;
     }

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/StartedProtocolWorker.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/StartedProtocolWorker.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/StartedProtocolWorker.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/protocol/worker/StartedProtocolWorker.java Mon Jan  3 10:17:12 2011
@@ -43,6 +43,7 @@ public class StartedProtocolWorker exten
     @Override
     protected boolean checkState(SessionContext sessionContext, SessionStateHolder sessionStateHolder, Stanza stanza,
             StanzaHandler stanzaHandler) {
+
         if (stanzaHandler instanceof StartTLSHandler)
             return true;
         if (sessionContext.isServerToServer() && stanzaHandler instanceof DbVerifyHandler)

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/response/ServerResponses.java Mon Jan  3 10:17:12 2011
@@ -41,14 +41,6 @@ public class ServerResponses {
         return getStreamOpener(forClient, from, null, version, errorStanza).build();
     }
 
-    public Stanza getStreamOpener(boolean forClient, Entity from, XMPPVersion version, SessionContext sessionContext) {
-        if(forClient) {
-            return getStreamOpenerForClient(from, version, sessionContext);
-        } else {
-            return getStreamOpenerForServerAcceptor(from, version, sessionContext);
-        }
-    }
-    
     public Stanza getStreamOpenerForClient(Entity from, XMPPVersion version, SessionContext sessionContext) {
         Stanza innerFeatureStanza;
         if (sessionContext.getState() == SessionState.INITIATED)
@@ -69,7 +61,7 @@ public class ServerResponses {
         return stanzaBuilder.build();
     }
 
-    public Stanza getStreamOpenerForServerAcceptor(Entity from, XMPPVersion version, SessionContext sessionContext) {
+    public Stanza getStreamOpenerForServerAcceptor(Entity from, XMPPVersion version, SessionContext sessionContext, boolean tlsConfigured) {
         StanzaBuilder featureBuilder = startFeatureStanza();
         if (sessionContext.getState() == SessionState.INITIATED) {
             featureBuilder.startInnerElement("starttls", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS).endInnerElement();

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnector.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnector.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnector.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnector.java Mon Jan  3 10:17:12 2011
@@ -1,5 +1,6 @@
 package org.apache.vysper.xmpp.server.s2s;
 import java.nio.channels.UnresolvedAddressException;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Timer;
 import java.util.TimerTask;
@@ -22,9 +23,11 @@ import org.apache.vysper.xmpp.delivery.f
 import org.apache.vysper.xmpp.delivery.failure.RemoteServerTimeoutException;
 import org.apache.vysper.xmpp.modules.extension.xep0119_xmppping.XmppPingListener;
 import org.apache.vysper.xmpp.modules.extension.xep0119_xmppping.XmppPingModule;
-import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DialbackIdGenerator;
-import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DbResultHandler;
+import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DbVerifyHandler;
+import org.apache.vysper.xmpp.protocol.ResponseStanzaContainer;
 import org.apache.vysper.xmpp.protocol.SessionStateHolder;
+import org.apache.vysper.xmpp.protocol.StanzaHandler;
 import org.apache.vysper.xmpp.server.ServerRuntimeContext;
 import org.apache.vysper.xmpp.server.SessionContext;
 import org.apache.vysper.xmpp.server.SessionState;
@@ -32,7 +35,6 @@ import org.apache.vysper.xmpp.server.XMP
 import org.apache.vysper.xmpp.server.response.ServerResponses;
 import org.apache.vysper.xmpp.server.s2s.XmppEndpointResolver.ResolvedAddress;
 import org.apache.vysper.xmpp.stanza.Stanza;
-import org.apache.vysper.xmpp.stanza.StanzaBuilder;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -57,7 +59,7 @@ public class DefaultXMPPServerConnector 
     private SessionContext dialbackSessionContext;
     private SessionStateHolder dialbackSessionStateHolder;
     
-    private Timer pingTimer = new Timer("pingtimer", true);
+    private Timer pingTimer;
     
     public DefaultXMPPServerConnector(Entity otherServer, ServerRuntimeContext serverRuntimeContext, SessionContext dialbackSessionContext, SessionStateHolder dialbackSessionStateHolder) {
         this.serverRuntimeContext = serverRuntimeContext;
@@ -84,7 +86,6 @@ public class DefaultXMPPServerConnector 
                 LOG.info("Connecting to XMPP server {} at {}", otherServer, address.getAddress());
                 
                 connector = createConnector(authenticatedLatch);
-                
                 ConnectFuture connectFuture = connector.connect(address.getAddress());
                 if(connectFuture.awaitUninterruptibly(connectTimeout) && connectFuture.isConnected()) {
                     // success on the TCP/IP level, now wait for the XMPP handshake
@@ -138,8 +139,9 @@ public class DefaultXMPPServerConnector 
 
     
     private void startPinging() {
-        // is the XMPP ping module active?
-        if(serverRuntimeContext.getModule(XmppPingModule.class) != null) {
+        // are pings not already running and is the XMPP ping module active?
+        if(pingTimer == null && serverRuntimeContext.getModule(XmppPingModule.class) != null) {
+            pingTimer = new Timer("pingtimer", true);
             pingTimer.schedule(new PingTask(), pingPeriod, pingPeriod);
         }
     }
@@ -177,6 +179,14 @@ public class DefaultXMPPServerConnector 
     }
 
     private final class ConnectorIoHandler extends IoHandlerAdapter {
+        
+        private final List<StanzaHandler> handlers = Arrays.asList(
+            new DbVerifyHandler(),
+            new DbResultHandler(),
+            new TlsProceedHandler(),
+            new FeaturesHandler()
+            ); 
+        
         private final CountDownLatch authenticatedLatch;
 
         private ConnectorIoHandler(CountDownLatch authenticatedLatch) {
@@ -185,13 +195,21 @@ public class DefaultXMPPServerConnector 
 
         @Override
         public void exceptionCaught(IoSession session, Throwable cause) throws Exception {
-            LOG.info("Exception thrown by XMPP server connector to {}, probably a bug in Vysper", otherServer);
+            LOG.warn("Exception thrown by XMPP server connector to " + otherServer + ", probably a bug in Vysper", cause);
         }
 
+        private StanzaHandler lookupHandler(Stanza stanza) {
+            for(StanzaHandler handler : handlers) {
+                if(handler.verify(stanza)) {
+                    return handler;
+                }
+            }
+            return null;
+        }
+        
         @Override
         public void messageReceived(IoSession session, Object message) throws Exception {
             if(message == SslFilter.SESSION_SECURED) {
-                // TODO handle unsecure
                 // connection secured, send stream opener
                 sessionStateHolder.setState(SessionState.ENCRYPTED);
                 
@@ -203,93 +221,47 @@ public class DefaultXMPPServerConnector 
                 Stanza opener = new ServerResponses().getStreamOpenerForServerConnector(serverRuntimeContext.getServerEnitity(), otherServer, XMPPVersion.VERSION_1_0, sessionContext);
                 
                 sessionContext.write(opener);
-            } else {
-                Stanza msg = (Stanza) message;
+            } else if(message instanceof Stanza) {
+                Stanza stanza = (Stanza) message;
                 
-                if(msg.getName().equals("stream")) {
-                    sessionContext.setSessionId(msg.getAttributeValue("id"));
-                } else if(msg.getName().equals("features")) {
-                    if(dialbackSessionContext != null) {
-                        // connector is being used for dialback verificiation, don't do further authentication
-                        session.setAttribute("DIALBACK_SESSION_CONTEXT", dialbackSessionContext);
-                        session.setAttribute("DIALBACK_SESSION_STATE_HOLDER", dialbackSessionStateHolder);
-                        
-                        sessionStateHolder.setState(SessionState.AUTHENTICATED);
-                        authenticatedLatch.countDown();
-                    } else {
-                        if(startTlsSupported(msg)) {
-                            LOG.info("XMPP server connector to {} is starting TLS", otherServer);
-                            Stanza startTlsStanza = new StanzaBuilder("starttls", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS).build();
-                            
-                            sessionContext.write(startTlsStanza);
-                            
-                        } else if(dialbackSupported(msg)) {
-                            Entity originating = serverRuntimeContext.getServerEnitity();
-       
-                            String dailbackId = new DialbackIdGenerator().generate(otherServer, originating, sessionContext.getSessionId());
-                            
-                            Stanza dbResult = new StanzaBuilder("result", NamespaceURIs.JABBER_SERVER_DIALBACK, "db")
-                                .addAttribute("from", originating.getDomain())
-                                .addAttribute("to", otherServer.getDomain())
-                                .addText(dailbackId)
-                                .build();
-                            
-                            sessionContext.write(dbResult);
-                        } else {
-                            // TODO how to handle
-                            throw new RuntimeException("Unsupported features");
-                        }
+                // check for basic stanza handlers
+                StanzaHandler handler = lookupHandler(stanza);
+                
+                if(handler != null) {
+                    ResponseStanzaContainer container = handler.execute(stanza, serverRuntimeContext, false, sessionContext, sessionStateHolder);
+                    if(container != null && container.hasResponse()) {
+                        sessionContext.write(container.getResponseStanza());
                     }
-                } else if(msg.getName().equals("proceed") && NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS.equals(msg.getNamespaceURI())) {
-                    sessionStateHolder.setState(SessionState.ENCRYPTION_STARTED);
-                    
-                    LOG.debug("XMPP server connector to {} switching to TLS", otherServer);
-                    sessionContext.switchToTLS(false, true);
-                } else if(msg.getName().equals("result") && NamespaceURIs.JABBER_SERVER_DIALBACK.equals(msg.getNamespaceURI())) {
-                    // TODO check and handle dailback result
-                    sessionStateHolder.setState(SessionState.AUTHENTICATED);
-                    
-                    LOG.info("XMPP server connector to {} authenticated using dialback", otherServer);
-                    authenticatedLatch.countDown();
                     
-                    // connection established, start pinging
-                    startPinging();
-                } else if(msg.getName().equals("verify") && NamespaceURIs.JABBER_SERVER_DIALBACK.equals(msg.getNamespaceURI())) {
-                    Entity originating = serverRuntimeContext.getServerEnitity();
-                    String type = msg.getAttributeValue("type");
-                    
-                    String resultType = "invalid";
-                    if("valid".equals(type)) {
-                        dialbackSessionStateHolder.setState(SessionState.AUTHENTICATED);
-                        dialbackSessionContext.setInitiatingEntity(otherServer);
-                        resultType = "valid";
+                    if(sessionStateHolder.getState() == SessionState.AUTHENTICATED) {
+                        LOG.info("XMPP server connector to {} authenticated", otherServer);
+                        authenticatedLatch.countDown();
+                        
+                        // connection established, start pinging
+                        startPinging();
                     }
+                // none of the handlers matched, stream start is handled separately
+                } else if(stanza.getName().equals("stream")) {
+                    sessionContext.setSessionId(stanza.getAttributeValue("id"));
+                    sessionContext.setInitiatingEntity(stanza.getFrom());
                     
-                    // <db:result xmlns:db="jabber:server:dialback" to="xmpp.protocol7.com" from="jabber.org" type="valid"></db:result>
-                    StanzaBuilder builder = new StanzaBuilder("result", NamespaceURIs.JABBER_SERVER_DIALBACK, "db");
-                    builder.addAttribute("from", originating.getDomain());
-                    builder.addAttribute("to", otherServer.getDomain());
-                    builder.addAttribute("type", resultType);
-
-                    dialbackSessionContext.write(builder.build());
-                    
-                    // close this session as we are now done checking dialback
-                    close();
+                    if(dialbackSessionContext != null) {
+                        // connector is being used for dialback verification, don't do further authentication
+                        sessionContext.putAttribute("DIALBACK_SESSION_CONTEXT", dialbackSessionContext);
+                        sessionContext.putAttribute("DIALBACK_SESSION_STATE_HOLDER", dialbackSessionStateHolder);
+                     
+                        sessionContext.setInitiatingEntity(stanza.getFrom());
+                        sessionStateHolder.setState(SessionState.AUTHENTICATED);
+                        authenticatedLatch.countDown();
+                    }
                 } else {
                     // TODO other stanzas coming here?
                 }
+            } else {
+                throw new RuntimeException("Only handles SSL events and stanzas");
             }
         }
 
-        private boolean startTlsSupported(Stanza stanza) {
-            return !stanza.getInnerElementsNamed("starttls", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS).isEmpty();
-        }
-
-        private boolean dialbackSupported(Stanza stanza) {
-            // TODO check for dialback namespace
-            return !stanza.getInnerElementsNamed("dialback", NamespaceURIs.URN_XMPP_FEATURES_DIALBACK).isEmpty();
-        }
-
         @Override
         public void sessionClosed(IoSession session) throws Exception {
             // Socket was closed, make sure we close the connector
@@ -313,6 +285,4 @@ public class DefaultXMPPServerConnector 
             pingModule.ping(DefaultXMPPServerConnector.this, serverRuntimeContext.getServerEnitity(), otherServer, pingTimeout, DefaultXMPPServerConnector.this);
         }
     }
-    
-
 }

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnectorRegistry.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnectorRegistry.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnectorRegistry.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/DefaultXMPPServerConnectorRegistry.java Mon Jan  3 10:17:12 2011
@@ -24,14 +24,6 @@ public class DefaultXMPPServerConnectorR
      */
     @SpecCompliant(spec = "draft-ietf-xmpp-3920bis-22", section = "10.4", status = SpecCompliant.ComplianceStatus.IN_PROGRESS, coverage = SpecCompliant.ComplianceCoverage.COMPLETE)
     public synchronized XMPPServerConnector connect(Entity server) throws RemoteServerNotFoundException, RemoteServerTimeoutException {
-        return connect(server, null, null);
-    }
-    
-    public synchronized XMPPServerConnector connectForDialback(Entity server, SessionContext orginalSessionContext, SessionStateHolder originalSessionStateHolder) throws RemoteServerNotFoundException, RemoteServerTimeoutException {
-        return connect(server, orginalSessionContext, originalSessionStateHolder);
-    }
-    
-    private XMPPServerConnector connect(Entity server, SessionContext dialbackSessionContext, SessionStateHolder dialbackSessionStateHolder) throws RemoteServerNotFoundException, RemoteServerTimeoutException {
         DefaultXMPPServerConnector connector = connectors.get(server);
 
         if(connector != null && connector.isClosed()) {
@@ -40,18 +32,21 @@ public class DefaultXMPPServerConnectorR
         } 
         
         if(connector == null) {
-            connector = new DefaultXMPPServerConnector(server, serverRuntimeContext, dialbackSessionContext, dialbackSessionStateHolder);
+            connector = new DefaultXMPPServerConnector(server, serverRuntimeContext, null, null);
             connector.start();
 
-            // only register if we're not starting a connector for dialback
-            if(dialbackSessionContext == null) {
-                connectors.put(server, connector);
-            }
+            connectors.put(server, connector);
         }
         
         return connector;        
     }
-
+    
+    public synchronized XMPPServerConnector connectForDialback(Entity server, SessionContext orginalSessionContext, SessionStateHolder originalSessionStateHolder) throws RemoteServerNotFoundException, RemoteServerTimeoutException {
+        DefaultXMPPServerConnector connector = new DefaultXMPPServerConnector(server, serverRuntimeContext, orginalSessionContext, originalSessionStateHolder);
+        connector.start();
+        return connector;
+    }
+    
     /* (non-Javadoc)
      * @see org.apache.vysper.xmpp.server.s2s.XMPPServerConnectorRegistry#close()
      */
@@ -60,4 +55,6 @@ public class DefaultXMPPServerConnectorR
             connector.close();
         }
     }
+
+
 }

Added: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/FeaturesHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/FeaturesHandler.java?rev=1054572&view=auto
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/FeaturesHandler.java (added)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/FeaturesHandler.java Mon Jan  3 10:17:12 2011
@@ -0,0 +1,103 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+package org.apache.vysper.xmpp.server.s2s;
+
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DialbackIdGenerator;
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.protocol.ResponseStanzaContainer;
+import org.apache.vysper.xmpp.protocol.ResponseStanzaContainerImpl;
+import org.apache.vysper.xmpp.protocol.SessionStateHolder;
+import org.apache.vysper.xmpp.protocol.StanzaHandler;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.server.SessionState;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.apache.vysper.xmpp.stanza.StanzaBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class FeaturesHandler implements StanzaHandler {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(FeaturesHandler.class);
+    
+    public String getName() {
+        return "features";
+    }
+
+    public boolean verify(Stanza stanza) {
+        if (stanza == null) return false;
+        if (!getName().equals(stanza.getName())) return false;
+        String namespaceURI = stanza.getNamespaceURI();
+        if (namespaceURI == null) return false;
+        return namespaceURI.equals(NamespaceURIs.HTTP_ETHERX_JABBER_ORG_STREAMS);
+    }
+
+    public boolean isSessionRequired() {
+        return true;
+    }
+
+    public ResponseStanzaContainer execute(Stanza stanza, ServerRuntimeContext serverRuntimeContext,
+            boolean isOutboundStanza, SessionContext sessionContext, SessionStateHolder sessionStateHolder) {
+        if(sessionStateHolder.getState() != SessionState.AUTHENTICATED) {
+            Entity otherServer = sessionContext.getInitiatingEntity();
+            
+            if(startTlsSupported(stanza) && serverRuntimeContext.getSslContext() != null) {
+                // remote server support TLS and we got keys set up
+                LOG.info("XMPP server connector to {} is starting TLS", otherServer);
+                Stanza startTlsStanza = new StanzaBuilder("starttls", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS).build();
+                
+                return new ResponseStanzaContainerImpl(startTlsStanza);
+            } else if(dialbackSupported(stanza)) {
+                Entity originating = serverRuntimeContext.getServerEnitity();
+
+                String dailbackId = new DialbackIdGenerator().generate(otherServer, originating, sessionContext.getSessionId());
+                
+                Stanza dbResult = new StanzaBuilder("result", NamespaceURIs.JABBER_SERVER_DIALBACK, "db")
+                    .addAttribute("from", originating.getDomain())
+                    .addAttribute("to", otherServer.getDomain())
+                    .addText(dailbackId)
+                    .build();
+                
+                return new ResponseStanzaContainerImpl(dbResult);
+            } else {
+                // TODO how to handle
+                throw new RuntimeException("Unsupported features");
+            }
+        }
+        
+        return null;
+    }
+    
+    private boolean startTlsSupported(Stanza stanza) {
+        return !stanza.getInnerElementsNamed("starttls", NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS).isEmpty();
+    }
+
+    private boolean dialbackSupported(Stanza stanza) {
+        return !stanza.getInnerElementsNamed("dialback", NamespaceURIs.URN_XMPP_FEATURES_DIALBACK).isEmpty();
+    }
+
+
+}

Added: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/TlsProceedHandler.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/TlsProceedHandler.java?rev=1054572&view=auto
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/TlsProceedHandler.java (added)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/TlsProceedHandler.java Mon Jan  3 10:17:12 2011
@@ -0,0 +1,67 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you under the Apache License, Version 2.0 (the
+ *  "License"); you may not use this file except in compliance
+ *  with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing,
+ *  software distributed under the License is distributed on an
+ *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *  KIND, either express or implied.  See the License for the
+ *  specific language governing permissions and limitations
+ *  under the License.
+ *
+ */
+
+package org.apache.vysper.xmpp.server.s2s;
+
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.protocol.ResponseStanzaContainer;
+import org.apache.vysper.xmpp.protocol.SessionStateHolder;
+import org.apache.vysper.xmpp.protocol.StanzaHandler;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.SessionContext;
+import org.apache.vysper.xmpp.server.SessionState;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author The Apache MINA Project (dev@mina.apache.org)
+ */
+public class TlsProceedHandler implements StanzaHandler {
+    
+    private static final Logger LOG = LoggerFactory.getLogger(TlsProceedHandler.class);
+    
+    public String getName() {
+        return "proceed";
+    }
+
+    public boolean verify(Stanza stanza) {
+        if (stanza == null) return false;
+        if (!getName().equals(stanza.getName())) return false;
+        String namespaceURI = stanza.getNamespaceURI();
+        if (namespaceURI == null) return false;
+        return namespaceURI.equals(NamespaceURIs.URN_IETF_PARAMS_XML_NS_XMPP_TLS);
+    }
+
+    public boolean isSessionRequired() {
+        return true;
+    }
+
+    public ResponseStanzaContainer execute(Stanza stanza, ServerRuntimeContext serverRuntimeContext,
+            boolean isOutboundStanza, SessionContext sessionContext, SessionStateHolder sessionStateHolder) {
+        sessionStateHolder.setState(SessionState.ENCRYPTION_STARTED);
+        
+        LOG.debug("XMPP server connector switching to TLS");
+        sessionContext.switchToTLS(false, true);
+
+        return null;
+    }
+}

Modified: mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/XMPPServerConnectorRegistry.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/XMPPServerConnectorRegistry.java?rev=1054572&r1=1054571&r2=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/XMPPServerConnectorRegistry.java (original)
+++ mina/vysper/branches/s2s/server/core/src/main/java/org/apache/vysper/xmpp/server/s2s/XMPPServerConnectorRegistry.java Mon Jan  3 10:17:12 2011
@@ -14,7 +14,6 @@ public interface XMPPServerConnectorRegi
     XMPPServerConnector connectForDialback(Entity server, SessionContext sessionContext, SessionStateHolder sessionStateHolder) throws RemoteServerNotFoundException,
     RemoteServerTimeoutException;
 
-    
     void close();
 
 }
\ No newline at end of file

Added: mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandlerTestCase.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandlerTestCase.java?rev=1054572&view=auto
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandlerTestCase.java (added)
+++ mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DbVerifyHandlerTestCase.java Mon Jan  3 10:17:12 2011
@@ -0,0 +1,63 @@
+package org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.addressing.EntityImpl;
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.apache.vysper.xmpp.stanza.StanzaBuilder;
+import org.mockito.Mockito;
+
+
+public class DbVerifyHandlerTestCase extends TestCase {
+
+    private static final Entity FROM = EntityImpl.parseUnchecked("from.org");
+    private static final Entity TO = EntityImpl.parseUnchecked("to.org");
+    private static final String ID = "D60000229F";
+
+    private DbVerifyHandler handler = new DbVerifyHandler();
+    
+    public void testVerify() {
+        Stanza correct = new StanzaBuilder("verify", NamespaceURIs.JABBER_SERVER_DIALBACK).build();
+        Stanza invalidNamespace = new StanzaBuilder("verify", "dummy").build();
+        Stanza invalidName = new StanzaBuilder("dummy", NamespaceURIs.JABBER_SERVER_DIALBACK).build();
+        
+        Assert.assertTrue(handler.verify(correct));
+        Assert.assertFalse(handler.verify(invalidNamespace));
+        Assert.assertFalse(handler.verify(invalidName));
+    }
+    
+    public void testExecuteValidVerification() {
+        String token = new DialbackIdGenerator().generate(FROM, TO, ID);
+        assertExecuteVerification(token, "valid");
+    }
+
+    public void testExecuteInvalidVerification() {
+        assertExecuteVerification("12345", "invalid");
+    }
+
+    private void assertExecuteVerification(String token, String expectedType) {
+        ServerRuntimeContext serverRuntimeContext = Mockito.mock(ServerRuntimeContext.class);
+        Mockito.when(serverRuntimeContext.getServerEnitity()).thenReturn(TO);
+        
+        Stanza stanza = new StanzaBuilder("verify", NamespaceURIs.JABBER_SERVER_DIALBACK)
+        .addAttribute("from", FROM.getFullQualifiedName())
+        .addAttribute("to", TO.getFullQualifiedName())
+        .addAttribute("id", ID)
+        .addText(token)
+        .build();
+        
+        Stanza response = handler.execute(stanza, serverRuntimeContext, false, null, null).getResponseStanza();
+        
+        Assert.assertNotNull(response);
+        Assert.assertEquals(TO, response.getFrom());
+        Assert.assertEquals(FROM, response.getTo());
+        Assert.assertEquals(ID, response.getAttributeValue("id"));
+        Assert.assertEquals(expectedType, response.getAttributeValue("type"));
+    }
+    
+    
+
+}

Copied: mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTestCase.java (from r1054458, mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTest.java)
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTestCase.java?p2=mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTestCase.java&p1=mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTest.java&r1=1054458&r2=1054572&rev=1054572&view=diff
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTest.java (original)
+++ mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/modules/extension/xep0220_server_dailback/DialbackIdGeneratorTestCase.java Mon Jan  3 10:17:12 2011
@@ -7,7 +7,7 @@ import org.apache.vysper.xmpp.addressing
 import org.apache.vysper.xmpp.modules.extension.xep0220_server_dailback.DialbackIdGenerator;
 
 
-public class DialbackIdGeneratorTest extends TestCase {
+public class DialbackIdGeneratorTestCase extends TestCase {
 
     private Entity receiving = EntityImpl.parseUnchecked("xmpp.example.com");
     private Entity originating = EntityImpl.parseUnchecked("example.org");

Added: mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/server/s2s/Server2Server.java
URL: http://svn.apache.org/viewvc/mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/server/s2s/Server2Server.java?rev=1054572&view=auto
==============================================================================
--- mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/server/s2s/Server2Server.java (added)
+++ mina/vysper/branches/s2s/server/core/src/test/java/org/apache/vysper/xmpp/server/s2s/Server2Server.java Mon Jan  3 10:17:12 2011
@@ -0,0 +1,133 @@
+package org.apache.vysper.xmpp.server.s2s;
+import java.io.File;
+
+import org.apache.vysper.mina.TCPEndpoint;
+import org.apache.vysper.storage.StorageProviderRegistry;
+import org.apache.vysper.storage.inmemory.MemoryStorageProviderRegistry;
+import org.apache.vysper.xmpp.addressing.Entity;
+import org.apache.vysper.xmpp.addressing.EntityImpl;
+import org.apache.vysper.xmpp.authorization.AccountManagement;
+import org.apache.vysper.xmpp.protocol.NamespaceURIs;
+import org.apache.vysper.xmpp.server.ServerRuntimeContext;
+import org.apache.vysper.xmpp.server.XMPPServer;
+import org.apache.vysper.xmpp.stanza.Stanza;
+import org.apache.vysper.xmpp.stanza.StanzaBuilder;
+import org.jivesoftware.smack.ConnectionConfiguration;
+import org.jivesoftware.smack.PacketListener;
+import org.jivesoftware.smack.XMPPConnection;
+import org.jivesoftware.smack.filter.PacketFilter;
+import org.jivesoftware.smack.packet.Message;
+import org.jivesoftware.smack.packet.Packet;
+
+
+public class Server2Server {
+
+    public static void main(String[] args) throws Exception {
+        Entity localServer = EntityImpl.parseUnchecked(args[0]);
+        Entity localUser = EntityImpl.parseUnchecked(args[1]);
+        Entity remoteServer = EntityImpl.parseUnchecked(args[2]);
+        Entity remoteUser = EntityImpl.parseUnchecked(args[3]);
+        String remotePassword = args[4];
+
+        String keystorePath;
+        String keystorePassword;
+        if(args.length > 5) {
+            keystorePath = args[5];
+            keystorePassword = args[6];
+        } else {
+            keystorePath = "src/main/config/bogus_mina_tls.cert";
+            keystorePassword = "boguspw";            
+        }
+        
+        XMPPServer server = new XMPPServer(localServer.getDomain());
+
+        StorageProviderRegistry providerRegistry = new MemoryStorageProviderRegistry();
+        final AccountManagement accountManagement = (AccountManagement) providerRegistry
+        .retrieve(AccountManagement.class);
+
+        if (!accountManagement.verifyAccountExists(localUser)) {
+            accountManagement.addUser(localUser.getFullQualifiedName(), "password1");
+        }
+
+        // S2S endpoint
+        TCPEndpoint s2sEndpoint = new TCPEndpoint();
+        s2sEndpoint.setPort(5269);
+        server.addEndpoint(s2sEndpoint);
+        
+        // C2S endpoint
+        server.addEndpoint(new TCPEndpoint());
+        
+        server.setStorageProviderRegistry(providerRegistry);
+        server.setTLSCertificateInfo(new File(keystorePath), keystorePassword);
+        
+        server.start();
+        
+        // enable server connection to use ping
+        //server.addModule(new XmppPingModule());
+
+        ServerRuntimeContext serverRuntimeContext = server.getServerRuntimeContext();
+        
+        Thread.sleep(2000);
+
+//        XMPPServerConnectorRegistry registry = serverRuntimeContext.getServerConnectorRegistry();
+//        
+//        XMPPServerConnector connector = registry.getConnector(remoteServer);
+//        
+//        Stanza stanza = new StanzaBuilder("message", NamespaceURIs.JABBER_SERVER)
+//            .addAttribute("from", localUser.getFullQualifiedName())
+//            .addAttribute("to", remoteUser.getFullQualifiedName())
+//            .startInnerElement("body", NamespaceURIs.JABBER_SERVER)
+//            .addText("Hello world")
+//            .endInnerElement()
+//            .build();
+//            
+//        connector.write(stanza);
+        
+        ConnectionConfiguration localConnectionConfiguration = new ConnectionConfiguration("localhost", 5222);
+        localConnectionConfiguration.setKeystorePath(keystorePath);
+        localConnectionConfiguration.setTruststorePath(keystorePath);
+        localConnectionConfiguration.setTruststorePassword(keystorePassword);
+        XMPPConnection localClient = new XMPPConnection(localConnectionConfiguration);
+
+        localClient.connect();
+        localClient.login(localUser.getNode(), "password1");
+        localClient.addPacketListener(new PacketListener() {
+            public void processPacket(Packet packet) {
+                System.out.println("# " + packet);
+            }
+        }, new PacketFilter() {
+            public boolean accept(Packet arg0) {
+                return true;
+            }
+        });
+        
+        
+        ConnectionConfiguration remoteConnectionConfiguration = new ConnectionConfiguration(remoteServer.getFullQualifiedName(), 5222);
+        remoteConnectionConfiguration.setKeystorePath(keystorePath);
+        remoteConnectionConfiguration.setTruststorePath(keystorePath);
+        remoteConnectionConfiguration.setTruststorePassword(keystorePassword);
+        XMPPConnection remoteClient = new XMPPConnection(remoteConnectionConfiguration);
+
+        remoteClient.connect();
+        remoteClient.login(remoteUser.getNode(), remotePassword);
+        
+        Thread.sleep(3000);
+        
+        Message msg = new Message(remoteUser.getFullQualifiedName());
+//        Message msg = new Message(localUser.getFullQualifiedName());
+        msg.setBody("Hello world");
+        
+        localClient.sendPacket(msg);
+//        remoteClient.sendPacket(msg);
+        
+        
+        Thread.sleep(8000);
+        remoteClient.disconnect();
+        localClient.disconnect();
+        
+        Thread.sleep(50000);
+        
+        server.stop();
+    }
+    
+}