/*!
  @file           RTEThread_ConsoleConnectionList.cpp
  @author         StefanP
  @special area   Kernel Console Thread
  @brief          Connection List
  @see            

\if EMIT_LICENCE
    ========== licence begin  GPL
    Copyright (c) 2002-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end

\endif
*/




/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include    "RunTime/RTE_CompilerFeatures.h"
#include    "RunTime/Threading/RTEThread_ConsoleConnectionList.h"
#include    "RunTime/System/RTESys_Time.h"
#include    "RunTime/Threading/RTEThread_ConsoleWorkerBase.hpp"
#include    "RunTime/Threading/RTEThread_ConsoleStandardWorker.hpp"
#include    "SAPDBCommon/Tracing/SAPDBTrace_Topic.hpp"
#include    "SAPDBCommon/Tracing/SAPDBTrace_Usage.hpp"
#include    "RunTime/RTE_MessageList.hpp"
#include    "RunTime/RTE_Message.hpp"
#include    "RunTime/RTE_Console_Thread_Messages.hpp"
#include    "RunTime/System/RTESys_ProcessState.hpp"



extern SAPDBTrace_Topic Console_Trace;

/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/



/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/



/*===========================================================================*
 *  LOCAL CLASSES, STRUCTURES, TYPES, UNIONS ...                             *
 *===========================================================================*/

/*===========================================================================*
 *  STATIC/INLINE FUNCTION PROTOTYPES                                        *
 *===========================================================================*/
RTEThread_ConsoleConnectionList   *RTEThread_ConsoleConnectionList::m_Instance = NULL;


/*===========================================================================*
 *  METHODS                                                                  *
 *===========================================================================*/


/*===========================================================================*
 *  RTEThread_ConsoleConnectionListItem                                      *
 *===========================================================================*/

RTEThread_ConsoleConnectionListItem::RTEThread_ConsoleConnectionListItem () 
:   m_Handle (CONNECTION_LIST_ITEM_INVALID),
    m_RemotePID (RTE_UNDEF_PID)
{
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionListItem::RTEThread_ConsoleConnectionListItem", 
                             Console_Trace, 9);
    sqlcreatemutex(&m_ConnectionListItemMutex);
}

/*---------------------------------------------------------------------------*/

RTEThread_ConsoleConnectionListItem::~RTEThread_ConsoleConnectionListItem ()
{
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionListItem::~RTEThread_ConsoleConnectionListItem", 
                             Console_Trace, 9);

    if (CONNECTION_LIST_ITEM_FREE != m_Handle && CONNECTION_LIST_ITEM_INVALID != m_Handle)
    {
        //In that case the pointer pWorker must point to a valid worker!!!
        destroy (m_Next.pWorker, RTEMem_Allocator::Instance());
    }

    sqldestroymutex(&m_ConnectionListItemMutex);
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool    RTEThread_ConsoleConnectionListItem::SetFree 
(
    RTEThread_ConsoleConnectionListItem   *    const        pNextFree,
    SAPDBErr_MessageList                                &   messageList
)     
{
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionListItem::SetFree", 
                             Console_Trace, 1);

    if (CONNECTION_LIST_ITEM_FREE != m_Handle)
    {   //Item has to be initialized or holds a connection
        if (CONNECTION_LIST_ITEM_INVALID != m_Handle)
        {
            destroy (m_Next.pWorker, RTEMem_Allocator::Instance());
        }

        m_Handle    = CONNECTION_LIST_ITEM_FREE; 
        m_RemotePID = RTE_UNDEF_PID;
        m_Next.pFreeItem  = pNextFree;
        return true;
    }
    else
    {
        messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEWARN_THREAD_CONS_FREE);
        return false;
    }
}

/*---------------------------------------------------------------------------*/

SAPDB_UInt4    RTEThread_ConsoleConnectionListItem::Initialize 
(
    RTE_ConsoleOpenData         const   &   openData,
    SAPDB_UInt4                 const       connectionSlot,
    SAPDB_UInt4                 const       remoteRef,  
    SAPDBErr_MessageList                &   messageList
)
{
   /*===========================================================================*
    *  Locals                                                                   *
    *===========================================================================*/
   /*===========================================================================*
    *  Instructions                                                             *
    *===========================================================================*/
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionListItem::Initialize", 
                             Console_Trace, 1);

    if (CONNECTION_LIST_ITEM_FREE == m_Handle)
    {
        switch (openData.commType)
        {
            case RTE_CONS_COM_STANDARD:
                m_Next.pWorker = new (RTEMem_Allocator::Instance()) RTEThread_ConsoleStandardWorker
                                                (RTE_CONSOLE_SERVER_MODE, openData.pid, connectionSlot, remoteRef);
                                                                        
                if (NULL == m_Next.pWorker)
                {
                    messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_SYS_ALLOC_INST, 
                                                                     "RTEThread_ConsoleStandardWorker");       
                    return RTE_CONS_ERROR;
                }

                break;
    /* Example:
    A support for a other communication types, e.g. XML, may be included at this point
            case RTE_CONS_COM_XML:
                break;
    */
            default:
                messageList = messageList + SAPDBErr_MessageList (RTE_CONTEXT, 
                                                                  RTEERR_THREAD_CONS_COMMUNICATION_TYPE, 
                                                                  SAPDB_ToString (openData.commType));
                return RTE_CONS_ERROR;
        }

        m_Handle    = RTEThread_ConsoleConnectionList::Instance ().IncrementConnectionCounter (); 
        m_RemotePID = openData.pid;
        
        /*
        RTE_Message (SAPDBErr_MessageList(RTE_CONTEXT, RTEINFO_THREAD_CONS_CREATE_CONNECTION, 
                                          SAPDB_ToString (m_Handle),
                                          SAPDB_ToString (openData.pid),
                                          SAPDB_ToString (remoteRef),
                                          SAPDB_ToString (connectionSlot)));
        */
        SAPDBTRACE_WRITELN(Console_Trace, 5, "Client PID " << (SAPDB_UInt8)openData.pid
                                             << ", Ref. "  << remoteRef << ":"      
                                             << " Create connection " << m_Handle << " at slot " << connectionSlot);

        if (!m_Next.pWorker->Initialize (openData.consoleShmID, 
                                         messageList))
        {
            messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_THREAD_CONS_INIT_WORKER);
            return RTE_CONS_ERROR;
        }
    }
    else
    {
        messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_THREAD_CONS_CONNECTION_IN_USE, 
                                                         SAPDB_ToString (m_Handle));       
        //Should not be happen: Fatal error
        return (RTE_CONS_FATAL_ERROR);
    }

    return (RTE_CONS_NO_ERROR);
}


/*===========================================================================*
 *  RTEThread_ConsoleConnectionList                                          *
 *===========================================================================*/
RTEThread_ConsoleConnectionList::RTEThread_ConsoleConnectionList 
()  :    m_ConnectionCounter (0),
         m_ConnectionList (NULL),
         m_FreeList (NULL),
         m_NumConnections (0) 
{
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionList::RTEThread_ConsoleConnectionList", 
                              Console_Trace, 9);
    sqlcreatemutex(&m_ConnectionListMutex);
}

/*---------------------------------------------------------------------------*/

RTEThread_ConsoleConnectionList::~RTEThread_ConsoleConnectionList()
{
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionList::~RTEThread_ConsoleConnectionList", 
                             Console_Trace, 9);
    if (NULL != m_ConnectionList)
    {
        destroyarray (m_ConnectionList, RTE_MAX_CONSOLE_CONNECTION, RTEMem_Allocator::Instance());       
    }

    sqldestroymutex(&m_ConnectionListMutex);
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool    RTEThread_ConsoleConnectionList::Initialize (SAPDBErr_MessageList        &   messageList)
{
   /*===========================================================================*
    *  Locals                                                                   *
    *===========================================================================*/

   /*===========================================================================*
    *  Instructions                                                             *
    *===========================================================================*/
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionList::Initialize", 
                             Console_Trace, 1);

    newarray (m_ConnectionList, RTE_MAX_CONSOLE_CONNECTION, RTEMem_Allocator::Instance());
    if (NULL == m_ConnectionList)
    {
        messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_SYS_ALLOC_ARRAY_INST, 
                                            SAPDB_ToString (RTE_MAX_CONSOLE_CONNECTION),
                                            "RTEThread_ConsoleConnectionListItem");
        return false;
    }

    m_FreeList = m_ConnectionList;
    //initialize the hole list as a free list
    for (SAPDB_UInt4 idx = 0; idx < RTE_MAX_CONSOLE_CONNECTION - 1; idx++)
    {
        if (!(m_ConnectionList + idx)->SetFree (m_ConnectionList + idx + 1, messageList))
        {
            messageList = messageList + SAPDBErr_MessageList (RTE_CONTEXT, RTEERR_THREAD_CONS_SET_FREE_CONNECTION, 
                                                              SAPDB_ToString (idx));
            return false;
        }
    }

    //Next pointer of the last element of the list has to be set to NULL
    if (!(m_ConnectionList + RTE_MAX_CONSOLE_CONNECTION - 1)->SetFree (NULL, messageList))
    {
        messageList = messageList + SAPDBErr_MessageList (RTE_CONTEXT, RTEERR_THREAD_CONS_SET_FREE_CONNECTION, 
                                                          SAPDB_ToString (RTE_MAX_CONSOLE_CONNECTION - 1));
        return false;
    }

    return true;
}

/*---------------------------------------------------------------------------*/

RTEThread_ConsoleConnectionList & RTEThread_ConsoleConnectionList::Instance()
{
   /*===========================================================================*
    *  Locals                                                                   *
    *===========================================================================*/
    SAPDBErr_MessageList    messageList;
   /*===========================================================================*
    *  Instructions                                                             *
    *===========================================================================*/
    SAPDBTRACE_ROUTINE_DEBUG("RTEThread_ConsoleConnectionList::Instance", Console_Trace, 9);

    if (NULL == m_Instance)
    {
        SAPDBTRACE_WRITELN(Console_Trace, 1, "Creation of connection list");
        m_Instance = new (RTEMem_Allocator::Instance()) RTEThread_ConsoleConnectionList();

        if (NULL == m_Instance)
        {
            RTE_Crash (SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_SYS_ALLOC_INST, "RTEThread_ConsoleConnectionList"));
        }

        if (!m_Instance->Initialize (messageList))
        {
            messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_THREAD_CONS_INIT_CONNECT_LIST);
            RTE_Crash (messageList);
        }
    }
 
  return *m_Instance;
}

/*---------------------------------------------------------------------------*/

SAPDB_UInt4  RTEThread_ConsoleConnectionList::OpenConnection
(
    SAPDB_UInt4 const                           openMode,
    RTEThread_ConsoleRequest const &            requestData,
    SAPDB_UInt4 const                           index,
    RTEThread_ConsoleConnectionListItem **      ppConnectionItem,      
    SAPDBErr_MessageList &                      messageList 
)  
{
   /*===========================================================================*
    *  Locals                                                                   *
    *===========================================================================*/
    RTEThread_ConsoleConnectionListItem    *pNext;
    RTEThread_ConsoleWorkerBase            *pWorker; 
    SAPDB_UInt4                             rc;
    SAPDB_UInt4                             connectionSlot;

   /*===========================================================================*
    *  Instructions                                                             *
    *===========================================================================*/
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionList::OpenConnection", 
                             Console_Trace, 1);

    if (RTE_CREATE_NEW == openMode)
    {
        //Look for a free connection slot
        Lock ();
    
        if (NULL != m_FreeList)
        {
            *ppConnectionItem = m_FreeList;
            connectionSlot = (SAPDB_UInt4)(m_FreeList - m_ConnectionList);
            if (!m_FreeList->GetNextFreeConnectListItem (&pNext))
            {
                //First item of free list is not free => Inconsistency!!!
                Unlock ();
                messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_THREAD_CONS_FREE_LIST_INCONSIST);       
                return (RTE_CONS_FATAL_ERROR);
            }
            else
            {
                m_FreeList = pNext;
            }

            ++m_NumConnections;
        }
        else
        {
            Unlock ();
            messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_THREAD_CONS_NO_FREE_CONNECTION,
                                                             SAPDB_ToString (requestData.data.connectData.pid), 
                                                             SAPDB_ToString (requestData.senderRef));       
            return RTE_CONS_ERROR;
        }
        
        Unlock ();

        SAPDBTRACE_WRITELN(Console_Trace, 9, "Number of connected clients: " << m_NumConnections);
            
        rc = (*ppConnectionItem)->Initialize (requestData.data.connectData, 
                                              connectionSlot, 
                                              requestData.senderRef,
                                              messageList);

        if (RTE_CONS_NO_ERROR != rc)
        {
            messageList = messageList + SAPDBErr_MessageList(RTE_CONTEXT, RTEERR_THREAD_CONS_INIT_CONNECT_SLOT,
                                                             SAPDB_ToString (connectionSlot));

            if (RTE_CONS_FATAL_ERROR != rc)
            {
                if (!ReleaseConnection (*ppConnectionItem, requestData.senderRef, messageList))
                {

                    //=> (SetFree () == false) => m_Handle == CONNECTION_LIST_ITEM_FREE
                    //=> No initialization has been done for this item (connection slot)
                    //   Particularly no worker was allocated

                    //Therefor we have just to add the item back to the Free list:
                    (*ppConnectionItem)->SetNextFreeConnectListItem (m_FreeList);
                    m_FreeList    = *ppConnectionItem;
                    --m_NumConnections;
                }
            }

            SAPDBTRACE_WRITELN(Console_Trace, 5, "Client PID " << (SAPDB_UInt8)requestData.data.connectData.pid
                                                 << ", Ref. "  << requestData.senderRef << ":"      
                                                 << " Open connection to slot " << connectionSlot << "aborted");
            SAPDBTRACE_WRITELN(Console_Trace, 9, "Number of connected clients: " << m_NumConnections);

            return rc;
        }

#if defined (LINUX)
 		pWorker = (*ppConnectionItem)->GetWorker ();
#endif

        SAPDBTRACE_WRITELN(Console_Trace, 5, "Client PID " << (SAPDB_UInt8)requestData.data.connectData.pid
                                             << ", Ref. "  << requestData.senderRef << ":"      
                                             << "Connection handle " << (*ppConnectionItem)->GetHandle ());
    }
    else    //RTE_OPEN_EXISTING
    {
        *ppConnectionItem = m_ConnectionList + requestData.receiverRef;
        (*ppConnectionItem)->Lock ();

        //Is wanted connection still open
        if (NULL == (pWorker = (*ppConnectionItem)->GetWorker ()) 
            || requestData.data.hConnect != (*ppConnectionItem)->GetHandle ())
        {
            (*ppConnectionItem)->Unlock ();
            messageList = messageList + SAPDBErr_MessageList (RTE_CONTEXT, RTEWARN_THREAD_CONS_CONNECT_EXISTING, 
                                                              SAPDB_ToString (requestData.data.hConnect), 
                                                              SAPDB_ToString((*ppConnectionItem)->GetHandle ())); 
            SAPDBTRACE_WRITELN(Console_Trace, 5, "Client connect to slot " 
                                                 << requestData.receiverRef 
                                                 << " failed: Connection handle " 
                                                 << requestData.data.hConnect
                                                 << " does not exist anymore");

            return RTE_CONS_ERROR;
        }

        pWorker->SetBusyState (true);
        pWorker->SetConsoleLastAccessTime ();
        (*ppConnectionItem)->Unlock ();
/*
        RTE_Message (SAPDBErr_MessageList(RTE_CONTEXT, RTEINFO_THREAD_CONS_OPEN_CONNECTION, 
                                          SAPDB_ToString ((*ppConnectionItem)->GetHandle ()),
                                          SAPDB_ToString ((*ppConnectionItem)->GetRemotePID ()),
                                          SAPDB_ToString (requestData.senderRef),
                                          SAPDB_ToString (requestData.receiverRef)));
*/
        SAPDBTRACE_WRITELN(Console_Trace, 5, "Client PID " << (SAPDB_UInt8)((*ppConnectionItem)->GetRemotePID ())
                                             << ", Ref. "  << requestData.senderRef << ":"      
                                             << "Open connection " << requestData.data.hConnect 
                                             << " at slot " << requestData.receiverRef);
    }

#if defined (LINUX)
    pWorker->SetThreadIndex (index);
#endif

    return RTE_CONS_NO_ERROR;
}

/*---------------------------------------------------------------------------*/

SAPDB_Bool   RTEThread_ConsoleConnectionList::ReleaseConnection
(
    RTEThread_ConsoleConnectionListItem     *   const   pConnectionItem,
    SAPDB_UInt4                                 const   remoteRef,
    SAPDBErr_MessageList                    &           messageList
)
{
   /*===========================================================================*
    *  Locals                                                                   *
    *===========================================================================*/
    SAPDB_UInt4                             connectionSlot;
    RTE_PID                                 remotePid;
    RTE_ConsoleHandle                       connectionHandle;
   /*===========================================================================*
    *  Instructions                                                             *
    *===========================================================================*/
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionList::ReleaseConnection", 
                             Console_Trace, 1);

    connectionSlot = (SAPDB_UInt4)(pConnectionItem - m_ConnectionList);

    remotePid = pConnectionItem->GetRemotePID ();
    connectionHandle = pConnectionItem->GetHandle ();

    Lock ();
    
    if (!pConnectionItem->SetFree (m_FreeList, messageList))
    {
        Unlock ();
        messageList = messageList + SAPDBErr_MessageList (RTE_CONTEXT, RTEERR_THREAD_CONS_SET_FREE_CONNECTION, 
                                                          SAPDB_ToString (connectionSlot));
        SAPDBTRACE_WRITELN(Console_Trace, 5, "Release connection failed:" 
                                             << " Connection slot " << connectionSlot 
                                             << " is already free"); 
        return false;
    }

    m_FreeList    = pConnectionItem;
    Unlock ();
/*
    RTE_Message (SAPDBErr_MessageList(RTE_CONTEXT, RTEINFO_THREAD_CONS_RELEASE_CONNECTION, 
                                      SAPDB_ToString (connectionHandle),                                      
                                      SAPDB_ToString (remotePid),
                                      SAPDB_ToString (remoteRef),
                                      SAPDB_ToString (connectionSlot)));
*/
    SAPDBTRACE_WRITELN(Console_Trace, 5, "Client PID " << (SAPDB_UInt8)remotePid
                                             << ", Ref. "  << remoteRef << ":"      
                                             << " Release connection " << connectionHandle 
                                             << " at slot " << connectionSlot);
    --m_NumConnections;

    SAPDBTRACE_WRITELN(Console_Trace, 9, "Number of connected clients: " << m_NumConnections);

    return true;
}

/*---------------------------------------------------------------------------*/

void   RTEThread_ConsoleConnectionList::ScanConnectionsForTimeout
(
    void
)
{
   /*===========================================================================*
    *  Locals                                                                   *
    *===========================================================================*/
    RTEThread_ConsoleConnectionListItem    *pConnectionItem = m_ConnectionList; 
    SAPDB_UInt4                             idx;
    SAPDB_UInt8                             lastAccessTime;
    SAPDB_UInt8                             currentTime;
    RTEThread_ConsoleWorkerBase            *pWorker;
    SAPDBErr_MessageList                    messageList;
   /*===========================================================================*
    *  Instructions                                                             *
    *===========================================================================*/
    SAPDBTRACE_METHOD_DEBUG ("RTEThread_ConsoleConnectionList::ScanConnectionsForTimeout", 
                             Console_Trace, 1);

    for (idx = 0; 
         idx < RTE_MAX_CONSOLE_CONNECTION; 
         ++idx, ++pConnectionItem)
    {
        pConnectionItem->Lock ();
        if (CONNECTION_LIST_ITEM_FREE == pConnectionItem->GetHandle ()
            || CONNECTION_LIST_ITEM_INVALID == pConnectionItem->GetHandle ())
        {   
            pConnectionItem->Unlock ();
            SAPDBTRACE_WRITELN(Console_Trace, 5, "Slot " << idx << ": Free");
            continue;
        }

        pWorker = pConnectionItem->GetWorker ();
        lastAccessTime = pWorker->GetConsoleLastAccessTime ();
        currentTime = RTESys_Time ();

        if (!pWorker->IsBusy ())
        {
            if (currentTime - lastAccessTime > RTE_MAX_CONSOLE_IDLE_TIME)
            {
                //Could be optimized by copying the connection data temporarily. Then
                //the deletion of system resources and the message to the application
                //could be done after UnLock. Here we would only have to delete the 
                //connection data in our list. But this seems not very meaningful at 
                //the moment

                //Send timeout to XCons

                RTE_Message (SAPDBErr_MessageList(RTE_CONTEXT, RTEINFO_THREAD_CONS_TIMEOUT, 
                    SAPDB_ToString (pConnectionItem->GetHandle ()),
                    SAPDB_ToString (pConnectionItem->GetRemotePID ()),
                    SAPDB_ToString (pWorker->GetClientReference ()),
                    SAPDB_ToString (idx)));

                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
                //The following send may not be blocking! Since XCons is not awaiting an answer
                //at the moment we have to be sure that all error data fit in one packet.
                //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                if (!pWorker->SendError (TIMEOUT, RTE_CONS_REMOTE_TIMEOUT, messageList))
                {
                    RTE_Message (SAPDBErr_MessageList (RTE_CONTEXT, RTEERR_THREAD_CONS_SEND_ERR));
                }

                if (!ReleaseConnection (pConnectionItem, pWorker->GetClientReference (), messageList))
                {
                    RTE_Crash (messageList);
                }

                SAPDBTRACE_WRITELN(Console_Trace, 5, "Slot " << idx << ": Last access time"
                    << lastAccessTime <<" -> Connection timeout");
            }
            else
            {
                //Check if the client is still alive
                RTESys_ProcessState     clientProcess (pConnectionItem->GetRemotePID ());

                if (RTESys_ProcessState::Alive != clientProcess.State ())
                {
                    RTE_Message (SAPDBErr_MessageList(RTE_CONTEXT, RTEINFO_THREAD_CONS_CLIENT_DIED, 
                        SAPDB_ToString (pConnectionItem->GetHandle ()),
                        SAPDB_ToString (pConnectionItem->GetRemotePID ()),
                        SAPDB_ToString (pWorker->GetClientReference ()),
                        SAPDB_ToString (idx)));

                    if (!ReleaseConnection (pConnectionItem, pWorker->GetClientReference (), messageList))
                    {
                        RTE_Crash (messageList);
                    }

                    SAPDBTRACE_WRITELN(Console_Trace, 5, "Client connection " << (SAPDB_UInt8)pConnectionItem->GetRemotePID () 
                        << " has died");
                }
            }
        }
        else
        {
            SAPDBTRACE_WRITELN(Console_Trace, 5, "Slot " << idx << ": Last access time"
                                                 << lastAccessTime);
        }

        pConnectionItem->Unlock ();
    }
}



/*---------------------------------------------------------------------------*/
/*--- C  Interfaces  --------------------------------------------------------*/
/*---------------------------------------------------------------------------*/

externC void   RTEThread_ConsoleScanConnectionsForTimeout
(
    void
)
{
    RTEThread_ConsoleConnectionList::Instance().ScanConnectionsForTimeout ();
}

/*===========================================================================*
 *  END OF CODE                                                              *
 *===========================================================================*/