/*++ Microsoft Windows NT RPC Name Service Copyright (c) 1995 Microsoft Corporation Module Name: api.cxx Abstract: This file contains 1. implementations of most noninline member functions in the Locator class. 2. implementations of the remoted API functions called by the name service client DLL. 3. implementations of the locator-to-locator API functions. Author: Satish Thatte (SatishT) 08/15/95 Created all the code below except where otherwise indicated. --*/ #include #include #include // server side stub definitions for locator #include // LAN Manager basic definitions #include // NetServerEnum etc #include // NetWkstaGetInfo etc #include // NetGetDCName etc #include // mailslot-related data structures /*********** **********/ /*********** constructor and utility operations in the Locator class **********/ /*********** **********/ Locator::Locator() /*++ Member Description: Constructor. Initializes the state of the locator, including discovering whether it is running in a domain or workgroup, and the names of DCs, if any. In a domain, if the PDC machine (not just the PDC locator) is down, the environment is initialized to workgroup instead of domain. --*/ { piiIndex = new CInterfaceIndex(this); pgslEntryList = new TGSLEntryList; psllBroadcastHistory = new TSLLBroadcastQP; ulMaxCacheAge = MAX_CACHE_AGE; fDCsAreDown = FALSE; WKSTA_INFO_100 * WorkInfo; NET_API_STATUS NetStatus = NetWkstaGetInfo(NULL, 100, (LPBYTE *) &WorkInfo); srand( (unsigned)time( NULL ) ); if (NetStatus != NO_ERROR) StopLocator( "NetWkstaGetInfo Failed", NSI_S_INTERNAL_ERROR ); hMailslotForReplies = new READ_MAIL_SLOT(PMAILNAME_C, sizeof(QueryReply)); hMasterFinderSlot = new READ_MAIL_SLOT(RESPONDERMSLOT_C, sizeof(QueryReply)); pDomainName = new CStringW(WorkInfo->wki100_langroup); pComputerName = new CStringW(WorkInfo->wki100_computername); if (!SetRoleAndSystemType()) StopLocator( "Failed to determine system type", NSI_S_INTERNAL_ERROR ); switch (System) { case Domain: LPBYTE DCnameBuffer; NET_API_STATUS NetStatus; NetStatus = NetGetDCName(NULL,NULL,&DCnameBuffer); if ((NetStatus == NO_ERROR) || (NetStatus == ERROR_MORE_DATA)) { pPrimaryDCName = new CStringW(((STRING_T) DCnameBuffer) + 2); // skip over "\\" InitializeDomainBasedLocator(); } else { // in the absence of a PDC, we pretend to be in a workgroup pPrimaryDCName = NULL; System = Workgroup; InitializeWorkgroupBasedLocator(); } break; case Workgroup: pPrimaryDCName = NULL; InitializeWorkgroupBasedLocator(); break; default: StopLocator( "Unknown system type", NSI_S_INTERNAL_ERROR ); } } Locator::~Locator() /*++ Member Description: Destructor. --*/ { delete pDomainName; delete pComputerName; delete pPrimaryDCName; pgslEntryList->wipeOut(); delete pgslEntryList; PCSBroadcastHistory.Enter(); psllBroadcastHistory->wipeOut(); delete psllBroadcastHistory; pAllMasters->wipeOut(); delete pAllMasters; delete piiIndex; delete hMailslotForReplies; delete hMasterFinderSlot; } void Locator::InitializeDomainBasedLocator() /*++ Member Description: Initialize the domain locator. The list of masters is initialized to hold names of all BDCs. The name of the PDC has already been initialized. --*/ { if ((Role == Master) || (Role == Backup)) pAllMasters = new TGSLString; // DC locators don't use BDCs as masters else pAllMasters = EnumDCs(pDomainName,SV_TYPE_DOMAIN_BAKCTRL,100); } void Locator::InitializeWorkgroupBasedLocator() /*++ Member Description: Initialize the workgroup locator. No masters are known to start with. --*/ { pAllMasters = new TGSLString; // initialize with empty list, and add // potential masters in QueryProcess Role = Backup; // always ready to serve, if called upon to do so } TGSLString * Locator::EnumDCs( CStringW * pDomainName, DWORD ServerType, long lNumWanted ) /*++ Member Description: This is a static private helper operation for enumerating servers of a given type in a given domain. Arguments: pDomainName - the Unicode string name of the domain ServerType - the mask bits defining server types of interest lNumWanted - the number of servers to ask for; it seems a good idea to ask for a lot (say 100) to make sure you get all because NetServerEnum can be stingy with names Returns: A Guarded Skiplist of string names. --*/ { DWORD EntriesRead, TotalEntries, ResumeHandle; SERVER_INFO_100 * buffer; NET_API_STATUS NetStatus = NetServerEnum ( NULL, // local 100, // info level (LPBYTE *) &buffer, lNumWanted*sizeof(SERVER_INFO_100), &EntriesRead, &TotalEntries, ServerType, *pDomainName, // auto conversion to STRING_T &ResumeHandle ); TGSLString *pResult = new TGSLString; if ((NetStatus == NO_ERROR) || (NetStatus == ERROR_MORE_DATA)) { for (DWORD i = 0; i < EntriesRead; i++) { pResult->insert(new CStringW(buffer->sv100_name)); buffer++; } } else StopLocator( "NetServerEnum Failed", NSI_S_INTERNAL_ERROR ); return pResult; } BOOL Locator::broadcastCleared( QueryPacket& NetRequest, ULONG ulCacheTolerance ) /*++ Member Description: Given a query packet and a tolerance for staleness, decide if a broadcast should be made based on recent history of broadcasts. Arguments: NetRequest - the request packet ulCacheTolerance - tolerance for staleness in seconds Returns: TRUE - if broadcast should be made FALSE - if broadcast is unnecessary --*/ { SimpleCriticalSection me(PCSBroadcastHistory); TSLLBroadcastQPIter histIter(*psllBroadcastHistory); for (CBroadcastQueryPacket *pbqp = histIter.next(); pbqp; pbqp = histIter.next()) { // if the history is too stale for the global cache retirement age, remove it. if (!pbqp->isCurrent(ulMaxCacheAge)) { psllBroadcastHistory->remove(pbqp); delete pbqp; } // otherwise, in the subsumes check, use the requested cache retirement age else if (pbqp->subsumes(NetRequest,ulCacheTolerance)) { return FALSE; } } return TRUE; } CEntry * Locator::getEntry( IN UNSIGNED32 EntryNameSyntax, IN STRING_T EntryName, TGSLEntryList * pEntryList ) /*++ Member Description: Get the given entry, either locally or from persistent store. Raise exceptions if anything is wrong. Arguments: EntryNameSyntax - Name syntax EntryName - Name string of the entry to export Interface - Interface to standardize Returns: The entry found -- NULL if none. --*/ { if (!pEntryList) pEntryList = this->pgslEntryList; if (EntryNameSyntax != RPC_C_NS_SYNTAX_DCE) Raise(NSI_S_UNSUPPORTED_NAME_SYNTAX); if (!EntryName) Raise(NSI_S_INCOMPLETE_NAME); /* The constructor for CEntryName used below makes the name local if possible */ CStringW * pswName = new CStringW(CEntryName(EntryName)); CEntry * pEntry = NULL; __try { pEntry = pEntryList->find(pswName); if (!pEntry) pEntry = GetPersistentEntry(EntryName); } __finally { delete pswName; } return pEntry; } CRemoteLookupHandle * Locator::NetLookup( UNSIGNED32 EntryNameSyntax, STRING_T EntryName, CGUIDVersion * pGVinterface, CGUIDVersion * pGVsyntax, CGUID * pIDobject, unsigned long ulVectorSize, unsigned long ulCacheAge ) /*++ Member Description: Use the given lookup parameters to perform a lookup from the network -- either via a master locator or via broadcast depending on the status of the current locator and the status of the master locator(s). Since net lookup is now "lazy" (net is accessed only if needed), we need a lazy handle which initializes itself according to the old pattern of "use master if you can, broadcast if you must". Arguments: EntryNameSyntax - Name syntax, optional EntryName - (raw) Name of the entry to look up, optional pGVinterface - (wrapped) Interface to look up, optional pGVsyntax - (wrapped) Transfer syntax, optional pIDobject - (wrapped) Object UUID, optional ulVectorSize - Max size of vectors of binding handles, 0 for default ulCacheAge - acceptable max age of cached information from a master Returns: A lookup handle based on the info retrieved. --*/ { return new CNetLookupHandle( EntryNameSyntax, EntryName, pGVinterface, pGVsyntax, pIDobject, ulVectorSize, ulCacheAge ); } void Locator::UpdateCache( STRING_T entry_name, UNSIGNED32 entry_name_syntax, RPC_SYNTAX_IDENTIFIER rsiInterface, RPC_SYNTAX_IDENTIFIER rsiTransferSyntax, STRING_T string, NSI_UUID_VECTOR_P_T pUuidVector, TSSLEntryList * psslTempNetCache ) /*++ Member Description: Update the locator's cache with information retrieved from the net (either from a master locator or from a broadcast). Also update the temporary cache (last parameter) which holds only new information for use in the remote handle based on the current NetLookup. The use of this temporary cache avoids duplication in the information returned to the client. Arguments: entry_name - (raw) name of the entry being updated entry_name_syntax - name syntax rsiInterface - (raw) interface rsiTransferSyntax - (raw) transfer syntax string - (raw) string binding handle pUuidVector - vector of object UUIDs to add to entry psslTempNetCache - a temporary cache of entries for use in a remote handle --*/ { NSI_SERVER_BINDING_VECTOR_T BindingVector; BindingVector.count = 1; BindingVector.string[0] = string; NSI_INTERFACE_ID_T Interface; Interface.Interface = rsiInterface; Interface.TransferSyntax = rsiTransferSyntax; /* first we update the locator's cache */ if ( nsi_binding_export( entry_name_syntax, entry_name, &Interface, &BindingVector, pUuidVector, Cache ) ) { /* if there was something new, we update the temporary cache for the net handle. The constructor for CEntryName used below makes the name local if possible. */ CStringW * pswName = new CStringW(CEntryName(entry_name)); CServerEntry * pTempCacheEntry = (CServerEntry*) psslTempNetCache->find(pswName); delete pswName; if (!pTempCacheEntry) { pTempCacheEntry = new CServerEntry(entry_name); psslTempNetCache->insert(pTempCacheEntry); } export_to_server_entry( pTempCacheEntry, &Interface, &BindingVector, pUuidVector ); } } CObjectInqHandle * Locator::NetObjectInquiry( UNSIGNED32 EntryNameSyntax, STRING_T EntryName ) /*++ Member Description: Perform an inquiry on the network for object UUIDs registered in the given entry. The network is searched either via a master locator or via broadcast depending on the status of the current locator and the status of the master locator(s). Arguments: EntryNameSyntax - Name syntax, optional EntryName - (raw) Name of the entry to look up, optional Returns: A handle based on the info retrieved. --*/ { return new CNetObjectInqHandle( EntryName, ulMaxCacheAge ); } int Locator::export_to_server_entry( IN CServerEntry * pEntry, IN NSI_INTERFACE_ID_T * Interface, IN NSI_SERVER_BINDING_VECTOR_T * BindingVector, IN NSI_UUID_VECTOR_P_T ObjectVector ) /*++ Member Description: Export interfaces and objects to a server entry. Arguments: Interface - (raw) Interface+TransferSyntax to export BindingVector - (raw) Vector of string bindings to export. ObjectVector - (raw) Vector of object UUIDs to add to the entry Returns: TRUE - if the export results in changes to the entry FALSE - if the entry is unchanged Exceptions: NSI_OUT_OF_MEMORY, NSI_S_INVALID_OBJECT, NSI_S_INVALID_STRING_BINDING, NSI_S_NOTHING_TO_EXPORT --*/ { int fChanges = FALSE; if (Interface && IsNilIfId(&(Interface->Interface))) Interface = NULL; if (!ObjectVector && (!Interface || !BindingVector)) Raise(NSI_S_NOTHING_TO_EXPORT); if (ObjectVector) fChanges = pEntry->addObjects(ObjectVector); if (Interface && BindingVector) fChanges = pEntry->addToInterface(Interface,BindingVector,piiIndex) || fChanges; return fChanges; } // export_to_server_entry /*********** **********/ /*********** primary API operations in the Locator class **********/ /*********** **********/ CServerEntry * Locator::nsi_binding_export( IN UNSIGNED32 EntryNameSyntax, IN STRING_T EntryName, IN NSI_INTERFACE_ID_T * Interface, IN NSI_SERVER_BINDING_VECTOR_T * BindingVector, IN NSI_UUID_VECTOR_P_T ObjectVector, IN ExportType type ) /*++ Member Description: This is basically the API function for binding export. The member version here does raise exception (often inside a try block) but they are all error situations and therefore acceptable for performance. This member is also used for updating the locator's cache. Arguments: EntryNameSyntax - Name syntax, optional EntryName - (raw) Name of the entry to look up, optional Interface - (raw) Interface+TransferSyntax to export BindingVector - (raw) Vector of string bindings to export. ObjectVector - (raw) Vector of object UUIDs to add to the entry type - local or cache (owned or imported information) Returns: A pointer to the entry to which export occurred if there were changes, NULL otherwise. Exceptions: NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_INCOMPLETE_NAME, NSI_OUT_OF_MEMORY, NSI_S_INVALID_OBJECT, NSI_S_NOTHING_TO_EXPORT, NSI_S_ENTRY_TYPE_MISMATCH --*/ { int fChanges = FALSE, fNewEntry = FALSE; CEntry * pEntry = getEntry( EntryNameSyntax, EntryName, pgslEntryList ); CServerEntry * pRealEntry; CFullServerEntry * pFSentry; if (!pEntry) { // NOTE: SECURITY: need extra check here pFSentry = new CFullServerEntry(EntryName); pgslEntryList->insert(pFSentry); fNewEntry = fChanges = TRUE; } else { if (pEntry->getType() != FullServerEntryType) Raise(NSI_S_ENTRY_NOT_FOUND); else pFSentry = (CFullServerEntry *) pEntry; } switch (type) { case Local: pRealEntry = pFSentry->getLocal(); break; case Cache: pRealEntry = pFSentry->getCache(); } __try { fChanges = export_to_server_entry( pRealEntry, Interface, BindingVector, ObjectVector ) || fChanges; } __except ( (GetExceptionCode() == NSI_S_NOTHING_TO_EXPORT) && fNewEntry ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { { /* BUGBUG: This guard should really be here but it conflicts with the reader guard in isEmpty -- leave out for now. CriticalWriter me(rwEntryGuard); */ if (pFSentry->isEmpty()) { pgslEntryList->remove(pFSentry); delete pFSentry; } } Raise(NSI_S_NOTHING_TO_EXPORT); } if (fChanges && (type == Local)) UpdatePersistentEntry(pRealEntry); if (fChanges) return pRealEntry; else return NULL; } // nsi_binding_export void Locator::nsi_mgmt_binding_unexport( UNSIGNED32 EntryNameSyntax, STRING_T EntryName, NSI_IF_ID_P_T Interface, UNSIGNED32 VersOption, NSI_UUID_VECTOR_P_T ObjectVector ) /*++ Member Description: unexport information from a server entry -- finer control than nsi_binding counterpart. Arguments: EntryNameSyntax - name syntax EntryName - (raw) Name string of the entry to unexport Interface - (raw) Interface+TransferSyntax to unexport VersOption - flag which controls in fine detail which interfaces to remove ObjectVector - objects to remove from the entry Exceptions: NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_INCOMPLETE_NAME, NSI_S_INVALID_VERS_OPTION, NSI_S_ENTRY_NOT_FOUND. NSI_S_NOTHING_TO_UNEXPORT, NSI_S_NOT_ALL_OBJS_UNEXPORTED, NSI_S_INTERFACE_NOT_FOUND, NSI_S_ENTRY_TYPE_MISMATCH --*/ { int fChanges = FALSE; if (Interface && IsNilIfId(Interface)) Interface = NULL; if (!ObjectVector && !Interface) Raise(NSI_S_NOTHING_TO_UNEXPORT); CEntry * pEntry = getEntry( EntryNameSyntax, EntryName, pgslEntryList ); CServerEntry * pSEntry; if (!pEntry || pEntry->getType() != FullServerEntryType) Raise(NSI_S_ENTRY_NOT_FOUND); else pSEntry = ((CFullServerEntry *) pEntry)->getLocal(); if (Interface) fChanges = pSEntry->removeInterfaces(Interface,VersOption,piiIndex); if (Interface && !fChanges) Raise(NSI_S_INTERFACE_NOT_FOUND); /* objects are removed only if interfaces are successfully removed */ int fRemovedAll = TRUE; // safe assumption if (ObjectVector) fChanges = pSEntry->removeObjects(ObjectVector,fRemovedAll) || fChanges; if (fChanges) UpdatePersistentEntry(pSEntry); if (!fRemovedAll) Raise(NSI_S_NOT_ALL_OBJS_UNEXPORTED); } // nsi_mgmt_binding_unexport NSI_NS_HANDLE_T Locator::nsi_binding_lookup_begin( IN UNSIGNED32 EntryNameSyntax, IN STRING_T EntryName, IN NSI_INTERFACE_ID_T * Interface, OPT IN NSI_UUID_P_T Object, OPT IN UNSIGNED32 VectorSize, IN UNSIGNED32 MaxCacheAge ) /*++ Member Description: Perform a lookup operation, including all available information (owned, cached and from the network). Arguments: EntryNameSyntax - Name syntax EntryName - Name string to lookup on. Interface - Interface to search for Object - Object UUID to search for VectorSize - Size of return vector Returns: A context handle for NS lookup. Exceptions: NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_ENTRY_NOT_FOUND, NSI_S_OUT_OF_MEMORY, NSI_S_INVALID_OBJECT --*/ { if (Interface && IsNilIfId(&(Interface->Interface))) Interface = NULL; CEntry * pEntry = NULL; int fDefaultEntry = FALSE; int fTentativeStatus = NSI_S_OK; if (EntryName) pEntry = getEntry( EntryNameSyntax, EntryName, pgslEntryList ); else fDefaultEntry = TRUE; /* BUGBUG: in the following statement, we are assuming a server entry whereas the real entry may be a group or profile entry. However, direct caching as a server entry is adequate for now. */ if (!fDefaultEntry && !pEntry) { pEntry = new CFullServerEntry(EntryName); pgslEntryList->insert(pEntry); fTentativeStatus = NSI_S_ENTRY_NOT_FOUND; } CGUIDVersion * pGVinterface = NULL; CGUIDVersion * pGVsyntax = NULL; CGUID * pIDobject = NULL; CLookupHandle * pFinalHandle = NULL; __try { unsigned long ulVectorSize = (VectorSize) ? VectorSize : RPC_C_BINDING_MAX_COUNT; pGVinterface = (Interface)? new CGUIDVersion(Interface->Interface) : NULL; pGVsyntax = (Interface)? new CGUIDVersion(Interface->TransferSyntax) : NULL; RPC_STATUS dummyStatus; pIDobject = (!Object || UuidIsNil(Object,&dummyStatus)) ? NULL : new CGUID(*Object) ; if (fDefaultEntry) { /* it is important to do the index lookup before the net lookup so as to avoid duplication in the results returned. If the net lookup uses a broadcast handle, the initialization will create both a private and a public cache (the former to avoid duplication), and the latter will be picked up by index lookup if it is done later. */ CLookupHandle *pGLHindex = new CIndexLookupHandle( pGVinterface, pGVsyntax, pIDobject, ulVectorSize, MaxCacheAge? MaxCacheAge: ulMaxCacheAge ); CRemoteLookupHandle *prlhNetLookup = NetLookup( EntryNameSyntax, EntryName, pGVinterface, pGVsyntax, pIDobject, ulVectorSize, MaxCacheAge? MaxCacheAge: ulMaxCacheAge ); DBGOUT(MEM1,"Creating Complete Handle for NULL Entry\n\n"); pFinalHandle = new CCompleteHandle( pGLHindex, NULL, prlhNetLookup, MaxCacheAge? MaxCacheAge: ulMaxCacheAge ); } else { DBGOUT(MEM1,"Creating Complete Handle for " << *pEntry << "\n\n"); pFinalHandle = pEntry->lookup( pGVinterface, pGVsyntax, pIDobject, ulVectorSize, MaxCacheAge? MaxCacheAge: ulMaxCacheAge ); if (fTentativeStatus == NSI_S_ENTRY_NOT_FOUND) { fTentativeStatus = ((CCompleteHandle*) pFinalHandle)->netStatus(); /* BUGBUG: This guard should really be here but it conflicts with the reader guard in isEmpty below -- leave out for now. CriticalWriter me(rwEntryGuard); */ if ((fTentativeStatus == NSI_S_NO_MORE_BINDINGS) && pEntry->isEmpty()) { pgslEntryList->remove(pEntry); delete pEntry; } } } } __finally { delete pGVinterface; delete pGVsyntax; delete pIDobject; } if (fTentativeStatus != NSI_S_OK) { delete pFinalHandle; Raise(fTentativeStatus); } return (NSI_NS_HANDLE_T) pFinalHandle; } /* Note that there is no such thing as an object inquiry in the default entry */ NSI_NS_HANDLE_T Locator::nsi_entry_object_inq_begin( UNSIGNED32 EntryNameSyntax, STRING_T EntryName ) /*++ Member Description: Perform an object inquiry, including all available information (owned, cached and from the network). Arguments: EntryNameSyntax - Name syntax EntryName - Name string to lookup on. Returns: A context handle. Exceptions: NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_INCOMPLETE_NAME, NSI_S_OUT_OF_MEMORY --*/ { if (!EntryName) Raise(NSI_S_INCOMPLETE_NAME); CEntry * pEntry = getEntry( EntryNameSyntax, EntryName, pgslEntryList ); /* BUGBUG: in the following statement, we are assuming a server entry whereas the real entry may be a group or profile entry. However, direct caching as a server entry is adequate for now. */ if (!pEntry) { pEntry = new CFullServerEntry(EntryName); pgslEntryList->insert(pEntry); } CObjectInqHandle * InqContext = pEntry->objectInquiry(ulMaxCacheAge); return (NSI_NS_HANDLE_T) InqContext; } /************* ************* ************* The top level API routines follow ************* ************* *************/ extern "C" { #include "nsisvr.h" void nsi_binding_export( IN UNSIGNED32 EntryNameSyntax, IN STRING_T EntryName, IN NSI_INTERFACE_ID_T * Interface, IN NSI_SERVER_BINDING_VECTOR_T *BindingVector, IN NSI_UUID_VECTOR_P_T ObjectVector, OPT IN UNSIGNED16 * status ) /*++ Routine Description: Export interfaces and objects to a server entry. Arguments: EntryNameSyntax - Name syntax EntryName - Name string of the entry to export Interface - Interface unexport BindingVector - Vector of string bindings to export. ObjectVector - Objects to add to the entry status - Status is returned here Returned Status: NSI_S_OK, NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_INCOMPLETE_NAME, NSI_S_OUT_OF_MEMORY, NSI_S_INVALID_OBJECT, NSI_S_NOTHING_TO_EXPORT, NSI_S_ENTRY_TYPE_MISMATCH --*/ { DBGOUT(API, "\nExport for Entry " << EntryName << "\n\n"); DBGOUT(API, "With Binding Vector:\n" << BindingVector); DBGOUT(API, "\n\nAnd Object Vector:\n" << ObjectVector << "\n\n"); *status = NSI_S_OK; RPC_STATUS raw_status; __try { myRpcLocator->nsi_binding_export( EntryNameSyntax, EntryName, Interface, BindingVector, ObjectVector, Local ); } __except (EXCEPTION_EXECUTE_HANDLER) { switch (raw_status = GetExceptionCode()) { case NSI_S_UNSUPPORTED_NAME_SYNTAX: case NSI_S_INCOMPLETE_NAME: case NSI_S_OUT_OF_MEMORY: case NSI_S_INVALID_OBJECT: case NSI_S_NOTHING_TO_EXPORT: case NSI_S_ENTRY_TYPE_MISMATCH: /* the following converts ULONG to UNSIGNED16 but that's OK for the actual values */ *status = (UNSIGNED16) raw_status; break; default: *status = NSI_S_INTERNAL_ERROR; } } } void nsi_mgmt_binding_unexport( UNSIGNED32 EntryNameSyntax, STRING_T EntryName, NSI_IF_ID_P_T Interface, UNSIGNED32 VersOption, NSI_UUID_VECTOR_P_T ObjectVector, UNSIGNED16 * status ) /*++ Routine Description: unExport a information from a server entry finer control then nsi_binding counter part. Arguments: EntryNameSyntax - Name syntax EntryName - Name string of the entry to unexport Interface - Interface to unexport VersOption - controls in fine detail which interfaces to remove. ObjectVector - Objects to remove from the entry status - Status is returned here Returned Status: NSI_S_OK, NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_INCOMPLETE_NAME, NSI_S_INVALID_VERS_OPTION, NSI_S_ENTRY_NOT_FOUND. NSI_S_NOTHING_TO_UNEXPORT, NSI_S_NOT_ALL_OBJS_UNEXPORTED, NSI_S_INTERFACE_NOT_FOUND --*/ { RPC_STATUS raw_status; *status = NSI_S_OK; __try { myRpcLocator->nsi_mgmt_binding_unexport( EntryNameSyntax, EntryName, Interface, VersOption, ObjectVector ); } __except (EXCEPTION_EXECUTE_HANDLER) { switch (raw_status = GetExceptionCode()) { case NSI_S_UNSUPPORTED_NAME_SYNTAX: case NSI_S_INCOMPLETE_NAME: case NSI_S_OUT_OF_MEMORY: case NSI_S_ENTRY_NOT_FOUND: case NSI_S_NOTHING_TO_UNEXPORT: case NSI_S_ENTRY_TYPE_MISMATCH: case NSI_S_NOT_ALL_OBJS_UNEXPORTED: case NSI_S_INTERFACE_NOT_FOUND: case NSI_S_INVALID_VERS_OPTION: /* the following converts ULONG to UNSIGNED16 but that's OK for the actual values */ *status = (UNSIGNED16) raw_status; break; default: *status = NSI_S_INTERNAL_ERROR; } } } void nsi_binding_unexport( IN UNSIGNED32 EntryNameSyntax, IN STRING_T EntryName, IN NSI_INTERFACE_ID_T * Interface, IN NSI_UUID_VECTOR_P_T ObjectVector, OPT IN UNSIGNED16 * status ) /*++ Routine Description: unExport a information from a server entry.. Arguments: EntryNameSyntax - Name syntax EntryName - Name string of the entry to unexport Interface - Interface to unexport ObjectVector - Objects to remove from the entry status - Status is returned here Returned Status: See: nsi_mgmt_binding_unexport() --*/ { if (Interface && IsNilIfId(&(Interface->Interface))) Interface = NULL; nsi_mgmt_binding_unexport(EntryNameSyntax, EntryName, (Interface)? &Interface->Interface: NULL, RPC_C_VERS_EXACT, ObjectVector, status); } void nsi_binding_lookup_begin( IN UNSIGNED32 EntryNameSyntax, IN STRING_T EntryName, IN NSI_INTERFACE_ID_T * Interface, OPT IN NSI_UUID_P_T Object, OPT IN UNSIGNED32 VectorSize, IN UNSIGNED32 MaxCacheAge, OUT NSI_NS_HANDLE_T * InqContext, IN UNSIGNED16 * status ) /*++ Routine Description: Start a lookup operation. Just save all the input params in the newly created lookup context. Perform the initial query. Arguments: EntryNameSyntax - Name syntax EntryName - Name string to lookup on. Interface - Interface to search for Object - Object to search for VectorSize- Size of return vector MaxCacheAge - take seriously if nonzero -- always zero for old locator InqContext - Context to continue with for use with "Next" status - Status is returned here Returned Status: NSI_S_OK, NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_ENTRY_NOT_FOUND, NSI_OUT_OF_MEMORY --*/ { DBGOUT(API, "\nLookup Begin for Entry " << EntryName << "\n\n"); RPC_STATUS raw_status; *status = NSI_S_OK; __try { *InqContext = myRpcLocator->nsi_binding_lookup_begin( EntryNameSyntax, EntryName, Interface, OPT Object, OPT VectorSize, MaxCacheAge ); } __except (EXCEPTION_EXECUTE_HANDLER) { switch (raw_status = GetExceptionCode()) { case NSI_S_UNSUPPORTED_NAME_SYNTAX: case NSI_S_INCOMPLETE_NAME: case NSI_S_OUT_OF_MEMORY: case NSI_S_ENTRY_NOT_FOUND: case NSI_S_INVALID_OBJECT: case NSI_S_NAME_SERVICE_UNAVAILABLE: case NSI_S_NO_NS_PRIVILEGE: case NSI_S_ENTRY_TYPE_MISMATCH: /* the following converts ULONG to UNSIGNED16 but that's OK for the actual values */ *status = (UNSIGNED16) raw_status; break; case NSI_S_NO_MORE_BINDINGS: *status = NSI_S_ENTRY_NOT_FOUND; /* BUGBUG: This is all we really know, but the old locator did the above *status = NSI_S_OK; */ break; default: *status = NSI_S_INTERNAL_ERROR; } *InqContext = new CContextHandle; // i.e., a NULL handle } DBGOUT(API, "\nExiting Lookup Begin with Status " << *status << "\n\n"); } void nsi_binding_lookup_next( OUT NSI_NS_HANDLE_T InqContext, OUT NSI_BINDING_VECTOR_T ** BindingVectorOut, IN UNSIGNED16 * status ) /*++ Routine Description: Continue a lookup operation. Arguments: InqContext - Context to continue with. BindingVectorOut - Pointer to return new vector of bindings status - Status is returned here Returned Status: NSI_S_OK, NSI_OUT_OF_MEMORY, NSI_S_NO_MORE_BINDINGS, NSI_S_INVALID_NS_HANDLE --*/ { __try { CLookupHandle *pHandle = (CLookupHandle *) InqContext; *BindingVectorOut = pHandle->next(); } __except (EXCEPTION_EXECUTE_HANDLER) { *status = (UNSIGNED16) GetExceptionCode(); return; } if (!*BindingVectorOut) *status = NSI_S_NO_MORE_BINDINGS; else *status = NSI_S_OK; } void nsi_binding_lookup_done( IN OUT NSI_NS_HANDLE_T * pInqContext, IN UNSIGNED16 * pStatus ) /*++ Routine Description: Finish up a lookup operation. Arguments: InqContext - Context to close status - Status is returned here Returned Status: NSI_S_OK --*/ { NSI_NS_HANDLE_T_done(pInqContext,pStatus); } void nsi_mgmt_handle_set_exp_age( /* [in] */ NSI_NS_HANDLE_T inq_context, /* [in] */ UNSIGNED32 expiration_age, /* [out] */ UNSIGNED16 __RPC_FAR *status) /*++ Routine Description: Set cache tolerance (expiration) age for a specific NS handle. Arguments: InqContext - Context to set age for expiration_age - expiration age in seconds status - Status is returned here Returned Status: NSI_S_OK --*/ { CContextHandle *pHandle = (CContextHandle *) inq_context; *status = NSI_S_OK; if (pHandle) __try { pHandle->setExpiryAge(expiration_age); } __except (EXCEPTION_EXECUTE_HANDLER) { *status = (UNSIGNED16) GetExceptionCode(); } } void nsi_mgmt_inq_exp_age( /* [out] */ UNSIGNED32 __RPC_FAR *expiration_age, /* [out] */ UNSIGNED16 __RPC_FAR *status) /*++ Routine Description: Check the global cache tolerance (expiration) age. Arguments: expiration_age - expiration age in seconds returned here status - Status is returned here Returned Status: NSI_S_OK --*/ { *expiration_age = myRpcLocator->ulMaxCacheAge; *status = NSI_S_OK; } void nsi_mgmt_inq_set_age( /* [in] */ UNSIGNED32 expiration_age, /* [out] */ UNSIGNED16 __RPC_FAR *status) /*++ Routine Description: Set the global cache tolerance (expiration) age. Arguments: expiration_age - new global expiration age in seconds status - Status is returned here Returned Status: NSI_S_OK --*/ { /* No need for locks since the new value does not depend on the old and race conditions need not be dealt with -- the old value is as legitimate as the new */ myRpcLocator->ulMaxCacheAge = expiration_age; /* we also purge the broadcast history, if any, to reflect the new ulMaxCacheAge setting, with a phoney "clear broacast" request. */ QueryPacket NetRequest; myRpcLocator->broadcastCleared(NetRequest,myRpcLocator->ulMaxCacheAge); *status = NSI_S_OK; } void nsi_entry_object_inq_begin( /* [in] */ UNSIGNED32 EntryNameSyntax, /* [in] */ STRING_T EntryName, /* [out] */ NSI_NS_HANDLE_T __RPC_FAR *InqContext, /* [out] */ UNSIGNED16 __RPC_FAR *status) /*++ Routine Description: Perform an object inquiry, including all available information (owned, cached and from the network). Return a context handle for actual information. Arguments: EntryNameSyntax - Name syntax EntryName - Name string to lookup on InqContext - The NS context handle is returned here --*/ { DBGOUT(API, "\nLookup Begin for Entry " << EntryName << "\n\n"); RPC_STATUS raw_status; *status = NSI_S_OK; __try { *InqContext = myRpcLocator->nsi_entry_object_inq_begin( EntryNameSyntax, EntryName ); } __except (EXCEPTION_EXECUTE_HANDLER) { switch (raw_status = GetExceptionCode()) { case NSI_S_UNSUPPORTED_NAME_SYNTAX: case NSI_S_INCOMPLETE_NAME: case NSI_S_OUT_OF_MEMORY: case NSI_S_ENTRY_NOT_FOUND: case NSI_S_NAME_SERVICE_UNAVAILABLE: case NSI_S_NO_NS_PRIVILEGE: case NSI_S_ENTRY_TYPE_MISMATCH: *status = (UNSIGNED16) raw_status; break; default: *status = NSI_S_INTERNAL_ERROR; } *InqContext = new CContextHandle; // i.e., a NULL handle } DBGOUT(API, "\nExiting ObjectInq Begin with Status " << *status << "\n\n"); } void nsi_entry_object_inq_next( /* [in] */ NSI_NS_HANDLE_T InqContext, /* [out][in] */ NSI_UUID_P_T uuid, /* [out] */ UNSIGNED16 __RPC_FAR *status) /*++ Routine Description: Get the next object UUID from the given context handle. Arguments: InqContext - The NS context handle uuid - a pointer to the UUID is returned here Returned Status: NSI_S_OK, NSI_S_NO_MORE_MEMBERS --*/ { GUID * pgNextResult; __try { pgNextResult = ((CObjectInqHandle *) InqContext)->next(); } __except (EXCEPTION_EXECUTE_HANDLER) { *status = (UNSIGNED16) GetExceptionCode(); return; } if (!pgNextResult) *status = NSI_S_NO_MORE_MEMBERS; else { *status = NSI_S_OK; *uuid = *pgNextResult; } } void nsi_entry_object_inq_done( /* [out][in] */ NSI_NS_HANDLE_T __RPC_FAR *inq_context, /* [out] */ UNSIGNED16 __RPC_FAR *status) { NSI_NS_HANDLE_T_done(inq_context,status); } /********* Locator-to-Locator Server-side API implementations *********/ void I_nsi_lookup_begin( handle_t hrpcPrimaryLocatorHndl, UNSIGNED32 EntryNameSyntax, STRING_T EntryName, RPC_SYNTAX_IDENTIFIER * Interface, RPC_SYNTAX_IDENTIFIER * XferSyntax, NSI_UUID_P_T Object, UNSIGNED32 VectorSize, UNSIGNED32 maxCacheAge, // if nonzero, take it seriously NSI_NS_HANDLE_T *InqContext, UNSIGNED16 *status) /*++ Routine Description: Arguments: Returns: --*/ { NSI_INTERFACE_ID_T * InterfaceAndXfer = new NSI_INTERFACE_ID_T; if (Interface) InterfaceAndXfer->Interface = *Interface; else memset(&InterfaceAndXfer->Interface,0,sizeof(InterfaceAndXfer->Interface)); if (XferSyntax) InterfaceAndXfer->TransferSyntax = *XferSyntax; else memset(&InterfaceAndXfer->TransferSyntax,0,sizeof(InterfaceAndXfer->TransferSyntax)); nsi_binding_lookup_begin( EntryNameSyntax, EntryName, InterfaceAndXfer, Object, VectorSize, maxCacheAge, InqContext, status); delete InterfaceAndXfer; /* here we are using a formerly unused parameter to avoid sending outdated info from the master. this is only a partial solution but better than nothing */ if ((*status == NSI_S_OK) && (maxCacheAge != 0)) nsi_mgmt_handle_set_exp_age( *InqContext, maxCacheAge, status ); } void I_nsi_lookup_done( handle_t hrpcPrimaryLocatorHndl, NSI_NS_HANDLE_T *InqContext, UNSIGNED16 *status) /*++ Routine Description: Arguments: Returns: --*/ { nsi_binding_lookup_done(InqContext, status); } void I_nsi_lookup_next( handle_t hrpcPrimaryLocatorHndl, NSI_NS_HANDLE_T InqContext, NSI_BINDING_VECTOR_P_T *BindingVectorOut, UNSIGNED16 *status) /*++ Routine Description: Arguments: Returns: --*/ { nsi_binding_lookup_next( InqContext, BindingVectorOut, status); if (*BindingVectorOut) StripObjectsFrom(BindingVectorOut); } void I_nsi_entry_object_inq_next( IN handle_t hrpcPrimaryLocatorHndl, IN NSI_NS_HANDLE_T InqContext, OUT NSI_UUID_VECTOR_P_T *uuid_vector, OUT UNSIGNED16 *status ) /*++ Routine Description: Continue an inquiry for objects in an entry. Arguments: InqContext - Context to continue with uuid - pointer to return object in. status - Status is returned here Returns: NSI_S_OK, NSI_S_NO_MORE_MEMBERS --*/ { __try { *uuid_vector = getVector((CObjectInqHandle *) InqContext); } __except (EXCEPTION_EXECUTE_HANDLER) { *status = (UNSIGNED16) GetExceptionCode(); return; } *status = NSI_S_OK; } void I_nsi_ping_locator( handle_t h, error_status_t * Status ) { if (h); *Status = 0; } void I_nsi_entry_object_inq_begin( handle_t hrpcPrimaryHandle, IN UNSIGNED32 EntryNameSyntax, IN STRING_T EntryName, OUT NSI_NS_HANDLE_T *InqContext, OUT UNSIGNED16 *status ) /*++ Routine Description: Start a inquiry for objects in an entry. Arguments: EntryNameSyntax - Name syntax EntryName - Name of the entry to find objects in InqContext - Context to continue with for use with "Next" status - Status is returned here Returns: NSI_S_OK, NSI_S_UNSUPPORTED_NAME_SYNTAX, NSI_S_INCOMPLETE_NAME, NSI_OUT_OF_MEMORY --*/ { nsi_entry_object_inq_begin( EntryNameSyntax, EntryName, InqContext, status ); } void I_nsi_entry_object_inq_done( IN OUT NSI_NS_HANDLE_T *pInqContext, OUT UNSIGNED16 *pStatus ) /*++ Routine Description: Finish an inquiry on a object. Arguments: InqContext - Context to close status - Status is returned here --*/ { NSI_NS_HANDLE_T_done(pInqContext,pStatus); } } // extern "C"