[ 
https://issues.apache.org/jira/browse/DIRMINA-1086?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Wenxiang Qiu updated DIRMINA-1086:
----------------------------------
    Description: 
I'm using ApacheDS, I found this problem and am not sure if it's a mina issue 
or an ApacheDS issue.

 

AbstractPollingIoProcessor#read looks like this:

 
{code:java}
private void read(S session) {
    IoSessionConfig config = session.getConfig();
    int bufferSize = config.getReadBufferSize();
    IoBuffer buf = IoBuffer.allocate(bufferSize);

    final boolean hasFragmentation = 
session.getTransportMetadata().hasFragmentation();

    try {
        /* omitted */

        if (ret < 0) {
            IoFilterChain filterChain = session.getFilterChain();
            filterChain.fireInputClosed();
        }
    } catch (Exception e) {
        if ((e instanceof IOException) &&
(!(e instanceof PortUnreachableException)
|| !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
|| ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable())) {
            scheduleRemove(session);
        }

        IoFilterChain filterChain = session.getFilterChain();
        filterChain.fireExceptionCaught(e);
    }
}
{code}
 

When an exception occurs with an LDAP connection, e.g. Connection reset by 
peer, catch block is entered and ExcpetionCaught gets fired:
{code:java}
filterChain.fireExceptionCaught(e);{code}
The session is thus closed by LdapProtocolHandler#exceptionCaught:
{code:java}
public void exceptionCaught( IoSession session, Throwable cause )
{
    if ( cause.getCause() instanceof ResponseCarryingMessageException )
    {
        ResponseCarryingMessageException rcme = ( 
ResponseCarryingMessageException ) cause.getCause();

        if ( rcme.getResponse() != null )
        {
            session.write( rcme.getResponse() );
            return;
        }
    }

    LOG.warn( "Unexpected exception forcing session to close: sending 
disconnect notice to client.", cause );

    session.write( NoticeOfDisconnect.PROTOCOLERROR );
    LdapSession ldapSession = 
this.ldapServer.getLdapSessionManager().removeLdapSession( session );
    cleanUpSession( ldapSession );
    session.close( true );
}
{code}
Although this session is scheduled for removal, due to its state being closing, 
AbstractPollingIoProcessor#removeSessions does nothing about this session:
{code:java}
case CLOSING:
    // Skip if channel is already closed
    // In any case, remove the session from the queue
    removedSessions++;
    break;
{code}
Consequence is that this session is kept forever in 
IoServiceListenerSupport.managedSessions, and as its size grows, this 
ConcurrentMap can take up quite a large amount of memory.

  was:
I'm using ApacheDS, I found this problem and am not sure if it's a mina issue 
or an ApacheDS issue.

 

AbstractPollingIoProcessor#read looks like this:

 
{code:java}
private void read(S session) {
    IoSessionConfig config = session.getConfig();
    int bufferSize = config.getReadBufferSize();
    IoBuffer buf = IoBuffer.allocate(bufferSize);

    final boolean hasFragmentation = 
session.getTransportMetadata().hasFragmentation();

    try {
        /* omitted */

        if (ret < 0) {
            IoFilterChain filterChain = session.getFilterChain();
            filterChain.fireInputClosed();
        }
    } catch (Exception e) {
        if ((e instanceof IOException) &&
(!(e instanceof PortUnreachableException)
|| !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
|| ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable())) {
            scheduleRemove(session);
        }

        IoFilterChain filterChain = session.getFilterChain();
        filterChain.fireExceptionCaught(e);
    }
}
{code}
 

When an exception occurs with an LDAP connection, i.e. Connection reset by 
peer, catch block is entered and ExcpetionCaught gets fired:
{code:java}
filterChain.fireExceptionCaught(e);{code}
The session is thus closed by LdapProtocolHandler#exceptionCaught:
{code:java}
public void exceptionCaught( IoSession session, Throwable cause )
{
    if ( cause.getCause() instanceof ResponseCarryingMessageException )
    {
        ResponseCarryingMessageException rcme = ( 
ResponseCarryingMessageException ) cause.getCause();

        if ( rcme.getResponse() != null )
        {
            session.write( rcme.getResponse() );
            return;
        }
    }

    LOG.warn( "Unexpected exception forcing session to close: sending 
disconnect notice to client.", cause );

    session.write( NoticeOfDisconnect.PROTOCOLERROR );
    LdapSession ldapSession = 
this.ldapServer.getLdapSessionManager().removeLdapSession( session );
    cleanUpSession( ldapSession );
    session.close( true );
}
{code}
Although this session is scheduled for removal, due to its state being closing, 
AbstractPollingIoProcessor#removeSessions does nothing about this session:
{code:java}
case CLOSING:
    // Skip if channel is already closed
    // In any case, remove the session from the queue
    removedSessions++;
    break;
{code}
Consequence is that this session is kept forever in 
IoServiceListenerSupport.managedSessions, and as its size grows, this 
ConcurrentMap can take up quite a large amount of memory.


> IoSessions closed by filterChain.fireExceptionCaught(e) are kept in memory
> --------------------------------------------------------------------------
>
>                 Key: DIRMINA-1086
>                 URL: https://issues.apache.org/jira/browse/DIRMINA-1086
>             Project: MINA
>          Issue Type: Bug
>          Components: Core
>    Affects Versions: 2.0.17
>         Environment: mina in ApacheDS
>            Reporter: Wenxiang Qiu
>            Priority: Major
>
> I'm using ApacheDS, I found this problem and am not sure if it's a mina issue 
> or an ApacheDS issue.
>  
> AbstractPollingIoProcessor#read looks like this:
>  
> {code:java}
> private void read(S session) {
>     IoSessionConfig config = session.getConfig();
>     int bufferSize = config.getReadBufferSize();
>     IoBuffer buf = IoBuffer.allocate(bufferSize);
>     final boolean hasFragmentation = 
> session.getTransportMetadata().hasFragmentation();
>     try {
>         /* omitted */
>         if (ret < 0) {
>             IoFilterChain filterChain = session.getFilterChain();
>             filterChain.fireInputClosed();
>         }
>     } catch (Exception e) {
>         if ((e instanceof IOException) &&
> (!(e instanceof PortUnreachableException)
> || !AbstractDatagramSessionConfig.class.isAssignableFrom(config.getClass())
> || ((AbstractDatagramSessionConfig) config).isCloseOnPortUnreachable())) {
>             scheduleRemove(session);
>         }
>         IoFilterChain filterChain = session.getFilterChain();
>         filterChain.fireExceptionCaught(e);
>     }
> }
> {code}
>  
> When an exception occurs with an LDAP connection, e.g. Connection reset by 
> peer, catch block is entered and ExcpetionCaught gets fired:
> {code:java}
> filterChain.fireExceptionCaught(e);{code}
> The session is thus closed by LdapProtocolHandler#exceptionCaught:
> {code:java}
> public void exceptionCaught( IoSession session, Throwable cause )
> {
>     if ( cause.getCause() instanceof ResponseCarryingMessageException )
>     {
>         ResponseCarryingMessageException rcme = ( 
> ResponseCarryingMessageException ) cause.getCause();
>         if ( rcme.getResponse() != null )
>         {
>             session.write( rcme.getResponse() );
>             return;
>         }
>     }
>     LOG.warn( "Unexpected exception forcing session to close: sending 
> disconnect notice to client.", cause );
>     session.write( NoticeOfDisconnect.PROTOCOLERROR );
>     LdapSession ldapSession = 
> this.ldapServer.getLdapSessionManager().removeLdapSession( session );
>     cleanUpSession( ldapSession );
>     session.close( true );
> }
> {code}
> Although this session is scheduled for removal, due to its state being 
> closing, AbstractPollingIoProcessor#removeSessions does nothing about this 
> session:
> {code:java}
> case CLOSING:
>     // Skip if channel is already closed
>     // In any case, remove the session from the queue
>     removedSessions++;
>     break;
> {code}
> Consequence is that this session is kept forever in 
> IoServiceListenerSupport.managedSessions, and as its size grows, this 
> ConcurrentMap can take up quite a large amount of memory.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to