opends/resource/config/config.ldif
@@ -425,6 +425,7 @@ ds-cfg-allow-tcp-reuse-address: true ds-cfg-send-rejection-notice: true ds-cfg-max-request-size: 5 megabytes ds-cfg-max-blocked-write-time-limit: 2 minutes ds-cfg-num-request-handlers: 2 ds-cfg-allow-start-tls: false ds-cfg-use-ssl: false @@ -448,6 +449,7 @@ ds-cfg-allow-tcp-reuse-address: true ds-cfg-send-rejection-notice: true ds-cfg-max-request-size: 5 megabytes ds-cfg-max-blocked-write-time-limit: 2 minutes ds-cfg-num-request-handlers: 2 ds-cfg-allow-start-tls: false ds-cfg-use-ssl: true opends/resource/schema/02-config.ldif
@@ -1642,6 +1642,10 @@ NAME 'ds-cfg-referential-integrity-base-dn' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'OpenDS Directory Server' ) attributeTypes: ( 1.3.6.1.4.1.26027.1.1.486 NAME 'ds-cfg-max-blocked-write-time-limit' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.1 NAME 'ds-cfg-access-control-handler' SUP top STRUCTURAL MUST ( cn $ ds-cfg-acl-handler-class $ ds-cfg-acl-handler-enabled ) @@ -1735,7 +1739,8 @@ ds-cfg-ssl-client-auth-policy $ ds-cfg-ssl-cert-nickname $ ds-cfg-accept-backlog $ ds-cfg-key-manager-provider-dn $ ds-cfg-trust-manager-provider-dn $ ds-cfg-ssl-protocol $ ds-cfg-ssl-cipher-suite ) X-ORIGIN 'OpenDS Directory Server' ) ds-cfg-ssl-cipher-suite $ ds-cfg-max-blocked-write-time-limit ) X-ORIGIN 'OpenDS Directory Server' ) objectClasses: ( 1.3.6.1.4.1.26027.1.2.15 NAME 'ds-cfg-entry-cache' SUP top STRUCTURAL MUST ( cn $ ds-cfg-entry-cache-class $ ds-cfg-entry-cache-enabled ) X-ORIGIN 'OpenDS Directory Server' ) opends/src/admin/defn/org/opends/server/admin/std/LDAPConnectionHandlerConfiguration.xml
@@ -521,5 +521,30 @@ </adm:profile> </adm:property> <adm:property name="max-blocked-write-time-limit" mandatory="false"> <adm:synopsis> Specifies the maximum length of time that attempts to write data to LDAP clients should be allowed to block. If an attempt to write data to a client takes longer than this length of time, then the client connection will be terminated. </adm:synopsis> <adm:default-behavior> <adm:defined> <adm:value> 2 minutes </adm:value> </adm:defined> </adm:default-behavior> <adm:syntax> <adm:duration base-unit="ms" lower-limit="0" /> </adm:syntax> <adm:profile name="ldap"> <ldap:attribute> <ldap:oid>1.3.6.1.4.1.26027.1.1.486</ldap:oid> <ldap:name>ds-cfg-max-blocked-write-time-limit</ldap:name> </ldap:attribute> </adm:profile> </adm:property> </adm:managed-object> opends/src/server/org/opends/server/api/ClientConnection.java
@@ -25,24 +25,26 @@ * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.api; import org.opends.messages.Message; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.channels.Selector; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import org.opends.messages.Message; import org.opends.server.api.plugin.IntermediateResponsePluginResult; import org.opends.server.core.DirectoryServer; import org.opends.server.core.PersistentSearch; import org.opends.server.core.PluginConfigManager; import org.opends.server.core.SearchOperation; import org.opends.server.core.NetworkGroup; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.AbstractOperation; import org.opends.server.types.Attribute; import org.opends.server.types.AttributeType; @@ -62,11 +64,9 @@ import org.opends.server.types.SearchResultReference; import org.opends.server.util.TimeThread; import static org.opends.messages.CoreMessages.*; import static org.opends.server.config.ConfigConstants.*; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import static org.opends.messages.CoreMessages.*; import static org.opends.server.util.StaticUtils.*; @@ -402,6 +402,49 @@ /** * Retrieves a {@code Selector} that may be used to ensure that * write operations complete in a timely manner, or terminate the * connection in the event that they fail to do so. This is an * optional method for client connections, and the default * implementation returns {@code null} to indicate that the maximum * blocked write time limit is not supported for this connection. * Subclasses that do wish to support this functionality should * return a valid {@code Selector} object. * * @return The {@code Selector} that may be used to ensure that * write operations complete in a timely manner, or * {@code null} if this client connection does not support * maximum blocked write time limit functionality. */ public Selector getWriteSelector() { // There will not be a write selector in the default // implementation. return null; } /** * Retrieves the maximum length of time in milliseconds that * attempts to write data to the client should be allowed to block. * A value of zero indicates there should be no limit. * * @return The maximum length of time in milliseconds that attempts * to write data to the client should be allowed to block, * or zero if there should be no limit. */ public long getMaxBlockedWriteTimeLimit() { // By default, we'll return 0, which indicates that there should // be no maximum time limit. Subclasses should override this if // they want to support a maximum blocked write time limit. return 0L; } /** * Indicates that the data in the provided buffer has been read from * the client and should be processed. The contents of the provided * buffer will be in clear-text (the data may have been passed opends/src/server/org/opends/server/extensions/NullConnectionSecurityProvider.java
@@ -30,23 +30,27 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.Iterator; import org.opends.server.api.ClientConnection; import org.opends.server.api.ConnectionSecurityProvider; import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.DirectoryException; import org.opends.server.types.DisconnectReason; import org.opends.server.types.InitializationException; import org.opends.server.types.DebugLogLevel; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import static org.opends.messages.ExtensionMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.util.StaticUtils.*; /** * This class provides an implementation of a connection security provider that * does not actually provide any security for the communication process. Any @@ -62,7 +66,6 @@ /** * The buffer size in bytes that will be used for data on this connection. */ @@ -92,7 +95,6 @@ public NullConnectionSecurityProvider() { super(); } @@ -121,20 +123,9 @@ /** * Initializes this connection security provider using the information in the * provided configuration entry. * * @param configEntry The entry that contains the configuration for this * connection security provider. * * @throws ConfigException If the provided entry does not contain an * acceptable configuration for this security * provider. * * @throws InitializationException If a problem occurs during initialization * that is not related to the provided * configuration. * {@inheritDoc} */ @Override() public void initializeConnectionSecurityProvider(ConfigEntry configEntry) throws ConfigException, InitializationException { @@ -146,9 +137,9 @@ /** * Performs any finalization that may be necessary for this connection * security provider. * {@inheritDoc} */ @Override() public void finalizeConnectionSecurityProvider() { // No implementation is required. @@ -157,10 +148,9 @@ /** * Retrieves the name used to identify this security mechanism. * * @return The name used to identify this security mechanism. * {@inheritDoc} */ @Override() public String getSecurityMechanismName() { return "NULL"; @@ -169,13 +159,9 @@ /** * Indicates whether client connections using this connection security * provider should be considered secure. * * @return <CODE>true</CODE> if client connections using this connection * security provider should be considered secure, or * <CODE>false</CODE> if not. * {@inheritDoc} */ @Override() public boolean isSecure() { // This is not a secure provider. @@ -185,21 +171,9 @@ /** * Creates a new instance of this connection security provider that will be * used to encode and decode all communication on the provided client * connection. * * @param clientConnection The client connection with which this security * provider will be associated. * @param socketChannel The socket channel that may be used to * communicate with the client. * * @return The created connection security provider instance. * * @throws DirectoryException If a problem occurs while creating a new * instance of this security provider for the * given client connection. * {@inheritDoc} */ @Override() public ConnectionSecurityProvider newInstance(ClientConnection clientConnection, SocketChannel socketChannel) @@ -212,20 +186,9 @@ /** * Indicates that the associated client connection is being closed and that * this security provider should perform any necessary processing to deal with * that. If it is indicated that the connection is still valid, then the * security provider may attempt to communicate with the client to perform a * graceful shutdown. * * @param connectionValid Indicates whether the Directory Server believes * that the client connection is still valid and may * be used for communication with the client. Note * that this may be inaccurate, or that the state of * the connection may change during the course of * this method, so the security provider must be able * to handle failures if they arise. * {@inheritDoc} */ @Override() public void disconnect(boolean connectionValid) { // No implementation is required. @@ -234,13 +197,9 @@ /** * Retrieves the size in bytes that the client should use for the byte buffer * meant to hold clear-text data read from or to be written to the client. * * @return The size in bytes that the client should use for the byte buffer * meant to hold clear-text data read from or to be written to the * client. * {@inheritDoc} */ @Override() public int getClearBufferSize() { return BUFFER_SIZE; @@ -249,13 +208,9 @@ /** * Retrieves the size in bytes that the client should use for the byte buffer * meant to hold encoded data read from or to be written to the client. * * @return The size in bytes that the client should use for the byte buffer * meant to hold encoded data read from or to be written to the * client. * {@inheritDoc} */ @Override() public int getEncodedBufferSize() { return BUFFER_SIZE; @@ -264,18 +219,9 @@ /** * Reads data from a client connection, performing any necessary negotiation * in the process. Whenever any clear-text data has been obtained, then the * connection security provider should make that available to the client by * calling the <CODE>ClientConnection.processDataRead</CODE> 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. * {@inheritDoc} */ @Override() public boolean readData() { clearBuffer.clear(); @@ -342,23 +288,9 @@ /** * Writes the data contained in the provided clear-text buffer to the client, * performing any necessary encoding in the process. It must be capable of * dealing with input buffers that are larger than the value returned by the * <CODE>getClearBufferSize</CODE> method. When this method returns, the * provided buffer should be in its original state with regard to the position * and limit. * * @param clearData The buffer containing the clear-text data to write to * the client. * * @return <CODE>true</CODE> if all the data in the provided buffer was * written to the client and the connection may remain established, * or <CODE>false</CODE> if a problem occurred and the client * connection is no longer valid. Note that if this method does * return <CODE>false</CODE>, then it must have already disconnected * the client. * {@inheritDoc} */ @Override() public boolean writeData(ByteBuffer clearData) { int position = clearData.position(); @@ -376,6 +308,14 @@ null); return false; } else if (bytesWritten == 0) { // This can happen if the server can't send data to the client (e.g., // because the client is blocked or there is a network problem. In // that case, then use a selector to perform the write, timing out and // terminating the client connection if necessary. return writeWithTimeout(clientConnection, socketChannel, clearData); } } return true; @@ -411,5 +351,143 @@ clearData.limit(limit); } } /** * Writes the contents of the provided buffer to the client, terminating the * connection if the write is unsuccessful for too long (e.g., if the client * is unresponsive or there is a network problem). If possible, it will * attempt to use the selector returned by the * {@code ClientConnection.getWriteSelector} method, but it is capable of * working even if that method returns {@code null}. * <BR><BR> * Note that this method has been written in a generic manner so that other * connection security providers can use it to send data to the client, * provided that the given buffer contains the appropriate pre-encoded * information. * <BR><BR> * Also note that the original position and limit values will not be * preserved, so if that is important to the caller, then it should record * them before calling this method and restore them after it returns. * * @param clientConnection The client connection to which the data is to be * written. * @param socketChannel The socket channel over which to write the data. * @param buffer The data to be written to the client. * * @return <CODE>true</CODE> if all the data in the provided buffer was * written to the client and the connection may remain established, * or <CODE>false</CODE> if a problem occurred and the client * connection is no longer valid. Note that if this method does * return <CODE>false</CODE>, then it must have already disconnected * the client. * * @throws IOException If a problem occurs while attempting to write data * to the client. The caller will be responsible for * catching this and terminating the client connection. */ public static boolean writeWithTimeout(ClientConnection clientConnection, SocketChannel socketChannel, ByteBuffer buffer) throws IOException { long startTime = System.currentTimeMillis(); long waitTime = clientConnection.getMaxBlockedWriteTimeLimit(); if (waitTime <= 0) { // We won't support an infinite time limit, so fall back to using // five minutes, which is a very long timeout given that we're // blocking a worker thread. waitTime = 300000L; } long stopTime = startTime + waitTime; Selector selector = clientConnection.getWriteSelector(); if (selector == null) { // The client connection does not provide a selector, so we'll fall back // to a more inefficient way that will work without a selector. while (buffer.hasRemaining() && (System.currentTimeMillis() < stopTime)) { if (socketChannel.write(buffer) < 0) { // The client connection has been closed. Disconnect and return. clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT, false, null); return false; } } if (buffer.hasRemaining()) { // If we've gotten here, then the write timed out. Terminate the client // connection. clientConnection.disconnect(DisconnectReason.IO_TIMEOUT, false, null); return false; } return true; } // Register with the selector for handling write operations. SelectionKey key = socketChannel.register(selector, SelectionKey.OP_WRITE); try { selector.select(waitTime); while (buffer.hasRemaining()) { long currentTime = System.currentTimeMillis(); if (currentTime >= stopTime) { // We've been blocked for too long. Terminate the client connection. clientConnection.disconnect(DisconnectReason.IO_TIMEOUT, false, null); return false; } else { waitTime = stopTime - currentTime; } Iterator<SelectionKey> iterator = selector.selectedKeys().iterator(); while (iterator.hasNext()) { SelectionKey k = iterator.next(); if (k.isWritable()) { int bytesWritten = socketChannel.write(buffer); if (bytesWritten < 0) { // The client connection has been closed. Disconnect and return. clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT, false, null); return false; } iterator.remove(); } } if (buffer.hasRemaining()) { selector.select(waitTime); } } return true; } finally { if (key.isValid()) { key.cancel(); selector.selectNow(); } } } } opends/src/server/org/opends/server/extensions/TLSConnectionSecurityProvider.java
@@ -25,7 +25,6 @@ * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.extensions; import org.opends.messages.Message; @@ -40,6 +39,7 @@ import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLSession; import org.opends.messages.Message; import org.opends.server.api.ClientConnection; import org.opends.server.api.ConnectionSecurityProvider; import org.opends.server.api.KeyManagerProvider; @@ -47,16 +47,16 @@ import org.opends.server.config.ConfigEntry; import org.opends.server.config.ConfigException; import org.opends.server.core.DirectoryServer; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DirectoryException; import org.opends.server.types.DisconnectReason; import org.opends.server.types.InitializationException; import org.opends.server.types.SSLClientAuthPolicy; import org.opends.server.util.SelectableCertificateKeyManager; import static org.opends.server.loggers.debug.DebugLogger.*; import org.opends.server.loggers.debug.DebugTracer; import org.opends.server.types.DebugLogLevel; import static org.opends.messages.ExtensionMessages.*; import static org.opends.server.loggers.debug.DebugLogger.*; import static org.opends.server.util.StaticUtils.*; @@ -64,7 +64,7 @@ /** * This class provides an implementation of a connection security provider that * uses SSL/TLS to encrypt the communication to and from the client. It uses * the <CODE>javax.net.ssl.SSLEngine</CODE> class to provide the actual SSL * the {@code javax.net.ssl.SSLEngine} class to provide the actual SSL * communication layer, and the Directory Server key and trust store providers * to determine which key and trust stores to use. */ @@ -132,10 +132,10 @@ /** * Creates a new instance of this connection security provider. Note that * no initialization should be done here, since it should all be done in the * <CODE>initializeConnectionSecurityProvider</CODE> method. Also note that * this instance should only be used to create new instances that are * associated with specific client connections. This instance itself should * not be used to attempt secure communication with the client. * {@code initializeConnectionSecurityProvider} method. Also note that this * instance should only be used to create new instances that are associated * with specific client connections. This instance itself should not be used * to attempt secure communication with the client. */ public TLSConnectionSecurityProvider() { @@ -276,20 +276,9 @@ /** * Initializes this connection security provider using the information in the * provided configuration entry. * * @param configEntry The entry that contains the configuration for this * connection security provider. * * @throws ConfigException If the provided entry does not contain an * acceptable configuration for this security * provider. * * @throws InitializationException If a problem occurs during initialization * that is not related to the provided * configuration. * {@inheritDoc} */ @Override() public void initializeConnectionSecurityProvider(ConfigEntry configEntry) throws ConfigException, InitializationException { @@ -314,9 +303,9 @@ /** * Performs any finalization that may be necessary for this connection * security provider. * {@inheritDoc} */ @Override() public void finalizeConnectionSecurityProvider() { // No implementation is required. @@ -325,10 +314,9 @@ /** * Retrieves the name used to identify this security mechanism. * * @return The name used to identify this security mechanism. * {@inheritDoc} */ @Override() public String getSecurityMechanismName() { return SSL_CONTEXT_INSTANCE_NAME; @@ -337,13 +325,9 @@ /** * Indicates whether client connections using this connection security * provider should be considered secure. * * @return <CODE>true</CODE> if client connections using this connection * security provider should be considered secure, or * <CODE>false</CODE> if not. * {@inheritDoc} */ @Override() public boolean isSecure() { // This should be considered secure. @@ -353,21 +337,9 @@ /** * Creates a new instance of this connection security provider that will be * used to encode and decode all communication on the provided client * connection. * * @param clientConnection The client connection with which this security * provider will be associated. * @param socketChannel The socket channel that may be used to * communicate with the client. * * @return The created connection security provider instance. * * @throws DirectoryException If a problem occurs while creating a new * instance of this security provider for the * given client connection. * {@inheritDoc} */ @Override() public ConnectionSecurityProvider newInstance(ClientConnection clientConnection, SocketChannel socketChannel) @@ -380,20 +352,9 @@ /** * Indicates that the associated client connection is being closed and that * this security provider should perform any necessary processing to deal with * that. If it is indicated that the connection is still valid, then the * security provider may attempt to communicate with the client to perform a * graceful shutdown. * * @param connectionValid Indicates whether the Directory Server believes * that the client connection is still valid and may * be used for communication with the client. Note * that this may be inaccurate, or that the state of * the connection may change during the course of * this method, so the security provider must be able * to handle failures if they arise. * {@inheritDoc} */ @Override() public void disconnect(boolean connectionValid) { if (connectionValid) @@ -468,13 +429,9 @@ /** * Retrieves the size in bytes that the client should use for the byte buffer * meant to hold clear-text data read from or to be written to the client. * * @return The size in bytes that the client should use for the byte buffer * meant to hold clear-text data read from or to be written to the * client. * {@inheritDoc} */ @Override() public int getClearBufferSize() { return clearBufferSize; @@ -483,13 +440,9 @@ /** * Retrieves the size in bytes that the client should use for the byte buffer * meant to hold encoded data read from or to be written to the client. * * @return The size in bytes that the client should use for the byte buffer * meant to hold encoded data read from or to be written to the * client. * {@inheritDoc} */ @Override() public int getEncodedBufferSize() { return sslBufferSize; @@ -498,18 +451,9 @@ /** * Reads data from a client connection, performing any necessary negotiation * in the process. Whenever any clear-text data has been obtained, then the * connection security provider should make that available to the client by * calling the <CODE>ClientConnection.processDataRead</CODE> 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. * {@inheritDoc} */ @Override() public boolean readData() { while (true) @@ -675,23 +619,9 @@ /** * Writes the data contained in the provided clear-text buffer to the client, * performing any necessary encoding in the process. It must be capable of * dealing with input buffers that are larger than the value returned by the * <CODE>getClearBufferSize</CODE> method. When this method returns, the * provided buffer should be in its original state with regard to the position * and limit. * * @param clearData The buffer containing the clear-text data to write to * the client. * * @return <CODE>true</CODE> if all the data in the provided buffer was * written to the client and the connection may remain established, * or <CODE>false</CODE> if a problem occurred and the client * connection is no longer valid. Note that if this method does * return <CODE>false</CODE>, then it must have already disconnected * the client. * {@inheritDoc} */ @Override() public boolean writeData(ByteBuffer clearData) { int originalPosition = clearData.position(); @@ -741,17 +671,16 @@ * Writes the data contained in the provided clear-text buffer to the client, * performing any necessary encoding in the process. The amount of data in * the provided buffer must be less than or equal to the value returned by the * <CODE>getClearBufferSize</CODE> method. * {@code getClearBufferSize} method. * * @param clearData The buffer containing the clear-text data to write to * the client. * * @return <CODE>true</CODE> if all the data in the provided buffer was * written to the client and the connection may remain established, * or <CODE>false</CODE> if a problem occurred and the client * connection is no longer valid. Note that if this method does * return <CODE>false</CODE>, then it must have already disconnected * the client. * @return {@code true} if all the data in the provided buffer was written to * the client and the connection may remain established, or * {@code false} if a problem occurred and the client connection is * no longer valid. Note that if this method does return * {@code false}, then it must have already disconnected the client. */ private boolean writeInternal(ByteBuffer clearData) { @@ -785,6 +714,11 @@ DisconnectReason.CLIENT_DISCONNECT, false, null); return false; } else if (bytesWritten == 0) { return NullConnectionSecurityProvider.writeWithTimeout( clientConnection, socketChannel, sslOutBuffer); } } break; @@ -885,6 +819,11 @@ DisconnectReason.CLIENT_DISCONNECT, false, null); return false; } else if (bytesWritten == 0) { return NullConnectionSecurityProvider.writeWithTimeout( clientConnection, socketChannel, sslOutBuffer); } } break; @@ -935,6 +874,11 @@ false, null); return false; } else if (bytesWritten == 0) { return NullConnectionSecurityProvider.writeWithTimeout( clientConnection, socketChannel, sslOutBuffer); } } } @@ -976,8 +920,8 @@ /** * Retrieves the set of SSL protocols that will be allowed. * * @return The set of SSL protocols that will be allowed, or * <CODE>null</CODE> if the default set will be used. * @return The set of SSL protocols that will be allowed, or {@code null} if * the default set will be used. */ public String[] getEnabledProtocols() { @@ -990,8 +934,7 @@ * Specifies the set of SSL protocols that will be allowed. * * @param enabledProtocols The set of SSL protocols that will be allowed, or * <CODE>null</CODE> if the default set will be * used. * {@code null} if the default set will be used. */ public void setEnabledProtocols(String[] enabledProtocols) { @@ -1068,8 +1011,8 @@ * listed, followed by the certificates of any issuers in the chain. * * @return The certificate chain that the client presented to the server * during the handshake process, or <CODE>null</CODE> if the client * did not present a certificate. * during the handshake process, or {@code null} if the client did * not present a certificate. */ public Certificate[] getClientCertificateChain() { opends/src/server/org/opends/server/protocols/ldap/LDAPClientConnection.java
@@ -25,22 +25,12 @@ * Portions Copyright 2006-2007 Sun Microsystems, Inc. */ package org.opends.server.protocols.ldap; import org.opends.messages.Message; import static org.opends.server.loggers.AccessLogger.logDisconnect; import static org.opends.server.loggers.ErrorLogger.logError; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.server.loggers.debug.DebugLogger.getTracer; import static org.opends.messages.ProtocolMessages.*; import org.opends.messages.MessageBuilder; import static org.opends.server.protocols.ldap.LDAPConstants.*; import static org.opends.server.util.StaticUtils.getExceptionMessage; import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; import java.net.InetAddress; import java.nio.ByteBuffer; import java.nio.channels.Selector; import java.nio.channels.SocketChannel; import java.util.ArrayList; import java.util.Collection; @@ -48,8 +38,11 @@ import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.locks.ReentrantLock; import org.opends.messages.Message; import org.opends.messages.MessageBuilder; import org.opends.server.api.ClientConnection; import org.opends.server.api.ConnectionHandler; import org.opends.server.api.ConnectionSecurityProvider; @@ -82,8 +75,6 @@ import org.opends.server.types.DebugLogLevel; import org.opends.server.types.DirectoryException; import org.opends.server.types.DisconnectReason; import org.opends.server.types.IntermediateResponse; import org.opends.server.types.Operation; import org.opends.server.types.ResultCode; @@ -91,6 +82,15 @@ import org.opends.server.types.SearchResultReference; import org.opends.server.util.TimeThread; import static org.opends.messages.ProtocolMessages.*; import static org.opends.server.loggers.AccessLogger.logDisconnect; import static org.opends.server.loggers.ErrorLogger.logError; import static org.opends.server.loggers.debug.DebugLogger.debugEnabled; import static org.opends.server.loggers.debug.DebugLogger.getTracer; import static org.opends.server.protocols.ldap.LDAPConstants.*; import static org.opends.server.util.StaticUtils.getExceptionMessage; import static org.opends.server.util.StaticUtils.stackTraceToSingleLineString; /** @@ -115,6 +115,9 @@ // The next operation ID that should be used for this connection. private AtomicLong nextOperationID; // The selector that may be used for write operations. private AtomicReference<Selector> writeSelector; // Indicates whether the Directory Server believes this connection to be // valid and available for communication. private boolean connectionValid; @@ -251,6 +254,7 @@ operationsInProgress = new ConcurrentHashMap<Integer,AbstractOperation>(); keepStats = connectionHandler.keepStats(); protocol = "LDAP"; writeSelector = new AtomicReference<Selector>(); clientAddress = clientChannel.socket().getInetAddress().getHostAddress(); clientPort = clientChannel.socket().getPort(); @@ -992,6 +996,17 @@ finalizeConnectionInternal(); // If there is a write selector for this connection, then close it. Selector selector = writeSelector.get(); if (selector != null) { try { selector.close(); } catch (Exception e) {} } // See if we should send a notification to the client. If so, then // construct and send a notice of disconnection unsolicited response. // Note that we cannot send this notification to an LDAPv2 client. @@ -1430,6 +1445,49 @@ /** * {@inheritDoc} */ @Override() public Selector getWriteSelector() { Selector selector = writeSelector.get(); if (selector == null) { try { selector = Selector.open(); if (! writeSelector.compareAndSet(null, selector)) { selector.close(); selector = writeSelector.get(); } } catch (Exception e) { if (debugEnabled()) { TRACER.debugCaught(DebugLogLevel.ERROR, e); } } } return selector; } /** * {@inheritDoc} */ @Override() public long getMaxBlockedWriteTimeLimit() { return connectionHandler.getMaxBlockedWriteTimeLimit(); } /** * 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 opends/src/server/org/opends/server/protocols/ldap/LDAPConnectionHandler.java
@@ -486,6 +486,20 @@ /** * Retrieves the maximum length of time in milliseconds that attempts to write * to LDAP client connections should be allowed to block. * * @return The maximum length of time in milliseconds that attempts to write * to LDAP client connections should be allowed to block, or zero if * there should not be any limit imposed. */ public long getMaxBlockedWriteTimeLimit() { return currentConfig.getMaxBlockedWriteTimeLimit(); } /** * Retrieves the maximum ASN.1 element value length that will be * allowed by this connection handler. *