/*++ Copyright (C) Microsoft Corporation, 1991 - 1999 Module Name: binding.cxx Abstract: The implementation of the DCE binding class is contained in this file. Author: Michael Montague (mikemon) 04-Nov-1991 Revision History: Kamen Moutafov (KamenM) Dec 99 - Feb 2000 - Support for cell debugging stuff --*/ #include #include #include #include #include #include #include #include #include #include #include UUID MgmtIf = { 0xafa8bd80,0x7d8a,0x11c9, {0xbe,0xf4,0x08,0x00,0x2b,0x10,0x29,0x89} }; UUID NullUuid = { 0L, 0, 0, {0,0,0,0,0,0,0,0} }; int IsMgmtIfUuid( UUID PAPI * IfId ) { if (RpcpMemoryCompare(IfId, &MgmtIf, sizeof(UUID)) == 0) { return 1; } return 0; } RPC_CHAR * DuplicateString ( IN RPC_CHAR PAPI * String ) /*++ Routine Description: When this routine is called, it will duplicate the string into a fresh string and return it. Arguments, either: String - Supplies the string to be duplicated. Ansi String - Supplies the string to be duplicated. Return Value: The duplicated string is returned. If insufficient memory is available to allocate a fresh string, zero will be returned. --*/ { RPC_CHAR * FreshString, * FreshStringScan; RPC_CHAR PAPI * StringScan; unsigned int Length; ASSERT(String); Length = 1; StringScan = String; while (*StringScan++ != 0) Length += 1; FreshString = new RPC_CHAR[Length]; if (FreshString == 0) return(0); for (FreshStringScan = FreshString, StringScan = String; *StringScan != 0; FreshStringScan++, StringScan++) { *FreshStringScan = *StringScan; } *FreshStringScan = *StringScan; return(FreshString); } DCE_BINDING::DCE_BINDING ( IN RPC_CHAR PAPI * ObjectUuid OPTIONAL, IN RPC_CHAR PAPI * RpcProtocolSequence OPTIONAL, IN RPC_CHAR PAPI * NetworkAddress OPTIONAL, IN RPC_CHAR PAPI * Endpoint OPTIONAL, IN RPC_CHAR PAPI * Options OPTIONAL, OUT RPC_STATUS PAPI * Status ) /*++ Routine Description: The constructor creates a DCE_BINDING object based on the pieces of the string binding specified. Arguments: ObjectUuid - Optionally supplies the object uuid component of the binding. RpcProtocolSequence - Optionally supplies the rpc protocol sequence component of the binding. NetworkAddress - Optionally supplies the network address component of the binding. Endpoint - Optionally supplies the endpoint component of the binding. Options - Optionally supplies the network options component of the binding. Status - Returns the status of the operation. This argument will be set to one of the following values. RPC_S_OK - The operation completed successfully. RPC_S_INVALID_STRING_UUID - The specified object uuid does not contain the valid string representation of a uuid. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to complete the operation. --*/ { ALLOCATE_THIS(DCE_BINDING); *Status = RPC_S_OK; if ( ARGUMENT_PRESENT(ObjectUuid) && (ObjectUuid[0] != 0)) { if (this->ObjectUuid.ConvertFromString(ObjectUuid)) { *Status = RPC_S_INVALID_STRING_UUID; this->ObjectUuid.SetToNullUuid(); } } else this->ObjectUuid.SetToNullUuid(); if (ARGUMENT_PRESENT(RpcProtocolSequence)) { this->RpcProtocolSequence = DuplicateString(RpcProtocolSequence); if (this->RpcProtocolSequence == 0) *Status = RPC_S_OUT_OF_MEMORY; } else this->RpcProtocolSequence = 0; if (ARGUMENT_PRESENT(NetworkAddress)) { this->NetworkAddress = DuplicateString(NetworkAddress); if (this->NetworkAddress == 0) *Status = RPC_S_OUT_OF_MEMORY; } else this->NetworkAddress = 0; if (ARGUMENT_PRESENT(Endpoint)) { this->Endpoint = DuplicateString(Endpoint); if (this->Endpoint == 0) *Status = RPC_S_OUT_OF_MEMORY; } else this->Endpoint = 0; if (ARGUMENT_PRESENT(Options)) { this->Options = DuplicateString(Options); if (this->Options == 0) *Status = RPC_S_OUT_OF_MEMORY; } else { this->Options = 0; } } /*static*/ RPC_CHAR PAPI * StringCharSearchWithEscape ( IN RPC_CHAR PAPI * String, IN unsigned int Character ) /*++ Routine Description: This routine is the same as the library routine, strchr, except that the backslash character ('\') is treated as an escape character. Arguments: String - Supplies the string in which to search for the character. Character - Supplies the character to search for in the string. Return Value: A pointer to the first occurance of Character in String is returned. If Character does not exist in String, then 0 is returned. --*/ { #ifdef DBCS_ENABLED ASSERT(IsDBCSLeadByte((RPC_CHAR)Character) == FALSE); ASSERT(IsDBCSLeadByte(RPC_CONST_CHAR('\\')) == FALSE); while(*String != (RPC_CHAR)Character) { if (*String == 0) return(0); if (*String == RPC_CONST_CHAR('\\')) { String = (RPC_CHAR *)CharNext((LPCSTR)String); } String = (RPC_CHAR *)CharNext((LPCSTR)String); } return(String); #else while (*String != (RPC_CHAR) Character) { if (*String == RPC_CONST_CHAR('\\')) String++; if (*String == 0) return(0); String++; } return(String); #endif } /*static*/ void StringCopyWithEscape ( OUT RPC_CHAR PAPI * Destination, IN RPC_CHAR PAPI * Source ) /*++ Routine Description: This routine is the same as the library routine, strcpy, except that the backslash character ('\') is treated as an escape character. When a character is escaped, the backslash character is not copied to the Destination. Arguments: Destination - Returns a duplicate of the string specified in Source, but with out escaped characters escaped. Source - Specifies the string to be copied. Return Value: None. --*/ { BOOL fLastQuote = FALSE; #ifdef DBCS_ENABLED ASSERT(IsDBCSLeadByte('\\') == FALSE); #endif while ((*Destination = *Source) != 0) { #ifdef DBCS_ENABLED if (IsDBCSLeadByte(*Source)) { // Copy the whole DBCS character; don't look for // escapes within the character. Destination++; Source++; *Destination = *Source; if (*Source == 0) { ASSERT(0); // Bad string, NULL following a lead byte. return; } Destination++; Source++; } else #endif { if ( *Source != RPC_CONST_CHAR('\\') || fLastQuote == TRUE) { Destination++; fLastQuote = FALSE; } else { fLastQuote = TRUE; } Source++; } } } /*static*/ RPC_STATUS ParseAndCopyEndpointField ( OUT RPC_CHAR ** Endpoint, IN RPC_CHAR PAPI * String ) /*++ Routine Description: This routine parses and then copies the endpoint field in String. A copy of the field is made into a newly allocated string and returned in Endpoint. String is assumed to contain only the endpoint field; the terminating ',' or ']' are not included. Arguments: Endpoint - Returns a copy of the endpoint field in a newly allocated string. String - Supplies the endpoint field to be parsed and copied. Return Value: RPC_S_OK - The operation completed successfully. RPC_S_OUT_OF_MEMORY - There is no memory available to make a copy of the string. RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint field is syntactically incorrect. This error code will be returned if the endpoint field does not match the following pattern. [ | "endpoint=" ] --*/ { // Search will be used to scan along the string to find the end of // the endpoint field and the '='. RPC_CHAR PAPI * Search; Search = StringCharSearchWithEscape(String,RPC_CONST_CHAR('=')); if (Search == 0) { // This means that we have the pattern, so we just // copy the endpoint field. Search = StringCharSearchWithEscape(String,0); *Endpoint = new RPC_CHAR[size_t(Search - String + 1)]; if (*Endpoint == 0) return(RPC_S_OUT_OF_MEMORY); StringCopyWithEscape(*Endpoint,String); return(RPC_S_OK); } // Otherwise, we have the "endpoint=" pattern. First we need to check // that the string before the '=' is in fact "endpoint". *Search = 0; if ( RpcpStringCompare(String, RPC_CONST_STRING("endpoint")) != 0 ) { *Search = RPC_CONST_CHAR('='); return(RPC_S_INVALID_ENDPOINT_FORMAT); } *Search = RPC_CONST_CHAR('='); String = Search + 1; // Now we just need to allocate a new string and copy the endpoint into // it. Search = StringCharSearchWithEscape(String,0); *Endpoint = new RPC_CHAR[size_t(Search - String + 1)]; if (*Endpoint == 0) return(RPC_S_OUT_OF_MEMORY); StringCopyWithEscape(*Endpoint,String); return(RPC_S_OK); } RPC_CHAR * AllocateEmptyString ( void ) /*++ Routine Description: This routine allocates and returns an empty string (""). Return Value: A newly allocated empty string will be returned. --*/ { RPC_CHAR * String; String = new RPC_CHAR[1]; if (String != 0) *String = 0; return(String); } DCE_BINDING::DCE_BINDING ( IN RPC_CHAR PAPI * StringBinding, OUT RPC_STATUS PAPI * Status ) /*++ Routine Description: This constructor creates a DCE_BINDING object from a string binding, which requires that the string binding be parsed into seperate strings and validated. Arguments: StringBinding - Supplies the string being to be parsed. Status - Returns the status of the operation. This parameter will take on the following values: RPC_S_OK - The operation completed successfully. RPC_S_OUT_OF_MEMORY - Insufficient memory is available to allocate space for the fields of the string binding. RPC_S_INVALID_STRING_BINDING - The string binding is syntactically invalid. RPC_S_INVALID_ENDPOINT_FORMAT - The endpoint specified in the string binding is syntactically incorrect. RPC_S_INVALID_STRING_UUID - The specified object uuid does not contain the valid string representation of a uuid. --*/ { // String will point to the beginning of the field we are trying to // parse. RPC_CHAR PAPI * String; // Search will be used to scan along the string to find the end of // the field we are trying to parse. RPC_CHAR PAPI * Search; // This will contain the string representation of the object uuid. RPC_CHAR PAPI * ObjectUuidString; ALLOCATE_THIS(DCE_BINDING); // A string binding consists of an optional object uuid, an RPC protocol // sequence, a network address, an optional endpoint, and zero or more // option fields. // // [ "@" ] ":" // [ "[" ( | "endpoint=" | ) [","] // [ ","