/*++

Copyright (c) 1998, Microsoft Corporation

Module Name:

    rmh323.c

Abstract:

    This module contains routines for the H.323 transparent proxy module's
    interface to the IP router-manager. (See ROUTPROT.H for details).

Author:

    Abolade Gbadegesin (aboladeg)   18-Jun-1999

Revision History:

--*/

#include "precomp.h"
#pragma hdrstop
#include <h323icsp.h>

COMPONENT_REFERENCE H323ComponentReference;
PIP_H323_GLOBAL_INFO H323GlobalInfo = NULL;
CRITICAL_SECTION H323GlobalInfoLock;
HANDLE H323NotificationEvent;
ULONG H323ProtocolStopped = 0;
const MPR_ROUTING_CHARACTERISTICS H323RoutingCharacteristics =
{
    MS_ROUTER_VERSION,
    MS_IP_H323,
    RF_ROUTING|RF_ADD_ALL_INTERFACES,
    H323RmStartProtocol,
    H323RmStartComplete,
    H323RmStopProtocol,
    H323RmGetGlobalInfo,
    H323RmSetGlobalInfo,
    NULL,
    NULL,
    H323RmAddInterface,
    H323RmDeleteInterface,
    H323RmInterfaceStatus,
    
    H323RmGetInterfaceInfo,
    H323RmSetInterfaceInfo,
    H323RmGetEventMessage,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    H323RmMibCreate,
    H323RmMibDelete,
    H323RmMibGet,
    H323RmMibSet,
    H323RmMibGetFirst,
    H323RmMibGetNext,
    NULL,
    NULL
};

SUPPORT_FUNCTIONS H323SupportFunctions;


VOID
H323CleanupModule(
    VOID
    )

/*++

Routine Description:

    This routine is invoked to cleanup the H.323 transparent proxy module.

Arguments:

    none.

Return Value:

    none.

Environment:

    Invoked from within a 'DllMain' routine on 'DLL_PROCESS_DETACH'.

--*/

{
    // TODO: Call h323ics!CleanupModule
    H323ProxyCleanupModule();

    H323ShutdownInterfaceManagement();
    DeleteCriticalSection(&H323GlobalInfoLock);
    DeleteComponentReference(&H323ComponentReference);

} // H323CleanupModule


VOID
H323CleanupProtocol(
    VOID
    )

/*++

Routine Description:

    This routine is invoked to cleanup the H.323 transparent proxy
    protocol-component after a 'StopProtocol'. It runs when the last reference
    to the component is released. (See 'COMPREF.H').

Arguments:

    none.

Return Value:

    none.

Environment:

    Invoked from within an arbitrary context with no locks held.

--*/

{
    PROFILE("H323CleanupProtocol");
    if (H323GlobalInfo) { NH_FREE(H323GlobalInfo); H323GlobalInfo = NULL; }

    // TODO: Call h323ics!StopService
    H323ProxyStopService();

    InterlockedExchange(reinterpret_cast<LPLONG>(&H323ProtocolStopped), 1);
    SetEvent(H323NotificationEvent);
    ResetComponentReference(&H323ComponentReference);

} // H323CleanupProtocol


BOOLEAN
H323InitializeModule(
    VOID
    )

/*++

Routine Description:

    This routine is invoked to initialize the H323 module.

Arguments:

    none.

Return Value:

    BOOLEAN - TRUE if initialization succeeded, FALSE otherwise

Environment:

    Invoked in the context of a 'DllMain' routine on 'DLL_PROCESS_ATTACH'.

--*/

{
    if (InitializeComponentReference(
            &H323ComponentReference, H323CleanupProtocol
            )) {
        return FALSE;
    }

    __try {
        InitializeCriticalSection(&H323GlobalInfoLock);
    } __except(EXCEPTION_EXECUTE_HANDLER) {
        DeleteComponentReference(&H323ComponentReference);
        return FALSE;
    }

    if (H323InitializeInterfaceManagement())  {
        DeleteCriticalSection(&H323GlobalInfoLock);
        DeleteComponentReference(&H323ComponentReference);
        return FALSE;
    }

    // TODO: Call h323ics!InitializeModule
    H323ProxyInitializeModule();

    return TRUE;

} // H323InitializeModule


ULONG
APIENTRY
H323RmStartProtocol(
    HANDLE NotificationEvent,
    PSUPPORT_FUNCTIONS SupportFunctions,
    PVOID GlobalInfo,
    ULONG StructureVersion,
    ULONG StructureSize,
    ULONG StructureCount    
    )

/*++

Routine Description:

    This routine is invoked to indicate the component's operation should begin.

Arguments:

    NotificationEvent - event on which we notify the router-manager
        about asynchronous occurrences

    SupportFunctions - functions for initiating router-related operations

    GlobalInfo - configuration for the component

Return Value:

    ULONG - Win32 status code.

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Error = NO_ERROR;
    ULONG Size;

    PROFILE("H323RmStartProtocol");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    if (!GlobalInfo) { DEREFERENCE_H323_AND_RETURN(ERROR_INVALID_PARAMETER); }

    do {

        //
        // Copy the global configuration
        //

        EnterCriticalSection(&H323GlobalInfoLock);

        Size = sizeof(*H323GlobalInfo);
    
        H323GlobalInfo
            = reinterpret_cast<PIP_H323_GLOBAL_INFO>(NH_ALLOCATE(Size));

        if (!H323GlobalInfo) {
            LeaveCriticalSection(&H323GlobalInfoLock);
            NhTrace(
                TRACE_FLAG_INIT,
                "H323RmStartProtocol: cannot allocate global info"
                );
            NhErrorLog(
                IP_H323_LOG_ALLOCATION_FAILED,
                0,
                "%d",
                Size
                );
            Error = ERROR_NOT_ENOUGH_MEMORY;
            break;
        }

        CopyMemory(H323GlobalInfo, GlobalInfo, Size);

        //
        // Save the notification event
        //

        H323NotificationEvent = NotificationEvent;

        //
        // Save the support functions
        //

        if (!SupportFunctions) {
            ZeroMemory(&H323SupportFunctions, sizeof(H323SupportFunctions));
        } else {
            CopyMemory(
                &H323SupportFunctions,
                SupportFunctions,
                sizeof(*SupportFunctions)
                );
        }

        // TODO: Call h323ics!StartModule
        H323ProxyStartService();

        LeaveCriticalSection(&H323GlobalInfoLock);
        InterlockedExchange(reinterpret_cast<LPLONG>(&H323ProtocolStopped), 0);

    } while (FALSE);

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmStartProtocol


ULONG
APIENTRY
H323RmStartComplete(
    VOID
    )

/*++

Routine Description:

    This routine is invoked when the router has finished adding the initial
    configuration.

Arguments:

    none.

Return Value:

    ULONG - Win32 status code

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    return NO_ERROR;
} // H323RmStartComplete


ULONG
APIENTRY
H323RmStopProtocol(
    VOID
    )

/*++

Routine Description:

    This routine is invoked to stop the protocol.

Arguments:

    none.

Return Value:

    ULONG - Win32 status code

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    //
    // Reference the module to make sure it's running
    //

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    //
    // Drop the initial reference to cause a cleanup
    //

    ReleaseInitialComponentReference(&H323ComponentReference);

    return DEREFERENCE_H323() ? NO_ERROR : ERROR_PROTOCOL_STOP_PENDING;

} // H323RmStopProtocol


ULONG
APIENTRY
H323RmAddInterface(
    PWCHAR Name,
    ULONG Index,
    NET_INTERFACE_TYPE Type,
    ULONG MediaType,
    USHORT AccessType,
    USHORT ConnectionType,
    PVOID InterfaceInfo,
    ULONG StructureVersion,
    ULONG StructureSize,
    ULONG StructureCount
    )

/*++

Routine Description:

    This routine is invoked to add an interface to the component.

Arguments:

    Name - the name of the interface (unused)

    Index - the index of the interface

    Type - the type of the interface

    InterfaceInfo - the configuration information for the interface

Return Value:

    ULONG - Win32 status code.

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Error;
    PROFILE("H323RmAddInterface");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error =
        H323CreateInterface(
            Index,
            Type,
            (PIP_H323_INTERFACE_INFO)InterfaceInfo,
            NULL
            );

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmAddInterface


ULONG
APIENTRY
H323RmDeleteInterface(
    ULONG Index
    )

/*++

Routine Description:

    This routine is invoked to delete an interface from the component.

Arguments:

    Index - the index of the interface

Return Value:

    ULONG - Win32 status code

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Error;
    PROFILE("H323RmDeleteInterface");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error =
        H323DeleteInterface(
            Index
            );

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmDeleteInterface


ULONG
APIENTRY
H323RmGetEventMessage(
    OUT ROUTING_PROTOCOL_EVENTS* Event,
    OUT MESSAGE* Result
    )

/*++

Routine Description:

    This routine is invoked to retrieve an event message from the component.
    The only event message we generate is the 'ROUTER_STOPPED' message.

Arguments:

    Event - receives the generated event

    Result - receives the associated result

Return Value:

    ULONG - Win32 status code.

--*/

{
    PROFILE("H323RmGetEventMessage");

    if (InterlockedExchange(reinterpret_cast<LPLONG>(&H323ProtocolStopped), 0)) {
        *Event = ROUTER_STOPPED;
        return NO_ERROR;
    }

    return ERROR_NO_MORE_ITEMS;

} // H323RmGetEventMessage


ULONG
APIENTRY
H323RmGetInterfaceInfo(
    ULONG Index,
    PVOID InterfaceInfo,
    IN OUT PULONG InterfaceInfoSize,
    IN OUT PULONG StructureVersion,
    IN OUT PULONG StructureSize,
    IN OUT PULONG StructureCount
    )

/*++

Routine Description:

    This routine is invoked to retrieve the component's per-interface
    configuration.

Arguments:

    Index - the index of the interface to be queried

    InterfaceInfo - receives the query results

    InterfaceInfoSize - receives the amount of data retrieved

Return Value:

    ULONG - Win32 status code.

--*/

{
    ULONG Error;
    PROFILE("H323RmGetInterfaceInfo");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error =
        H323QueryInterface(
            Index,
            (PIP_H323_INTERFACE_INFO)InterfaceInfo,
            InterfaceInfoSize
            );
    *StructureSize = *InterfaceInfoSize;
    if (StructureCount) {*StructureCount = 1;}
    
    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmGetInterfaceInfo


ULONG
APIENTRY
H323RmSetInterfaceInfo(
    ULONG Index,
    PVOID InterfaceInfo,
    ULONG StructureVersion,
    ULONG StructureSize,
    ULONG StructureCount
    )

/*++

Routine Description:

    This routine is invoked to change the component's per-interface
    configuration.

Arguments:

    Index - the index of the interface to be updated

    InterfaceInfo - supplies the new configuration

Return Value:

    ULONG - Win32 status code.

--*/

{
    ULONG Error;
    PROFILE("H323RmSetInterfaceInfo");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error = 
        H323ConfigureInterface(
            Index,
            (PIP_H323_INTERFACE_INFO)InterfaceInfo
            );

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmSetInterfaceInfo


ULONG
APIENTRY
H323RmInterfaceStatus(
    ULONG Index,
    BOOL InterfaceActive,
    ULONG StatusType,
    PVOID StatusInfo
    )

/*++

Routine Description:

    This routine is invoked to bind/unbind, enable/disable an interface

Arguments:

    Index - the interface to be bound

    InterfaceActive - whether the interface is active

    StatusType - type of status being changed (bind or enabled)

    StatusInfo - Info pertaining to the state being changed

Return Value:

    ULONG - Win32 Status code

Environment:

    The routine runs in the context of an IP router-manager thread.
    
--*/

{
    ULONG Error = NO_ERROR;

    switch(StatusType) {
        case RIS_INTERFACE_ADDRESS_CHANGE: {
            PIP_ADAPTER_BINDING_INFO BindInfo =
                (PIP_ADAPTER_BINDING_INFO)StatusInfo;

            if (BindInfo->AddressCount) {
                Error = H323RmBindInterface(Index, StatusInfo);
            } else {
                Error = H323RmUnbindInterface(Index);
            }
            break;
        }

        case RIS_INTERFACE_ENABLED: {
            Error = H323RmEnableInterface(Index);
            break;
        }

        case RIS_INTERFACE_DISABLED: {
            Error = H323RmDisableInterface(Index);
            break;
        }
    }

    return Error;
    
} // H323RmInterfaceStatus


ULONG
H323RmBindInterface(
    ULONG Index,
    PVOID BindingInfo
    )

/*++

Routine Description:

    This routine is invoked to bind an interface to its IP address(es).

Arguments:

    Index - the interface to be bound

    BindingInfo - the addressing information

Return Value:

    ULONG - Win32 status code.

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Error;
    PROFILE("H323RmBindInterface");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error =
        H323BindInterface(
            Index,
            (PIP_ADAPTER_BINDING_INFO)BindingInfo
            );

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmBindInterface


ULONG
H323RmUnbindInterface(
    ULONG Index
    )

/*++

Routine Description:

    This routine is invoked to unbind an interface from its IP address(es).

Arguments:

    Index - the interface to be unbound

Return Value:

    ULONG - Win32 status code.

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Error;
    PROFILE("H323RmUnbindInterface");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error =
        H323UnbindInterface(
            Index
            );

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmUnbindInterface


ULONG
H323RmEnableInterface(
    ULONG Index
    )

/*++

Routine Description:

    This routine is invoked to enable operation on an interface.

Arguments:

    Index - the interface to be enabled.

Return Value:

    ULONG - Win32 status code.

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Error;
    PROFILE("H323RmEnableInterface");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error =
        H323EnableInterface(
            Index
            );

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmEnableInterface


ULONG
H323RmDisableInterface(
    ULONG Index
    )

/*++

Routine Description:

    This routine is invoked to disable operation on an interface.

Arguments:

    Index - the interface to be disabled.

Return Value:

    ULONG - Win32 status code.

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Error;
    PROFILE("H323RmDisableInterface");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    Error =
        H323DisableInterface(
            Index
            );

    DEREFERENCE_H323_AND_RETURN(Error);

} // H323RmDisableInterface


ULONG
APIENTRY
H323RmGetGlobalInfo(
    PVOID GlobalInfo,
    IN OUT PULONG GlobalInfoSize,
    IN OUT PULONG StructureVersion,
    IN OUT PULONG StructureSize,
    IN OUT PULONG StructureCount
    )

/*++

Routine Description:

    This routine is invoked to retrieve the configuration for the component.

Arguments:

    GlobalInfo - receives the configuration

    GlobalInfoSize - receives the size of the configuration

Return Value:

    ULONG - Win32 status code

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG Size;
    PROFILE("H323RmGetGlobalInfo");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    if (!GlobalInfoSize || (*GlobalInfoSize && !GlobalInfo)) {
        DEREFERENCE_H323_AND_RETURN(ERROR_INVALID_PARAMETER);
    }

    EnterCriticalSection(&H323GlobalInfoLock);
    Size = sizeof(*H323GlobalInfo);
    if (*GlobalInfoSize < Size) {
        LeaveCriticalSection(&H323GlobalInfoLock);
        *StructureSize = *GlobalInfoSize = Size;
        if (StructureCount) {*StructureCount = 1;}
        DEREFERENCE_H323_AND_RETURN(ERROR_INSUFFICIENT_BUFFER);
    }
    CopyMemory(GlobalInfo, H323GlobalInfo, Size);
    LeaveCriticalSection(&H323GlobalInfoLock);
    *StructureSize = *GlobalInfoSize = Size;
    if (StructureCount) {*StructureCount = 1;}
    
    DEREFERENCE_H323_AND_RETURN(NO_ERROR);
    
} // H323RmGetGlobalInfo


ULONG
APIENTRY
H323RmSetGlobalInfo(
    PVOID GlobalInfo,
    ULONG StructureVersion,
    ULONG StructureSize,
    ULONG StructureCount
    )

/*++

Routine Description:

    This routine is invoked to change the configuration for the component.

Arguments:

    GlobalInfo - the new configuration

Return Value:

    ULONG - Win32 status code

Environment:

    The routine runs in the context of an IP router-manager thread.

--*/

{
    ULONG OldFlags;
    ULONG NewFlags;
    PIP_H323_GLOBAL_INFO NewInfo;
    ULONG Size;

    PROFILE("H323RmSetGlobalInfo");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    if (!GlobalInfo) { DEREFERENCE_H323_AND_RETURN(ERROR_INVALID_PARAMETER); }

    Size = sizeof(*H323GlobalInfo);
    NewInfo = reinterpret_cast<PIP_H323_GLOBAL_INFO>(NH_ALLOCATE(Size));
    if (!NewInfo) {
        NhTrace(
            TRACE_FLAG_INIT,
            "H323RmSetGlobalInfo: error reallocating global info"
            );
        NhErrorLog(
            IP_H323_LOG_ALLOCATION_FAILED,
            0,
            "%d",
            Size
            );
        DEREFERENCE_H323_AND_RETURN(ERROR_NOT_ENOUGH_MEMORY);
    }
    CopyMemory(NewInfo, GlobalInfo, Size);

    EnterCriticalSection(&H323GlobalInfoLock);
    OldFlags = H323GlobalInfo->Flags;
    NH_FREE(H323GlobalInfo);
    H323GlobalInfo = NewInfo;
    NewFlags = H323GlobalInfo->Flags;
    LeaveCriticalSection(&H323GlobalInfoLock);

    DEREFERENCE_H323_AND_RETURN(NO_ERROR);
    
} // H323RmSetGlobalInfo


ULONG
APIENTRY
H323RmMibCreate(
    ULONG InputDataSize,
    PVOID InputData
    )
{
    return ERROR_NOT_SUPPORTED;
}

ULONG
APIENTRY
H323RmMibDelete(
    ULONG InputDataSize,
    PVOID InputData
    )
{
    return ERROR_NOT_SUPPORTED;
}


ULONG
APIENTRY
H323RmMibGet(
    ULONG InputDataSize,
    PVOID InputData,
    OUT PULONG OutputDataSize,
    OUT PVOID OutputData
    )

/*++

Routine Description:

    The transparent proxy only exposes one item to the MIB; its statistics.

Arguments:

    InputDataSize - the MIB query data size

    InputData - specifies the MIB object to be retrieved

    OutputDataSize - the MIB response data size

    OutputData - receives the MIB object retrieved

Return Value:

    ULONG - Win32 status code.

--*/

{
    ULONG Error;
    PIP_H323_MIB_QUERY Oidp;

    PROFILE("H323RmMibGet");

    REFERENCE_H323_OR_RETURN(ERROR_CAN_NOT_COMPLETE);

    if (InputDataSize < sizeof(*Oidp) || !OutputDataSize) {
        Error = ERROR_INVALID_PARAMETER;
    } else {
        Oidp = (PIP_H323_MIB_QUERY)InputData;
//      switch(Oidp->Oid) {
//          default: {
                NhTrace(
                    TRACE_FLAG_H323,
                    "H323RmMibGet: oid %d invalid",
                    Oidp->Oid
                    );
                Error = ERROR_INVALID_PARAMETER;
//              break;
//          }
//      }
    }

    DEREFERENCE_H323_AND_RETURN(Error);
}


ULONG
APIENTRY
H323RmMibSet(
    ULONG InputDataSize,
    PVOID InputData
    )
{
    return ERROR_NOT_SUPPORTED;
}

ULONG
APIENTRY
H323RmMibGetFirst(
    ULONG InputDataSize,
    PVOID InputData,
    OUT PULONG OutputDataSize,
    OUT PVOID OutputData
    )
{
    return ERROR_NOT_SUPPORTED;
}

ULONG
APIENTRY
H323RmMibGetNext(
    ULONG InputDataSize,
    PVOID InputData,
    OUT PULONG OutputDataSize,
    OUT PVOID OutputData
    )
{
    return ERROR_NOT_SUPPORTED;
}