mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Yannick Lecaillez
07.39.2016 09f4651f340aee430254c8b367cb9830162efe55
OPENDJ-3179: Migrate LDAP Connection Handler to SDK Grizzly transport

Fix bug in buffer management producing error while reading ldap
messages.
7 files modified
95 ■■■■ changed files
opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java 2 ●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferReader.java 1 ●●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferWriter.java 9 ●●●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyUtils.java 4 ●●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPClientFilter.java 20 ●●●● patch | view | raw | blame | history
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapCodec.java 55 ●●●●● patch | view | raw | blame | history
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ASN1BufferWriterTestCase.java 4 ●●●● patch | view | raw | blame | history
opendj-core/src/test/java/org/forgerock/opendj/ldap/LDAPServer.java
@@ -546,6 +546,6 @@
        if (!isRunning) {
            throw new IllegalStateException("Server is not running");
        }
        return (InetSocketAddress) listener.getSocketAddresses().iterator().next();
        return listener.firstSocketAddress();
    }
}
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferReader.java
@@ -150,6 +150,7 @@
    ASN1BufferReader(final int maxElementSize, final Buffer buffer) {
        this.readLimiter = new RootSequenceLimiter();
        this.buffer = buffer;
        this.buffer.allowBufferDispose(false);
        this.maxElementSize = maxElementSize;
    }
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/ASN1BufferWriter.java
@@ -139,19 +139,19 @@
    /** Default maximum size for cached protocol/entry encoding buffers. */
    private static final int DEFAULT_MAX_INTERNAL_BUFFER_SIZE = 32 * 1024;
    private final MemoryManager<Buffer> memoryManager;
    private MemoryManager<Buffer> memoryManager;
    private SequenceBuffer sequenceBuffer;
    private Buffer outBuffer;
    private final RootSequenceBuffer rootBuffer;
    /** Creates a new ASN.1 writer that writes to a StreamWriter. */
    ASN1BufferWriter(MemoryManager memoryManager) {
    ASN1BufferWriter() {
        this.rootBuffer = new RootSequenceBuffer();
        this.memoryManager = memoryManager;
    }
    /** Reset the writer. */
    void reset() {
    void reset(final MemoryManager memoryManager) {
        this.memoryManager = memoryManager;
        sequenceBuffer = rootBuffer;
        outBuffer = memoryManager.allocate(BUFFER_INIT_SIZE);
    }
@@ -189,6 +189,7 @@
    /** Recycle the writer to allow re-use. */
    @Override
    public void recycle() {
        memoryManager = null;
        sequenceBuffer = null;
        outBuffer = null;
    }
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/GrizzlyUtils.java
@@ -165,9 +165,9 @@
                ? ThreadCache.takeFromCache(WRITER_INDEX)
                : ThreadCache.takeFromCache(WRITER_INDEX_V2);
        if (writer == null) {
            writer = LDAP.getWriter(new ASN1BufferWriter(memoryManager), protocolVersion);
            writer = LDAP.getWriter(new ASN1BufferWriter(), protocolVersion);
        }
        writer.getASN1Writer().reset();
        writer.getASN1Writer().reset(memoryManager);
        return writer;
    }
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LDAPClientFilter.java
@@ -422,16 +422,26 @@
        final Buffer buffer = (Buffer) ctx.getMessage();
        try (final ASN1BufferReader reader = new ASN1BufferReader(maxASN1ElementSize, buffer)) {
            final LDAPReader<? extends ASN1Reader> ldapReader = LDAP.getReader(reader, decodeOptions);
            while (ldapReader.hasMessageAvailable()) {
                ldapReader.readMessage(handler);
            buffer.mark();
            if (!reader.elementAvailable()) {
                buffer.reset();
                return ctx.getStopAction(buffer);
            }
            buffer.shrink();
            final int length = reader.peekLength();
            final Buffer remainder = buffer.remaining() > length ? buffer.split(buffer.position() + length) : null;
            buffer.reset();
            try (final ASN1BufferReader packetReader = new ASN1BufferReader(maxASN1ElementSize, buffer)) {
                final LDAPReader<? extends ASN1Reader> ldapReader = LDAP.getReader(packetReader, decodeOptions);
                ctx.setMessage(null);
                ldapReader.readMessage(handler);
            } finally {
                buffer.tryDispose();
            }
            return ctx.getInvokeAction(remainder);
        } catch (IOException e) {
            handleReadException(ctx, e);
            throw e;
        }
        return ctx.getStopAction(buffer.hasRemaining() ? buffer : null);
    }
    private final void handleReadException(FilterChainContext ctx, IOException e) {
opendj-grizzly/src/main/java/org/forgerock/opendj/grizzly/LdapCodec.java
@@ -36,7 +36,6 @@
import org.forgerock.opendj.ldap.spi.LdapMessages.LdapRequestEnvelope;
import org.forgerock.opendj.ldap.spi.LdapMessages.LdapResponseMessage;
import org.glassfish.grizzly.Buffer;
import org.glassfish.grizzly.attributes.AttributeStorage;
import org.glassfish.grizzly.filterchain.FilterChainContext;
import org.glassfish.grizzly.filterchain.NextAction;
@@ -57,14 +56,26 @@
    public NextAction handleRead(final FilterChainContext ctx) throws IOException {
        try {
            final Buffer buffer = ctx.getMessage();
            final LdapRequestEnvelope message;
            message = readMessage(buffer, ctx.getConnection());
            if (message != null) {
                ctx.setMessage(message);
                return ctx.getInvokeAction(getRemainingBuffer(buffer));
            try (final ASN1BufferReader reader = new ASN1BufferReader(maxASN1ElementSize, buffer)) {
                buffer.mark();
                if (!reader.elementAvailable()) {
                    buffer.reset();
                    return ctx.getStopAction(buffer);
                }
                final int length = reader.peekLength();
                if (length > maxASN1ElementSize) {
                    buffer.reset();
                    throw DecodeException.fatalError(
                            ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(length, maxASN1ElementSize));
                }
                final Buffer remainder = (buffer.remaining() > length)
                        ? buffer.split(buffer.position() + length)
                        : null;
                buffer.reset();
                ctx.setMessage(decodePacket(new ASN1BufferReader(maxASN1ElementSize, buffer)));
                buffer.tryDispose();
                return ctx.getInvokeAction(remainder);
            }
            return ctx.getStopAction(getRemainingBuffer(buffer));
        } catch (Exception e) {
            onLdapCodecError(ctx, e);
            ctx.getConnection().closeSilently();
@@ -76,29 +87,7 @@
    protected abstract void onLdapCodecError(FilterChainContext ctx, Throwable error);
    private LdapRequestEnvelope readMessage(final Buffer buffer, final AttributeStorage attributeStorage)
            throws IOException {
        try (final ASN1BufferReader reader = new ASN1BufferReader(maxASN1ElementSize, buffer)) {
            final int packetStart = buffer.position();
            if (!reader.elementAvailable()) {
                buffer.position(packetStart);
                return null;
            }
            final int length = reader.peekLength();
            if (length > maxASN1ElementSize) {
                buffer.position(packetStart);
                throw DecodeException.fatalError(
                        ERR_LDAP_CLIENT_DECODE_MAX_REQUEST_SIZE_EXCEEDED.get(length, maxASN1ElementSize));
            }
            final Buffer packet = buffer.slice(packetStart, buffer.position() + length);
            buffer.position(buffer.position() + length);
            return decodePacket(new ASN1BufferReader(maxASN1ElementSize, packet), attributeStorage);
        }
    }
    private LdapRequestEnvelope decodePacket(final ASN1BufferReader reader, final AttributeStorage attributeStorage)
    private LdapRequestEnvelope decodePacket(final ASN1BufferReader reader)
            throws IOException {
        reader.mark();
        try {
@@ -138,10 +127,6 @@
        }
    }
    private Buffer getRemainingBuffer(final Buffer buffer) {
        return buffer.hasRemaining() ? buffer : null;
    }
    @Override
    public NextAction handleWrite(final FilterChainContext ctx) throws IOException {
        final LdapResponseMessage response = ctx.<LdapResponseMessage>getMessage();
opendj-grizzly/src/test/java/org/forgerock/opendj/grizzly/ASN1BufferWriterTestCase.java
@@ -35,7 +35,7 @@
@Test
public class ASN1BufferWriterTestCase extends ASN1WriterTestCase {
    private final ASN1BufferWriter writer = new ASN1BufferWriter(MemoryManager.DEFAULT_MEMORY_MANAGER);
    private final ASN1BufferWriter writer = new ASN1BufferWriter();
    @Override
    protected byte[] getEncodedBytes() throws IOException, DecodeException {
@@ -53,7 +53,7 @@
    @Override
    protected ASN1Writer getWriter() throws IOException {
        writer.flush();
        writer.reset();
        writer.reset(MemoryManager.DEFAULT_MEMORY_MANAGER);
        return writer;
    }
}