Revert "DIRAPI-342: Unbind/close breaks connection"
This reverts commit 125889b6e094be7659f9f448027e79029dcfa890.
diff --git a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
index b10a887..7c86a16 100644
--- a/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
+++ b/ldap/client/api/src/main/java/org/apache/directory/ldap/client/api/LdapNetworkConnection.java
@@ -42,6 +42,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.ReentrantLock;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
@@ -195,7 +196,7 @@
private long timeout = LdapConnectionConfig.DEFAULT_TIMEOUT;
/** configuration object for the connection */
- private final LdapConnectionConfig config;
+ private LdapConnectionConfig config;
/** The Socket configuration */
private SocketSessionConfig socketSessionConfig;
@@ -203,6 +204,9 @@
/** The connector open with the remote server */
private IoConnector connector;
+ /** A mutex used to avoid a double close of the connector */
+ private ReentrantLock connectorMutex = new ReentrantLock();
+
/**
* The created session, created when we open a connection with
* the Ldap server.
@@ -210,7 +214,7 @@
private IoSession ldapSession;
/** a map to hold the ResponseFutures for all operations */
- private final Map<Integer, ResponseFuture<? extends Response>> futureMap = new ConcurrentHashMap<>();
+ private Map<Integer, ResponseFuture<? extends Response>> futureMap = new ConcurrentHashMap<>();
/** list of controls supported by the server */
private List<String> supportedControls;
@@ -221,13 +225,16 @@
/** A flag indicating that the BindRequest has been issued and successfully authenticated the user */
private AtomicBoolean authenticated = new AtomicBoolean( false );
+ /** A flag indicating that the connection is connected or not */
+ private AtomicBoolean connected = new AtomicBoolean( false );
+
/** a list of listeners interested in getting notified when the
* connection's session gets closed cause of network issues
*/
private List<ConnectionClosedEventListener> conCloseListeners;
/** The Ldap codec protocol filter */
- private final IoFilter ldapProtocolFilter = new ProtocolCodecFilter( codec.getProtocolCodecFactory() );
+ private IoFilter ldapProtocolFilter = new ProtocolCodecFilter( codec.getProtocolCodecFactory() );
/** the SslFilter key */
private static final String SSL_FILTER_KEY = "sslFilter";
@@ -237,10 +244,10 @@
/** The krb5 configuration property */
private static final String KRB5_CONF = "java.security.krb5.conf";
-
- /** A future used to block any action until the handshake is completed */
+
+ /** A future used to block any action until the handhake is completed */
private HandshakeFuture handshakeFuture;
-
+
// ~~~~~~~~~~~~~~~~~ common error messages ~~~~~~~~~~~~~~~~~~~~~~~~~~
static final String TIME_OUT_ERROR = I18n.err( I18n.ERR_04170_TIMEOUT_OCCURED );
@@ -524,7 +531,7 @@
@Override
public boolean isConnected()
{
- return ( ldapSession != null ) && ldapSession.isConnected() && !ldapSession.isClosing();
+ return ( ldapSession != null ) && connected.get() && !ldapSession.isClosing();
}
@@ -562,7 +569,7 @@
throw new InvalidConnectionException( I18n.err( I18n.ERR_04104_NULL_CONNECTION_CANNOT_CONNECT ) );
}
- if ( !isConnected() )
+ if ( !connected.get() )
{
throw new InvalidConnectionException( I18n.err( I18n.ERR_04108_INVALID_CONNECTION ) );
}
@@ -817,74 +824,65 @@
closeFuture.addListener( future ->
{
- synchronized ( LdapNetworkConnection.this )
+ // Process all the waiting operations and cancel them
+ if ( LOG.isDebugEnabled() )
{
- // DIRAPI-342: Skip processing if LDAP session changed, i.e. after re-connect.
- if ( future.getSession() != ldapSession )
- {
- return;
- }
+ LOG.debug( I18n.msg( I18n.MSG_04137_NOD_RECEIVED ) );
+ }
- // Process all the waiting operations and cancel them
+ for ( ResponseFuture<?> responseFuture : futureMap.values() )
+ {
if ( LOG.isDebugEnabled() )
{
- LOG.debug( I18n.msg( I18n.MSG_04137_NOD_RECEIVED ) );
+ LOG.debug( I18n.msg( I18n.MSG_04134_CLOSING, responseFuture ) );
}
- for ( ResponseFuture<?> responseFuture : futureMap.values() )
+ responseFuture.cancel();
+
+ try
{
- if ( LOG.isDebugEnabled() )
+ if ( responseFuture instanceof AddFuture )
{
- LOG.debug( I18n.msg( I18n.MSG_04134_CLOSING, responseFuture ) );
+ ( ( AddFuture ) responseFuture ).set( AddNoDResponse.PROTOCOLERROR );
}
-
- responseFuture.cancel();
-
- try
+ else if ( responseFuture instanceof BindFuture )
{
- if ( responseFuture instanceof AddFuture )
- {
- ( ( AddFuture ) responseFuture ).set( AddNoDResponse.PROTOCOLERROR );
- }
- else if ( responseFuture instanceof BindFuture )
- {
- ( ( BindFuture ) responseFuture ).set( BindNoDResponse.PROTOCOLERROR );
- }
- else if ( responseFuture instanceof CompareFuture )
- {
- ( ( CompareFuture ) responseFuture ).set( CompareNoDResponse.PROTOCOLERROR );
- }
- else if ( responseFuture instanceof DeleteFuture )
- {
- ( ( DeleteFuture ) responseFuture ).set( DeleteNoDResponse.PROTOCOLERROR );
- }
- else if ( responseFuture instanceof ExtendedFuture )
- {
- ( ( ExtendedFuture ) responseFuture ).set( ExtendedNoDResponse.PROTOCOLERROR );
- }
- else if ( responseFuture instanceof ModifyFuture )
- {
- ( ( ModifyFuture ) responseFuture ).set( ModifyNoDResponse.PROTOCOLERROR );
- }
- else if ( responseFuture instanceof ModifyDnFuture )
- {
- ( ( ModifyDnFuture ) responseFuture ).set( ModifyDnNoDResponse.PROTOCOLERROR );
- }
- else if ( responseFuture instanceof SearchFuture )
- {
- ( ( SearchFuture ) responseFuture ).set( SearchNoDResponse.PROTOCOLERROR );
- }
+ ( ( BindFuture ) responseFuture ).set( BindNoDResponse.PROTOCOLERROR );
}
- catch ( InterruptedException e )
+ else if ( responseFuture instanceof CompareFuture )
{
- LOG.error( I18n.err( I18n.ERR_04113_ERROR_PROCESSING_NOD, responseFuture ), e );
+ ( ( CompareFuture ) responseFuture ).set( CompareNoDResponse.PROTOCOLERROR );
}
-
- futureMap.remove( messageId.get() );
+ else if ( responseFuture instanceof DeleteFuture )
+ {
+ ( ( DeleteFuture ) responseFuture ).set( DeleteNoDResponse.PROTOCOLERROR );
+ }
+ else if ( responseFuture instanceof ExtendedFuture )
+ {
+ ( ( ExtendedFuture ) responseFuture ).set( ExtendedNoDResponse.PROTOCOLERROR );
+ }
+ else if ( responseFuture instanceof ModifyFuture )
+ {
+ ( ( ModifyFuture ) responseFuture ).set( ModifyNoDResponse.PROTOCOLERROR );
+ }
+ else if ( responseFuture instanceof ModifyDnFuture )
+ {
+ ( ( ModifyDnFuture ) responseFuture ).set( ModifyDnNoDResponse.PROTOCOLERROR );
+ }
+ else if ( responseFuture instanceof SearchFuture )
+ {
+ ( ( SearchFuture ) responseFuture ).set( SearchNoDResponse.PROTOCOLERROR );
+ }
+ }
+ catch ( InterruptedException e )
+ {
+ LOG.error( I18n.err( I18n.ERR_04113_ERROR_PROCESSING_NOD, responseFuture ), e );
}
- futureMap.clear();
+ futureMap.remove( messageId.get() );
}
+
+ futureMap.clear();
} );
}
@@ -928,7 +926,7 @@
@Override
public boolean connect() throws LdapException
{
- if ( isConnected() )
+ if ( ( ldapSession != null ) && connected.get() )
{
// No need to connect if we already have a connected session
return true;
@@ -976,43 +974,34 @@
* {@inheritDoc}
*/
@Override
- public synchronized void close()
+ public void close()
{
- if ( !isConnected() )
- {
- return;
- }
-
// Close the session
- ldapSession.closeNow().awaitUninterruptibly( timeout );
- ldapSession = null;
-
- clearMaps();
+ if ( ( ldapSession != null ) && connected.get() )
+ {
+ ldapSession.closeNow();
+ connected.set( false );
+ }
// And close the connector if it has been created locally
// Release the connector
+ connectorMutex.lock();
- if ( connector != null )
+ try
{
- connector.dispose();
- connector = null;
+ if ( connector != null )
+ {
+ connector.dispose();
+ connector = null;
+ }
+ }
+ finally
+ {
+ connectorMutex.unlock();
}
// Reset the messageId
messageId.set( 0 );
-
- if ( conCloseListeners != null )
- {
- if ( LOG.isDebugEnabled() )
- {
- LOG.debug( I18n.msg( I18n.MSG_04136_NOTIFYING_CLOSE_LISTENERS ) );
- }
-
- for ( ConnectionClosedEventListener listener : conCloseListeners )
- {
- listener.connectionClosed();
- }
- }
}
@@ -2405,9 +2394,17 @@
responseFuture.cancel();
}
+ // clear the mappings
+ clearMaps();
+
// We now have to close the session
close();
+ connected.set( false );
+
+ // Last, not least, reset the MessageId value
+ messageId.set( 0 );
+
// And get out
if ( LOG.isDebugEnabled() )
{
@@ -4749,6 +4746,7 @@
codec, config.getBinaryAttributeDetector() );
session.setAttribute( LdapDecoder.MESSAGE_CONTAINER_ATTR, ldapMessageContainer );
+ connected.set( true );
}
@@ -4756,21 +4754,48 @@
* {@inheritDoc}
*/
@Override
- public synchronized void sessionClosed( IoSession session ) throws Exception
+ public void sessionClosed( IoSession session ) throws Exception
{
- // DIRAPI-342: Skip processing if LDAP session changed, i.e. after re-connect.
- if ( session != ldapSession )
- {
- return;
- }
-
// no need to handle if this session was closed by the user
- if ( !isConnected() )
+ if ( ldapSession == null || !connected.get() )
{
return;
}
- close();
+ ldapSession.closeNow();
+ connected.set( false );
+ // Reset the messageId
+ messageId.set( 0 );
+
+ connectorMutex.lock();
+
+ try
+ {
+ if ( connector != null )
+ {
+ connector.dispose();
+ connector = null;
+ }
+ }
+ finally
+ {
+ connectorMutex.unlock();
+ }
+
+ clearMaps();
+
+ if ( conCloseListeners != null )
+ {
+ if ( LOG.isDebugEnabled() )
+ {
+ LOG.debug( I18n.msg( I18n.MSG_04136_NOTIFYING_CLOSE_LISTENERS ) );
+ }
+
+ for ( ConnectionClosedEventListener listener : conCloseListeners )
+ {
+ listener.connectionClosed();
+ }
+ }
}
@@ -4876,7 +4901,7 @@
// for LDAPS/TLS
handshakeFuture = new HandshakeFuture();
- if ( !isConnected() )
+ if ( ( ldapSession == null ) || !connected.get() )
{
connector.getFilterChain().addFirst( SSL_FILTER_KEY, sslFilter );
}