ANSC_STATUS
AnscDeuoStop
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_ENGINE_UDP_OBJECT  pMyObject    = (PANSC_DAEMON_ENGINE_UDP_OBJECT)hThisObject;

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

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

    pMyObject->Reset((ANSC_HANDLE)pMyObject);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscSctoInitTlsClient
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_SIMPLE_CLIENT_TCP_OBJECT  pMyObject    = (PANSC_SIMPLE_CLIENT_TCP_OBJECT)hThisObject;
    PANSC_SCTO_WORKER_OBJECT        pWorker      = (PANSC_SCTO_WORKER_OBJECT      )pMyObject->hWorker;
    PTLS_SCS_INTERFACE              pTlsScsIf    = (PTLS_SCS_INTERFACE            )pMyObject->hTlsScsIf;
    PTLS_TSA_INTERFACE              pTlsTsaIf    = (PTLS_TSA_INTERFACE            )pMyObject->hTlsTsaIf;
    TLS_CONNECTION_PARAMS           tlsConnParams;

    if ( !pMyObject->bTlsEnabled || !pTlsScsIf )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }

    if ( TRUE )
    {
        TlsInitConnParams((&tlsConnParams));

        tlsConnParams.bSessionSharing  = TRUE;
        tlsConnParams.bQuickHandshake  = TRUE;
        tlsConnParams.bReqCertificate  = FALSE;
        tlsConnParams.bTlsClient       = TRUE;

        tlsConnParams.HostID           = pMyObject->HostAddress.Value;
        tlsConnParams.PeerID           = pMyObject->PeerAddress.Value;
        tlsConnParams.SessionIDSize    = 0;

        tlsConnParams.CipherSuiteCount = 0;
        tlsConnParams.CompressionCount = 0;
    }

    pMyObject->hTlsConnection =
        pTlsScsIf->CreateConnection
            (
                pTlsScsIf->hOwnerContext,
                (ANSC_HANDLE)pTlsTsaIf
            );

    if ( !pMyObject->hTlsConnection )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        returnStatus =
            pTlsScsIf->ConfigConnection
                (
                    pTlsScsIf->hOwnerContext,
                    pMyObject->hTlsConnection,
                    (ANSC_HANDLE)&tlsConnParams
                );
    }

    AnscResetEvent(&pMyObject->TlsConnEvent);

    returnStatus =
        pTlsScsIf->StartConnection
            (
                pTlsScsIf->hOwnerContext,
                pMyObject->hTlsConnection
            );

    if ( returnStatus == ANSC_STATUS_SUCCESS )
    {
        AnscWaitEvent(&pMyObject->TlsConnEvent, 0xFFFFFFFF);
    }

    if ( !pMyObject->bTlsConnected )
    {
        returnStatus =
            pTlsScsIf->RemoveConnection
                (
                    pTlsScsIf->hOwnerContext,
                    pMyObject->hTlsConnection
                );

        pMyObject->hTlsConnection = (ANSC_HANDLE)NULL;

        returnStatus = ANSC_STATUS_FAILURE;
    }
    else
    {
        returnStatus = ANSC_STATUS_SUCCESS;
    }

    return  returnStatus;
}
ANSC_STATUS
AnscDstoCancel
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pMyObject    = (PANSC_DAEMON_SERVER_TCP_OBJECT)hThisObject;
    PANSC_DSTO_WORKER_OBJECT        pWorker      = (PANSC_DSTO_WORKER_OBJECT      )pMyObject->hWorker;

    if ( !pMyObject->bActive )
    {
        return  ANSC_STATUS_SUCCESS;
    }
    else if ( !pWorker )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        pWorker->Unload(pWorker->hWorkerContext);

        pMyObject->bActive = FALSE;
    }

    if ( ((pMyObject->Socket != XSKT_SOCKET_INVALID_SOCKET) &&  (pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) ||
         ((pMyObject->Socket != ANSC_SOCKET_INVALID_SOCKET) && !(pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET)) )
    {
        if ( pMyObject->Mode & ANSC_DSTO_MODE_POLLING_ACCEPT )
        {
            AnscWaitEvent(&pMyObject->AcceptEvent, ANSC_DSTO_TASK_CLEANUP_TIME);

            if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
            {
                _xskt_shutdown   (pMyObject->Socket, XSKT_SOCKET_SD_BOTH);
                _xskt_closesocket(pMyObject->Socket);
            }
            else
            {
                _ansc_shutdown   (pMyObject->Socket, ANSC_SOCKET_SD_BOTH);
                _ansc_closesocket(pMyObject->Socket);
            }
        }
        else
        {
            if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
            {
                _xskt_shutdown   (pMyObject->Socket, XSKT_SOCKET_SD_BOTH);
                _xskt_closesocket(pMyObject->Socket);
            }
            else
            {
                _ansc_shutdown   (pMyObject->Socket, ANSC_SOCKET_SD_BOTH);
                _ansc_closesocket(pMyObject->Socket);
            }

            AnscWaitEvent(&pMyObject->AcceptEvent, ANSC_DSTO_TASK_CLEANUP_TIME);
        }
    }

    pMyObject->StopEngines      ((ANSC_HANDLE)pMyObject);
    pMyObject->DestroyEnginePool((ANSC_HANDLE)pMyObject);
    pMyObject->DestroySocketPool((ANSC_HANDLE)pMyObject);

    /*
     * The underlying socket wrapper may require an explicit cleanup() call, such is the case on
     * Microsoft windows platforms. The wrapper initialization has to done for each task. On most
     * real-time operating systems, this call is not required.
     */
    if ( pMyObject->Mode & ANSC_DSTO_MODE_XSOCKET )
    {
        AnscCleanupXsocketWrapper((ANSC_HANDLE)pMyObject);
    }
    else
    {
        AnscCleanupSocketWrapper((ANSC_HANDLE)pMyObject);
    }

    pMyObject->Reset((ANSC_HANDLE)pMyObject);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
BbhmDiageoResultQueryTask
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus        = ANSC_STATUS_SUCCESS;
    PBBHM_DIAG_EXEC_OBJECT          pMyObject           = (PBBHM_DIAG_EXEC_OBJECT     )hThisObject;
    PDSLH_DIAG_INFO_BASE            pDiagInfo           = NULL;
    BOOLEAN                         bQueryDone          = FALSE;

    AnscTraceFlow(("BbhmDiageoResultQueryTask ...\n"));

    do
    {
        returnStatus = pMyObject->RetrieveResult((ANSC_HANDLE)pMyObject);

        if ( returnStatus == ANSC_STATUS_SUCCESS )
        {
            pDiagInfo  = (PDSLH_DIAG_INFO_BASE)pMyObject->hDslhDiagInfo;
            bQueryDone = TRUE;

            if ( (pDiagInfo->DiagnosticState != DSLH_DIAG_STATE_TYPE_Inprogress)
                  && (pDiagInfo->DiagnosticState != DSLH_DIAG_STATE_TYPE_Requested) )
            {
                pMyObject->ResultTimestamp = AnscGetTickInSeconds();
                break;
            }
        }
        else
        {
            /* internal error occurs, quit immediatelly */
            break;
        }

        AnscWaitEvent(&pMyObject->ResultQueryEvent, 1000);
    }
    while ( pMyObject->bResultQueryRunning );

    if ( TRUE/*pDiagInfo->RequestType == DSLH_DIAGNOSTIC_REQUEST_TYPE_Acs*/ )
    {
        /* Always notify the initiator */
        CcspTraceInfo(("BbhmDiageoResultQueryTask -- notify initiator.....\n"));

        /* send out the notification */
        if ( ANSC_STATUS_SUCCESS != CosaSendDiagCompleteSignal() )
        {
            AnscTraceWarning(("Failed to send event for diagnostics completion.\n"));
        }
    }

    AnscAcquireLock(&pMyObject->AccessLock);

    AnscTraceFlow(("BbhmDiageoResultQueryTask -- quiting...\n"));

    /*
     *  stop the diagnostic process
     */
    pMyObject->bResultQueryRunning  = FALSE;

    if ( !bQueryDone )
    {
        pMyObject->StopDiag((ANSC_HANDLE)pMyObject);
    }

    AnscSetEvent(&pMyObject->ResultQueryExitEvent);

    AnscReleaseLock(&pMyObject->AccessLock);

    AnscTraceFlow(("BbhmDiageoStartDiag -- exit...\n"));

    return  ANSC_STATUS_SUCCESS;
}
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;
}
ANSC_STATUS
AnscBetoRecvTask
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PANSC_BROKER_ENGINE_TCP_OBJECT  pMyObject     = (PANSC_BROKER_ENGINE_TCP_OBJECT)hThisObject;
    PANSC_BROKER_SERVER_TCP_OBJECT  pServer       = (PANSC_BROKER_SERVER_TCP_OBJECT)pMyObject->hBrokerServer;
    ansc_fd_set*                    pRecvSet1     = (ansc_fd_set*                  )pMyObject->RecvSocketSet;
    xskt_fd_set*                    pRecvSet2     = (xskt_fd_set*                  )pMyObject->RecvSocketSet;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pSocket       = NULL;
    ULONG                           ulLastCleanAt = AnscGetTickInSeconds();
    ANSC_SOCKET                     s_socket      = ANSC_SOCKET_INVALID_SOCKET;
    int                             s_result      = 0;
    int                             s_result_excp = 0;
    int                             s_error       = 0;
    int                             i             = 0;
    uni_fd_set                      read_fd_set;
    /*uni_fd_set                      excp_fd_set;*/
    uni_timeval                     timeval;

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

    /*
     * 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 ( pMyObject->bCleaningDemanded  || 
             (AnscGetTickInSeconds() - ulLastCleanAt) >= ANSC_BETO_CLEAN_TASK_INTERVAL )
        {
            pMyObject->Clean((ANSC_HANDLE)pMyObject);

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

        /*
         * 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_BSTO_MODE_XSOCKET )
        {
            /*
             * no need to use lock for read_fd_set here, dirty read does not matter.
             */
            read_fd_set.xset = *pRecvSet2;

            if( XSKT_SOCKET_FD_ISNUL(&read_fd_set.xset) )
            {
                if ( pServer->Mode & ANSC_BSTO_MODE_EVENT_SYNC )
                {
                    AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_BETO_WAIT_EVENT_INTERVAL);
                    AnscResetEvent(&pMyObject->NewSocketEvent);
                }
                else
                {
                    AnscSleep(ANSC_BETO_TASK_BREAK_INTERVAL);
                }

                continue;
            }

            timeval.xtv.tv_sec  = (ANSC_BETO_POLL_INTERVAL_MS / 1000);          /* number of seconds      */
            timeval.xtv.tv_usec = (ANSC_BETO_POLL_INTERVAL_MS % 1000) * 1000;   /* number of microseconds */

            s_result = _xskt_select(XSKT_SOCKET_FD_SETSIZE, &read_fd_set.xset, NULL, NULL, &timeval.xtv);

            if ( s_result == 0 )
            {
                continue;
            }

            if ( s_result == XSKT_SOCKET_ERROR )
            {
                s_error = _xskt_get_last_error();
                pMyObject->Reset((ANSC_HANDLE)pMyObject);
                continue;
            }
            
        }
        else
        {
            /*
             * no need to use lock for read_fd_set here, dirty read does not matter.
             */
            read_fd_set.aset = *pRecvSet1;

            if( ANSC_SOCKET_FD_ISNUL(&read_fd_set.aset) )
            {

                if ( pServer->Mode & ANSC_BSTO_MODE_EVENT_SYNC )
                {
                    AnscWaitEvent (&pMyObject->NewSocketEvent, ANSC_BETO_WAIT_EVENT_INTERVAL);
                    AnscResetEvent(&pMyObject->NewSocketEvent);
                }
                else
                {
                    AnscSleep(ANSC_BETO_TASK_BREAK_INTERVAL);
                }

                continue;
            }

            timeval.atv.tv_sec  = (ANSC_BETO_POLL_INTERVAL_MS / 1000);          /* number of seconds      */
            timeval.atv.tv_usec = (ANSC_BETO_POLL_INTERVAL_MS % 1000) * 1000;   /* number of microseconds */

            s_result = _ansc_select(ANSC_SOCKET_FD_SETSIZE, &read_fd_set.aset, NULL, NULL, &timeval.atv);

            if ( s_result == 0 )
            {
                continue;
            }

            if ( s_result == ANSC_SOCKET_ERROR )
            {
                s_error = _ansc_get_last_error();
                pMyObject->Reset((ANSC_HANDLE)pMyObject);
                continue;
            }
            
        }

        /*
         * 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.
         */
        for ( i = 0; i < s_result; i++ )
        {
            if ( !pMyObject->bStarted )
            {
                break;
            }

            if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET )
            {
                XSKT_SOCKET_FD_GET(&read_fd_set.xset, s_socket, (ULONG)i);
                if( s_socket == XSKT_SOCKET_INVALID_SOCKET )
                {
                    break;
                }

                if( ! XSKT_SOCKET_FD_ISSET(s_socket, pRecvSet2) )
                {
                    AnscTraceError(("AnscBetoRecvTask: XSKT_SOCKET_FD_ISSET returned FALSE.\n"));
                    continue;
                }
            }
            else
            {
                ANSC_SOCKET_FD_GET(&read_fd_set.aset, s_socket, (ULONG)i);
                if( s_socket == ANSC_SOCKET_INVALID_SOCKET )
                {
                    break;
                }

                if( ! ANSC_SOCKET_FD_ISSET(s_socket, pRecvSet1) )
                {
                    AnscTraceError(("AnscBetoRecvTask: XSKT_SOCKET_FD_ISSET returned FALSE.\n"));
                    continue;
                }
            }

            pSocket =
                (PANSC_BROKER_SOCKET_TCP_OBJECT)pMyObject->GetSocketByOsocket
                    (
                        (ANSC_HANDLE)pMyObject,
                        s_socket
                    );
 
            if ( !pSocket )
            {
                continue;
            }

            /*
             * 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.
             *
             * 11/20/09 - Re-activate the following code segment to validate the socket before
             * proceeding.
             */
            /*
            if ( pServer->Mode & ANSC_BSTO_MODE_XSOCKET )
            {
                XSKT_SOCKET_FD_ZERO((&excp_fd_set.xset));
                XSKT_SOCKET_FD_SET ((XSKT_SOCKET)s_socket, (&excp_fd_set.xset));

                timeval.xtv.tv_sec  = 0;
                timeval.xtv.tv_usec = 0;

                s_result_excp = _xskt_select(XSKT_SOCKET_FD_SETSIZE, NULL, NULL, &excp_fd_set.xset, &timeval.xtv);
            }
            else
            {
                ANSC_SOCKET_FD_ZERO((&excp_fd_set.aset));
                ANSC_SOCKET_FD_SET (s_socket, (&excp_fd_set.aset));

                timeval.atv.tv_sec  = 0;
                timeval.atv.tv_usec = 0;

                s_result_excp = _ansc_select(ANSC_SOCKET_FD_SETSIZE, NULL, NULL, &excp_fd_set.aset, &timeval.atv);
            }

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

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

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

                continue;
            }
            */

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

    AnscSetEvent(&pMyObject->RecvEvent);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
CcspCwmpAcscoRequest
    (
        ANSC_HANDLE                 hThisObject,
        char*                       pSoapMessage,
        char*                       pMethodName,
        ULONG                       ulReqEnvCount,
        ULONG                       ulRepEnvCount
    )
{
    PCCSP_CWMP_ACS_CONNECTION_OBJECT pMyObject      = (PCCSP_CWMP_ACS_CONNECTION_OBJECT)hThisObject;
    PHTTP_SIMPLE_CLIENT_OBJECT      pHttpClient     = (PHTTP_SIMPLE_CLIENT_OBJECT)pMyObject->hHttpSimpleClient;
    PCCSP_CWMP_SESSION_OBJECT       pWmpSession     = (PCCSP_CWMP_SESSION_OBJECT   )pMyObject->hCcspCwmpSession;
    PCCSP_CWMP_CPE_CONTROLLER_OBJECT pCcspCwmpCpeController = (PCCSP_CWMP_CPE_CONTROLLER_OBJECT)pWmpSession->hCcspCwmpCpeController;
    PCCSP_CWMP_STAT_INTERFACE       pCcspCwmpStatIf = (PCCSP_CWMP_STAT_INTERFACE)pCcspCwmpCpeController->hCcspCwmpStaIf;
	PCCSP_CWMP_CFG_INTERFACE		pCcspCwmpCfgIf	= (PCCSP_CWMP_CFG_INTERFACE)pCcspCwmpCpeController->hCcspCwmpCfgIf;
    PCCSP_CWMP_MCO_INTERFACE        pCcspCwmpMcoIf  = (PCCSP_CWMP_MCO_INTERFACE        )pWmpSession->hCcspCwmpMcoIf;
    PHTTP_HFP_INTERFACE             pHttpHfpIf      = (PHTTP_HFP_INTERFACE)pHttpClient->GetHfpIf((ANSC_HANDLE)pHttpClient);
    PHTTP_CAS_INTERFACE             pHttpCasIf      = NULL;
    PHTTP_REQUEST_URI               pHttpReqInfo    = NULL;
    ANSC_STATUS                     returnStatus    = ANSC_STATUS_SUCCESS;
    PANSC_ACS_INTERN_HTTP_CONTENT   pHttpGetReq     = &intHttpContent;
    BOOL                            bApplyTls       = FALSE;
    PCHAR                           pRequestURL     = NULL;
    PCHAR                           pTempString     = NULL;
    PHTTP_AUTH_CLIENT_OBJECT        pAuthClientObj  = NULL;
    char                            pNewUrl[257]    = { 0 };
    ULONG                           uRedirect       = 0;
    ULONG                           uMaxRedirect    = 5;
	ULONG							ulRpcCallTimeout= CCSP_CWMPSO_RPCCALL_TIMEOUT; 

    /* If the response is 401 authentication required, we need to try again */
    int                             nMaxAuthRetries = 2;

    if( pMyObject->AcsUrl == NULL || AnscSizeOfString(pMyObject->AcsUrl) <= 10 || pHttpHfpIf == NULL)
    {
        return ANSC_STATUS_NOT_READY;
    }

    AnscZeroMemory(pHttpGetReq, sizeof(ANSC_ACS_INTERN_HTTP_CONTENT));

    CcspTr069PaTraceDebug(("CcspCwmpAcscoRequest -- AcsUrl = '%s'\n", pMyObject->AcsUrl));

    pHttpCasIf  = (PHTTP_CAS_INTERFACE)pHttpClient->GetCasIf((ANSC_HANDLE)pHttpClient);

    if ( pHttpCasIf != NULL)
    {
        if( pMyObject->Username == NULL || AnscSizeOfString(pMyObject->Username) == 0)
        {
            pHttpCasIf->EnableAuth(pHttpCasIf->hOwnerContext, FALSE);
        }
        else
        {
            pHttpCasIf->EnableAuth(pHttpCasIf->hOwnerContext, TRUE);

            pAuthClientObj  = (PHTTP_AUTH_CLIENT_OBJECT)pHttpClient->GetClientAuthObj((ANSC_HANDLE)pHttpClient);

            if ( pAuthClientObj != NULL)
            {
                pAuthClientObj->SetAcmIf((ANSC_HANDLE)pAuthClientObj, (ANSC_HANDLE)pMyObject->hHttpAcmIf);
            }
            else
            {
                CcspTr069PaTraceError(("Failed to Get HttpAuthClient object.\n"));
            }
        }
    }

#ifdef   _DEBUG
    if ( !pSoapMessage )
    {
        CcspTr069PaTraceDebug(("CPE Request:\n<EMPTY>\n"));
    }
    else if ( AnscSizeOfString(pSoapMessage) <= CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH )
    {
        CcspTr069PaTraceDebug(("CPE Request:\n%s\n", pSoapMessage));
    }
    else
    {
        char                        partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+1+8];

        AnscCopyMemory(partSoap, pSoapMessage, CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH);
        partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH] = '\n';
        partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+1] = '.';
        partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+2] = '.';
        partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+3] = '.';
        partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+4] = '\n';
        partSoap[CCSP_CWMP_TRACE_MAX_SOAP_MSG_LENGTH+5] = 0;
        CcspTr069PaTraceDebug(("CPE Request:\n%s\n", partSoap));
    }
#endif
    
START:
    pRequestURL = pMyObject->AcsUrl;

    pHttpReqInfo =
        (PHTTP_REQUEST_URI)pHttpHfpIf->ParseHttpUrl
            (
                pHttpHfpIf->hOwnerContext,
                pRequestURL,
                AnscSizeOfString(pRequestURL)
            );

    if ( !pHttpReqInfo )
    {
        return ANSC_STATUS_INTERNAL_ERROR;
    }

    pHttpReqInfo->Type = HTTP_URI_TYPE_ABS_PATH;

    /* init the request */
    AnscZeroMemory(pHttpGetReq, sizeof(ANSC_ACS_INTERN_HTTP_CONTENT));
    pHttpGetReq->bIsRedirect    = FALSE;
    pHttpGetReq->SoapMessage    = pSoapMessage;

    /* When there is more than one envelope in a single HTTP Request,
     * when there is a SOAP response in an HTTP Request, or when there is a
     * SOAP Fault response in an HTTP Request, the SOAPAction header in the
     * HTTP Request MUST have no value (with no quotes), indicating that this
     * header provides no information as to the intent of the message."
     */
    if( ulReqEnvCount == 1 && ulRepEnvCount == 0)
    {
        pHttpGetReq->MethodName     = pMethodName;
    }

    AnscInitializeEvent(&pHttpGetReq->CompleteEvent);

    while ( nMaxAuthRetries > 0 )
    {
        CcspTr069PaTraceInfo(("ACS Request now at: %u\n", (unsigned int)AnscGetTickInSeconds()));

        if ( AnscEqualString2(pRequestURL, "https", 5, FALSE) )
        {
            bApplyTls = TRUE;
        }
        else if ( AnscEqualString2(pRequestURL, "http", 4, FALSE) )
        {
            if ( bIsComcastImage() ){                
#ifdef _SUPPORT_HTTP
               CcspTr069PaTraceInfo(("HTTP request from ACS is supported\n"));
               bApplyTls = FALSE;
#else
               CcspTr069PaTraceInfo(("TR-069 blocked unsecured traffic from ACS\n"));
               pHttpGetReq->CompleteStatus = ANSC_STATUS_NOT_SUPPORTED;
               pHttpGetReq->bUnauthorized = TRUE;
               pHttpGetReq->bIsRedirect = FALSE;
               break;
#endif
            }
            else {
               bApplyTls = FALSE; 
            }
        }
        else
        {
             pHttpGetReq->CompleteStatus = ANSC_STATUS_NOT_SUPPORTED;
             pHttpGetReq->bUnauthorized = FALSE;
             pHttpGetReq->bIsRedirect = FALSE;
             break;
        }

        if(pHttpGetReq->pContent != NULL)
        {
            CcspTr069PaFreeMemory(pHttpGetReq->pContent);

            pHttpGetReq->pContent = NULL;
        }

        pHttpGetReq->CompleteStatus = ANSC_STATUS_FAILURE;
        pHttpGetReq->bUnauthorized  = FALSE;
        AnscResetEvent     (&pHttpGetReq->CompleteEvent);

        returnStatus =
            pHttpClient->Request
                (
                    (ANSC_HANDLE)pHttpClient,
                    (ULONG      )HTTP_METHOD_CODE_POST,
                    (ANSC_HANDLE)pHttpReqInfo,
                    (ANSC_HANDLE)pHttpGetReq,
                    bApplyTls
                );

        if( returnStatus != ANSC_STATUS_SUCCESS)
        {
            CcspTr069PaTraceError(("ACS Request failed: returnStatus = %.X\n", (unsigned int)returnStatus));
			break;
        }

		if ( pCcspCwmpCfgIf && pCcspCwmpCfgIf->GetCwmpRpcTimeout )
		{
			ulRpcCallTimeout = pCcspCwmpCfgIf->GetCwmpRpcTimeout(pCcspCwmpCfgIf->hOwnerContext);	
			if ( ulRpcCallTimeout < CCSP_CWMPSO_RPCCALL_TIMEOUT )
			{
				ulRpcCallTimeout = CCSP_CWMPSO_RPCCALL_TIMEOUT;
			}
		}

        AnscWaitEvent(&pHttpGetReq->CompleteEvent, ulRpcCallTimeout * 1000);
        if ( pHttpGetReq->CompleteStatus == ANSC_STATUS_SUCCESS && pHttpGetReq->bUnauthorized && nMaxAuthRetries > 0 )
        {
            CcspTr069PaTraceError(("ACS Request is not authenticated, try again.\n"));
            nMaxAuthRetries --;
			
#ifdef _ANSC_USE_OPENSSL_
            if( bApplyTls )
        	{
	        	if ( ANSC_STATUS_SUCCESS == CcspTr069PaSsp_GetTr069CertificateLocationForSyndication( &openssl_client_ca_certificate_files ) )
        		{
					openssl_load_ca_certificates( SSL_CLIENT_CALLS );
        		}
        	}
#endif /* _ANSC_USE_OPENSSL_ */
        }
        else
        {
            CcspTr069PaTraceInfo(("ACS Request has completed with status code %lu, at %lu\n", pHttpGetReq->CompleteStatus, AnscGetTickInSeconds()));

            break;
        }
    }

    /* AnscResetEvent (&pHttpGetReq->CompleteEvent); */
    AnscFreeEvent(&pHttpGetReq->CompleteEvent);

    CcspTr069PaFreeMemory(pHttpReqInfo);

    if ( pHttpGetReq->CompleteStatus != ANSC_STATUS_SUCCESS )
    {
        if ( pHttpGetReq->CompleteStatus == ANSC_STATUS_RESET_SESSION )
        {
            goto  REDIRECTED;
        }
        else
        {
            returnStatus = pHttpGetReq->CompleteStatus;

            goto  EXIT;
        }
    }
    else if( pHttpGetReq->bUnauthorized)
    {
        returnStatus = ANSC_STATUS_FAILURE;

        if( pCcspCwmpStatIf)
        {
            pCcspCwmpStatIf->IncTcpFailure(pCcspCwmpStatIf->hOwnerContext);
        }

        goto EXIT;
    }

REDIRECTED:
    if( pHttpGetReq->bIsRedirect)
    {
        if( _ansc_strstr((PCHAR)pHttpGetReq->pContent, "http") == pHttpGetReq->pContent)
        {
            if ( pMyObject->AcsUrl ) CcspTr069PaFreeMemory(pMyObject->AcsUrl);
            pMyObject->AcsUrl = CcspTr069PaCloneString(pHttpGetReq->pContent);
        }
        else
        {
            /* if it's partial path */
            pTempString = _ansc_strstr(pRequestURL, "//");

            if( pTempString == NULL)
            {
                returnStatus = ANSC_STATUS_FAILURE;

                goto EXIT;
            }

            pTempString += AnscSizeOfString("//");
            pTempString  = _ansc_strstr(pTempString, "/");

            if( pTempString == NULL)
            {
                returnStatus = ANSC_STATUS_FAILURE;

                goto EXIT;
            }

            AnscCopyMemory(pNewUrl, pRequestURL, (ULONG)(pTempString - pRequestURL));
            AnscCatString(pNewUrl, (PCHAR)pHttpGetReq->pContent);

            if ( pMyObject->AcsUrl ) CcspTr069PaFreeMemory(pMyObject->AcsUrl);
            pMyObject->AcsUrl = CcspTr069PaCloneString(pNewUrl);
        }

        uRedirect ++;

        if( uRedirect >= uMaxRedirect)
        {
            CcspTr069PaTraceDebug(("Maximum Redirection reached. Give up!\n"));

            returnStatus = ANSC_STATUS_FAILURE;

            goto EXIT;
        }
        else
        {
            CcspTr069PaTraceDebug(("Acs connection redirection #%u: '%s'\n", (unsigned int)uRedirect, pMyObject->AcsUrl));

            /* in case redirected ACS challenges CPE again */
            nMaxAuthRetries = 2;

            /* tear down current HTTP session before redirecting to new ACS,
             * otherwise, there might be case that ACS sends out redirection
             * response and immediately closes the socket, CWMP may be 
             * confused by closing CWMP session prematurely. 
             */
            pHttpClient->DelAllWcsos((ANSC_HANDLE)pHttpClient);

            goto START;
        }
    }

    if(pWmpSession != NULL)
    {
        if( pHttpGetReq->ulContentSize > 0 && pHttpGetReq->pContent != NULL)
        {
            CcspTr069PaTraceDebug(("Response:\n%s\n", (char*)pHttpGetReq->pContent));

            returnStatus =
                pWmpSession->RecvSoapMessage
                    (
                       pWmpSession,
                       (PCHAR)pHttpGetReq->pContent
                    );
        }
        else
        {
            CcspTr069PaTraceDebug(("Response: <EMPTY>\n"));

            returnStatus =
                pCcspCwmpMcoIf->NotifyAcsStatus
                    (
                        pCcspCwmpMcoIf->hOwnerContext,
                        TRUE,           /* no more requests */
                        FALSE
                    );
        }
    }

EXIT:

    if(pHttpGetReq->pContent != NULL)
    {
        CcspTr069PaFreeMemory(pHttpGetReq->pContent);

        pHttpGetReq->pContent = NULL;
    }

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

    return returnStatus;
}