From 943ba3cd559f1166b927a01a1763abe664e883f6 Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Mon, 09 Feb 2009 23:11:53 +0000
Subject: [PATCH] Fix for issue 3788 - Modified selector loop to remove all processed keys. - Fixed potential NullPointerException when accepting new connections when in lockdown mode.

---
 opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java |  257 +++++++++++++++++++++++++++------------------------
 1 files changed, 135 insertions(+), 122 deletions(-)

diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
index 7499f45..e8d951b 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -889,133 +889,33 @@
         // Enter a loop, waiting for new connections to arrive and
         // then accepting them as they come in.
         boolean lastIterationFailed = false;
+        int selectorState;
         while (enabled && (!shutdownRequested)) {
           try {
-            if (selector.select() > 0) {
-              Iterator<SelectionKey> iterator = selector
-                  .selectedKeys().iterator();
+            selectorState = selector.select();
 
-              while (iterator.hasNext()) {
-                SelectionKey key = iterator.next();
-                if (key.isAcceptable()) {
-                  // Accept the new client connection.
-                  ServerSocketChannel serverChannel = (ServerSocketChannel) key
-                      .channel();
-                  SocketChannel clientChannel = serverChannel
-                      .accept();
-                  LDAPClientConnection clientConnection  =
-                                          createClientConnection(clientChannel);
-                  // Check to see if the core server rejected the
-                  // connection (e.g., already too many connections
-                  // established).
-                  if (clientConnection.getConnectionID() < 0) {
-                    // The connection will have already been closed.
-                    iterator.remove();
-                    continue;
-                  }
+            // We can't rely on return value of select to deterine if any keys
+            // are ready.
+            // see http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4850373
+            Iterator<SelectionKey> iterator = selector
+                .selectedKeys().iterator();
 
-                  InetAddress clientAddr = clientConnection
-                      .getRemoteAddress();
-                  // Check to see if the client is on the denied list.
-                  // If so, then reject it immediately.
-                  if ((deniedClients.length > 0)
-                      && AddressMask.maskListContains(clientAddr
-                          .getAddress(), clientAddr.getHostName(),
-                          deniedClients)) {
-                    clientConnection.disconnect(
-                        DisconnectReason.CONNECTION_REJECTED,
-                        currentConfig.isSendRejectionNotice(),
-                        ERR_LDAP_CONNHANDLER_DENIED_CLIENT.get(
-                          clientConnection.getClientHostPort(),
-                          clientConnection.getServerHostPort()));
-
-                    iterator.remove();
-                    continue;
-                  }
-                  // Check to see if there is an allowed list and if
-                  // there is whether the client is on that list. If
-                  // not, then reject the connection.
-                  if ((allowedClients.length > 0)
-                      && (!AddressMask.maskListContains(clientAddr
-                          .getAddress(), clientAddr.getHostName(),
-                          allowedClients))) {
-                    clientConnection.disconnect(
-                        DisconnectReason.CONNECTION_REJECTED,
-                        currentConfig.isSendRejectionNotice(),
-                        ERR_LDAP_CONNHANDLER_DISALLOWED_CLIENT.get(
-                          clientConnection.getClientHostPort(),
-                          clientConnection.getServerHostPort()));
-                    iterator.remove();
-                    continue;
-                  }
-                  clientChannel.socket().setKeepAlive(
-                      currentConfig.isUseTCPKeepAlive());
-                  clientChannel.socket().setTcpNoDelay(
-                      currentConfig.isUseTCPNoDelay());
-
-                  // If we've gotten here, then we'll take the
-                  // connection so invoke the post-connect plugins and
-                  // register the client connection with a request
-                  // handler.
-                  try {
-                    PluginConfigManager pluginManager = DirectoryServer
-                        .getPluginConfigManager();
-                    PluginResult.PostConnect pluginResult = pluginManager
-                        .invokePostConnectPlugins(clientConnection);
-                    if (!pluginResult.continueProcessing()) {
-                      clientConnection.disconnect(
-                          pluginResult.getDisconnectReason(),
-                          pluginResult.sendDisconnectNotification(),
-                          pluginResult.getErrorMessage());
-
-                      iterator.remove();
-                      continue;
-                    }
-
-                    LDAPRequestHandler requestHandler =
-                      requestHandlers[requestHandlerIndex++];
-                    if (requestHandlerIndex >= numRequestHandlers) {
-                      requestHandlerIndex = 0;
-                    }
-
-                    if (requestHandler
-                        .registerClient(clientConnection)) {
-                      logConnect(clientConnection);
-                    } else {
-                      iterator.remove();
-                      continue;
-                    }
-                  } catch (Exception e) {
-                    if (debugEnabled())
-                    {
-                      TRACER.debugCaught(DebugLogLevel.ERROR, e);
-                    }
-
-                    Message message =
-                      INFO_LDAP_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT.
-                          get(clientConnection.getClientHostPort(),
-                              clientConnection.getServerHostPort(),
-                              getExceptionMessage(e));
-                    logError(message);
-
-                    clientConnection.disconnect(
-                        DisconnectReason.SERVER_ERROR, currentConfig
-                            .isSendRejectionNotice(), message);
-
-                    iterator.remove();
-                    continue;
-                  }
-                }
-
-                iterator.remove();
+            while (iterator.hasNext()) {
+              SelectionKey key = iterator.next();
+              iterator.remove();
+              if (key.isAcceptable()) {
+                acceptConnection(key);
               }
-            } else {
-              if (shutdownRequested) {
-                cleanUpSelector();
-                selector.close();
-                listening = false;
-                enabled = false;
-                continue;
+
+              if(selectorState == 0 && enabled && (!shutdownRequested) &&
+                  debugEnabled())
+              {
+                // Selected keys was non empty but select() returned 0.
+                // Log warning and hope it blocks on the next select() call.
+                TRACER.debugWarning("Selector.select() returned 0. " +
+                    "Selected Keys: %d, Interest Ops: %d, Ready Ops: %d ",
+                    selector.selectedKeys().size(), key.interestOps(),
+                    key.readyOps());
               }
             }
 
@@ -1057,6 +957,14 @@
             }
           }
         }
+
+        if (shutdownRequested) {
+          cleanUpSelector();
+          selector.close();
+          listening = false;
+          enabled = false;
+        }
+
       } catch (Exception e) {
         if (debugEnabled())
         {
@@ -1086,7 +994,112 @@
     }
   }
 
+  private void acceptConnection(SelectionKey key)
+      throws IOException, DirectoryException
+  {
+    // Accept the new client connection.
+    ServerSocketChannel serverChannel = (ServerSocketChannel) key
+        .channel();
+    SocketChannel clientChannel = serverChannel
+        .accept();
 
+    if(clientChannel == null)
+    {
+      // There wasn't a connection pending.
+      return;
+    }
+
+    LDAPClientConnection clientConnection  =
+        createClientConnection(clientChannel);
+    // Check to see if the core server rejected the
+    // connection (e.g., already too many connections
+    // established).
+    if (clientConnection.getConnectionID() < 0) {
+      // The connection will have already been closed.
+      return;
+    }
+
+    InetAddress clientAddr = clientConnection
+        .getRemoteAddress();
+    // Check to see if the client is on the denied list.
+    // If so, then reject it immediately.
+    if ((deniedClients.length > 0)
+        && AddressMask.maskListContains(clientAddr
+        .getAddress(), clientAddr.getHostName(),
+        deniedClients)) {
+      clientConnection.disconnect(
+          DisconnectReason.CONNECTION_REJECTED,
+          currentConfig.isSendRejectionNotice(),
+          ERR_LDAP_CONNHANDLER_DENIED_CLIENT.get(
+              clientConnection.getClientHostPort(),
+              clientConnection.getServerHostPort()));
+      return;
+    }
+    // Check to see if there is an allowed list and if
+    // there is whether the client is on that list. If
+    // not, then reject the connection.
+    if ((allowedClients.length > 0)
+        && (!AddressMask.maskListContains(clientAddr
+        .getAddress(), clientAddr.getHostName(),
+        allowedClients))) {
+      clientConnection.disconnect(
+          DisconnectReason.CONNECTION_REJECTED,
+          currentConfig.isSendRejectionNotice(),
+          ERR_LDAP_CONNHANDLER_DISALLOWED_CLIENT.get(
+              clientConnection.getClientHostPort(),
+              clientConnection.getServerHostPort()));
+      return;
+    }
+    clientChannel.socket().setKeepAlive(
+        currentConfig.isUseTCPKeepAlive());
+    clientChannel.socket().setTcpNoDelay(
+        currentConfig.isUseTCPNoDelay());
+
+    // If we've gotten here, then we'll take the
+    // connection so invoke the post-connect plugins and
+    // register the client connection with a request
+    // handler.
+    try {
+      PluginConfigManager pluginManager = DirectoryServer
+          .getPluginConfigManager();
+      PluginResult.PostConnect pluginResult = pluginManager
+          .invokePostConnectPlugins(clientConnection);
+      if (!pluginResult.continueProcessing()) {
+        clientConnection.disconnect(
+            pluginResult.getDisconnectReason(),
+            pluginResult.sendDisconnectNotification(),
+            pluginResult.getErrorMessage());
+        return;
+      }
+
+      LDAPRequestHandler requestHandler =
+          requestHandlers[requestHandlerIndex++];
+      if (requestHandlerIndex >= numRequestHandlers) {
+        requestHandlerIndex = 0;
+      }
+
+      if (requestHandler
+          .registerClient(clientConnection)) {
+        logConnect(clientConnection);
+      }
+    } catch (Exception e) {
+      if (debugEnabled())
+      {
+        TRACER.debugCaught(DebugLogLevel.ERROR, e);
+      }
+
+      Message message =
+          INFO_LDAP_CONNHANDLER_UNABLE_TO_REGISTER_CLIENT.
+              get(clientConnection.getClientHostPort(),
+                  clientConnection.getServerHostPort(),
+                  getExceptionMessage(e));
+      logError(message);
+
+      clientConnection.disconnect(
+          DisconnectReason.SERVER_ERROR, currentConfig
+              .isSendRejectionNotice(), message);
+    }
+  }
 
   /**
    * Appends a string representation of this connection handler to the

--
Gitblit v1.10.0