ANSC_STATUS
AnscSctoTsaSendTlsMessage
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hMessageBdo
    )
{
    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;
    PANSC_BUFFER_DESCRIPTOR         pPayloadBdo  = (PANSC_BUFFER_DESCRIPTOR)hMessageBdo;

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

    AnscFreeBdo((ANSC_HANDLE)pPayloadBdo);

    return  returnStatus;
}
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
HttpPsoVer2FinishedByClient
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus   = ANSC_STATUS_SUCCESS;
    PHTTP_PSO_VER2_OBJECT           pMyObject      = (PHTTP_PSO_VER2_OBJECT         )hThisObject;
    PHTTP_ADVANCED_PROXY_OBJECT     pAdvancedProxy = (PHTTP_ADVANCED_PROXY_OBJECT   )pMyObject->hOwnerContext;
    PHTTP_WAM_INTERFACE             pWamIf         = (PHTTP_WAM_INTERFACE           )pMyObject->hWamIf;
    PHTTP_SBC_INTERFACE             pSbcIf         = (PHTTP_SBC_INTERFACE           )pMyObject->hSbcIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pClientSocket  = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hClientSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp    = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_TRANS_RECORD_OBJECT       pTransRecord   = (PHTTP_TRANS_RECORD_OBJECT     )pMyObject->GetLastTro((ANSC_HANDLE)pMyObject);

    if ( !pTransRecord )
    {
        if ( pBufferDesp )
        {
            AnscFreeBdo((ANSC_HANDLE)pBufferDesp);
        }

        return  ANSC_STATUS_INTERNAL_ERROR;
    }
    else if ( pTransRecord->GetTransState((ANSC_HANDLE)pTransRecord) == HTTP_TRO_STATE_FINISHED )
    {
        if ( pBufferDesp )
        {
            AnscFreeBdo((ANSC_HANDLE)pBufferDesp);
        }

        pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);

        return  ANSC_STATUS_UNAPPLICABLE;
    }

    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pTransRecord->FinishedByClient
            (
                (ANSC_HANDLE)pTransRecord,
                buffer,
                ulSize,
                (ANSC_HANDLE)pBufferDesp
            );

    pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);

    return  returnStatus;
}
ANSC_STATUS
HttpWssoFinish
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_WEBS_SESSION_OBJECT       pMyObject     = (PHTTP_WEBS_SESSION_OBJECT     )hThisObject;
    PHTTP_SIMPLE_SERVER_OBJECT      pSimpleServer = (PHTTP_SIMPLE_SERVER_OBJECT    )pMyObject->hOwnerContext;
    PHTTP_WSP_INTERFACE             pWspIf        = (PHTTP_WSP_INTERFACE           )pMyObject->hWspIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pWebSocket    = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hWebSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_WEBS_TRANS_OBJECT         pWebsTrans    = (PHTTP_WEBS_TRANS_OBJECT       )pMyObject->GetEndWsto((ANSC_HANDLE)pMyObject);

    if ( !pWebsTrans )
    {
        if ( pBufferDesp )
        {
            AnscFreeBdo((ANSC_HANDLE)pBufferDesp);
        }

        return  ANSC_STATUS_INTERNAL_ERROR;
    }
    else if ( pWebsTrans->GetTransState((ANSC_HANDLE)pWebsTrans) == HTTP_WSTO_STATE_FINISHED )
    {
        if ( pBufferDesp )
        {
            AnscFreeBdo((ANSC_HANDLE)pBufferDesp);
        }

        pWebsTrans->ReleaseAccess((ANSC_HANDLE)pWebsTrans);

        return  ANSC_STATUS_UNAPPLICABLE;
    }

    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pWebsTrans->Finish
            (
                (ANSC_HANDLE)pWebsTrans,
                buffer,
                ulSize,
                (ANSC_HANDLE)pBufferDesp
            );

    pWebsTrans->ReleaseAccess((ANSC_HANDLE)pWebsTrans);

    return  returnStatus;
}
ANSC_STATUS
HttpTroRecvFromClient
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus   = ANSC_STATUS_SUCCESS;
    PHTTP_TRANS_RECORD_OBJECT       pMyObject      = (PHTTP_TRANS_RECORD_OBJECT     )hThisObject;
    PHTTP_ADVANCED_PROXY_OBJECT     pAdvancedProxy = (PHTTP_ADVANCED_PROXY_OBJECT   )pMyObject->hOwnerContext;
    PHTTP_WAM_INTERFACE             pWamIf         = (PHTTP_WAM_INTERFACE           )pMyObject->hWamIf;
    PHTTP_SBC_INTERFACE             pSbcIf         = (PHTTP_SBC_INTERFACE           )pMyObject->hSbcIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pClientSocket  = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hClientSocket;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pServerSocket  = (PANSC_BROKER_SOCKET_TCP_OBJECT)pMyObject->hServerSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp    = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_BMO_REQ_OBJECT            pBmoReq        = (PHTTP_BMO_REQ_OBJECT          )pMyObject->hBmoReq;
    ULONG                           ulBmoState     = HTTP_BMO_STATE_EMPTY;

    /*
     * At time like this, you will always have two options on how to proceed with the message
     * processing:
     *
     *      $ Examine the current object states and the content of the message payload
     *        to make the processing decisions in this object.
     *
     *      $ Offload the examination and certain state-transition functions to another
     *        object and provide an interface to be notified when something happens.
     *
     * Guess which one we're using here ...
     */
    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pBmoReq->Process
            (
                (ANSC_HANDLE)pBmoReq,
                (ANSC_HANDLE)pBufferDesp
            );

    if ( (returnStatus != ANSC_STATUS_SUCCESS    ) &&
         (returnStatus != ANSC_STATUS_DO_IT_AGAIN) )
    {
        pMyObject->TransState = HTTP_TRO_STATE_FINISHED;
    }

    return  returnStatus;
}
ANSC_STATUS
HttpPsoVer2RecvFromClient
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus   = ANSC_STATUS_SUCCESS;
    PHTTP_PSO_VER2_OBJECT           pMyObject      = (PHTTP_PSO_VER2_OBJECT         )hThisObject;
    PHTTP_ADVANCED_PROXY_OBJECT     pAdvancedProxy = (PHTTP_ADVANCED_PROXY_OBJECT   )pMyObject->hOwnerContext;
    PHTTP_WAM_INTERFACE             pWamIf         = (PHTTP_WAM_INTERFACE           )pMyObject->hWamIf;
    PHTTP_SBC_INTERFACE             pSbcIf         = (PHTTP_SBC_INTERFACE           )pMyObject->hSbcIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pClientSocket  = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hClientSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp    = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_TRANS_RECORD_OBJECT       pTransRecord   = (PHTTP_TRANS_RECORD_OBJECT     )pMyObject->GetCurTro((ANSC_HANDLE)pMyObject);

    if ( !pTransRecord )
    {
        pMyObject->SessionState = HTTP_PSOVER2_STATE_FINISHED;

        return  ANSC_STATUS_INTERNAL_ERROR;
    }

    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pTransRecord->RecvFromClient
            (
                (ANSC_HANDLE)pTransRecord,
                buffer,
                ulSize,
                (ANSC_HANDLE)pBufferDesp
            );

    if ( (returnStatus != ANSC_STATUS_SUCCESS    ) &&
         (returnStatus != ANSC_STATUS_DO_IT_AGAIN) )
    {
        pMyObject->SessionState = HTTP_PSOVER2_STATE_FINISHED;
    }

    pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);

    return  returnStatus;
}
ANSC_STATUS
HttpWssoRecv
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_WEBS_SESSION_OBJECT       pMyObject     = (PHTTP_WEBS_SESSION_OBJECT     )hThisObject;
    PHTTP_SIMPLE_SERVER_OBJECT      pSimpleServer = (PHTTP_SIMPLE_SERVER_OBJECT    )pMyObject->hOwnerContext;
    PHTTP_WSP_INTERFACE             pWspIf        = (PHTTP_WSP_INTERFACE           )pMyObject->hWspIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pWebSocket    = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hWebSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_WEBS_TRANS_OBJECT         pWebsTrans    = (PHTTP_WEBS_TRANS_OBJECT       )pMyObject->GetCurWsto((ANSC_HANDLE)pMyObject);

    if ( !pWebsTrans )
    {
        pMyObject->SessionState = HTTP_WSSO_STATE_FINISHED;

        return  ANSC_STATUS_INTERNAL_ERROR;
    }

    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pWebsTrans->Recv
            (
                (ANSC_HANDLE)pWebsTrans,
                buffer,
                ulSize,
                (ANSC_HANDLE)pBufferDesp
            );

    if ( (returnStatus != ANSC_STATUS_SUCCESS    ) &&
         (returnStatus != ANSC_STATUS_DO_IT_AGAIN) )
    {
        pMyObject->SessionState = HTTP_WSSO_STATE_FINISHED;
    }

    pWebsTrans->ReleaseAccess((ANSC_HANDLE)pWebsTrans);

    return  returnStatus;
}
ANSC_STATUS
HttpTroFinishedByClient
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus   = ANSC_STATUS_SUCCESS;
    PHTTP_TRANS_RECORD_OBJECT       pMyObject      = (PHTTP_TRANS_RECORD_OBJECT     )hThisObject;
    PHTTP_ADVANCED_PROXY_OBJECT     pAdvancedProxy = (PHTTP_ADVANCED_PROXY_OBJECT   )pMyObject->hOwnerContext;
    PHTTP_WAM_INTERFACE             pWamIf         = (PHTTP_WAM_INTERFACE           )pMyObject->hWamIf;
    PHTTP_SBC_INTERFACE             pSbcIf         = (PHTTP_SBC_INTERFACE           )pMyObject->hSbcIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pClientSocket  = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hClientSocket;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pServerSocket  = (PANSC_BROKER_SOCKET_TCP_OBJECT)pMyObject->hServerSocket;
    PHTTP_BMO_REQ_OBJECT            pBmoReq        = (PHTTP_BMO_REQ_OBJECT          )pMyObject->hBmoReq;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp    = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    ULONG                           ulBmoState     = pBmoReq->GetState((ANSC_HANDLE)pBmoReq);

    if ( (ulBmoState == HTTP_BMO_STATE_COMPLETE   ) ||
         (ulBmoState == HTTP_BMO_STATE_OVER_PACKED) )
    {
        if ( pBufferDesp )
        {
            AnscFreeBdo((ANSC_HANDLE)pBufferDesp);
        }

        return  ANSC_STATUS_UNAPPLICABLE;
    }

    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pBmoReq->CloseUp
            (
                (ANSC_HANDLE)pBmoReq,
                (ANSC_HANDLE)pBufferDesp
            );

    return  returnStatus;
}
ANSC_STATUS
HttpWstoFinish
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_WEBS_TRANS_OBJECT         pMyObject     = (PHTTP_WEBS_TRANS_OBJECT       )hThisObject;
    PHTTP_SIMPLE_SERVER_OBJECT      pSimpleServer = (PHTTP_SIMPLE_SERVER_OBJECT    )pMyObject->hOwnerContext;
    PHTTP_WSP_INTERFACE             pWspIf        = (PHTTP_WSP_INTERFACE           )pMyObject->hWspIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pWebSocket    = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hWebSocket;
    PHTTP_BMO_REQ_OBJECT            pBmoReq       = (PHTTP_BMO_REQ_OBJECT          )pMyObject->hBmoReq;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    ULONG                           ulBmoState    = pBmoReq->GetState((ANSC_HANDLE)pBmoReq);

    if ( (ulBmoState == HTTP_BMO_STATE_COMPLETE   ) ||
         (ulBmoState == HTTP_BMO_STATE_OVER_PACKED) )
    {
        if ( pBufferDesp )
        {
            AnscFreeBdo((ANSC_HANDLE)pBufferDesp);
        }

        return  ANSC_STATUS_UNAPPLICABLE;
    }

    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pBmoReq->CloseUp
            (
                (ANSC_HANDLE)pBmoReq,
                (ANSC_HANDLE)pBufferDesp
            );

    return  returnStatus;
}
ULONG
HttpWstoQuery
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_WEBS_TRANS_OBJECT         pMyObject     = (PHTTP_WEBS_TRANS_OBJECT       )hThisObject;
    PHTTP_SIMPLE_SERVER_OBJECT      pSimpleServer = (PHTTP_SIMPLE_SERVER_OBJECT    )pMyObject->hOwnerContext;
    PHTTP_WSP_INTERFACE             pWspIf        = (PHTTP_WSP_INTERFACE           )pMyObject->hWspIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pWebSocket    = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hWebSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_BMO_REQ_OBJECT            pBmoReq       = (PHTTP_BMO_REQ_OBJECT          )pMyObject->hBmoReq;
    ULONG                           ulWstoQmode   = HTTP_WSTO_QMODE_COLLECT;
    ULONG                           ulBmoState1   = HTTP_BMO_STATE_EMPTY;
    ULONG                           ulBmoState2   = HTTP_BMO_STATE_EMPTY;

    /*
     * The decision on how to process the received payload should be made based on two message
     * states: the message state before payload arrival and the state after. The caller must ensure
     * the consistency of the buffer descriptor.
     */
    buffer      = AnscBdoGetBlock    (pBufferDesp);
    ulSize      = AnscBdoGetBlockSize(pBufferDesp);
    ulBmoState1 = pBmoReq->GetState((ANSC_HANDLE)pBmoReq);
    ulBmoState2 =
        pBmoReq->Examine
            (
                (ANSC_HANDLE)pBmoReq,
                buffer,
                ulSize
            );

    switch ( ulBmoState2 )
    {
        case    HTTP_BMO_STATE_EMPTY :
        case    HTTP_BMO_STATE_PART_HEADER :

                ulWstoQmode = HTTP_WSTO_QMODE_COLLECT;

                break;

        case    HTTP_BMO_STATE_HEADER_ARRIVED :

                ulWstoQmode = HTTP_WSTO_QMODE_PROCESS;

                break;

        case    HTTP_BMO_STATE_PART_BODY :

                if ( ulBmoState1 == HTTP_BMO_STATE_PART_BODY )
                {
                    if ( AnscBdoGetLeftSize(pBufferDesp) >= HTTP_SSO_RECV_BUFFER_ROOM )
                    {
                        ulWstoQmode = HTTP_WSTO_QMODE_COLLECT;
                    }
                    else
                    {
                        ulWstoQmode = HTTP_WSTO_QMODE_PROCESS;
                    }
                }
                else
                {
                    ulWstoQmode = HTTP_WSTO_QMODE_PROCESS;
                }

                break;

        case    HTTP_BMO_STATE_COMPLETE :
        case    HTTP_BMO_STATE_OVER_PACKED :

                ulWstoQmode = HTTP_WSTO_QMODE_PROCESS;

                break;

        case    HTTP_BMO_STATE_UNKNOWN :

                ulWstoQmode = HTTP_WSTO_QMODE_PROCESS;

                break;

        default :

                ulWstoQmode = HTTP_WSTO_QMODE_COLLECT;

                break;
    }

    return  ulWstoQmode;
}
ULONG
HttpTroQueryForClient
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus   = ANSC_STATUS_SUCCESS;
    PHTTP_TRANS_RECORD_OBJECT       pMyObject      = (PHTTP_TRANS_RECORD_OBJECT     )hThisObject;
    PHTTP_ADVANCED_PROXY_OBJECT     pAdvancedProxy = (PHTTP_ADVANCED_PROXY_OBJECT   )pMyObject->hOwnerContext;
    PHTTP_WAM_INTERFACE             pWamIf         = (PHTTP_WAM_INTERFACE           )pMyObject->hWamIf;
    PHTTP_SBC_INTERFACE             pSbcIf         = (PHTTP_SBC_INTERFACE           )pMyObject->hSbcIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pClientSocket  = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hClientSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp    = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_BMO_REQ_OBJECT            pBmoReq        = (PHTTP_BMO_REQ_OBJECT          )pMyObject->hBmoReq;
    ULONG                           ulTroQmode     = HTTP_TRO_QMODE_FORWARD;
    ULONG                           ulBmoState1    = HTTP_BMO_STATE_EMPTY;
    ULONG                           ulBmoState2    = HTTP_BMO_STATE_EMPTY;

    /*
     * If the SBC (Server Behavior Controller) has allowed everything to be relayed internally by
     * the proxy object itself (or simply because there's no SBC registered), we SHALL pass payload
     * data from one socket to the other, whenever there's data available.
     */
    if ( (pMyObject->TransState == HTTP_TRO_STATE_ESTABLISHED) &&
         (pMyObject->SbcPmode   == HTTP_SBC_PMODE_RELAY2     ) )
    {
        return  HTTP_TRO_QMODE_FORWARD;
    }

    /*
     * The decision on how to process the received payload should be made based on two message
     * states: the message state before payload arrival and the state after. The caller must ensure
     * the consistency of the buffer descriptor.
     */
    buffer      = AnscBdoGetBlock    (pBufferDesp);
    ulSize      = AnscBdoGetBlockSize(pBufferDesp);
    ulBmoState1 = pBmoReq->GetState((ANSC_HANDLE)pBmoReq);
    ulBmoState2 =
        pBmoReq->Examine
            (
                (ANSC_HANDLE)pBmoReq,
                buffer,
                ulSize
            );

    switch ( ulBmoState2 )
    {
        case    HTTP_BMO_STATE_EMPTY :
        case    HTTP_BMO_STATE_PART_HEADER :

                ulTroQmode = HTTP_TRO_QMODE_COLLECT;

                break;

        case    HTTP_BMO_STATE_HEADER_ARRIVED :

                ulTroQmode = HTTP_TRO_QMODE_PROCESS;

                break;

        case    HTTP_BMO_STATE_PART_BODY :

                if ( ulBmoState1 == HTTP_BMO_STATE_PART_BODY )
                {
                    if ( AnscBdoGetLeftSize(pBufferDesp) > HTTP_SPO_RECV_BUFFER_ROOM )
                    {
                        ulTroQmode = HTTP_TRO_QMODE_COLLECT;
                    }
                    else
                    {
                        ulTroQmode = HTTP_TRO_QMODE_PROCESS;
                    }
                }
                else
                {
                    ulTroQmode = HTTP_TRO_QMODE_PROCESS;
                }

                break;

        case    HTTP_BMO_STATE_COMPLETE :
        case    HTTP_BMO_STATE_OVER_PACKED :

                ulTroQmode = HTTP_TRO_QMODE_PROCESS;

                break;

        case    HTTP_BMO_STATE_UNKNOWN :

                ulTroQmode = HTTP_TRO_QMODE_PROCESS;

                break;

        default :

                ulTroQmode = HTTP_TRO_QMODE_COLLECT;

                break;
    }

    return  ulTroQmode;
}
ANSC_STATUS
HttpBmoReqParseStartLine
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_BMO_REQ_OBJECT            pMyObject     = (PHTTP_BMO_REQ_OBJECT   )hThisObject;
    PHTTP_HFP_INTERFACE             pHfpIf        = (PHTTP_HFP_INTERFACE    )pMyObject->hHfpIf;
    PANSC_BUFFER_DESCRIPTOR         pHeaderBdo    = (PANSC_BUFFER_DESCRIPTOR)pMyObject->hHeaderBdo;
    PHTTP_REQUEST_INFO              pReqInfo      = (PHTTP_REQUEST_INFO     )pMyObject->hReqInfo;
    PVOID                           pHeaderBuffer = NULL;
    ULONG                           ulBufferSize  = 0;
    char*                           pHfStart      = NULL;
    ULONG                           ulSkipSize    = 0;
    char*                           pRawHfLine    = NULL;
    char*                           pStdHfLine    = (char*)pMyObject->ScratchPad1;
    ULONG                           ulRawLineSize = 0;
    ULONG                           ulStdLineSize = 0;

    pMyObject->DelStartLine((ANSC_HANDLE)pMyObject);

    if ( !pHeaderBdo )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        pHeaderBuffer = AnscBdoGetBlock    (pHeaderBdo);
        ulBufferSize  = AnscBdoGetBlockSize(pHeaderBdo);
    }

    AnscHttpFindHfStart(pHeaderBuffer, ulBufferSize, pHfStart);

    if ( !pHfStart )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        ulSkipSize    = (ULONG)pHfStart - (ULONG)pHeaderBuffer;
        ulBufferSize -= ulSkipSize;
        pRawHfLine    = pHfStart;
    }

    AnscHttpGetHfLineSize(pRawHfLine, ulBufferSize, ulRawLineSize);

    if ( ulRawLineSize <= pMyObject->PadSize1 )
    {
        AnscHttpPrepareHeader(pRawHfLine, ulRawLineSize, pStdHfLine, ulStdLineSize);

        pStdHfLine[ulStdLineSize + 0] = HTTP_CARRIAGE_RETURN;
        pStdHfLine[ulStdLineSize + 1] = HTTP_LINE_FEED;

        pReqInfo =
            (PHTTP_REQUEST_INFO)pHfpIf->ParseRequestLine
                (
                    pHfpIf->hOwnerContext,
                    pStdHfLine,
                    ulStdLineSize
                );
    }
    else
    {
        pReqInfo = NULL;
    }

    if ( !pReqInfo )
    {
        return  ANSC_STATUS_BAD_PAYLOAD;
    }
    else
    {
        pMyObject->hReqInfo = (ANSC_HANDLE)pReqInfo;
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
HttpSpoPrvwoNotify
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        ULONG                       ulEvent,
        ANSC_HANDLE                 hReserved
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_SIMPLE_PROXY_OBJECT       pMyObject     = (PHTTP_SIMPLE_PROXY_OBJECT     )hThisObject;
    PHTTP_SIMPLE_PROXY_PROPERTY     pProperty     = (PHTTP_SIMPLE_PROXY_PROPERTY   )&pMyObject->Property;
    PANSC_SIMPLE_PROXY_TCP_OBJECT   pSimpleProxy  = (PANSC_SIMPLE_PROXY_TCP_OBJECT )pMyObject->hSimpleProxy;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pClientSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)hSocket;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pServerSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)NULL;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )pClientSocket->GetBufferContext((ANSC_HANDLE)pClientSocket);
    PHTTP_PROXY_SESSION_OBJECT      pSession      = NULL;

    AnscTrace
        (
            "Event = %d is indicated on client connection of %d.%d.%d.%d / TCP %d\n",
            ulEvent,
            pClientSocket->PeerAddress.Dot[0],
            pClientSocket->PeerAddress.Dot[1],
            pClientSocket->PeerAddress.Dot[2],
            pClientSocket->PeerAddress.Dot[3],
            pClientSocket->PeerPort
        );

    switch ( ulEvent )
    {
        case    ANSC_SPTOWO_EVENT_SOCKET_ERROR :

                pClientSocket->ToClean((ANSC_HANDLE)pClientSocket, TRUE, HTTP_SPO_SOCKET_TTC);

                break;

        case    ANSC_SPTOWO_EVENT_SOCKET_CLOSED :

                AnscAcquireLock(&pMyObject->SyncLock);

                pSession = (PHTTP_PROXY_SESSION_OBJECT)pClientSocket->GetClientContext((ANSC_HANDLE)pClientSocket);

                if ( !pSession )
                {
                    AnscReleaseLock(&pMyObject->SyncLock);

                    pClientSocket->Finish((ANSC_HANDLE)pClientSocket);

                    break;
                }
                else
                {
                    pSession->AcquireAccess((ANSC_HANDLE)pSession);
                }

                AnscReleaseLock(&pMyObject->SyncLock);

                pBufferDesp->BlockSize += pClientSocket->RecvPacketSize;
                returnStatus            =
                    pClientSocket->SetBufferContext
                        (
                            (ANSC_HANDLE)pClientSocket,
                            NULL,
                            0,
                            (ANSC_HANDLE)NULL
                        );

                returnStatus            =
                    pSession->FinishedByClient
                        (
                            (ANSC_HANDLE)pSession,
                            AnscBdoGetBlock    (pBufferDesp),
                            AnscBdoGetBlockSize(pBufferDesp),
                            (ANSC_HANDLE)pBufferDesp
                        );

                pSession->ReleaseAccess((ANSC_HANDLE)pSession);

                pClientSocket->Finish((ANSC_HANDLE)pClientSocket);

                break;

        case    ANSC_SPTOWO_EVENT_RESOURCES :

                break;

        case    ANSC_SPTOWO_EVENT_TIME_OUT :

                break;

        default :

                break;
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscDktoTsaRecvAppMessage
    (
        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;
    void*                           pRecvBuffer  = (void*                         )NULL;
    ANSC_HANDLE                     hRecvHandle  = (ANSC_HANDLE                   )NULL;
    ULONG                           ulRecvSize   = (ULONG                         )0;
    ULONG                           ulLeftSize   = (ULONG                         )AnscBdoGetBlockSize(pPayloadBdo);
    ULONG                           ulCopySize   = (ULONG                         )0;
    ULONG                           ulServingT1  = 0;
    ULONG                           ulServingT2  = 0;
    ULONG                           ulWaitCount  = 0;

    /*
     * Since the TLS handshake is done in the asynchronous task instead of the socket_recv task,
     * it's possible that we start receiving TLS client data traffic (i.e. HTTP) before handshake
     * task considers the handshaking is done. To accommodate such race condition, we need to sleep
     * for a while if there's no buffer available.
     */
    while ( !pMyObject->GetRecvBuffer
                (
                    (ANSC_HANDLE)pMyObject,
                    &ulRecvSize
                ) )
    {
        AnscSleep(10);

        ulWaitCount++;

        if ( ulWaitCount > 30 ) /* sleep for 300ms */
        {
            returnStatus = ANSC_STATUS_INTERNAL_ERROR;

            goto  EXIT1;
        }
    }

    while ( ulLeftSize > 0 )
    {
        pRecvBuffer =
            pMyObject->GetRecvBuffer
                (
                    (ANSC_HANDLE)pMyObject,
                    &ulRecvSize
                );

        if ( !pRecvBuffer )
        {
            returnStatus =
                pWorker->Notify
                    (
                        pWorker->hWorkerContext,
                        (ANSC_HANDLE)pMyObject,
                        ANSC_DSTOWO_EVENT_RESOURCES,
                        (ANSC_HANDLE)NULL
                    );

            break;
        }
        else if ( ulRecvSize == 0 )
        {
            pMyObject->ToClean((ANSC_HANDLE)pMyObject, TRUE, 2);

            break;
        }

        if ( ulRecvSize >= ulLeftSize )
        {
            ulCopySize = ulLeftSize;
        }
        else
        {
            ulCopySize = ulRecvSize;
        }

        if ( TRUE )
        {
            AnscCopyMemory
                (
                    pRecvBuffer,
                    AnscBdoGetBlock(pPayloadBdo),
                    ulCopySize
                );

            AnscBdoShrinkRight(pPayloadBdo, ulCopySize);

            ulLeftSize -= ulCopySize;
        }

        pMyObject->RecvBytesCount += ulCopySize;
        pMyObject->LastRecvAt      = AnscGetTickInSecondsAbs();

        /*
         * We have successfully transferred the received data into the buffer supplied by the
         * socket owener though may not use up the while buffer. Now is time to notify our loyal
         * socket owner about this exciting event.
         */
        ulServingT1  = AnscGetTickInMilliSeconds();
        returnStatus =
            pMyObject->Recv
                (
                    (ANSC_HANDLE)pMyObject,
                    pRecvBuffer,
                    ulCopySize
                );
        ulServingT2  = AnscGetTickInMilliSeconds();

        pEngine->AvgServingTime =
            (pEngine->AvgServingTime == 0)? (ulServingT2 - ulServingT1) : ((ulServingT2 - ulServingT1) + pEngine->AvgServingTime * 7) / 8;
        pEngine->TscCount++;
    }

    goto  EXIT1;


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

EXIT1:

    if ( pPayloadBdo )
    {
        AnscFreeBdo((ANSC_HANDLE)pPayloadBdo);
    }

    return  returnStatus;
}
ANSC_STATUS
HttpWstoRecv
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hBufferContext
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_WEBS_TRANS_OBJECT         pMyObject     = (PHTTP_WEBS_TRANS_OBJECT       )hThisObject;
    PHTTP_SIMPLE_SERVER_OBJECT      pSimpleServer = (PHTTP_SIMPLE_SERVER_OBJECT    )pMyObject->hOwnerContext;
    PHTTP_WSP_INTERFACE             pWspIf        = (PHTTP_WSP_INTERFACE           )pMyObject->hWspIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pWebSocket    = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pMyObject->hWebSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )hBufferContext;
    PHTTP_BMO_REQ_OBJECT            pBmoReq       = (PHTTP_BMO_REQ_OBJECT          )pMyObject->hBmoReq;
    ULONG                           ulBmoState    = HTTP_BMO_STATE_EMPTY;

    pBmoReq->SetFumIf((ANSC_HANDLE)pBmoReq, pSimpleServer->GetFumIf((ANSC_HANDLE)pSimpleServer));

    pBmoReq->SetWebSessionId((ANSC_HANDLE)pBmoReq, (ULONG)pMyObject->hWebsSession);

    /*
     * At time like this, you will always have two options on how to proceed with the message
     * processing:
     *
     *      $ Examine the current object states and the content of the message payload
     *        to make the processing decisions in this object.
     *
     *      $ Offload the examination and certain state-transition functions to another
     *        object and provide an interface to be notified when something happens.
     *
     * Guess which one we're using here ...
     */
    buffer       = AnscBdoGetBlock    (pBufferDesp);
    ulSize       = AnscBdoGetBlockSize(pBufferDesp);
    returnStatus =
        pBmoReq->Process
            (
                (ANSC_HANDLE)pBmoReq,
                (ANSC_HANDLE)pBufferDesp
            );

    if ( (returnStatus != ANSC_STATUS_SUCCESS    ) &&
         (returnStatus != ANSC_STATUS_DO_IT_AGAIN) )
    {
        pMyObject->TransState = HTTP_WSTO_STATE_FINISHED;
    }

    if ( (pMyObject->TransState == HTTP_WSTO_STATE_ESTABLISHED) ||
         (pMyObject->TransState == HTTP_WSTO_STATE_FINISHED   ) )
    {
        /*
         * To avoid unnessary memory consumption, we release the resources allocated for this
         * transaction right away...
         */
        pMyObject->Close((ANSC_HANDLE)pMyObject);
    }

    return  returnStatus;
}
ANSC_STATUS
HttpBmoCopyHeadersFrom
    (
        ANSC_HANDLE                 hThisObject,
        PVOID                       buffer,
        PULONG                      pulSize
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_BASIC_MESSAGE_OBJECT      pMyObject     = (PHTTP_BASIC_MESSAGE_OBJECT)hThisObject;
    PHTTP_HFP_INTERFACE             pHfpIf        = (PHTTP_HFP_INTERFACE       )pMyObject->hHfpIf;
    PANSC_BUFFER_DESCRIPTOR         pHeaderBdo    = (PANSC_BUFFER_DESCRIPTOR   )pMyObject->hHeaderBdo;
    PHTTP_HEADER_FIELD              pHttpHfo      = NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry   = NULL;
    ULONG                           ulHeadersSize = 0;
    ULONG                           ulCopySize    = 0;
    ULONG                           ulLeftSize    = *pulSize;
    char*                           pHfStream     = (char*)buffer;
    ULONG                           i             = 0;

    if ( *pulSize < pMyObject->GetHeadersSize((ANSC_HANDLE)pMyObject) )
    {
        return  ANSC_STATUS_BAD_SIZE;
    }
    else if ( pHeaderBdo )
    {
        AnscCopyMemory
            (
                buffer,
                AnscBdoGetBlock    (pHeaderBdo),
                AnscBdoGetBlockSize(pHeaderBdo)
            );

        *pulSize = AnscBdoGetBlockSize(pHeaderBdo);

        return  ANSC_STATUS_SUCCESS;
    }

    ulCopySize   = ulLeftSize;
    pHfStream    = (char*)((ULONG)buffer + ulHeadersSize);
    returnStatus =
        pMyObject->CopyStartLineFrom
            (
                (ANSC_HANDLE)pMyObject,
                (PVOID)pHfStream,
                &ulCopySize
            );

    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        return  returnStatus;
    }
    else
    {
        pHfStream     += ulCopySize;
        ulHeadersSize += ulCopySize;
        ulLeftSize    -= ulCopySize;

        pHfStream[0] = HTTP_CARRIAGE_RETURN;
        pHfStream[1] = HTTP_LINE_FEED;

        pHfStream     += 2;
        ulHeadersSize += 2;
        ulLeftSize    -= 2;
    }

    AnscAcquireLock(&pMyObject->HfoTableLock);

    for ( i = 0; i < HTTP_BMO_HFO_TABLE_SIZE; i++ )
    {
        pSLinkEntry = AnscQueueGetFirstEntry(&pMyObject->HfoTable[i]);

        while ( pSLinkEntry )
        {
            pHttpHfo    = ACCESS_HTTP_HEADER_FIELD(pSLinkEntry);
            pSLinkEntry = AnscQueueGetNextEntry(pSLinkEntry);

            ulCopySize  = pHfpIf->GetHeaderSize(pHfpIf->hOwnerContext, (ANSC_HANDLE)pHttpHfo);

            if ( ulCopySize > 0 )
            {
                returnStatus =
                    pHfpIf->BuildHeader
                        (
                            pHfpIf->hOwnerContext,
                            (ANSC_HANDLE)pHttpHfo,
                            (PVOID)pHfStream,
                            ulCopySize
                        );

                if ( returnStatus != ANSC_STATUS_SUCCESS )
                {
                    return  returnStatus;
                }
                else
                {
                    pHfStream     += ulCopySize;
                    ulHeadersSize += ulCopySize;
                    ulLeftSize    -= ulCopySize;

                    pHfStream[0] = HTTP_CARRIAGE_RETURN;
                    pHfStream[1] = HTTP_LINE_FEED;

                    pHfStream     += 2;
                    ulHeadersSize += 2;
                    ulLeftSize    -= 2;
                }
            }
        }
    }

    AnscReleaseLock(&pMyObject->HfoTableLock);

    pHfStream[0] = HTTP_CARRIAGE_RETURN;
    pHfStream[1] = HTTP_LINE_FEED;

    pHfStream     += 2;
    ulHeadersSize += 2;
    ulLeftSize    -= 2;

    *pulSize = ulHeadersSize;

    return  ANSC_STATUS_SUCCESS;
}
ULONG
AnscLpccoTcpBwoQuery
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        PVOID                       buffer,
        ULONG                       ulSize,
        PANSC_HANDLE                phQueryContext
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PANSC_LPCCO_TCP_OBJECT          pMyObject     = (PANSC_LPCCO_TCP_OBJECT        )hThisObject;
    PANSC_DAEMON_SERVER_TCP_OBJECT  pDaemonServer = (PANSC_DAEMON_SERVER_TCP_OBJECT)pMyObject->hDaemonServer;
    PANSC_BROKER_SERVER_TCP_OBJECT  pBrokerServer = (PANSC_BROKER_SERVER_TCP_OBJECT)pMyObject->hBrokerServer;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pBrokerSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)hSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )pBrokerSocket->GetBufferContext((ANSC_HANDLE)pBrokerSocket);
    PANSC_BUFFER_DESCRIPTOR         pNewBdo       = (PANSC_BUFFER_DESCRIPTOR       )NULL;
    PIMCP_HEADER                    pImcpHeader   = (PIMCP_HEADER                  )NULL;
    ULONG                           ulMsgSize     = (ULONG                         )0;
    ULONG                           ulCopySize    = (ULONG                         )0;
    ULONG                           ulLeftSize    = (ULONG                         )0;
    ULONG                           i             = 0;

    if ( !pBufferDesp )
    {
        return  ANSC_BSTOWO_PMODE_FINISH;
    }
    else
    {
        pBufferDesp->BlockSize += ulSize;
    }

    if ( AnscBdoGetUsableSize(pBufferDesp) <= sizeof(IMCP_HEADER) )
    {
        pNewBdo =
            (PANSC_BUFFER_DESCRIPTOR)AnscAllocateBdo
                (
                    ANSC_LPC_DEF_MESSAGE_SIZE,
                    0,
                    AnscBdoGetBlockSize(pBufferDesp)
                );

        if ( !pNewBdo )
        {
            return  ANSC_BSTOWO_PMODE_FINISH;
        }
        else
        {
            ulCopySize   = AnscBdoGetBlockSize(pBufferDesp);
            returnStatus =
                AnscBdoCopyFrom
                    (
                        (ANSC_HANDLE)pBufferDesp,
                        AnscBdoGetBlock(pNewBdo),
                        &ulCopySize,
                        0
                    );

            pBrokerSocket->SetBufferContext
                (
                    (ANSC_HANDLE)pBrokerSocket,
                    AnscBdoGetEndOfBlock(pNewBdo),
                    AnscBdoGetLeftSize  (pNewBdo),
                    (ANSC_HANDLE)pNewBdo
                );
        }

        AnscFreeBdo((ANSC_HANDLE)pBufferDesp);

        return  ANSC_BSTOWO_PMODE_COLLECT;
    }
    else if ( AnscBdoGetBlockSize(pBufferDesp) < sizeof(IMCP_HEADER) )
    {
        /*
         * We need to rollback the block size of the buffer descriptor before we return 'Collect'.
         * Next time when this Query() function is called, the 'ulSize' parameter will be set to
         * the total size of un-processed data, not the size of the newly received data.
         */
        pBufferDesp->BlockSize -= ulSize;

        return  ANSC_BSTOWO_PMODE_COLLECT;
    }
    else
    {
        pImcpHeader = (PIMCP_HEADER)AnscBdoGetBlock(pBufferDesp);
        ulMsgSize   = (ULONG       )ImcpGetMsgSize (pImcpHeader);
    }

    if ( ulMsgSize == AnscBdoGetBlockSize(pBufferDesp) )
    {
        pNewBdo =
            (PANSC_BUFFER_DESCRIPTOR)AnscAllocateBdo
                (
                    ANSC_LPC_DEF_MESSAGE_SIZE,
                    0,
                    0
                );

        if ( !pNewBdo )
        {
            return  ANSC_BSTOWO_PMODE_FINISH;
        }
        else
        {
            pBrokerSocket->SetBufferContext
                (
                    (ANSC_HANDLE)pBrokerSocket,
                    AnscBdoGetEndOfBlock(pNewBdo),
                    AnscBdoGetLeftSize  (pNewBdo),
                    (ANSC_HANDLE)pNewBdo
                );
        }

        returnStatus =
            pMyObject->Recv
                (
                    (ANSC_HANDLE)pMyObject,
                    (ANSC_HANDLE)pBrokerSocket,
                    (ANSC_HANDLE)pBufferDesp
                );

        return  ANSC_BSTOWO_PMODE_DISCARD;
    }
    else if ( ulMsgSize < AnscBdoGetBlockSize(pBufferDesp) )
    {
        pNewBdo =
            (PANSC_BUFFER_DESCRIPTOR)AnscAllocateBdo
                (
                    ulMsgSize,
                    0,
                    ulMsgSize
                );

        if ( !pNewBdo )
        {
            return  ANSC_BSTOWO_PMODE_FINISH;
        }
        else
        {
            ulCopySize   = ulMsgSize;
            returnStatus =
                AnscBdoCopyFrom
                    (
                        (ANSC_HANDLE)pBufferDesp,
                        AnscBdoGetBlock(pNewBdo),
                        &ulCopySize,
                        0
                    );
        }

        returnStatus =
            pMyObject->Recv
                (
                    (ANSC_HANDLE)pMyObject,
                    (ANSC_HANDLE)pBrokerSocket,
                    (ANSC_HANDLE)pNewBdo
                );

        /*
         * As Lina discovered, we cannot simply reset the 'BlockSize' to zero and make another
         * Query() call. If we do and the returned mode is COLLECT, the socket object would be
         * confused because the data processed in this call is still remembered and its size will
         * be covered in the next Query() call. We need to follow the steps as listed below to
         * ensure the packet data in the previous call is cleaned:
         *
         *      - Set the 'BlockSize' to whatever data left after processing.
         *      - Advance 'Offset' field by the message size.
         *      - Reset the buffer context of the socket object.
         *      - Calling Query() again with 'ulSize' set to zero.
         */
        ulLeftSize              = AnscBdoGetBlockSize(pBufferDesp) - ulMsgSize;
        pBufferDesp->Offset    += ulMsgSize;
        pBufferDesp->BlockSize -= ulMsgSize;

        pBrokerSocket->SetBufferContext
            (
                (ANSC_HANDLE)pBrokerSocket,
                AnscBdoGetEndOfBlock(pBufferDesp),
                AnscBdoGetLeftSize  (pBufferDesp),
                (ANSC_HANDLE)pBufferDesp
            );

        return  pMyObject->BwoQuery
                    (
                        (ANSC_HANDLE)pMyObject,
                        (ANSC_HANDLE)pBrokerSocket,
                        AnscBdoGetEndOfBlock(pBufferDesp),  /*AnscBdoGetBlock(pBufferDesp),*/
                        0,                                  /*ulLeftSize,                  */
                        phQueryContext
                    );
    }
    else if ( ulMsgSize <= AnscBdoGetUsableSize(pBufferDesp) )
    {
        /*
         * We need to rollback the block size of the buffer descriptor before we return 'Collect'.
         * Next time when this Query() function is called, the 'ulSize' parameter will be set to
         * the total size of un-processed data, not the size of the newly received data.
         */
        pBufferDesp->BlockSize -= ulSize;

        return  ANSC_BSTOWO_PMODE_COLLECT;
    }
    else
    {
        pNewBdo =
            (PANSC_BUFFER_DESCRIPTOR)AnscAllocateBdo
                (
                    ulMsgSize,
                    0,
                    AnscBdoGetBlockSize(pBufferDesp)
                );

        if ( !pNewBdo )
        {
            return  ANSC_BSTOWO_PMODE_FINISH;
        }
        else
        {
            ulCopySize   = AnscBdoGetBlockSize(pBufferDesp);
            returnStatus =
                AnscBdoCopyFrom
                    (
                        (ANSC_HANDLE)pBufferDesp,
                        AnscBdoGetBlock(pNewBdo),
                        &ulCopySize,
                        0
                    );

            pBrokerSocket->SetBufferContext
                (
                    (ANSC_HANDLE)pBrokerSocket,
                    AnscBdoGetEndOfBlock(pNewBdo),
                    AnscBdoGetLeftSize  (pNewBdo),
                    (ANSC_HANDLE)pNewBdo
                );
        }

        AnscFreeBdo((ANSC_HANDLE)pBufferDesp);

        return  ANSC_BSTOWO_PMODE_COLLECT;
    }

    return  ANSC_BSTOWO_PMODE_DISCARD;
}
ANSC_STATUS
HttpApoPubwoNotify
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        ULONG                       ulEvent,
        ANSC_HANDLE                 hReserved
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_ADVANCED_PROXY_OBJECT     pMyObject     = (PHTTP_ADVANCED_PROXY_OBJECT   )hThisObject;
    PHTTP_ADVANCED_PROXY_PROPERTY   pProperty     = (PHTTP_ADVANCED_PROXY_PROPERTY )&pMyObject->Property;
    PANSC_SIMPLE_PROXY_TCP_OBJECT   pSimpleProxy  = (PANSC_SIMPLE_PROXY_TCP_OBJECT )pMyObject->hSimpleProxy;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pServerSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)hSocket;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )pServerSocket->GetBufferContext((ANSC_HANDLE)pServerSocket);
    PHTTP_PSO_VER2_OBJECT           pPsoVer2      = NULL;
    PHTTP_TRANS_RECORD_OBJECT       pTransRecord  = NULL;

    AnscTrace
        (
            "Event = %d is indicated on server connection of %d.%d.%d.%d / TCP %d\n",
            ulEvent,
            pServerSocket->PeerAddress.Dot[0],
            pServerSocket->PeerAddress.Dot[1],
            pServerSocket->PeerAddress.Dot[2],
            pServerSocket->PeerAddress.Dot[3],
            pServerSocket->PeerPort
        );

    switch ( ulEvent )
    {
        case    ANSC_SPTOWO_EVENT_SOCKET_ERROR :

                pServerSocket->ToClean((ANSC_HANDLE)pServerSocket, TRUE, HTTP_APO_SOCKET_TTC);

                break;

        case    ANSC_SPTOWO_EVENT_SOCKET_CLOSED :

                AnscAcquireLock(&pMyObject->SyncLock);

                pPsoVer2 = (PHTTP_PSO_VER2_OBJECT)pServerSocket->GetClientContext((ANSC_HANDLE)pServerSocket);

                if ( pPsoVer2 )
                {
                    pPsoVer2->AcquireAccess((ANSC_HANDLE)pPsoVer2);

                    pTransRecord =
                        (PHTTP_TRANS_RECORD_OBJECT)pPsoVer2->AskTroBySocket
                            (
                                (ANSC_HANDLE)pPsoVer2,
                                (ANSC_HANDLE)pServerSocket
                            );

                    pPsoVer2->ReleaseAccess((ANSC_HANDLE)pPsoVer2);
                }
                else
                {
                    AnscReleaseLock(&pMyObject->SyncLock);

                    pServerSocket->Finish((ANSC_HANDLE)pServerSocket);

                    return  ANSC_STATUS_SUCCESS;
                }

                if ( !pTransRecord )
                {
                    AnscReleaseLock(&pMyObject->SyncLock);

                    pServerSocket->Finish((ANSC_HANDLE)pServerSocket);

                    return  ANSC_STATUS_SUCCESS;
                }

                AnscReleaseLock(&pMyObject->SyncLock);

                pBufferDesp->BlockSize += pServerSocket->RecvPacketSize;
                returnStatus            =
                    pServerSocket->SetBufferContext
                        (
                            (ANSC_HANDLE)pServerSocket,
                            NULL,
                            0,
                            (ANSC_HANDLE)NULL
                        );

                returnStatus            =
                    pTransRecord->FinishedByServer
                        (
                            (ANSC_HANDLE)pTransRecord,
                            AnscBdoGetBlock    (pBufferDesp),
                            AnscBdoGetBlockSize(pBufferDesp),
                            (ANSC_HANDLE)pBufferDesp
                        );

                pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);

                pServerSocket->Finish((ANSC_HANDLE)pServerSocket);

                break;

        case    ANSC_SPTOWO_EVENT_RESOURCES :

                break;

        case    ANSC_SPTOWO_EVENT_TIME_OUT :

                break;

        default :

                break;
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
HttpBmoParseHeaders
    (
        ANSC_HANDLE                 hThisObject
    )
{
    ANSC_STATUS                     returnStatus  = ANSC_STATUS_SUCCESS;
    PHTTP_BASIC_MESSAGE_OBJECT      pMyObject     = (PHTTP_BASIC_MESSAGE_OBJECT)hThisObject;
    PHTTP_HFP_INTERFACE             pHfpIf        = (PHTTP_HFP_INTERFACE       )pMyObject->hHfpIf;
    PANSC_BUFFER_DESCRIPTOR         pHeaderBdo    = (PANSC_BUFFER_DESCRIPTOR   )pMyObject->hHeaderBdo;
    PHTTP_HEADER_FIELD              pHttpHfo      = NULL;
    PVOID                           pHeaderBuffer = NULL;
    ULONG                           ulBufferSize  = 0;
    char*                           pHfStart      = NULL;
    ULONG                           ulSkipSize    = 0;
    char*                           pRawHfLine    = NULL;
    char*                           pStdHfLine    = (char*)pMyObject->ScratchPad1;
    ULONG                           ulRawLineSize = 0;
    ULONG                           ulStdLineSize = 0;

    pMyObject->DelStartLine((ANSC_HANDLE)pMyObject);
    pMyObject->DelAllHfos  ((ANSC_HANDLE)pMyObject);

    returnStatus = pMyObject->ParseStartLine((ANSC_HANDLE)pMyObject);

    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        return  returnStatus;
    }
    else if ( !pHeaderBdo )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        pHeaderBuffer = AnscBdoGetBlock    (pHeaderBdo);
        ulBufferSize  = AnscBdoGetBlockSize(pHeaderBdo);
    }

    AnscHttpFindHfStart(pHeaderBuffer, ulBufferSize, pHfStart);

    if ( !pHfStart )
    {
        return  ANSC_STATUS_UNAPPLICABLE;
    }
    else
    {
        ulSkipSize    = (ULONG)pHfStart - (ULONG)pHeaderBuffer;
        ulBufferSize -= ulSkipSize;
        pRawHfLine    = pHfStart;
    }

    /*
     * Skip the first line, which is the start line: request-line in client message and status-line
     * in server message.
     */
    AnscHttpGetHfLineSize(pRawHfLine, ulBufferSize, ulRawLineSize);

    pRawHfLine   += ulRawLineSize;
    ulBufferSize -= ulRawLineSize;

    /*
     * We don't have to verify the completeness of the header fields, since the caller SHOULD have
     * done so already. We create a separate HTTP Header Field Object for each header line and add
     * it into the distributed hash table. The end of header fields is signalled by the presece of
     * a CRLF pair.
     */
    while ( (ulBufferSize > 0) && pRawHfLine && !AnscHttpIsCr(*pRawHfLine) && !AnscHttpIsLf(*pRawHfLine) )
    {
        AnscHttpGetHfLineSize(pRawHfLine, ulBufferSize, ulRawLineSize);

        if ( ulRawLineSize <= pMyObject->PadSize1 )
        {
            AnscHttpPrepareHeader(pRawHfLine, ulRawLineSize, pStdHfLine, ulStdLineSize);

            pStdHfLine[ulStdLineSize + 0] = HTTP_CARRIAGE_RETURN;
            pStdHfLine[ulStdLineSize + 1] = HTTP_LINE_FEED;

            pHttpHfo =
                (PHTTP_HEADER_FIELD)pHfpIf->ParseHeader
                    (
                        pHfpIf->hOwnerContext,
                        pStdHfLine,
                        ulStdLineSize
                    );

            if ( pHttpHfo )
            {
                returnStatus =
                    pMyObject->AddHeaderField
                        (
                            (ANSC_HANDLE)pMyObject,
                            (ANSC_HANDLE)pHttpHfo
                        );
            }
        }

        pRawHfLine   += ulRawLineSize;
        ulBufferSize -= ulRawLineSize;
    }

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscSctoTsaRecvAppMessage
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hMessageBdo
    )
{
    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;
    PANSC_BUFFER_DESCRIPTOR         pPayloadBdo  = (PANSC_BUFFER_DESCRIPTOR       )hMessageBdo;
    void*                           pRecvBuffer  = (void*                         )NULL;
    ANSC_HANDLE                     hRecvHandle  = (ANSC_HANDLE                   )NULL;
    ULONG                           ulRecvSize   = (ULONG                         )0;
    ULONG                           ulLeftSize   = (ULONG                         )AnscBdoGetBlockSize(pPayloadBdo);
    ULONG                           ulCopySize   = (ULONG                         )0;

    while ( ulLeftSize > 0 )
    {
        pRecvBuffer =
            pMyObject->GetRecvBuffer
                (
                    (ANSC_HANDLE)pMyObject,
                    &ulRecvSize
                );

        if ( !pRecvBuffer )
        {
            returnStatus =
                pWorker->Notify
                    (
                        pWorker->hWorkerContext,
                        ANSC_SCTOWO_EVENT_RESOURCES,
                        (ANSC_HANDLE)NULL
                    );

            break;
        }

        if ( ulRecvSize >= ulLeftSize )
        {
            ulCopySize = ulLeftSize;
        }
        else
        {
            ulCopySize = ulRecvSize;
        }

        if ( TRUE )
        {
            AnscCopyMemory
                (
                    pRecvBuffer,
                    AnscBdoGetBlock(pPayloadBdo),
                    ulCopySize
                );

            AnscBdoShrinkRight(pPayloadBdo, ulCopySize);

            ulLeftSize -= ulCopySize;
        }

        pMyObject->RecvBytesCount += ulCopySize;
        pMyObject->LastRecvAt      = AnscGetTickInSeconds();

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

    goto  EXIT1;


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

EXIT1:

    if ( pPayloadBdo )
    {
        AnscFreeBdo((ANSC_HANDLE)pPayloadBdo);
    }

    return  returnStatus;
}