#include "core.hxx" #include "locquery.h" #include "locclass.hxx" #include "mailslot.hxx" #define PIPENAME ( (unsigned short *)L"\\PIPE\\LOCATOR" ) #define PROTSEQ ( (unsigned short *)L"ncacn_np" ) extern "C" { void CLIENT_I_nsi_ping_locator( handle_t hLocatortoPing, error_status_t *status); } /* Class __LOCATOR */ extern NATIVE_CLASS_LOCATOR *Locator; handle_t NATIVE_CLASS_LOCATOR::GetBindingToMasterLocator( int * Status) { if ( Status ) ; ASSERT(!"should never be triggered"); return((handle_t)0); } void NATIVE_CLASS_LOCATOR::CacheThisServer( PUZ ServerName) { //we really dont do much in the default case } /* void NATIVE_CLASS_LOCATOR::SetupHelperRoutine( ) { ASSERT(!"should never be triggered"); } */ /* void NATIVE_CLASS_LOCATOR::DestroyBindingToMasterLocator() { ASSERT(!"should never be triggered"); } */ void NATIVE_CLASS_LOCATOR::SetIamMasterLocator() { IamMasterLocatorFlag = TRUE; } handle_t NATIVE_CLASS_LOCATOR::GetBindingToNamedLocator( unsigned short * Server, int * Status ) { RPC_BINDING_HANDLE hNewHandle = NULL; unsigned short * StringBindingW = 0; *Status = RpcStringBindingComposeW( 0, PROTSEQ, (unsigned short *)Server, PIPENAME, 0, &StringBindingW ); if (*Status == RPC_S_OK) { *Status = RpcBindingFromStringBindingW( StringBindingW, &hNewHandle ); } if (*Status == RPC_S_OK) { CLIENT_I_nsi_ping_locator( hNewHandle, (error_status_t *)Status ); } if (*Status == RPC_S_OK) { //Now Update The DataStructure and Mark The State Etc DataStructureMutex.Request(); if (State == BOUND) { //oops someone already bound to something while we getDCing //lets try and use the same thing *Status = RpcBindingFree(&hNewHandle); RpcStringFreeW(&StringBindingW); ASSERT(*Status == RPC_S_OK); } else { State = BOUND; MasterLocatorStringBinding = StringBindingW; MasterLocator = StrdupUZ((PUZ)Server); } DataStructureMutex.Clear(); } return((handle_t) hNewHandle); } BOOL NATIVE_CLASS_LOCATOR::IsReplyNeeded( PQUERYLOCATOR Query) { switch (Query->MessageType) { case QUERY_MASTER_LOCATOR: return (Locator->InqIfIamMasterLocator()); case QUERY_ANY_LOCATOR: return(TRUE); case QUERY_DC_LOCATOR: return((SysType == ROLE_LMNT_BACKUPDC) || (SysType == ROLE_LMNT_PDC)); case QUERY_BOUND_LOCATOR: return((State == BOUND) || (Locator->InqIfIamMasterLocator())); default: DLIST(3, "Bogus Query MsgType=" << Query->MessageType << nl); }; return (FALSE); } handle_t DOMAIN_MACHINE_LOCATOR::GetBindingToMasterLocator( int * RetStatus) { /* Routine Description: Returns a binding handle to the master locator. Returns RPC_S_SERVER_UNAVAILABLE if master is unavailable */ handle_t hNewHandle = 0; unsigned long IState; LPBYTE ServerNameBuffer = 0; LPBYTE Buffer = 0; DWORD ReturnedEntries, TotalEntries; LPSERVER_INFO_100 LPServerInfo; UICHAR UZServerName[UNCLEN+1]; DataStructureMutex.Request(); if ((IState = State) == BOUND) { *RetStatus = RpcBindingFromStringBindingW( MasterLocatorStringBinding, &hNewHandle ); } DataStructureMutex.Clear(); if (IState == BOUND) { ASSERT(*RetStatus == RPC_S_OK); return(hNewHandle); } //Now try Locators on PDC and then BDCs *RetStatus = NetGetDCName( 0, 0, &ServerNameBuffer ); if (*RetStatus == NERR_Success) { DLIST(3, "PDC=> " << (PUZ) ServerNameBuffer << nl); hNewHandle = GetBindingToNamedLocator ( (unsigned short *) ServerNameBuffer, (int *)RetStatus ); if (*RetStatus == RPC_S_OK) { IState = BOUND; } } if (ServerNameBuffer != 0) { NetApiBufferFree(ServerNameBuffer); } if (IState == BOUND) { ASSERT(*RetStatus == RPC_S_OK); return(hNewHandle); } //If we are here we need to try all the BDCs. *RetStatus = NetServerEnum( 0, 100, &Buffer, 0xffffffff, &ReturnedEntries, &TotalEntries, SV_TYPE_DOMAIN_BAKCTRL, 0, 0 ); if (*RetStatus != NERR_Success) { goto Cleanup; } LPServerInfo = (LPSERVER_INFO_100)Buffer; while (ReturnedEntries != 0) { ServerNameBuffer = (LPBYTE)LPServerInfo->sv100_name; UZServerName[0] = '\\'; UZServerName[1] = '\\'; UZServerName[2] = 0; CatUZ(UZServerName, (PUZ)ServerNameBuffer); DLIST(3, "now trying BDC [" << UZServerName << "] \n"); hNewHandle = GetBindingToNamedLocator ( (unsigned short *) UZServerName, (int *)RetStatus ); if (*RetStatus == RPC_S_OK) break; LPServerInfo++; ReturnedEntries--; } Cleanup: if (Buffer != NULL) NetApiBufferFree(Buffer); if (*RetStatus != RPC_S_OK) *RetStatus = RPC_S_SERVER_UNAVAILABLE; return(hNewHandle); } void WRKGRP_MACHINE_LOCATOR::TryBroadcastingForMasterLocator( ) { QUERYLOCATOR Query; STATUS Status; int MailStatus; WRITE_MAIL_SLOT BSResponder(RESPONDERMSLOT_S, DomainName, &Status); if (Status != NSI_S_OK) { //Log it but ignore it DLIST(3, "Attempted Broadcast Failure Err=" << Status << nl); return; } Query.SenderOsType = OS_NTWKGRP; Query.MessageType = QUERY_MASTER_LOCATOR; Query.RequesterName[0] = 0; CatUZ(Query.RequesterName, SelfName); MailStatus = BSResponder.Write((PB) &Query, sizeof(Query)); if (MailStatus != 0) { //Log it, but not much else we can do DLIST(3, "Attempted Write to BroadcastMS Err=" << Status << nl); return; } } handle_t WRKGRP_MACHINE_LOCATOR::GetBindingToMasterLocator( int * RetStatus) { /* Routine Description: Returns a binding handle to the master locator. Returns RPC_S_SERVER_UNAVAILABLE if master is unavailable */ handle_t hNewHandle; unsigned long IState; UICHAR ServerName[UNCLEN+1]; PCACHEDNODE pNode; BOOL TriedBroadcasting = FALSE; DataStructureMutex.Request(); if ((IState = State) == BOUND) { *RetStatus = RpcBindingFromStringBindingW( MasterLocatorStringBinding, &hNewHandle ); } DataStructureMutex.Clear(); if (IState == BOUND) { ASSERT(*RetStatus == RPC_S_OK); return(hNewHandle); } //Now try all the cached locators, one after the other! while (1) { DataStructureMutex.Request(); if (Head == NULL) { if (TriedBroadcasting == FALSE) { TryBroadcastingForMasterLocator(); TriedBroadcasting = TRUE; DataStructureMutex.Clear(); continue; } *RetStatus = RPC_S_SERVER_UNAVAILABLE; DataStructureMutex.Clear(); break; } ServerName[0] = NIL; CatUZ((PUZ)ServerName, (PUZ)Head->ServerName); DataStructureMutex.Clear(); hNewHandle = GetBindingToNamedLocator ( (unsigned short *) ServerName, (int *)RetStatus ); if (*RetStatus == RPC_S_OK) { return(hNewHandle); } else { DataStructureMutex.Request(); pNode = FindCachedEntry(ServerName); pNode = DeleteCachedEntry(pNode); delete pNode; DataStructureMutex.Clear(); } } } void NATIVE_CLASS_LOCATOR::DestroyBindingToMasterLocator() { DataStructureMutex.Request(); State = UNBOUND; if (MasterLocator != 0) { delete MasterLocator; } if (MasterLocatorStringBinding != 0) { RpcStringFreeW(&MasterLocatorStringBinding); } MasterLocatorStringBinding = 0; DataStructureMutex.Clear(); } void NATIVE_CLASS_LOCATOR::ProcessMessage( PQUERYLOCATOR Query, int * Status ) { QUERYLOCATORREPLY Reply; int MailStatus; STATUS Err; *Status = NSI_S_OK; if (IsReplyNeeded(Query) == FALSE) return; //Copy SelfName Reply.SenderName[0] = Nil; CatUZ(Reply.SenderName, SelfName); Reply.Uptime = CurrentTimeMS() - LocatorStartTime; if (((InqIfIamMasterLocator() == TRUE)) || (SysType == ROLE_LMNT_PDC)) { Reply.Hint = REPLY_MASTER_LOCATOR; } else if (State == BOUND) { Reply.Hint = REPLY_BOUND_LOCATOR; } else { Reply.Hint = ((SysType == ROLE_LMNT_BACKUPDC) ? REPLY_DC_LOCATOR : REPLY_OTHER_LOCATOR); } //Now form the return Mailslot name // UICHAR ReplyMSName[sizeof(RESPONDERMSLOT_C) + sizeof(Query->RequesterName)]; ReplyMSName[0] = '\\'; ReplyMSName[1] = '\\'; ReplyMSName[2] = Nil; CatUZ(CatUZ(ReplyMSName, Query->RequesterName), RESPONDERMSLOT_C); WRITE_MAIL_SLOT MSReply(ReplyMSName, NIL, &Err); if (Err != NSI_S_OK) { DLIST( 3, "Error (" << *Status << ") creating a MSlot" << nl); return; } MailStatus = MSReply.Write((char *) &Reply, sizeof(Reply)); if (MailStatus) { DLIST( 3, "Error (" << *Status << ") writting to MSlot" << nl); return; } } void DomainLocatorResponder( ) /*++ Routine Description: Each Locator has an additional thread that creates a mailslot This thread replies to queries that seek to find the master locator. This particular Responder runs on Domain locators only --*/ { int Status; int MailStatus; int LongStatus; unsigned short LookupStatus; QUERYLOCATOR Query; QUERYLOCATORREPLY Reply; int cbBytesRead; READ_MAIL_SLOT hMSRead(RESPONDERMSLOT_S, sizeof(QUERYLOCATOR), &Status); DLIST(2, "starting LocatorSearchResponder Thread..\n"); if (Status != NSI_S_OK) { AbortServer("Error in new mailslot", Status); } Reply.SenderName[0] = NIL; CatUZ(Reply.SenderName, SelfName); while (1) { ASSERT(AssertHeap()); MailStatus = hMSRead.Read((PB) &Query, cbBytesRead); if (MailStatus) AbortServer("Mailslot read error", MailStatus); if (!CmpUZ(Query.RequesterName, SelfName)) continue; DLIST(3, Query.RequesterName << " did query for locator" << nl); if (cbBytesRead != sizeof(QUERYLOCATOR)) { DLIST(3, "Bummer, Bad Message of size(" << cbBytesRead << ") recvd" << nl); continue; } Locator->ProcessMessage(&Query, &LongStatus); } } void NATIVE_CLASS_LOCATOR::SetupHelperRoutine( ) { void * pThreadHandle; DWORD ThreadId; pThreadHandle = CreateThread( 0, 0, (LPTHREAD_START_ROUTINE)DomainLocatorResponder, 0, 0, &ThreadId ); } PCACHEDNODE WRKGRP_MACHINE_LOCATOR::FindCachedEntry(PUZ ServerName) { PCACHEDNODE pNode; for(pNode = Head; pNode; pNode = pNode->Next) { if ( CmpUZ(pNode->ServerName, (PUZ)ServerName) == 0 ) { break; } } return(pNode); } void WRKGRP_MACHINE_LOCATOR::InsertCacheEntry(PCACHEDNODE pNode) { if (Tail == NULL) { ASSERT(Head == NULL); Tail = pNode; } pNode->Previous = 0; pNode->Next = Head; if (Head != NULL) Head->Previous = pNode; Head = pNode; CacheSize ++; } PCACHEDNODE WRKGRP_MACHINE_LOCATOR::DeleteCachedEntry(PCACHEDNODE pNode) { if (pNode == NULL) return((PCACHEDNODE)NULL); if (Head == pNode) Head = pNode->Next; if (Tail == pNode) Tail = pNode->Previous; if (pNode->Next != NULL) pNode->Next->Previous = pNode->Previous; if (pNode->Previous != NULL) pNode->Previous->Next = pNode->Next; CacheSize--; return(pNode); } void WRKGRP_MACHINE_LOCATOR::CacheThisServer(PUZ ServerName) { register PCACHEDNODE pNode; DataStructureMutex.Request(); pNode = FindCachedEntry(ServerName); if (pNode == NULL) { pNode = new CACHEDNODE; pNode->Next = pNode->Previous = 0; pNode->ServerName[0] = NIL; CatUZ(pNode->ServerName, (PUZ)ServerName); if (CacheSize == CACHESIZE) DeleteCachedEntry(Tail); InsertCacheEntry(pNode); } else { if (pNode != Head) { pNode = DeleteCachedEntry(pNode); InsertCacheEntry(pNode); } } DataStructureMutex.Clear(); }