ANSC_STATUS
AnscDetoStop
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject;

    if ( !pMyObject->bStarted )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    else
    {
        pMyObject->bStarted = FALSE;
    }

    AnscWaitEvent(&pMyObject->RecvEvent, ANSC_DETO_TASK_CLEANUP_TIME);
    AnscWaitEvent(&pMyObject->SendEvent, ANSC_DETO_TASK_CLEANUP_TIME);

    pMyObject->Reset((ANSC_HANDLE)pMyObject);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDktoTsaSendTlsMessage
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hMessageBdo
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SOCKET_TCP_OBJECT)hThisObject;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pServer      = (PANSC_DAEMON_SERVER_TCP_OBJECT)pMyObject->hDaemonServer;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pEngine      = (PANSC_DAEMON_ENGINE_TCP_OBJECT)pMyObject->hDaemonEngine;
    PANSC_DSTO_WORKER_OBJECT        pWorker      = (PANSC_DSTO_WORKER_OBJECT      )pServer->hWorker;
    PANSC_BUFFER_DESCRIPTOR         pPayloadBdo  = (PANSC_BUFFER_DESCRIPTOR       )hMessageBdo;

    if ( pMyObject->bClosed || pMyObject->bBroken )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }

    returnStatus =
        pEngine->Send2
            (
                (ANSC_HANDLE)pEngine,
                (ANSC_HANDLE)pMyObject,
                AnscBdoGetBlock    (pPayloadBdo),
                AnscBdoGetBlockSize(pPayloadBdo),
                (ANSC_HANDLE)NULL
            );

    AnscFreeBdo((ANSC_HANDLE)pPayloadBdo);

    return  returnStatus;
}
ANSC_STATUS
AnscDstoStopEngines
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SERVER_TCP_OBJECT)hThisObject;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pEngine      = NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;

    AnscAcquireLock(&pMyObject->EngineQueueLock);

    pSLinkEntry = AnscQueueGetFirstEntry(&pMyObject->EngineQueue);

    while ( pSLinkEntry )
    {
        pEngine     = ACCESS_ANSC_DAEMON_ENGINE_TCP_OBJECT(pSLinkEntry);
        pSLinkEntry = AnscQueueGetNextEntry(pSLinkEntry);

        pEngine->Stop((ANSC_HANDLE)pEngine);
    }

    AnscReleaseLock(&pMyObject->EngineQueueLock);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDetoStart
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject;

    if ( pMyObject->bStarted )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    else
    {
        pMyObject->Reset((ANSC_HANDLE)pMyObject);

        pMyObject->StartTime = AnscGetTickInSecondsAbs();
        pMyObject->bStarted  = TRUE;
    }

    if ( TRUE )
    {
        AnscResetEvent(&pMyObject->RecvEvent);
        returnStatus =
            AnscSpawnTask3
                (
                    (void*)pMyObject->RecvTask,
                    (ANSC_HANDLE)pMyObject,
                    ANSC_DETO_RECV_TASK_NAME,
                    ANSC_TASK_PRIORITY_NORMAL,
                    ANSC_DETO_RECV_TASK_STACK_SIZE
                );
    }

    if ( pMyObject->ControlFlags & ANSC_DETO_FLAG_ASYNC_SEND )
    {
        AnscResetEvent(&pMyObject->SendEvent);
        returnStatus =
            AnscSpawnTask
                (
                    (void*)pMyObject->SendTask,
                    (ANSC_HANDLE)pMyObject,
                    ANSC_DETO_SEND_TASK_NAME
                );
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDstoStartEngines
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SERVER_TCP_OBJECT)hThisObject;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pEngine      = NULL;
    ULONG                           ulFlags      = 0;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;

    AnscAcquireLock(&pMyObject->EngineQueueLock);

    pSLinkEntry = AnscQueueGetFirstEntry(&pMyObject->EngineQueue);

    while ( pSLinkEntry )
    {
        pEngine     = ACCESS_ANSC_DAEMON_ENGINE_TCP_OBJECT(pSLinkEntry);
        pSLinkEntry = AnscQueueGetNextEntry(pSLinkEntry);
        ulFlags     = pEngine->GetControlFlags((ANSC_HANDLE)pEngine);

        if ( pMyObject->Mode & ANSC_DSTO_MODE_ASYNC_SEND )
        {
            ulFlags |= ANSC_DETO_FLAG_ASYNC_SEND;
        }

        if ( pMyObject->Mode & ANSC_DSTO_MODE_NO_TIMEOUT )
        {
            ulFlags |= ANSC_DETO_FLAG_NO_TIMEOUT;
        }

        pEngine->SetControlFlags((ANSC_HANDLE)pEngine, ulFlags);
        pEngine->Start          ((ANSC_HANDLE)pEngine);
    }

    AnscReleaseLock(&pMyObject->EngineQueueLock);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDstoPoEngineCloseUp
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hForm,
        ULONG                       ulIndex
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SERVER_TCP_OBJECT)hThisObject;
    PANSC_DSTO_CLOSE_UP_FORM        pCloseUpForm = (PANSC_DSTO_CLOSE_UP_FORM      )hForm;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pEngine      = NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;

    AnscAcquireLock(&pMyObject->EngineQueueLock);
    pSLinkEntry = AnscQueueSearchEntryByIndex(&pMyObject->EngineQueue, ulIndex);
    AnscReleaseLock(&pMyObject->EngineQueueLock);

    if ( !pSLinkEntry )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        pEngine = ACCESS_ANSC_DAEMON_ENGINE_TCP_OBJECT(pSLinkEntry);
    }

    returnStatus =
        pEngine->CloseUp
            (
                (ANSC_HANDLE)pEngine,
                (ANSC_HANDLE)pCloseUpForm
            );

    pCloseUpForm->EngineIndex = ulIndex;

    return  returnStatus;
}
ANSC_STATUS
AnscDetoRemove
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject;

    pMyObject->Stop ((ANSC_HANDLE)pMyObject);
    pMyObject->Reset((ANSC_HANDLE)pMyObject);

    AnscFreeEvent(&pMyObject->RecvEvent        );
    AnscFreeEvent(&pMyObject->SendEvent        );
    AnscFreeEvent(&pMyObject->NewSocketEvent   );
    AnscFreeLock (&pMyObject->RecvSocketSetLock);
    AnscFreeLock (&pMyObject->SendSocketSetLock);
    AnscFreeLock (&pMyObject->SocketTableLock  );
    AnscFreeLock (&pMyObject->PacketQueueLock  );

    AnscCoRemove((ANSC_HANDLE)pMyObject);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDstoWorkerTask
    (
        ANSC_HANDLE                 hSocket
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pSocket      = (PANSC_DAEMON_SOCKET_TCP_OBJECT)hSocket;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SERVER_TCP_OBJECT)pSocket->hDaemonServer;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pEngine      = (PANSC_DAEMON_ENGINE_TCP_OBJECT)pSocket->hDaemonEngine;
    PANSC_DSTO_WORKER_OBJECT        pWorker      = (PANSC_DSTO_WORKER_OBJECT      )pMyObject->hWorker;
    ULONG                           ulPacketSize = pSocket->RecvPacketSize;

    pSocket->RecvPacketSize = 0;
    pSocket->RecvOffset     = 0;

    returnStatus =
        pWorker->ProcessAsync
            (
                pWorker->hWorkerContext,
                (ANSC_HANDLE)pSocket,
                pSocket->RecvBuffer,
                ulPacketSize,
                (ANSC_HANDLE)NULL
            );

    returnStatus =
        pEngine->EnableRecv
            (
                (ANSC_HANDLE)pEngine,
                (ANSC_HANDLE)pSocket,
                TRUE
            );

    return  returnStatus;
}
ANSC_STATUS
AnscDetoClean
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pServer      = (PANSC_DAEMON_SERVER_TCP_OBJECT)pMyObject->hDaemonServer;
    PANSC_DSTO_WORKER_OBJECT        pWorker      = (PANSC_DSTO_WORKER_OBJECT      )pServer->hWorker;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pSocket      = NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    ULONG                           ulHashIndex  = 0;
    BOOL                            bSocketFound = FALSE;
    ULONG                           ulCurTime    = AnscGetTickInSecondsAbs();
    ULONG                           ulTimeout    = ANSC_DETO_SOCKET_TIMEOUT;

    if ( !pMyObject->bStarted )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    /*
    else if ( pMyObject->ControlFlags & ANSC_DETO_FLAG_NO_TIMEOUT )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    */

    if ( pMyObject->CurSocketCount >= pMyObject->MaxSocketCount )
    {
        ulTimeout = ANSC_DETO_SOCKET_TIMEOUT2;
    }
    else
    {
        ulTimeout = ANSC_DETO_SOCKET_TIMEOUT;
    }

    ulHashIndex  = 0;
    bSocketFound = FALSE;

    while ( ulHashIndex < ANSC_DETO_SOCKET_TABLE_SIZE )
    {
        AnscAcquireLock(&pMyObject->SocketTableLock);

        bSocketFound = FALSE;
        pSLinkEntry  = AnscSListGetFirstEntry(&pMyObject->SocketTable[ulHashIndex]);

        while ( pSLinkEntry )
        {
            pSocket     = ACCESS_ANSC_DAEMON_SOCKET_TCP_OBJECT(pSLinkEntry);
            pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry);

            if ( pSocket->bLocked )
            {
                continue;
            }
            else if ( pSocket->bToBeCleaned )
            {
                bSocketFound = TRUE;

                break;
            }
            else if ( pMyObject->ControlFlags & ANSC_DETO_FLAG_NO_TIMEOUT )
            {
                continue;
            }
            else
            {
                ulCurTime = AnscGetTickInSecondsAbs();
            }

            if ( ((ulCurTime - pSocket->LastRecvAt) >= ulTimeout) &&
                 ((ulCurTime - pSocket->LastSendAt) >= ulTimeout) )
            {
                bSocketFound = TRUE;

                break;
            }
        }

        AnscReleaseLock(&pMyObject->SocketTableLock);

        if ( bSocketFound )
        {
            if ( !pSocket->bTlsEnabled ||
                 (pSocket->bTlsEnabled && pSocket->bTlsConnected) )
            {
                returnStatus =
                    pWorker->Notify
                        (
                            pWorker->hWorkerContext,
                            (ANSC_HANDLE)pSocket,
                            ANSC_DSTOWO_EVENT_TIME_OUT,
                            (ANSC_HANDLE)NULL
                        );
            }

            returnStatus =
                pMyObject->DelSocket
                    (
                        (ANSC_HANDLE)pMyObject,
                        (ANSC_HANDLE)pSocket
                    );

            pMyObject->TtcCount++;
        }
        else
        {
            ulHashIndex++;
        }
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDstoAsyncJobTask
    (
        ANSC_HANDLE                 hAsyncJob
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DSTO_ASYNC_JOB            pAsyncJob    = (PANSC_DSTO_ASYNC_JOB          )hAsyncJob;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SERVER_TCP_OBJECT)pAsyncJob->hThisObject;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pCurEngine   = (PANSC_DAEMON_ENGINE_TCP_OBJECT)NULL;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pSocket      = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pAsyncJob->hSocket;
    PANSC_DSTO_WORKER_OBJECT        pWorker      = (PANSC_DSTO_WORKER_OBJECT      )pMyObject->hWorker;
    ULONG                           ulRetryCount = 0;

    switch ( pAsyncJob->JobType )
    {
        case    ANSC_DSTO_JOB_TYPE_initTlsConnection :

                /*
                 * We have to assign an engine object to this new socket object. The assignment is done by
                 * round-robin. However, we need to make sure that the assigned engine object is not over-
                 * loaded. If it is, we repeat the search until finding a happen one.
                 */
                ulRetryCount = 0;

                if ( pSocket->bTlsEnabled )
                {
                    returnStatus = pSocket->InitTlsServer((ANSC_HANDLE)pSocket);

                    if ( returnStatus != ANSC_STATUS_SUCCESS )
                    {
                        /*
                         * I don't understand why this line was commented out before: maybe the
                         * TLS_TSA implementation in AnscDaemonSocketTcp used to clean up socket
                         * object if anything goes wrong? Anyway, it seems a good idea to enable
                         * this line. 07/20/04 - I think the reason is that it's easier to close
                         * socket from the recv() context.
                         */
                        pSocket->Finish((ANSC_HANDLE)pSocket);

                        pMyObject->TccCount++;

                        break;
                    }
                }

                while ( pCurEngine =
                            (PANSC_DAEMON_ENGINE_TCP_OBJECT)pMyObject->AssignEngine
                                (
                                    (ANSC_HANDLE)pMyObject
                                ) )
                {
                    returnStatus =
                        pCurEngine->AddSocket
                            (
                                (ANSC_HANDLE)pCurEngine,
                                (ANSC_HANDLE)pSocket
                            );

                    if ( returnStatus == ANSC_STATUS_SUCCESS )
                    {
                        pMyObject->TscCount++;

                        break;
                    }
                    else
                    {
                        ulRetryCount++;

                        if ( ulRetryCount >= pMyObject->EngineCount )
                        {
                            pSocket->Close ((ANSC_HANDLE)pSocket);
                            pSocket->Return((ANSC_HANDLE)pSocket);

                            pMyObject->TrcCount++;

                            returnStatus = ANSC_STATUS_FAILURE;

                            break;
                        }
                    }
                }

                /*
                 * If AddSocket() failed, socket has already been destroyed. In this case, we need
                 * to terminate TLS negotiation task silently. Note that the only scenario where
                 * AddSocket() fails is that the engine is serving a large number of sockets, the
                 * maximum socket number limitation has already been reached.
                 */
                if ( returnStatus != ANSC_STATUS_SUCCESS )
                {
                    break;
                }
                else if ( pSocket->bTlsEnabled )
                {
                    returnStatus = pSocket->OpenTlsServer((ANSC_HANDLE)pSocket);

                    if ( returnStatus != ANSC_STATUS_SUCCESS )
                    {
                        /*
                         * I don't understand why this line was commented out before: maybe the
                         * TLS_TSA implementation in AnscDaemonSocketTcp used to clean up socket
                         * object if anything goes wrong? Anyway, it seems a good idea to enable
                         * this line. 07/20/04 - I think the reason is that it's easier to close
                         * socket from the recv() context.
                         */
                        pSocket->ToClean((ANSC_HANDLE)pSocket, TRUE, 2);

                        pMyObject->TccCount++;

                        break;
                    }
                }

                if ( !pWorker->Accept
                        (
                            pWorker->hWorkerContext,
                            (ANSC_HANDLE)pSocket,
                            &pSocket->hClientContext
                        ) )
                {
                    pSocket->ToClean((ANSC_HANDLE)pSocket, TRUE, 2);

                    pMyObject->TccCount++;

                    break;
                }
                else
                {
                    returnStatus =
                        pWorker->SetOut
                            (
                                pWorker->hWorkerContext,
                                (ANSC_HANDLE)pSocket
                            );
                }

                /*
                 * Mark the flag that we've completed initializing the TLS connection...
                 */
                pSocket->bTlsInitializing = FALSE;

                break;

        default :

                break;
    }

    AnscFreeMemory(pAsyncJob);

    return  returnStatus;
}
ANSC_STATUS
AnscDetoRecvTask
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_TCP_OBJECT  pMyObject     = (PANSC_DAEMON_ENGINE_TCP_OBJECT)hThisObject;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pServer       = (PANSC_DAEMON_SERVER_TCP_OBJECT)pMyObject->hDaemonServer;
    PANSC_DSTO_WORKER_OBJECT        pWorker       = (PANSC_DSTO_WORKER_OBJECT      )pServer->hWorker;
#if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX)
    ansc_fd_set*                    pRecvSet1     = (ansc_fd_set*                  )pMyObject->RecvSocketSet;
    xskt_fd_set*                    pRecvSet2     = (xskt_fd_set*                  )pMyObject->RecvSocketSet;
#endif
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pSocket       = NULL;
    ULONG                           ulLastCleanAt = AnscGetTickInSecondsAbs();
    ANSC_SOCKET                     s_socket      = ANSC_SOCKET_INVALID_SOCKET;
    int                             s_result      = 0;
    int                             s_result_excp = 0;
    int                             s_error       = 0;
    int                             i             = 0;
#if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX)
    ansc_fd_set*                    read_fd_set1  = NULL;
    xskt_fd_set*                    read_fd_set2  = NULL;
    ansc_fd_set*                    excp_fd_set1  = NULL;
    xskt_fd_set*                    excp_fd_set2  = NULL;
    ansc_timeval                    timeval1;
    xskt_timeval                    timeval2;
#endif

    AnscTrace("AnscDetoRecvTask is activated ...!\n");

#if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX)
    read_fd_set1 = (ansc_fd_set*)AnscAllocateMemory(sizeof(ansc_fd_set));
    read_fd_set2 = (xskt_fd_set*)AnscAllocateMemory(sizeof(xskt_fd_set));
    excp_fd_set1 = (ansc_fd_set*)AnscAllocateMemory(sizeof(ansc_fd_set));
    excp_fd_set2 = (xskt_fd_set*)AnscAllocateMemory(sizeof(xskt_fd_set));

    if ( !read_fd_set1 || !read_fd_set2 || !excp_fd_set1 || !excp_fd_set2 )
    {
        goto  EXIT1;
    }
#endif

    /*
     * As a scalable server implemention, we shall accept as many incoming client connections as
     * possible and can only be limited by the system resources. Once the listening socket becomes
     * readable, which means an incoming connection attempt has arrived. We create a new socket
     * object and associate it with the client. This is a repeated process until the socket owner
     * closes the socket.
     */
    while ( pMyObject->bStarted )
    {
        ANSC_COMMIT_TASK();

        /*
         * To avoid letting the old half-dead sockets hogging up the system resource, we need to
         * periodically invoke the cleaning routine. The default interval is 10 seconds, and the
         * idle timeout value is 90 seconds.
         */
	#if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX)
        if ( pMyObject->bCleaningDemanded )
	#else
		if ( FALSE ) /*if ( pMyObject->bCleaningDemanded )*/
	#endif
        {
            pMyObject->Clean((ANSC_HANDLE)pMyObject);

            ulLastCleanAt                = AnscGetTickInSecondsAbs();
            pMyObject->bCleaningDemanded = FALSE;
        }
        else if ( (AnscGetTickInSecondsAbs() - ulLastCleanAt) >= ANSC_DETO_CLEAN_TASK_INTERVAL )
        {
            pMyObject->Clean((ANSC_HANDLE)pMyObject);

            ulLastCleanAt                = AnscGetTickInSecondsAbs();
            pMyObject->bCleaningDemanded = FALSE;
        }

        /*
         * Since the original bsd compatible socket api doesn't support asynchronous operation, the
         * nonblocking status polling is the best we can get. As a matter of fact, the current unix
         * and linux actually still don't support asynchronous notification on any socket operation.
         */
    #if defined(_ANSC_KERNEL) && defined(_ANSC_LINUX)
        if ( !pMyObject->CurSocketCount)
        {
            if ( pServer->Mode & ANSC_DSTO_MODE_EVENT_SYNC )
            {
                AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_DETO_WAIT_EVENT_INTERVAL);
                AnscResetEvent(&pMyObject->NewSocketEvent);

                if (!pMyObject->CurSocketCount)
                {
                    AnscTaskRelinquish();

                    continue;
                }
            }
            else
            {
                AnscSleep(ANSC_DETO_TASK_BREAK_INTERVAL);

                continue;
            }
        }
    #else
        if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET )
        {
            AnscAcquireLock(&pMyObject->RecvSocketSetLock);
            *read_fd_set2 = *pRecvSet2;
            AnscReleaseLock(&pMyObject->RecvSocketSetLock);
        }
        else
        {
            AnscAcquireLock(&pMyObject->RecvSocketSetLock);
            *read_fd_set1 = *pRecvSet1;
            AnscReleaseLock(&pMyObject->RecvSocketSetLock);
        }

        if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && XSKT_SOCKET_FD_ISNUL(read_fd_set2)) ||
             (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && ANSC_SOCKET_FD_ISNUL(read_fd_set1)) )
        {
            if ( pServer->Mode & ANSC_DSTO_MODE_EVENT_SYNC )
            {
                AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_DETO_WAIT_EVENT_INTERVAL);
                AnscResetEvent(&pMyObject->NewSocketEvent);

                if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET )
                {
                    AnscAcquireLock(&pMyObject->RecvSocketSetLock);
                    *read_fd_set2 = *pRecvSet2;
                    AnscReleaseLock(&pMyObject->RecvSocketSetLock);
                }
                else
                {
                    AnscAcquireLock(&pMyObject->RecvSocketSetLock);
                    *read_fd_set1 = *pRecvSet1;
                    AnscReleaseLock(&pMyObject->RecvSocketSetLock);
                }

                if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && XSKT_SOCKET_FD_ISNUL(read_fd_set2)) ||
                     (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && ANSC_SOCKET_FD_ISNUL(read_fd_set1)) )
                {
                    AnscTaskRelinquish();

                    continue;
                }
            }
            else
            {
                AnscSleep(ANSC_DETO_TASK_BREAK_INTERVAL);

                continue;
            }
        }

        if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET )
        {
            timeval2.tv_sec  = (ANSC_DETO_POLL_INTERVAL_MS / 1000);          /* number of seconds      */
            timeval2.tv_usec = (ANSC_DETO_POLL_INTERVAL_MS % 1000) * 1000;   /* number of microseconds */
        }
        else
        {
            timeval1.tv_sec  = (ANSC_DETO_POLL_INTERVAL_MS / 1000);          /* number of seconds      */
            timeval1.tv_usec = (ANSC_DETO_POLL_INTERVAL_MS % 1000) * 1000;   /* number of microseconds */
        }

        /*
         * The _ansc_select() function returns the total number of socket handles that are ready
         * and contained in the fd_set structures, zero if the time limit expired, or SOCKET_ERROR
         * if an error occurred. Upon return, the structures are updated to reflect the subset of
         * these sockets that meet the specified condition.
         */
        if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET )
        {
            s_result = _xskt_select(XSKT_SOCKET_FD_SETSIZE, read_fd_set2, NULL, NULL, &timeval2);
        }
        else
        {
            s_result = _ansc_select(ANSC_SOCKET_FD_SETSIZE, read_fd_set1, NULL, NULL, &timeval1);
        }

        if ( s_result == 0 )
        {
            continue;
        }
        else if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_result == XSKT_SOCKET_ERROR)) ||
                  (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_result == ANSC_SOCKET_ERROR)) )
        {
            s_error = (pServer->Mode & ANSC_DSTO_MODE_XSOCKET)? _xskt_get_last_error() : _ansc_get_last_error();

            /*
             * Previously we simply reset everything when _ansc_select() fails, which is not a good
             * solution: we shall notify the worker module and gracefully shutdown the socket(s)
             * that caused the error.
             */
            /*
            pMyObject->Reset((ANSC_HANDLE)pMyObject);
            */
            pMyObject->ExpAllSockets((ANSC_HANDLE)pMyObject);

            continue;
        }
        else if ( !pMyObject->bStarted )
        {
            break;
        }
	#endif

        /*
         * If there're multiple sockets are receiving data, we loop through the returned fd_set
         * structure and process them one-by-one. However, we have a slight problem: the resulted
         * fd_set consists of only the native socket handles, not the associated Socket Objects.
         * We have to first retrieve the peer's IP address from the socket, and use it to find
         * the associated socket object.
         */
	#if defined(_ANSC_KERNEL) && defined(_ANSC_LINUX)
        if (TRUE)
        {
            int                             i; 
            PSINGLE_LINK_ENTRY              pSLinkEntry;

            for ( i = 0; i < ANSC_DETO_SOCKET_TABLE_SIZE ; i++)
            {
                if (!AnscSListQueryDepth(&pMyObject->SocketTable[i]))
                {
                    continue;
                }

                AnscAcquireLock(&pMyObject->SocketTableLock);

                pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->SocketTable[i]);

                AnscReleaseLock(&pMyObject->SocketTableLock);

                while ( pSLinkEntry )
                {
                    pSocket     = ACCESS_ANSC_DAEMON_SOCKET_TCP_OBJECT(pSLinkEntry);
                    pSLinkEntry = AnscSListGetNextEntry(pSLinkEntry);

					if ( pSocket->bTlsEnabled )
					{
                        pMyObject->bBusy = TRUE;

                        returnStatus =
                            pMyObject->Recv2
                                (
                                    (ANSC_HANDLE)pMyObject,
                                    (ANSC_HANDLE)pSocket
                                );

                        pMyObject->bBusy = FALSE;
					}
                    else
                    {
                        pMyObject->bBusy = TRUE;

						returnStatus =
							pMyObject->Recv
								(
									(ANSC_HANDLE)pMyObject,
									(ANSC_HANDLE)pSocket
								);

                        pMyObject->bBusy = FALSE;
                    }
                }

                if ( !pMyObject->bStarted )
                {
                    break;
                }
            }

            AnscSleep(10);
        }
	#else
        for ( i = 0; i < s_result; i++ )
        {
            if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET )
            {
                XSKT_SOCKET_FD_GET(read_fd_set2, s_socket, (ULONG)i);
            }
            else
            {
                ANSC_SOCKET_FD_GET(read_fd_set1, s_socket, (ULONG)i);
            }

            if ( ( (pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_socket == XSKT_SOCKET_INVALID_SOCKET)) ||
                 (!(pServer->Mode & ANSC_DSTO_MODE_XSOCKET) && (s_socket == ANSC_SOCKET_INVALID_SOCKET)) )
            {
                break;
            }
            else
            {
                pSocket =
                    (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket
                        (
                            (ANSC_HANDLE)pMyObject,
                            s_socket
                        );
                /*
                 * We should make sure this socket is still valid before proceeding with the socket
                 * receive operations. For example, the peer may have already closed or reset the
                 * TCP connection while we're serving the previous socket request.
                 *
                 * 10/06/04 - It's believed this modification is slowing down the GUI and we're not
                 * seeing tangible evidence that GUI responsivenss has been improved. So we disable
                 * it for now.
                 */
                /*
                if ( pServer->Mode & ANSC_DSTO_MODE_XSOCKET )
                {
                    XSKT_SOCKET_FD_ZERO(excp_fd_set2);
                    XSKT_SOCKET_FD_SET ((XSKT_SOCKET)s_socket, excp_fd_set2);

                    timeval2.tv_sec  = 0;
                    timeval2.tv_usec = 0;

                    s_result_excp = _xskt_select(XSKT_SOCKET_FD_SETSIZE, NULL, NULL, excp_fd_set2, &timeval2);
                }
                else
                {
                    ANSC_SOCKET_FD_ZERO(excp_fd_set1);
                    ANSC_SOCKET_FD_SET (s_socket, excp_fd_set1);

                    timeval1.tv_sec  = 0;
                    timeval1.tv_usec = 0;

                    s_result_excp = _ansc_select(ANSC_SOCKET_FD_SETSIZE, NULL, NULL, excp_fd_set1, &timeval1);
                }
                */
            }

            /*
            if ( ((s_result_excp == 1                )                                             ) ||
                 ((s_result_excp == XSKT_SOCKET_ERROR) &&  (pServer->Mode & ANSC_DSTO_MODE_XSOCKET)) ||
                 ((s_result_excp == ANSC_SOCKET_ERROR) && !(pServer->Mode & ANSC_DSTO_MODE_XSOCKET)) )
            {
                if ( TRUE )
                {
                    pSocket->bBroken = TRUE;

                    pMyObject->EnableRecv((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE);
                    pMyObject->EnableSend((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket, FALSE);
                }

                if ( pSocket->bTlsEnabled )
                {
                    if ( pSocket->bTlsEnabled && pSocket->bTlsConnected && !pSocket->bTlsInitializing )
                    {
                        returnStatus =
                            pWorker->Notify
                                (
                                    pWorker->hWorkerContext,
                                    (ANSC_HANDLE)pSocket,
                                    ANSC_DSTOWO_EVENT_SOCKET_ERROR,
                                    (ANSC_HANDLE)NULL
                                );
                    }
                    else
                    {
                        AnscSetEvent(&pSocket->TlsConnEvent);
                    }
                }
                else
                {
                    returnStatus =
                        pWorker->Notify
                            (
                                pWorker->hWorkerContext,
                                (ANSC_HANDLE)pSocket,
                                ANSC_DSTOWO_EVENT_SOCKET_ERROR,
                                (ANSC_HANDLE)NULL
                            );
                }

                if ( pServer->Mode & ANSC_DSTO_MODE_AUTO_CLOSE )
                {
                    pMyObject->DelSocket((ANSC_HANDLE)pMyObject, (ANSC_HANDLE)pSocket);
                }

                pMyObject->TrcCount++;

                continue;
            }
            else
            {
                pSocket =
                    (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket
                        (
                            (ANSC_HANDLE)pMyObject,
                            s_socket
                        );
            }
            */

            if ( !pSocket )
            {
                continue;
            }
            else if ( pSocket->bTlsEnabled )
            {
#ifdef _ANSC_USE_OPENSSL_
                pMyObject->bBusy = TRUE;

                returnStatus =
                    pMyObject->Recv
                        (
                            (ANSC_HANDLE)pMyObject,
                            (ANSC_HANDLE)pSocket
                        );

                pMyObject->bBusy = FALSE;
#else
                pMyObject->bBusy = TRUE;

                returnStatus =
                    pMyObject->Recv2
                        (
                            (ANSC_HANDLE)pMyObject,
                            (ANSC_HANDLE)pSocket
                        );

                pMyObject->bBusy = FALSE;
#endif
            }
            else
            {
                pMyObject->bBusy = TRUE;

                returnStatus =
                    pMyObject->Recv
                        (
                            (ANSC_HANDLE)pMyObject,
                            (ANSC_HANDLE)pSocket
                        );

                pMyObject->bBusy = FALSE;
            }

            /*
             * Check whether 'bToBeCleaned' flag is set for this socket: if it is, we should close
             * this socket right away; otherwise, we continue the processing. WARNING!!! This new
             * change seems to incur instability in SLAP, we have to roll back to the initial
             * approach.
             */
            /*
            if ( pSocket->bToBeCleaned )
            {
                returnStatus =
                    pMyObject->DelSocket
                        (
                            (ANSC_HANDLE)pMyObject,
                            (ANSC_HANDLE)pSocket
                        );
            }
            */

            if ( !pMyObject->bStarted )
            {
                break;
            }
        }
	#endif
    }


    /******************************************************************
                GRACEFUL ROLLBACK PROCEDURES AND EXIT DOORS
    ******************************************************************/

EXIT1:

    AnscSetEvent(&pMyObject->RecvEvent);

#if !defined(_ANSC_KERNEL) || !defined(_ANSC_LINUX)
    if ( read_fd_set1 )
    {
        AnscFreeMemory(read_fd_set1);
    }

    if ( read_fd_set2 )
    {
        AnscFreeMemory(read_fd_set2);
    }

    if ( excp_fd_set1 )
    {
        AnscFreeMemory(excp_fd_set1);
    }

    if ( excp_fd_set2 )
    {
        AnscFreeMemory(excp_fd_set2);
    }
#endif

    return  ANSC_STATUS_SUCCESS;
}