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_HANDLE
HttpPsoVer2GetCurTro
    (
        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_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;
    PHTTP_TRANS_RECORD_OBJECT       pTransRecord   = NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry    = NULL;
    ULONG                           ulTroState     = HTTP_TRO_STATE_INITIALIZED;

    AnscAcquireLock(&pMyObject->TroSListLock);

    pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->TroSList);

    if ( pSLinkEntry )
    {
        pTransRecord = ACCESS_HTTP_TRANS_RECORD_OBJECT(pSLinkEntry);
        ulTroState   = pTransRecord->GetTransState((ANSC_HANDLE)pTransRecord);

        if ( (ulTroState != HTTP_TRO_STATE_ESTABLISHED) &&
             (ulTroState != HTTP_TRO_STATE_FINISHED   ) )
        {
            pTransRecord->AcquireAccess((ANSC_HANDLE)pTransRecord);

            AnscReleaseLock(&pMyObject->TroSListLock);

            return  (ANSC_HANDLE)pTransRecord;
        }
    }

    AnscReleaseLock(&pMyObject->TroSListLock);

    pTransRecord = (PHTTP_TRANS_RECORD_OBJECT)pMyObject->AddNewTro((ANSC_HANDLE)pMyObject);

    return  (ANSC_HANDLE)pTransRecord;
}
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;
}
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;
}