Пример #1
0
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;
}
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;
}
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;
}
Пример #4
0
BOOL
HttpSpoPrvwoAccept
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSocket,
        PANSC_HANDLE                phClientContext
    )
{
    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;
    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;
    PHTTP_HFP_INTERFACE             pHfpIf         = (PHTTP_HFP_INTERFACE           )pMyObject->hHfpIf;
    PANSC_DAEMON_SOCKET_TCP_OBJECT  pClientSocket  = (PANSC_DAEMON_SOCKET_TCP_OBJECT)hSocket;
    PANSC_BROKER_SOCKET_TCP_OBJECT  pServerSocket  = (PANSC_BROKER_SOCKET_TCP_OBJECT)NULL;
    PHTTP_PROXY_SESSION_OBJECT      pSession       = (PHTTP_PROXY_SESSION_OBJECT    )pMyObject->AcquirePso((ANSC_HANDLE)pMyObject);
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp    = NULL;

    AnscTrace
        (
            "PrvwoAccept accepts a new client connection from %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
        );

    *phClientContext = (ANSC_HANDLE)NULL;

    /*
     * This routine is called when there's a new incoming connection (i.e., requested by the HTTP
     * client) is to be established. Following are the processing procedures applied:
     *
     *      (1) create a new HTTP Proxy Session Object for the connection
     *      (2) call sbc_connect(), the Server Behavior Controller either denies the
     *          connection or allows it.
     *      (3) create buffer_descriptor object and associate it with the socket object
     */
    if ( !pSession )
    {
        return  FALSE;
    }
    else
    {
        pSession->SetWamIf       ((ANSC_HANDLE)pSession, (ANSC_HANDLE)pWamIf       );
        pSession->SetSbcIf       ((ANSC_HANDLE)pSession, (ANSC_HANDLE)pSbcIf       );
        pSession->SetCbcIf       ((ANSC_HANDLE)pSession, (ANSC_HANDLE)pCbcIf       );
        pSession->SetPbcIf       ((ANSC_HANDLE)pSession, (ANSC_HANDLE)pPbcIf       );
        pSession->SetHfpIf       ((ANSC_HANDLE)pSession, (ANSC_HANDLE)pHfpIf       );
        pSession->SetClientSocket((ANSC_HANDLE)pSession, (ANSC_HANDLE)pClientSocket);
    }

    if ( !pSession->AcceptClient
            (
                (ANSC_HANDLE)pSession,
                (ANSC_HANDLE)NULL
            ) )
    {
        pSession->Return((ANSC_HANDLE)pSession);

        return  FALSE;
    }
    else
    {
        pSession->SetSessionState((ANSC_HANDLE)pSession, HTTP_PSO_STATE_CLIENT_CONNECTED);
        pSession->Open           ((ANSC_HANDLE)pSession);
    }

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

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

    *phClientContext = (ANSC_HANDLE)pSession;

    return  TRUE;
}
ANSC_STATUS
HttpWcsoConnectPeer
    (
        ANSC_HANDLE                 hThisObject,
        ULONG                       ipAddrToConnect
    )
{
    ANSC_STATUS                     returnStatus     = ANSC_STATUS_SUCCESS;
    PHTTP_WEBC_SESSION_OBJECT       pMyObject        = (PHTTP_WEBC_SESSION_OBJECT     )hThisObject;
    PHTTP_WEBC_SESSION_PROPERTY     pProperty        = (PHTTP_WEBC_SESSION_PROPERTY   )&pMyObject->Property;
    PHTTP_BSP_INTERFACE             pBspIf           = (PHTTP_BSP_INTERFACE           )pMyObject->hBspIf;
    PANSC_SIMPLE_CLIENT_TCP_OBJECT  pTcpSimpleClient = (PANSC_SIMPLE_CLIENT_TCP_OBJECT)pMyObject->hTcpSimpleClient;
    PHTTP_SIMPLE_CLIENT_OBJECT      pHttpSco         = (PHTTP_SIMPLE_CLIENT_OBJECT    )pMyObject->hOwnerContext;
    ULONG                           ulSctoMode       = ANSC_SCTO_MODE_FOREIGN_BUFFER;
    PANSC_BUFFER_DESCRIPTOR         pBufferDesp      = NULL;
    BOOL                            bGotPeerAddr     = TRUE;
    ANSC_IPV4_ADDRESS               PeerAddr;
    PANSC_BUFFER_DESCRIPTOR         pRecvBdo         = (ANSC_HANDLE)NULL;
    ULONG                           ipAddr           = ipAddrToConnect;

TRY_NEXT:
    if ( ipAddr == 0 )
    {
        goto NO_MORE_TRY;
    }

    PeerAddr.Value  = ipAddr;

    pRecvBdo     = (PANSC_BUFFER_DESCRIPTOR)pTcpSimpleClient->GetBufferContext((ANSC_HANDLE)pTcpSimpleClient);
    pTcpSimpleClient->SetBufferContext((ANSC_HANDLE)pTcpSimpleClient, NULL, 0, NULL);

    if ( pRecvBdo )
    {
        AnscReleaseBdo(pRecvBdo);
        pRecvBdo    = NULL;
    }

    returnStatus = pTcpSimpleClient->Cancel((ANSC_HANDLE)pTcpSimpleClient);

    if ( pProperty->SessionFlags & HTTP_WCSO_FLAG_tlsEnabled )
    {
        ulSctoMode |= ANSC_SCTO_MODE_TLS_ENABLED;
    }

    if ( pProperty->SessionFlags & HTTP_WCSO_FLAG_xsocketEnabled )
    {
        ulSctoMode |= ANSC_SCTO_MODE_XSOCKET;
    }

    pTcpSimpleClient->SetHostAddress   ((ANSC_HANDLE)pTcpSimpleClient, pProperty->HostAddr.Dot   );
    pTcpSimpleClient->SetHostPort      ((ANSC_HANDLE)pTcpSimpleClient, pProperty->HostPort       );
    pTcpSimpleClient->SetPeerName      ((ANSC_HANDLE)pTcpSimpleClient, pProperty->PeerName       );
    pTcpSimpleClient->SetPeerAddress   ((ANSC_HANDLE)pTcpSimpleClient, PeerAddr.Dot              );
    pTcpSimpleClient->SetPeerPort      ((ANSC_HANDLE)pTcpSimpleClient, pProperty->PeerPort       );
    pTcpSimpleClient->SetMaxMessageSize((ANSC_HANDLE)pTcpSimpleClient, HTTP_WCSO_MAX_MESSAGE_SIZE);
    pTcpSimpleClient->SetMode          ((ANSC_HANDLE)pTcpSimpleClient, ulSctoMode                );

    //    fprintf(stderr, "<RT> %s: HTTP Client DeviceName = '%s'\n", __FUNCTION__, pHttpSco ? pHttpSco->Property.BindToDevice.DeviceName : "NULL");
    if( pHttpSco && pHttpSco->Property.BindToDevice.DeviceName[0] &&
        AnscSizeOfString(pHttpSco->Property.BindToDevice.DeviceName) < ANSC_OBJ_IF_NAME_SIZE)
    {
        pTcpSimpleClient->SetSocketBindToDevice ((ANSC_HANDLE)pTcpSimpleClient, TRUE);
        pTcpSimpleClient->SetSocketDeviceName   ((ANSC_HANDLE)pTcpSimpleClient, pHttpSco->Property.BindToDevice.DeviceName);
    }
    else 
    {
        pTcpSimpleClient->SetSocketBindToDevice ((ANSC_HANDLE)pTcpSimpleClient, FALSE);
        pTcpSimpleClient->SetSocketDeviceName   ((ANSC_HANDLE)pTcpSimpleClient, "");
    }

    returnStatus = pTcpSimpleClient->Engage((ANSC_HANDLE)pTcpSimpleClient);

NO_MORE_TRY:
    if ( returnStatus != ANSC_STATUS_SUCCESS )
    {
        if ( bGotPeerAddr )
        {
            BOOL                    bSucc   = FALSE;

            bSucc   = pHttpSco->GetNextPeerAddr((ANSC_HANDLE)pHttpSco, &ipAddr);

            if ( bSucc && ipAddr != 0 )
            {
                pMyObject->SessionState = HTTP_WCSO_STATE_INITIALIZED;

                goto TRY_NEXT;
            }
        }

        return  ANSC_STATUS_FAILURE;
    }
    else
    {
        pMyObject->SessionState = HTTP_WCSO_STATE_SERVER_CONNECTED;
    }

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

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

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