ANSC_STATUS
AnscLpccoTcpBwoRemove
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket
    )
{
    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_TIMER_DESCRIPTOR_OBJECT   pConnTimerObj = (PANSC_TIMER_DESCRIPTOR_OBJECT )pMyObject->hConnTimerObj;
    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_LPC_PARTY_ADDR            pPartyAddr    = (PANSC_LPC_PARTY_ADDR          )pBrokerSocket->GetClientContext((ANSC_HANDLE)pBrokerSocket);

    pBrokerSocket->SetClientContext((ANSC_HANDLE)pBrokerSocket, (ANSC_HANDLE)NULL         );
    pBrokerSocket->SetBufferContext((ANSC_HANDLE)pBrokerSocket, NULL, 0, (ANSC_HANDLE)NULL);

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

    if ( pPartyAddr )
    {
        pPartyAddr->Timestamp   = AnscGetTickInSeconds();
        pPartyAddr->PartyState &= ~ANSC_LPC_PARTY_STATE_connectedOut;
        pPartyAddr->PartySocket = (ANSC_HANDLE)NULL;

        /*
         * We shouldn't return until the reference count of 'pPartyAddr' reaches zero. Because if
         * we do, the socket may be deleted while there's still active task is trying to send
         * message to this party. For example: if LPC manager is issuing a LOCO call to all LPC
         * parties while one party is trying disconnect, a race condition is formed.
         */
        while ( pPartyAddr->ActiveCalls > 0 )
        {
            AnscSleep(20);
        }

        if ( !(pPartyAddr->PartyState & ANSC_LPC_PARTY_STATE_connectedIn ) &&
             !(pPartyAddr->PartyState & ANSC_LPC_PARTY_STATE_connectedOut) )
        {
            if ( pMyObject->bActive )
            {
                pConnTimerObj->Stop       ((ANSC_HANDLE)pConnTimerObj);
                pConnTimerObj->SetInterval((ANSC_HANDLE)pConnTimerObj, ANSC_LPCCO_DEF_CONN_TIMEOUT);
                pConnTimerObj->Start      ((ANSC_HANDLE)pConnTimerObj);
            }
        }
    }

    return  ANSC_STATUS_SUCCESS;
}
BOOL
HttpApoPubwoAccept
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        PANSC_HANDLE                phClientContext
    )
{
    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;
    PHTTP_WAM_INTERFACE             pWamIf         = (PHTTP_WAM_INTERFACE           )pMyObject->hWamIf;
    PHTTP_SBC_INTERFACE             pSbcIf         = (PHTTP_SBC_INTERFACE           )pMyObject->hSbcIf;
    PHTTP_CBC_INTERFACE             pCbcIf         = (PHTTP_CBC_INTERFACE           )pMyObject->hCbcIf;
    PHTTP_PBC_INTERFACE             pPbcIf         = (PHTTP_PBC_INTERFACE           )pMyObject->hPbcIf;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pServerSocket  = (PANSC_BROKER_SOCKET_TCP_OBJECT)hSocket;
    PHTTP_PSO_VER2_OBJECT           pPsoVer2       = NULL;
    PHTTP_TRANS_RECORD_OBJECT       pTransRecord   = NULL;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp    = NULL;

    AnscTrace
        (
            "PubwoAccept creates a new server connection to %d.%d.%d.%d / TCP %d\n",
            pServerSocket->PeerAddress.Dot[0],
            pServerSocket->PeerAddress.Dot[1],
            pServerSocket->PeerAddress.Dot[2],
            pServerSocket->PeerAddress.Dot[3],
            pServerSocket->PeerPort
        );

    pBufferDesp =
        (PANSC_BUFFER_DESCRIPTOR)AnscAllocateBdo
            (
                HTTP_APO_MAX_MESSAGE_SIZE,
                0,
                0
            );

    if ( pBufferDesp )
    {
        pServerSocket->SetBufferContext
            (
                (ANSC_HANDLE)pServerSocket,
                AnscBdoGetEndOfBlock(pBufferDesp),
                AnscBdoGetLeftSize  (pBufferDesp),
                (ANSC_HANDLE)pBufferDesp
            );
    }

    return  TRUE;
}
ANSC_STATUS
AnscLpccoTcpSendHello
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket
    )
{
    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;
    PIMCP_HEADER                    pImcpHeader       = (PIMCP_HEADER                  )NULL;
    PIMCP_HELLO_MESSAGE             pImcpHelloMessage = (PIMCP_HELLO_MESSAGE           )NULL;
    ULONG                           ulImcpMsgSize     = (ULONG                         )0;

    if ( TRUE )
    {
        ulImcpMsgSize = sizeof(IMCP_HEADER) + sizeof(IMCP_HELLO_MESSAGE) + AnscSizeOfString(pMyObject->PartyName);
        pImcpHeader   = (PIMCP_HEADER)AnscAllocateMemory(ulImcpMsgSize);

        if ( !pImcpHeader )
        {
            return  ANSC_STATUS_RESOURCES;
        }
        else
        {
            ImcpSetMsgType  (pImcpHeader, IMCP_MESSAGE_TYPE_HELLO            );
            ImcpSetMsgLength(pImcpHeader, ulImcpMsgSize - sizeof(IMCP_HEADER));

            pImcpHelloMessage = (PIMCP_HELLO_MESSAGE)ImcpGetMsgData(pImcpHeader);
        }

        ImcpHelloSetPartyAddrValue(pImcpHelloMessage, pMyObject->MyAddress.Value);
        ImcpHelloSetPartyPort     (pImcpHelloMessage, pMyObject->MyPort         );
        ImcpHelloSetPartyName     (pImcpHelloMessage, pMyObject->PartyName      );
    }

    returnStatus =
        pBrokerSocket->Send
            (
                (ANSC_HANDLE)pBrokerSocket,
                pImcpHeader,
                ulImcpMsgSize,
                (ANSC_HANDLE)NULL
            );

    AnscFreeMemory(pImcpHeader);

    return  returnStatus;
}
ANSC_STATUS
HttpPsoVer2DelAllTros
    (
        ANSC_HANDLE                 hThisObject
    )
{
    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_TRANS_RECORD_OBJECT       pTransRecord   = NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry    = NULL;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pServerSocket  = NULL;

    AnscAcquireLock(&pMyObject->TroSListLock);

    pSLinkEntry = AnscSListPopEntry(&pMyObject->TroSList);

    while ( pSLinkEntry )
    {
        pTransRecord = ACCESS_HTTP_TRANS_RECORD_OBJECT(pSLinkEntry);
        pSLinkEntry  = AnscSListPopEntry(&pMyObject->TroSList);

        returnStatus =
            pWamIf->Close
                (
                    pWamIf->hOwnerContext,
                    (ANSC_HANDLE)pTransRecord
                );

        pTransRecord->AcquireAccess((ANSC_HANDLE)pTransRecord);

        pServerSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)pTransRecord->GetServerSocket((ANSC_HANDLE)pTransRecord);

        if ( pServerSocket )
        {
            pServerSocket->SetClientContext((ANSC_HANDLE)pServerSocket, (ANSC_HANDLE)NULL        );
            pServerSocket->ToClean         ((ANSC_HANDLE)pServerSocket, TRUE, HTTP_APO_SOCKET_TTC);
        }

        pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);
        pTransRecord->Close        ((ANSC_HANDLE)pTransRecord);
        pTransRecord->Return       ((ANSC_HANDLE)pTransRecord);
    }

    AnscReleaseLock(&pMyObject->TroSListLock);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscLpccoTcpBwoNotify
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        ULONG                       ulEvent,
        ANSC_HANDLE                 hReserved
    )
{
    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;

    switch ( ulEvent )
    {
        case    ANSC_BSTOWO_EVENT_SOCKET_ERROR :

                pBrokerSocket->ToClean((ANSC_HANDLE)pBrokerSocket, TRUE, 2);

                break;

        case    ANSC_BSTOWO_EVENT_SOCKET_CLOSED :

                pBrokerSocket->Finish((ANSC_HANDLE)pBrokerSocket);

                break;

        case    ANSC_BSTOWO_EVENT_RESOURCES :

                break;

        case    ANSC_BSTOWO_EVENT_TIME_OUT :

                break;

        default :

                break;
    }

    return  ANSC_STATUS_SUCCESS;
}
BOOL
AnscLpccoTcpBwoAccept
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        PANSC_HANDLE                phClientContext
    )
{
    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   = NULL;

    pBufferDesp =
        (PANSC_BUFFER_DESCRIPTOR)AnscAllocateBdo
            (
                ANSC_LPC_DEF_MESSAGE_SIZE,
                0,
                0
            );

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

    return  TRUE;
}
ANSC_STATUS
HttpSpoPrvwoProcessSync
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hQueryContext
    )
{
    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;
    PHTTP_SBC_INTERFACE             pSbcIf         = (PHTTP_SBC_INTERFACE           )pMyObject->hSbcIf;
    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;
    ULONG                           ulPsoQmode     = (ULONG)hQueryContext;
    BOOL                            bFinishSocket  = FALSE;

    AnscAcquireLock(&pMyObject->SyncLock);

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

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

        pClientSocket->Finish((ANSC_HANDLE)pClientSocket);

        return  ANSC_STATUS_SUCCESS;
    }
    else
    {
        pSession->AcquireAccess((ANSC_HANDLE)pSession);
    }

    AnscReleaseLock(&pMyObject->SyncLock);

    switch ( ulPsoQmode )
    {
        case    HTTP_PSO_QMODE_FORWARD :

                pServerSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)pSession->GetServerSocket((ANSC_HANDLE)pSession);

                if ( !pServerSocket)
                {
                    bFinishSocket = TRUE;
                    returnStatus  = ANSC_STATUS_INTERNAL_ERROR;

                    break;
                }
                else
                {
                    returnStatus =
                        pServerSocket->Send
                            (
                                (ANSC_HANDLE)pServerSocket,
                                buffer,
                                ulSize,
                                (ANSC_HANDLE)NULL
                            );
                }

                pBufferDesp->BlockSize = 0;

                break;

        case    HTTP_PSO_QMODE_PROCESS :

                pClientSocket->SetBufferContext
                    (
                        (ANSC_HANDLE)pClientSocket,
                        NULL,
                        0,
                        (ANSC_HANDLE)NULL
                    );

                returnStatus =
                    pSession->RecvFromClient
                        (
                            (ANSC_HANDLE)pSession,
                            buffer,
                            ulSize,
                            (ANSC_HANDLE)pBufferDesp
                        );

                if ( pSession->GetSessionState((ANSC_HANDLE)pSession) == HTTP_PSO_STATE_FINISHED )
                {
                    bFinishSocket = TRUE;

                    break;
                }

                break;

        default :

                returnStatus = ANSC_STATUS_UNAPPLICABLE;

                break;
    }

    pSession->ReleaseAccess((ANSC_HANDLE)pSession);

    if ( bFinishSocket )
    {
        pClientSocket->Finish((ANSC_HANDLE)pClientSocket);
    }

    return  returnStatus;
}
ANSC_STATUS
HttpSpoPrvwoRemove
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket
    )
{
    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;
    PHTTP_WAM_INTERFACE             pWamIf         = (PHTTP_WAM_INTERFACE           )pMyObject->hWamIf;
    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
        (
            "PrvwoRemove removes the client connection of %d.%d.%d.%d / TCP %d\n",
            pClientSocket->PeerAddress.Dot[0],
            pClientSocket->PeerAddress.Dot[1],
            pClientSocket->PeerAddress.Dot[2],
            pClientSocket->PeerAddress.Dot[3],
            pClientSocket->PeerPort
        );

    AnscAcquireLock(&pMyObject->SyncLock);

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

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

        pServerSocket = (PANSC_BROKER_SOCKET_TCP_OBJECT)pSession->GetServerSocket((ANSC_HANDLE)pSession);
    }
    else
    {
        pServerSocket = NULL;
    }

    if ( pServerSocket )
    {
        pServerSocket->SetClientContext((ANSC_HANDLE)pServerSocket, (ANSC_HANDLE)NULL        );
        pServerSocket->ToClean         ((ANSC_HANDLE)pServerSocket, TRUE, HTTP_SPO_SOCKET_TTC);
    }

    AnscReleaseLock(&pMyObject->SyncLock);

    /*
     * Just a couple regular clean-up tasks to do:
     *
     *      (1) dis-associate the proxy session object from the client socket
     *      (2) clean the foreign buffer associated with the client socket
     *      (3) dis-associate the proxy session object from the server socket
     *
     * Note that we CANNOT clean the foreign buffer associated with the server socket because the
     * access to that buffer is NOT synchornized between the prv_recv() and pub_recv routines. It
     * SHOULD be done in the pub_remove() function.
     */
    pClientSocket->SetClientContext((ANSC_HANDLE)pClientSocket,          (ANSC_HANDLE)NULL);
    pClientSocket->SetBufferContext((ANSC_HANDLE)pClientSocket, NULL, 0, (ANSC_HANDLE)NULL);

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

    if ( !pSession )
    {
        return  ANSC_STATUS_SUCCESS;
    }

    pSession->ReleaseAccess((ANSC_HANDLE)pSession);
    pSession->Close        ((ANSC_HANDLE)pSession);
    pSession->Return       ((ANSC_HANDLE)pSession);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
AnscLpccoTcpSendRequest
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        void*                       buffer,
        ULONG                       ulSize,
        ULONG                       ulSeqNumber,
        ULONG                       ulReqType
    )
{
    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;
    void*                           pMessageBuffer      = (void*                         )NULL;
    ULONG                           ulBufferSize        = (ULONG                         )0;
    PIMCP_HEADER                    pImcpHeader         = (PIMCP_HEADER                  )NULL;
    PIMCP_REQUEST_MESSAGE           pImcpRequestMessage = (PIMCP_REQUEST_MESSAGE         )NULL;
    ULONG                           ulImcpMsgSize       = (ULONG                         )sizeof(IMCP_HEADER) + sizeof(IMCP_REQUEST_MESSAGE) + ulSize;

    if ( buffer && ulSize )
    {
        pImcpHeader         = (PIMCP_HEADER         )((ULONG)buffer - sizeof(IMCP_REQUEST_MESSAGE) - sizeof(IMCP_HEADER));
        pImcpRequestMessage = (PIMCP_REQUEST_MESSAGE)((ULONG)buffer - sizeof(IMCP_REQUEST_MESSAGE));
    }
    else
    {
        ulBufferSize   = sizeof(IMCP_HEADER) + sizeof(IMCP_REQUEST_MESSAGE);
        pMessageBuffer = AnscAllocateMemory(ulBufferSize);

        if ( !pMessageBuffer )
        {
            return  ANSC_STATUS_RESOURCES;
        }
        else
        {
            pImcpHeader         = (PIMCP_HEADER         )pMessageBuffer;
            pImcpRequestMessage = (PIMCP_REQUEST_MESSAGE)ImcpGetMsgData(pImcpHeader);
        }
    }

    if ( TRUE )
    {
        ImcpSetMsgType         (pImcpHeader,         IMCP_MESSAGE_TYPE_REQUEST          );
        ImcpSetMsgLength       (pImcpHeader,         ulImcpMsgSize - sizeof(IMCP_HEADER));
        ImcpRequestSetSeqNumber(pImcpRequestMessage, ulSeqNumber                        );
        ImcpRequestSetReqType  (pImcpRequestMessage, ulReqType                          );
        ImcpRequestSetReqSize  (pImcpRequestMessage, ulSize                             );
    }

    returnStatus =
        pBrokerSocket->Send
            (
                (ANSC_HANDLE)pBrokerSocket,
                pImcpHeader,
                ulImcpMsgSize,
                (ANSC_HANDLE)NULL
            );

    if ( pMessageBuffer )
    {
        AnscFreeMemory(pMessageBuffer);
    }

    return  returnStatus;
}
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
HttpApoPubwoProcessSync
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        PVOID                       buffer,
        ULONG                       ulSize,
        ANSC_HANDLE                 hQueryContext
    )
{
    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_DAEMON_SOCKET_TCP_OBJECT  pClientSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)NULL;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )pServerSocket->GetBufferContext((ANSC_HANDLE)pServerSocket);
    PHTTP_PSO_VER2_OBJECT           pPsoVer2      = NULL;
    PHTTP_TRANS_RECORD_OBJECT       pTransRecord  = NULL;
    ULONG                           ulTroQmode    = (ULONG)hQueryContext;
    BOOL                            bFinishSocket = FALSE;

    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);

    switch ( ulTroQmode )
    {
        case    HTTP_TRO_QMODE_FORWARD :

                pClientSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pTransRecord->GetClientSocket((ANSC_HANDLE)pTransRecord);

                if ( !pClientSocket)
                {
                    bFinishSocket = TRUE;
                    returnStatus  = ANSC_STATUS_INTERNAL_ERROR;

                    break;
                }
                else
                {
                    returnStatus =
                        pClientSocket->Send
                            (
                                (ANSC_HANDLE)pClientSocket,
                                buffer,
                                ulSize,
                                (ANSC_HANDLE)NULL
                            );
                }

                pBufferDesp->BlockSize = 0;

                break;

        case    HTTP_TRO_QMODE_PROCESS :

                pServerSocket->SetBufferContext
                    (
                        (ANSC_HANDLE)pServerSocket,
                        NULL,
                        0,
                        (ANSC_HANDLE)NULL
                    );

                returnStatus =
                    pTransRecord->RecvFromServer
                        (
                            (ANSC_HANDLE)pTransRecord,
                            buffer,
                            ulSize,
                            (ANSC_HANDLE)pBufferDesp
                        );

                if ( pTransRecord->GetTransState((ANSC_HANDLE)pTransRecord) == HTTP_TRO_STATE_FINISHED )
                {
                    bFinishSocket = TRUE;

                    break;
                }

                break;

        default :

                returnStatus = ANSC_STATUS_UNAPPLICABLE;

                break;
    }

    pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);

    if ( bFinishSocket )
    {
        pServerSocket->Finish((ANSC_HANDLE)pServerSocket);
    }

    return  returnStatus;
}
ULONG
HttpApoPubwoQuery
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        PVOID                       buffer,
        ULONG                       ulSize,
        PANSC_HANDLE                phQueryContext
    )
{
    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;
    ULONG                           ulSptoPmode   = ANSC_SPTOWO_PMODE_PROCESS_SYNC;
    ULONG                           ulTroQmode    = HTTP_TRO_QMODE_PROCESS;

    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);

        return  ANSC_SPTOWO_PMODE_FINISH;
    }

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

        return  ANSC_SPTOWO_PMODE_FINISH;
    }

    AnscReleaseLock(&pMyObject->SyncLock);

    pBufferDesp->BlockSize += ulSize;
    ulTroQmode              =
        pTransRecord->QueryForServer
            (
                (ANSC_HANDLE)pTransRecord,
                buffer,
                ulSize,
                (ANSC_HANDLE)pBufferDesp
            );

    switch ( ulTroQmode )
    {
        case    HTTP_TRO_QMODE_COLLECT :

                pBufferDesp->BlockSize -= ulSize;
                ulSptoPmode             = ANSC_SPTOWO_PMODE_COLLECT;

                break;

        case    HTTP_TRO_QMODE_FORWARD :
        case    HTTP_TRO_QMODE_PROCESS :

                ulSptoPmode = ANSC_SPTOWO_PMODE_PROCESS_SYNC;

                break;

        default :

                ulSptoPmode = ANSC_SPTOWO_PMODE_FINISH;

                break;
    }

    *phQueryContext = (ANSC_HANDLE)ulTroQmode;

    pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);

    return  ulSptoPmode;
}
ANSC_STATUS
HttpApoPubwoRemove
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket
    )
{
    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_DAEMON_SOCKET_TCP_OBJECT  pClientSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)NULL;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp   = (PANSC_BUFFER_DESCRIPTOR       )pServerSocket->GetBufferContext((ANSC_HANDLE)pServerSocket);
    PHTTP_PSO_VER2_OBJECT           pPsoVer2      = NULL;
    PHTTP_TRANS_RECORD_OBJECT       pTransRecord  = NULL;
    BOOL                            bRemovePso    = FALSE;

    AnscTrace
        (
            "PubwoRemove removes the server connection of %d.%d.%d.%d / TCP %d\n",
            pServerSocket->PeerAddress.Dot[0],
            pServerSocket->PeerAddress.Dot[1],
            pServerSocket->PeerAddress.Dot[2],
            pServerSocket->PeerAddress.Dot[3],
            pServerSocket->PeerPort
        );

    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
                );
    }

    /*
     * Just a couple regular clean-up tasks to do:
     *
     *      (1) dis-associate the trans record object from the server socket
     *      (2) clean the foreign buffer associated with the server socket
     *      (3) dis-associate the trans record object from the client socket
     *
     * Note that we CANNOT clean the foreign buffer associated with the client socket because the
     * access to that buffer is NOT synchornized between the prv_recv() and pub_recv routines. It
     * SHOULD be done in the prv_remove() function.
     */
    pServerSocket->SetClientContext((ANSC_HANDLE)pServerSocket,          (ANSC_HANDLE)NULL);
    pServerSocket->SetBufferContext((ANSC_HANDLE)pServerSocket, NULL, 0, (ANSC_HANDLE)NULL);

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

    if ( pTransRecord )
    {
        pTransRecord->SetServerSocket((ANSC_HANDLE)pTransRecord, (ANSC_HANDLE)NULL      );
        pTransRecord->SetTransState  ((ANSC_HANDLE)pTransRecord, HTTP_TRO_STATE_FINISHED);
        pTransRecord->ReleaseAccess  ((ANSC_HANDLE)pTransRecord);
    }

    /*
     * The idea of pipeline the client requests over a single client session is great, however, we
     * may run into a situation where wrongly-implemented clients are waiting forever for server to
     * close the connection. To prevent that, we should close the session if no outstanding trans-
     * action needs to be completed.
     */
    if ( pPsoVer2 )
    {
        pTransRecord = (PHTTP_TRANS_RECORD_OBJECT)pPsoVer2->GetLastTro((ANSC_HANDLE)pPsoVer2);

        if ( pTransRecord )
        {
            if ( (pTransRecord->GetTransState((ANSC_HANDLE)pTransRecord) == HTTP_TRO_STATE_FINISHED) &&
                 (pTransRecord->bCloseConnection                         == TRUE                   ) )
            {
                bRemovePso    = TRUE;
                pClientSocket = (PANSC_DAEMON_SOCKET_TCP_OBJECT)pPsoVer2->GetClientSocket((ANSC_HANDLE)pPsoVer2);

                if ( pClientSocket )
                {
                    pClientSocket->SetClientContext((ANSC_HANDLE)pClientSocket, (ANSC_HANDLE)NULL         );
                    pClientSocket->ToClean         ((ANSC_HANDLE)pClientSocket, FALSE, HTTP_APO_SOCKET_TTC);
                }
            }

            pTransRecord->ReleaseAccess((ANSC_HANDLE)pTransRecord);
        }

        pPsoVer2->ReleaseAccess((ANSC_HANDLE)pPsoVer2);
    }

    AnscReleaseLock(&pMyObject->SyncLock);

    /*
     * If you're wondering why we have to explicitly close the connection here, why not wait until
     * triggered by the clients-side actions, here's why: the stupid desktop browsers (i.e., Micro-
     * soft IE browsers) will not take any action but waiting for the connection to be closed.
     */
    if ( bRemovePso )
    {
        pPsoVer2->DelAllTros((ANSC_HANDLE)pPsoVer2);
        pPsoVer2->Close     ((ANSC_HANDLE)pPsoVer2);
        pPsoVer2->Return    ((ANSC_HANDLE)pPsoVer2);
    }

    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;
}