| | |
| | | import java.util.ArrayList; |
| | | import java.util.Collection; |
| | | import java.util.Iterator; |
| | | |
| | | import java.util.LinkedList; |
| | | import java.util.List; |
| | | |
| | | import org.opends.messages.Message; |
| | | import org.opends.server.api.DirectoryThread; |
| | | import org.opends.server.api.ServerShutdownListener; |
| | | import org.opends.server.core.DirectoryServer; |
| | | import org.opends.server.loggers.ErrorLogger; |
| | | import org.opends.server.loggers.debug.DebugTracer; |
| | | import org.opends.server.protocols.asn1.ASN1ByteChannelReader; |
| | | import org.opends.server.types.DebugLogLevel; |
| | | import org.opends.server.types.DisconnectReason; |
| | | import org.opends.server.types.InitializationException; |
| | |
| | | */ |
| | | private static final DebugTracer TRACER = getTracer(); |
| | | |
| | | |
| | | |
| | | |
| | | /** |
| | | * The buffer size in bytes to use when reading data from a client. |
| | | */ |
| | | public static final int BUFFER_SIZE = 8192; |
| | | |
| | | |
| | | |
| | | // Indicates whether the Directory Server is in the process of shutting down. |
| | | private volatile boolean shutdownRequested = false; |
| | | |
| | |
| | | |
| | | // The queue that will be used to hold the set of pending connections that |
| | | // need to be registered with the selector. |
| | | // TODO: revisit, see Issue 4202. |
| | | private List<LDAPClientConnection> pendingConnections = |
| | | new LinkedList<LDAPClientConnection>(); |
| | | |
| | | // Lock object for synchronizing access to the pending connections queue. |
| | | private final Object pendingConnectionsLock = new Object(); |
| | | |
| | | // The list of connections ready for request processing. |
| | | private LinkedList<LDAPClientConnection> readyConnections = |
| | | new LinkedList<LDAPClientConnection>(); |
| | | |
| | | // The selector that will be used to monitor the client connections. |
| | | private final Selector selector; |
| | | |
| | |
| | | // loop, check for new requests, then check for new connections. |
| | | while (!shutdownRequested) |
| | | { |
| | | LDAPClientConnection readyConnection = null; |
| | | while ((readyConnection = readyConnections.poll()) != null) |
| | | { |
| | | try |
| | | { |
| | | ASN1ByteChannelReader asn1Reader = readyConnection.getASN1Reader(); |
| | | boolean ldapMessageProcessed = false; |
| | | while (true) |
| | | { |
| | | if (asn1Reader.elementAvailable()) |
| | | { |
| | | if (!ldapMessageProcessed) |
| | | { |
| | | if (readyConnection.processLDAPMessage( |
| | | LDAPReader.readMessage(asn1Reader))) |
| | | { |
| | | ldapMessageProcessed = true; |
| | | } |
| | | else |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | readyConnections.add(readyConnection); |
| | | break; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | if (readyConnection.processDataRead() <= 0) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Check to see if we have any pending connections that need to be |
| | | // registered with the selector. |
| | | List<LDAPClientConnection> tmp = null; |
| | | synchronized (pendingConnectionsLock) |
| | | { |
| | | if (!pendingConnections.isEmpty()) |
| | | { |
| | | tmp = pendingConnections; |
| | | pendingConnections = new LinkedList<LDAPClientConnection>(); |
| | | } |
| | | } |
| | | |
| | | if (tmp != null) |
| | | { |
| | | for (LDAPClientConnection c : tmp) |
| | | { |
| | | try |
| | | { |
| | | SocketChannel socketChannel = c.getSocketChannel(); |
| | | socketChannel.configureBlocking(false); |
| | | socketChannel.register(selector, SelectionKey.OP_READ, c); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | c.disconnect(DisconnectReason.SERVER_ERROR, true, |
| | | ERR_LDAP_REQHANDLER_CANNOT_REGISTER.get(handlerName, |
| | | String.valueOf(e))); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Create a copy of the selection keys which can be used in a |
| | | // thread-safe manner by getClientConnections. This copy is only |
| | | // updated once per loop, so may not be accurate. |
| | |
| | | |
| | | try |
| | | { |
| | | if (! clientConnection.processDataRead()) |
| | | int readResult = clientConnection.processDataRead(); |
| | | if (readResult < 0) |
| | | { |
| | | key.cancel(); |
| | | } |
| | | if (readResult > 0) { |
| | | readyConnections.add(clientConnection); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | // Check to see if we have any pending connections that need to be |
| | | // registered with the selector. |
| | | List<LDAPClientConnection> tmp = null; |
| | | synchronized (pendingConnectionsLock) |
| | | { |
| | | if (!pendingConnections.isEmpty()) |
| | | { |
| | | tmp = pendingConnections; |
| | | pendingConnections = new LinkedList<LDAPClientConnection>(); |
| | | } |
| | | } |
| | | |
| | | if (tmp != null) |
| | | { |
| | | for (LDAPClientConnection c : tmp) |
| | | { |
| | | try |
| | | { |
| | | SocketChannel socketChannel = c.getSocketChannel(); |
| | | socketChannel.configureBlocking(false); |
| | | socketChannel.register(selector, SelectionKey.OP_READ, c); |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | if (debugEnabled()) |
| | | { |
| | | TRACER.debugCaught(DebugLogLevel.ERROR, e); |
| | | } |
| | | |
| | | c.disconnect(DisconnectReason.SERVER_ERROR, true, |
| | | ERR_LDAP_REQHANDLER_CANNOT_REGISTER.get(handlerName, |
| | | String.valueOf(e))); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | // Disconnect all active connections. |
| | |
| | | return false; |
| | | } |
| | | |
| | | |
| | | // Try to add the new connection to the queue. If it succeeds, then wake |
| | | // up the selector so it will be picked up right away. Otherwise, |
| | | // disconnect the client. |