/*++

Copyright (c) 1991 Microsoft Corporation

Module Name:

    dcecmisc.cxx


Abstract:

    This module contains the code implementing miscellaneous DCE RPC
    runtime APIs.  In particular, this includes the following APIs:
    RpcIfInqId, RpcNetworkIsProtseqValid, RpcMgmtInqComTimeout,
    RpcMgmtSetComTimeout, RpcMgmtSetCancelTimeout, and DceErrorInqText.

Author:

    Michael Montague (mikemon) 11-Nov-1991

Revision History:

--*/

#include <precomp.hxx>
#include <rpctran.h>



#ifdef NTENV
unsigned long RecvWindow = 0;
unsigned long SendWindow = 0;
#endif


RPC_STATUS RPC_ENTRY
RpcIfInqId (
    IN RPC_IF_HANDLE RpcIfHandle,
    OUT RPC_IF_ID PAPI * RpcIfId
    )
/*++

Routine Description:

    The routine is used by an application to obtain the interface
    identification part of an interface specification.  This is a really
    simple API since the RpcIfHandle points to the interface information,
    so all we have got to do is cast RpcIfHandle and copy some stuff.

Arguments:

    RpcIfHandle - Supplies a handle to the interface specification.

    RpcIfId - Returns the interface identification part of the interface
        specification.

Return Value:

    RPC_S_OK - The operation completed successfully.

--*/
{
    RPC_CLIENT_INTERFACE PAPI * RpcInterfaceInformation;

    InitializeIfNecessary();

    RpcInterfaceInformation = (RPC_CLIENT_INTERFACE PAPI *) RpcIfHandle;
    RpcpMemoryCopy(&(RpcIfId->Uuid),
            &(RpcInterfaceInformation->InterfaceId.SyntaxGUID),sizeof(UUID));
    RpcIfId->VersMajor =
            RpcInterfaceInformation->InterfaceId.SyntaxVersion.MajorVersion;
    RpcIfId->VersMinor =
            RpcInterfaceInformation->InterfaceId.SyntaxVersion.MinorVersion;
    return(RPC_S_OK);
}


RPC_STATUS RPC_ENTRY
RpcNetworkIsProtseqValidW (
    IN RPC_CHAR PAPI * Protseq
    )
/*++

Routine Description:

    An application program will use this API to determine if an rpc
    protocol sequence is supported by the current system.

Arguments:

    Protseq - Supplies an rpc protocol sequence to be check to see if
        it is supported.

Return Value:

    RPC_S_OK - The specified rpc protocol sequence is support.

    RPC_S_PROTSEQ_NOT_SUPPORTED - The specified rpc protocol sequence
        is not supported (but it appears to be valid).

    RPC_S_INVALID_RPC_PROTSEQ - The specified rpc protocol sequence is
        invalid.

--*/
{
    InitializeIfNecessary();

    return(IsRpcProtocolSequenceSupported(Protseq));
}


RPC_STATUS RPC_ENTRY
RpcMgmtInqComTimeout (
    IN RPC_BINDING_HANDLE Binding,
    OUT unsigned int PAPI * Timeout
    )
/*++

Routine Description:

    This routine is used to obtain the communications timeout from a
    binding handle.

Arguments:

    Binding - Supplies a binding handle from which to inquire the
        communication timeout.

    Timeout - Returns the communications timeout in the binding handle.

Return Value:

    RPC_S_OK - The operation completed successfully.

    RPC_S_INVALID_BINDING - The specified binding is not a client side
        binding handle.
--*/
{
    BINDING_HANDLE * BindingHandle;

    InitializeIfNecessary();

    BindingHandle = (BINDING_HANDLE *) Binding;
    if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
        return(RPC_S_INVALID_BINDING);

    *Timeout = BindingHandle->InqComTimeout();
    return(RPC_S_OK);
}


RPC_STATUS RPC_ENTRY
RpcMgmtSetComTimeout (
    IN RPC_BINDING_HANDLE Binding,
    IN unsigned int Timeout
    )
/*++

Routine Description:

    An application will use this routine to set the communications
    timeout for a binding handle.  The timeout value specifies the
    relative amount of time that should be spent to establish a binding
    to the server before giving up.

Arguments:

    Binding - Supplies the binding handle for which the communications
        timeout value will be set.

    Timeout - Supplies the communications timeout value to set in the
        binding handle.

Return Value:

    RPC_S_OK - The operation completed successfully.

    RPC_S_INVALID_BINDING - The specified binding is not a client side
        binding handle.

    RPC_S_INVALID_TIMEOUT - The specified timeout value is invalid.

--*/
{
    BINDING_HANDLE * BindingHandle;

    InitializeIfNecessary();

    BindingHandle = (BINDING_HANDLE *) Binding;
    if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
        return(RPC_S_INVALID_BINDING);

    return(BindingHandle->SetComTimeout(Timeout));
}


RPC_STATUS RPC_ENTRY
I_RpcIfInqTransferSyntaxes (
    IN RPC_IF_HANDLE RpcIfHandle,
    OUT RPC_TRANSFER_SYNTAX PAPI * TransferSyntaxes,
    IN unsigned int TransferSyntaxSize,
    OUT unsigned int PAPI * TransferSyntaxCount
    )
/*++

Routine Description:

    This routine will be used to obtain the transfer syntaxes support
    by an interface.  A description of the interface is supplied via
    the interface handle.

Arguments:

    RpcIfHandle - Supplies a reference to the interface from which we
        want to inquire the transfer syntaxes.

    TransferSyntaxes - Returns a copy of the transfer syntaxes support
        by the interface.

    TransferSyntaxSize - Supplies the number of RPC_TRANSFER_SYNTAX records
        which can fit in the transfer syntaxes buffer.

    TransferSyntaxCount - Returns the number of transfer syntaxes supported
        by the interface.  This value will always be returned, whether or
        not an error occurs.

Return Value:

    RPC_S_OK - We copied the transfer syntaxes into the buffer successfully.

    RPC_S_BUFFER_TOO_SMALL - The supplies transfer syntaxes buffer is too
        small; the transfer syntax count parameter will return the minimum
        size required.

--*/
{
    RPC_CLIENT_INTERFACE PAPI * RpcInterfaceInformation;

    *TransferSyntaxCount = 1;
    if (TransferSyntaxSize < 1)
        return(RPC_S_BUFFER_TOO_SMALL);

    RpcInterfaceInformation = (RPC_CLIENT_INTERFACE PAPI *) RpcIfHandle;
    RpcpMemoryCopy(&(TransferSyntaxes->Uuid),
            &(RpcInterfaceInformation->TransferSyntax.SyntaxGUID),
            sizeof(UUID));
    TransferSyntaxes->VersMajor =
        RpcInterfaceInformation->TransferSyntax.SyntaxVersion.MajorVersion;
    TransferSyntaxes->VersMinor =
        RpcInterfaceInformation->TransferSyntax.SyntaxVersion.MinorVersion;

    return(RPC_S_OK);
}


RPC_STATUS RPC_ENTRY
RpcMgmtEnableIdleCleanup (
    void
    )
/*++

Routine Description:

    An application will use this routine to enable cleanup of idle resources.
    For the connection oriented protocol module, a connection must be idle
    for five minutes before it is cleaned up.

Return Value:

    RPC_S_OK - Cleanup of idle resources has been enabled.

    RPC_S_OUT_OF_THREADS - Insufficient threads are available to be able
        to perform this operation.

    RPC_S_OUT_OF_RESOURCES - Insufficient resources are available to be
        able to perform this operation.

    RPC_S_OUT_OF_MEMORY - Insufficient memory is available to be able to
        perform this operation.

--*/
{
    InitializeIfNecessary();

    return(EnableGarbageCollection());
}


#if !defined(DOS) && !defined(MAC)

RPC_STATUS RPC_ENTRY
DceErrorInqTextA (
    IN RPC_STATUS RpcStatus,
    OUT unsigned char __RPC_FAR * ErrorText
    )
/*++

Routine Description:

    The supplied status code is converted into a text message if possible.

Arguments:

    RpcStatus - Supplies the status code to convert.

    ErrorText - Returns a character string containing the text message
        for the status code.

Return Value:

    RPC_S_OK - The supplied status codes has successfully been converted
        into a text message.

    RPC_S_INVALID_ARG - The supplied value is not a valid status code.

--*/
{
    if ( FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS
            | FORMAT_MESSAGE_FROM_SYSTEM, 0, RpcStatus, 0, (char *)ErrorText,
            DCE_C_ERROR_STRING_LEN, 0) == 0 )
        {
          if ( FormatMessageA( FORMAT_MESSAGE_IGNORE_INSERTS |
                   FORMAT_MESSAGE_FROM_SYSTEM, 0, RPC_S_NOT_RPC_ERROR,
                   0, (char *)ErrorText, DCE_C_ERROR_STRING_LEN,  0 ) == 0 )
              {
              *ErrorText = '\0';
              return(RPC_S_INVALID_ARG);
              }
        }

    return(RPC_S_OK);
}


RPC_STATUS RPC_ENTRY
DceErrorInqTextW (
    IN RPC_STATUS RpcStatus,
    OUT unsigned short __RPC_FAR * ErrorText
    )
/*++

Routine Description:

    The supplied status code is converted into a text message if possible.

Arguments:

    RpcStatus - Supplies the status code to convert.

    ErrorText - Returns a character string containing the text message
        for the status code.

Return Value:

    RPC_S_OK - The supplied status codes has successfully been converted
        into a text message.

    RPC_S_INVALID_ARG - The supplied value is not a valid status code.

--*/
{
    if ( FormatMessageW(FORMAT_MESSAGE_IGNORE_INSERTS
            | FORMAT_MESSAGE_FROM_SYSTEM, 0, RpcStatus, 0, ErrorText,
            DCE_C_ERROR_STRING_LEN * sizeof(RPC_CHAR), 0) == 0 )
        {
          if ( FormatMessageW( FORMAT_MESSAGE_IGNORE_INSERTS |
                FORMAT_MESSAGE_FROM_SYSTEM, 0, RPC_S_NOT_RPC_ERROR, 0,
                ErrorText, DCE_C_ERROR_STRING_LEN * sizeof(RPC_CHAR),0 ) == 0 )
              {
              *ErrorText = 0;
              return(RPC_S_INVALID_ARG);
              }
        }

    return(RPC_S_OK);
}

#endif // !DOS

#if defined(NTENV) || defined(WIN96)
#define CANCEL_TIMEOUT_SHIFT (16)

long
ThreadGetRpcCancelTimeout(
    )
{

 THREAD * ThreadInfo = RpcpGetThreadPointer();

 if ( (long)ThreadInfo == 0 )
     {
     //
     // ASSERT(Client Side Thread && SetCancelTO not called)
     //
     return (RPC_C_CANCEL_INFINITE_TIMEOUT);
     }

 if ( (long)ThreadInfo & HIGHBITSET )
     {
     //
     // ASSERT(CLIENT Side Thread && ! ServerSideThread && SetCancelTO called)
     //
     return (((long)ThreadInfo & ~HIGHBITSET) >> CANCEL_TIMEOUT_SHIFT );
     }

 //
 // ASSERT(Server Side Thread .. );
 //
 return (ThreadInfo->CancelTimeout);
}

#endif // NTDEV || WIN96

#ifdef NTENV


RPC_STATUS RPC_ENTRY
I_RpcConnectionInqSockBuffSize(
  OUT unsigned long __RPC_FAR * RecvBuffSize,
  OUT unsigned long __RPC_FAR * SendBuffSize
  )
{
    RequestGlobalMutex();

    *RecvBuffSize = RecvWindow;
    *SendBuffSize = SendWindow;

    ClearGlobalMutex();
    return (RPC_S_OK);
}


RPC_STATUS RPC_ENTRY
I_RpcConnectionSetSockBuffSize(
   IN unsigned long RecvBuffSize,
   IN unsigned long SendBuffSize
   )
{
    if (RecvBuffSize > 0xFFFF)
        {
        RecvBuffSize = 0xFFFF;
        }
    if (SendBuffSize > 0xFFFF)
        {
        SendBuffSize = 0xFFFF;
        }
    RequestGlobalMutex();
    RecvWindow =  RecvBuffSize;
    SendWindow = SendBuffSize;
    ClearGlobalMutex();

    return (RPC_S_OK);
}


void RPC_ENTRY
I_RpcConnectionInqSockBuffSize2(
    OUT unsigned long __RPC_FAR * RecvWindowSize
    )
{
    *RecvWindowSize = RecvWindow;
}




#endif // NTENV



RPC_STATUS RPC_ENTRY
RpcMgmtBindingSetParameter (
    IN RPC_BINDING_HANDLE Binding,
    IN unsigned Parameter,
    IN unsigned long Value
    )
{
    BINDING_HANDLE * BindingHandle;

    InitializeIfNecessary();

    BindingHandle = (BINDING_HANDLE *) Binding;
    if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
        return(RPC_S_INVALID_BINDING);

    return(BindingHandle->SetConnectionParameter(Parameter, Value));
}


RPC_STATUS RPC_ENTRY
RpcMgmtBindingInqParameter (
    IN RPC_BINDING_HANDLE Binding,
    IN unsigned Parameter,
    IN unsigned long __RPC_FAR * Value
    )
{
    BINDING_HANDLE * BindingHandle;

    InitializeIfNecessary();

    BindingHandle = (BINDING_HANDLE *) Binding;
    if (BindingHandle->InvalidHandle(BINDING_HANDLE_TYPE))
        return(RPC_S_INVALID_BINDING);

    return(BindingHandle->InqConnectionParameter(Parameter, Value));
}


RPC_STATUS RPC_ENTRY
RpcMgmtSetParameter (
    IN unsigned Parameter,
    IN unsigned long Value
    )
/*++

Routine Description:

    This fn changes connection parameters for the whole process.
    Unrecognized parameter constants are ignored.

Arguments:

    Parameter - a constant representing the parameter to change
    Value     - new value for the parameter

Return Value:

    RPC_S_OK - all is well

--*/

{
    switch (Parameter)
        {
        case RPC_C_PARM_BUFFER_LENGTH:
            {
            if (Value)
                {
                ::DefaultConnectionBufferLength = (unsigned) Value;
                }
            else
                {
                ::DefaultConnectionBufferLength = DEFAULT_CONNECTION_BUFFER_LENGTH;
                }

            break;
            }

        case RPC_C_PARM_MAX_PACKET_LENGTH:
            {
            if (Value)
                {
                ::DefaultMaxDatagramLength = (unsigned) Value;
                }
            else
                {
                ::DefaultMaxDatagramLength = DEFAULT_MAX_DATAGRAM_LENGTH;
                }

            break;
            }
        }

    return RPC_S_OK;
}


RPC_STATUS RPC_ENTRY
RpcMgmtInqParameter (
    IN unsigned Parameter,
    IN unsigned long __RPC_FAR * Value
    )
/*++

Routine Description:

    This fn examines connection parameters for the process.

Arguments:

    Parameter - a constant representing the parameter to see
    Value     - pointer where the value is copied

Return Value:

    RPC_S_OK - all is well
    RPC_S_INVALID_ARG - unknown or inapplicable parm constant

--*/
{
    switch (Parameter)
        {
        case RPC_C_PARM_BUFFER_LENGTH:
            {
            *Value = ::DefaultConnectionBufferLength;

            return RPC_S_OK;
            }

        case RPC_C_PARM_MAX_PACKET_LENGTH:
            {
            *Value = ::DefaultMaxDatagramLength;

            return RPC_S_OK;
            }

        default:
            {
            return RPC_S_INVALID_ARG;
            }
        }
}