/*++

Copyright (c) 1998 - 2000  Microsoft Corporation

Module Name:

    cblist.cpp

Abstract:
    
    Definitions of methods for CALL_BRIDGE_LIST container. 

Revision History:
    1. 31-Jul-1998 -- File creation                     Ajay Chitturi (ajaych) 
    2. 15-Jul-1999 --                                   Arlie Davis   (arlied)    
    3. 14-Feb-2000 -- Added method to remove call       Ilya Kleyman  (ilyak)
                      bridges by connected interface                     
    
--*/

#include "stdafx.h"

CALL_BRIDGE_LIST      CallBridgeList;


CALL_BRIDGE_LIST::CALL_BRIDGE_LIST (
    void
    )
/*++

Routine Description:
    Constructor for CALL_BRIDGE_LIST class

Arguments:
    None

Return Values:
    None

Notes:

--*/

{
    IsEnabled = FALSE;
} // CALL_BRIDGE_LIST::CALL_BRIDGE_LIST


CALL_BRIDGE_LIST::~CALL_BRIDGE_LIST (
    void
    )
/*++

Routine Description:
    Destructor for CALL_BRIDGE_LIST class

Arguments:
    None

Return Values:
    None

Notes:

--*/
{
    assert (!IsEnabled);
    assert (CallArray.Length == 0);

    CallArray.Free();
} // CALL_BRIDGE_LIST::~CALL_BRIDGE_LIST


void
CALL_BRIDGE_LIST::Start (
    void
    )
/*++

Routine Description:
    Activates the container

Arguments:
    None

Return Values:
    None

Notes:

--*/
{
    Lock();

    IsEnabled = TRUE;

    Unlock();
} // CALL_BRIDGE_LIST::Start


void
CALL_BRIDGE_LIST::Stop (
    void
    )
/*++

Routine Description:
    Deactivates the container. Terminates and removes
    all contained items.

Arguments:
    None

Return Values:
    None

Notes:

--*/
{
    CALL_BRIDGE *    CallBridge;

    Lock ();

    IsEnabled = FALSE;

    while (CallArray.GetLength()) {

        CallBridge = CallArray [0].CallBridge;

        CallBridge -> AddRef ();

        Unlock();

        CallBridge -> TerminateExternal();
        
        Lock();

        CallBridge -> Release ();
    }

    CallArray.Free();

    Unlock();
} // CALL_BRIDGE_LIST::Stop


HRESULT
CALL_BRIDGE_LIST::InsertCallBridge (
    IN    CALL_BRIDGE *    CallBridge
    )
/*++

Routine Description:
    Insert an item into the container

Arguments:
    CallBridge -- item to be inserted

Return Values:
    S_OK - if insertion was successful
    E_OUTOFMEMORY - if insertion failed due to the lack of memory
    E_FAIL - if insertion failed because the container was not enabled
    E_ABORT - if insertion failed because maximum number of concurrent 
              H.323 connections is exceeded

Notes:

--*/
{
    CALL_BRIDGE_ENTRY *    Entry;
    HRESULT        Result;
    DWORD        Index;

    Lock();

    if (IsEnabled) {

        if (CallArray.Length <= MAX_NUM_CALL_BRIDGES) {

            if (CallArray.BinarySearch ((SEARCH_FUNC_CALL_BRIDGE_ENTRY)CALL_BRIDGE_LIST::BinarySearchFunc,
                CallBridge, &Index)) {

                DebugF (_T("H323: 0x%x already exists in CallBridgeList.\n"), CallBridge);

                Result = S_OK;
            }
            else {

                Entry = CallArray.AllocAtPos (Index);

                if (Entry) {

                    Entry -> CallBridge = CallBridge;
                    Entry -> CallBridge -> AddRef();

                    Result = S_OK;
                }
                else {
                    DebugF (_T("H323: 0x%x allocation failure when inserting in CallBridgeList.\n"), CallBridge);

                    Result = E_OUTOFMEMORY;
                }
            }
        } else {
    
            return E_ABORT;
        }

    } else {

        Result = E_FAIL;
    }

    Unlock();

    return Result;
} // CALL_BRIDGE_LIST::InsertCallBridge


HRESULT
CALL_BRIDGE_LIST::RemoveCallBridge (
    IN    CALL_BRIDGE *    CallBridge
    )
/*++

Routine Description:
    Removes an entry from the container

Arguments:
    CallBridge - item to removed

Return Values:
    S_OK    - if removal was successful
    S_FALSE - if removal failed because the entry
              was not in the container

Notes:

--*/
{
    DWORD    Index;
    HRESULT    Result;

    Lock();

    if (CallArray.BinarySearch ((SEARCH_FUNC_CALL_BRIDGE_ENTRY)CALL_BRIDGE_LIST::BinarySearchFunc,
        CallBridge, &Index)) {

        CallArray.DeleteAtPos (Index);

        Result = S_OK;
    }
    else {
        DebugF (_T("H323: 0x%x could not be removed from the array because it is not there.\n"), CallBridge);

        Result = S_FALSE;
    }

    Unlock();

    if (Result == S_OK)
        CallBridge -> Release ();

    return Result;
} // CALL_BRIDGE_LIST::RemoveCallBridge


void
CALL_BRIDGE_LIST::OnInterfaceShutdown (
    IN DWORD InterfaceAddress // host order
    ) 
/*++

Routine Description:
    Searches through the list of CALL_BRIDGES, and terminates
    all of them that proxy a connection through the interface specified.

Arguments:

    InterfaceAddress - address of the interface, H.323 connections
                       through which are to be terminated.

                       
Return Values:


Notes:

--*/

{
    DWORD ArrayIndex = 0;
    CALL_BRIDGE* CallBridge;
    CALL_BRIDGE** CallBridgeHolder;
    DYNAMIC_ARRAY <CALL_BRIDGE*> TempArray;

    Lock ();

    while (ArrayIndex < CallArray.GetLength()) {

        CallBridge = CallArray[ArrayIndex].CallBridge;

        if (CallBridge -> IsConnectionThrough (InterfaceAddress))
        {
            DebugF (_T("Q931: 0x%x terminating (killing all connections through %08X).\n"), 
                CallBridge, InterfaceAddress);

            CallBridgeHolder = TempArray.AllocAtEnd ();

            if (NULL == CallBridgeHolder) {

                Debug (_T("CALL_BRIDGE_LIST::OnInterfaceShutdown - unable to grow array.\n"));

            } else {

                CallBridge -> AddRef ();

                *CallBridgeHolder = CallBridge;
            }
        } 

        ArrayIndex++;
    }

    Unlock ();

    ArrayIndex = 0;

    while (ArrayIndex < TempArray.GetLength ()) {
        CallBridge = TempArray[ArrayIndex];

        CallBridge -> OnInterfaceShutdown ();

        CallBridge -> Release ();

        ArrayIndex++;
    }

} // CALL_BRIDGE_LIST::OnInterfaceShutdown


// static
INT
CALL_BRIDGE_LIST::BinarySearchFunc (
    IN    const CALL_BRIDGE       *    SearchKey,
    IN    const CALL_BRIDGE_ENTRY *    Comparand
    )
/*++

Routine Description:
    Compares an entry with a key. Used by a binary search
    procedure.

Arguments:
    SearchKey - self-explanatory
    Comparand - self-explanatory

Return Values:
    1 if SearchKey is considered greater than Comparand
    -1 if SearchKey is considered less than Comparand
    0 if SearchKey is considered equal to Comparand

Notes:
    Static method

--*/
{
    const    CALL_BRIDGE *    ComparandA;
    const    CALL_BRIDGE *    ComparandB;

    ComparandA = SearchKey;
    ComparandB = Comparand -> CallBridge;

    if (ComparandA < ComparandB) return -1;
    if (ComparandA > ComparandB) return 1;

    return 0;
} // CALL_BRIDGE_LIST::BinarySearchFunc