static
ANSC_HANDLE
WebVhoGetOldestGso
(
    ANSC_HANDLE                 hThisObject,
    ULONG                       ulSessionId,
    char*                       identifier,
    PUCHAR                      address,
    PULONG                      pulSessionCount
)
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PWEB_VIRTUAL_HOST_OBJECT        pMyObject    = (PWEB_VIRTUAL_HOST_OBJECT  )hThisObject;
    PWEB_SITE_MANAGER_OBJECT        pSiteManager = (PWEB_SITE_MANAGER_OBJECT  )pMyObject->hOwnerContext;
    WEB_SITE_MANAGER_PROPERTY       SMProperty;
    PWEB_VIRTUAL_HOST_PROPERTY      pProperty    = (PWEB_VIRTUAL_HOST_PROPERTY)&pMyObject->Property;
    PHTTP_HFP_INTERFACE             pHfpIf       = (PHTTP_HFP_INTERFACE       )pMyObject->hHfpIf;
    PWEB_LSM_INTERFACE              pLsmIf       = (PWEB_LSM_INTERFACE        )pMyObject->hLsmIf;
    PWEB_GENERAL_SESSION_OBJECT     pSession     = NULL;
    ULONG                           ulClientAddr = 0;
    USHORT                          usClientPort = 0;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    ULONG                           ulHashIndex  = AnscHashUlong(ulSessionId, WEB_VHO_GSO_TABLE_SIZE);
    ULONG                           i;
    ULONG                           ulCSessCount = 0;
    PWEB_GENERAL_SESSION_OBJECT     pOldSession  = NULL;

    for ( i = 0; i < WEB_VHO_GSO_TABLE_SIZE; i ++ )
    {
        pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->GsoTable[i]);

        while ( pSLinkEntry )
        {
            pSession     = ACCESS_WEB_GENERAL_SESSION_OBJECT(pSLinkEntry);
            ulClientAddr = *(PULONG)pSession->GetClientAddr((ANSC_HANDLE)pSession);
            usClientPort = pSession->GetClientPort((ANSC_HANDLE)pSession);
            pSLinkEntry  = AnscSListGetNextEntry(pSLinkEntry);

            if ( pSession->LsmMaxAge != 0 && ulClientAddr == AnscReadUlong(address) )
            {
                ulCSessCount ++;
                if ( !pOldSession )
                {
                    pOldSession = pSession;
                }
                else if (
                    pSession->LastReqAtInSec <= pOldSession->LastReqAtInSec &&
                    pSession->LastRepAtInSec <= pOldSession->LastRepAtInSec
                )
                {
                    pOldSession = pSession;
                }
            }
        }
    }

    *pulSessionCount = ulCSessCount;

    return  (ANSC_HANDLE)pSession;
}
ANSC_STATUS
WebVhoDelAllGsos
(
    ANSC_HANDLE                 hThisObject
)
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PWEB_VIRTUAL_HOST_OBJECT        pMyObject    = (PWEB_VIRTUAL_HOST_OBJECT  )hThisObject;
    PWEB_VIRTUAL_HOST_PROPERTY      pProperty    = (PWEB_VIRTUAL_HOST_PROPERTY)&pMyObject->Property;
    PHTTP_HFP_INTERFACE             pHfpIf       = (PHTTP_HFP_INTERFACE       )pMyObject->hHfpIf;
    PWEB_LSM_INTERFACE              pLsmIf       = (PWEB_LSM_INTERFACE        )pMyObject->hLsmIf;
    PWEB_GENERAL_SESSION_OBJECT     pSession     = NULL;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    ULONG                           i            = 0;

    AnscAcquireLock(&pMyObject->GsoTableLock);

    for ( i = 0; i < WEB_VHO_GSO_TABLE_SIZE; i++ )
    {
        pSLinkEntry = AnscSListPopEntry(&pMyObject->GsoTable[i]);

        while ( pSLinkEntry )
        {
            pSession    = ACCESS_WEB_GENERAL_SESSION_OBJECT(pSLinkEntry);
            pSLinkEntry = AnscSListPopEntry(&pMyObject->GsoTable[i]);

            pSession->AcquireAccess((ANSC_HANDLE)pSession);

            returnStatus =
                pLsmIf->ExpireSession
                (
                    pLsmIf->hOwnerContext,
                    (ANSC_HANDLE)pSession
                );

            pSession->ReleaseAccess((ANSC_HANDLE)pSession);
            pSession->Cancel       ((ANSC_HANDLE)pSession);
            pSession->Remove       ((ANSC_HANDLE)pSession);
        }
    }

    AnscReleaseLock(&pMyObject->GsoTableLock);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
WebVhoDelGso
(
    ANSC_HANDLE                 hThisObject,
    ULONG                       ulSessionId,
    PUCHAR                      address,
    USHORT                      port
)
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PWEB_VIRTUAL_HOST_OBJECT        pMyObject    = (PWEB_VIRTUAL_HOST_OBJECT  )hThisObject;
    PWEB_VIRTUAL_HOST_PROPERTY      pProperty    = (PWEB_VIRTUAL_HOST_PROPERTY)&pMyObject->Property;
    PHTTP_HFP_INTERFACE             pHfpIf       = (PHTTP_HFP_INTERFACE       )pMyObject->hHfpIf;
    PWEB_LSM_INTERFACE              pLsmIf       = (PWEB_LSM_INTERFACE        )pMyObject->hLsmIf;
    PWEB_GENERAL_SESSION_OBJECT     pSession     = NULL;
    ULONG                           ulClientAddr = 0;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    ULONG                           ulHashIndex  = AnscHashUlong(ulSessionId, WEB_VHO_GSO_TABLE_SIZE);

    AnscAcquireLock(&pMyObject->GsoTableLock);

    pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->GsoTable[ulHashIndex]);

    while ( pSLinkEntry )
    {
        pSession     = ACCESS_WEB_GENERAL_SESSION_OBJECT(pSLinkEntry);
        ulClientAddr = *(PULONG)pSession->GetClientAddr((ANSC_HANDLE)pSession);
        pSLinkEntry  = AnscSListGetNextEntry(pSLinkEntry);

        if ( (pSession->GetSessionId((ANSC_HANDLE)pSession) == ulSessionId           ) &&
                (ulClientAddr                                  == AnscReadUlong(address)) )
        {
            AnscSListPopEntryByLink(&pMyObject->GsoTable[ulHashIndex], &pSession->Linkage);

            pSession->AcquireAccess((ANSC_HANDLE)pSession);

            returnStatus =
                pLsmIf->EndSession
                (
                    pLsmIf->hOwnerContext,
                    (ANSC_HANDLE)pSession
                );

            pSession->ReleaseAccess((ANSC_HANDLE)pSession);
            pSession->Cancel       ((ANSC_HANDLE)pSession);
            pSession->Remove       ((ANSC_HANDLE)pSession);
        }
    }

    AnscReleaseLock(&pMyObject->GsoTableLock);

    return  ANSC_STATUS_SUCCESS;
}
ANSC_STATUS
WebVhoLsmNewContact
    (
        ANSC_HANDLE                 hThisObject,
        ANSC_HANDLE                 hSession
    )
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PWEB_VIRTUAL_HOST_OBJECT        pMyObject    = (PWEB_VIRTUAL_HOST_OBJECT   )hThisObject;
    PWEB_VIRTUAL_HOST_PROPERTY      pProperty    = (PWEB_VIRTUAL_HOST_PROPERTY )&pMyObject->Property;
    PHTTP_HFP_INTERFACE             pHfpIf       = (PHTTP_HFP_INTERFACE        )pMyObject->hHfpIf;
    PWEB_LSM_INTERFACE              pLsmIf       = (PWEB_LSM_INTERFACE         )pMyObject->hLsmIf;
    PWEB_GENERAL_SESSION_OBJECT     pSession     = (PWEB_GENERAL_SESSION_OBJECT)hSession;

    returnStatus =
        pSession->SetLsmIdentifier
            (
                (ANSC_HANDLE)pSession,
                WEB_DEF_LSM_CLIENT_ID
            );

    return  returnStatus;
}
ANSC_HANDLE
WebVhoAddGso
(
    ANSC_HANDLE                 hThisObject,
    char*                       identifier,
    PUCHAR                      address,
    USHORT                      port
)
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PWEB_VIRTUAL_HOST_OBJECT        pMyObject    = (PWEB_VIRTUAL_HOST_OBJECT  )hThisObject;
    PWEB_VIRTUAL_HOST_PROPERTY      pProperty    = (PWEB_VIRTUAL_HOST_PROPERTY)&pMyObject->Property;
    PHTTP_HFP_INTERFACE             pHfpIf       = (PHTTP_HFP_INTERFACE       )pMyObject->hHfpIf;
    PWEB_LSM_INTERFACE              pLsmIf       = (PWEB_LSM_INTERFACE        )pMyObject->hLsmIf;
    PWEB_GENERAL_SESSION_OBJECT     pSession     = NULL;
    ULONG                           ulHashIndex  = 0;

    pMyObject->GlobalSidCount++;

    if ( pMyObject->GlobalSidCount >= 0x7FFFFFFF )
    {
        pMyObject->GlobalSidCount = 0;
    }

    pSession =
        (PWEB_GENERAL_SESSION_OBJECT)WebCreateGeneralSession
        (
            pMyObject->hContainerContext,
            (ANSC_HANDLE)pMyObject,
            (ANSC_HANDLE)NULL
        );

    if ( !pSession )
    {
        return  (ANSC_HANDLE)NULL;
    }
    else
    {
        pSession->SetHfpIf      ((ANSC_HANDLE)pSession, (ANSC_HANDLE)pHfpIf          );
        pSession->SetSessionId  ((ANSC_HANDLE)pSession, pMyObject->GlobalSidCount    );
        pSession->SetClientAddr ((ANSC_HANDLE)pSession, address                      );
        pSession->SetClientPort ((ANSC_HANDLE)pSession, port                         );
        pSession->SetLsmContext ((ANSC_HANDLE)pSession, (ANSC_HANDLE)NULL            );
        pSession->SetLsmMaxAge  ((ANSC_HANDLE)pSession, pProperty->LsmCookieMaxAge   );
        pSession->SetLsmExpire  ((ANSC_HANDLE)pSession, pProperty->SessionTimeOut    );
        pSession->SetMaxLifespan((ANSC_HANDLE)pSession, pProperty->SessionMaxLifespan);
    }

    if ( identifier )
    {
        pSession->SetLsmIdentifier((ANSC_HANDLE)pSession, identifier);

        returnStatus =
            pLsmIf->ClassifyClient
            (
                pLsmIf->hOwnerContext,
                (ANSC_HANDLE)pSession
            );
    }
    else
    {
        returnStatus =
            pLsmIf->NewContact
            (
                pLsmIf->hOwnerContext,
                (ANSC_HANDLE)pSession
            );
    }

    ulHashIndex         = AnscHashUlong(pSession->SessionId, WEB_VHO_GSO_TABLE_SIZE);
    pSession->HashIndex = ulHashIndex;

    AnscAcquireLock(&pMyObject->GsoTableLock);

    pSession->AcquireAccess((ANSC_HANDLE)pSession);
    pSession->Engage       ((ANSC_HANDLE)pSession);

    AnscSListPushEntry(&pMyObject->GsoTable[ulHashIndex], &pSession->Linkage);

    AnscReleaseLock(&pMyObject->GsoTableLock);

    return  (ANSC_HANDLE)pSession;
}
ANSC_HANDLE
WebVhoGetGso
(
    ANSC_HANDLE                 hThisObject,
    ULONG                       ulSessionId,
    char*                       identifier,
    PUCHAR                      address,
    USHORT                      port
)
{
    ANSC_STATUS                     returnStatus = ANSC_STATUS_SUCCESS;
    PWEB_VIRTUAL_HOST_OBJECT        pMyObject    = (PWEB_VIRTUAL_HOST_OBJECT  )hThisObject;
    PWEB_SITE_MANAGER_OBJECT        pSiteManager = (PWEB_SITE_MANAGER_OBJECT  )pMyObject->hOwnerContext;
    WEB_SITE_MANAGER_PROPERTY       SMProperty;
    PWEB_VIRTUAL_HOST_PROPERTY      pProperty    = (PWEB_VIRTUAL_HOST_PROPERTY)&pMyObject->Property;
    PHTTP_HFP_INTERFACE             pHfpIf       = (PHTTP_HFP_INTERFACE       )pMyObject->hHfpIf;
    PWEB_LSM_INTERFACE              pLsmIf       = (PWEB_LSM_INTERFACE        )pMyObject->hLsmIf;
    PWEB_GENERAL_SESSION_OBJECT     pSession     = NULL;
    ULONG                           ulClientAddr = 0;
    USHORT                          usClientPort = 0;
    PSINGLE_LINK_ENTRY              pSLinkEntry  = NULL;
    ULONG                           ulHashIndex  = AnscHashUlong(ulSessionId, WEB_VHO_GSO_TABLE_SIZE);
    ULONG                           i;
    ULONG                           ulCSessCount = 0;
    PWEB_GENERAL_SESSION_OBJECT     pOldSession  = NULL;

    AnscAcquireLock(&pMyObject->GsoTableLock);

    if ( ulSessionId != 0xFFFFFFFF )
    {
        pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->GsoTable[ulHashIndex]);

        while ( pSLinkEntry )
        {
            pSession     = ACCESS_WEB_GENERAL_SESSION_OBJECT(pSLinkEntry);
            ulClientAddr = *(PULONG)pSession->GetClientAddr((ANSC_HANDLE)pSession);
            usClientPort = pSession->GetClientPort((ANSC_HANDLE)pSession);
            pSLinkEntry  = AnscSListGetNextEntry(pSLinkEntry);

            if ( pSession->GetLsmMaxAge((ANSC_HANDLE)pSession) == 0 )
            {
                /* this session is marked to be closed */
                continue;
            }

            if ( (pSession->GetSessionId((ANSC_HANDLE)pSession) == ulSessionId) &&
                    (ulClientAddr == AnscReadUlong(address)) )
            {
                char*               pLsmId       = pSession->GetLsmIdentifier((ANSC_HANDLE)pSession);

                if ( !identifier )
                {
                    if ( !pLsmId || AnscSizeOfString(pLsmId) == 0 )
                    {
                        AnscReleaseLock(&pMyObject->GsoTableLock);

                        pSession->AcquireAccess((ANSC_HANDLE)pSession);

                        return  (ANSC_HANDLE)pSession;
                    }
                    else
                    {
                        break;
                    }
                }
                else if ( AnscEqualString
                          (
                              pLsmId,
                              identifier,
                              TRUE
                          ) )
                {
                    AnscReleaseLock(&pMyObject->GsoTableLock);

                    pSession->AcquireAccess((ANSC_HANDLE)pSession);

                    return  (ANSC_HANDLE)pSession;
                }
                else
                {
                    break;
                }
            }
        }
    }
    else
    {
        for ( i = 0; i < WEB_VHO_GSO_TABLE_SIZE; i ++ )
        {
            pSLinkEntry = AnscSListGetFirstEntry(&pMyObject->GsoTable[i]);

            while ( pSLinkEntry )
            {
                pSession     = ACCESS_WEB_GENERAL_SESSION_OBJECT(pSLinkEntry);
                ulClientAddr = *(PULONG)pSession->GetClientAddr((ANSC_HANDLE)pSession);
                usClientPort = pSession->GetClientPort((ANSC_HANDLE)pSession);
                pSLinkEntry  = AnscSListGetNextEntry(pSLinkEntry);

                if ( (ulClientAddr == AnscReadUlong(address)) && usClientPort == port )
                {
                    AnscReleaseLock(&pMyObject->GsoTableLock);

                    /* same connection */
                    pSession->AcquireAccess((ANSC_HANDLE)pSession);

                    return  (ANSC_HANDLE)pSession;
                }
            }
        }
    }

    pSiteManager->GetProperty((ANSC_HANDLE)pSiteManager, &SMProperty);

    pOldSession =
        (PWEB_GENERAL_SESSION_OBJECT)WebVhoGetOldestGso
        (
            (ANSC_HANDLE)pMyObject,
            ulSessionId,
            identifier,
            address,
            &ulCSessCount
        );

    if ( pOldSession && SMProperty.MaxSessionCountPerPeer != 0 && ulCSessCount >= SMProperty.MaxSessionCountPerPeer )
    {
        pOldSession->Terminate((ANSC_HANDLE)pOldSession);
    }

    AnscReleaseLock(&pMyObject->GsoTableLock);

    /*
     * We couldn't find a general session object for this client, we shall create a new one and
     * let the Logical Session Manager classify the client based on his/her identifier.
     */
    pSession =
        (PWEB_GENERAL_SESSION_OBJECT)pMyObject->AddGso
        (
            (ANSC_HANDLE)pMyObject,
            identifier,
            address,
            port
        );

    return  (ANSC_HANDLE)pSession;
}