Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1099 lines
33 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. bowelect.c
  5. Abstract:
  6. This module implements all of the election related routines for the NT
  7. browser
  8. Author:
  9. Larry Osterman (LarryO) 21-Jun-1990
  10. Revision History:
  11. 21-Jun-1990 LarryO
  12. Created
  13. --*/
  14. #include "precomp.h"
  15. #pragma hdrstop
  16. #define INCLUDE_SMB_TRANSACTION
  17. NTSTATUS
  18. BowserStartElection(
  19. IN PTRANSPORT Transport
  20. );
  21. LONG
  22. BowserSetElectionCriteria(
  23. IN PPAGED_TRANSPORT Transport
  24. );
  25. NTSTATUS
  26. BowserElectMaster(
  27. IN PTRANSPORT Transport
  28. );
  29. VOID
  30. HandleElectionWorker(
  31. IN PVOID Ctx
  32. );
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text(PAGE, GetMasterName)
  35. #pragma alloc_text(PAGE, HandleElectionWorker)
  36. #pragma alloc_text(PAGE, BowserSetElectionCriteria)
  37. #pragma alloc_text(PAGE, BowserStartElection)
  38. #pragma alloc_text(PAGE, BowserElectMaster)
  39. #pragma alloc_text(PAGE, BowserLoseElection)
  40. #pragma alloc_text(PAGE, BowserFindMaster)
  41. #pragma alloc_text(PAGE, BowserSendElection)
  42. #endif
  43. NTSTATUS
  44. GetMasterName (
  45. IN PIRP Irp,
  46. IN BOOLEAN Wait,
  47. IN BOOLEAN InFsd,
  48. IN PLMDR_REQUEST_PACKET InputBuffer
  49. )
  50. {
  51. NTSTATUS Status;
  52. PTRANSPORT Transport;
  53. PPAGED_TRANSPORT PagedTransport;
  54. PAGED_CODE();
  55. dprintf(DPRT_FSCTL, ("NtDeviceIoControlFile: GetMasterName "));
  56. ExAcquireResourceExclusive(&BowserDataResource, TRUE);
  57. if (BowserData.Initialized != TRUE) {
  58. dprintf(DPRT_FSCTL, ("Bowser already started\n"));
  59. ExReleaseResource(&BowserDataResource);
  60. return STATUS_REDIRECTOR_NOT_STARTED;
  61. }
  62. ExReleaseResource(&BowserDataResource);
  63. Transport = BowserFindTransport(&InputBuffer->TransportName);
  64. if (Transport == NULL) {
  65. return STATUS_OBJECT_NAME_NOT_FOUND;
  66. }
  67. PagedTransport = Transport->PagedTransport;
  68. try {
  69. //
  70. // Ensure the primary name has been added.
  71. //
  72. if ( Transport->PrimaryDomain == NULL ) {
  73. try_return( STATUS_OBJECT_NAME_NOT_FOUND );
  74. }
  75. PagedTransport->ElectionCount = ELECTION_COUNT;
  76. Status = BowserQueueNonBufferRequest(Irp,
  77. &Transport->FindMasterQueue,
  78. BowserCancelQueuedRequest
  79. );
  80. if (!NT_SUCCESS(Status)) {
  81. try_return(Status);
  82. }
  83. Status = BowserFindMaster(Transport);
  84. //
  85. // If we couldn't initiate the find master process, complete all the
  86. // queued find master requests.
  87. //
  88. if (!NT_SUCCESS(Status)) {
  89. BowserCompleteFindMasterRequests(Transport, &PagedTransport->MasterName, Status);
  90. }
  91. //
  92. // Since we marked the IRP as pending, we need to return pending
  93. // now.
  94. //
  95. try_return(Status = STATUS_PENDING);
  96. try_exit:NOTHING;
  97. } finally {
  98. BowserDereferenceTransport(Transport);
  99. }
  100. return(Status);
  101. UNREFERENCED_PARAMETER(Wait);
  102. UNREFERENCED_PARAMETER(InFsd);
  103. }
  104. DATAGRAM_HANDLER(BowserHandleElection)
  105. {
  106. PTA_NETBIOS_ADDRESS Address = SourceAddress;
  107. return BowserPostDatagramToWorkerThread(
  108. TransportName,
  109. Buffer,
  110. BytesAvailable,
  111. BytesTaken,
  112. SourceAddress,
  113. SourceAddressLength,
  114. SourceName,
  115. SourceNameLength,
  116. HandleElectionWorker,
  117. NonPagedPool,
  118. CriticalWorkQueue,
  119. ReceiveFlags,
  120. FALSE // Response will be sent, but...
  121. );
  122. }
  123. VOID
  124. HandleElectionWorker(
  125. IN PVOID Ctx
  126. )
  127. {
  128. PPOST_DATAGRAM_CONTEXT Context = Ctx;
  129. PTRANSPORT_NAME TransportName = Context->TransportName;
  130. PREQUEST_ELECTION_1 ElectionResponse = Context->Buffer;
  131. ULONG BytesAvailable = Context->BytesAvailable;
  132. ULONG TimeUp;
  133. BOOLEAN Winner;
  134. UCHAR ComputerName[LM20_CNLEN+1];
  135. PTRANSPORT Transport = TransportName->Transport;
  136. OEM_STRING AnsiName;
  137. NTSTATUS Status;
  138. LONG ElectionDelay, NextElection;
  139. OEM_STRING ClientNameO;
  140. UNICODE_STRING ClientName;
  141. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  142. PAGED_CODE();
  143. LOCK_TRANSPORT(Transport);
  144. ClientName.Buffer = NULL;
  145. try {
  146. BowserStatistics.NumberOfElectionPackets += 1;
  147. //
  148. // Remember the last time we heard an election packet.
  149. //
  150. PagedTransport->LastElectionSeen = BowserTimeUp();
  151. if (Transport->ElectionState == DeafToElections) {
  152. try_return(NOTHING);
  153. }
  154. //
  155. // If we've disable the transport for any reason,
  156. // then we disregard all elections.
  157. //
  158. if (PagedTransport->DisabledTransport) {
  159. try_return(NOTHING);
  160. }
  161. //
  162. // Convert the client name in the election packet to unicode so we can
  163. // log it.
  164. //
  165. RtlInitString(&ClientNameO, ElectionResponse->ServerName);
  166. Status = RtlOemStringToUnicodeString(&ClientName, &ClientNameO, TRUE);
  167. if (!NT_SUCCESS(Status)) {
  168. BowserWriteErrorLogEntry(EVENT_BOWSER_NAME_CONVERSION_FAILED, Status, ClientNameO.Buffer, ClientNameO.Length, 0);
  169. try_return(NOTHING);
  170. }
  171. if (BowserLogElectionPackets) {
  172. BowserWriteErrorLogEntry(EVENT_BOWSER_ELECTION_RECEIVED, STATUS_SUCCESS, ElectionResponse, (USHORT)BytesAvailable, 2, ClientName.Buffer, PagedTransport->TransportName.Buffer);
  173. }
  174. dlog(DPRT_ELECT, ("Received election packet on net %wZ from machine %s. Version: %lx; Criteria: %lx; TimeUp: %lx\n", &PagedTransport->TransportName,
  175. ElectionResponse->ServerName,
  176. ElectionResponse->Version,
  177. SmbGetUlong(&ElectionResponse->Criteria),
  178. SmbGetUlong(&ElectionResponse->TimeUp)));
  179. AnsiName.Buffer = ComputerName;
  180. AnsiName.MaximumLength = LM20_CNLEN+1;
  181. Status = RtlUnicodeStringToOemString(&AnsiName, &Transport->ComputerName->PagedTransportName->Name->Name, FALSE);
  182. if (!NT_SUCCESS(Status)) {
  183. BowserWriteErrorLogEntry( EVENT_BOWSER_NAME_CONVERSION_FAILED,
  184. Status,
  185. Transport->ComputerName->PagedTransportName->Name->Name.Buffer,
  186. Transport->ComputerName->PagedTransportName->Name->Name.Length,
  187. 0);
  188. try_return(NOTHING);
  189. }
  190. //
  191. // Figure out our time up for the election compare.
  192. //
  193. // If we're running an election, we'll use our advertised time, else
  194. // we'll use our actual uptime. Also, if we're running an election
  195. // we'll check to see if we sent this. If we're not running an election
  196. // and we receive this, it's because the redirector didn't find a
  197. // master, so we want to continue the election and become master.
  198. //
  199. if (Transport->ElectionState == RunningElection) {
  200. if (!strcmp(ComputerName, ElectionResponse->ServerName)) {
  201. try_return(NOTHING);
  202. }
  203. //
  204. // If this request was initiated from a client, ignore it.
  205. //
  206. if ((SmbGetUlong(&ElectionResponse->Criteria) == 0) &&
  207. (ElectionResponse->ServerName[0] == '\0')) {
  208. dlog(DPRT_ELECT, ("Dummy election request ignored during election.\n"));
  209. try_return(NOTHING);
  210. }
  211. if (PagedTransport->Role == Master) {
  212. ElectionDelay = BowserRandom(MASTER_ELECTION_DELAY);
  213. } else {
  214. ElectionDelay = ELECTION_RESPONSE_MIN + BowserRandom(ELECTION_RESPONSE_MAX-ELECTION_RESPONSE_MIN);
  215. }
  216. } else {
  217. //
  218. // Starting a new election - set various election criteria
  219. // including Uptime.
  220. //
  221. ElectionDelay = BowserSetElectionCriteria(PagedTransport);
  222. }
  223. TimeUp = PagedTransport->Uptime;
  224. if (ElectionResponse->Version != BROWSER_ELECTION_VERSION) {
  225. Winner = (ElectionResponse->Version < BROWSER_ELECTION_VERSION);
  226. } else if (SmbGetUlong(&ElectionResponse->Criteria) != PagedTransport->ElectionCriteria) {
  227. Winner = (SmbGetUlong(&ElectionResponse->Criteria) < PagedTransport->ElectionCriteria);
  228. } else if (TimeUp != SmbGetUlong(&ElectionResponse->TimeUp)) {
  229. Winner = TimeUp > SmbGetUlong(&ElectionResponse->TimeUp);
  230. } else {
  231. Winner = (strcmp(ComputerName, ElectionResponse->ServerName) <= 0);
  232. }
  233. //
  234. // If we lost, we stop our timer and turn off our election flag, just
  235. // in case we had an election or find master going. If we're a backup,
  236. // we want to find out who the new master is, either from this election
  237. // frame or waiting awhile and querying.
  238. //
  239. if (!Winner) {
  240. //
  241. // Remember if we legitimately lost the last election, and if
  242. // so, don't force an election if we see server announcements
  243. // from a non DC, just give up.
  244. //
  245. PagedTransport->Flags |= ELECT_LOST_LAST_ELECTION;
  246. }
  247. if (!Winner || (PagedTransport->ElectionsSent > ELECTION_MAX)) {
  248. if (BowserData.IsPrimaryDomainController) {
  249. DWORD ElectionInformation[6];
  250. ElectionInformation[0] = ElectionResponse->Version;
  251. ElectionInformation[1] = SmbGetUlong(&ElectionResponse->Criteria);
  252. ElectionInformation[2] = SmbGetUlong(&ElectionResponse->TimeUp);
  253. ElectionInformation[3] = BROWSER_ELECTION_VERSION;
  254. ElectionInformation[4] = PagedTransport->ElectionCriteria;
  255. ElectionInformation[5] = TimeUp;
  256. //
  257. // Write this information into the event log.
  258. //
  259. BowserWriteErrorLogEntry(EVENT_BOWSER_PDC_LOST_ELECTION,
  260. STATUS_SUCCESS,
  261. ElectionInformation,
  262. sizeof(ElectionInformation),
  263. 2,
  264. ClientName.Buffer,
  265. PagedTransport->TransportName.Buffer);
  266. KdPrint(("HandleElectionWorker: Lose election, but we're the PDC. Winner: Version: %lx; Criteria: %lx; Time Up: %lx; Name: %s\n",
  267. ElectionResponse->Version,
  268. SmbGetUlong(&ElectionResponse->Criteria),
  269. SmbGetUlong(&ElectionResponse->TimeUp),
  270. ElectionResponse->ServerName));
  271. }
  272. BowserLoseElection(Transport);
  273. } else {
  274. //
  275. // We won this election, make sure that we don't think that we
  276. // lost it.
  277. //
  278. PagedTransport->Flags &= ~ELECT_LOST_LAST_ELECTION;
  279. //
  280. // If we won and we're not running an election, we'll start one.
  281. // If we are running, we don't do anything because our timer will
  282. // take care of it. If the NET_ELECTION flag is clear, we know
  283. // timeup is approx. equal to time_up() because we set it above,
  284. // so we'll use that. This algorithm includes a damping constant
  285. // (we won't start an election if we've just lost one in the
  286. // last 1.5 seconds) to avoid election storms.
  287. //
  288. #if 0
  289. //
  290. // If we've won and we're not a DC and this is't a wanish
  291. // transport, and we're a member of a domain, log an event. This
  292. // should never happen.
  293. //
  294. if (ElectionResponse->ServerName[0] != '\0' &&
  295. SmbGetUlong(&ElectionResponse->Criteria) != 0 &&
  296. Transport->ElectionState == RunningElection &&
  297. BowserData.IsDomainMember &&
  298. !BowserData.IsLanmanNt &&
  299. !Transport->Wannish) {
  300. DWORD ElectionInformation[6];
  301. ElectionInformation[0] = ElectionResponse->Version;
  302. ElectionInformation[1] = SmbGetUlong(&ElectionResponse->Criteria);
  303. ElectionInformation[2] = SmbGetUlong(&ElectionResponse->TimeUp);
  304. ElectionInformation[3] = BROWSER_ELECTION_VERSION;
  305. ElectionInformation[4] = Transport->ElectionCriteria;
  306. ElectionInformation[5] = TimeUp;
  307. //
  308. // Write this information into the event log.
  309. //
  310. BowserWriteErrorLogEntry(EVENT_BOWSER_NON_PDC_WON_ELECTION,
  311. STATUS_SUCCESS,
  312. ElectionInformation,
  313. sizeof(ElectionInformation),
  314. 1,
  315. Transport->TransportName.Buffer);
  316. dlog(DPRT_ELECT, ("HandleElectionWorker: Won election, but we're not the PDC. Winner: Version: %lx; Criteria: %lx; Time Up: %lx; Name: %s\n",
  317. ElectionResponse->Version,
  318. SmbGetUlong(&ElectionResponse->Criteria),
  319. SmbGetUlong(&ElectionResponse->TimeUp),
  320. ElectionResponse->ServerName));
  321. }
  322. #endif
  323. if (Transport->ElectionState != RunningElection) {
  324. //
  325. // If we recently lost an election, then ignore the fact
  326. // that we won, and pretend we lost this one.
  327. //
  328. if ((PagedTransport->TimeLastLost != 0) &&
  329. ((BowserTimeUp() - PagedTransport->TimeLastLost) < ELECTION_EXEMPT_TIME)) {
  330. dlog(DPRT_ELECT, ("Bowser: Browser is exempt from election\n"));
  331. try_return(NOTHING);
  332. }
  333. dlog(DPRT_ELECT, ("Bowser:elect_rcv: Better criteria, calling elect_master in %ld milliseconds.\n", ElectionDelay));
  334. //
  335. // Ensure the timer is running.
  336. // We don't actually win the election until the timer expires.
  337. //
  338. Transport->ElectionState = RunningElection;
  339. PagedTransport->NextElection = 0;
  340. }
  341. PagedTransport->ElectionCount = ELECTION_COUNT;
  342. //
  343. // Note: the next elect time must be computed into a signed
  344. // integer in case the expiration time has already passed so
  345. // don't try to optimize this code too much.
  346. //
  347. NextElection = PagedTransport->NextElection - (TimeUp - BowserTimeUp());
  348. if ((PagedTransport->NextElection == 0) || NextElection > ElectionDelay) {
  349. BowserStopTimer(&Transport->ElectionTimer);
  350. PagedTransport->NextElection = TimeUp + ElectionDelay;
  351. dlog(DPRT_ELECT, ("Calling ElectMaster in %ld milliseconds\n", ElectionDelay));
  352. BowserStartTimer(&Transport->ElectionTimer, ElectionDelay, BowserElectMaster, Transport);
  353. }
  354. }
  355. try_exit:NOTHING;
  356. } finally {
  357. UNLOCK_TRANSPORT(Transport);
  358. InterlockedDecrement( &BowserPostedCriticalDatagramCount );
  359. FREE_POOL(Context);
  360. if (ClientName.Buffer != NULL) {
  361. RtlFreeUnicodeString(&ClientName);
  362. }
  363. BowserDereferenceTransportName(TransportName);
  364. BowserDereferenceTransport(Transport);
  365. }
  366. return;
  367. }
  368. LONG
  369. BowserSetElectionCriteria(
  370. IN PPAGED_TRANSPORT PagedTransport
  371. )
  372. /*++
  373. Routine Description:
  374. Set election criteria for a network.
  375. Prepare for an election by setting Transport->ElectionCriteria based upon the local
  376. browser state. Set Transport->Uptime to the current local up time.
  377. Arguments:
  378. Transport - The transport for the net we're on.
  379. Return Value
  380. Number of milliseconds to delay before sending the election packet.
  381. --*/
  382. {
  383. LONG Delay;
  384. PAGED_CODE();
  385. PagedTransport->ElectionsSent = 0; // clear bid counter
  386. PagedTransport->Uptime = BowserTimeUp();
  387. if (BowserData.IsLanmanNt) {
  388. PagedTransport->ElectionCriteria = ELECTION_CR_LM_NT;
  389. } else {
  390. PagedTransport->ElectionCriteria = ELECTION_CR_WIN_NT;
  391. }
  392. PagedTransport->ElectionCriteria |=
  393. ELECTION_MAKE_REV(BROWSER_VERSION_MAJOR, BROWSER_VERSION_MINOR);
  394. if (BowserData.MaintainServerList &&
  395. ((PagedTransport->NumberOfServersInTable +
  396. RtlNumberGenericTableElements(&PagedTransport->AnnouncementTable)+
  397. RtlNumberGenericTableElements(&PagedTransport->DomainTable)) != 0)) {
  398. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_CFG_BKP;
  399. }
  400. if (BowserData.IsPrimaryDomainController) {
  401. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_PDC;
  402. }
  403. if (BowserData.IsDomainMaster) {
  404. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_DOMMSTR;
  405. }
  406. if (PagedTransport->Role == Master) {
  407. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_MASTER;
  408. Delay = MASTER_ELECTION_DELAY;
  409. } else if (BowserData.IsPrimaryDomainController) {
  410. //
  411. // If we are the PDC, we want to set our timeouts
  412. // as if we were already the master.
  413. //
  414. // This prevents us from getting into a situation where it takes
  415. // more than ELECTION_DELAY_MAX to actually send out our response
  416. // to an election.
  417. //
  418. Delay = MASTER_ELECTION_DELAY;
  419. } else if ((PagedTransport->Role == Backup) ||
  420. BowserData.IsLanmanNt) {
  421. //
  422. // Likewise, if we are NTAS machines, we want to set out delay
  423. // to match that of backup browsers (even if we're not a backup
  424. // quite yet).
  425. //
  426. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_AM_BACKUP;
  427. Delay = BACKUP_ELECTION_DELAY_MIN + BowserRandom(BACKUP_ELECTION_DELAY_MAX-BACKUP_ELECTION_DELAY_MIN);
  428. } else {
  429. Delay = ELECTION_DELAY_MIN + BowserRandom(ELECTION_DELAY_MAX-ELECTION_DELAY_MIN);
  430. }
  431. //
  432. // Assume for now that all wannish transports are running the WINS client.
  433. //
  434. if ( PagedTransport->Wannish ) {
  435. PagedTransport->ElectionCriteria |= ELECTION_DESIRE_WINS_CLIENT;
  436. }
  437. return Delay;
  438. }
  439. NTSTATUS
  440. BowserStartElection(
  441. IN PTRANSPORT Transport
  442. )
  443. /*++
  444. Routine Description:
  445. Initiate a browser election
  446. This routine is called when we are unable to find a master, and we want to
  447. elect one.
  448. Arguments:
  449. Transport - The transport for the net we're on.
  450. Return Value
  451. None.
  452. --*/
  453. {
  454. NTSTATUS Status = STATUS_SUCCESS;
  455. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  456. PAGED_CODE();
  457. LOCK_TRANSPORT(Transport);
  458. try {
  459. //
  460. // If we've disable the transport for any reason,
  461. // then we disregard all elections.
  462. //
  463. if (PagedTransport->DisabledTransport) {
  464. try_return(Status = STATUS_UNSUCCESSFUL);
  465. }
  466. //
  467. // If we're deaf to elections, or aren't any kind of
  468. // browser then we can't start elections either.
  469. //
  470. if (Transport->ElectionState == DeafToElections ||
  471. PagedTransport->Role == None) {
  472. try_return(Status = STATUS_UNSUCCESSFUL);
  473. }
  474. PagedTransport->ElectionCount = ELECTION_COUNT;
  475. Transport->ElectionState = RunningElection;
  476. BowserSetElectionCriteria(PagedTransport);
  477. Status = BowserElectMaster(Transport);
  478. try_exit:NOTHING;
  479. } finally {
  480. UNLOCK_TRANSPORT(Transport);
  481. }
  482. return Status;
  483. }
  484. NTSTATUS
  485. BowserElectMaster(
  486. IN PTRANSPORT Transport
  487. )
  488. /*++
  489. Routine Description:
  490. Elect a master browser server.
  491. This routine is called when we think there is no master and we need to
  492. elect one. We check our retry count, and if it's non-zero we send an
  493. elect datagram to the group name. Otherwise we become the master ourselves.
  494. Arguments:
  495. Transport - The transport for the net we're on.
  496. Return Value
  497. None.
  498. --*/
  499. {
  500. NTSTATUS Status;
  501. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  502. PAGED_CODE();
  503. LOCK_TRANSPORT(Transport);
  504. try {
  505. //
  506. // If we're not running the election at this time, it means that
  507. // between the time that we decided we were going to win the election
  508. // and now, someone else announced with better criteria. It is
  509. // possible that this could happen if the announcement came in just
  510. // before we ran (ie. if the announcement occured between when the
  511. // timer DPC was queued and when the DPC actually fired).
  512. //
  513. if (Transport->ElectionState != RunningElection) {
  514. KdPrint(("BowserElectMaster: Lose election because we are no longer running the election\n"));
  515. BowserLoseElection(Transport);
  516. } else if (PagedTransport->ElectionCount != 0) {
  517. BowserStopTimer(&Transport->ElectionTimer);
  518. PagedTransport->ElectionCount -= 1;
  519. PagedTransport->ElectionsSent += 1;
  520. PagedTransport->NextElection = BowserTimeUp() + ELECTION_RESEND_DELAY;
  521. Status = BowserSendElection(&Transport->PrimaryDomain->PagedTransportName->Name->Name, BrowserElection, Transport, TRUE);
  522. // Lose the election if we can't send a datagram.
  523. if (!NT_SUCCESS(Status)) {
  524. BowserLoseElection(Transport);
  525. try_return(Status);
  526. }
  527. //
  528. // If we were able to send the election,
  529. // start the timer running.
  530. //
  531. BowserStartTimer(&Transport->ElectionTimer,
  532. ELECTION_RESEND_DELAY,
  533. BowserElectMaster,
  534. Transport);
  535. } else {
  536. Transport->ElectionState = Idle;
  537. //
  538. // If we're already the master we just return. This can happen if
  539. // somebody starts an election (which we win) while we're already
  540. // the master.
  541. //
  542. if (PagedTransport->Role != Master) {
  543. OEM_STRING OemString;
  544. NTSTATUS Status;
  545. //
  546. // Convert the unicode computer name into ANSI for BowserNewMaster
  547. //
  548. Status = RtlUnicodeStringToOemString(&OemString, &Transport->ComputerName->PagedTransportName->Name->Name, TRUE);
  549. if (!NT_SUCCESS(Status)) {
  550. BowserWriteErrorLogEntry(EVENT_BOWSER_NAME_CONVERSION_FAILED,
  551. Status,
  552. Transport->ComputerName->PagedTransportName->Name->Name.Buffer,
  553. Transport->ComputerName->PagedTransportName->Name->Name.Length,
  554. 0);
  555. try_return(Status);
  556. }
  557. //
  558. // We're the new master - we won!
  559. //
  560. BowserNewMaster(Transport, OemString.Buffer);
  561. RtlFreeAnsiString(&OemString);
  562. } else {
  563. //
  564. // Were already the master. Make sure that all the backups
  565. // know this by sending an announcent
  566. //
  567. //
  568. // This one's easy - simply set the servers announcement event to the
  569. // signalled state. If the server is running, this will force an
  570. // announcement
  571. //
  572. KeSetEvent(BowserServerAnnouncementEvent, IO_NETWORK_INCREMENT, FALSE);
  573. }
  574. }
  575. try_return(Status = STATUS_SUCCESS);
  576. try_exit:NOTHING;
  577. } finally {
  578. UNLOCK_TRANSPORT(Transport);
  579. }
  580. return Status;
  581. }
  582. VOID
  583. BowserLoseElection(
  584. IN PTRANSPORT Transport
  585. )
  586. {
  587. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  588. PAGED_CODE();
  589. LOCK_TRANSPORT(Transport);
  590. BowserStopTimer(&Transport->ElectionTimer);
  591. dlog(DPRT_ELECT, ("We lost the election\n"));
  592. PagedTransport->TimeLastLost = BowserTimeUp();
  593. //
  594. // We lost the election - we re-enter the idle state.
  595. //
  596. Transport->ElectionState = Idle;
  597. if (PagedTransport->Role == Master) {
  598. //
  599. // If we lost, and we are currently a master, then tickle
  600. // the browser service and stop being a master.
  601. //
  602. BowserResetStateForTransport(Transport, RESET_STATE_STOP_MASTER);
  603. //
  604. // Remove all the entries on the server list for this
  605. // transport.
  606. //
  607. LOCK_ANNOUNCE_DATABASE(Transport);
  608. //
  609. // Flag that there should be no more announcements received on
  610. // this name.
  611. //
  612. BowserForEachTransportName(Transport, BowserStopProcessingAnnouncements, NULL);
  613. // KdPrint(("Deleting entire table on transport %wZ because we lost the election\n", &Transport->TransportName));
  614. BowserDeleteGenericTable(&PagedTransport->AnnouncementTable);
  615. BowserDeleteGenericTable(&PagedTransport->DomainTable);
  616. UNLOCK_ANNOUNCE_DATABASE(Transport);
  617. #if 0
  618. } else if (Transport->Role == Backup) { // If we're a backup, find master
  619. dlog(DPRT_ELECT, ("We're a backup - Find the new master\n"));
  620. //
  621. // If this guy is not the master, then we want to
  622. // find a master at some later time.
  623. //
  624. Transport->ElectionCount = FIND_MASTER_COUNT;
  625. Transport->Uptime = Transport->TimeLastLost;
  626. BowserStopTimer(&Transport->FindMasterTimer);
  627. BowserStartTimer(&Transport->FindMasterTimer,
  628. FIND_MASTER_WAIT-(FIND_MASTER_WAIT/8)+ BowserRandom(FIND_MASTER_WAIT/4),
  629. BowserFindMaster,
  630. Transport);
  631. #endif
  632. }
  633. UNLOCK_TRANSPORT(Transport);
  634. }
  635. NTSTATUS
  636. BowserFindMaster(
  637. IN PTRANSPORT Transport
  638. )
  639. /*++
  640. Routine Description:
  641. Find the master browser server.
  642. This routine attempts to find the master browser server by
  643. sending a request announcement message to the master. If no response is
  644. heard after a while, we assume the master isn't present and run and
  645. election.
  646. Arguments:
  647. Transport - The transport for the net we're on.
  648. Return Value
  649. None.
  650. --*/
  651. {
  652. NTSTATUS Status;
  653. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  654. PAGED_CODE();
  655. LOCK_TRANSPORT(Transport);
  656. try {
  657. //
  658. // If our count hasn't gone to 0 yet, we'll send a find master PDU.
  659. //
  660. if (PagedTransport->ElectionCount != 0) {
  661. PagedTransport->ElectionCount -= 1; // Update count, and set timer
  662. BowserStopTimer(&Transport->FindMasterTimer);
  663. Status = BowserSendRequestAnnouncement(&Transport->PrimaryDomain->PagedTransportName->Name->Name,
  664. MasterBrowser,
  665. Transport);
  666. if (NT_SUCCESS(Status)) {
  667. BowserStartTimer(&Transport->FindMasterTimer,
  668. FIND_MASTER_DELAY,
  669. BowserFindMaster,
  670. Transport);
  671. } else {
  672. try_return(Status);
  673. }
  674. } else {
  675. ULONG CurrentTime;
  676. LONG TimeTilNextElection;
  677. //
  678. // Count has expired, so we'll try to elect a new master.
  679. //
  680. dlog(DPRT_ELECT, ("Bowser::Find_Master: Master not found, forcing election.\n"));
  681. if (BowserLogElectionPackets) {
  682. BowserWriteErrorLogEntry(EVENT_BOWSER_ELECTION_SENT_FIND_MASTER_FAILED, STATUS_SUCCESS, NULL, 0, 1, PagedTransport->TransportName.Buffer);
  683. }
  684. //
  685. // If it's been more than a reasonable of time since the last
  686. // election, force a new election, otherwise set a timer to
  687. // start an election after a reasonable amount of time.
  688. //
  689. //
  690. // Calculate the time until the next election only once
  691. // since it is possible that we might cross over the ELECTION_TIME
  692. // threshold while performing these checks.
  693. //
  694. CurrentTime = BowserTimeUp();
  695. if ( CurrentTime >= PagedTransport->LastElectionSeen) {
  696. TimeTilNextElection = (ELECTION_TIME - (CurrentTime - PagedTransport->LastElectionSeen));
  697. } else {
  698. TimeTilNextElection = ELECTION_TIME;
  699. }
  700. if ( TimeTilNextElection <= 0 ) {
  701. dlog(DPRT_ELECT, ("Bowser: Last election long enough ago, forcing election on %wZ\n",
  702. &PagedTransport->TransportName));
  703. Status = BowserStartElection(Transport);
  704. //
  705. // If we couldn't start the election, complete the find
  706. // master requests with the appropriate error.
  707. //
  708. if (!NT_SUCCESS(Status)) {
  709. //
  710. // Complete the requests with the current master name - it's
  711. // as good as anyone.
  712. //
  713. BowserCompleteFindMasterRequests(Transport, &PagedTransport->MasterName, Status);
  714. }
  715. } else {
  716. dlog(DPRT_ELECT, ("Bowser: Last election too recent, delay %ld before forcing election on %wZ\n",
  717. TimeTilNextElection,
  718. &PagedTransport->TransportName));
  719. BowserStartTimer(&Transport->FindMasterTimer,
  720. TimeTilNextElection,
  721. BowserStartElection,
  722. Transport);
  723. }
  724. }
  725. try_return(Status = STATUS_SUCCESS);
  726. try_exit:NOTHING;
  727. } finally {
  728. UNLOCK_TRANSPORT(Transport);
  729. }
  730. return Status;
  731. }
  732. NTSTATUS
  733. BowserSendElection(
  734. IN PUNICODE_STRING NameToSend OPTIONAL,
  735. IN DGRECEIVER_NAME_TYPE NameType,
  736. IN PTRANSPORT Transport,
  737. IN BOOLEAN SendActualBrowserInfo
  738. )
  739. {
  740. UCHAR Buffer[sizeof(REQUEST_ELECTION)+LM20_CNLEN+1];
  741. PREQUEST_ELECTION ElectionRequest = (PREQUEST_ELECTION) Buffer;
  742. OEM_STRING OemString;
  743. NTSTATUS Status;
  744. PPAGED_TRANSPORT PagedTransport = Transport->PagedTransport;
  745. PAGED_CODE();
  746. ElectionRequest->Type = Election;
  747. //
  748. // If this transport is disabled,
  749. // don't send any election packets.
  750. //
  751. if ( PagedTransport->DisabledTransport ) {
  752. return STATUS_UNSUCCESSFUL;
  753. }
  754. //
  755. // If we are supposed to send the actual browser info, and we are
  756. // running the browser send a real election packet, otherwise we
  757. // just want to send a dummy packet.
  758. //
  759. if (SendActualBrowserInfo &&
  760. (PagedTransport->ServiceStatus & (SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_BACKUP_BROWSER | SV_TYPE_MASTER_BROWSER))) {
  761. dlog(DPRT_ELECT, ("Send true election.\n"));
  762. //
  763. // If this request comes as a part of an election, we want to send
  764. // the accurate browser information.
  765. //
  766. ElectionRequest->ElectionRequest.Version = BROWSER_ELECTION_VERSION;
  767. ElectionRequest->ElectionRequest.TimeUp = PagedTransport->Uptime;
  768. ElectionRequest->ElectionRequest.Criteria = PagedTransport->ElectionCriteria;
  769. ElectionRequest->ElectionRequest.MustBeZero = 0;
  770. OemString.Buffer = ElectionRequest->ElectionRequest.ServerName;
  771. OemString.MaximumLength = LM20_CNLEN+1;
  772. Status = RtlUnicodeStringToOemString(&OemString, &Transport->ComputerName->PagedTransportName->Name->Name, FALSE);
  773. if (!NT_SUCCESS(Status)) {
  774. BowserWriteErrorLogEntry(EVENT_BOWSER_NAME_CONVERSION_FAILED,
  775. Status,
  776. Transport->ComputerName->PagedTransportName->Name->Name.Buffer,
  777. Transport->ComputerName->PagedTransportName->Name->Name.Length,
  778. 0);
  779. return Status;
  780. }
  781. } else {
  782. dlog(DPRT_ELECT, ("Send dummy election.\n"));
  783. //
  784. // If we are forcing the election because we can't get a backup list,
  785. // send only dummy information.
  786. //
  787. ElectionRequest->ElectionRequest.Version = 0;
  788. ElectionRequest->ElectionRequest.Criteria = 0;
  789. ElectionRequest->ElectionRequest.TimeUp = 0;
  790. ElectionRequest->ElectionRequest.ServerName[0] = '\0';
  791. ElectionRequest->ElectionRequest.MustBeZero = 0;
  792. OemString.Length = 0;
  793. }
  794. return BowserSendSecondClassMailslot(Transport,
  795. NameToSend,
  796. NameType,
  797. ElectionRequest,
  798. FIELD_OFFSET(REQUEST_ELECTION, ElectionRequest.ServerName)+OemString.Length+sizeof(UCHAR),
  799. TRUE,
  800. MAILSLOT_BROWSER_NAME,
  801. NULL
  802. );
  803. }