/*++ Copyright (C) Microsoft Corporation, 1991 - 1999 Module Name: epmapper.cxx Abstract: This routine implements the server side DCE runtime APIs. The routines in this file are used by server applications only. Author: Bharat Shah (barats) 3-5-92 Revision History: 06-03-96 gopalp Added code to cleanup stale EP Mapper entries. --*/ #include #include #include #include #include #include #include #include // // Global EP cleanup context handle. Initially NULL, this will // be allocated by Endpoint Mapper. As of now, it points to the // EP entries registered by this process. This way, the Endpoint // Mapper can cleanup entries of this process as soon as process // goes away. // void * hEpContext = NULL; MUTEX *EpContextMutex = NULL; RPC_STATUS InitializeEPMapperClient( void ) { RPC_STATUS Status = RPC_S_OK; if (EpContextMutex == NULL) { EpContextMutex = new MUTEX(&Status, TRUE // pre-allocate semaphore ); if (EpContextMutex == NULL) { return RPC_S_OUT_OF_MEMORY; } if (Status != RPC_S_OK) { delete EpContextMutex; EpContextMutex = NULL; } } return Status; } inline void RequestEPClientMutex(void) { EpContextMutex->Request(); } inline void ClearEPClientMutex(void) { EpContextMutex->Clear(); } RPC_STATUS BindingAndIfToTower( IN RPC_IF_HANDLE IfSpec, IN RPC_BINDING_HANDLE BindingHandle, OUT twr_t PAPI * PAPI * Tower ) /*+ Routine Description: Helper routine that returns a Tower from the Interface Spec and a bindinh handle Arguments: IfSpec - Client or Server IfSpec structure. BindingHandle - A partially bound binding handle Tower - Returns a Tower if the Binding Handle had a dynamic endpoint, else Tower=NULL. The caller needs to free this memory. Return Value: RPC_S_OK - The ansi string was successfully converted into a unicode string. RPC_S_OUT_OF_MEMORY - Insufficient memory is available for the unicode string. EP_S_CANT_PERFORM_OP - The Binding Handle or IfSpec were in valid. --*/ { RPC_STATUS err = 0; unsigned char *Protseq = 0; unsigned char *NWAddress= 0; unsigned char *Binding = 0; unsigned char *Endpoint = 0; RPC_CHAR * String = 0; RPC_IF_ID Ifid; RPC_TRANSFER_SYNTAX Xferid; unsigned int Size; *Tower = NULL; err = RpcIfInqId(IfSpec, &Ifid); if (!err) { err = I_RpcIfInqTransferSyntaxes( IfSpec, &Xferid, sizeof(Xferid), &Size ); } if (!err) { err = I_RpcBindingInqDynamicEndpoint(BindingHandle, &String); } if (err) { return (err); } if (!err) { err = RpcBindingToStringBindingA(BindingHandle, &Binding); } if (!err) { if (String != 0) { // It is a dynamic endpoint Endpoint = UnicodeToAnsiString(String, &err); if (!err) { err = RpcStringBindingParseA( Binding, NULL, &Protseq, &NWAddress, NULL, NULL ); } } else { err = RpcStringBindingParseA( Binding, NULL, &Protseq, &NWAddress, &Endpoint, NULL ); } } if (!err) { err = TowerConstruct( &Ifid, &Xferid, (char PAPI*)Protseq, (char PAPI *)Endpoint, (char PAPI *)NWAddress, Tower ); } if (Endpoint) RpcStringFreeA(&Endpoint); if (String) RpcStringFreeA((unsigned char PAPI * PAPI *)&String); if (Protseq) RpcStringFreeA(&Protseq); if (NWAddress) RpcStringFreeA(&NWAddress); if (Binding) RpcStringFreeA(&Binding); return(err); } RPC_STATUS RegisterEntries( IN RPC_IF_HANDLE IfSpec, IN RPC_BINDING_VECTOR * BindingVector, IN UUID_VECTOR * ObjUuidVector, IN unsigned char * Annotation, IN unsigned long ReplaceNoReplace ) /*++ Routine Description: This helper function is called by RpcEpRegister or RpcEpRegisterNoReplace Depending on the TypeOp, it tries to Add or replace endpoint entries in the EP-database. Arguments: IfSpec - Interface Spec Handle for which the entries are to be registered. BindingVector - A Vector of Binding Handles which need to be registered ObjUUIDVector - A Vector of Objects Annotation - A String representing the Annotation TypeOp - A Flag : REGISTER_REPLACE or REGISTER_NO_REPLACE Return Value: RPC_S_OK - Some of the entries specified were successfully registered. RPC_S_OUT_OF_MEMORY - Insufficient memory is available, EP_S_CANT_PERFORM_OP - Misc. local error occured; e.g. could not bind to the EpMapper. --*/ { RPC_STATUS err; unsigned int i, j, k, Entries, CountBH, CountObj; RPC_BINDING_HANDLE EpMapperHandle; unsigned char * PStringBinding = NULL; twr_p_t Twr; ept_entry_t * EpEntries = NULL, *p; unsigned long ArgC = 0; char *ArgV[1] = { NULL }; if (BindingVector->Count == 0) { // // PNP // err = GlobalRpcServer->InterfaceExported( (PRPC_SERVER_INTERFACE) IfSpec, ObjUuidVector, Annotation, ReplaceNoReplace); return RPC_S_OK; } if (err = BindToEpMapper(&EpMapperHandle, NULL, // NetworkAddress NULL, // Protseq 0, // Options RPC_C_BINDING_DEFAULT_TIMEOUT, INFINITE, // CallTimeout NULL // AuthInfo )) { return err; } CountObj = (unsigned int)ObjUuidVector->Count; CountBH = (unsigned int) BindingVector->Count; if ((p = (EpEntries = (ept_entry_t *) I_RpcAllocate(CountBH * sizeof(ept_entry_t)))) == NULL) { return(RPC_S_OUT_OF_MEMORY); } for (i = 0, Entries = 0; (!err) && (i < CountBH); i++) { if (BindingVector->BindingH[i] == 0) { continue; } if (err = BindingAndIfToTower(IfSpec, BindingVector->BindingH[i], &Twr)) { err = 0; continue; } if (Twr == NULL) { continue; } Entries ++; p->tower = Twr; lstrcpyA((char PAPI *)p->annotation, (char PAPI *)Annotation); p++; } for (j = 0; j < CountObj; j++) { for (k = 0, p = EpEntries; k < Entries; k++, p++) { RpcpMemoryCopy( (char PAPI *)&p->object, (char PAPI *)ObjUuidVector->Uuid[j], sizeof(UUID) ); } RequestEPClientMutex(); RpcTryExcept { ept_insert_ex( EpMapperHandle, &hEpContext, Entries, EpEntries, ReplaceNoReplace, (error_status PAPI *)&err ); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { err = RpcExceptionCode(); } RpcEndExcept ClearEPClientMutex(); if (err == RPC_S_SERVER_UNAVAILABLE) { // //Try to start the epmapper and retry // err = StartServiceIfNecessary(); if (err == RPC_S_OK) { RequestEPClientMutex(); RpcTryExcept { ept_insert_ex( EpMapperHandle, &hEpContext, Entries, EpEntries, ReplaceNoReplace, (error_status PAPI *)&err ); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { RpcpErrorAddRecord(EEInfoGCRuntime, EPT_S_CANT_CREATE, EEInfoDLRegisterEntries10, RpcExceptionCode()); err = EPT_S_CANT_CREATE; } RpcEndExcept ClearEPClientMutex(); } } if (err != RPC_S_OK) { RpcpErrorAddRecord(EEInfoGCRuntime, EPT_S_CANT_CREATE, EEInfoDLRegisterEntries20, err); err = EPT_S_CANT_CREATE; break; } // Subsequent Inserts should be (ALWAYS) NOREPLACE // ReplaceNoReplace = REGISTER_NOREPLACE; } // for loop over UUID Vectors for (i = 0, p = EpEntries; i < Entries; i++,p++) I_RpcFree(p->tower); if (EpEntries) { I_RpcFree(EpEntries); } RpcBindingFree(&EpMapperHandle); if (err == RPC_S_OK) { // // We successfully registered our bindings, // reflect that in the interface so that if we get a // PNP notification, we can update the bindings // err = GlobalRpcServer->InterfaceExported( (PRPC_SERVER_INTERFACE) IfSpec, ObjUuidVector, Annotation, ReplaceNoReplace); } return(err); } RPC_STATUS RPC_ENTRY RpcEpRegisterNoReplaceA ( IN RPC_IF_HANDLE IfSpec, IN RPC_BINDING_VECTOR * BindingVector, IN UUID_VECTOR * UuidVector OPTIONAL, IN unsigned char * Annotation ) /*++ Routine Description: A server application will call this routine to register a series of end points with the local endpoint mapper. Arguments: Return Value: --*/ { UUID_VECTOR UuidVectorNull; UUID_VECTOR PAPI *PObjUuidVector = &UuidVectorNull; UUID NilUuid; unsigned char AnnotStr[] = {'\0'}; THREAD *Thread; if (!ARGUMENT_PRESENT(Annotation)) Annotation = AnnotStr; if (strlen((char PAPI *)Annotation) >= ep_max_annotation_size) return(EPT_S_INVALID_ENTRY); if (!ARGUMENT_PRESENT( BindingVector)) { return(RPC_S_NO_BINDINGS); } if (ARGUMENT_PRESENT( UuidVector )) { PObjUuidVector = UuidVector; } else { UuidVectorNull.Count = 1; RpcpMemorySet(&NilUuid, 0, sizeof(UUID)); UuidVectorNull.Uuid[0] = &NilUuid; } Thread = ThreadSelf(); if (Thread) { RpcpPurgeEEInfoFromThreadIfNecessary(Thread); } return(RegisterEntries( IfSpec, BindingVector, PObjUuidVector, Annotation, EP_REGISTER_NOREPLACE )); } RPC_STATUS RPC_ENTRY RpcEpRegisterNoReplaceW ( IN RPC_IF_HANDLE IfSpec, IN RPC_BINDING_VECTOR * BindingVector, IN UUID_VECTOR * UuidVector OPTIONAL, IN unsigned short * Annotation ) /*++ Routine Description: A server application will call this routine to register [Add] a series of end points with the local endpoint mapper This is the Unicode version of the API. Arguments: IfSpec - Server side Interface specification structure generated by MIDL, that describes Interface UUId and version Binding Vector - A vector of binding handles that the server has registered with the runtime. UuidVector- A vector of Uuids of objects that the server is supporting Annotation - Annotation String Return Value: --*/ { CHeapAnsi AnsiString; USES_CONVERSION; RPC_STATUS err; if (ARGUMENT_PRESENT(Annotation)) { ATTEMPT_HEAP_W2A(AnsiString, Annotation); } err = RpcEpRegisterNoReplaceA( IfSpec, BindingVector, UuidVector, AnsiString ); return(err); } RPC_STATUS RPC_ENTRY RpcEpRegisterA ( IN RPC_IF_HANDLE IfSpec, IN RPC_BINDING_VECTOR * BindingVector, IN UUID_VECTOR * UuidVector OPTIONAL, IN unsigned char * Annotation ) /*++ Routine Description: A server application will call this routine to register a series of end points with the local endpoint mapper, replacing existing database entries in the process. This is the Ansi version of the API. Arguments: IfSpec - Server side Interface specification structure generated by MIDL, that describes Interface UUId and version Binding Vector- A vector of binding handles that the server has registered with the runtime. UuidVector- A vector of Uuids of objects that the server is supporting Annotation - Annotation String Return Value: --*/ { UUID_VECTOR UuidVectorNull; UUID_VECTOR PAPI *PObjUuidVector = &UuidVectorNull; UUID NilUuid; unsigned char AnnotStr[] = {'\0'}; THREAD *Thread; if (!ARGUMENT_PRESENT(Annotation)) Annotation = AnnotStr; if (strlen((char PAPI *)Annotation) >= ep_max_annotation_size) return(EPT_S_INVALID_ENTRY); if (!ARGUMENT_PRESENT( BindingVector)) { return(RPC_S_NO_BINDINGS); } if (ARGUMENT_PRESENT( UuidVector )) { PObjUuidVector = UuidVector; } else { UuidVectorNull.Count = 1; RpcpMemorySet(&NilUuid, 0, sizeof(UUID)); UuidVectorNull.Uuid[0] = &NilUuid; } Thread = ThreadSelf(); if (Thread) { RpcpPurgeEEInfoFromThreadIfNecessary(Thread); } return(RegisterEntries( IfSpec, BindingVector, PObjUuidVector, Annotation, EP_REGISTER_REPLACE )); } RPC_STATUS RPC_ENTRY RpcEpRegisterW ( IN RPC_IF_HANDLE IfSpec, IN RPC_BINDING_VECTOR * BindingVector, IN UUID_VECTOR * UuidVector, IN unsigned short * Annotation ) /*++ Routine Description: A server application will call this routine to register a series of end points with the local endpoint mapper, replcaing existing entries in the process. This is the Unicode version of the API. Arguments: IfSpec - Server side Interface specification structure generated by MIDL, that describes Interface UUId and version Binding Vector- A vector of binding handles that the server has registered with the runtime. UuidVector- A vector of Uuids of objects that the server is supporting Annotation - Annotation String Return Value: --*/ { USES_CONVERSION; CHeapAnsi AnsiString; RPC_STATUS err; if (ARGUMENT_PRESENT(Annotation)) { ATTEMPT_HEAP_W2A(AnsiString, Annotation); } err = RpcEpRegisterA( IfSpec, BindingVector, UuidVector, AnsiString ); return(err); } RPC_STATUS RPC_ENTRY RpcEpUnregister( IN RPC_IF_HANDLE IfSpec, IN RPC_BINDING_VECTOR * BindingVector, IN UUID_VECTOR * UuidVector ) /*++ Routine Description: A server application will call this routine to unregister a series of end points. Arguments: IfSpec - Pointer to Interface Specification generated by MIDL BindingVector - A Vector of Binding handles maintained by runtime for the server. UuidVector - A Vector of UUIDs for objects supported by the the server Return Value: RPC_S_OK - RPC_S_OUT_OF_MEMORY - There is no memory available to construct towers --*/ { UUID_VECTOR UuidVectorNull; UUID_VECTOR PAPI *PObjUuidVector = &UuidVectorNull; UUID NilUuid; RPC_STATUS err; unsigned int i, j, CountBH, CountObj; RPC_BINDING_HANDLE EpMapperHandle; ept_entry_t PAPI * EpEntries, * p; twr_t PAPI *Twr; if (!ARGUMENT_PRESENT( BindingVector)) { return(RPC_S_NO_BINDINGS); } if (ARGUMENT_PRESENT( UuidVector )) { PObjUuidVector = UuidVector; } else { UuidVectorNull.Count = 1; RpcpMemorySet(&NilUuid, 0, sizeof(UUID)); UuidVectorNull.Uuid[0] = &NilUuid; } if (err = BindToEpMapper( &EpMapperHandle, NULL, // NetworkAddress NULL, // Protseq 0, // Options RPC_C_BINDING_DEFAULT_TIMEOUT, INFINITE, // CallTimeout NULL // AuthInfo )) { return(err); } CountObj = (unsigned int)PObjUuidVector->Count; if ((EpEntries = (ept_entry_t *) I_RpcAllocate(sizeof(ept_entry_t)*CountObj)) == NULL) { RpcBindingFree(&EpMapperHandle); return(RPC_S_OUT_OF_MEMORY); } RPC_STATUS FinalStatus = EPT_S_CANT_PERFORM_OP; CountBH = (unsigned int) BindingVector->Count; for (i = 0; i < CountBH; i++) { if (BindingVector->BindingH[i] == 0) { continue; } if (err = BindingAndIfToTower(IfSpec, BindingVector->BindingH[i], &Twr)) { FinalStatus = err; break; } if (Twr == NULL) { continue; } for (p=EpEntries,j = 0; j < CountObj; j++,p++) { RpcpMemoryCopy( (char PAPI *)&p->object, (char PAPI *)PObjUuidVector->Uuid[j], sizeof(UUID) ); p->tower = Twr; p->annotation[0] = '\0'; } RequestEPClientMutex(); RpcTryExcept { ept_delete_ex( EpMapperHandle, &hEpContext, CountObj, EpEntries, (error_status PAPI *)&err ); } RpcExcept(I_RpcExceptionFilter(RpcExceptionCode())) { err = EPT_S_CANT_PERFORM_OP; } RpcEndExcept ClearEPClientMutex(); I_RpcFree(Twr); } // For loop over Binding Handle Vector if (FinalStatus != RPC_S_OK) { FinalStatus = err; } I_RpcFree(EpEntries); RpcBindingFree(&EpMapperHandle); return(FinalStatus); }