//+-------------------------------------------------------------------------
//
//  Microsoft Windows
//
//  Copyright (C) Microsoft Corporation, 1990 - 1999
//
//  File:       ProtBind.cxx
//
//--------------------------------------------------------------------------

/* --------------------------------------------------------------------

File: ProtBind.cxx

Description:

    The implementation of the classes that support the binding process for 
    connection oriented and local.

History :

kamenm     10-01-00    Cloned from other files with a face lift and few stitches added

-------------------------------------------------------------------- */

#include <precomp.hxx>
#include <ProtBind.hxx>

// the following lookup table uses the least significant byte of
// SyntaxGUID.Data4[0]. It is 0xF for NDR20, 0x3 for NDR64, and
// 0x5 for NDRTest
const int SyntaxBindingCapabilitiesLookup[0x10] = {
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 0
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 1
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 2
    MTSyntaxBinding::SyntaxBindingCapabilityNDR64,       // 3 - NDR64
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 4
    MTSyntaxBinding::SyntaxBindingCapabilityNDRTest,     // 5 - NDRTest
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 6
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 7
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 8
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 9
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 0xA
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 0xB
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 0xC
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 0xD
    MTSyntaxBinding::SyntaxBindingCapabilityInvalid,     // 0xE
    MTSyntaxBinding::SyntaxBindingCapabilityNDR20        // 0xF - NDR20
    };


RPC_STATUS 
MTSyntaxBinding::FindOrCreateBinding (
    IN PRPC_CLIENT_INTERFACE RpcInterfaceInformation,
    IN RPC_MESSAGE *Message,
    IN SIMPLE_DICT *BindingsDict,
    IN CreateBindingFn CreateBinding,
    OUT int *NumberOfBindings,
    IN OUT MTSyntaxBinding *BindingsForThisInterface[],
    IN OUT BOOL BindingCreated[]
    )
/*++

Routine Description:

    This method gets called to find the bindings (a dictionary
    entry) corresponding to the specified rpc interface information.
    The caller of this routine is responsible for synchronization

Arguments:

    RpcInterfaceInformation - Supplies the interface information for
        which we are looking for an osf binding object.
    Message - supplies the RPC_MESSAGE for this call
    NumberOfBindings - an out parameter that will return the number
        of retrieved bindings
    BindingsForThisInterface - a caller supplied array where the
        found bindings will be placed.

Return Value:

    RPC_S_OK for success, other for failure

--*/
{
    MTSyntaxBinding *Binding;
    DictionaryCursor cursor;
    unsigned int i;
    ULONG NumberOfTransferSyntaxes;
    MIDL_SYNTAX_INFO *SyntaxInfoArray;
    int NextBindingToBeReturned;
    RPC_STATUS Status;
    BOOL fHasMultiSyntaxes;
    TRANSFER_SYNTAX_STUB_INFO *CurrentTransferInfo;
    int ClientPreferredTransferSyntax;
    MTSyntaxBinding *CurrentBinding;
    int CapabilitiesBitmap;
    unsigned char CurrentTransferInfoLookupValue;
    int CurrentCapability;

    if ((RpcInterfaceInformation->Length != sizeof(RPC_CLIENT_INTERFACE)) &&
        (RpcInterfaceInformation->Length != NT351_INTERFACE_SIZE))
        {
        return RPC_S_UNKNOWN_IF;
        }

    if (DoesInterfaceSupportMultipleTransferSyntaxes(RpcInterfaceInformation))
        {
        Status = NdrClientGetSupportedSyntaxes (RpcInterfaceInformation,
            &NumberOfTransferSyntaxes, &SyntaxInfoArray);
        if (Status != RPC_S_OK)
            return Status;

        ASSERT(NumberOfTransferSyntaxes > 0);
        ASSERT(SyntaxInfoArray != NULL);

        fHasMultiSyntaxes = TRUE;
        }
    else
        {
        fHasMultiSyntaxes = FALSE;
        NumberOfTransferSyntaxes = 1;
        }

    // build the capabilities bitmap
    CapabilitiesBitmap = 0;
    for (i = 0; i < NumberOfTransferSyntaxes; i ++)
        {
        if (fHasMultiSyntaxes)
            {
            CurrentTransferInfo 
                = (TRANSFER_SYNTAX_STUB_INFO *)&SyntaxInfoArray[i].TransferSyntax;
            }
        else
            {
            CurrentTransferInfo 
                = (TRANSFER_SYNTAX_STUB_INFO *)&RpcInterfaceInformation->TransferSyntax;
            }

        CurrentTransferInfoLookupValue = CurrentTransferInfo->TransferSyntax.SyntaxGUID.Data4[0] & 0xF;
        CurrentCapability = SyntaxBindingCapabilitiesLookup[CurrentTransferInfoLookupValue];

        ASSERT(CurrentCapability != MTSyntaxBinding::SyntaxBindingCapabilityInvalid);

        if (CurrentCapability == MTSyntaxBinding::SyntaxBindingCapabilityInvalid)
            return RPC_S_UNSUPPORTED_TRANS_SYN;

        CapabilitiesBitmap |= CurrentCapability;
        }

    // if we create a binding here, we must also properly link it to the
    // other bindings that differ only by transfer syntax. We rely on the fact
    // that the stubs will always return multiple transfer syntaxes in the same
    // order. Therefore, we add them one by one, and if we fail towards the end
    // we leave the already added entries there. The next time we come, we
    // will try to continue off where we left
    NextBindingToBeReturned = 0;
    CurrentBinding = 0;
    for (i = 0; i < NumberOfTransferSyntaxes; i ++)
        {
        //
        // First we search for an existing presentation context
        // corresponding to the specified interface information.  Otherwise,
        // we create a new presentation context.
        //
        if (fHasMultiSyntaxes)
            {
            CurrentTransferInfo 
                = (TRANSFER_SYNTAX_STUB_INFO *)&SyntaxInfoArray[i].TransferSyntax;
            }
        else
            {
            CurrentTransferInfo 
                = (TRANSFER_SYNTAX_STUB_INFO *)&RpcInterfaceInformation->TransferSyntax;
            }

        BindingsDict->Reset(cursor);
        while ((Binding = (MTSyntaxBinding *)BindingsDict->Next(cursor)) != 0)
            {
            if (Binding->CompareWithRpcInterfaceInformation(&RpcInterfaceInformation->InterfaceId,
                    CurrentTransferInfo, CapabilitiesBitmap) == 0)
                {
                BindingCreated[NextBindingToBeReturned] = FALSE;

                CurrentBinding = Binding;
                goto StoreResultAndLookForNextTransferSyntax;
                }
            }

        // if we are here, we haven't found any bindings for this transfer syntax -
        // create some
        Binding = CreateBinding(&RpcInterfaceInformation->InterfaceId, 
            CurrentTransferInfo, CapabilitiesBitmap);

        if (Binding == 0)
            {
            *NumberOfBindings = i;
            return(RPC_S_OUT_OF_MEMORY);
            }

        Binding->SetPresentationContext(BindingsDict->Insert(Binding));
        if (Binding->GetPresentationContext() == -1)
            {
            delete Binding;
            *NumberOfBindings = i;
            return RPC_S_OUT_OF_MEMORY;
            }

        if (CurrentBinding != 0)
            CurrentBinding->SetNextBinding(Binding);

        CurrentBinding = Binding;

        // the first transfer syntax info is marked as the list start
        // this helps us figure out where the list starts later on
        if (i == 0)
            Binding->TransferSyntaxIsListStart();

        BindingCreated[NextBindingToBeReturned] = TRUE;

StoreResultAndLookForNextTransferSyntax:
        // return the newly created binding to our caller
        BindingsForThisInterface[NextBindingToBeReturned] = Binding;
        NextBindingToBeReturned ++;
        }

    *NumberOfBindings = NumberOfTransferSyntaxes;
    return RPC_S_OK;
}