|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
bowelect.c
Abstract:
This module implements all of the election related routines for the NT browser
Author:
Larry Osterman (LarryO) 21-Jun-1990
Revision History:
21-Jun-1990 LarryO
Created
--*/
#include "precomp.h"
#pragma hdrstop
#define INCLUDE_SMB_TRANSACTION
NTSTATUS BowserStartElection( IN PTRANSPORT Transport );
LONG BowserSetElectionCriteria( IN PPAGED_TRANSPORT Transport );
NTSTATUS BowserElectMaster( IN PTRANSPORT Transport );
VOID HandleElectionWorker( IN PVOID Ctx );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, GetMasterName)
#pragma alloc_text(PAGE, HandleElectionWorker)
#pragma alloc_text(PAGE, BowserSetElectionCriteria)
#pragma alloc_text(PAGE, BowserStartElection)
#pragma alloc_text(PAGE, BowserElectMaster)
#pragma alloc_text(PAGE, BowserLoseElection)
#pragma alloc_text(PAGE, BowserFindMaster)
#pragma alloc_text(PAGE, BowserSendElection)
#endif
NTSTATUS GetMasterName ( IN PIRP Irp, IN BOOLEAN Wait, IN BOOLEAN InFsd, IN PLMDR_REQUEST_PACKET InputBuffer, IN ULONG InputBufferLength ) { NTSTATUS Status; PTRANSPORT Transport = NULL; PPAGED_TRANSPORT PagedTransport; PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
PAGED_CODE();
try { WCHAR TransportNameBuffer[MAX_PATH+1]; WCHAR DomainNameBuffer[DNLEN+1];
if (IrpSp->Parameters.DeviceIoControl.OutputBufferLength < (ULONG)FIELD_OFFSET(LMDR_REQUEST_PACKET, Parameters.GetMasterName.Name)+3*sizeof(WCHAR)) { try_return(Status = STATUS_INVALID_PARAMETER); }
if (InputBufferLength < sizeof(LMDR_REQUEST_PACKET)) { try_return(Status = STATUS_INVALID_PARAMETER); }
CAPTURE_UNICODE_STRING( &InputBuffer->TransportName, TransportNameBuffer ); CAPTURE_UNICODE_STRING( &InputBuffer->EmulatedDomainName, DomainNameBuffer ); Transport = BowserFindTransport(&InputBuffer->TransportName, &InputBuffer->EmulatedDomainName ); dprintf(DPRT_REF, ("Called Find transport %lx from GetMasterName.\n", Transport));
if (Transport == NULL) { try_return (Status = STATUS_OBJECT_NAME_NOT_FOUND); }
PagedTransport = Transport->PagedTransport;
dlog(DPRT_FSCTL, ("%s: %ws: NtDeviceIoControlFile: GetMasterName\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer ));
PagedTransport->ElectionCount = ELECTION_COUNT;
Status = BowserQueueNonBufferRequest(Irp, &Transport->FindMasterQueue, BowserCancelQueuedRequest ); if (!NT_SUCCESS(Status)) { try_return(Status); }
Status = BowserFindMaster(Transport);
//
// If we couldn't initiate the find master process, complete all the
// queued find master requests.
//
if (!NT_SUCCESS(Status)) { BowserCompleteFindMasterRequests(Transport, &PagedTransport->MasterName, Status); }
//
// Since we marked the IRP as pending, we need to return pending
// now.
//
try_return(Status = STATUS_PENDING);
try_exit:NOTHING; } finally { if ( Transport != NULL ) { BowserDereferenceTransport(Transport); } }
return(Status);
UNREFERENCED_PARAMETER(Wait); UNREFERENCED_PARAMETER(InFsd);
}
DATAGRAM_HANDLER(BowserHandleElection) { // PTA_NETBIOS_ADDRESS Address = SourceAddress;
return BowserPostDatagramToWorkerThread( TransportName, Buffer, BytesAvailable, BytesTaken, SourceAddress, SourceAddressLength, SourceName, SourceNameLength, HandleElectionWorker, NonPagedPool, CriticalWorkQueue, ReceiveFlags, FALSE // Response will be sent, but...
);
}
VOID HandleElectionWorker( IN PVOID Ctx ) { PPOST_DATAGRAM_CONTEXT Context = Ctx; PTRANSPORT_NAME TransportName = Context->TransportName; PREQUEST_ELECTION_1 ElectionResponse = Context->Buffer; ULONG BytesAvailable = Context->BytesAvailable; ULONG TimeUp; BOOLEAN Winner; PTRANSPORT Transport = TransportName->Transport; NTSTATUS Status; LONG ElectionDelay, NextElection; OEM_STRING ClientNameO; UNICODE_STRING ClientName; PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
PAGED_CODE();
LOCK_TRANSPORT(Transport);
ClientName.Buffer = NULL;
try {
//
// If this packet was smaller than a minimal packet,
// ignore the packet.
//
if (BytesAvailable <= FIELD_OFFSET(REQUEST_ELECTION_1, ServerName)) { try_return(NOTHING); }
//
// If the packet doesn't have a zero terminated ServerName,
// ignore the packet.
//
if ( !IsZeroTerminated( ElectionResponse->ServerName, BytesAvailable - FIELD_OFFSET(REQUEST_ELECTION_1, ServerName) ) ) { try_return(NOTHING); }
BowserStatistics.NumberOfElectionPackets += 1;
//
// Remember the last time we heard an election packet.
//
PagedTransport->LastElectionSeen = BowserTimeUp();
if (Transport->ElectionState == DeafToElections) { try_return(NOTHING); }
//
// If we've disable the transport for any reason,
// then we disregard all elections.
//
if (PagedTransport->DisabledTransport) { try_return(NOTHING); }
//
// Convert the client name in the election packet to unicode so we can
// log it.
//
RtlInitString(&ClientNameO, ElectionResponse->ServerName);
Status = RtlOemStringToUnicodeString(&ClientName, &ClientNameO, TRUE);
if (!NT_SUCCESS(Status)) { BowserLogIllegalName( Status, ClientNameO.Buffer, ClientNameO.Length );
try_return(NOTHING); }
if (BowserLogElectionPackets) { BowserWriteErrorLogEntry(EVENT_BOWSER_ELECTION_RECEIVED, STATUS_SUCCESS, ElectionResponse, (USHORT)BytesAvailable, 2, ClientName.Buffer, PagedTransport->TransportName.Buffer); }
dlog(DPRT_ELECT, ("%s: %ws: Received election packet from machine %s. Version: %lx; Criteria: %lx; TimeUp: %lx\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer, ElectionResponse->ServerName, ElectionResponse->Version, SmbGetUlong(&ElectionResponse->Criteria), SmbGetUlong(&ElectionResponse->TimeUp)));
//
// Figure out our time up for the election compare.
//
// If we're running an election, we'll use our advertised time, else
// we'll use our actual uptime. Also, if we're running an election
// we'll check to see if we sent this. If we're not running an election
// and we receive this, it's because the redirector didn't find a
// master, so we want to continue the election and become master.
//
if (Transport->ElectionState == RunningElection) { if (!strcmp(Transport->DomainInfo->DomOemComputerNameBuffer, ElectionResponse->ServerName)) { try_return(NOTHING); }
//
// If this request was initiated from a client, ignore it.
//
if ((SmbGetUlong(&ElectionResponse->Criteria) == 0) && (ElectionResponse->ServerName[0] == '\0')) { dlog(DPRT_ELECT, ("%s: %ws: Dummy election request ignored during election.\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer )); try_return(NOTHING); }
if (PagedTransport->Role == Master) { ElectionDelay = BowserRandom(MASTER_ELECTION_DELAY); } else { ElectionDelay = ELECTION_RESPONSE_MIN + BowserRandom(ELECTION_RESPONSE_MAX-ELECTION_RESPONSE_MIN); }
} else {
//
// Starting a new election - set various election criteria
// including Uptime.
//
ElectionDelay = BowserSetElectionCriteria(PagedTransport);
}
TimeUp = PagedTransport->Uptime;
if (ElectionResponse->Version != BROWSER_ELECTION_VERSION) { Winner = (ElectionResponse->Version < BROWSER_ELECTION_VERSION); } else if (SmbGetUlong(&ElectionResponse->Criteria) != PagedTransport->ElectionCriteria) { Winner = (SmbGetUlong(&ElectionResponse->Criteria) < PagedTransport->ElectionCriteria); } else if (TimeUp != SmbGetUlong(&ElectionResponse->TimeUp)) { Winner = TimeUp > SmbGetUlong(&ElectionResponse->TimeUp); } else { Winner = (strcmp(Transport->DomainInfo->DomOemDomainName, ElectionResponse->ServerName) <= 0); }
//
// If we lost, we stop our timer and turn off our election flag, just
// in case we had an election or find master going. If we're a backup,
// we want to find out who the new master is, either from this election
// frame or waiting awhile and querying.
//
if (!Winner) {
//
// Remember if we legitimately lost the last election, and if
// so, don't force an election if we see server announcements
// from a non DC, just give up.
//
PagedTransport->Flags |= ELECT_LOST_LAST_ELECTION; }
if (!Winner || (PagedTransport->ElectionsSent > ELECTION_MAX)) {
if (PagedTransport->IsPrimaryDomainController) {
DWORD ElectionInformation[6];
ElectionInformation[0] = ElectionResponse->Version; ElectionInformation[1] = SmbGetUlong(&ElectionResponse->Criteria); ElectionInformation[2] = SmbGetUlong(&ElectionResponse->TimeUp); ElectionInformation[3] = BROWSER_ELECTION_VERSION; ElectionInformation[4] = PagedTransport->ElectionCriteria; ElectionInformation[5] = TimeUp;
//
// Write this information into the event log.
//
BowserWriteErrorLogEntry(EVENT_BOWSER_PDC_LOST_ELECTION, STATUS_SUCCESS, ElectionInformation, sizeof(ElectionInformation), 2, ClientName.Buffer, PagedTransport->TransportName.Buffer);
KdPrint(("HandleElectionWorker: Lose election, but we're the PDC. Winner: Version: %lx; Criteria: %lx; Time Up: %lx; Name: %s\n", ElectionResponse->Version, SmbGetUlong(&ElectionResponse->Criteria), SmbGetUlong(&ElectionResponse->TimeUp), ElectionResponse->ServerName));
}
BowserLoseElection(Transport);
} else { //
// We won this election, make sure that we don't think that we
// lost it.
//
PagedTransport->Flags &= ~ELECT_LOST_LAST_ELECTION;
//
// If we won and we're not running an election, we'll start one.
// If we are running, we don't do anything because our timer will
// take care of it. If the NET_ELECTION flag is clear, we know
// timeup is approx. equal to time_up() because we set it above,
// so we'll use that. This algorithm includes a damping constant
// (we won't start an election if we've just lost one in the
// last 1.5 seconds) to avoid election storms.
//
if (Transport->ElectionState != RunningElection) {
//
// If we recently lost an election, then ignore the fact
// that we won, and pretend we lost this one.
//
if ((PagedTransport->TimeLastLost != 0) && ((BowserTimeUp() - PagedTransport->TimeLastLost) < ELECTION_EXEMPT_TIME)) {
dlog(DPRT_ELECT, ("%s: %ws: Browser is exempt from election\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer ));
try_return(NOTHING); }
dlog(DPRT_ELECT, ("%s: %ws: Better criteria, calling elect_master in %ld milliseconds.\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer, ElectionDelay));
//
// Ensure the timer is running.
// We don't actually win the election until the timer expires.
//
Transport->ElectionState = RunningElection;
PagedTransport->NextElection = 0; }
PagedTransport->ElectionCount = ELECTION_COUNT;
//
// Note: the next elect time must be computed into a signed
// integer in case the expiration time has already passed so
// don't try to optimize this code too much.
//
NextElection = PagedTransport->NextElection - (TimeUp - BowserTimeUp());
if ((PagedTransport->NextElection == 0) || NextElection > ElectionDelay) { BowserStopTimer(&Transport->ElectionTimer);
PagedTransport->NextElection = TimeUp + ElectionDelay;
dlog(DPRT_ELECT, ("%s: %ws: Calling ElectMaster in %ld milliseconds\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer, ElectionDelay));
BowserStartTimer(&Transport->ElectionTimer, ElectionDelay, BowserElectMaster, Transport); } }
try_exit:NOTHING; } finally {
UNLOCK_TRANSPORT(Transport);
InterlockedDecrement( &BowserPostedCriticalDatagramCount ); FREE_POOL(Context);
if (ClientName.Buffer != NULL) { RtlFreeUnicodeString(&ClientName); }
BowserDereferenceTransportName(TransportName); BowserDereferenceTransport(Transport); }
return;
}
LONG BowserSetElectionCriteria( IN PPAGED_TRANSPORT PagedTransport )
/*++
Routine Description: Set election criteria for a network.
Prepare for an election by setting Transport->ElectionCriteria based upon the local browser state. Set Transport->Uptime to the current local up time.
Arguments: Transport - The transport for the net we're on.
Return Value Number of milliseconds to delay before sending the election packet.
--*/ { LONG Delay;
PAGED_CODE();
PagedTransport->ElectionsSent = 0; // clear bid counter
PagedTransport->Uptime = BowserTimeUp();
if (BowserData.IsLanmanNt) { PagedTransport->ElectionCriteria = ELECTION_CR_LM_NT; } else { PagedTransport->ElectionCriteria = ELECTION_CR_WIN_NT; }
PagedTransport->ElectionCriteria |= ELECTION_MAKE_REV(BROWSER_VERSION_MAJOR, BROWSER_VERSION_MINOR);
if (BowserData.MaintainServerList && ((PagedTransport->NumberOfServersInTable + RtlNumberGenericTableElements(&PagedTransport->AnnouncementTable)+ RtlNumberGenericTableElements(&PagedTransport->DomainTable)) != 0)) { PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_CFG_BKP; }
if (PagedTransport->IsPrimaryDomainController) { PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_PDC; PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_DOMMSTR; }
#ifdef ENABLE_PSEUDO_BROWSER
if (BowserData.PseudoServerLevel == BROWSER_PSEUDO || BowserData.PseudoServerLevel == BROWSER_SEMI_PSEUDO_NO_DMB ) { // Pseudo or Semi-Pseudo will win elections over peers
// & in case of semi-pseudo except no DMB communications
// all other functionality will remain on.
PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_PSEUDO; } #endif
if (PagedTransport->Role == Master) { PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_MASTER;
Delay = MASTER_ELECTION_DELAY;
} else if (PagedTransport->IsPrimaryDomainController) {
//
// If we are the PDC, we want to set our timeouts
// as if we were already the master.
//
// This prevents us from getting into a situation where it takes
// more than ELECTION_DELAY_MAX to actually send out our response
// to an election.
//
Delay = MASTER_ELECTION_DELAY;
} else if ((PagedTransport->Role == Backup) || BowserData.IsLanmanNt) { //
// Likewise, if we are NTAS machines, we want to set out delay
// to match that of backup browsers (even if we're not a backup
// quite yet).
//
PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_BACKUP; Delay = BACKUP_ELECTION_DELAY_MIN + BowserRandom(BACKUP_ELECTION_DELAY_MAX-BACKUP_ELECTION_DELAY_MIN);
} else { Delay = ELECTION_DELAY_MIN + BowserRandom(ELECTION_DELAY_MAX-ELECTION_DELAY_MIN); }
//
// Assume for now that all wannish transports are running the WINS client.
//
if ( PagedTransport->Wannish ) { PagedTransport->ElectionCriteria |= ELECTION_DESIRE_WINS_CLIENT; }
return Delay; }
NTSTATUS BowserStartElection( IN PTRANSPORT Transport ) /*++
Routine Description: Initiate a browser election
This routine is called when we are unable to find a master, and we want to elect one.
Arguments: Transport - The transport for the net we're on.
Return Value None.
--*/ { NTSTATUS Status = STATUS_SUCCESS; PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport; PAGED_CODE();
LOCK_TRANSPORT(Transport);
try {
//
// If we've disable the transport for any reason,
// then we disregard all elections.
//
if (PagedTransport->DisabledTransport) { try_return(Status = STATUS_UNSUCCESSFUL); }
//
// If we're deaf to elections, or aren't any kind of
// browser then we can't start elections either.
//
if (Transport->ElectionState == DeafToElections || PagedTransport->Role == None) { try_return(Status = STATUS_UNSUCCESSFUL); }
PagedTransport->ElectionCount = ELECTION_COUNT;
Transport->ElectionState = RunningElection;
BowserSetElectionCriteria(PagedTransport);
Status = BowserElectMaster(Transport); try_exit:NOTHING; } finally { UNLOCK_TRANSPORT(Transport);
}
return Status; }
NTSTATUS BowserElectMaster( IN PTRANSPORT Transport ) /*++
Routine Description: Elect a master browser server.
This routine is called when we think there is no master and we need to elect one. We check our retry count, and if it's non-zero we send an elect datagram to the group name. Otherwise we become the master ourselves.
Arguments: Transport - The transport for the net we're on.
Return Value None.
--*/ { NTSTATUS Status; PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport; PAGED_CODE();
LOCK_TRANSPORT(Transport);
try {
//
// If we're not running the election at this time, it means that
// between the time that we decided we were going to win the election
// and now, someone else announced with better criteria. It is
// possible that this could happen if the announcement came in just
// before we ran (ie. if the announcement occured between when the
// timer DPC was queued and when the DPC actually fired).
//
if (Transport->ElectionState != RunningElection) {
KdPrint(("BowserElectMaster: Lose election because we are no longer running the election\n"));
BowserLoseElection(Transport);
} else if (PagedTransport->ElectionCount != 0) {
BowserStopTimer(&Transport->ElectionTimer);
PagedTransport->ElectionCount -= 1;
PagedTransport->ElectionsSent += 1;
PagedTransport->NextElection = BowserTimeUp() + ELECTION_RESEND_DELAY;
Status = BowserSendElection(&Transport->DomainInfo->DomUnicodeDomainName, BrowserElection, Transport, TRUE);
// Lose the election if we can't send a datagram.
if (!NT_SUCCESS(Status)) { BowserLoseElection(Transport); try_return(Status); }
//
// If we were able to send the election,
// start the timer running.
//
BowserStartTimer(&Transport->ElectionTimer, ELECTION_RESEND_DELAY, BowserElectMaster, Transport);
} else { Transport->ElectionState = Idle;
//
// If we're already the master we just return. This can happen if
// somebody starts an election (which we win) while we're already
// the master.
//
if (PagedTransport->Role != Master) {
//
// We're the new master - we won!
//
BowserNewMaster(Transport, Transport->DomainInfo->DomOemComputerNameBuffer );
} else {
//
// Were already the master. Make sure that all the backups
// know this by sending an announcent
//
//
// This one's easy - simply set the servers announcement event to the
// signalled state. If the server is running, this will force an
// announcement
//
KeSetEvent(BowserServerAnnouncementEvent, IO_NETWORK_INCREMENT, FALSE); } }
try_return(Status = STATUS_SUCCESS);
try_exit:NOTHING; } finally { UNLOCK_TRANSPORT(Transport); }
return Status; }
VOID BowserLoseElection( IN PTRANSPORT Transport ) { PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport; PAGED_CODE();
LOCK_TRANSPORT(Transport);
BowserStopTimer(&Transport->ElectionTimer);
dlog(DPRT_ELECT, ("We lost the election\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer ));
PagedTransport->TimeLastLost = BowserTimeUp();
//
// We lost the election - we re-enter the idle state.
//
Transport->ElectionState = Idle;
if (PagedTransport->Role == Master) {
//
// If we lost, and we are currently a master, then tickle
// the browser service and stop being a master.
//
BowserResetStateForTransport(Transport, RESET_STATE_STOP_MASTER);
//
// Remove all the entries on the server list for this
// transport.
//
LOCK_ANNOUNCE_DATABASE(Transport);
//
// Flag that there should be no more announcements received on
// this name.
//
BowserForEachTransportName(Transport, BowserStopProcessingAnnouncements, NULL);
// KdPrint(("Deleting entire table on transport %wZ because we lost the election\n", &Transport->TransportName));
BowserDeleteGenericTable(&PagedTransport->AnnouncementTable);
BowserDeleteGenericTable(&PagedTransport->DomainTable);
UNLOCK_ANNOUNCE_DATABASE(Transport);
#if 0
} else if (Transport->Role == Backup) { // If we're a backup, find master
dlog(DPRT_ELECT, ("We're a backup - Find the new master\n"));
//
// If this guy is not the master, then we want to
// find a master at some later time.
//
Transport->ElectionCount = FIND_MASTER_COUNT; Transport->Uptime = Transport->TimeLastLost; BowserStopTimer(&Transport->FindMasterTimer); BowserStartTimer(&Transport->FindMasterTimer, FIND_MASTER_WAIT-(FIND_MASTER_WAIT/8)+ BowserRandom(FIND_MASTER_WAIT/4), BowserFindMaster, Transport); #endif
}
UNLOCK_TRANSPORT(Transport);
}
NTSTATUS BowserFindMaster( IN PTRANSPORT Transport ) /*++
Routine Description: Find the master browser server.
This routine attempts to find the master browser server by sending a request announcement message to the master. If no response is heard after a while, we assume the master isn't present and run and election.
Arguments: Transport - The transport for the net we're on.
Return Value None.
--*/
{ NTSTATUS Status; PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport; PAGED_CODE();
LOCK_TRANSPORT(Transport);
try {
//
// If our count hasn't gone to 0 yet, we'll send a find master PDU.
//
if (PagedTransport->ElectionCount != 0) {
PagedTransport->ElectionCount -= 1; // Update count, and set timer
BowserStopTimer(&Transport->FindMasterTimer);
Status = BowserSendRequestAnnouncement( &Transport->DomainInfo->DomUnicodeDomainName, MasterBrowser, Transport);
if (NT_SUCCESS(Status) || Status == STATUS_BAD_NETWORK_PATH) { //
// We will retry on the following cases:
// - netbt returns success. Meaning I'll be looking for it.
// - nwlnknb returns STATUS_BAD_NETWORK_PATH meaning I can't find it.
// In either case, we would try for ElectionCount times & then move
// fwd to initiate elections. Otherwise we may end up in a state where because
// we didn't find a master browser, we won't attempt to elect one & we'll fail
// to become one. This will result w/ a domain w/ no master browser.
//
BowserStartTimer(&Transport->FindMasterTimer, FIND_MASTER_DELAY, BowserFindMaster, Transport); } else { try_return(Status); }
} else { ULONG CurrentTime; LONG TimeTilNextElection;
//
// Count has expired, so we'll try to elect a new master.
//
dlog(DPRT_ELECT, ("%s: %ws: Find_Master: Master not found, forcing election.\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer ));
if (BowserLogElectionPackets) { BowserWriteErrorLogEntry(EVENT_BOWSER_ELECTION_SENT_FIND_MASTER_FAILED, STATUS_SUCCESS, NULL, 0, 1, PagedTransport->TransportName.Buffer); }
//
// If it's been more than a reasonable of time since the last
// election, force a new election, otherwise set a timer to
// start an election after a reasonable amount of time.
//
//
// Calculate the time until the next election only once
// since it is possible that we might cross over the ELECTION_TIME
// threshold while performing these checks.
//
CurrentTime = BowserTimeUp(); if ( CurrentTime >= PagedTransport->LastElectionSeen) { TimeTilNextElection = (ELECTION_TIME - (CurrentTime - PagedTransport->LastElectionSeen)); } else { TimeTilNextElection = ELECTION_TIME; }
if ( TimeTilNextElection <= 0 ) {
dlog(DPRT_ELECT, ("%s: %ws: Last election long enough ago, forcing election\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer ));
Status = BowserStartElection(Transport);
//
// If we couldn't start the election, complete the find
// master requests with the appropriate error.
//
if (!NT_SUCCESS(Status)) {
//
// Complete the requests with the current master name - it's
// as good as anyone.
//
BowserCompleteFindMasterRequests(Transport, &PagedTransport->MasterName, Status); }
} else {
dlog(DPRT_ELECT, ("%s: %ws: Last election too recent, delay %ld before forcing election\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer, TimeTilNextElection ));
BowserStartTimer(&Transport->FindMasterTimer, TimeTilNextElection, BowserStartElection, Transport); }
}
try_return(Status = STATUS_SUCCESS); try_exit:NOTHING; } finally { UNLOCK_TRANSPORT(Transport); }
return Status; }
NTSTATUS BowserSendElection( IN PUNICODE_STRING NameToSend OPTIONAL, IN DGRECEIVER_NAME_TYPE NameType, IN PTRANSPORT Transport, IN BOOLEAN SendActualBrowserInfo ) { UCHAR Buffer[sizeof(REQUEST_ELECTION)+LM20_CNLEN+1]; PREQUEST_ELECTION ElectionRequest = (PREQUEST_ELECTION) Buffer; ULONG ComputerNameSize; NTSTATUS Status; PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
PAGED_CODE();
ElectionRequest->Type = Election;
//
// If this transport is disabled,
// don't send any election packets.
//
if ( PagedTransport->DisabledTransport ) { return STATUS_UNSUCCESSFUL; }
//
// If we are supposed to send the actual browser info, and we are
// running the browser send a real election packet, otherwise we
// just want to send a dummy packet.
//
if (SendActualBrowserInfo && (PagedTransport->ServiceStatus & (SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_BACKUP_BROWSER | SV_TYPE_MASTER_BROWSER))) { dlog(DPRT_ELECT, ("%s: %ws: Send true election.\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer ));
//
// If this request comes as a part of an election, we want to send
// the accurate browser information.
//
ElectionRequest->ElectionRequest.Version = BROWSER_ELECTION_VERSION;
ElectionRequest->ElectionRequest.TimeUp = PagedTransport->Uptime;
ElectionRequest->ElectionRequest.Criteria = PagedTransport->ElectionCriteria;
ElectionRequest->ElectionRequest.MustBeZero = 0;
ComputerNameSize = Transport->DomainInfo->DomOemComputerName.Length; strcpy( ElectionRequest->ElectionRequest.ServerName, Transport->DomainInfo->DomOemComputerName.Buffer );
} else { dlog(DPRT_ELECT, ("%s: %ws: Send dummy election.\n", Transport->DomainInfo->DomOemDomainName, PagedTransport->TransportName.Buffer ));
//
// If we are forcing the election because we can't get a backup list,
// send only dummy information.
//
ElectionRequest->ElectionRequest.Version = 0; ElectionRequest->ElectionRequest.Criteria = 0; ElectionRequest->ElectionRequest.TimeUp = 0; ElectionRequest->ElectionRequest.ServerName[0] = '\0'; ElectionRequest->ElectionRequest.MustBeZero = 0; ComputerNameSize = 0; }
return BowserSendSecondClassMailslot(Transport, NameToSend, NameType, ElectionRequest, FIELD_OFFSET(REQUEST_ELECTION, ElectionRequest.ServerName)+ComputerNameSize+sizeof(UCHAR), TRUE, MAILSLOT_BROWSER_NAME, NULL ); }
|