From 67405dde9ba213331dab1fc46cb18c485070fd5b Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Fri, 05 Jun 2009 09:04:50 +0000
Subject: [PATCH] svn merge -r5333:5417 https://opends.dev.java.net/svn/opends/branches/b2.0

---
 opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java |  188 +++++++++++++++++++++-------------------------
 1 files changed, 87 insertions(+), 101 deletions(-)

diff --git a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java b/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
index 1360862..e28d51a 100644
--- a/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
+++ b/opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -37,7 +37,6 @@
 import static org.opends.server.util.StaticUtils.*;
 
 import java.net.InetAddress;
-import java.nio.ByteBuffer;
 import java.nio.channels.Selector;
 import java.nio.channels.SocketChannel;
 import java.security.cert.Certificate;
@@ -76,6 +75,7 @@
 import org.opends.server.monitors.OperationMonitor;
 import org.opends.server.protocols.asn1.ASN1;
 import org.opends.server.protocols.asn1.ASN1ByteChannelReader;
+import org.opends.server.protocols.asn1.ASN1Reader;
 import org.opends.server.protocols.asn1.ASN1Writer;
 import org.opends.server.types.*;
 import org.opends.server.util.TimeThread;
@@ -93,6 +93,64 @@
     TLSCapableConnection
 {
   /**
+   * A runnable whose task is to close down all IO related channels
+   * associated with a client connection after a small delay.
+   */
+  private static final class ConnectionFinalizerJob implements Runnable
+  {
+    // The client connection ASN1 reader.
+    private final ASN1Reader asn1Reader;
+
+    // The client connection socket channel.
+    private final SocketChannel socketChannel;
+
+    // Creates a new connection finalizer job.
+    private ConnectionFinalizerJob(long connectionID,
+        ASN1Reader asn1Reader, SocketChannel socketChannel)
+    {
+      this.asn1Reader = asn1Reader;
+      this.socketChannel = socketChannel;
+    }
+
+
+
+    /**
+     * {@inheritDoc}
+     */
+    public void run()
+    {
+      try
+      {
+        asn1Reader.close();
+      }
+      catch (Exception e)
+      {
+        // In general, we don't care about any exception that might be
+        // thrown here.
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+      }
+
+      try
+      {
+        socketChannel.close();
+      }
+      catch (Exception e)
+      {
+        // In general, we don't care about any exception that might be
+        // thrown here.
+        if (debugEnabled())
+        {
+          TRACER.debugCaught(DebugLogLevel.ERROR, e);
+        }
+      }
+    }
+  }
+
+
+  /**
    * The tracer object for the debug logger.
    */
   private static final DebugTracer TRACER = getTracer();
@@ -108,7 +166,7 @@
 
   // Indicates whether the Directory Server believes this connection to
   // be valid and available for communication.
-  private boolean connectionValid;
+  private volatile boolean connectionValid;
 
   // Indicates whether this connection is about to be closed. This will
   // be used to prevent accepting new requests while a disconnect is in
@@ -178,10 +236,10 @@
   // client has connected.
   private final String serverAddress;
 
-  private final ThreadLocal<WriterBuffer> cachedBuffers;
-
   private ASN1ByteChannelReader asn1Reader;
 
+  private ASN1Writer asn1Writer;
+
   private static int APPLICATION_BUFFER_SIZE = 4096;
 
   private final RedirectingByteChannel saslChannel;
@@ -205,17 +263,6 @@
 
 
   /**
-   * This class wraps the byte string buffer and ASN1 writer.
-   */
-  private static class WriterBuffer
-  {
-    ASN1Writer writer;
-    ByteStringBuilder buffer;
-  }
-
-
-
-  /**
    * Creates a new LDAP client connection with the provided information.
    *
    * @param connectionHandler
@@ -268,7 +315,6 @@
       statTracker.updateConnect();
     }
 
-    cachedBuffers = new ThreadLocal<WriterBuffer>();
     tlsChannel =
         RedirectingByteChannel.getRedirectingByteChannel(clientChannel);
     saslChannel =
@@ -754,20 +800,6 @@
   public void sendLDAPMessage(LDAPMessage message)
   {
     // Get the buffer used by this thread.
-    WriterBuffer writerBuffer = cachedBuffers.get();
-    if (writerBuffer == null)
-    {
-      writerBuffer = new WriterBuffer();
-      if (isSecure())
-      {
-        int appBufSize = activeProvider.getAppBufSize();
-        writerBuffer.writer = ASN1.getWriter(saslChannel, appBufSize);
-      }
-      else
-        writerBuffer.writer =
-                          ASN1.getWriter(saslChannel, APPLICATION_BUFFER_SIZE);
-      cachedBuffers.set(writerBuffer);
-    }
     try
     {
       // Make sure that we can only send one message at a time. This
@@ -775,8 +807,22 @@
       // requests from the client.
       synchronized (transmitLock)
       {
-        message.write(writerBuffer.writer);
-        writerBuffer.writer.flush();
+        if (asn1Writer == null)
+        {
+          if (isSecure())
+          {
+            int appBufSize = activeProvider.getAppBufSize();
+            asn1Writer = ASN1.getWriter(saslChannel, appBufSize);
+          }
+          else
+          {
+            asn1Writer =
+                ASN1.getWriter(saslChannel, APPLICATION_BUFFER_SIZE);
+          }
+        }
+
+        message.write(asn1Writer);
+        asn1Writer.flush();
         if(debugEnabled())
         {
           TRACER.debugProtocolElement(DebugLogLevel.VERBOSE,
@@ -790,7 +836,6 @@
           statTracker.updateMessageWritten(message, 4096);
         }
       }
-      // writerBuffer.buffer.clear();
     }
     catch (Exception e)
     {
@@ -944,37 +989,10 @@
       }
     }
 
-    // Close the connection to the client.
-    try
-    {
-      asn1Reader.close();
-    }
-    catch (Exception e)
-    {
-      // In general, we don't care about any exception that might be
-      // thrown here.
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-
-    try
-    {
-      clientChannel.close();
-    }
-    catch (Exception e)
-    {
-      // In general, we don't care about any exception that might be
-      // thrown here.
-      if (debugEnabled())
-      {
-        TRACER.debugCaught(DebugLogLevel.ERROR, e);
-      }
-    }
-
-    // Remove the thread local buffers.
-    cachedBuffers.remove();
+    // Enqueue the connection channels for closing by the finalizer.
+    Runnable r =
+      new ConnectionFinalizerJob(connectionID, asn1Reader, clientChannel);
+    connectionHandler.registerConnectionFinalizer(r);
 
     // NYI -- Deregister the client connection from any server components that
     // might know about it.
@@ -1434,7 +1452,11 @@
           // Decode all complete elements from the last read
           while (asn1Reader.elementAvailable())
           {
-            processLDAPMessage(LDAPReader.readMessage(asn1Reader));
+            if (!processLDAPMessage(LDAPReader.readMessage(asn1Reader)))
+            {
+              // Fatal connection error - client disconnected.
+              return false;
+            }
           }
         }
       }
@@ -1456,40 +1478,6 @@
 
 
   /**
-   * Process the information contained in the provided byte buffer as an
-   * ASN.1 element. It may take several calls to this method in order to
-   * get all the information necessary to decode a single ASN.1 element,
-   * but it may also be possible that there are multiple elements (or at
-   * least fragments of multiple elements) in a single buffer. This will
-   * fully process whatever the client provided and set up the
-   * appropriate state information to make it possible to pick up in the
-   * right place the next time around.
-   *
-   * @param buffer
-   *          The buffer containing the data to be processed. It must be
-   *          ready for reading (i.e., it should have been flipped by
-   *          the caller), and the data provided must be unencrypted
-   *          (e.g., if the client is communicating over SSL, then the
-   *          decryption should happen before calling this method).
-   * @return <CODE>true</CODE> if all the data in the provided buffer
-   *         was processed and the client connection can remain
-   *         established, or <CODE>false</CODE> if a decoding error
-   *         occurred and requests from this client should no longer be
-   *         processed. Note that if this method does return
-   *         <CODE>false</CODE>, then it must have already disconnected
-   *         the client, and upon returning the request handler should
-   *         remove it from the associated selector.
-   */
-  @Override
-  public boolean processDataRead(ByteBuffer buffer)
-  {
-    // this is no longer used.
-    return true;
-  }
-
-
-
-  /**
    * Processes the provided LDAP message read from the client and takes
    * whatever action is appropriate. For most requests, this will
    * include placing the operation in the work queue. Certain requests
@@ -2506,7 +2494,6 @@
   public void setTLSPendingProvider(ConnectionSecurityProvider provider)
   {
     tlsPendingProvider = provider;
-
   }
 
 
@@ -2522,7 +2509,6 @@
   public void setSASLPendingProvider(ConnectionSecurityProvider provider)
   {
     saslPendingProvider = provider;
-
   }
 
 

--
Gitblit v1.10.0