提交 63caf01b 编写于 作者: R robm

8129957: Deadlock in JNDI LDAP implementation when closing the LDAP context

Reviewed-by: vinnie
上级 37b07e03
...@@ -494,16 +494,14 @@ public final class LdapClient implements PooledConnection { ...@@ -494,16 +494,14 @@ public final class LdapClient implements PooledConnection {
*/ */
void processConnectionClosure() { void processConnectionClosure() {
// Notify listeners // Notify listeners
synchronized (unsolicited) { if (unsolicited.size() > 0) {
if (unsolicited.size() > 0) { String msg;
String msg; if (conn != null) {
if (conn != null) { msg = conn.host + ":" + conn.port + " connection closed";
msg = conn.host + ":" + conn.port + " connection closed"; } else {
} else { msg = "Connection closed";
msg = "Connection closed";
}
notifyUnsolicited(new CommunicationException(msg));
} }
notifyUnsolicited(new CommunicationException(msg));
} }
// Remove from pool // Remove from pool
...@@ -1499,13 +1497,8 @@ public final class LdapClient implements PooledConnection { ...@@ -1499,13 +1497,8 @@ public final class LdapClient implements PooledConnection {
if (debug > 0) { if (debug > 0) {
System.err.println("LdapClient.removeUnsolicited" + ctx); System.err.println("LdapClient.removeUnsolicited" + ctx);
} }
synchronized (unsolicited) {
if (unsolicited.size() == 0) {
return;
}
unsolicited.removeElement(ctx); unsolicited.removeElement(ctx);
} }
}
// NOTE: Cannot be synchronized because this is called asynchronously // NOTE: Cannot be synchronized because this is called asynchronously
// by the reader thread in Connection. Instead, sync on 'unsolicited' Vector. // by the reader thread in Connection. Instead, sync on 'unsolicited' Vector.
...@@ -1513,30 +1506,35 @@ public final class LdapClient implements PooledConnection { ...@@ -1513,30 +1506,35 @@ public final class LdapClient implements PooledConnection {
if (debug > 0) { if (debug > 0) {
System.err.println("LdapClient.processUnsolicited"); System.err.println("LdapClient.processUnsolicited");
} }
synchronized (unsolicited) { try {
try { // Parse the response
// Parse the response LdapResult res = new LdapResult();
LdapResult res = new LdapResult();
ber.parseSeq(null); // init seq
ber.parseSeq(null); // init seq ber.parseInt(); // msg id; should be 0; ignored
ber.parseInt(); // msg id; should be 0; ignored if (ber.parseByte() != LDAP_REP_EXTENSION) {
if (ber.parseByte() != LDAP_REP_EXTENSION) { throw new IOException(
throw new IOException( "Unsolicited Notification must be an Extended Response");
"Unsolicited Notification must be an Extended Response"); }
} ber.parseLength();
ber.parseLength(); parseExtResponse(ber, res);
parseExtResponse(ber, res);
if (DISCONNECT_OID.equals(res.extensionId)) { if (DISCONNECT_OID.equals(res.extensionId)) {
// force closing of connection // force closing of connection
forceClose(pooled); forceClose(pooled);
} }
LdapCtx first = null;
UnsolicitedNotification notice = null;
synchronized (unsolicited) {
if (unsolicited.size() > 0) { if (unsolicited.size() > 0) {
first = unsolicited.elementAt(0);
// Create an UnsolicitedNotification using the parsed data // Create an UnsolicitedNotification using the parsed data
// Need a 'ctx' object because we want to use the context's // Need a 'ctx' object because we want to use the context's
// list of provider control factories. // list of provider control factories.
UnsolicitedNotification notice = new UnsolicitedResponseImpl( notice = new UnsolicitedResponseImpl(
res.extensionId, res.extensionId,
res.extensionValue, res.extensionValue,
res.referrals, res.referrals,
...@@ -1544,42 +1542,45 @@ public final class LdapClient implements PooledConnection { ...@@ -1544,42 +1542,45 @@ public final class LdapClient implements PooledConnection {
res.errorMessage, res.errorMessage,
res.matchedDN, res.matchedDN,
(res.resControls != null) ? (res.resControls != null) ?
unsolicited.elementAt(0).convertControls(res.resControls) : first.convertControls(res.resControls) :
null); null);
}
}
// Fire UnsolicitedNotification events to listeners if (notice != null) {
notifyUnsolicited(notice); // Fire UnsolicitedNotification events to listeners
notifyUnsolicited(notice);
// If "disconnect" notification, // If "disconnect" notification,
// notify unsolicited listeners via NamingException // notify unsolicited listeners via NamingException
if (DISCONNECT_OID.equals(res.extensionId)) { if (DISCONNECT_OID.equals(res.extensionId)) {
notifyUnsolicited( notifyUnsolicited(
new CommunicationException("Connection closed")); new CommunicationException("Connection closed"));
}
} }
} catch (IOException e) { }
if (unsolicited.size() == 0) } catch (IOException e) {
return; // no one registered; ignore NamingException ne = new CommunicationException(
"Problem parsing unsolicited notification");
NamingException ne = new CommunicationException( ne.setRootCause(e);
"Problem parsing unsolicited notification");
ne.setRootCause(e);
notifyUnsolicited(ne); notifyUnsolicited(ne);
} catch (NamingException e) { } catch (NamingException e) {
notifyUnsolicited(e); notifyUnsolicited(e);
}
} }
} }
private void notifyUnsolicited(Object e) { private void notifyUnsolicited(Object e) {
for (int i = 0; i < unsolicited.size(); i++) { Vector<LdapCtx> unsolicitedCopy;
unsolicited.elementAt(i).fireUnsolicited(e); synchronized (unsolicited) {
unsolicitedCopy = new Vector<>(unsolicited);
if (e instanceof NamingException) {
unsolicited.setSize(0); // no more listeners after exception
}
} }
if (e instanceof NamingException) { for (int i = 0; i < unsolicitedCopy.size(); i++) {
unsolicited.setSize(0); // no more listeners after exception unsolicitedCopy.elementAt(i).fireUnsolicited(e);
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册