--- old/src/java.naming/share/classes/com/sun/jndi/ldap/BerDecoder.java 2018-09-03 14:42:58.446295614 -0700 +++ new/src/java.naming/share/classes/com/sun/jndi/ldap/BerDecoder.java 2018-09-03 14:42:58.006253939 -0700 @@ -186,12 +186,16 @@ * */ private int parseIntWithTag(int tag) throws DecodeException { - - if (parseByte() != tag) { + // Ber could have been reset; + String s; + if (offset > 0) { + s = Integer.toString(buf[offset - 1] & 0xff); + } else { + s = "Empty tag"; + } throw new DecodeException("Encountered ASN.1 tag " + - Integer.toString(buf[offset - 1] & 0xff) + - " (expected tag " + Integer.toString(tag) + ")"); + s + " (expected tag " + Integer.toString(tag) + ")"); } int len = parseLength(); --- old/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java 2018-09-03 14:42:59.435389286 -0700 +++ new/src/java.naming/share/classes/com/sun/jndi/ldap/Connection.java 2018-09-03 14:42:59.053353105 -0700 @@ -408,65 +408,29 @@ /** * Reads a reply; waits until one is ready. */ - BerDecoder readReply(LdapRequest ldr) - throws IOException, NamingException { + BerDecoder readReply(LdapRequest ldr) throws IOException, NamingException { BerDecoder rber; - // Track down elapsed time to workaround spurious wakeups - long elapsedMilli = 0; - long elapsedNano = 0; - - while (((rber = ldr.getReplyBer()) == null) && - (readTimeout <= 0 || elapsedMilli < readTimeout)) - { try { - // If socket closed, don't even try - synchronized (this) { - if (sock == null) { - throw new ServiceUnavailableException(host + ":" + port + - "; socket closed"); - } - } - synchronized (ldr) { - // check if condition has changed since our last check - rber = ldr.getReplyBer(); - if (rber == null) { - if (readTimeout > 0) { // Socket read timeout is specified - long beginNano = System.nanoTime(); - - // will be woken up before readTimeout if reply is - // available - ldr.wait(readTimeout - elapsedMilli); - elapsedNano += (System.nanoTime() - beginNano); - elapsedMilli += elapsedNano / 1000_000; - elapsedNano %= 1000_000; - - } else { - // no timeout is set so we wait infinitely until - // a response is received - // http://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap.html#PROP - ldr.wait(); - } - } else { - break; - } - } + // if no timeout is set so we wait infinitely until + // a response is received + // http://docs.oracle.com/javase/8/docs/technotes/guides/jndi/jndi-ldap.html#PROP + rber = ldr.getReplyBer(readTimeout); } catch (InterruptedException ex) { throw new InterruptedNamingException( "Interrupted during LDAP operation"); } - } - if ((rber == null) && (elapsedMilli >= readTimeout)) { + if (rber == null) { abandonRequest(ldr, null); - throw new NamingException("LDAP response read timed out, timeout used:" + throw new NamingException( + "LDAP response read timed out, timeout used:" + readTimeout + "ms." ); } return rber; } - //////////////////////////////////////////////////////////////////////////// // // Methods to add, find, delete, and abandon requests made to server @@ -660,14 +624,11 @@ if (nparent) { LdapRequest ldr = pendingRequests; while (ldr != null) { - - synchronized (ldr) { - ldr.notify(); + ldr.close(); ldr = ldr.next; } } } - } if (nparent) { parent.processConnectionClosure(); } @@ -755,7 +716,7 @@ * the safest thing to do is to shut it down. */ - private Object pauseLock = new Object(); // lock for reader to wait on while paused + private final Object pauseLock = new Object(); // lock for reader to wait on while paused private boolean paused = false; // paused state of reader /* --- old/src/java.naming/share/classes/com/sun/jndi/ldap/LdapRequest.java 2018-09-03 14:43:00.229464490 -0700 +++ new/src/java.naming/share/classes/com/sun/jndi/ldap/LdapRequest.java 2018-09-03 14:42:59.864429919 -0700 @@ -29,41 +29,41 @@ import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import javax.naming.CommunicationException; +import java.util.concurrent.TimeUnit; final class LdapRequest { - LdapRequest next; // Set/read in synchronized Connection methods - int msgId; // read-only + private final static BerDecoder EOF = new BerDecoder(new byte[]{}, -1, 0); - private int gotten = 0; - private BlockingQueue replies; - private int highWatermark = -1; - private boolean cancelled = false; - private boolean pauseAfterReceipt = false; - private boolean completed = false; + LdapRequest next; // Set/read in synchronized Connection methods + final int msgId; // read-only - LdapRequest(int msgId, boolean pause) { - this(msgId, pause, -1); - } + private final BlockingQueue replies; + private volatile boolean cancelled; + private boolean completed; + private final boolean pauseAfterReceipt; LdapRequest(int msgId, boolean pause, int replyQueueCapacity) { this.msgId = msgId; this.pauseAfterReceipt = pause; if (replyQueueCapacity == -1) { - this.replies = new LinkedBlockingQueue(); + this.replies = new LinkedBlockingQueue<>(); } else { - this.replies = - new LinkedBlockingQueue(replyQueueCapacity); - highWatermark = (replyQueueCapacity * 80) / 100; // 80% capacity + this.replies = new LinkedBlockingQueue<>(8 * replyQueueCapacity / 10); } } - synchronized void cancel() { + void cancel() { cancelled = true; + replies.offer(EOF); + } - // Unblock reader of pending request - // Should only ever have at most one waiter - notify(); + synchronized void close() { + try { + replies.put(EOF); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } } synchronized boolean addReplyBer(BerDecoder ber) { @@ -87,34 +87,32 @@ // ignore } ber.reset(); - - notify(); // notify anyone waiting for reply - /* - * If a queue capacity has been set then trigger a pause when the - * queue has filled to 80% capacity. Later, when the queue has drained - * then the reader gets unpaused. - */ - if (highWatermark != -1 && replies.size() >= highWatermark) { - return true; // trigger the pause - } return pauseAfterReceipt; } - synchronized BerDecoder getReplyBer() throws CommunicationException { + BerDecoder getReplyBer(long millis) throws CommunicationException, + InterruptedException { if (cancelled) { throw new CommunicationException("Request: " + msgId + " cancelled"); } - /* - * Remove a reply if the queue is not empty. - * poll returns null if queue is empty. - */ - BerDecoder reply = replies.poll(); - return reply; + BerDecoder result = millis > 0 ? + replies.poll(millis, TimeUnit.MILLISECONDS) : replies.take(); + + if (cancelled) { + throw new CommunicationException("Request: " + msgId + + " cancelled"); + } + + if (result == LdapRequest.EOF) { + return null; + } + + return result; } - synchronized boolean hasSearchCompleted() { + boolean hasSearchCompleted() { return completed; } }