Leaked source code of windows server 2003
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.

11142 lines
344 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. replica.c
  5. Abstract:
  6. Replica Control Command Server (Replica).
  7. The Ds Poller periodically pulls the configuration from the DS,
  8. checks it for consistency, and then merges it with the current
  9. local configuration. The Ds Poller then makes copies of each
  10. replica for this machine and sends the copy to this replica
  11. control command server.
  12. Author:
  13. Billy J. Fuller 23-May-1997
  14. Revised:
  15. David A. Orbits 24-Jan-1998, added locking and interfaced with INLOG.
  16. Restructured Connection JOIN sequence.
  17. Jul-1999 Registry code rewrite
  18. Environment
  19. User mode winnt
  20. --*/
  21. #include <ntreppch.h>
  22. #pragma hdrstop
  23. #include <ntdsapi.h>
  24. #include <frs.h>
  25. #include <tablefcn.h>
  26. #include <ntfrsapi.h>
  27. #include <perrepsr.h>
  28. #include <Sddl.h>
  29. //
  30. // Connection flags.
  31. //
  32. FLAG_NAME_TABLE CxtionFlagNameTable[] = {
  33. {CXTION_FLAGS_CONSISTENT , "Consistent " },
  34. {CXTION_FLAGS_SCHEDULE_OFF , "SchedOff " },
  35. {CXTION_FLAGS_VOLATILE , "Volatile " },
  36. {CXTION_FLAGS_DEFERRED_JOIN , "DeferredJoin " },
  37. {CXTION_FLAGS_DEFERRED_UNJOIN , "DeferUnjoin " },
  38. {CXTION_FLAGS_TIMEOUT_SET , "TimeOutSet " },
  39. {CXTION_FLAGS_JOIN_GUID_VALID , "JoinGuidValid " },
  40. {CXTION_FLAGS_UNJOIN_GUID_VALID , "UnJoinGuidValid "},
  41. {CXTION_FLAGS_PERFORM_VVJOIN , "PerformVVJoin" },
  42. {CXTION_FLAGS_DEFERRED_DELETE , "DeferredDel " },
  43. {CXTION_FLAGS_PAUSED , "Paused " },
  44. {CXTION_FLAGS_HUNG_INIT_SYNC , "HungInitSync " },
  45. {CXTION_FLAGS_TRIM_OUTLOG , "TrimOutLog " },
  46. {CXTION_FLAGS_INIT_SYNC , "InitSync " },
  47. {CXTION_FLAGS_TRIGGER_SCHEDULE , "TriggerSched " },
  48. {0, NULL}
  49. };
  50. //
  51. // Directory and file filter lists from registry.
  52. //
  53. extern PWCHAR RegistryFileExclFilterList;
  54. extern PWCHAR RegistryDirExclFilterList;
  55. extern ULONGLONG ActiveChange;
  56. BOOL CurrentSysvolReadyIsValid;
  57. DWORD CurrentSysvolReady;
  58. //
  59. // Replica tombstone in days
  60. //
  61. DWORD ReplicaTombstone;
  62. ULONGLONG ReplicaTombstoneInFileTime;
  63. //
  64. // Retry a join every MinJoinRetry milliseconds, increasing by
  65. // MinJoinRetry every retry (but no longer than MaxJoinRetry).
  66. //
  67. #define JOIN_RETRY_EVENT (5) // record event every 5 join retries
  68. LONG MinJoinRetry;
  69. LONG MaxJoinRetry;
  70. extern DWORD CommTimeoutInMilliSeconds;
  71. //
  72. // Start replication even if the DS could not be accessed
  73. //
  74. DWORD ReplicaStartTimeout;
  75. //
  76. // Struct for the Replica Control Command Server
  77. // Contains info about the queues and the threads
  78. //
  79. COMMAND_SERVER ReplicaCmdServer;
  80. //
  81. // Table of active replicas
  82. //
  83. PGEN_TABLE ReplicasByGuid;
  84. PGEN_TABLE ReplicasByNumber;
  85. //
  86. // Table of deleted replicas discovered at startup. These replicas
  87. // never make it into the active tables, ever.
  88. //
  89. PGEN_TABLE DeletedReplicas;
  90. //
  91. // Table of cxtions deleted during runtime. They are eventually
  92. // freed at shutdown.
  93. //
  94. PGEN_TABLE DeletedCxtions;
  95. PGEN_TABLE ReplicasNotInTheDs;
  96. #define MINUTES_IN_INTERVAL (15)
  97. #define CMD_DELETE_RETRY_SHORT_TIMEOUT (10 * 1000)
  98. #define CMD_DELETE_RETRY_LONG_TIMEOUT (60 * 1000)
  99. //
  100. // Partners are not allowed to join if their clocks are out-of-sync
  101. //
  102. ULONGLONG MaxPartnerClockSkew;
  103. DWORD PartnerClockSkew;
  104. #define ReplicaCmdSetInitialTimeOut(_Cmd_, _Init_) \
  105. if (RsTimeout(Cmd) == 0) { \
  106. RsTimeout(Cmd) = (_Init_); \
  107. }
  108. #define SET_JOINED(_Replica_, _Cxtion_, _S_) \
  109. { \
  110. SetCxtionState(_Cxtion_, CxtionStateJoined); \
  111. PM_INC_CTR_REPSET((_Replica_), Joins, 1); \
  112. PM_INC_CTR_CXTION((_Cxtion_), Joins, 1); \
  113. \
  114. DPRINT3(0, ":X: ***** %s CxtG %08x "FORMAT_CXTION_PATH2"\n", \
  115. _S_, \
  116. ((_Cxtion_) != NULL) ? ((PCXTION)(_Cxtion_))->Name->Guid->Data1 : 0,\
  117. PRINT_CXTION_PATH2(_Replica_, _Cxtion_)); \
  118. if (_Cxtion_->JoinCmd && \
  119. (LONG)RsTimeout(_Cxtion_->JoinCmd) > (JOIN_RETRY_EVENT * MinJoinRetry)) { \
  120. if (_Cxtion_->Inbound) { \
  121. EPRINT3(EVENT_FRS_LONG_JOIN_DONE, \
  122. _Cxtion_->Partner->Name, ComputerName, _Replica_->Root); \
  123. } else { \
  124. EPRINT3(EVENT_FRS_LONG_JOIN_DONE, \
  125. ComputerName, _Cxtion_->Partner->Name, _Replica_->Root); \
  126. } \
  127. } \
  128. }
  129. //
  130. // Unidle the change order process queue if it is blocked.
  131. //
  132. #define UNIDLE_CO_PROCESS_QUEUE(_Replica_, _Cxtion_, _CoProcessQueue_) \
  133. { \
  134. if (_CoProcessQueue_ != NULL) { \
  135. CXTION_STATE_TRACE(3, _Cxtion_, _Replica_, 0, "CO Process Q Unblock"); \
  136. FrsRtlUnIdledQueue(_CoProcessQueue_); \
  137. _CoProcessQueue_ = NULL; \
  138. } \
  139. }
  140. //
  141. // UNJOIN TRIGGER
  142. //
  143. // Trigger an unjoin after N co's on *ONE* cxtion *ONE* time.
  144. //
  145. #if DBG
  146. #define PULL_UNJOIN_TRIGGER(_Cxtion_, _Cmd_) \
  147. { \
  148. if (_Cxtion_->UnjoinTrigger && (--_Cxtion_->UnjoinTrigger == 0)) { \
  149. DPRINT1(0, ":X: UNJOIN TRIGGER FIRED FOR %ws\n", _Cxtion_->Name->Name); \
  150. FrsCompleteCommand(_Cmd_, ERROR_OPERATION_ABORTED); \
  151. return; \
  152. } \
  153. }
  154. #define SET_UNJOIN_TRIGGER(_Cxtion_) \
  155. { \
  156. if (DebugInfo.UnjoinTrigger) { \
  157. _Cxtion_->UnjoinReset = DebugInfo.UnjoinTrigger; \
  158. DebugInfo.UnjoinTrigger = 0; \
  159. } \
  160. _Cxtion_->UnjoinTrigger = _Cxtion_->UnjoinReset; \
  161. _Cxtion_->UnjoinReset <<= 1; \
  162. _Cxtion_->UnjoinReset = 0; \
  163. }
  164. #else DBG
  165. #define SET_UNJOIN_TRIGGER(_Cxtion_)
  166. #define PULL_UNJOIN_TRIGGER(_Cxtion_, _Cmd_)
  167. #endif DBG
  168. //
  169. // Flags for RcsCheckCmd.
  170. //
  171. #define CHECK_CMD_PARTNERCOC (0x00000001)
  172. #define CHECK_CMD_REPLICA (0x00000002)
  173. #define CHECK_CMD_CXTION (0x00000004)
  174. #define CHECK_CMD_JOINGUID (0x00000008)
  175. #define CHECK_CMD_COE (0x00000010)
  176. #define CHECK_CMD_COGUID (0x00000020)
  177. #define CHECK_CMD_NOT_EXPIRED (0x00000040)
  178. #define CHECK_CMD_JOINTIME (0x00000080)
  179. #define CHECK_CMD_REPLICA_VERSION_GUID (0x00000100)
  180. #define CHECK_CMD_CXTION_OK (CHECK_CMD_REPLICA | \
  181. CHECK_CMD_CXTION)
  182. #define CHECK_CMD_CXTION_AND_COGUID_OK (CHECK_CMD_CXTION_OK | \
  183. CHECK_CMD_COGUID)
  184. #define CHECK_CMD_CXTION_AND_JOINGUID_OK (CHECK_CMD_CXTION_OK | \
  185. CHECK_CMD_JOINGUID)
  186. VOID
  187. ChgOrdStartJoinRequest(
  188. IN PREPLICA Replica,
  189. IN PCXTION Cxtion
  190. );
  191. ULONG
  192. OutLogRetireCo(
  193. PREPLICA Replica,
  194. ULONG COx,
  195. PCXTION PartnerCxtion
  196. );
  197. ULONG
  198. OutLogInitPartner(
  199. PREPLICA Replica,
  200. PCXTION PartnerInfo
  201. );
  202. ULONG
  203. RcsForceUnjoin(
  204. IN PREPLICA Replica,
  205. IN PCXTION Cxtion
  206. );
  207. VOID
  208. RcsCreatePerfmonCxtionName(
  209. PREPLICA Replica,
  210. PCXTION Cxtion
  211. );
  212. DWORD
  213. SndCsAssignCommQueue(
  214. VOID
  215. );
  216. VOID
  217. SndCsCreateCxtion(
  218. IN OUT PCXTION Cxtion
  219. );
  220. VOID
  221. SndCsDestroyCxtion(
  222. IN PCXTION Cxtion,
  223. IN DWORD CxtionFlags
  224. );
  225. VOID
  226. SndCsSubmitCommPkt(
  227. IN PREPLICA Replica,
  228. IN PCXTION Cxtion,
  229. IN PCHANGE_ORDER_ENTRY Coe,
  230. IN GUID *JoinGuid,
  231. IN BOOL SetTimeout,
  232. IN PCOMM_PACKET CommPkt,
  233. IN DWORD CommQueueIndex
  234. );
  235. VOID
  236. SndCsSubmitCommPkt2(
  237. IN PREPLICA Replica,
  238. IN PCXTION Cxtion,
  239. IN PCHANGE_ORDER_ENTRY Coe,
  240. IN BOOL SetTimeout,
  241. IN PCOMM_PACKET CommPkt
  242. );
  243. VOID
  244. SndCsSubmitCmd(
  245. IN PREPLICA Replica,
  246. IN PCXTION Cxtion,
  247. IN PCOMMAND_SERVER FlushCs,
  248. IN PCOMMAND_PACKET FlushCmd,
  249. IN DWORD CommQueueIndex
  250. );
  251. VOID
  252. ChgOrdInjectControlCo(
  253. IN PREPLICA Replica,
  254. IN PCXTION Cxtion,
  255. IN ULONG ContentCmd
  256. );
  257. VOID
  258. RcsUpdateReplicaSetMember(
  259. IN PREPLICA Replica
  260. );
  261. VOID
  262. RcsReplicaSetRegistry(
  263. IN PREPLICA Replica
  264. );
  265. VOID
  266. CfgFilesNotToBackup(
  267. IN PGEN_TABLE Replicas
  268. );
  269. DWORD
  270. NtFrsApi_Rpc_BindEx(
  271. IN PWCHAR MachineName,
  272. OUT PWCHAR *OutPrincName,
  273. OUT handle_t *OutHandle,
  274. OUT ULONG *OutParentAuthLevel
  275. );
  276. PWCHAR
  277. FrsDsConvertName(
  278. IN HANDLE Handle,
  279. IN PWCHAR InputName,
  280. IN DWORD InputFormat,
  281. IN PWCHAR DomainDnsName,
  282. IN DWORD DesiredFormat
  283. );
  284. DWORD
  285. UtilRpcServerHandleToAuthSidString(
  286. IN handle_t ServerHandle,
  287. IN PWCHAR AuthClient,
  288. OUT PWCHAR *ClientSid
  289. );
  290. VOID
  291. RcsCloseReplicaSetmember(
  292. IN PREPLICA Replica
  293. );
  294. VOID
  295. RcsCloseReplicaCxtions(
  296. IN PREPLICA Replica
  297. );
  298. ULONG
  299. DbsProcessReplicaFaultList(
  300. PDWORD pReplicaSetsDeleted
  301. );
  302. ULONG
  303. DbsCheckForOverlapErrors(
  304. IN PREPLICA Replica
  305. );
  306. PCOMMAND_PACKET
  307. CommPktToCmd(
  308. IN PCOMM_PACKET CommPkt
  309. );
  310. PCOMM_PACKET
  311. CommBuildCommPkt(
  312. IN PREPLICA Replica,
  313. IN PCXTION Cxtion,
  314. IN ULONG Command,
  315. IN PGEN_TABLE VVector,
  316. IN PCOMMAND_PACKET Cmd,
  317. IN PCHANGE_ORDER_COMMAND Coc
  318. );
  319. BOOL
  320. RcsAreAuthNamesEqual(
  321. IN PWCHAR AuthName1,
  322. IN PWCHAR AuthName2
  323. )
  324. /*++
  325. Routine Description:
  326. Are the two auth names equal?
  327. The principle name comes from an rpc server handle or
  328. from DsCrackName(NT4 ACCOUNT NAME). The formats are
  329. slightly different so this isn't a simple wcsicmp().
  330. The principle name from the server handle has the format
  331. DNS-Domain-Name\ComputerName$.
  332. The principle name from DsCrackName has the format
  333. NetBIOS-Domain-Name\ComputerName$.
  334. The principle name from RpcMgmtInqServerPrincName() has the format
  335. ComputerName$@DNS-Domain-Name
  336. The names may be stringized sids.
  337. Arguments:
  338. AuthName1 - from rpc server handle or DsCrackName()
  339. AuthName2 - from rpc server handle or DsCrackName()
  340. Return Value:
  341. TRUE - the princnames are effectively equal
  342. FALSE - not
  343. --*/
  344. {
  345. #undef DEBSUB
  346. #define DEBSUB "RcsAreAuthNamesEqual:"
  347. BOOL AreEqual = FALSE;
  348. PWCHAR c;
  349. PWCHAR Sam1Begin;
  350. PWCHAR Sam2Begin;
  351. PWCHAR Sam1End;
  352. PWCHAR Sam2End;
  353. PWCHAR Dom1Begin;
  354. PWCHAR Dom2Begin;
  355. PWCHAR Dom1End;
  356. PWCHAR Dom2End;
  357. //
  358. // NULL Param
  359. //
  360. if (!AuthName1 || !AuthName2) {
  361. if (!AuthName1 && !AuthName2) {
  362. AreEqual = TRUE;
  363. goto CLEANUP;
  364. }
  365. goto CLEANUP;
  366. }
  367. //
  368. // principal names are usually in the format domain\samaccount
  369. // or stringized SID
  370. //
  371. if (WSTR_EQ(AuthName1, AuthName2)) {
  372. AreEqual = TRUE;
  373. goto CLEANUP;
  374. }
  375. //
  376. // Find the sam account name and the domain name
  377. //
  378. for (c = AuthName1; *c && *c != L'\\' && *c != L'@'; ++c);
  379. if (*c) {
  380. //
  381. // domain\samaccount
  382. //
  383. if (*c == L'\\') {
  384. Dom1Begin = AuthName1;
  385. Dom1End = c;
  386. Sam1Begin = c + 1;
  387. Sam1End = &AuthName1[wcslen(AuthName1)];
  388. }
  389. //
  390. // samaccount@dnsdomain
  391. //
  392. else {
  393. Sam1Begin = AuthName1;
  394. Sam1End = c;
  395. Dom1Begin = c + 1;
  396. for (; *c && *c != L'.'; ++c);
  397. Dom1End = c;
  398. }
  399. }
  400. //
  401. // Unknown format
  402. //
  403. else {
  404. goto CLEANUP;
  405. }
  406. for (c = AuthName2; *c && *c != L'\\' && *c != L'@'; ++c);
  407. if (*c) {
  408. //
  409. // domain\samaccount
  410. //
  411. if (*c == L'\\') {
  412. Dom2Begin = AuthName2;
  413. Dom2End = c;
  414. Sam2Begin = c + 1;
  415. Sam2End = &AuthName2[wcslen(AuthName2)];
  416. }
  417. //
  418. // samaccount@dnsdomain
  419. //
  420. else {
  421. Sam2Begin = AuthName2;
  422. Sam2End = c;
  423. Dom2Begin = c + 1;
  424. for (; *c && *c != L'.'; ++c);
  425. Dom2End = c;
  426. }
  427. }
  428. //
  429. // Unknown format
  430. //
  431. else {
  432. goto CLEANUP;
  433. }
  434. //
  435. // Compare samaccount
  436. //
  437. while (Sam1Begin != Sam1End && Sam2Begin != Sam2End) {
  438. if (towlower(*Sam1Begin) != towlower(*Sam2Begin)) {
  439. goto CLEANUP;
  440. }
  441. ++Sam1Begin;
  442. ++Sam2Begin;
  443. }
  444. //
  445. // compare domain
  446. //
  447. while (Dom1Begin != Dom1End && Dom2Begin != Dom2End) {
  448. if (towlower(*Dom1Begin) != towlower(*Dom2Begin)) {
  449. goto CLEANUP;
  450. }
  451. ++Dom1Begin;
  452. ++Dom2Begin;
  453. }
  454. AreEqual = (Sam1Begin == Sam1End &&
  455. Sam2Begin == Sam2End &&
  456. Dom1Begin == Dom1End &&
  457. Dom2Begin == Dom2End);
  458. CLEANUP:
  459. DPRINT3(4, "Auth names %ws %s %ws\n",
  460. AuthName1, (AreEqual) ? "==" : "!=", AuthName2);
  461. return AreEqual;
  462. }
  463. PREPLICA
  464. RcsFindReplicaByNumber(
  465. IN ULONG ReplicaNumber
  466. )
  467. /*++
  468. Routine Description:
  469. Find the replica by internal number
  470. Arguments:
  471. ReplicaNumber
  472. Return Value:
  473. Address of the replica or NULL.
  474. --*/
  475. {
  476. #undef DEBSUB
  477. #define DEBSUB "RcsFindReplicaByNumber:"
  478. //
  479. // Find the replica by internal replica number (used in the Jet Table names)
  480. //
  481. return GTabLookup(ReplicasByNumber, &ReplicaNumber, NULL);
  482. }
  483. PREPLICA
  484. RcsFindReplicaByGuid(
  485. IN GUID *Guid
  486. )
  487. /*++
  488. Routine Description:
  489. Find a replica by Guid
  490. Arguments:
  491. Guid - Replica->ReplicaName->Guid
  492. Return Value:
  493. Address of the replica or NULL.
  494. --*/
  495. {
  496. #undef DEBSUB
  497. #define DEBSUB "RcsFindReplicaByGuid:"
  498. //
  499. // Find the replica by guid
  500. //
  501. return GTabLookup(ReplicasByGuid, Guid, NULL);
  502. }
  503. PREPLICA
  504. RcsFindReplicaById(
  505. IN ULONG Id
  506. )
  507. /*++
  508. Routine Description:
  509. Find a replica given the internal ID.
  510. Arguments:
  511. Id - Internal Replica ID.
  512. Return Value:
  513. Address of the replica or NULL.
  514. --*/
  515. {
  516. #undef DEBSUB
  517. #define DEBSUB "RcsFindReplicaById:"
  518. PREPLICA RetVal = NULL;
  519. ForEachListEntry( &ReplicaListHead, REPLICA, ReplicaList,
  520. if (pE->ReplicaNumber == Id) {
  521. RetVal = pE;
  522. break;
  523. }
  524. );
  525. return RetVal;
  526. }
  527. BOOL
  528. RcsCheckCmd(
  529. IN PCOMMAND_PACKET Cmd,
  530. IN PCHAR Debsub,
  531. IN ULONG Flags
  532. )
  533. /*++
  534. Routine Description:
  535. Check the command packet for the specified fields.
  536. Arguments:
  537. Cmd
  538. Hdr
  539. Flags
  540. Return Value:
  541. TRUE - packet is ok
  542. FALSE - not
  543. --*/
  544. {
  545. #undef DEBSUB
  546. #define DEBSUB "RcsCheckCmd:"
  547. BOOL Ret = TRUE;
  548. PREPLICA Replica = RsReplica(Cmd);
  549. CHAR Tstr1[128];
  550. //
  551. // Replica
  552. //
  553. if ((Flags & CHECK_CMD_REPLICA) && !RsReplica(Cmd)) {
  554. DPRINT(0, "WARN - No replica in command packet\n");
  555. FrsCompleteCommand(Cmd, ERROR_INVALID_PARAMETER);
  556. return FALSE;
  557. }
  558. //
  559. // Partner change order command
  560. //
  561. if ((Flags & CHECK_CMD_PARTNERCOC) && !RsPartnerCoc(Cmd)) {
  562. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_PARTNERCOC failed", Debsub);
  563. Tstr1[sizeof(Tstr1)-1] = '\0';
  564. Ret = FALSE;
  565. }
  566. //
  567. // Replica has been (or may be) deleted
  568. //
  569. if ((Flags & CHECK_CMD_NOT_EXPIRED) &&
  570. !IS_TIME_ZERO(RsReplica(Cmd)->MembershipExpires)) {
  571. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_NOT_EXPIRED failed", Debsub);
  572. Tstr1[sizeof(Tstr1)-1] = '\0';
  573. Ret = FALSE;
  574. }
  575. //
  576. // Cxtion
  577. //
  578. if ((Flags & CHECK_CMD_CXTION) &&
  579. !(RsCxtion(Cmd) && RsCxtion(Cmd)->Guid)) {
  580. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_CXTION failed", Debsub);
  581. Tstr1[sizeof(Tstr1)-1] = '\0';
  582. Ret = FALSE;
  583. }
  584. //
  585. // Join guid
  586. //
  587. if ((Flags & CHECK_CMD_JOINGUID) && !RsJoinGuid(Cmd)) {
  588. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_JOINGUID failed", Debsub);
  589. Tstr1[sizeof(Tstr1)-1] = '\0';
  590. Ret = FALSE;
  591. }
  592. //
  593. // Replica Version Guid
  594. //
  595. if ((Flags & CHECK_CMD_REPLICA_VERSION_GUID) &&
  596. !RsReplicaVersionGuid(Cmd)) {
  597. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_REPLICA_VERSION_GUID failed", Debsub);
  598. Tstr1[sizeof(Tstr1)-1] = '\0';
  599. Ret = FALSE;
  600. }
  601. //
  602. // Change order entry
  603. //
  604. if ((Flags & CHECK_CMD_COE) && !RsCoe(Cmd)) {
  605. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_COE failed", Debsub);
  606. Tstr1[sizeof(Tstr1)-1] = '\0';
  607. Ret = FALSE;
  608. }
  609. //
  610. // Change order guid
  611. //
  612. if ((Flags & CHECK_CMD_COGUID) && !RsCoGuid(Cmd)) {
  613. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_COGUID failed", Debsub);
  614. Tstr1[sizeof(Tstr1)-1] = '\0';
  615. Ret = FALSE;
  616. }
  617. //
  618. // Join time
  619. //
  620. if ((Flags & CHECK_CMD_JOINTIME) && !RsJoinTime(Cmd)) {
  621. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CHECK_CMD_JOINTIME failed", Debsub);
  622. Tstr1[sizeof(Tstr1)-1] = '\0';
  623. Ret = FALSE;
  624. }
  625. if (!Ret) {
  626. Tstr1[sizeof(Tstr1)-1] = '\0';
  627. REPLICA_STATE_TRACE(3, Cmd, Replica, ERROR_INVALID_PARAMETER, Tstr1);
  628. FrsCompleteCommand(Cmd, ERROR_INVALID_PARAMETER);
  629. }
  630. return Ret;
  631. }
  632. ULONG
  633. RcsCheckCxtionCommon(
  634. IN PCOMMAND_PACKET Cmd,
  635. IN PCXTION Cxtion,
  636. IN PCHAR Debsub,
  637. IN ULONG Flags,
  638. OUT PFRS_QUEUE *CoProcessQueue
  639. )
  640. /*++
  641. Routine Description:
  642. find the in/outbound cxtion referenced by a command received
  643. from a remote machine.
  644. The caller should have used RcsCheckCmd() with
  645. CHECK_CMD_REPLICA
  646. CHECK_CMD_CXTION
  647. CHECK_CMD_JOINGUID (if CHECK_CXTION_JOINGUID)
  648. before calling this function.
  649. Arguments:
  650. Cmd -- Command packet
  651. Cxtion -- connection struct to be checked.
  652. Debsub
  653. Flags
  654. CoProcessQueue -- return the pointer to the process queue to unidle.
  655. Return Value:
  656. Error status code.
  657. --*/
  658. {
  659. #undef DEBSUB
  660. #define DEBSUB "RcsCheckCxtionCommon:"
  661. PREPLICA Replica = RsReplica(Cmd);
  662. //
  663. // Cxtion exists
  664. //
  665. if ((Flags & CHECK_CXTION_EXISTS) &&
  666. ((Cxtion == NULL) ||
  667. CxtionStateIs(Cxtion, CxtionStateInit))) {
  668. DPRINT2(1, "++ WARN - %s no cxtion for %08x\n", Debsub, Cmd);
  669. return ERROR_INVALID_PARAMETER;
  670. }
  671. //
  672. // Not much purpose in continuing
  673. //
  674. if (!Cxtion) {
  675. return ERROR_INVALID_PARAMETER;
  676. }
  677. //
  678. // Inbound cxtion
  679. //
  680. if ((Flags & CHECK_CXTION_INBOUND) && !Cxtion->Inbound) {
  681. DPRINT2(1, "++ WARN - %s cxtion is not inbound for %08x\n", Debsub, Cmd);
  682. //
  683. // Change order accept better not be waiting for this cxtion.
  684. //
  685. FRS_ASSERT(Cxtion->CoProcessQueue == NULL);
  686. return ERROR_INVALID_PARAMETER;
  687. }
  688. //
  689. // Outbound cxtion
  690. //
  691. if ((Flags & CHECK_CXTION_OUTBOUND) && Cxtion->Inbound) {
  692. DPRINT2(1, "++ WARN - %s cxtion is not outbound for %08x\n", Debsub, Cmd);
  693. return ERROR_INVALID_PARAMETER;
  694. }
  695. //
  696. // Jrnl cxtion
  697. //
  698. if ((Flags & CHECK_CXTION_JRNLCXTION) && !Cxtion->JrnlCxtion) {
  699. DPRINT2(1, "++ WARN - %s cxtion is not jrnlcxtion for %08x\n", Debsub, Cmd);
  700. return ERROR_INVALID_PARAMETER;
  701. }
  702. //
  703. // Version vector
  704. //
  705. if ((Flags & CHECK_CXTION_VVECTOR) && !Cxtion->VVector) {
  706. DPRINT2(1, "++ WARN - %s no version vector for %08x\n", Debsub, Cmd);
  707. return ERROR_INVALID_PARAMETER;
  708. }
  709. //
  710. // Authenticate Partner
  711. //
  712. if ((Flags & CHECK_CXTION_PARTNER)) {
  713. //
  714. // Increment the Authentications counter for
  715. // both the replica set and connection objects
  716. //
  717. PM_INC_CTR_CXTION(Cxtion, Authentications, 1);
  718. PM_INC_CTR_REPSET(Replica, Authentications, 1);
  719. if (
  720. #if DBG
  721. //
  722. // We don't enable authentication when emulating machines
  723. //
  724. !ServerGuid &&
  725. #endif DBG
  726. (Cxtion->PartnerAuthLevel == CXTION_AUTH_KERBEROS_FULL) &&
  727. RunningAsAService &&
  728. #ifdef DS_FREE
  729. (NoDs == FALSE) &&
  730. #endif DS_FREE
  731. (!RcsAreAuthNamesEqual(Cxtion->PartnerSid, RsAuthSid(Cmd)) &&
  732. !RcsAreAuthNamesEqual(Cxtion->PartnerPrincName, RsAuthClient(Cmd)))) {
  733. DPRINT4(1, "++ WARN - %s %08x: PrincName %ws != %ws\n",
  734. Debsub, Cmd, RsAuthClient(Cmd), Cxtion->PartnerPrincName);
  735. DPRINT4(1, "++ WARN - %s %08x: AuthSid %ws != %ws\n",
  736. Debsub, Cmd, RsAuthSid(Cmd), Cxtion->PartnerSid);
  737. return ERROR_INVALID_PARAMETER;
  738. } else {
  739. //
  740. // Increment the Authentications in error counter for
  741. // both the replica set and connection objects
  742. //
  743. PM_INC_CTR_CXTION(Cxtion, AuthenticationsError, 1);
  744. PM_INC_CTR_REPSET(Replica, AuthenticationsError, 1);
  745. }
  746. }
  747. //
  748. // Authentication info
  749. //
  750. if ((Flags & CHECK_CXTION_AUTH)) {
  751. //
  752. // Increment the Authentications counter for
  753. // both the replica set and connection objects
  754. //
  755. PM_INC_CTR_CXTION(Cxtion, Authentications, 1);
  756. PM_INC_CTR_REPSET(Replica, Authentications, 1);
  757. if (
  758. #if DBG
  759. //
  760. // We don't enable authentication when emulating machines
  761. //
  762. !ServerGuid &&
  763. #endif DBG
  764. //
  765. // We don't enable authentication when running in DS_FREE mode.
  766. //
  767. #ifdef DS_FREE
  768. (NoDs == FALSE) &&
  769. #endif DS_FREE
  770. (Cxtion->PartnerAuthLevel == CXTION_AUTH_KERBEROS_FULL) &&
  771. (RsAuthLevel(Cmd) != RPC_C_AUTHN_LEVEL_PKT_PRIVACY ||
  772. (RsAuthN(Cmd) != RPC_C_AUTHN_GSS_KERBEROS &&
  773. RsAuthN(Cmd) != RPC_C_AUTHN_GSS_NEGOTIATE))) {
  774. DPRINT2(1, "++ WARN - %s bad authentication for %08x\n", Debsub, Cmd);
  775. return ERROR_INVALID_PARAMETER;
  776. } else {
  777. //
  778. // Increment the Authentications in error counter for
  779. // both the replica set and connection objects
  780. //
  781. PM_INC_CTR_CXTION(Cxtion, AuthenticationsError, 1);
  782. PM_INC_CTR_REPSET(Replica, AuthenticationsError, 1);
  783. }
  784. }
  785. //
  786. // Fix Join
  787. //
  788. // We may receive change orders after a successful join but
  789. // before we receive the JOINED packet from our inbound
  790. // partner. Fix the JOINED flag if so.
  791. //
  792. if ((Flags & CHECK_CXTION_FIXJOINED) &&
  793. CxtionStateIs(Cxtion, CxtionStateWaitJoin) &&
  794. RsJoinGuid(Cmd) &&
  795. Replica &&
  796. GUIDS_EQUAL(&Cxtion->JoinGuid, RsJoinGuid(Cmd)) &&
  797. CxtionFlagIs(Cxtion, CXTION_FLAGS_JOIN_GUID_VALID)) {
  798. SET_JOINED(Replica, Cxtion, "OOJOINED");
  799. //
  800. // Return the pointer to the process queue to the caller so that the caller
  801. // can unidle the queue after releasing the cxtion lock.
  802. // Never try to lock the process queue when you have the cxtion lock. It will
  803. // result in a deadlock.
  804. //
  805. *CoProcessQueue = Cxtion->CoProcessQueue;
  806. Cxtion->CoProcessQueue = NULL;
  807. SET_UNJOIN_TRIGGER(Cxtion);
  808. }
  809. //
  810. // Joined
  811. //
  812. if ((Flags & CHECK_CXTION_JOINED) &&
  813. !CxtionStateIs(Cxtion, CxtionStateJoined)) {
  814. DPRINT2(1, "++ WARN - %s cxtion is not joined for %08x\n", Debsub, Cmd);
  815. return ERROR_INVALID_PARAMETER;
  816. }
  817. //
  818. // Join guid
  819. //
  820. if ((Flags & CHECK_CXTION_JOINGUID) &&
  821. (!RsJoinGuid(Cmd) ||
  822. !GUIDS_EQUAL(&Cxtion->JoinGuid, RsJoinGuid(Cmd)) ||
  823. !CxtionFlagIs(Cxtion, CXTION_FLAGS_JOIN_GUID_VALID))) {
  824. DPRINT2(1, "++ WARN - %s wrong join guid for %08x\n", Debsub, Cmd);
  825. return ERROR_INVALID_PARAMETER;
  826. }
  827. //
  828. // UnJoin guid
  829. //
  830. if ((Flags & CHECK_CXTION_UNJOINGUID) &&
  831. (!RsJoinGuid(Cmd) ||
  832. !GUIDS_EQUAL(&Cxtion->JoinGuid, RsJoinGuid(Cmd)) ||
  833. !CxtionFlagIs(Cxtion, CXTION_FLAGS_UNJOIN_GUID_VALID))) {
  834. DPRINT2(1, "++ WARN - %s wrong unjoin guid for %08x\n", Debsub, Cmd);
  835. return ERROR_INVALID_PARAMETER;
  836. }
  837. return ERROR_SUCCESS;
  838. }
  839. PCXTION
  840. RcsCheckCxtion(
  841. IN PCOMMAND_PACKET Cmd,
  842. IN PCHAR Debsub,
  843. IN ULONG Flags
  844. )
  845. /*++
  846. Routine Description:
  847. find the in/outbound cxtion referenced by a command received
  848. from a remote machine.
  849. The caller should have used RcsCheckCmd() with
  850. CHECK_CMD_REPLICA
  851. CHECK_CMD_CXTION
  852. CHECK_CMD_JOINGUID (if CHECK_CXTION_JOINGUID)
  853. before calling this function.
  854. Complete the command with an error if a specified check fails.
  855. Arguments:
  856. Cmd
  857. Debsub
  858. Flags
  859. Return Value:
  860. Address of the cxtion or NULL.
  861. --*/
  862. {
  863. #undef DEBSUB
  864. #define DEBSUB "RcsCheckCxtion:"
  865. PCXTION Cxtion;
  866. PREPLICA Replica = RsReplica(Cmd);
  867. ULONG WStatus;
  868. CHAR Tstr1[64];
  869. PFRS_QUEUE CoProcessQueue = NULL;
  870. //
  871. // Lock the connection table to sync with INLOG and OUTLOG access.
  872. //
  873. LOCK_CXTION_TABLE(Replica);
  874. //
  875. // Find the cxtion and check it.
  876. //
  877. Cxtion = GTabLookupNoLock(Replica->Cxtions, RsCxtion(Cmd)->Guid, NULL);
  878. WStatus = RcsCheckCxtionCommon(Cmd, Cxtion, Debsub, Flags, &CoProcessQueue);
  879. UNLOCK_CXTION_TABLE(Replica);
  880. //
  881. // If RcsCheckCxtionCommon wanted us to unidle the process queue then do it here
  882. // after releasing the cxtion lock.
  883. //
  884. UNIDLE_CO_PROCESS_QUEUE(Replica, Cxtion, CoProcessQueue);
  885. //
  886. // If check not successfull then complete the command with an error.
  887. //
  888. if (!WIN_SUCCESS(WStatus)) {
  889. //
  890. // The join command packet is being rejected; Clear the reference.
  891. //
  892. _snprintf(Tstr1, sizeof(Tstr1), "W, %s CheckCxtion failed", Debsub);
  893. Tstr1[sizeof(Tstr1)-1] = '\0';
  894. REPLICA_STATE_TRACE(3, Cmd, Replica, WStatus, Tstr1);
  895. if (Cxtion && Cxtion->JoinCmd == Cmd) {
  896. Cxtion->JoinCmd = NULL;
  897. }
  898. //
  899. // Do not complete the command if the check is being made for the
  900. // fetch command server.
  901. //
  902. if (!BooleanFlagOn(Flags, CHECK_CXTION_FOR_FETCHCS)) {
  903. FrsCompleteCommand(Cmd, WStatus);
  904. }
  905. return NULL;
  906. }
  907. //
  908. // Check is successful. Return the Cxtion.
  909. //
  910. return Cxtion;
  911. }
  912. VOID
  913. RcsJoinCxtionLater(
  914. IN PREPLICA Replica,
  915. IN PCXTION Cxtion,
  916. IN PCOMMAND_PACKET Cmd
  917. )
  918. /*++
  919. Routine Description:
  920. Check on the join status of the cxtion occasionally. Restart the join
  921. process if needed. The cxtion contains the retry timeout.
  922. Cmd contains enough info to get back to the replica\cxtion.
  923. Arguments:
  924. Replica
  925. Cxtion
  926. Cmd
  927. Return Value:
  928. None.
  929. --*/
  930. {
  931. #undef DEBSUB
  932. #define DEBSUB "RcsJoinCxtionLater:"
  933. ULONG Timeout;
  934. //
  935. // There is already a join command packet in the works; done
  936. //
  937. if (Cxtion->JoinCmd) {
  938. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  939. return;
  940. }
  941. Cxtion->JoinCmd = Cmd;
  942. Cmd->Command = CMD_JOIN_CXTION;
  943. //
  944. // Stop retrying after a while, but not too long or too short.
  945. //
  946. RsTimeout(Cmd) += MinJoinRetry;
  947. if ((LONG)RsTimeout(Cmd) < MinJoinRetry) {
  948. RsTimeout(Cmd) = MinJoinRetry;
  949. }
  950. if ((LONG)RsTimeout(Cmd) > MaxJoinRetry) {
  951. RsTimeout(Cmd) = MaxJoinRetry;
  952. }
  953. //
  954. // Add in the penalty from failed rpc calls, but not too long or too short.
  955. //
  956. Timeout = RsTimeout(Cmd) + Cxtion->Penalty;
  957. if ((LONG)Timeout < MinJoinRetry) {
  958. Timeout = MinJoinRetry;
  959. }
  960. if ((LONG)Timeout > MaxJoinRetry) {
  961. Timeout = MaxJoinRetry;
  962. }
  963. //
  964. // Inform the user that the join is taking a long time.
  965. // The user receives no notification if a join occurs in
  966. // a short time.
  967. //
  968. // A trigger scheduled cxtion will stop retrying once the
  969. // trigger interval goes off (usually in 15 minutes).
  970. //
  971. if (!(RsTimeout(Cmd) % (JOIN_RETRY_EVENT * MinJoinRetry))) {
  972. if (Cxtion->Inbound) {
  973. EPRINT4(EVENT_FRS_LONG_JOIN, Cxtion->Partner->Name, ComputerName,
  974. Replica->Root, Cxtion->PartnerDnsName);
  975. } else {
  976. EPRINT4(EVENT_FRS_LONG_JOIN, ComputerName, Cxtion->Partner->Name,
  977. Replica->Root, Cxtion->PartnerDnsName);
  978. }
  979. }
  980. //
  981. // This command will come back to us in a bit
  982. //
  983. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, Timeout);
  984. }
  985. VOID
  986. RcsJoinCxtion(
  987. IN PCOMMAND_PACKET Cmd
  988. )
  989. /*++
  990. Routine Description:
  991. Kick off the commands needed to join with our in/outbound partners.
  992. Joining an inbound partner is a two step process. First, we pass a
  993. command to the inbound log process to allow it to scan the inbound log
  994. for any change orders from this connection. These change orders are
  995. inserted on the CO process queue so we preserve ordering with new change
  996. orders that arrive after the Join completes. In addtion we extract the
  997. the sequence number and change order ID of the last change order we have
  998. pending from this inbound partner. Second, we send the join request to
  999. the inbound partner. This same path is taken whether this is a clean
  1000. startup or a startup after a crash.
  1001. JOINING:
  1002. UNJOINED -> UNJOINED ask our partner if it is alive
  1003. UNJOINED -> START our partner responded
  1004. START -> STARTING call ChgOrdStartJoinRequest()
  1005. STARTING -> SCANNING (when chgord starts inlog scan)
  1006. SCANNING -> SENDJOIN (when chgord completes inlog scan)
  1007. SENDJOIN -> WAITJOIN (when join sent to partner)
  1008. WAITJOIN -> JOINED (when partner responds)
  1009. UNJOINING
  1010. STARTING |
  1011. SCANNING |
  1012. SENDJOIN |
  1013. WAITJOIN -> UNJOINING (wait for remote change orders to retry)
  1014. UNJOINING -> UNJOINED (no more remote change orders)
  1015. UNJOINED -> DELETED (cxtion has been deleted)
  1016. Arguments:
  1017. Replica -- ptr to the Replica struct
  1018. Cxtion -- ptr to the connection struct we are talking to.
  1019. Return Value:
  1020. True if if ReJoin is needed.
  1021. --*/
  1022. {
  1023. #undef DEBSUB
  1024. #define DEBSUB "RcsJoinCxtion:"
  1025. PREPLICA Replica;
  1026. PCXTION Cxtion;
  1027. PCOMM_PACKET CPkt;
  1028. ULONG CmdCode;
  1029. DWORD CQIndex;
  1030. //
  1031. // Check the command packet
  1032. //
  1033. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK)) {
  1034. return;
  1035. }
  1036. Replica = RsReplica(Cmd);
  1037. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsJoinCxtion entry1");
  1038. //
  1039. // Find and check the cxtion
  1040. //
  1041. Cxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS);
  1042. if (!Cxtion) {
  1043. return;
  1044. }
  1045. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, RcsJoinCxtion entry2");
  1046. //
  1047. // This is our periodic join command packet
  1048. // - clear the reference
  1049. // - Ignore if the cxtion has successfully joined;
  1050. // our partner will inform us if there is a state change.
  1051. // - ignore if the replica set is in seeding state and this
  1052. // connection has been paused by the initial sync command server.
  1053. //
  1054. if (Cxtion->JoinCmd == Cmd) {
  1055. Cxtion->JoinCmd = NULL;
  1056. if ((CxtionStateIs(Cxtion, CxtionStateJoined) &&
  1057. !CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN)) ||
  1058. (BooleanFlagOn(Replica->CnfFlags,CONFIG_FLAG_SEEDING) &&
  1059. CxtionFlagIs(Cxtion,CXTION_FLAGS_PAUSED))) {
  1060. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1061. return;
  1062. }
  1063. }
  1064. //
  1065. // Don't bother joining if the service is shutting down
  1066. //
  1067. if (FrsIsShuttingDown) {
  1068. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1069. return;
  1070. }
  1071. //
  1072. // Get lock to sync with change order accept
  1073. //
  1074. LOCK_CXTION_TABLE(Replica);
  1075. switch (GetCxtionState(Cxtion)) {
  1076. case CxtionStateInit:
  1077. //
  1078. // Not setup, yet. Ignore
  1079. //
  1080. DPRINT1(4, ":X: Cxtion isn't inited at join: "FORMAT_CXTION_PATH2"\n",
  1081. PRINT_CXTION_PATH2(Replica, Cxtion));
  1082. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1083. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1084. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1085. SetCxtionState(Cxtion, CxtionStateDeleted);
  1086. }
  1087. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1088. break;
  1089. case CxtionStateUnjoined:
  1090. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1091. //
  1092. // Cxtion is deleted; nevermind
  1093. //
  1094. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1095. SetCxtionState(Cxtion, CxtionStateDeleted);
  1096. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1097. break;
  1098. }
  1099. //
  1100. // Schedule is off; nevermind
  1101. //
  1102. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  1103. DPRINT1(4, ":X: Schedule is off at join: "FORMAT_CXTION_PATH2"\n",
  1104. PRINT_CXTION_PATH2(Replica, Cxtion));
  1105. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1106. break;
  1107. }
  1108. //
  1109. // Replica is deleted; nevermind
  1110. //
  1111. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  1112. DPRINT1(4, ":S: Replica deleted at join: "FORMAT_CXTION_PATH2"\n",
  1113. PRINT_CXTION_PATH2(Replica, Cxtion));
  1114. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1115. break;
  1116. }
  1117. //
  1118. // Send our join info to our inbound partner or request an outbound
  1119. // partner to start a join. Don't send anything if this is the
  1120. // journal cxtion.
  1121. //
  1122. // Do not join with a downstream partner if this replica is still
  1123. // seeding and is not online.
  1124. //
  1125. if (Cxtion->Inbound) {
  1126. if (Cxtion->JrnlCxtion) {
  1127. DPRINT1(4, "DO NOT Send CMD_START_JOIN to jrnl cxtion: "FORMAT_CXTION_PATH2"\n",
  1128. PRINT_CXTION_PATH2(Replica, Cxtion));
  1129. } else {
  1130. DPRINT1(4, ":X: Send CMD_NEED_JOIN to inbound: "FORMAT_CXTION_PATH2"\n",
  1131. PRINT_CXTION_PATH2(Replica, Cxtion));
  1132. }
  1133. } else {
  1134. if ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  1135. Replica->IsSeeding) &&
  1136. !BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  1137. DPRINT1(4, ":X: DO NOT Send CMD_START_JOIN until we are Online: "FORMAT_CXTION_PATH2"\n",
  1138. PRINT_CXTION_PATH2(Replica, Cxtion));
  1139. } else {
  1140. DPRINT1(4, ":X: Send CMD_START_JOIN to outbound: "FORMAT_CXTION_PATH2"\n",
  1141. PRINT_CXTION_PATH2(Replica, Cxtion));
  1142. }
  1143. }
  1144. //
  1145. // Journal cxtions transition from unjoined to joined w/o
  1146. // any intervening states UNLESS someone adds code at
  1147. // this point to activate the journal for this set. But
  1148. // that would require a rewrite of the journal startup
  1149. // subsystem. Which may happen...
  1150. //
  1151. if (Cxtion->JrnlCxtion) {
  1152. DPRINT1(0, ":X: ***** JOINED "FORMAT_CXTION_PATH2"\n",
  1153. PRINT_CXTION_PATH2(Replica, Cxtion));
  1154. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, JOINED");
  1155. SetCxtionState(Cxtion, CxtionStateJoined);
  1156. SndCsCreateCxtion(Cxtion);
  1157. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1158. break;
  1159. }
  1160. //
  1161. // Do not join with a downstream partner if this replica is still
  1162. // seeding and is not online. Do not send a join if this
  1163. // is a journal cxtion. Do not join if there is already an
  1164. // active join request outstanding.
  1165. //
  1166. // The SndCs and the ReplicaCs cooperate to limit the
  1167. // number of active join "pings" so that the Snd threads
  1168. // are not hung waiting for pings to dead servers to
  1169. // time out.
  1170. //
  1171. if (!Cxtion->ActiveJoinCommPkt &&
  1172. !Cxtion->JrnlCxtion &&
  1173. (Cxtion->Inbound ||
  1174. BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE) ||
  1175. (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  1176. !Replica->IsSeeding))) {
  1177. //
  1178. // Increment the Join Notifications sent counter for
  1179. // both the replica set and connection objects
  1180. //
  1181. PM_INC_CTR_CXTION(Cxtion, JoinNSent, 1);
  1182. PM_INC_CTR_REPSET(Replica, JoinNSent, 1);
  1183. //
  1184. // Assign a comm queue if none has been assigned. A cxtion
  1185. // must use the same comm queue for a given session (join guid)
  1186. // to maintain packet order. Old packets have an invalid join
  1187. // guid and are either not sent or ignored on the receiving side.
  1188. //
  1189. if (!Cxtion->CommQueueIndex) {
  1190. Cxtion->CommQueueIndex = SndCsAssignCommQueue();
  1191. }
  1192. //
  1193. // Partner is considered slow-to-respond if the last
  1194. // rpc calls are erroring off and their cumulative
  1195. // timeouts are greater than MinJoinRetry.
  1196. //
  1197. // BUT, Don't reassign the cxtion's queue index because,
  1198. // if this is an outbound cxtion, the flush-at-join
  1199. // logic needs to know the old queue index so that it
  1200. // flushes the correct queue.
  1201. //
  1202. CQIndex = Cxtion->CommQueueIndex;
  1203. if ((LONG)Cxtion->Penalty > MinJoinRetry) {
  1204. CQIndex = 0;
  1205. }
  1206. CmdCode = (Cxtion->Inbound) ? CMD_NEED_JOIN : CMD_START_JOIN;
  1207. CPkt = CommBuildCommPkt(Replica, Cxtion, CmdCode, NULL, NULL, NULL);
  1208. //
  1209. // The SndCs and the ReplicaCs cooperate to limit the
  1210. // number of active join "pings" so that the Snd threads
  1211. // are not hung waiting for pings to dead servers to
  1212. // time out.
  1213. //
  1214. Cxtion->ActiveJoinCommPkt = CPkt;
  1215. SndCsSubmitCommPkt(Replica, Cxtion, NULL, NULL, FALSE, CPkt, CQIndex);
  1216. }
  1217. //
  1218. // Keep trying an inbound cxtion but try the outbound connection
  1219. // only once. The outbound partner will keep trying the join and
  1220. // the connection will eventually join.
  1221. //
  1222. if (Cxtion->Inbound) {
  1223. RcsJoinCxtionLater(Replica, Cxtion, Cmd);
  1224. } else {
  1225. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1226. }
  1227. break;
  1228. case CxtionStateStart:
  1229. //
  1230. // Unjoined and our partner has responed; start the join
  1231. //
  1232. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1233. //
  1234. // Cxtion is deleted; nevermind
  1235. //
  1236. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1237. SetCxtionState(Cxtion, CxtionStateDeleted);
  1238. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1239. break;
  1240. }
  1241. //
  1242. // Schedule is off; nevermind
  1243. //
  1244. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  1245. DPRINT1(4, ":X: Schedule is off at join: "FORMAT_CXTION_PATH2"\n",
  1246. PRINT_CXTION_PATH2(Replica, Cxtion));
  1247. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1248. break;
  1249. }
  1250. //
  1251. // Replica is deleted; nevermind
  1252. //
  1253. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  1254. DPRINT1(4, ":X: Replica deleted at join: "FORMAT_CXTION_PATH2"\n",
  1255. PRINT_CXTION_PATH2(Replica, Cxtion));
  1256. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1257. break;
  1258. }
  1259. if (Cxtion->Inbound) {
  1260. //
  1261. // Tell the inbound log subsystem to initialize for a Join with
  1262. // an inbound partner. When it begins processing the request it
  1263. // sets the state to STARTING. When it completes it sets the
  1264. // state to SENDJOIN and sends a CMD_JOIN_CXTION command.
  1265. //
  1266. // We need our join guid at this time because the change
  1267. // orders are stamped with the join guid during change order
  1268. // accept. Mismatched joinguids result in a unjoin-with-
  1269. // retry call so that old change orders can drain out
  1270. // of change order accept and into the replica command
  1271. // server after a cxtion is unjoined and joined again.
  1272. //
  1273. SetCxtionState(Cxtion, CxtionStateStarting);
  1274. SndCsCreateCxtion(Cxtion);
  1275. //
  1276. // ** DEADLOCK WARNING **
  1277. // The connection table lock must be unlocked before the request is
  1278. // put on the change order process queue. This is because the
  1279. // change order accept thread locks the process queue while it is
  1280. // considering the issue state of the head entry. If the CO it is
  1281. // trying to issue is for a connection being restarted it will wait
  1282. // until the cxtion starts otherwise the subsequent fetch request by
  1283. // the CO would just fail. While change_order_accept has the queue
  1284. // lock it then acquires the cxtion table lock. Thus two threads
  1285. // are acquiring two locks in different orders causing deadlock.
  1286. //
  1287. UNLOCK_CXTION_TABLE(Replica);
  1288. ChgOrdStartJoinRequest(Replica, Cxtion);
  1289. LOCK_CXTION_TABLE(Replica);
  1290. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1291. }
  1292. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1293. break;
  1294. case CxtionStateStarting:
  1295. case CxtionStateScanning:
  1296. //
  1297. // Join in process; our inbound partner will be informed later
  1298. //
  1299. DPRINT1(4, ":X: Scanning at join: "FORMAT_CXTION_PATH2"\n",
  1300. PRINT_CXTION_PATH2(Replica, Cxtion));
  1301. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1302. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1303. break;
  1304. case CxtionStateSendJoin:
  1305. case CxtionStateWaitJoin:
  1306. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1307. //
  1308. // Replica is deleted,
  1309. // The cxtion needs to be unjoined, or
  1310. // The cxtion needs to be deleted
  1311. // Unjoin
  1312. //
  1313. if (!IS_TIME_ZERO(Replica->MembershipExpires) ||
  1314. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN) ||
  1315. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1316. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  1317. break;
  1318. }
  1319. //
  1320. // Send our join info to our inbound partner
  1321. //
  1322. // This request times out if our partner doesn't answer.
  1323. //
  1324. DPRINT1(4, ":X: Send join info at send/wait join: "FORMAT_CXTION_PATH2"\n",
  1325. PRINT_CXTION_PATH2(Replica, Cxtion));
  1326. SetCxtionState(Cxtion, CxtionStateWaitJoin);
  1327. //
  1328. // Increment the Join Notifications sent counter for
  1329. // both the replica set and connection objects
  1330. //
  1331. PM_INC_CTR_CXTION(Cxtion, JoinNSent, 1);
  1332. PM_INC_CTR_REPSET(Replica, JoinNSent, 1);
  1333. CPkt = CommBuildCommPkt(Replica, Cxtion, CMD_JOINING, Replica->VVector, NULL, NULL);
  1334. SndCsSubmitCommPkt2(Replica, Cxtion, NULL, TRUE, CPkt);
  1335. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1336. break;
  1337. case CxtionStateJoined:
  1338. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1339. //
  1340. // Replica is deleted,
  1341. // The cxtion needs to be unjoined, or
  1342. // The cxtion needs to be deleted
  1343. // Unjoin
  1344. //
  1345. if (!IS_TIME_ZERO(Replica->MembershipExpires) ||
  1346. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN) ||
  1347. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  1348. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  1349. break;
  1350. }
  1351. //
  1352. // Refresh our inbound partner's join state (with timeout)
  1353. //
  1354. if (Cxtion->Inbound && !Cxtion->JrnlCxtion) {
  1355. DPRINT1(4, ":X: send join info at join: "FORMAT_CXTION_PATH2"\n",
  1356. PRINT_CXTION_PATH2(Replica, Cxtion));
  1357. //
  1358. // Increment the Join Notifications sent counter for
  1359. // both the replica set and connection objects
  1360. //
  1361. PM_INC_CTR_CXTION(Cxtion, JoinNSent, 1);
  1362. PM_INC_CTR_REPSET(Replica, JoinNSent, 1);
  1363. CPkt = CommBuildCommPkt(Replica, Cxtion, CMD_JOINING, Replica->VVector, NULL, NULL);
  1364. SndCsSubmitCommPkt2(Replica, Cxtion, NULL, TRUE, CPkt);
  1365. }
  1366. //
  1367. // Already joined; nothing to do
  1368. //
  1369. DPRINT1(4, ":X: Joined at join: "FORMAT_CXTION_PATH2"\n",
  1370. PRINT_CXTION_PATH2(Replica, Cxtion));
  1371. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1372. break;
  1373. case CxtionStateUnjoining:
  1374. //
  1375. // Ignore requests to join while unjoining so that we don't
  1376. // end up with multiple inbound log scans. If this join
  1377. // request originated from our partner then the caller
  1378. // will set the CXTION_FLAGS_DEFERRED_JOIN and the join
  1379. // will start at the transition from UNJOINING to UNJOINED.
  1380. //
  1381. DPRINT1(4, ":X: Unjoining at join: "FORMAT_CXTION_PATH2"\n",
  1382. PRINT_CXTION_PATH2(Replica, Cxtion));
  1383. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1384. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1385. break;
  1386. case CxtionStateDeleted:
  1387. //
  1388. // Deleted; nothing to do
  1389. //
  1390. DPRINT1(4, ":X: Cxtion is deleted at join: "FORMAT_CXTION_PATH2"\n",
  1391. PRINT_CXTION_PATH2(Replica, Cxtion));
  1392. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  1393. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  1394. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1395. break;
  1396. default:
  1397. //
  1398. // ?
  1399. //
  1400. DPRINT2(0, ":X: ERROR - bad state %d for "FORMAT_CXTION_PATH2"\n",
  1401. GetCxtionState(Cxtion),
  1402. PRINT_CXTION_PATH2(Replica, Cxtion));
  1403. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1404. break;
  1405. }
  1406. UNLOCK_CXTION_TABLE(Replica);
  1407. }
  1408. VOID
  1409. RcsEmptyPreExistingDir(
  1410. IN PREPLICA Replica
  1411. )
  1412. /*++
  1413. Routine Description:
  1414. Delete empty directories in the preexisting directory, inclusive.
  1415. WARN: The replica set must be filtering the preexisting directory.
  1416. Arguments:
  1417. Replica - The replica is filtering the preexisting directory.
  1418. Return Value:
  1419. None.
  1420. --*/
  1421. {
  1422. #undef DEBSUB
  1423. #define DEBSUB "RcsEmptyPreExistingDir:"
  1424. ULONG WStatus;
  1425. PWCHAR PreExistingPath = NULL;
  1426. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, RcsEmptyPreExistingDir entry");
  1427. //
  1428. // Not if the set isn't open
  1429. //
  1430. if (!Replica->IsOpen) {
  1431. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, RcsEmptyPreExistingDir: not open");
  1432. return;
  1433. }
  1434. //
  1435. // Not if the set isn't journaling
  1436. //
  1437. if (!Replica->IsJournaling) {
  1438. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, RcsEmptyPreExistingDir: not journaling");
  1439. return;
  1440. }
  1441. //
  1442. // Empty the preexisting directory (continue on error)
  1443. //
  1444. PreExistingPath = FrsWcsPath(Replica->Root, NTFRS_PREEXISTING_DIRECTORY);
  1445. WStatus = FrsDeletePath(PreExistingPath,
  1446. ENUMERATE_DIRECTORY_FLAGS_ERROR_CONTINUE |
  1447. ENUMERATE_DIRECTORY_FLAGS_DIRECTORIES_ONLY);
  1448. DPRINT1_WS(3, "++ ERROR - FrsDeletePath(%ws) (IGNORED);", PreExistingPath, WStatus);
  1449. REPLICA_STATE_TRACE(3, NULL, Replica, WStatus, "W, RcsEmptyPreExistingDir: done");
  1450. FrsFree(PreExistingPath);
  1451. }
  1452. VOID
  1453. RcsOpenReplicaSetMember(
  1454. IN PREPLICA Replica
  1455. )
  1456. /*++
  1457. Routine Description:
  1458. Open a replica set.
  1459. Arguments:
  1460. Replica -- ptr to a REPLICA struct
  1461. Return Value:
  1462. None.
  1463. --*/
  1464. {
  1465. #undef DEBSUB
  1466. #define DEBSUB "RcsOpenReplicaSetMember:"
  1467. ULONG WStatus;
  1468. PCOMMAND_PACKET Cmd = NULL;
  1469. Replica->FStatus = FrsErrorSuccess;
  1470. if (Replica->IsOpen) {
  1471. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Replica already open");
  1472. return;
  1473. }
  1474. //
  1475. // Submit an open
  1476. //
  1477. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  1478. Replica, // Replica,
  1479. CMD_OPEN_REPLICA_SET_MEMBER, // CmdRequest,
  1480. NULL, // TableCtx,
  1481. NULL, // CallContext,
  1482. 0, // TableType,
  1483. 0, // AccessRequest,
  1484. 0, // IndexType,
  1485. NULL, // KeyValue,
  1486. 0, // KeyValueLength,
  1487. FALSE); // Submit
  1488. //
  1489. // Don't free the packet when the command completes.
  1490. //
  1491. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  1492. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "Submit DB OPEN_REPLICA_SET_MEMBER");
  1493. //
  1494. // SUBMIT DB Cmd and wait for completion.
  1495. //
  1496. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  1497. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  1498. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, OPEN_REPLICA_SET_MEMBER return");
  1499. //
  1500. // If wait or database op failed
  1501. //
  1502. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  1503. //
  1504. // If wait / submit failed then let caller know cmd srv submit failed.
  1505. //
  1506. if (FRS_SUCCESS(Replica->FStatus)) {
  1507. Replica->FStatus = FrsErrorCmdSrvFailed;
  1508. }
  1509. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Open Replica failed;",
  1510. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  1511. DPRINT_WS(0, "ERROR: Open Replica DB Command failed", WStatus);
  1512. goto out;
  1513. }
  1514. Replica->IsOpen = FRS_SUCCESS(Replica->FStatus);
  1515. out:
  1516. if (Cmd) {
  1517. FrsFreeCommand(Cmd, NULL);
  1518. }
  1519. }
  1520. VOID
  1521. RcsInitOneReplicaSet(
  1522. IN PREPLICA Replica
  1523. )
  1524. /*++
  1525. Routine Description:
  1526. Open a replica set.
  1527. Arguments:
  1528. Replica -- ptr to a REPLICA struct
  1529. Return Value:
  1530. None.
  1531. --*/
  1532. {
  1533. #undef DEBSUB
  1534. #define DEBSUB "RcsInitOneReplicaSet:"
  1535. ULONG FStatus;
  1536. //
  1537. // Already journaling; done
  1538. //
  1539. if (Replica->IsJournaling) {
  1540. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, IsJournaling True");
  1541. return;
  1542. }
  1543. if (!Replica->IsOpen) {
  1544. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, IsOpen False");
  1545. return;
  1546. }
  1547. //
  1548. // Don't retry if in journal wrap error state error
  1549. //
  1550. if (Replica->ServiceState == REPLICA_STATE_JRNL_WRAP_ERROR) {
  1551. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, In Jrnl Wrap Error State");
  1552. return;
  1553. }
  1554. //
  1555. // Otherwise set it to the initializing state.
  1556. //
  1557. if (REPLICA_IN_ERROR_STATE(Replica->ServiceState)) {
  1558. JrnlSetReplicaState(Replica, REPLICA_STATE_INITIALIZING);
  1559. }
  1560. //
  1561. // Don't start journaling if the preinstall directory is unavailable
  1562. //
  1563. if (!HANDLE_IS_VALID(Replica->PreInstallHandle)) {
  1564. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, No PreInstallHandle");
  1565. return;
  1566. }
  1567. //
  1568. // Initialize the DB and Journal subsystems for this replica set.
  1569. //
  1570. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, DbsInitOneReplicaSet call");
  1571. FStatus = DbsInitOneReplicaSet(Replica);
  1572. REPLICA_STATE_TRACE(3, NULL, Replica, FStatus, "F, DbsInitOneReplicaSet return");
  1573. }
  1574. VOID
  1575. RcsJoiningAfterFlush(
  1576. IN PCOMMAND_PACKET Cmd
  1577. )
  1578. /*++
  1579. Routine Description:
  1580. A downstream partner (X) sent this JOINING request to us. We are its
  1581. inbound partner. We should have a corresponding outbound connection
  1582. for X. If we do and the replication schedule allows we activate the
  1583. outbound log partner and ack the Joining request with CMD_JOINED.
  1584. This command packet was first placed on the SndCs's queue by
  1585. RcsJoining() so that all of the old comm packets with the
  1586. old join guid have been discarded. This protocol is needed because
  1587. this function may REJOIN and revalidate the old join guid. Packets
  1588. still on the send queue would then be sent out of order.
  1589. NOTE:
  1590. Activating the OUTLOG partner before sending the JOINED cmd to the partner
  1591. can cause COs to be sent to the partner before it sees the JOINED cmd.
  1592. Since the JoinGuid matches in the sent change orders the partner accepts
  1593. them and queues them to the change order process queue. If this CO gets to
  1594. the head of the process queue the issue logic in ChgOrdAccept will
  1595. block the queue waiting for the connection to go to the JOINED state. When
  1596. the JOINED cmd arrives it is processed by RcsInboundJoined() which sets the
  1597. connection state to JOINED and unblocks the change order process queue.
  1598. We can't send the JOINED cmd first because the partner may then send back
  1599. a fetch request before we think it has joined. The JOINED cmd must always
  1600. be sent so the partner knows it can start sending fetch cmds because we
  1601. may have no outbound COs to send. In addtion the JOINED command contains
  1602. the new value for LastJoinedTime that is saved in the connection record
  1603. for the next join request.
  1604. NOTE:
  1605. Cxtion activation should always come from the downstream partner. Only they
  1606. know if a VVJoin is required because of a database re-init or restore.
  1607. Otherwise we will just continue sending from the last unacked CO in the log.
  1608. At best we can notify outbound partners we are now available to provide
  1609. change orders (via CMD_JOIN_RESEND)
  1610. Arguments:
  1611. Cmd
  1612. Return Value:
  1613. None.
  1614. --*/
  1615. {
  1616. #undef DEBSUB
  1617. #define DEBSUB "RcsJoiningAfterFlush:"
  1618. ULONGLONG Delta;
  1619. ULONG FStatus;
  1620. PREPLICA Replica;
  1621. PCXTION OutCxtion;
  1622. PCOMM_PACKET CPkt;
  1623. #define CXTION_STR_MAX 256
  1624. WCHAR CxtionStr[CXTION_STR_MAX];
  1625. WCHAR WSkew[15], WDelta[15];
  1626. CHAR UpstreamTimeStr[TIME_STRING_LENGTH];
  1627. CHAR DownstreamTimeStr[TIME_STRING_LENGTH];
  1628. PVOID Key;
  1629. PGEN_ENTRY Entry;
  1630. //
  1631. // Check the command packet
  1632. //
  1633. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK |
  1634. CHECK_CMD_REPLICA_VERSION_GUID |
  1635. CHECK_CMD_JOINTIME |
  1636. CHECK_CMD_NOT_EXPIRED)) {
  1637. return;
  1638. }
  1639. Replica = RsReplica(Cmd);
  1640. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsJoiningAfterFlush entry");
  1641. //
  1642. // Find and check the cxtion
  1643. //
  1644. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  1645. CHECK_CXTION_OUTBOUND |
  1646. CHECK_CXTION_PARTNER |
  1647. CHECK_CXTION_AUTH);
  1648. if (!OutCxtion) {
  1649. return;
  1650. }
  1651. //
  1652. // Shutting down; ignore join request
  1653. //
  1654. if (FrsIsShuttingDown) {
  1655. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, FrsIsShuttingDown");
  1656. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  1657. return;
  1658. }
  1659. //
  1660. // Do not join with a downstream partner if this replica is still
  1661. // seeding and is not online.
  1662. //
  1663. if ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  1664. Replica->IsSeeding) &&
  1665. !BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  1666. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Seeding and Offline");
  1667. FrsCompleteCommand(Cmd, ERROR_RETRY);
  1668. return;
  1669. }
  1670. //
  1671. // Already joined; should we rejoin?
  1672. //
  1673. if (CxtionStateIs(OutCxtion, CxtionStateJoined)) {
  1674. //
  1675. // Don't rejoin if this is a retry by our outbound partner
  1676. //
  1677. if (GUIDS_EQUAL(&OutCxtion->JoinGuid, RsJoinGuid(Cmd)) &&
  1678. CxtionFlagIs(OutCxtion, CXTION_FLAGS_JOIN_GUID_VALID)) {
  1679. //
  1680. // Tell our outbound partner that we have rejoined successfully
  1681. // Increment the Joins counter for
  1682. // both the replica set and connection objects
  1683. //
  1684. PM_INC_CTR_CXTION(OutCxtion, Joins, 1);
  1685. PM_INC_CTR_REPSET(Replica, Joins, 1);
  1686. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, REJOINED");
  1687. DPRINT1(0, ":X: ***** REJOINED "FORMAT_CXTION_PATH2"\n",
  1688. PRINT_CXTION_PATH2(Replica, OutCxtion));
  1689. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_JOINED, NULL, NULL, NULL);
  1690. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  1691. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1692. return;
  1693. }
  1694. //
  1695. // Unjoin and rejoin. Partner may have restarted.
  1696. // WARN: forcing an unjoin of an outbound cxtion works
  1697. // because outbound cxtions transition from Joined to
  1698. // Unjoined with no intervening states.
  1699. //
  1700. FStatus = RcsForceUnjoin(Replica, OutCxtion);
  1701. CXTION_STATE_TRACE(3, OutCxtion, Replica, FStatus, "F, RcsForceUnjoin return");
  1702. if (!FRS_SUCCESS(FStatus)) {
  1703. DPRINT_FS(0, ":X: ERROR - return from RcsForceUnjoin:", FStatus);
  1704. FrsCompleteCommand(Cmd, ERROR_REQUEST_ABORTED);
  1705. return;
  1706. }
  1707. }
  1708. //
  1709. // Machines can't join if their times are badly out of sync
  1710. // UNLESS this is a VOLATILE cxtion (I.e., sysvol seeding).
  1711. //
  1712. // Compare the time when the packet was built by our partner and the time
  1713. // when we received the packet.
  1714. // Time in 100nsec tics since Jan 1, 1601
  1715. //
  1716. if (*RsCommPktRcvTime(Cmd) > *RsJoinTime(Cmd)) {
  1717. Delta = *RsCommPktRcvTime(Cmd) - *RsJoinTime(Cmd);
  1718. } else {
  1719. Delta = *RsJoinTime(Cmd) - *RsCommPktRcvTime(Cmd);
  1720. }
  1721. //
  1722. // Ignore out-of-sync times if this is a volatile cxtion. Volatile
  1723. // cxtions are only used for sysvol seeding where times don't matter.
  1724. //
  1725. if (!CxtionFlagIs(OutCxtion, CXTION_FLAGS_VOLATILE) &&
  1726. (Delta > MaxPartnerClockSkew)) {
  1727. Delta = Delta / CONVERT_FILETIME_TO_MINUTES;
  1728. DPRINT1(0, ":X: ERROR - Joining CommPkt receive time is %08x %08x\n", PRINTQUAD(*RsCommPktRcvTime(Cmd)));
  1729. DPRINT1(0, ":X: ERROR - Joining CommPkt send time on partner is %08x %08x\n", PRINTQUAD(*RsJoinTime(Cmd)));
  1730. _snwprintf(CxtionStr, CXTION_STR_MAX, FORMAT_CXTION_PATH2W,
  1731. PRINT_CXTION_PATH2(Replica, OutCxtion));
  1732. CxtionStr[CXTION_STR_MAX-1] = UNICODE_NULL;
  1733. _itow(PartnerClockSkew, WSkew, 10);
  1734. _itow((LONG)Delta, WDelta, 10);
  1735. EPRINT3(EVENT_FRS_JOIN_FAIL_TIME_SKEW, WSkew, CxtionStr, WDelta);
  1736. DPRINT2(0, ":X: ERROR - Cannot join (%ws) clocks are out of sync by %d minutes\n",
  1737. CxtionStr, (LONG)Delta);
  1738. DPRINT(0, ":X: Note: If this time difference is close to a multiple of 60 minutes then it\n");
  1739. DPRINT(0, ":X: is likely that either this computer or its partner computer was set to the\n");
  1740. DPRINT(0, ":X: incorrect time zone when the computer time was initially set. Check that both \n");
  1741. DPRINT(0, ":X: the time zones and the time is set correctly on both computers.\n");
  1742. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  1743. return;
  1744. }
  1745. //
  1746. // Grab the new version vector. Initialize an empty version vector
  1747. // if our outbound partner did not send a version vector. Our partner
  1748. // simply does not yet have any entries in his version vector.
  1749. //
  1750. OutCxtion->VVector = (RsVVector(Cmd) != NULL) ?
  1751. RsVVector(Cmd) : GTabAllocTable();
  1752. RsVVector(Cmd) = NULL;
  1753. //
  1754. // Grab the compression table from the outbound partner.
  1755. // This table is a list of guids 1 for each compression format that
  1756. // the partner supports.
  1757. //
  1758. OutCxtion->CompressionTable = (RsCompressionTable(Cmd) != NULL) ?
  1759. RsCompressionTable(Cmd) : GTabAllocTable();
  1760. DPRINT1(4, "Received following compression table from %ws.\n", OutCxtion->PartnerDnsName);
  1761. GTabLockTable(OutCxtion->CompressionTable);
  1762. Key = NULL;
  1763. while (Entry = GTabNextEntryNoLock(OutCxtion->CompressionTable, &Key)) {
  1764. FrsPrintGuid(Entry->Key1);
  1765. }
  1766. GTabUnLockTable(OutCxtion->CompressionTable);
  1767. RsCompressionTable(Cmd) = NULL;
  1768. //
  1769. // Assign the join guid and comm queue to this cxtion.
  1770. //
  1771. DPRINT1(4, ":X: %ws: Assigning join guid.\n", OutCxtion->Name->Name);
  1772. COPY_GUID(&OutCxtion->JoinGuid, RsJoinGuid(Cmd));
  1773. SetCxtionFlag(OutCxtion, CXTION_FLAGS_JOIN_GUID_VALID |
  1774. CXTION_FLAGS_UNJOIN_GUID_VALID);
  1775. //
  1776. // Assign a comm queue. A cxtion must use the same comm queue
  1777. // for a given session (join guid) to maintain packet order.
  1778. // Old packets have an invalid join guid and are either not
  1779. // sent or ignored on the receiving side.
  1780. //
  1781. OutCxtion->CommQueueIndex = SndCsAssignCommQueue();
  1782. VV_PRINT_OUTBOUND(4, OutCxtion->Partner->Name, OutCxtion->VVector);
  1783. //
  1784. // Use the last join time to check if the connection is a new connection.
  1785. // If the connection on upstream or the connection on downstream is new
  1786. // then force a vvjoin. Upstream may have deleted the connection because
  1787. // the downstream did not join for a week (Outlog change history time).
  1788. // When the database on downstream or upstream is restored both will have
  1789. // valid times but we want a vvjoin at that time. We don't support restoring
  1790. // old FRS database so we will not worry about that scenario here.
  1791. // We used to just compare LastJoinTimes and force vvjoin if they didn't
  1792. // match but that can result in unnecessary vvjoins. (Customer reported problem)
  1793. //
  1794. // For E.g. If the upstream crashed when it was in this function at the point
  1795. // where it had initialized a new LastJoinTime but before it sent the CMD_JOINED
  1796. // packet to the downstream then when the downstream joins later LastJoinTime
  1797. // will not match and a vvjoin will be performed unnecessarily.
  1798. //
  1799. FileTimeToString((PFILETIME) &OutCxtion->LastJoinTime, UpstreamTimeStr);
  1800. FileTimeToString((PFILETIME) &RsLastJoinTime(Cmd), DownstreamTimeStr);
  1801. CXTION_STATE_TRACE(4, OutCxtion, Replica, 0, "LastJoinTime Check");
  1802. DPRINT2(4, ":X: Upstream (This Computer) LastJoinTime = %s ; Downstream LastJoinTime = %s\n", UpstreamTimeStr,DownstreamTimeStr);
  1803. if ((RsLastJoinTime(Cmd) == (ULONGLONG) 1) ||
  1804. (OutCxtion->LastJoinTime == (ULONGLONG) 1)) {
  1805. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, LastJoinTime Mismatch, force VVJoin");
  1806. SetCxtionFlag(OutCxtion, CXTION_FLAGS_PERFORM_VVJOIN);
  1807. }
  1808. //
  1809. // Our partner's replica version guid (aka originator guid) used
  1810. // for dampening requests to our partner.
  1811. //
  1812. COPY_GUID(&OutCxtion->ReplicaVersionGuid, RsReplicaVersionGuid(Cmd));
  1813. //
  1814. // REPLICA JOINED
  1815. //
  1816. SetCxtionState(OutCxtion, CxtionStateJoined);
  1817. //
  1818. // Inform the user that a long join has finally completed.
  1819. // The user receives no notification if a join occurs in a short time.
  1820. //
  1821. if (OutCxtion->JoinCmd &&
  1822. (LONG)RsTimeout(OutCxtion->JoinCmd) > (JOIN_RETRY_EVENT * MinJoinRetry)) {
  1823. if (OutCxtion->Inbound) {
  1824. EPRINT3(EVENT_FRS_LONG_JOIN_DONE,
  1825. OutCxtion->Partner->Name, ComputerName, Replica->Root);
  1826. } else {
  1827. EPRINT3(EVENT_FRS_LONG_JOIN_DONE,
  1828. ComputerName, OutCxtion->Partner->Name, Replica->Root);
  1829. }
  1830. }
  1831. //
  1832. // Tell the Outbound Log that this partner has joined. This call is synchronous.
  1833. //
  1834. #if DBG
  1835. //
  1836. // Always VvJoin
  1837. if (DebugInfo.ForceVvJoin) {
  1838. SetCxtionFlag(OutCxtion, CXTION_FLAGS_PERFORM_VVJOIN);
  1839. }
  1840. #endif DBG
  1841. FStatus = OutLogSubmit(Replica, OutCxtion, CMD_OUTLOG_ACTIVATE_PARTNER);
  1842. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, OUTLOG_ACTIVATE_PARTNER return");
  1843. if (!FRS_SUCCESS(FStatus)) {
  1844. //
  1845. // Could not enable outbound log processing for this cxtion
  1846. //
  1847. DPRINT_FS(0, "++ ERROR - return from CMD_OUTLOG_ACTIVATE_PARTNER:", FStatus);
  1848. RcsForceUnjoin(Replica, OutCxtion);
  1849. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  1850. return;
  1851. }
  1852. //
  1853. // OUTBOUND LOG PROCESSING HAS BEEN ENABLED
  1854. //
  1855. //
  1856. // Tell our outbound partner that we are ready to go.
  1857. //
  1858. // WARN: comm packets may have already been sent to our partner once we
  1859. // activated outlog processing above. In that case, our partner treated
  1860. // the packet as an implicit CMD_JOINED and completed the join. This
  1861. // packet is then ignored as an extraneous join request except that it
  1862. // causes our partner to update the last joined time to match ours.
  1863. //
  1864. // Increment the Joins counter for
  1865. // both the replica set and connection objects
  1866. //
  1867. PM_INC_CTR_CXTION(OutCxtion, Joins, 1);
  1868. PM_INC_CTR_REPSET(Replica, Joins, 1);
  1869. DPRINT1(0, ":X: ***** JOINED "FORMAT_CXTION_PATH2"\n",
  1870. PRINT_CXTION_PATH2(Replica, OutCxtion));
  1871. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, JOINED");
  1872. //
  1873. // Update the DB cxtion table record with the new Join Time.
  1874. //
  1875. // *NOTE* The following call is synchronous. If we have the Cxtion
  1876. // table lock then a hang is possible.
  1877. //
  1878. GetSystemTimeAsFileTime((PFILETIME)&OutCxtion->LastJoinTime);
  1879. InterlockedIncrement(&Replica->OutLogCxtionsJoined);
  1880. DPRINT1(4, "TEMP: OutLogCxtionsJoined %d\n", Replica->OutLogCxtionsJoined);
  1881. FStatus = OutLogSubmit(Replica, OutCxtion, CMD_OUTLOG_UPDATE_PARTNER);
  1882. CXTION_STATE_TRACE(3, OutCxtion, Replica, FStatus, "F, OUTLOG_UPDATE_PARTNER return");
  1883. if (!FRS_SUCCESS(FStatus)) {
  1884. DPRINT3(0, "++ WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  1885. OutCxtion->Name->Name, OutCxtion->Partner->Name, Replica->ReplicaName->Name);
  1886. }
  1887. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Cxtion JOINED, xmit resp");
  1888. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_JOINED, NULL, NULL, NULL);
  1889. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  1890. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1891. //
  1892. // Inject a end-of-opt-vvjoin control co if this cxtion is in the
  1893. // OptVVJoinMode. This co is used to send a fake vvjoindone to downstream
  1894. // so it can transition out of initsync state.
  1895. //
  1896. OutLogAcquireLock(Replica);
  1897. if ((OutCxtion->OLCtx != NULL) && InOptVVJoinMode(OutCxtion->OLCtx)) {
  1898. ChgOrdInjectControlCo(Replica, OutCxtion, FCN_CO_END_OF_OPTIMIZED_VVJOIN);
  1899. }
  1900. //
  1901. // Inject a end-of-join control co if this cxtion is using a trigger
  1902. // schedule. Note that the EndOfJoin Co may have been processed by
  1903. // the time this call returns.
  1904. //
  1905. if (CxtionFlagIs(OutCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  1906. if (OutCxtion->OLCtx &&
  1907. !InVVJoinMode(OutCxtion->OLCtx) &&
  1908. CxtionStateIs(OutCxtion, CxtionStateJoined)) {
  1909. ChgOrdInjectControlCo(Replica, OutCxtion, FCN_CO_END_OF_JOIN);
  1910. }
  1911. }
  1912. OutLogReleaseLock(Replica);
  1913. }
  1914. VOID
  1915. RcsJoining(
  1916. IN PCOMMAND_PACKET Cmd
  1917. )
  1918. /*++
  1919. Routine Description:
  1920. A downstream partner (X) sent this JOINING request to us. We are its
  1921. inbound partner. We should have a corresponding outbound connection
  1922. for X. If we do and the replication schedule allows we activate the
  1923. outbound log partner and ack the Joining request with CMD_JOINED.
  1924. This command packet is first put on the SndCs's(Send Command Server)
  1925. queue so that all of the old comm packets with the old join guid
  1926. will have been discarded. This protocol is needed because this
  1927. function may REJOIN and revalidate the old join guid. Packets
  1928. still on the send queue would then be sent out of order.
  1929. The command packet is sent to RcsJoiningAfterFlush() after
  1930. bubbling up to the top of the send queue.
  1931. Arguments:
  1932. Cmd
  1933. Return Value:
  1934. None.
  1935. --*/
  1936. {
  1937. #undef DEBSUB
  1938. #define DEBSUB "RcsJoining:"
  1939. ULONG FStatus;
  1940. PREPLICA Replica;
  1941. PCXTION OutCxtion;
  1942. PCOMM_PACKET CPkt;
  1943. //
  1944. // Check the command packet
  1945. //
  1946. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK |
  1947. CHECK_CMD_REPLICA_VERSION_GUID |
  1948. CHECK_CMD_JOINTIME |
  1949. CHECK_CMD_NOT_EXPIRED)) {
  1950. return;
  1951. }
  1952. Replica = RsReplica(Cmd);
  1953. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsJoining entry");
  1954. //
  1955. // Find and check the cxtion
  1956. //
  1957. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  1958. CHECK_CXTION_OUTBOUND |
  1959. CHECK_CXTION_PARTNER |
  1960. CHECK_CXTION_AUTH);
  1961. if (!OutCxtion) {
  1962. return;
  1963. }
  1964. //
  1965. // Increment the Join Notifications Received counter for
  1966. // both the replica set and connection objects
  1967. //
  1968. PM_INC_CTR_CXTION(OutCxtion, JoinNRcvd, 1);
  1969. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  1970. //
  1971. // Shutting down; ignore join request
  1972. //
  1973. if (FrsIsShuttingDown) {
  1974. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  1975. return;
  1976. }
  1977. //
  1978. // Do not join with a downstream partner if this replica is still
  1979. // seeding and is not online.
  1980. //
  1981. if ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  1982. Replica->IsSeeding) &&
  1983. !BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  1984. FrsCompleteCommand(Cmd, ERROR_RETRY);
  1985. return;
  1986. }
  1987. //
  1988. // Put this command packet at the end of this cxtion's send queue. Once it
  1989. // bubbles up to the top the command packet will be sent back to this
  1990. // command server with the ccommand CMD_JOINING_AFTER_FLUSH and will be
  1991. // given to RcsJoiningAfterFlush() for processing.
  1992. //
  1993. Cmd->Command = CMD_JOINING_AFTER_FLUSH;
  1994. SndCsSubmitCmd(Replica,
  1995. OutCxtion,
  1996. &ReplicaCmdServer,
  1997. Cmd,
  1998. OutCxtion->CommQueueIndex);
  1999. }
  2000. VOID
  2001. RcsNeedJoin(
  2002. IN PCOMMAND_PACKET Cmd
  2003. )
  2004. /*++
  2005. Routine Description:
  2006. Our outbound partner has sent this packet to see if we are alive.
  2007. Respond with a start-your-join packet.
  2008. Arguments:
  2009. Cmd
  2010. Return Value:
  2011. None.
  2012. --*/
  2013. {
  2014. #undef DEBSUB
  2015. #define DEBSUB "RcsNeedJoin:"
  2016. PREPLICA Replica;
  2017. PCXTION OutCxtion;
  2018. PCOMM_PACKET CPkt;
  2019. DWORD CQIndex;
  2020. //
  2021. // Check the command packet
  2022. //
  2023. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA |
  2024. CHECK_CMD_CXTION |
  2025. CHECK_CMD_NOT_EXPIRED)) {
  2026. return;
  2027. }
  2028. Replica = RsReplica(Cmd);
  2029. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsNeedJoin entry");
  2030. //
  2031. // Find and check the cxtion
  2032. //
  2033. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  2034. CHECK_CXTION_OUTBOUND |
  2035. CHECK_CXTION_PARTNER |
  2036. CHECK_CXTION_AUTH);
  2037. if (!OutCxtion) {
  2038. return;
  2039. }
  2040. //
  2041. // Increment the Join Notifications Received counter for
  2042. // both the replica set and connection objects
  2043. //
  2044. PM_INC_CTR_CXTION(OutCxtion, JoinNRcvd, 1);
  2045. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  2046. //
  2047. // Do not join with a downstream partner if this replica is still
  2048. // seeding and is not online.
  2049. //
  2050. if ((!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  2051. !Replica->IsSeeding) ||
  2052. BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  2053. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Xmit START_JOIN req");
  2054. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_START_JOIN, NULL, NULL, NULL);
  2055. CQIndex = OutCxtion->CommQueueIndex;
  2056. SndCsSubmitCommPkt(Replica, OutCxtion, NULL, NULL, FALSE, CPkt, CQIndex);
  2057. }
  2058. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2059. }
  2060. VOID
  2061. RcsStartJoin(
  2062. IN PCOMMAND_PACKET Cmd
  2063. )
  2064. /*++
  2065. Routine Description:
  2066. Our inbound partner has sent this packet to tell us it is alive
  2067. and that the join can be started.
  2068. Arguments:
  2069. Cmd
  2070. Return Value:
  2071. None.
  2072. --*/
  2073. {
  2074. #undef DEBSUB
  2075. #define DEBSUB "RcsStartJoin:"
  2076. PREPLICA Replica;
  2077. PCXTION InCxtion;
  2078. //
  2079. // Check the command packet
  2080. //
  2081. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA |
  2082. CHECK_CMD_CXTION |
  2083. CHECK_CMD_NOT_EXPIRED)) {
  2084. return;
  2085. }
  2086. Replica = RsReplica(Cmd);
  2087. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsStartJoin entry");
  2088. //
  2089. // Find and check the cxtion
  2090. //
  2091. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  2092. CHECK_CXTION_INBOUND |
  2093. CHECK_CXTION_PARTNER |
  2094. CHECK_CXTION_AUTH);
  2095. if (!InCxtion) {
  2096. return;
  2097. }
  2098. //
  2099. // Increment the Join Notifications Received counter for
  2100. // both the replica set and connection objects
  2101. //
  2102. PM_INC_CTR_CXTION(InCxtion, JoinNRcvd, 1);
  2103. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  2104. //
  2105. // If this replica set is in seeding state and this connection is in
  2106. // initial sync state then let the initial sync command server decide
  2107. // how to respond to this START_JOIN. It will respond to one START_JOIN
  2108. // at a time.
  2109. //
  2110. if (BooleanFlagOn(Replica->CnfFlags,CONFIG_FLAG_SEEDING) &&
  2111. CxtionFlagIs(InCxtion,CXTION_FLAGS_INIT_SYNC)) {
  2112. InitSyncCsSubmitTransfer(Cmd, CMD_INITSYNC_START_JOIN);
  2113. return;
  2114. }
  2115. LOCK_CXTION_TABLE(Replica);
  2116. //
  2117. // If we were waiting for our partner to respond or think we
  2118. // have already joined then either start the join process or
  2119. // resend our join info.
  2120. //
  2121. // Otherwise, let the normal join flow take over. If there are
  2122. // problems then the join will timeout and retry.
  2123. //
  2124. if (CxtionStateIs(InCxtion, CxtionStateUnjoined) ||
  2125. CxtionStateIs(InCxtion, CxtionStateJoined)) {
  2126. if (CxtionStateIs(InCxtion, CxtionStateUnjoined)) {
  2127. SetCxtionState(InCxtion, CxtionStateStart);
  2128. }
  2129. //
  2130. // Start the join process or resend the join info
  2131. //
  2132. UNLOCK_CXTION_TABLE(Replica);
  2133. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, RcsJoinCxtion call");
  2134. RcsJoinCxtion(Cmd);
  2135. } else {
  2136. UNLOCK_CXTION_TABLE(Replica);
  2137. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Cannot start join");
  2138. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2139. }
  2140. }
  2141. VOID
  2142. RcsSubmitReplicaCxtionJoin(
  2143. IN PREPLICA Replica,
  2144. IN PCXTION Cxtion,
  2145. IN BOOL Later
  2146. )
  2147. /*++
  2148. Routine Description:
  2149. Submit a join command to a replica\cxtion.
  2150. Build cmd pkt with Cxtion GName and replica ptr. Submit to Replica cmd
  2151. server. Calls dispatch function and translates cxtion GName to cxtion ptr
  2152. SYNCHRONIZATION -- Only called from the context of the
  2153. Replica Command Server. No locks needed.
  2154. Arguments:
  2155. Replica - existing replica
  2156. Cxtion - existing cxtion
  2157. Later - Delayed submission
  2158. Return Value:
  2159. None.
  2160. --*/
  2161. {
  2162. #undef DEBSUB
  2163. #define DEBSUB "RcsSubmitReplicaCxtionJoin:"
  2164. PCOMMAND_PACKET Cmd;
  2165. //
  2166. // The cxtion already has a join command outstanding; don't flood the
  2167. // queue with extraneous requests.
  2168. //
  2169. if (Cxtion->JoinCmd) {
  2170. return;
  2171. }
  2172. //
  2173. // Not scheduled to run
  2174. //
  2175. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  2176. return;
  2177. }
  2178. //
  2179. // Already joined; done
  2180. //
  2181. if (CxtionStateIs(Cxtion, CxtionStateJoined) &&
  2182. !CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN)) {
  2183. return;
  2184. }
  2185. //
  2186. // Trigger schedules are managed by RcsCheckSchedules()
  2187. //
  2188. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  2189. return;
  2190. }
  2191. //
  2192. // Allocate a command packet
  2193. //
  2194. Cmd = FrsAllocCommand(Replica->Queue, CMD_JOIN_CXTION);
  2195. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  2196. //
  2197. // Address of replica set and new replica set
  2198. //
  2199. RsReplica(Cmd) = Replica;
  2200. RsCxtion(Cmd) = FrsDupGName(Cxtion->Name);
  2201. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, RcsSubmitReplicaCxtionJoin entry");
  2202. //
  2203. // Cxtion should have just one join command outstanding
  2204. //
  2205. if (Later) {
  2206. DPRINT5(4, "++ Submit LATER %08x for Cmd %08x %ws\\%ws\\%ws\n",
  2207. Cmd->Command, Cmd, Replica->SetName->Name,
  2208. Replica->MemberName->Name, Cxtion->Name->Name);
  2209. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, RcsJoinCxtionLater call");
  2210. RcsJoinCxtionLater(Replica, Cxtion, Cmd);
  2211. } else {
  2212. Cxtion->JoinCmd = Cmd;
  2213. DPRINT5(4, "++ Submit %08x for Cmd %08x %ws\\%ws\\%ws\n",
  2214. Cmd->Command, Cmd, Replica->SetName->Name,
  2215. Replica->MemberName->Name, Cxtion->Name->Name);
  2216. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Submit JOIN_CXTION req");
  2217. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  2218. }
  2219. }
  2220. ULONG
  2221. RcsResubmitActiveCOsOnCxtion(
  2222. IN PREPLICA Replica,
  2223. IN PCXTION Cxtion
  2224. )
  2225. /*++
  2226. Routine Description:
  2227. Remove the active change orders from this connection and resubmit them.
  2228. This is done when downstream notices that the upstream has rejoined.
  2229. It may have dropped a fetch request that we send causing us to hang for ever.
  2230. Assumes: Caller has acquired the CXTION_TABLE lock.
  2231. Arguments:
  2232. Replica - ptr to replica struct for this replica set.
  2233. Cxtion - ptr to connection struct being unjoined.
  2234. Return Value:
  2235. FrsErrorStatus
  2236. --*/
  2237. {
  2238. #undef DEBSUB
  2239. #define DEBSUB "RcsResubmitActiveCOsOnCxtion:"
  2240. PVOID Key;
  2241. PCHANGE_ORDER_ENTRY Coe;
  2242. //
  2243. // Take idle change orders through retry
  2244. //
  2245. LOCK_CXTION_COE_TABLE(Replica, Cxtion);
  2246. Key = NULL;
  2247. while (Coe = GTabNextDatumNoLock(Cxtion->CoeTable, &Key)) {
  2248. if (CO_FLAG_ON(Coe, CO_FLAG_LOCALCO)) {
  2249. CHANGE_ORDER_TRACE(3, Coe, "Do not ReSubmit Local COs");
  2250. } else {
  2251. FRS_ASSERT(CO_STATE_IS_LE(Coe, IBCO_FETCH_RETRY));
  2252. CHANGE_ORDER_TRACE(3, Coe, "ReSubmit CO to fetch");
  2253. Key = NULL;
  2254. GTabDeleteNoLock(Cxtion->CoeTable, &Coe->Cmd.ChangeOrderGuid, NULL, NULL);
  2255. RcsSubmitRemoteCoAccepted(Coe);
  2256. }
  2257. }
  2258. UNLOCK_CXTION_COE_TABLE(Replica, Cxtion);
  2259. return FrsErrorSuccess;
  2260. }
  2261. ULONG
  2262. RcsDrainActiveCOsOnCxtion(
  2263. IN PREPLICA Replica,
  2264. IN PCXTION Cxtion
  2265. )
  2266. /*++
  2267. Routine Description:
  2268. Remove the active change orders from this connection and send them
  2269. thru retry.
  2270. Assumes: Caller has acquired the CXTION_TABLE lock.
  2271. Arguments:
  2272. Replica - ptr to replica struct for this replica set.
  2273. Cxtion - ptr to connection struct being unjoined.
  2274. Return Value:
  2275. FrsErrorStatus
  2276. --*/
  2277. {
  2278. #undef DEBSUB
  2279. #define DEBSUB "RcsDrainActiveCOsOnCxtion:"
  2280. PVOID Key;
  2281. PCHANGE_ORDER_ENTRY Coe;
  2282. ULONG FStatus = FrsErrorSuccess;
  2283. //
  2284. // Take idle change orders through retry
  2285. //
  2286. LOCK_CXTION_COE_TABLE(Replica, Cxtion);
  2287. Key = NULL;
  2288. while (Coe = GTabNextDatumNoLock(Cxtion->CoeTable, &Key)) {
  2289. Key = NULL;
  2290. GTabDeleteNoLock(Cxtion->CoeTable, &Coe->Cmd.ChangeOrderGuid, NULL, NULL);
  2291. SET_COE_FLAG(Coe, COE_FLAG_NO_INBOUND);
  2292. if (Cxtion->JrnlCxtion) {
  2293. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to stage gen retry");
  2294. ChgOrdInboundRetry(Coe, IBCO_STAGING_RETRY);
  2295. } else {
  2296. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to fetch retry");
  2297. ChgOrdInboundRetry(Coe, IBCO_FETCH_RETRY);
  2298. }
  2299. }
  2300. UNLOCK_CXTION_COE_TABLE(Replica, Cxtion);
  2301. //
  2302. // If there are no outstanding change orders that need to be taken through the
  2303. // retry path, unjoin complete. Otherwise, the unjoin will complete once
  2304. // the count reaches 0. Until then, further attempts to join will be
  2305. // ignored.
  2306. //
  2307. if (Cxtion->ChangeOrderCount == 0) {
  2308. SndCsDestroyCxtion(Cxtion, CXTION_FLAGS_UNJOIN_GUID_VALID);
  2309. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2310. //
  2311. // Increment the Unjoins counter for
  2312. // both the replica set and connection objects
  2313. //
  2314. PM_INC_CTR_CXTION(Cxtion, Unjoins, 1);
  2315. PM_INC_CTR_REPSET(Replica, Unjoins, 1);
  2316. DPRINT1(0, ":X: ***** UNJOINED "FORMAT_CXTION_PATH2"\n",
  2317. PRINT_CXTION_PATH2(Replica, Cxtion));
  2318. //
  2319. // Deleted cxtion
  2320. //
  2321. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2322. SetCxtionState(Cxtion, CxtionStateDeleted);
  2323. //
  2324. // Rejoin if requested.
  2325. //
  2326. } else if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_JOIN)) {
  2327. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  2328. RcsSubmitReplicaCxtionJoin(Replica, Cxtion, TRUE);
  2329. }
  2330. } else {
  2331. FStatus = FrsErrorUnjoining;
  2332. DPRINT2(0, ":X: ***** UNJOINING "FORMAT_CXTION_PATH2" (%d cos)\n",
  2333. PRINT_CXTION_PATH2(Replica, Cxtion), Cxtion->ChangeOrderCount);
  2334. }
  2335. return FStatus;
  2336. }
  2337. ULONG
  2338. RcsForceUnjoin(
  2339. IN PREPLICA Replica,
  2340. IN PCXTION Cxtion
  2341. )
  2342. /*++
  2343. Routine Description:
  2344. Unjoin this connection.
  2345. Arguments:
  2346. Replica - ptr to replica struct for this replica set.
  2347. Cxtion - ptr to connection struct being unjoined.
  2348. Return Value:
  2349. FrsErrorStatus
  2350. --*/
  2351. {
  2352. #undef DEBSUB
  2353. #define DEBSUB "RcsForceUnjoin:"
  2354. ULONG FStatus = FrsErrorSuccess;
  2355. CHAR GuidStr[GUID_CHAR_LEN + 1];
  2356. PFRS_QUEUE CoProcessQueue = NULL;
  2357. //
  2358. // Get the table lock to sync with change order accept and the
  2359. // inbound log scanner. The outbound log process uses different
  2360. // state to control its own processing.
  2361. //
  2362. LOCK_CXTION_TABLE(Replica);
  2363. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->Flags, "Flags, RcsForceUnjoin entry");
  2364. switch (GetCxtionState(Cxtion)) {
  2365. case CxtionStateInit:
  2366. //
  2367. // ?
  2368. //
  2369. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2370. //
  2371. // Deleted cxtion
  2372. //
  2373. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2374. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2375. SetCxtionState(Cxtion, CxtionStateDeleted);
  2376. }
  2377. break;
  2378. case CxtionStateUnjoined:
  2379. //
  2380. // Unidle the change order process queue if it is blocked.
  2381. //
  2382. CoProcessQueue = Cxtion->CoProcessQueue;
  2383. Cxtion->CoProcessQueue = NULL;
  2384. //
  2385. // Unjoined; nothing to do
  2386. //
  2387. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2388. //
  2389. // Deleted cxtion
  2390. //
  2391. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2392. SetCxtionState(Cxtion, CxtionStateDeleted);
  2393. }
  2394. break;
  2395. case CxtionStateStart:
  2396. //
  2397. // Unidle the change order process queue if it is blocked.
  2398. //
  2399. CoProcessQueue = Cxtion->CoProcessQueue;
  2400. Cxtion->CoProcessQueue = NULL;
  2401. //
  2402. // Haven't had a chance to start; nothing to do
  2403. //
  2404. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2405. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2406. //
  2407. // Deleted cxtion
  2408. //
  2409. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) {
  2410. SetCxtionState(Cxtion, CxtionStateDeleted);
  2411. }
  2412. break;
  2413. case CxtionStateUnjoining:
  2414. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2415. //
  2416. // Take idle change orders through retry
  2417. //
  2418. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->ChangeOrderCount,
  2419. "COs, A-Send Idle COs to retry");
  2420. //
  2421. // Unidle the change order process queue if it is blocked.
  2422. //
  2423. CoProcessQueue = Cxtion->CoProcessQueue;
  2424. Cxtion->CoProcessQueue = NULL;
  2425. RcsDrainActiveCOsOnCxtion(Replica, Cxtion);
  2426. break;
  2427. case CxtionStateStarting:
  2428. case CxtionStateScanning:
  2429. //
  2430. // Wait for the inbound scan to finish. The change order retry
  2431. // thread or the change order accept thread will eventually unjoin us.
  2432. //
  2433. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2434. FStatus = FrsErrorUnjoining;
  2435. break;
  2436. case CxtionStateSendJoin:
  2437. case CxtionStateWaitJoin:
  2438. case CxtionStateJoined:
  2439. //
  2440. // Once we destroy our join guid, future remote change
  2441. // orders will be discarded by the replica command server
  2442. // before they show up on the change order process queue.
  2443. //
  2444. // This works because the replica command server is
  2445. // single threaded per replica; any packets received during
  2446. // this function have been enqueued for later processing.
  2447. //
  2448. // The outlog process may attempt to send change orders
  2449. // if this is an outbound cxtion but they will bounce
  2450. // because the join guid is incorrect.
  2451. //
  2452. //
  2453. // Invalidate our join guid
  2454. //
  2455. SndCsDestroyCxtion(Cxtion, 0);
  2456. SetCxtionState(Cxtion, CxtionStateUnjoining);
  2457. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2458. if (Cxtion->Inbound) {
  2459. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->ChangeOrderCount,
  2460. "COs, B-Send Idle COs to retry");
  2461. //
  2462. // Unidle the change order process queue if it is blocked.
  2463. //
  2464. CoProcessQueue = Cxtion->CoProcessQueue;
  2465. Cxtion->CoProcessQueue = NULL;
  2466. RcsDrainActiveCOsOnCxtion(Replica, Cxtion);
  2467. } else {
  2468. //
  2469. // Tell the vvjoin command server to stop
  2470. // Tell outlog process to Unjoin from this partner.
  2471. // The call is synchronous so drop the lock around the call.
  2472. //
  2473. if (Cxtion->OLCtx != NULL) {
  2474. UNLOCK_CXTION_TABLE(Replica);
  2475. SubmitVvJoinSync(Replica, Cxtion, CMD_VVJOIN_DONE_UNJOIN);
  2476. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_DEACTIVATE_PARTNER);
  2477. if (!FRS_SUCCESS(FStatus)) {
  2478. DPRINT1_FS(0, ":X: ERROR - %ws: Can't deactivate at unjoin;",
  2479. Cxtion->Name->Name, FStatus);
  2480. }
  2481. LOCK_CXTION_TABLE(Replica);
  2482. }
  2483. //
  2484. // Free the outbound version vector, if present
  2485. //
  2486. Cxtion->VVector = VVFreeOutbound(Cxtion->VVector);
  2487. //
  2488. // Invalidate the un/join guid
  2489. //
  2490. SndCsDestroyCxtion(Cxtion, CXTION_FLAGS_UNJOIN_GUID_VALID);
  2491. SetCxtionState(Cxtion, CxtionStateUnjoined);
  2492. //
  2493. // Increment the Unjoins counter for
  2494. // both the replica set and connection objects
  2495. //
  2496. PM_INC_CTR_CXTION(Cxtion, Unjoins, 1);
  2497. PM_INC_CTR_REPSET(Replica, Unjoins, 1);
  2498. DPRINT1(0, ":X: ***** UNJOINED "FORMAT_CXTION_PATH2"\n",
  2499. PRINT_CXTION_PATH2(Replica, Cxtion));
  2500. //
  2501. // :SP1: Volatile connection cleanup.
  2502. //
  2503. // Deleted cxtion or outbound volatile connection. Volatile
  2504. // connection gets deleted after the first time it UNJOINS.
  2505. //
  2506. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE) ||
  2507. VOLATILE_OUTBOUND_CXTION(Cxtion)) {
  2508. SetCxtionState(Cxtion, CxtionStateDeleted);
  2509. //
  2510. // Rejoin
  2511. //
  2512. } else if (CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_JOIN)) {
  2513. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  2514. RcsSubmitReplicaCxtionJoin(Replica, Cxtion, TRUE);
  2515. }
  2516. }
  2517. break;
  2518. case CxtionStateDeleted:
  2519. //
  2520. // Unidle the change order process queue if it is blocked.
  2521. //
  2522. CoProcessQueue = Cxtion->CoProcessQueue;
  2523. Cxtion->CoProcessQueue = NULL;
  2524. //
  2525. // Deleted; nothing to do
  2526. //
  2527. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  2528. break;
  2529. default:
  2530. //
  2531. // ?
  2532. //
  2533. DPRINT2(0, ":X: ERROR - bad state %d for "FORMAT_CXTION_PATH2"\n",
  2534. GetCxtionState(Cxtion), PRINT_CXTION_PATH2(Replica, Cxtion));
  2535. break;
  2536. }
  2537. UNLOCK_CXTION_TABLE(Replica);
  2538. //
  2539. // The process queue should be unidled here after releasing the cxtion
  2540. // lock to prevent deadlock. Never lock the process queue when you have the
  2541. // cxtion lock.
  2542. //
  2543. UNIDLE_CO_PROCESS_QUEUE(Replica, Cxtion, CoProcessQueue);
  2544. return FStatus;
  2545. }
  2546. BOOL
  2547. RcsSetSysvolReady(
  2548. IN DWORD NewSysvolReady
  2549. )
  2550. /*++
  2551. Routine Description:
  2552. Set the registry value for ...\netlogon\parameters\SysvolReady to
  2553. the specified value. Do nothing if the SysvolReady value is
  2554. set accordingly.
  2555. Arguments:
  2556. None.
  2557. Return Value:
  2558. TRUE - SysvolReady is set to TRUE
  2559. FALSE - State of SysvolReady is unknown
  2560. --*/
  2561. {
  2562. #undef DEBSUB
  2563. #define DEBSUB "RcsSetSysvolReady:"
  2564. DWORD WStatus;
  2565. DPRINT1(4, ":S: Setting SysvolReady to %d\n", NewSysvolReady);
  2566. //
  2567. // Restrict values to 0 or 1
  2568. //
  2569. if (NewSysvolReady) {
  2570. NewSysvolReady = 1;
  2571. }
  2572. if (CurrentSysvolReadyIsValid &&
  2573. CurrentSysvolReady == NewSysvolReady) {
  2574. DPRINT1(4, ":S: SysvolReady is already set to %d\n", NewSysvolReady);
  2575. return TRUE;
  2576. }
  2577. //
  2578. // Access the netlogon\parameters key to tell NetLogon to share the sysvol
  2579. //
  2580. WStatus = CfgRegWriteDWord(FKC_SYSVOL_READY, NULL, 0, NewSysvolReady);
  2581. CLEANUP3_WS(0, "++ ERROR - writing %ws\\%ws to %d;",
  2582. NETLOGON_SECTION, SYSVOL_READY, NewSysvolReady, WStatus, RETURN_ERROR);
  2583. CurrentSysvolReady = NewSysvolReady;
  2584. CurrentSysvolReadyIsValid = TRUE;
  2585. DPRINT1(3, ":S: SysvolReady is set to %d\n", NewSysvolReady);
  2586. //
  2587. // Report event if transitioning from 0 to 1
  2588. //
  2589. if (NewSysvolReady) {
  2590. EPRINT1(EVENT_FRS_SYSVOL_READY, ComputerName);
  2591. }
  2592. return TRUE;
  2593. RETURN_ERROR:
  2594. return FALSE;
  2595. }
  2596. VOID
  2597. RcsVvJoinDoneUnJoin(
  2598. IN PCOMMAND_PACKET Cmd
  2599. )
  2600. /*++
  2601. Routine Description:
  2602. From: Myself
  2603. The VvJoin hack has declared victory and told our inbound partner
  2604. to unjoin from us. That was VVJOIN_HACK_TIMEOUT seconds ago. By
  2605. now, our inbound partner should have unjoined from us and we can
  2606. tell dcpromo that the sysvol has been promoted.
  2607. Arguments:
  2608. Cmd
  2609. Return Value:
  2610. None.
  2611. --*/
  2612. {
  2613. #undef DEBSUB
  2614. #define DEBSUB "RcsVvJoinDoneUnJoin:"
  2615. PREPLICA Replica;
  2616. PCXTION InCxtion;
  2617. //
  2618. // Check the command packet
  2619. //
  2620. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK )) {
  2621. return;
  2622. }
  2623. Replica = RsReplica(Cmd);
  2624. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, ReplicaVvJoinDoneUnjoin entry");
  2625. //
  2626. // Find and check the cxtion
  2627. //
  2628. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2629. CHECK_CXTION_INBOUND);
  2630. if (!InCxtion) {
  2631. return;
  2632. }
  2633. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  2634. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2635. }
  2636. VOID
  2637. RcsCheckPromotion(
  2638. IN PCOMMAND_PACKET Cmd
  2639. )
  2640. /*++
  2641. Routine Description:
  2642. From: Delayed command server
  2643. Check on the process of the sysvol promotion. If there has been
  2644. no activity since the last time we checked, set the replica's
  2645. promotion state to "done with error".
  2646. Arguments:
  2647. Cmd
  2648. Return Value:
  2649. None.
  2650. --*/
  2651. {
  2652. #undef DEBSUB
  2653. #define DEBSUB "RcsCheckPromotion:"
  2654. PREPLICA Replica;
  2655. PCXTION InCxtion;
  2656. ULONG Timeout;
  2657. //
  2658. // Check the command packet
  2659. //
  2660. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  2661. return;
  2662. }
  2663. Replica = RsReplica(Cmd);
  2664. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsCheckPromotion entry");
  2665. //
  2666. // Promotion is done; ignore
  2667. //
  2668. if (Replica->NtFrsApi_ServiceState != NTFRSAPI_SERVICE_PROMOTING) {
  2669. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not promoting");
  2670. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2671. return;
  2672. }
  2673. //
  2674. // No activity in awhile, declare failure
  2675. //
  2676. if (Replica->NtFrsApi_HackCount == RsTimeout(Cmd)) {
  2677. REPLICA_STATE_TRACE(3, Cmd, Replica, FRS_ERR_SYSVOL_POPULATE_TIMEOUT,
  2678. "W, Replica promotion timed out");
  2679. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE_TIMEOUT;
  2680. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  2681. FrsCompleteCommand(Cmd, ERROR_SERVICE_SPECIFIC_ERROR);
  2682. return;
  2683. }
  2684. //
  2685. // There has been activity. Wait awhile and check again
  2686. //
  2687. CfgRegReadDWord(FKC_PROMOTION_TIMEOUT, NULL, 0, &Timeout);
  2688. RsTimeout(Cmd) = Replica->NtFrsApi_HackCount;
  2689. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, Timeout);
  2690. }
  2691. #ifndef NOVVJOINHACK
  2692. #define VVJOIN_HACK_TIMEOUT (5 * 1000)
  2693. #endif NOVVJOINHACK
  2694. VOID
  2695. RcsVvJoinDone(
  2696. IN PCOMMAND_PACKET Cmd
  2697. )
  2698. /*++
  2699. Routine Description:
  2700. From: Inbound partner
  2701. The VvJoin thread has initiated all of the change orders. This doesn't
  2702. mean that the change orders have been installed, or even received.
  2703. At this second, we are trying to get sysvols to work; we
  2704. don't really care if the vvjoin is done or not except in
  2705. the case of sysvols. Hence, the hack below.
  2706. Use the sysvol seeding hack to initiate the deleting of empty
  2707. directories in the preexisting directory.
  2708. Arguments:
  2709. Cmd
  2710. Return Value:
  2711. None.
  2712. --*/
  2713. {
  2714. #undef DEBSUB
  2715. #define DEBSUB "RcsVvJoinDone:"
  2716. PREPLICA Replica;
  2717. PCXTION InCxtion;
  2718. ULONG FStatus;
  2719. //
  2720. // Check the command packet
  2721. //
  2722. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  2723. return;
  2724. }
  2725. Replica = RsReplica(Cmd);
  2726. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsVvJoinDone entry");
  2727. //
  2728. // Find and check the cxtion
  2729. //
  2730. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2731. CHECK_CXTION_INBOUND);
  2732. if (!InCxtion) {
  2733. return;
  2734. }
  2735. //
  2736. // Seeding has pretty much completed. We go ahead and hammer
  2737. // the configrecord in the DB in the hopes we don't lose this
  2738. // once-in-replica-lifetime state transition. The state is lost
  2739. // if this service restarts and none of the upstream partners
  2740. // vvjoins again.
  2741. //
  2742. // Set the incore BOOL that lets this code know the replica
  2743. // set is still seeding even though the CONFIG_FLAG_SEEDING
  2744. // bit is off. And yes, this is by design. The incore flag
  2745. // is enabled iff the DB state was updated successfully.
  2746. //
  2747. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  2748. ClearCxtionFlag(InCxtion, CXTION_FLAGS_INIT_SYNC);
  2749. FStatus = OutLogSubmit(Replica, InCxtion, CMD_OUTLOG_UPDATE_PARTNER);
  2750. CXTION_STATE_TRACE(3, InCxtion, Replica, FStatus, "F, OUTLOG_UPDATE_PARTNER return");
  2751. if (!FRS_SUCCESS(FStatus)) {
  2752. DPRINT3(0, "++ WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  2753. InCxtion->Name->Name, InCxtion->Partner->Name, Replica->ReplicaName->Name);
  2754. }
  2755. }
  2756. //
  2757. // First time; wait a bit and retry
  2758. //
  2759. #ifndef NOVVJOINHACK
  2760. if (!RsTimeout(Cmd)) {
  2761. Replica->NtFrsApi_HackCount++; // != 0
  2762. RsTimeout(Cmd) = Replica->NtFrsApi_HackCount;
  2763. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, VVJOIN_HACK_TIMEOUT);
  2764. return;
  2765. }
  2766. //
  2767. // There as been no activity on this cxtion for awhile after the
  2768. // vvjoin done was received. Declare success. Tell our upstream
  2769. // partner to discard the volatile cxtion. Update the database
  2770. // if it hasn't already been updated. If updated successfully,
  2771. // inform NetLogon that it is time to share the sysvol.
  2772. //
  2773. if (RsTimeout(Cmd) == Replica->NtFrsApi_HackCount) {
  2774. //
  2775. // VVJOIN DONE
  2776. //
  2777. //
  2778. // Send this command to the initial sync command server for further
  2779. // processing if we are in seeding state.
  2780. //
  2781. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  2782. InitSyncCsSubmitTransfer(Cmd, CMD_INITSYNC_VVJOIN_DONE);
  2783. } else {
  2784. Cmd->Command = CMD_VVJOIN_DONE_UNJOIN;
  2785. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  2786. }
  2787. } else {
  2788. //
  2789. // VVJOIN IN PROGRESS
  2790. //
  2791. RsTimeout(Cmd) = Replica->NtFrsApi_HackCount;
  2792. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, VVJOIN_HACK_TIMEOUT);
  2793. }
  2794. #endif NOVVJOINHACK
  2795. }
  2796. VOID
  2797. RcsVvJoinSuccess(
  2798. IN PCOMMAND_PACKET Cmd
  2799. )
  2800. /*++
  2801. Routine Description:
  2802. Type: Local
  2803. From: VvJoin Thread
  2804. Change the state of the oubound cxtion from VVJOINING to JOINED and
  2805. tell the outbound partner that the vvjoin thread is done.
  2806. Arguments:
  2807. Cmd
  2808. Return Value:
  2809. None.
  2810. --*/
  2811. {
  2812. #undef DEBSUB
  2813. #define DEBSUB "RcsVvJoinSuccess:"
  2814. PREPLICA Replica;
  2815. PCXTION OutCxtion;
  2816. PCOMM_PACKET CPkt;
  2817. //
  2818. // Check the command packet
  2819. //
  2820. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  2821. return;
  2822. }
  2823. Replica = RsReplica(Cmd);
  2824. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsVvJoinSuccess entry");
  2825. //
  2826. // Find and check the cxtion
  2827. //
  2828. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2829. CHECK_CXTION_OUTBOUND);
  2830. if (!OutCxtion) {
  2831. return;
  2832. }
  2833. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_VVJOIN_DONE, NULL, NULL, NULL);
  2834. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  2835. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2836. }
  2837. VOID
  2838. RcsHungCxtion(
  2839. IN PCOMMAND_PACKET Cmd
  2840. )
  2841. /*++
  2842. Routine Description:
  2843. From: Local OutLog Command Server
  2844. The outlog command server has detected a wrapped ack vector. This
  2845. may have been caused by a lost ack. In any case, check the progress
  2846. of the change orders by examining the the ack vector, the trailing
  2847. index, and the count of comm packets.
  2848. A cxtion is hung if it is wrapped and both the trailing index and
  2849. the number of comm packets received remains unchanged for
  2850. CommTimeoutInMilliSeconds (~5 minutes). In that case, the cxtion
  2851. is unjoined.
  2852. If the trailing index remains unchanged but comm packets are
  2853. being received then the timeout is reset to another
  2854. CommTimeoutInMilliSeconds interval.
  2855. If the cxtion appears un-hung, the command packet is completed.
  2856. Arguments:
  2857. Cmd
  2858. Return Value:
  2859. None.
  2860. --*/
  2861. {
  2862. #undef DEBSUB
  2863. #define DEBSUB "RcsHungCxtion:"
  2864. PREPLICA Replica;
  2865. PCXTION OutCxtion;
  2866. //
  2867. // Check the command packet
  2868. //
  2869. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  2870. return;
  2871. }
  2872. Replica = RsReplica(Cmd);
  2873. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsHungCxtion entry");
  2874. //
  2875. // Find and check the cxtion
  2876. //
  2877. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  2878. CHECK_CXTION_OUTBOUND);
  2879. if (!OutCxtion) {
  2880. return;
  2881. }
  2882. DPRINT1(4, ":X: Check Hung Cxtion for "FORMAT_CXTION_PATH2"\n",
  2883. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2884. //
  2885. // No out log context; can't be hung
  2886. //
  2887. if (!OutCxtion->OLCtx) {
  2888. DPRINT1(4, "++ No partner context for "FORMAT_CXTION_PATH2"\n",
  2889. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2890. FrsCompleteCommand(Cmd, ERROR_INVALID_PARAMETER);
  2891. return;
  2892. }
  2893. //
  2894. // No longer wrapped; not hung
  2895. //
  2896. if (!AVWrapped(OutCxtion->OLCtx)) {
  2897. DPRINT1(4, "++ No longer wrapped for "FORMAT_CXTION_PATH2"\n",
  2898. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2899. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2900. return;
  2901. }
  2902. //
  2903. // AV is not wrapped at the same trailing index; not hung
  2904. //
  2905. if (OutCxtion->OLCtx->COTx != RsCOTx(Cmd)) {
  2906. DPRINT3(4, "++ COTx is %d; not %d for "FORMAT_CXTION_PATH2"\n",
  2907. OutCxtion->OLCtx->COTx,
  2908. RsCOTx(Cmd), PRINT_CXTION_PATH2(Replica, OutCxtion));
  2909. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  2910. return;
  2911. }
  2912. //
  2913. // Some comm pkts have shown up from the downstream partner,
  2914. // may not be hung. Check again later.
  2915. //
  2916. if (OutCxtion->CommPkts != RsCommPkts(Cmd)) {
  2917. DPRINT3(4, "++ CommPkts is %d; not %d for "FORMAT_CXTION_PATH2"\n",
  2918. OutCxtion->CommPkts,
  2919. RsCommPkts(Cmd), PRINT_CXTION_PATH2(Replica, OutCxtion));
  2920. RsCommPkts(Cmd) = OutCxtion->CommPkts;
  2921. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CommTimeoutInMilliSeconds);
  2922. } else {
  2923. DPRINT1(4, "++ WARN - Unjoin; cxtion is hung "FORMAT_CXTION_PATH2"\n",
  2924. PRINT_CXTION_PATH2(Replica, OutCxtion));
  2925. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  2926. }
  2927. return;
  2928. }
  2929. VOID
  2930. RcsDeleteCxtionFromReplica(
  2931. IN PREPLICA Replica,
  2932. IN PCXTION Cxtion
  2933. )
  2934. /*++
  2935. Routine Description:
  2936. Common subroutine that synchronously deletes the cxtion from the
  2937. database and then removes it from the replica's table of cxtions.
  2938. The caller is responsible for insuring that this operation is
  2939. appropriate (cxtion exists, appropriate locks are held, ...)
  2940. Arguments:
  2941. Replica
  2942. Cxtion
  2943. Return Value:
  2944. TRUE - replica set was altered
  2945. FALSE - replica is unaltered
  2946. --*/
  2947. {
  2948. #undef DEBSUB
  2949. #define DEBSUB "RcsDeleteCxtionFromReplica:"
  2950. ULONG FStatus;
  2951. //
  2952. // Delete the cxtion from the database and then remove it from
  2953. // the replica's table of cxtions. Keep it in the table of
  2954. // deleted cxtions because change orders may contain the address
  2955. // of this cxtion.
  2956. //
  2957. DPRINT1(4, ":X: Deleting cxtion from Db: "FORMAT_CXTION_PATH2"\n",
  2958. PRINT_CXTION_PATH2(Replica, Cxtion));
  2959. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Deleting cxtion from Db");
  2960. //
  2961. // Must be in the deleted state to be deleted
  2962. //
  2963. if (!CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  2964. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, ERROR Cxtion state not deleted");
  2965. return;
  2966. }
  2967. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_REMOVE_PARTNER);
  2968. if (!FRS_SUCCESS(FStatus)) {
  2969. CXTION_STATE_TRACE(0, Cxtion, Replica, FStatus, "F, Warn: Del cxtion failed");
  2970. DPRINT1(0, "++ WARN Could not delete cxtion: "FORMAT_CXTION_PATH2"\n",
  2971. PRINT_CXTION_PATH2(Replica, Cxtion));
  2972. }
  2973. if (FRS_SUCCESS(FStatus)) {
  2974. DPRINT1(4, "++ Deleting cxtion from table: "FORMAT_CXTION_PATH2"\n",
  2975. PRINT_CXTION_PATH2(Replica, Cxtion));
  2976. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Deleting cxtion GenTab");
  2977. GTabDelete(Replica->Cxtions, Cxtion->Name->Guid, NULL, NULL);
  2978. //
  2979. // Remove the connection from the perfmon tables so we stop returning
  2980. // data and allow a new connection with the same name to be established.
  2981. //
  2982. DeletePerfmonInstance(REPLICACONN, Cxtion->PerfRepConnData);
  2983. GTabInsertEntry(DeletedCxtions, Cxtion, Cxtion->Name->Guid, NULL);
  2984. }
  2985. }
  2986. VOID
  2987. RcsUnJoinCxtion(
  2988. IN PCOMMAND_PACKET Cmd,
  2989. IN BOOL RemoteUnJoin
  2990. )
  2991. /*++
  2992. Routine Description:
  2993. A comm pkt could not be sent to a cxtion's partner. Unjoin the
  2994. cxtion and periodically retry the join unless the cxtion is
  2995. joined and volatile. In that case, delete the cxtion because
  2996. our partner is unlikely to be able to rejoin with us (volatile
  2997. cxtions are lost at restart).
  2998. Arguments:
  2999. Cmd
  3000. RemoteUnJoin - Check authentication if remote
  3001. Return Value:
  3002. None.
  3003. --*/
  3004. {
  3005. #undef DEBSUB
  3006. #define DEBSUB "RcsUnJoinCxtion:"
  3007. ULONG FStatus;
  3008. PREPLICA Replica;
  3009. PCXTION Cxtion;
  3010. BOOL CxtionWasJoined;
  3011. //
  3012. // Check the command packet
  3013. //
  3014. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  3015. return;
  3016. }
  3017. Replica = RsReplica(Cmd);
  3018. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsUnJoinCxtion entry");
  3019. //
  3020. // Abort promotion; if any
  3021. //
  3022. // We no longer seed during dcpromo so a unjoin during seeding means that the
  3023. // volatile connection has timed out (on upstream) because of no activity for
  3024. // some time (default 30 minutes). The vvjoin will finish over the new connection
  3025. // or the volatile connection will be re-established when the seeding downstream
  3026. // partner comes back up.
  3027. //
  3028. if (Replica->NtFrsApi_ServiceState == NTFRSAPI_SERVICE_PROMOTING) {
  3029. DPRINT1(4, ":X: Promotion aborted: unjoin for %ws.\n", Replica->SetName->Name);
  3030. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE;
  3031. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  3032. }
  3033. //
  3034. // Find and check the cxtion
  3035. //
  3036. Cxtion = RcsCheckCxtion(Cmd, DEBSUB,
  3037. CHECK_CXTION_EXISTS |
  3038. CHECK_CXTION_UNJOINGUID |
  3039. ((RemoteUnJoin) ? CHECK_CXTION_AUTH : 0) |
  3040. ((RemoteUnJoin) ? CHECK_CXTION_PARTNER : 0));
  3041. if (!Cxtion) {
  3042. return;
  3043. }
  3044. CXTION_STATE_TRACE(3, Cxtion, Replica, Cxtion->Flags, "Flags, RcsUnJoinCxtion entry");
  3045. //
  3046. // The call to RcsForceUnjoin may alter the cxtion state.
  3047. // Retry the join later. Don't retry if the cxtion isn't
  3048. // joined because there are other retry mechanisms covering
  3049. // that case.
  3050. //
  3051. LOCK_CXTION_TABLE(Replica);
  3052. CxtionWasJoined = CxtionStateIs(Cxtion, CxtionStateJoined);
  3053. if (!FrsIsShuttingDown &&
  3054. CxtionWasJoined &&
  3055. !CxtionFlagIs(Cxtion, CXTION_FLAGS_VOLATILE) &&
  3056. !CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) &&
  3057. !RemoteUnJoin &&
  3058. IS_TIME_ZERO(Replica->MembershipExpires)) {
  3059. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  3060. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Cxtion is DEFERRED_JOIN");
  3061. }
  3062. UNLOCK_CXTION_TABLE(Replica);
  3063. FStatus = RcsForceUnjoin(Replica, Cxtion);
  3064. CXTION_STATE_TRACE(3, Cxtion, Replica, FStatus, "F, RcsForceUnjoin return");
  3065. if (!FRS_SUCCESS(FStatus)) {
  3066. FrsCompleteCommand(Cmd, ERROR_REQUEST_ABORTED);
  3067. return;
  3068. }
  3069. //
  3070. // Delete the volatile cxtion if it was previously joined because
  3071. // there is no recovery for a failed sysvol seeding operation. Or
  3072. // if our downstream partner requested the unjoin.
  3073. //
  3074. if (!FrsIsShuttingDown &&
  3075. CxtionFlagIs(Cxtion, CXTION_FLAGS_VOLATILE) &&
  3076. (CxtionWasJoined || RemoteUnJoin)) {
  3077. RcsDeleteCxtionFromReplica(Replica, Cxtion);
  3078. }
  3079. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3080. }
  3081. VOID
  3082. RcsInboundJoined(
  3083. IN PCOMMAND_PACKET Cmd
  3084. )
  3085. /*++
  3086. Routine Description:
  3087. An inbound partner sent a JOINED command as a response to our join request.
  3088. JoinGuid may not match because we are seeing an old response after a timeout
  3089. on our end caused us to retry the join request (so the Guid changed).
  3090. The cxtion state should be JOINING but it could be JOINED if this is a
  3091. duplicate response. If we timed out and gave up and/or restarted the
  3092. entire Join sequence from the REQUEST_START state when a join response
  3093. finally arrives the JoinGuid won't match and the response is ignored.
  3094. Arguments:
  3095. Cmd
  3096. Return Value:
  3097. None.
  3098. --*/
  3099. {
  3100. #undef DEBSUB
  3101. #define DEBSUB "RcsInboundJoined:"
  3102. PCXTION InCxtion;
  3103. ULONG FStatus;
  3104. PREPLICA Replica;
  3105. PFRS_QUEUE CoProcessQueue = NULL;
  3106. //
  3107. // Check the command packet
  3108. //
  3109. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_JOINGUID_OK)) {
  3110. return;
  3111. }
  3112. Replica = RsReplica(Cmd);
  3113. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsInboundJoined entry");
  3114. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3115. CHECK_CXTION_INBOUND |
  3116. CHECK_CXTION_AUTH |
  3117. CHECK_CXTION_PARTNER |
  3118. CHECK_CXTION_JOINGUID);
  3119. if (!InCxtion) {
  3120. return;
  3121. }
  3122. //
  3123. // Shutting down; ignore join request
  3124. //
  3125. if (FrsIsShuttingDown) {
  3126. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, FrsIsShuttingDown");
  3127. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  3128. return;
  3129. }
  3130. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, RcsInboundJoined entry");
  3131. //
  3132. // Increment the Join Notifications Received counter for
  3133. // both the replica set and connection objects
  3134. //
  3135. PM_INC_CTR_CXTION(InCxtion, JoinNRcvd, 1);
  3136. PM_INC_CTR_REPSET(Replica, JoinNRcvd, 1);
  3137. //
  3138. // Update the LastJoinedTime in our connection record for use in the next
  3139. // Join request. The following call is synchronous. Can't hold the
  3140. // cxtion table lock across this call.
  3141. //
  3142. if (RsLastJoinTime(Cmd) != InCxtion->LastJoinTime) {
  3143. InCxtion->LastJoinTime = RsLastJoinTime(Cmd);
  3144. FStatus = OutLogSubmit(Replica, InCxtion, CMD_OUTLOG_UPDATE_PARTNER);
  3145. if (!FRS_SUCCESS(FStatus)) {
  3146. DPRINT3(0, ":X: WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  3147. InCxtion->Name->Name,
  3148. InCxtion->Partner->Name, Replica->ReplicaName->Name);
  3149. }
  3150. //
  3151. // If the last join time is changing and we are not in the waitjoin state
  3152. // then it means that the upstream is transitioning from join-unjoin-join.
  3153. // We might still have outstanding fetch requests on this connection that
  3154. // the upstream has dropped. Resubmit all fetch requests at this time.
  3155. //
  3156. LOCK_CXTION_TABLE(Replica);
  3157. RcsResubmitActiveCOsOnCxtion(Replica, InCxtion);
  3158. UNLOCK_CXTION_TABLE(Replica);
  3159. }
  3160. //
  3161. // Join complete; unidle the change order process queue
  3162. //
  3163. if (CxtionStateIs(InCxtion, CxtionStateWaitJoin)) {
  3164. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, JOINED");
  3165. LOCK_CXTION_TABLE(Replica);
  3166. SET_JOINED(Replica, InCxtion, "JOINED ");
  3167. CoProcessQueue = InCxtion->CoProcessQueue;
  3168. InCxtion->CoProcessQueue = NULL;
  3169. SET_UNJOIN_TRIGGER(InCxtion);
  3170. UNLOCK_CXTION_TABLE(Replica);
  3171. //
  3172. // The process queue should be unidled here after releasing the cxtion
  3173. // lock to prevent deadlock. Never lock the process queue when you have the
  3174. // cxtion lock.
  3175. //
  3176. UNIDLE_CO_PROCESS_QUEUE(Replica, InCxtion, CoProcessQueue);
  3177. } else {
  3178. //
  3179. // Increment the Joins counter for both the replica set and cxtion objects
  3180. //
  3181. PM_INC_CTR_CXTION(InCxtion, Joins, 1);
  3182. PM_INC_CTR_REPSET(Replica, Joins, 1);
  3183. DPRINT1(0, ":X: ***** REJOINED "FORMAT_CXTION_PATH2"\n",
  3184. PRINT_CXTION_PATH2(Replica, InCxtion));
  3185. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, REJOINED");
  3186. }
  3187. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3188. }
  3189. VOID
  3190. RcsRemoteCoDoneRvcd(
  3191. IN PCOMMAND_PACKET Cmd
  3192. )
  3193. /*++
  3194. Routine Description:
  3195. Our outbound partner has completed processing this change order.
  3196. Arguments:
  3197. Cmd
  3198. Return Value:
  3199. None.
  3200. --*/
  3201. {
  3202. #undef DEBSUB
  3203. #define DEBSUB "RcsRemoteCoDoneRvcd:"
  3204. ULONGLONG AckVersion;
  3205. PREPLICA Replica;
  3206. PCXTION OutCxtion;
  3207. POUT_LOG_PARTNER OutLogPartner;
  3208. //
  3209. // Check the command packet
  3210. //
  3211. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_PARTNERCOC)) {
  3212. return;
  3213. }
  3214. Replica = RsReplica(Cmd);
  3215. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRemoteCoDoneRvcd entry");
  3216. CHANGE_ORDER_COMMAND_TRACE(3, RsPartnerCoc(Cmd), "Command Remote CO Done");
  3217. //
  3218. // Find and check the cxtion
  3219. //
  3220. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3221. CHECK_CXTION_OUTBOUND |
  3222. CHECK_CXTION_JOINED |
  3223. CHECK_CXTION_JOINGUID |
  3224. CHECK_CXTION_AUTH);
  3225. if (!OutCxtion) {
  3226. return;
  3227. }
  3228. FRS_CO_COMM_PROGRESS(3, RsPartnerCoc(Cmd), RsCoSn(Cmd),
  3229. OutCxtion->PartSrvName, "Remote Co Done");
  3230. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, Remote Co Done");
  3231. //
  3232. // Update the outbound cxtion's version vector with the
  3233. // version (guid, vsn) supplied by the outbound partner
  3234. //
  3235. VVUpdateOutbound(OutCxtion->VVector, RsGVsn(Cmd));
  3236. RsGVsn(Cmd) = NULL;
  3237. //
  3238. // Check if this Ack is for a previous generation of the the Ack Vector
  3239. // and if it is just ignore it. Test for zero means that this is an old
  3240. // rev CO that was not sent with an AckVersion so skip the test.
  3241. // If we accept an ACK for a CO sent out with an old version of the Ack
  3242. // vector the effect will be to either accept an Ack for the wrong CO or
  3243. // mark the ack vector for a CO that has not yet been sent. The latter
  3244. // can later lead to an assert if the connection is now out of the
  3245. // VVJoin state.
  3246. //
  3247. OutLogPartner = OutCxtion->OLCtx;
  3248. AckVersion = RsPartnerCoc(Cmd)->AckVersion;
  3249. if ((AckVersion != 0) && (AckVersion != OutLogPartner->AckVersion)) {
  3250. CHANGE_ORDER_COMMAND_TRACE(3, RsPartnerCoc(Cmd), "Stale AckVersion - ignore");
  3251. return;
  3252. }
  3253. //
  3254. // Tell Outbound Log this CO for this connection is retired.
  3255. //
  3256. OutLogRetireCo(Replica, RsCoSn(Cmd), OutCxtion);
  3257. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3258. }
  3259. VOID
  3260. RcsSendRemoteCoDone(
  3261. IN PREPLICA Replica,
  3262. IN PCHANGE_ORDER_COMMAND Coc
  3263. )
  3264. /*++
  3265. Routine Description:
  3266. Tell our inbound partner that the change order is done
  3267. Arguments:
  3268. Replica
  3269. Coc
  3270. Return Value:
  3271. None.
  3272. --*/
  3273. {
  3274. #undef DEBSUB
  3275. #define DEBSUB "RcsSendRemoteCoDone:"
  3276. PCOMMAND_PACKET Cmd;
  3277. PCXTION InCxtion;
  3278. PCOMM_PACKET CPkt;
  3279. #ifndef NOVVJOINHACK
  3280. Replica->NtFrsApi_HackCount++;
  3281. #endif NOVVJOINHACK
  3282. //
  3283. // Return the (guid,vsn) and the co guid for this change order
  3284. //
  3285. Cmd = FrsAllocCommand(NULL, CMD_REMOTE_CO_DONE);
  3286. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  3287. RsGVsn(Cmd) = VVGetGVsn(Replica->VVector, &Coc->OriginatorGuid);
  3288. RsCoGuid(Cmd) = FrsDupGuid(&Coc->ChangeOrderGuid);
  3289. RsCoSn(Cmd) = Coc->PartnerAckSeqNumber;
  3290. //
  3291. // Find and check the cxtion
  3292. //
  3293. RsReplica(Cmd) = Replica;
  3294. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coc->CxtionGuid), NULL);
  3295. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3296. CHECK_CXTION_INBOUND |
  3297. CHECK_CXTION_JOINED);
  3298. if (!InCxtion) {
  3299. return;
  3300. }
  3301. //
  3302. // Only needed for the call to RcsCheckCxtion above.
  3303. //
  3304. RsCxtion(Cmd) = FrsFreeGName(RsCxtion(Cmd));
  3305. RsReplica(Cmd) = NULL;
  3306. //
  3307. // Tell our inbound partner that the remote CO is done
  3308. //
  3309. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Send REMOTE_CO_DONE");
  3310. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_REMOTE_CO_DONE, NULL, Cmd, Coc);
  3311. SndCsSubmitCommPkt2(Replica, InCxtion, NULL, FALSE, CPkt);
  3312. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3313. }
  3314. VOID
  3315. RcsInboundCommitOk(
  3316. IN PREPLICA Replica,
  3317. IN PCHANGE_ORDER_ENTRY Coe
  3318. )
  3319. /*++
  3320. Routine Description:
  3321. The change order has been retired; inform our inbound partner
  3322. Arguments:
  3323. Replica
  3324. Coe
  3325. Return Value:
  3326. None.
  3327. --*/
  3328. {
  3329. #undef DEBSUB
  3330. #define DEBSUB "RcsInboundCommitOk:"
  3331. PCHANGE_ORDER_COMMAND Coc = &Coe->Cmd;
  3332. #ifndef NOVVJOINHACK
  3333. Replica->NtFrsApi_HackCount++;
  3334. #endif NOVVJOINHACK
  3335. DPRINT2(4, "++ Commit the retire on %s co for %ws\n",
  3336. CO_FLAG_ON(Coe, CO_FLAG_LOCALCO) ? "Local" : "Remote", Coc->FileName);
  3337. //
  3338. // Tell our inbound partner that we are done with the change order
  3339. //
  3340. if (!CO_FLAG_ON(Coe, CO_FLAG_LOCALCO)) {
  3341. RcsSendRemoteCoDone(Replica, Coc);
  3342. }
  3343. }
  3344. BOOL
  3345. RcsSendCoToOneOutbound(
  3346. IN PREPLICA Replica,
  3347. IN PCXTION Cxtion,
  3348. IN PCHANGE_ORDER_COMMAND Coc
  3349. )
  3350. /*++
  3351. Routine Description:
  3352. Send the change order to one outbound cxtion
  3353. Arguments:
  3354. Replica
  3355. Cxtion
  3356. Coc
  3357. Return Value:
  3358. None.
  3359. --*/
  3360. {
  3361. #undef DEBSUB
  3362. #define DEBSUB "RcsSendCoToOneOutbound:"
  3363. ULONG OrigFlags;
  3364. PCOMM_PACKET CPkt;
  3365. BOOL RestoreOldParent = FALSE;
  3366. BOOL RestoreNewParent = FALSE;
  3367. //
  3368. // Must be a joined, outbound cxtion
  3369. //
  3370. FRS_ASSERT(!Cxtion->Inbound);
  3371. //
  3372. // Don't send a change order our outbound partner has seen
  3373. //
  3374. if (VVHasVsn(Cxtion->VVector, Coc)) {
  3375. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Dampen Send VV");
  3376. return FALSE;
  3377. }
  3378. //
  3379. // Don't send a change order to its originator unless
  3380. // this is a vvjoin change order that isn't in the
  3381. // originator's version vector.
  3382. //
  3383. if ((!COC_FLAG_ON(Coc, CO_FLAG_VVJOIN_TO_ORIG)) &&
  3384. GUIDS_EQUAL(&Cxtion->ReplicaVersionGuid, &Coc->OriginatorGuid)) {
  3385. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Dampen Send Originator");
  3386. return FALSE;
  3387. }
  3388. //
  3389. // Send the change order to our outbound partner
  3390. //
  3391. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Sending");
  3392. //
  3393. // We don't know the value of our partner's root guid. Instead,
  3394. // we substitute the value of our partner's guid. Our partner
  3395. // will substitute the correct value for its root guid when
  3396. // our partner detects our substitution.
  3397. //
  3398. if (GUIDS_EQUAL(&Coc->OldParentGuid, Replica->ReplicaRootGuid)) {
  3399. RestoreOldParent = TRUE;
  3400. COPY_GUID(&Coc->OldParentGuid, Cxtion->Partner->Guid);
  3401. }
  3402. if (GUIDS_EQUAL(&Coc->NewParentGuid, Replica->ReplicaRootGuid)) {
  3403. RestoreNewParent = TRUE;
  3404. COPY_GUID(&Coc->NewParentGuid, Cxtion->Partner->Guid);
  3405. }
  3406. //
  3407. // A change order can be directed to only one outbound cxtion. Once
  3408. // the change order goes across the wire it is no longer "directed"
  3409. // to an outbound cxtion. So, turn off the flag before it is sent.
  3410. //
  3411. OrigFlags = Coc->Flags;
  3412. CLEAR_COC_FLAG(Coc, CO_FLAG_DIRECTED_CO);
  3413. CPkt = CommBuildCommPkt(Replica, Cxtion, CMD_REMOTE_CO, NULL, NULL, Coc);
  3414. //
  3415. // Restore the root guids substituted above
  3416. //
  3417. if (RestoreOldParent) {
  3418. COPY_GUID(&Coc->OldParentGuid, Replica->ReplicaRootGuid);
  3419. }
  3420. if (RestoreNewParent) {
  3421. COPY_GUID(&Coc->NewParentGuid, Replica->ReplicaRootGuid);
  3422. }
  3423. //
  3424. // Restore the flags
  3425. //
  3426. SET_COC_FLAG(Coc, OrigFlags);
  3427. SndCsSubmitCommPkt2(Replica, Cxtion, NULL, FALSE, CPkt);
  3428. return TRUE;
  3429. }
  3430. VOID
  3431. RcsReceivedStageFile(
  3432. IN PCOMMAND_PACKET Cmd,
  3433. IN ULONG AdditionalCxtionChecks
  3434. )
  3435. /*++
  3436. Routine Description:
  3437. An outbound partner is sending a staging file to this inbound cxtion.
  3438. Request more if needed.
  3439. Arguments:
  3440. Cmd
  3441. AdditionalReplicaChecks
  3442. Return Value:
  3443. None.
  3444. --*/
  3445. {
  3446. #undef DEBSUB
  3447. #define DEBSUB "RcsReceivedStageFile:"
  3448. PCXTION InCxtion;
  3449. PREPLICA Replica;
  3450. PCHANGE_ORDER_ENTRY Coe;
  3451. PCHANGE_ORDER_COMMAND Coc;
  3452. PCOMM_PACKET CPkt;
  3453. ULONG Flags;
  3454. ULONG WStatus;
  3455. //
  3456. // Check the command packet
  3457. //
  3458. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_COE)) {
  3459. return;
  3460. }
  3461. Replica = RsReplica(Cmd);
  3462. Coe = RsCoe(Cmd);
  3463. Coc = RsCoc(Cmd);
  3464. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsReceivedStageFile entry");
  3465. CHANGE_ORDER_TRACEXP(3, Coe, "Replica received stage", Cmd);
  3466. #ifndef NOVVJOINHACK
  3467. Replica->NtFrsApi_HackCount++;
  3468. #endif NOVVJOINHACK
  3469. //
  3470. // *Note*
  3471. // Perf: Clean this up when the whole RCS, FETCS, STAGE_GEN_CS design is redone - Davidor.
  3472. //
  3473. // This bypass is needed because some of the callers want to make an
  3474. // authentication check on the received data fetch packet. In the case of an
  3475. // MD5 match where the MD5 checksum is supplied with the Change Order
  3476. // there is no authentication info to check so this check fails and causes
  3477. // the connection to unjoin and sends the CO thru retry. This makes the
  3478. // VVJoin real slow. This also skips over the perfmon fetch counters which
  3479. // is good since there was no fetch.
  3480. //
  3481. if (COE_FLAG_ON(Coe, COE_FLAG_PRE_EXIST_MD5_MATCH)) {
  3482. CHANGE_ORDER_TRACE(3, Coe, "MD5 Match Bypass");
  3483. //
  3484. // We can't skip the below because we need to check the staging
  3485. // file flags for STAGE_FLAG_DATA_PRESENT. If that is clear we need
  3486. // to pass this friggen cmd pkt to the FetchCs to do the final stage file
  3487. // reanme. So instead clear the CHECK_CXTION_AUTH flag to avoid bogus
  3488. // cxtion unjoins. This stinks.
  3489. //
  3490. ClearFlag(AdditionalCxtionChecks, CHECK_CXTION_AUTH);
  3491. // goto FETCH_IS_DONE;
  3492. }
  3493. //
  3494. // Find and check the cxtion
  3495. //
  3496. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3497. CHECK_CXTION_INBOUND |
  3498. AdditionalCxtionChecks);
  3499. if (!InCxtion) {
  3500. return;
  3501. }
  3502. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, RcsReceivedStageFile entry");
  3503. //
  3504. // If there is more staging file to fetch, go fetch it!
  3505. //
  3506. if (RsFileOffset(Cmd).QuadPart < RsFileSize(Cmd).QuadPart) {
  3507. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Send more stage");
  3508. //
  3509. // Remember what offset of the staging file we are requesting.
  3510. //
  3511. //Coe->FileOffset.QuadPart = RsFileOffset(Cmd).QuadPart;
  3512. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_SEND_STAGE, NULL, Cmd, Coc);
  3513. SndCsSubmitCommPkt2(Replica, InCxtion, Coe, TRUE, CPkt);
  3514. RsCoe(Cmd) = NULL;
  3515. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3516. return;
  3517. } else {
  3518. if (FrsDoesCoNeedStage(Coc)) {
  3519. //
  3520. // Even though all the data has been delivered the staging file rename
  3521. // may not have completed. E.g. a sharing violation on final rename.
  3522. // If so then send the cmd back to the Fetch CS to finish up.
  3523. //
  3524. Flags = STAGE_FLAG_EXCLUSIVE;
  3525. WStatus = StageAcquire(&Coc->ChangeOrderGuid,
  3526. Coc->FileName,
  3527. Coc->FileSize,
  3528. &Flags,
  3529. Replica->ReplicaNumber,
  3530. NULL);
  3531. if (WIN_RETRY_FETCH(WStatus)) {
  3532. //
  3533. // Retriable problem
  3534. //
  3535. CHANGE_ORDER_TRACEW(3, Coe, "Send to Fetch Retry", WStatus);
  3536. FrsFetchCsSubmitTransfer(Cmd, CMD_RETRY_FETCH);
  3537. return;
  3538. }
  3539. if (!WIN_SUCCESS(WStatus)) {
  3540. //
  3541. // Unrecoverable error; abort
  3542. //
  3543. CHANGE_ORDER_TRACEW(0, Coe, "Send to fetch abort", WStatus);
  3544. FrsFetchCsSubmitTransfer(Cmd, CMD_ABORT_FETCH);
  3545. return;
  3546. }
  3547. StageRelease(&Coc->ChangeOrderGuid, Coc->FileName, 0, NULL, NULL, NULL);
  3548. //
  3549. // Now check if we still need to finish the rename.
  3550. //
  3551. if (!(Flags & STAGE_FLAG_DATA_PRESENT)) {
  3552. FrsFetchCsSubmitTransfer(Cmd, CMD_RECEIVING_STAGE);
  3553. return;
  3554. }
  3555. }
  3556. //
  3557. // Increment the staging files fetched counter for the replica set.
  3558. //
  3559. PM_INC_CTR_REPSET(Replica, SFFetched, 1);
  3560. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Stage fetch complete");
  3561. }
  3562. //
  3563. // Increment the Fetch Requests Files Received counter for
  3564. // both the replica set and connection objects
  3565. //
  3566. PM_INC_CTR_CXTION(InCxtion, FetRReceived, 1);
  3567. PM_INC_CTR_REPSET(Replica, FetRReceived, 1);
  3568. //
  3569. // Display info for dcpromo during sysvol seeding.
  3570. // We don't seed during dcpromo anymore so we don't need to
  3571. // display any progress information.
  3572. //
  3573. // if (!Replica->NtFrsApi_ServiceDisplay) {
  3574. // Replica->NtFrsApi_ServiceDisplay = FrsWcsDup(Coc->FileName);
  3575. // }
  3576. // FETCH_IS_DONE:
  3577. //
  3578. // Installing the fetched staging file
  3579. //
  3580. SET_CHANGE_ORDER_STATE(Coe, IBCO_FETCH_COMPLETE);
  3581. SET_CHANGE_ORDER_STATE(Coe, IBCO_INSTALL_INITIATED);
  3582. //
  3583. // Install the staging file.
  3584. //
  3585. FrsInstallCsSubmitTransfer(Cmd, CMD_INSTALL_STAGE);
  3586. }
  3587. VOID
  3588. RcsRetryFetch(
  3589. IN PCOMMAND_PACKET Cmd
  3590. )
  3591. /*++
  3592. Routine Description:
  3593. Our inbound partner has requested that we retry fetching the staging
  3594. file at a later time.
  3595. Arguments:
  3596. Cmd
  3597. Return Value:
  3598. None.
  3599. --*/
  3600. {
  3601. #undef DEBSUB
  3602. #define DEBSUB "RcsRetryFetch:"
  3603. PCXTION InCxtion;
  3604. PREPLICA Replica;
  3605. //
  3606. // Check the command packet
  3607. //
  3608. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK | CHECK_CMD_COE)) {
  3609. return;
  3610. }
  3611. Replica = RsReplica(Cmd);
  3612. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRetryFetch entry");
  3613. CHANGE_ORDER_TRACEXP(3, RsCoe(Cmd), "Replica retry fetch", Cmd);
  3614. #ifndef NOVVJOINHACK
  3615. RsReplica(Cmd)->NtFrsApi_HackCount++;
  3616. #endif NOVVJOINHACK
  3617. //
  3618. // Find and check the cxtion
  3619. //
  3620. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3621. CHECK_CXTION_INBOUND |
  3622. CHECK_CXTION_AUTH);
  3623. if (!InCxtion) {
  3624. return;
  3625. }
  3626. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_RETRY_FETCH");
  3627. FrsFetchCsSubmitTransfer(Cmd, CMD_RETRY_FETCH);
  3628. }
  3629. VOID
  3630. RcsAbortFetch(
  3631. IN PCOMMAND_PACKET Cmd
  3632. )
  3633. /*++
  3634. Routine Description:
  3635. Our inbound partner has requested that we abort the fetch.
  3636. It could be out of disk space, out of disk quota or it may
  3637. not have the original file to create the staging file.
  3638. Arguments:
  3639. Cmd
  3640. Return Value:
  3641. None.
  3642. --*/
  3643. {
  3644. #undef DEBSUB
  3645. #define DEBSUB "RcsAbortFetch:"
  3646. PCXTION InCxtion;
  3647. PREPLICA Replica;
  3648. PCHANGE_ORDER_ENTRY Coe;
  3649. //
  3650. // Check the command packet
  3651. //
  3652. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK | CHECK_CMD_COE)) {
  3653. return;
  3654. }
  3655. Replica = RsReplica(Cmd);
  3656. Coe = RsCoe(Cmd);
  3657. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsAbortFetch entry");
  3658. CHANGE_ORDER_TRACEXP(3, Coe, "Replica abort fetch", Cmd);
  3659. //
  3660. // Abort promotion; if any
  3661. //
  3662. //
  3663. // We no longer seed during dcpromo so aborting a fetch during seeding is same as
  3664. // aborting it at any other time. If we abort a dir create then it will trigger a unjoin
  3665. // of the volatile connection. The vvjoin will finish over the new connection
  3666. // or the volatile connection will be re-established when the seeding downstream
  3667. // partner comes back up.
  3668. //
  3669. if (Replica->NtFrsApi_ServiceState == NTFRSAPI_SERVICE_PROMOTING) {
  3670. DPRINT1(4, "++ Promotion aborted: abort fetch for %ws.\n",
  3671. Replica->SetName->Name);
  3672. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE;
  3673. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  3674. }
  3675. //
  3676. // Find and check the cxtion
  3677. //
  3678. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3679. CHECK_CXTION_INBOUND |
  3680. CHECK_CXTION_AUTH);
  3681. if (InCxtion == NULL) {
  3682. return;
  3683. }
  3684. FrsFetchCsSubmitTransfer(Cmd, CMD_ABORT_FETCH);
  3685. }
  3686. VOID
  3687. RcsReceivingStageFile(
  3688. IN PCOMMAND_PACKET Cmd
  3689. )
  3690. /*++
  3691. Routine Description:
  3692. Received this data from our inbound partner. Give it to the fetcher
  3693. so he can put it into the staging file.
  3694. Arguments:
  3695. Cmd
  3696. Return Value:
  3697. None.
  3698. --*/
  3699. {
  3700. #undef DEBSUB
  3701. #define DEBSUB "RcsReceivingStageFile:"
  3702. PREPLICA Replica;
  3703. PCXTION InCxtion;
  3704. //
  3705. // Check the command packet
  3706. //
  3707. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK | CHECK_CMD_COE)) {
  3708. return;
  3709. }
  3710. Replica = RsReplica(Cmd);
  3711. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsReceivingStageFile entry");
  3712. CHANGE_ORDER_TRACEXP(3, RsCoe(Cmd), "Replica receiving stage", Cmd);
  3713. #ifndef NOVVJOINHACK
  3714. RsReplica(Cmd)->NtFrsApi_HackCount++;
  3715. #endif NOVVJOINHACK
  3716. //
  3717. // Find and check the cxtion
  3718. //
  3719. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3720. CHECK_CXTION_INBOUND |
  3721. CHECK_CXTION_AUTH);
  3722. if (!InCxtion) {
  3723. //
  3724. // Note: If auth check fails we might consider aborting the CO instead.
  3725. // Need to first try it and see if the CO would be aborted
  3726. // elsewhere first.
  3727. //
  3728. return;
  3729. }
  3730. //
  3731. // Display info for dcpromo during sysvol seeding
  3732. // We don't seed during dcpromo anymore so we don't need to
  3733. // display any progress information.
  3734. //
  3735. // if (!Replica->NtFrsApi_ServiceDisplay) {
  3736. // Replica->NtFrsApi_ServiceDisplay = FrsWcsDup(RsCoc(Cmd)->FileName);
  3737. // }
  3738. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_RECEIVING_STAGE");
  3739. //
  3740. // Increment the Fetch Requests Bytes Received counter for
  3741. // both the replica set and connection objects
  3742. //
  3743. PM_INC_CTR_CXTION(InCxtion, FetBRcvd, 1);
  3744. PM_INC_CTR_REPSET(Replica, FetBRcvd, 1);
  3745. PM_INC_CTR_CXTION(InCxtion, FetBRcvdBytes, RsBlockSize(Cmd));
  3746. PM_INC_CTR_REPSET(Replica, FetBRcvdBytes, RsBlockSize(Cmd));
  3747. FrsFetchCsSubmitTransfer(Cmd, CMD_RECEIVING_STAGE);
  3748. }
  3749. VOID
  3750. RcsSendRetryFetch(
  3751. IN PCOMMAND_PACKET Cmd
  3752. )
  3753. /*++
  3754. Routine Description:
  3755. Received from the local staging file fetcher. Tell our
  3756. outbound partner to retry the fetch at a later time.
  3757. Arguments:
  3758. Cmd
  3759. Return Value:
  3760. None.
  3761. --*/
  3762. {
  3763. #undef DEBSUB
  3764. #define DEBSUB "RcsSendRetryFetch:"
  3765. PREPLICA Replica;
  3766. PCXTION OutCxtion;
  3767. PCOMM_PACKET CPkt;
  3768. //
  3769. // Check the command packet
  3770. //
  3771. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK)) {
  3772. return;
  3773. }
  3774. Replica = RsReplica(Cmd);
  3775. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendRetryFetch entry");
  3776. #ifndef NOVVJOINHACK
  3777. RsReplica(Cmd)->NtFrsApi_HackCount++;
  3778. #endif NOVVJOINHACK
  3779. //
  3780. // Find and check the cxtion
  3781. //
  3782. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3783. CHECK_CXTION_OUTBOUND);
  3784. if (!OutCxtion) {
  3785. return;
  3786. }
  3787. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_RETRY_FETCH");
  3788. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_RETRY_FETCH, NULL, Cmd, NULL);
  3789. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  3790. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3791. }
  3792. VOID
  3793. RcsSendAbortFetch(
  3794. IN PCOMMAND_PACKET Cmd
  3795. )
  3796. /*++
  3797. Routine Description:
  3798. Received from the local staging file fetcher. Tell our
  3799. outbound partner to abort the fetch.
  3800. Arguments:
  3801. Cmd
  3802. Return Value:
  3803. None.
  3804. --*/
  3805. {
  3806. #undef DEBSUB
  3807. #define DEBSUB "RcsSendAbortFetch:"
  3808. PREPLICA Replica;
  3809. PCXTION OutCxtion;
  3810. PCOMM_PACKET CPkt;
  3811. //
  3812. // Check the command packet
  3813. //
  3814. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK)) {
  3815. return;
  3816. }
  3817. Replica = RsReplica(Cmd);
  3818. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendAbortFetch entry");
  3819. //
  3820. // Find and check the cxtion
  3821. //
  3822. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3823. CHECK_CXTION_OUTBOUND);
  3824. if (!OutCxtion) {
  3825. return;
  3826. }
  3827. //
  3828. // Tell our outbound partner that the file has been sent
  3829. //
  3830. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_ABORT_FETCH");
  3831. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_ABORT_FETCH, NULL, Cmd, NULL);
  3832. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  3833. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3834. }
  3835. VOID
  3836. RcsSendingStageFile(
  3837. IN PCOMMAND_PACKET Cmd
  3838. )
  3839. /*++
  3840. Routine Description:
  3841. Received from the local staging file fetcher. Push this data to
  3842. our outbound partner.
  3843. Arguments:
  3844. Cmd
  3845. Return Value:
  3846. None.
  3847. --*/
  3848. {
  3849. #undef DEBSUB
  3850. #define DEBSUB "RcsSendingStageFile:"
  3851. PREPLICA Replica;
  3852. PCXTION OutCxtion;
  3853. PCOMM_PACKET CPkt;
  3854. //
  3855. // Check the command packet
  3856. //
  3857. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK)) {
  3858. return;
  3859. }
  3860. Replica = RsReplica(Cmd);
  3861. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendingStageFile entry");
  3862. //
  3863. // Find and check the cxtion
  3864. //
  3865. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3866. CHECK_CXTION_OUTBOUND);
  3867. if (!OutCxtion) {
  3868. return;
  3869. }
  3870. //
  3871. // Increment the Fetch Blocks sent and Fetch Bytes sent counter for
  3872. // both the replica set and connection objects
  3873. //
  3874. PM_INC_CTR_CXTION(OutCxtion, FetBSent, 1);
  3875. PM_INC_CTR_REPSET(Replica, FetBSent, 1);
  3876. PM_INC_CTR_CXTION(OutCxtion, FetBSentBytes, RsBlockSize(Cmd));
  3877. PM_INC_CTR_REPSET(Replica, FetBSentBytes, RsBlockSize(Cmd));
  3878. //
  3879. // Send the next block of the file to the outbound partner.
  3880. //
  3881. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_RECEIVING_STAGE");
  3882. CPkt = CommBuildCommPkt(Replica, OutCxtion, CMD_RECEIVING_STAGE, NULL, Cmd, NULL);
  3883. SndCsSubmitCommPkt2(Replica, OutCxtion, NULL, FALSE, CPkt);
  3884. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  3885. }
  3886. VOID
  3887. RcsSendStageFile(
  3888. IN PCOMMAND_PACKET Cmd
  3889. )
  3890. /*++
  3891. Routine Description:
  3892. Received a request to send the staging control file to our
  3893. outbound partner. Tell the staging fetcher to send it on.
  3894. Arguments:
  3895. Cmd
  3896. Return Value:
  3897. None.
  3898. --*/
  3899. {
  3900. #undef DEBSUB
  3901. #define DEBSUB "RcsSendStageFile:"
  3902. PCXTION OutCxtion;
  3903. PREPLICA Replica;
  3904. //
  3905. // Check the command packet
  3906. //
  3907. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_AND_COGUID_OK |
  3908. CHECK_CMD_PARTNERCOC )) {
  3909. return;
  3910. }
  3911. Replica = RsReplica(Cmd);
  3912. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendStageFile entry");
  3913. CHANGE_ORDER_COMMAND_TRACE(3, RsPartnerCoc(Cmd), "Command send stage");
  3914. //
  3915. // Find and check the cxtion
  3916. //
  3917. OutCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  3918. CHECK_CXTION_OUTBOUND);
  3919. if (!OutCxtion) {
  3920. return;
  3921. }
  3922. //
  3923. // Tell the staging file generator to send the file
  3924. //
  3925. CXTION_STATE_TRACE(3, OutCxtion, Replica, 0, "F, submit cmd CMD_SEND_STAGE");
  3926. FrsFetchCsSubmitTransfer(Cmd, CMD_SEND_STAGE);
  3927. }
  3928. VOID
  3929. RcsRemoteCoAccepted(
  3930. IN PCOMMAND_PACKET Cmd
  3931. )
  3932. /*++
  3933. Routine Description:
  3934. We have accepted the remote change order, fetch the staging file
  3935. Arguments:
  3936. Cmd
  3937. Return Value:
  3938. None.
  3939. --*/
  3940. {
  3941. #undef DEBSUB
  3942. #define DEBSUB "RcsRemoteCoAccepted:"
  3943. DWORD WStatus;
  3944. DWORD Flags;
  3945. PREPLICA Replica;
  3946. PCXTION InCxtion;
  3947. PCHANGE_ORDER_ENTRY Coe;
  3948. PCHANGE_ORDER_COMMAND Coc;
  3949. PCOMM_PACKET CPkt;
  3950. //
  3951. // Check the command packet
  3952. //
  3953. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_COE)) {
  3954. return;
  3955. }
  3956. Replica = RsReplica(Cmd);
  3957. Coe = RsCoe(Cmd);
  3958. Coc = RsCoc(Cmd);
  3959. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRemoteCoAccepted entry");
  3960. CHANGE_ORDER_TRACEXP(3, Coe, "Replica remote co accepted", Cmd);
  3961. #ifndef NOVVJOINHACK
  3962. Replica->NtFrsApi_HackCount++;
  3963. #endif NOVVJOINHACK
  3964. //
  3965. // Find and check the cxtion
  3966. //
  3967. // We don't need auth check here because this cmd hasn't arrived
  3968. // from a partner. It is submitted by RcsSubmitRemoteCoAccepted()
  3969. //
  3970. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  3971. CHECK_CXTION_INBOUND |
  3972. CHECK_CXTION_JOINED);
  3973. if (!InCxtion) {
  3974. return;
  3975. }
  3976. FRS_CO_COMM_PROGRESS(3, Coc, (ULONG)(Coc->SequenceNumber),
  3977. InCxtion->PartSrvName, "Remote Co Accepted");
  3978. //
  3979. // MACRO MAY RETURN!!!
  3980. //
  3981. PULL_UNJOIN_TRIGGER(InCxtion, Cmd);
  3982. if (VVHasVsn(Replica->VVector, Coc)) {
  3983. CHANGE_ORDER_TRACE(3, Coe, "Dampen Accepted Remote Co");
  3984. }
  3985. //
  3986. // Don't fetch a non-existent staging file
  3987. //
  3988. if (!FrsDoesCoNeedStage(Coc)) {
  3989. //
  3990. // Allocate or update the Join Guid.
  3991. //
  3992. if (RsJoinGuid(Cmd) == NULL) {
  3993. RsJoinGuid(Cmd) = FrsDupGuid(&InCxtion->JoinGuid);
  3994. } else {
  3995. COPY_GUID(RsJoinGuid(Cmd), &InCxtion->JoinGuid);
  3996. }
  3997. RcsReceivedStageFile(Cmd, 0);
  3998. return;
  3999. }
  4000. //
  4001. // Don't refetch a recovered staging file
  4002. //
  4003. Flags = 0;
  4004. WStatus = StageAcquire(&Coc->ChangeOrderGuid, Coc->FileName, QUADZERO, &Flags, Replica->ReplicaNumber, NULL);
  4005. if (WIN_SUCCESS(WStatus)) {
  4006. StageRelease(&Coc->ChangeOrderGuid, Coc->FileName, Flags, NULL, NULL, NULL);
  4007. if (Flags & STAGE_FLAG_CREATED) {
  4008. //
  4009. // File has been fetched
  4010. //
  4011. RsFileOffset(Cmd).QuadPart = RsFileSize(Cmd).QuadPart;
  4012. //
  4013. // Allocate or update the Join Guid.
  4014. //
  4015. if (RsJoinGuid(Cmd) == NULL) {
  4016. RsJoinGuid(Cmd) = FrsDupGuid(&InCxtion->JoinGuid);
  4017. } else {
  4018. COPY_GUID(RsJoinGuid(Cmd), &InCxtion->JoinGuid);
  4019. }
  4020. RcsReceivedStageFile(Cmd, 0);
  4021. return;
  4022. }
  4023. }
  4024. //
  4025. // Attempt to use a preexisting file if this is the first block of the
  4026. // staging file, is a vvjoin co, and there is a preinstall file.
  4027. //
  4028. //
  4029. // 04/24/2002: We only do this for VVJoin COs. The change to look for a preexisting
  4030. // for non-vvjoin COs was removed as it was at the expense of a huge
  4031. // perf hit. Bug # 493700
  4032. //
  4033. if (InCxtion->PartnerMinor >= NTFRS_COMM_MINOR_1 &&
  4034. (RsFileOffset(Cmd).QuadPart == QUADZERO) &&
  4035. CO_FLAG_ON(Coe, CO_FLAG_VVJOIN_TO_ORIG) &&
  4036. COE_FLAG_ON(Coe, COE_FLAG_PREINSTALL_CRE)) {
  4037. //
  4038. // Removed the check for a VVJoin Co above. If this is a new file
  4039. // (i.e. a pe-install file was created) then check for a local file
  4040. // with a matching OID and MD5. Put out a trace record so we can
  4041. // tell when this case occurs.
  4042. //
  4043. if (!CO_FLAG_ON(Coe, CO_FLAG_VVJOIN_TO_ORIG)) {
  4044. CHANGE_ORDER_TRACE(3, Coe, "**** Chk Existing - non-VVJOIN Co");
  4045. }
  4046. FrsStageCsSubmitTransfer(Cmd, CMD_CREATE_EXISTING);
  4047. return;
  4048. }
  4049. //
  4050. // fetching the staging file
  4051. //
  4052. SET_CHANGE_ORDER_STATE(RsCoe(Cmd), IBCO_FETCH_INITIATED);
  4053. //
  4054. // Increment the Fetch Requests Files Requested counter for
  4055. // both the replica set and connection objects
  4056. //
  4057. PM_INC_CTR_CXTION(InCxtion, FetRSent, 1);
  4058. PM_INC_CTR_REPSET(Replica, FetRSent, 1);
  4059. //
  4060. // Tell our inbound partner to send the staging file
  4061. //
  4062. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_SEND_STAGE");
  4063. //
  4064. // Remember what offset of the staging file we are requesting.
  4065. //
  4066. //Coe->FileOffset.QuadPart = RsFileOffset(Cmd).QuadPart;
  4067. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_SEND_STAGE, NULL, Cmd, Coc);
  4068. SndCsSubmitCommPkt2(Replica, InCxtion, RsCoe(Cmd), TRUE, CPkt);
  4069. RsCoe(Cmd) = NULL;
  4070. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  4071. }
  4072. VOID
  4073. RcsSendStageFileRequest(
  4074. IN PCOMMAND_PACKET Cmd
  4075. )
  4076. /*++
  4077. Routine Description:
  4078. Generated staging file (maybe) from preexisting file.
  4079. Request stage file from upstream partner. If MD5Digest matches
  4080. on Upstream partner's stage file then our pre-existing stage file (if any)
  4081. is good.
  4082. Arguments:
  4083. Cmd
  4084. Return Value:
  4085. None.
  4086. --*/
  4087. {
  4088. #undef DEBSUB
  4089. #define DEBSUB "RcsSendStageFileRequest:"
  4090. PREPLICA Replica;
  4091. PCXTION InCxtion;
  4092. PCHANGE_ORDER_ENTRY Coe;
  4093. PCHANGE_ORDER_COMMAND Coc;
  4094. PCOMM_PACKET CPkt;
  4095. ULONG CocAttrs;
  4096. ULONG CoeAttrs;
  4097. //
  4098. // Check the command packet
  4099. //
  4100. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_COE)) {
  4101. return;
  4102. }
  4103. Replica = RsReplica(Cmd);
  4104. Coe = RsCoe(Cmd);
  4105. Coc = RsCoc(Cmd);
  4106. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSendStageFileRequest entry");
  4107. CHANGE_ORDER_TRACEXP(3, Coe, "Replica created existing", Cmd);
  4108. #ifndef NOVVJOINHACK
  4109. Replica->NtFrsApi_HackCount++;
  4110. #endif NOVVJOINHACK
  4111. CocAttrs = Coc->FileAttributes &
  4112. ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL);
  4113. CoeAttrs = Coe->FileAttributes &
  4114. ~(FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL);
  4115. //
  4116. // If the attribs don't match then we don't want to pass along or check the
  4117. // MD5 checksum. Otherwise we might wind up sending the local checksum
  4118. // upstream for our partner to do the check. He won't have the Attribs and
  4119. // would think the file was the same if only the attribs had changed.
  4120. //
  4121. if (CocAttrs != CoeAttrs) {
  4122. DPRINT2(3, "Attribute miss-match, zeroing MD5. CocAttrs: 0x%08x CoeAttrs: 0x%08x\n", CocAttrs, CoeAttrs);
  4123. RsMd5Digest(Cmd) = FrsFree(RsMd5Digest(Cmd));
  4124. }
  4125. if (RsMd5Digest(Cmd)) {
  4126. PDATA_EXTENSION_CHECKSUM CocDataChkSum;
  4127. //
  4128. // We have an existing file and the checksum has been created.
  4129. // See if we have a checksum in the changeorder from our inbound
  4130. // partner. If so and they match then we can move on to the install.
  4131. //
  4132. //
  4133. // We also need to check the attributes and the times, since they
  4134. // are not part of the checksum. Right now we do not have the times
  4135. // from the upstream partner so we can't check them.
  4136. //
  4137. CHANGE_ORDER_TRACE(3, Coe, "Created Existing");
  4138. CocDataChkSum = DbsDataExtensionFind(Coc->Extension, DataExtend_MD5_CheckSum);
  4139. if ((CocDataChkSum != NULL) &&
  4140. !IS_MD5_CHKSUM_ZERO(CocDataChkSum->Data) &&
  4141. MD5_EQUAL(CocDataChkSum->Data, RsMd5Digest(Cmd))) {
  4142. //
  4143. // MD5 digest from CO matches so our file is good and we can
  4144. // avoid having the inbound partner recompute the checksum.
  4145. //
  4146. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Md5, Attribs match preexisting, no fetch");
  4147. SET_COE_FLAG(Coe, COE_FLAG_PRE_EXIST_MD5_MATCH);
  4148. DPRINT1(4, "++ RsFileSize(Cmd).QuadPart: %08x %08x\n",
  4149. PRINTQUAD(RsFileSize(Cmd).QuadPart));
  4150. DPRINT1(4, "++ Coc->FileSize: %08x %08x\n",
  4151. PRINTQUAD(Coc->FileSize));
  4152. //
  4153. // Even if the file is 0 bytes in length, the staging file will
  4154. // always have at least the header. There are some retry paths
  4155. // that will incorrectly think the staging file has been fetched
  4156. // if RsFileSize(Cmd) is 0. So make sure it isn't.
  4157. //
  4158. if (RsFileSize(Cmd).QuadPart == QUADZERO) {
  4159. RsFileSize(Cmd).QuadPart = Coc->FileSize;
  4160. if (RsFileSize(Cmd).QuadPart == QUADZERO) {
  4161. RsFileSize(Cmd).QuadPart = sizeof(STAGE_HEADER);
  4162. }
  4163. }
  4164. DPRINT1(4, "++ RsFileSize(Cmd).QuadPart: %08x %08x\n",
  4165. PRINTQUAD(RsFileSize(Cmd).QuadPart));
  4166. //
  4167. // Set the offset to the size of the stage file so we don't request
  4168. // any data.
  4169. //
  4170. RsFileOffset(Cmd).QuadPart = RsFileSize(Cmd).QuadPart;
  4171. RsBlockSize(Cmd) = QUADZERO;
  4172. //
  4173. // Find and check the cxtion
  4174. //
  4175. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4176. CHECK_CXTION_INBOUND |
  4177. CHECK_CXTION_JOINED);
  4178. if (!InCxtion) {
  4179. return;
  4180. }
  4181. //
  4182. // Allocate or update the Join Guid.
  4183. //
  4184. if (RsJoinGuid(Cmd) == NULL) {
  4185. RsJoinGuid(Cmd) = FrsDupGuid(&InCxtion->JoinGuid);
  4186. } else {
  4187. COPY_GUID(RsJoinGuid(Cmd), &InCxtion->JoinGuid);
  4188. }
  4189. RcsReceivedStageFile(Cmd, 0);
  4190. //RcsSubmitTransferToRcs(Cmd, CMD_RECEIVED_STAGE);
  4191. return;
  4192. }
  4193. } else {
  4194. CHANGE_ORDER_TRACE(3, Coe, "Could not create existing");
  4195. }
  4196. //
  4197. // Find and check the cxtion
  4198. //
  4199. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4200. CHECK_CXTION_INBOUND |
  4201. CHECK_CXTION_JOINED);
  4202. if (!InCxtion) {
  4203. return;
  4204. }
  4205. //
  4206. // Tell our inbound partner to send the staging file
  4207. //
  4208. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_SEND_STAGE");
  4209. //
  4210. // Remember what offset of the staging file we are requesting.
  4211. //
  4212. //Coe->FileOffset.QuadPart = RsFileOffset(Cmd).QuadPart;
  4213. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_SEND_STAGE, NULL, Cmd, Coc);
  4214. SndCsSubmitCommPkt2(Replica, InCxtion, RsCoe(Cmd), TRUE, CPkt);
  4215. RsCoe(Cmd) = NULL;
  4216. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  4217. }
  4218. VOID
  4219. RcsRemoteCoReceived(
  4220. IN PCOMMAND_PACKET Cmd
  4221. )
  4222. /*++
  4223. Routine Description:
  4224. Remote CO has arrived.
  4225. Translate guid of our root dir if necc.
  4226. Attach the Change Order extension if provided.
  4227. Check version vector dampening and provide immediate Ack if we have
  4228. already seen this CO.
  4229. Finally, pass the change order on to the change order subsystem.
  4230. Arguments:
  4231. Cmd
  4232. Return Value:
  4233. None.
  4234. --*/
  4235. {
  4236. #undef DEBSUB
  4237. #define DEBSUB "RcsRemoteCoReceived:"
  4238. PCXTION InCxtion;
  4239. PREPLICA Replica;
  4240. PULONG pULong;
  4241. PCHANGE_ORDER_COMMAND Coc;
  4242. PCHANGE_ORDER_RECORD_EXTENSION CocExt;
  4243. //
  4244. // Check the command packet
  4245. //
  4246. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_CXTION_OK | CHECK_CMD_PARTNERCOC )) {
  4247. return;
  4248. }
  4249. Replica = RsReplica(Cmd);
  4250. Coc = RsPartnerCoc(Cmd);
  4251. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRemoteCoReceived entry");
  4252. #ifndef NOVVJOINHACK
  4253. RsReplica(Cmd)->NtFrsApi_HackCount++;
  4254. #endif NOVVJOINHACK
  4255. //
  4256. // Find and check the cxtion
  4257. //
  4258. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_JOIN_OK |
  4259. CHECK_CXTION_INBOUND |
  4260. CHECK_CXTION_AUTH |
  4261. CHECK_CXTION_FIXJOINED);
  4262. if (!InCxtion) {
  4263. return;
  4264. }
  4265. //
  4266. // Remember which cxtion this change order was directed at
  4267. //
  4268. COPY_GUID(&Coc->CxtionGuid, RsCxtion(Cmd)->Guid);
  4269. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Replica Received Remote Co");
  4270. //
  4271. // Our partner doesn't know the correct value for our root guid and
  4272. // so substituted our ReplicaName->Guid (its Cxtion->Partner->Guid)
  4273. // for its own root guids when sending the change order to us.
  4274. // We substitute our own root guids once we receive the change order
  4275. // and detect the substitution.
  4276. //
  4277. if (GUIDS_EQUAL(&Coc->OldParentGuid, RsReplica(Cmd)->ReplicaName->Guid)) {
  4278. COPY_GUID(&Coc->OldParentGuid, RsReplica(Cmd)->ReplicaRootGuid);
  4279. }
  4280. if (GUIDS_EQUAL(&Coc->NewParentGuid, RsReplica(Cmd)->ReplicaName->Guid)) {
  4281. COPY_GUID(&Coc->NewParentGuid, RsReplica(Cmd)->ReplicaRootGuid);
  4282. }
  4283. //
  4284. // Init the Coc pointer to the CO Data Extension. Down Rev partners
  4285. // won't have one so supply an empty field. Do this here in case VV
  4286. // Dampening short circuits the CO and sends back the RemoteCoDone ACK here.
  4287. //
  4288. CocExt = RsPartnerCocExt(Cmd);
  4289. if (CocExt == NULL) {
  4290. CocExt = FrsAlloc(sizeof(CHANGE_ORDER_RECORD_EXTENSION));
  4291. DbsDataInitCocExtension(CocExt);
  4292. DPRINT(4, "Allocating initial Coc Extension\n");
  4293. }
  4294. Coc->Extension = CocExt;
  4295. pULong = (PULONG) CocExt;
  4296. DPRINT5(5, "Extension Buffer: (%08x) %08x %08x %08x %08x\n",
  4297. pULong, *(pULong+0), *(pULong+1), *(pULong+2), *(pULong+3));
  4298. DPRINT5(5, "Extension Buffer: (%08x) %08x %08x %08x %08x\n",
  4299. (PCHAR)pULong+16, *(pULong+4), *(pULong+5), *(pULong+6), *(pULong+7));
  4300. //
  4301. // Don't redo a change order
  4302. //
  4303. if (VVHasVsn(RsReplica(Cmd)->VVector, Coc)) {
  4304. //
  4305. // Increment the Inbound CO dampned counter for
  4306. // both the replica set and connection objects
  4307. //
  4308. PM_INC_CTR_CXTION(InCxtion, InCODampned, 1);
  4309. PM_INC_CTR_REPSET(RsReplica(Cmd), InCODampned, 1);
  4310. CHANGE_ORDER_COMMAND_TRACE(3, Coc, "Dampen Received Remote Co");
  4311. RcsSendRemoteCoDone(RsReplica(Cmd), Coc);
  4312. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  4313. return;
  4314. }
  4315. //
  4316. // Put the change order on the inbound queue for this replica.
  4317. //
  4318. ChgOrdInsertRemoteCo(Cmd, InCxtion);
  4319. //
  4320. // Done
  4321. //
  4322. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  4323. }
  4324. VOID
  4325. RcsRetryStageFileCreate(
  4326. IN PCOMMAND_PACKET Cmd
  4327. )
  4328. /*++
  4329. Routine Description:
  4330. Retry generating the staging file.
  4331. Arguments:
  4332. Cmd
  4333. Return Value:
  4334. None.
  4335. --*/
  4336. {
  4337. #undef DEBSUB
  4338. #define DEBSUB "RcsRetryStageFileCreate:"
  4339. PREPLICA Replica;
  4340. PCXTION OutCxtion;
  4341. PCXTION InCxtion;
  4342. PVOID Key;
  4343. PCHANGE_ORDER_ENTRY Coe;
  4344. //
  4345. // Check the command packet
  4346. //
  4347. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA | CHECK_CMD_COE)) {
  4348. return;
  4349. }
  4350. Replica = RsReplica(Cmd);
  4351. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsRetryStageFileCreate entry");
  4352. CHANGE_ORDER_TRACEXP(3, RsCoe(Cmd), "Replica retry stage", Cmd);
  4353. //
  4354. // Find and check the cxtion
  4355. //
  4356. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4357. CHECK_CXTION_INBOUND |
  4358. CHECK_CXTION_JRNLCXTION |
  4359. CHECK_CXTION_JOINED);
  4360. if (!InCxtion) {
  4361. return;
  4362. }
  4363. //
  4364. // Ignore local change order if there are no outbound cxtions
  4365. //
  4366. Key = NULL;
  4367. while (OutCxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  4368. if (!OutCxtion->Inbound) {
  4369. break;
  4370. }
  4371. }
  4372. if (OutCxtion == NULL) {
  4373. //
  4374. // Make sure a user hasn't altered our object id on the file
  4375. // and then retire the change order without propagating to the
  4376. // outbound log. The stager is responsible for hammering the
  4377. // object id because it knows how to handle sharing violations
  4378. // and file-not-found errors.
  4379. //
  4380. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CHECK_OID");
  4381. FrsStageCsSubmitTransfer(Cmd, CMD_CHECK_OID);
  4382. } else {
  4383. //
  4384. // Generate the staging file
  4385. //
  4386. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CREATE_STAGE");
  4387. FrsStageCsSubmitTransfer(Cmd, CMD_CREATE_STAGE);
  4388. }
  4389. }
  4390. VOID
  4391. RcsLocalCoAccepted(
  4392. IN PCOMMAND_PACKET Cmd
  4393. )
  4394. /*++
  4395. Routine Description:
  4396. Process the accepted, local change order. Either retire it if there
  4397. are no outbound cxtions or send it own to the staging file generator.
  4398. Arguments:
  4399. Cmd
  4400. Return Value:
  4401. None.
  4402. --*/
  4403. {
  4404. #undef DEBSUB
  4405. #define DEBSUB "RcsLocalCoAccepted:"
  4406. PREPLICA Replica;
  4407. PCXTION OutCxtion;
  4408. PCXTION InCxtion;
  4409. PVOID Key;
  4410. PCHANGE_ORDER_ENTRY Coe;
  4411. //
  4412. // Check the command packet
  4413. //
  4414. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA | CHECK_CMD_COE)) {
  4415. return;
  4416. }
  4417. Replica = RsReplica(Cmd);
  4418. Coe = RsCoe(Cmd);
  4419. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsLocalCoAccepted entry");
  4420. CHANGE_ORDER_TRACEXP(3, Coe, "Replica local co accepted", Cmd);
  4421. //
  4422. // Find and check the cxtion
  4423. //
  4424. InCxtion = RcsCheckCxtion(Cmd, DEBSUB, CHECK_CXTION_EXISTS |
  4425. CHECK_CXTION_INBOUND |
  4426. CHECK_CXTION_JRNLCXTION |
  4427. CHECK_CXTION_JOINED);
  4428. if (!InCxtion) {
  4429. return;
  4430. }
  4431. FRS_CO_COMM_PROGRESS(3, &Coe->Cmd, Coe->Cmd.SequenceNumber,
  4432. InCxtion->PartSrvName, "Local Co Accepted");
  4433. //
  4434. // Ignore local change order if there are no outbound cxtions
  4435. //
  4436. Key = NULL;
  4437. while (OutCxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  4438. if (!OutCxtion->Inbound) {
  4439. break;
  4440. }
  4441. }
  4442. if (OutCxtion == NULL) {
  4443. //
  4444. // Make sure a user hasn't altered our object id on the file
  4445. // and then retire the change order without propagating to the
  4446. // outbound log. The stager is responsible for hammering the
  4447. // object id because it knows how to handle sharing violations
  4448. // and file-not-found errors.
  4449. //
  4450. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CHECK_OID");
  4451. FrsStageCsSubmitTransfer(Cmd, CMD_CHECK_OID);
  4452. } else {
  4453. //
  4454. // Generate the staging file
  4455. //
  4456. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, submit cmd CMD_CREATE_STAGE");
  4457. FrsStageCsSubmitTransfer(Cmd, CMD_CREATE_STAGE);
  4458. }
  4459. }
  4460. VOID
  4461. RcsBeginMergeWithDs(
  4462. VOID
  4463. )
  4464. /*++
  4465. Routine Description:
  4466. The DS has been polled and now has replicas to merge into the
  4467. active replicas initially retrieved from the database or merged
  4468. into the active replicas by a previous poll.
  4469. Each active replica is marked as "not merged with ds". Any
  4470. replica that remains in this state after the merge is done
  4471. is a deleted replica. See RcsEndMergeWithDs().
  4472. Arguments:
  4473. None.
  4474. Return Value:
  4475. TRUE - Continue with merge
  4476. FALSE - Abort merge
  4477. --*/
  4478. {
  4479. #undef DEBSUB
  4480. #define DEBSUB "RcsBeginMergeWithDs:"
  4481. PVOID Key;
  4482. PREPLICA Replica;
  4483. extern CRITICAL_SECTION MergingReplicasWithDs;
  4484. //
  4485. // Wait for the replica command server to start up. The shutdown
  4486. // code will set this event so we don't sleep forever.
  4487. //
  4488. WaitForSingleObject(ReplicaEvent, INFINITE);
  4489. //
  4490. // Synchronize with sysvol seeding
  4491. //
  4492. EnterCriticalSection(&MergingReplicasWithDs);
  4493. //
  4494. // Snapshot a copy of the replica table. Anything left in the table
  4495. // after the merge should be deleted because a corresponding entry
  4496. // no longer exists in the DS. This code is not multithread!
  4497. //
  4498. FRS_ASSERT(ReplicasNotInTheDs == NULL);
  4499. ReplicasNotInTheDs = GTabAllocTable();
  4500. Key = NULL;
  4501. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  4502. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Insert ReplicasNotInTheDs");
  4503. GTabInsertEntry(ReplicasNotInTheDs, Replica, Replica->ReplicaName->Guid, NULL);
  4504. }
  4505. }
  4506. VOID
  4507. RcsSubmitReplica(
  4508. IN PREPLICA Replica,
  4509. IN PREPLICA NewReplica, OPTIONAL
  4510. IN USHORT Command
  4511. )
  4512. /*++
  4513. Routine Description:
  4514. Submit a command to a replica.
  4515. Arguments:
  4516. Replica - existing replica
  4517. NewReplica - Changes to Replica (may be NULL)
  4518. Command
  4519. Return Value:
  4520. None.
  4521. --*/
  4522. {
  4523. #undef DEBSUB
  4524. #define DEBSUB "RcsSubmitReplica:"
  4525. PCOMMAND_PACKET Cmd;
  4526. //
  4527. // Allocate a command packet
  4528. //
  4529. Cmd = FrsAllocCommand(Replica->Queue, Command);
  4530. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  4531. //
  4532. // Address of replica set and new replica set
  4533. //
  4534. RsReplica(Cmd) = Replica;
  4535. RsNewReplica(Cmd) = NewReplica;
  4536. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsSubmitReplica cmd");
  4537. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  4538. }
  4539. VOID
  4540. RcsSubmitReplicaCxtion(
  4541. IN PREPLICA Replica,
  4542. IN PCXTION Cxtion,
  4543. IN USHORT Command
  4544. )
  4545. /*++
  4546. Routine Description:
  4547. Submit a command to a replica\cxtion.
  4548. Build cmd pkt with Cxtion GName, replica ptr, Join Guid and supplied command.
  4549. Submit to Replica cmd server.
  4550. Calls dispatch function and translates cxtion GName to cxtion ptr
  4551. Builds Comm pkt for cxtion and calls SndCsSubmit() to send it.
  4552. Arguments:
  4553. Replica - existing replica
  4554. Cxtion - existing cxtion
  4555. Command
  4556. Return Value:
  4557. None.
  4558. --*/
  4559. {
  4560. #undef DEBSUB
  4561. #define DEBSUB "RcsSubmitReplicaCxtion:"
  4562. PCOMMAND_PACKET Cmd;
  4563. //
  4564. // Allocate a command packet
  4565. //
  4566. Cmd = FrsAllocCommand(Replica->Queue, Command);
  4567. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  4568. //
  4569. // Address of replica set and new replica set
  4570. //
  4571. RsReplica(Cmd) = Replica;
  4572. RsCxtion(Cmd) = FrsDupGName(Cxtion->Name);
  4573. RsJoinGuid(Cmd) = FrsDupGuid(&Cxtion->JoinGuid);
  4574. //
  4575. // OLCtx and CommPkts are used for CMD_HUNG_CXTION.
  4576. // They are used to detect a hung outbound cxtion that
  4577. // is probably hung because of a dropped ack.
  4578. //
  4579. if (Cxtion->OLCtx) {
  4580. RsCOTx(Cmd) = Cxtion->OLCtx->COTx;
  4581. }
  4582. RsCommPkts(Cmd) = Cxtion->CommPkts - 1;
  4583. DPRINT5(5, "Submit %08x for Cmd %08x %ws\\%ws\\%ws\n",
  4584. Cmd->Command, Cmd, Replica->SetName->Name, Replica->MemberName->Name,
  4585. Cxtion->Name->Name);
  4586. CXTION_STATE_TRACE(5, Cxtion, Replica, 0, "F, RcsSubmitReplicaCxtion cmd");
  4587. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  4588. }
  4589. DWORD
  4590. RcsSubmitReplicaSync(
  4591. IN PREPLICA Replica,
  4592. IN PREPLICA NewReplica,
  4593. IN PCXTION VolatileCxtion,
  4594. IN USHORT Command
  4595. )
  4596. /*++
  4597. Routine Description:
  4598. Submit a command to a replica and wait for it to finish.
  4599. Arguments:
  4600. Replica - existing replica
  4601. NewReplica - Changes to Replica (may be NULL)
  4602. VolatileCxtion - New cxtion (currently used for seeding sysvols)
  4603. Command
  4604. Return Value:
  4605. None.
  4606. --*/
  4607. {
  4608. #undef DEBSUB
  4609. #define DEBSUB "RcsSubmitReplicaSync:"
  4610. DWORD WStatus;
  4611. PCOMMAND_PACKET Cmd;
  4612. //
  4613. // Allocate a command packet
  4614. //
  4615. Cmd = FrsAllocCommand(Replica->Queue, Command);
  4616. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  4617. //
  4618. // Address of replica set and new replica set
  4619. //
  4620. RsReplica(Cmd) = Replica;
  4621. RsNewReplica(Cmd) = NewReplica;
  4622. RsNewCxtion(Cmd) = VolatileCxtion;
  4623. RsCompletionEvent(Cmd) = FrsCreateEvent(TRUE, FALSE);
  4624. DPRINT3(5, "Submit Sync %08x for Cmd %08x %ws\n",
  4625. Cmd->Command, Cmd, RsReplica(Cmd)->ReplicaName->Name);
  4626. CXTION_STATE_TRACE(5, VolatileCxtion, Replica, 0, "F, RcsSubmitReplicaSync cmd");
  4627. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  4628. //
  4629. // Wait for the command to finish
  4630. //
  4631. WaitForSingleObject(RsCompletionEvent(Cmd), INFINITE);
  4632. FRS_CLOSE(RsCompletionEvent(Cmd));
  4633. WStatus = Cmd->ErrorStatus;
  4634. FrsCompleteCommand(Cmd, Cmd->ErrorStatus);
  4635. return WStatus;
  4636. }
  4637. VOID
  4638. RcsEndMergeWithDs(
  4639. VOID
  4640. )
  4641. /*++
  4642. Routine Description:
  4643. The DS has been polled and the replicas have been merged into the
  4644. active replicas.
  4645. Each active replica was initially included in a temporary table.
  4646. Any replica still left in the table is a deleted replica because
  4647. its corresponding entry in the DS was not found.
  4648. Arguments:
  4649. None.
  4650. Return Value:
  4651. None.
  4652. --*/
  4653. {
  4654. #undef DEBSUB
  4655. #define DEBSUB "RcsEndMergeWithDs:"
  4656. PVOID Key;
  4657. PREPLICA Replica;
  4658. DWORD ReplicaSetsDeleted;
  4659. extern BOOL DsIsShuttingDown;
  4660. extern CRITICAL_SECTION MergingReplicasWithDs;
  4661. extern ULONG DsPollingInterval;
  4662. extern ULONG DsPollingShortInterval;
  4663. //
  4664. // Any replica that is in the state "not merged" should be deleted
  4665. // unless the Ds is shutting down; in which case do not process
  4666. // deletes because a sysvol seeding operation may be in progress.
  4667. // We do not want to delete the sysvol we are currently trying to
  4668. // create.
  4669. //
  4670. Key = NULL;
  4671. while (!DsIsShuttingDown &&
  4672. (Replica = GTabNextDatum(ReplicasNotInTheDs, &Key))) {
  4673. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, submit replica CMD_DELETE");
  4674. RcsSubmitReplica(Replica, NULL, CMD_DELETE);
  4675. }
  4676. DbsProcessReplicaFaultList(&ReplicaSetsDeleted);
  4677. //
  4678. // If any replica sets were deleted while processing the fault list then we should
  4679. // trigger the next poll sooner so we can start the non-auth restore on the
  4680. // deleted replica sets.
  4681. //
  4682. if (ReplicaSetsDeleted) {
  4683. DsPollingInterval = DsPollingShortInterval;
  4684. }
  4685. GTabFreeTable(ReplicasNotInTheDs, NULL);
  4686. ReplicasNotInTheDs = NULL;
  4687. //
  4688. // Synchronize with sysvol seeding
  4689. //
  4690. LeaveCriticalSection(&MergingReplicasWithDs);
  4691. }
  4692. VOID
  4693. RcsReplicaSetRegistry(
  4694. IN PREPLICA Replica
  4695. )
  4696. /*++
  4697. Routine Description:
  4698. This function stores information about the replica set
  4699. into the registry for use by ntfrsupg /restore
  4700. (non-authoritative restore).
  4701. Arguments:
  4702. Replica
  4703. Return Value:
  4704. None.
  4705. --*/
  4706. {
  4707. #undef DEBSUB
  4708. #define DEBSUB "RcsReplicaSetRegistry:"
  4709. DWORD WStatus;
  4710. PWCHAR ReplicaSetTypeW;
  4711. DWORD NumberOfPartners;
  4712. DWORD BurFlags;
  4713. DWORD ReplicaSetTombstoned;
  4714. HKEY HSeedingsKey = INVALID_HANDLE_VALUE;
  4715. WCHAR GuidW[GUID_CHAR_LEN + 1];
  4716. //
  4717. // Sanity check
  4718. //
  4719. if (!Replica ||
  4720. !Replica->SetName || !Replica->SetName->Name ||
  4721. !Replica->MemberName || !Replica->MemberName->Guid) {
  4722. DPRINT(4, ":S: WARN - Partial replica set ignored\n");
  4723. return;
  4724. }
  4725. //
  4726. // Working path to jet Database dir.
  4727. //
  4728. CfgRegWriteString(FKC_SETS_JET_PATH, NULL, FRS_RKF_CREATE_KEY, JetPath);
  4729. //
  4730. // Create the subkey for this set
  4731. //
  4732. GuidToStrW(Replica->MemberName->Guid, GuidW);
  4733. //
  4734. // Replica set name
  4735. // Replica set root path
  4736. // Replica set stage path
  4737. //
  4738. CfgRegWriteString(FKC_SET_N_REPLICA_SET_NAME,
  4739. GuidW,
  4740. FRS_RKF_CREATE_KEY,
  4741. Replica->SetName->Name);
  4742. CfgRegWriteString(FKC_SET_N_REPLICA_SET_ROOT,
  4743. GuidW,
  4744. FRS_RKF_CREATE_KEY,
  4745. Replica->Root);
  4746. CfgRegWriteString(FKC_SET_N_REPLICA_SET_STAGE,
  4747. GuidW,
  4748. FRS_RKF_CREATE_KEY,
  4749. Replica->Stage);
  4750. //
  4751. // Replica set type
  4752. //
  4753. switch (Replica->ReplicaSetType) {
  4754. case FRS_RSTYPE_ENTERPRISE_SYSVOL:
  4755. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_ENTERPRISE;
  4756. break;
  4757. case FRS_RSTYPE_DOMAIN_SYSVOL:
  4758. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_DOMAIN;
  4759. break;
  4760. case FRS_RSTYPE_DFS:
  4761. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_DFS;
  4762. break;
  4763. default:
  4764. ReplicaSetTypeW = NTFRSAPI_REPLICA_SET_TYPE_OTHER;
  4765. break;
  4766. }
  4767. CfgRegWriteString(FKC_SET_N_REPLICA_SET_TYPE,
  4768. GuidW,
  4769. FRS_RKF_CREATE_KEY,
  4770. ReplicaSetTypeW);
  4771. //
  4772. // Replica Set Tombstoned
  4773. //
  4774. ReplicaSetTombstoned = (!IS_TIME_ZERO(Replica->MembershipExpires)) ? 1 : 0;
  4775. CfgRegWriteDWord(FKC_SET_N_REPLICA_SET_TOMBSTONED,
  4776. GuidW,
  4777. FRS_RKF_CREATE_KEY,
  4778. ReplicaSetTombstoned);
  4779. //
  4780. // Update the registry state under Cumulative Replica Sets for this set.
  4781. //
  4782. NumberOfPartners = GTabNumberInTable(Replica->Cxtions);
  4783. //
  4784. // If NumberOfPartners is non zero, subtract the Journal
  4785. // Cxtion entry since its not a real connection
  4786. //
  4787. if (NumberOfPartners > 0) {
  4788. NumberOfPartners -= 1;
  4789. }
  4790. CfgRegWriteDWord(FKC_CUMSET_N_NUMBER_OF_PARTNERS,
  4791. GuidW,
  4792. FRS_RKF_CREATE_KEY,
  4793. NumberOfPartners);
  4794. //
  4795. // Init Backup / Restore flags.
  4796. //
  4797. BurFlags = NTFRSAPI_BUR_FLAGS_NONE;
  4798. CfgRegWriteDWord(FKC_CUMSET_N_BURFLAGS, GuidW, FRS_RKF_CREATE_KEY, BurFlags);
  4799. //
  4800. // If done seeding then cleanup the sysvol seeding key.
  4801. //
  4802. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  4803. WStatus = CfgRegOpenKey(FKC_SYSVOL_SEEDING_SECTION_KEY,
  4804. NULL,
  4805. FRS_RKF_CREATE_KEY,
  4806. &HSeedingsKey);
  4807. CLEANUP1_WS(4, ":S: WARN - Cannot create sysvol seedings key for %ws;",
  4808. Replica->SetName->Name, WStatus, CLEANUP);
  4809. //
  4810. // Seeding is over so delete sysvol seeding key using replica set Name.
  4811. //
  4812. WStatus = RegDeleteKey(HSeedingsKey, Replica->ReplicaName->Name);
  4813. DPRINT1_WS(4, ":S: WARN - Cannot delete seeding key for %ws;",
  4814. Replica->SetName->Name, WStatus);
  4815. }
  4816. CLEANUP:
  4817. FRS_REG_CLOSE(HSeedingsKey);
  4818. }
  4819. BOOL
  4820. RcsReplicaIsRestored(
  4821. IN PREPLICA Replica
  4822. )
  4823. /*++
  4824. Routine Description:
  4825. Check if the replica set should be deleted because it has been
  4826. restored. Only called from RcsInitKnownReplicaSetMembers() at startup. The
  4827. BurFlags will be wiped after the replica set is recreated (if ever).
  4828. Arguments:
  4829. Replica
  4830. Return Value:
  4831. None.
  4832. --*/
  4833. {
  4834. #undef DEBSUB
  4835. #define DEBSUB "RcsReplicaIsRestored:"
  4836. DWORD WStatus;
  4837. DWORD BurFlags;
  4838. BOOL IsRestored = FALSE;
  4839. WCHAR GuidW[GUID_CHAR_LEN + 1];
  4840. //
  4841. // Sanity check
  4842. //
  4843. if (!Replica ||
  4844. !Replica->MemberName || !Replica->MemberName->Guid) {
  4845. DPRINT(0, ":S: WARN - Partial replica set ignored\n");
  4846. return IsRestored;
  4847. }
  4848. //
  4849. // Get BurFlags
  4850. // FRS_CONFIG_SECTION\Cumulative Replica Sets\Replica Sets\<guid>\BurFlags
  4851. //
  4852. GuidToStrW(Replica->MemberName->Guid, GuidW);
  4853. WStatus = CfgRegReadDWord(FKC_CUMSET_N_BURFLAGS, GuidW, FRS_RKF_CREATE_KEY, &BurFlags);
  4854. CLEANUP_WS(0, ":S: ERROR - Can't read FKC_CUMSET_N_BURFLAGS;", WStatus, CLEANUP);
  4855. if ((BurFlags & NTFRSAPI_BUR_FLAGS_RESTORE) &&
  4856. (BurFlags & NTFRSAPI_BUR_FLAGS_ACTIVE_DIRECTORY) &&
  4857. (BurFlags & (NTFRSAPI_BUR_FLAGS_PRIMARY |
  4858. NTFRSAPI_BUR_FLAGS_NON_AUTHORITATIVE))) {
  4859. //
  4860. // SUCCESS
  4861. //
  4862. IsRestored = TRUE;
  4863. DPRINT1(4, ":S: %ws has been restored\n", Replica->SetName->Name);
  4864. } else {
  4865. //
  4866. // FAILURE
  4867. //
  4868. DPRINT1(4, ":S: %ws has not been restored\n", Replica->SetName->Name);
  4869. }
  4870. CLEANUP:
  4871. return IsRestored;
  4872. }
  4873. VOID
  4874. RcsReplicaDeleteRegistry (
  4875. IN PREPLICA Replica
  4876. )
  4877. /*++
  4878. Routine Description:
  4879. This function deletes the information about the replica set
  4880. from the registry.
  4881. Arguments:
  4882. Replica
  4883. Return Value:
  4884. None.
  4885. --*/
  4886. {
  4887. #undef DEBSUB
  4888. #define DEBSUB "RcsReplicaDeleteRegistry:"
  4889. DWORD WStatus;
  4890. HKEY HKey = INVALID_HANDLE_VALUE;
  4891. HKEY HAllSetsKey = INVALID_HANDLE_VALUE;
  4892. HKEY HCumusKey = INVALID_HANDLE_VALUE;
  4893. WCHAR GuidW[GUID_CHAR_LEN + 1];
  4894. //
  4895. // Sanity check
  4896. //
  4897. if (!Replica ||
  4898. !Replica->SetName || !Replica->SetName->Name ||
  4899. !Replica->MemberName || !Replica->MemberName->Guid) {
  4900. DPRINT(0, ":S: WARN - Partial replica set ignored\n");
  4901. return;
  4902. }
  4903. //
  4904. // Delete old state from the registry
  4905. //
  4906. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4907. FRS_CONFIG_SECTION,
  4908. 0,
  4909. KEY_ALL_ACCESS,
  4910. &HKey);
  4911. CLEANUP1_WS(0, ":S: WARN - Cannot open parameters for %ws;",
  4912. Replica->SetName->Name, WStatus, CLEANUP);
  4913. //
  4914. // Create the subkey for all sets
  4915. //
  4916. WStatus = RegCreateKey(HKey, FRS_SETS_KEY, &HAllSetsKey);
  4917. CLEANUP1_WS(0, ":S: WARN - Cannot create sets key for %ws;",
  4918. Replica->SetName->Name, WStatus, CLEANUP);
  4919. //
  4920. // Delete the subkey for this set
  4921. //
  4922. GuidToStrW(Replica->MemberName->Guid, GuidW);
  4923. WStatus = RegDeleteKey(HAllSetsKey, GuidW);
  4924. CLEANUP1_WS(0, ":S: WARN - Cannot delete set key for %ws;",
  4925. Replica->SetName->Name, WStatus, CLEANUP);
  4926. //
  4927. // Cumulative Replica Sets
  4928. //
  4929. //
  4930. // Create the subkey for all sets
  4931. //
  4932. WStatus = RegCreateKey(HKey, FRS_CUMULATIVE_SETS_KEY, &HCumusKey);
  4933. CLEANUP1_WS(0, ":S: WARN - Cannot create cumulative sets key for %ws;",
  4934. Replica->SetName->Name, WStatus, CLEANUP);
  4935. //
  4936. // Delete the subkey for this set
  4937. //
  4938. WStatus = RegDeleteKey(HCumusKey, GuidW);
  4939. CLEANUP1_WS(0, ":S: WARN - Cannot delete cumulative key for %ws;",
  4940. Replica->SetName->Name, WStatus, CLEANUP);
  4941. CLEANUP:
  4942. FRS_REG_CLOSE(HKey);
  4943. FRS_REG_CLOSE(HAllSetsKey);
  4944. FRS_REG_CLOSE(HCumusKey);
  4945. }
  4946. VOID
  4947. RcsReplicaClearRegistry(
  4948. VOID
  4949. )
  4950. /*++
  4951. Routine Description:
  4952. This function deletes all of the replica set information in the registry.
  4953. This function should only be called after enumerating the configrecords.
  4954. Arguments:
  4955. None.
  4956. Return Value:
  4957. None.
  4958. --*/
  4959. {
  4960. #undef DEBSUB
  4961. #define DEBSUB "RcsReplicaClearRegistry:"
  4962. DWORD WStatus;
  4963. HKEY HKey = INVALID_HANDLE_VALUE;
  4964. HKEY HAllSetsKey = INVALID_HANDLE_VALUE;
  4965. WCHAR KeyBuf[MAX_PATH + 1];
  4966. //
  4967. // Empty the replica set info out of the registry
  4968. //
  4969. //
  4970. // Set new state in the registry
  4971. //
  4972. WStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  4973. FRS_CONFIG_SECTION,
  4974. 0,
  4975. KEY_ALL_ACCESS,
  4976. &HKey);
  4977. CLEANUP_WS(0, "WARN - Cannot open parameters for delete sets", WStatus, CLEANUP);
  4978. //
  4979. // Create the subkey for all sets
  4980. //
  4981. WStatus = RegCreateKey(HKey, FRS_SETS_KEY, &HAllSetsKey);
  4982. CLEANUP_WS(0, "WARN - Cannot create sets key for delete sets", WStatus, CLEANUP);
  4983. //
  4984. // Delete the subkeys
  4985. //
  4986. do {
  4987. WStatus = RegEnumKey(HAllSetsKey, 0, KeyBuf, MAX_PATH + 1);
  4988. if (WIN_SUCCESS(WStatus)) {
  4989. WStatus = RegDeleteKey(HAllSetsKey, KeyBuf);
  4990. }
  4991. } while (WIN_SUCCESS(WStatus));
  4992. if (WStatus != ERROR_NO_MORE_ITEMS) {
  4993. CLEANUP_WS(0, "WARN - Cannot delete all keys", WStatus, CLEANUP);
  4994. }
  4995. CLEANUP:
  4996. FRS_REG_CLOSE(HKey);
  4997. FRS_REG_CLOSE(HAllSetsKey);
  4998. }
  4999. DWORD
  5000. RcsCreateReplicaSetMember(
  5001. IN PREPLICA Replica
  5002. )
  5003. /*++
  5004. Routine Description:
  5005. Create a database record for Replica.
  5006. Arguments:
  5007. Replica
  5008. Return Value:
  5009. An Frs Error status
  5010. --*/
  5011. {
  5012. #undef DEBSUB
  5013. #define DEBSUB "RcsCreateReplicaSetMember:"
  5014. ULONG Status;
  5015. ULONG FStatus;
  5016. ULONG WStatus;
  5017. ULONG RootLen;
  5018. ULONG i, Rest;
  5019. PVOID Key;
  5020. PCXTION Cxtion;
  5021. PCOMMAND_PACKET Cmd = NULL;
  5022. PTABLE_CTX TableCtx = NULL;
  5023. PWCHAR WStatusUStr, FStatusUStr;
  5024. #define CXTION_EVENT_RPT_MAX 8
  5025. PWCHAR InWStr, OutWStr, WStrArray[CXTION_EVENT_RPT_MAX];
  5026. #define CXTION_STR_MAX 256
  5027. WCHAR CxtionStr[CXTION_STR_MAX];
  5028. extern ULONGLONG ActiveChange;
  5029. Replica->FStatus = FrsErrorSuccess;
  5030. //
  5031. // We are creating a new replica set member. Set the Cnf flag to CONFIG_FLAG_SEEDING.
  5032. // This will trigger a serialvvjoin for this replica set.
  5033. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_PRIMARY)) {
  5034. SetFlag(Replica->CnfFlags, CONFIG_FLAG_SEEDING);
  5035. }
  5036. //
  5037. // Table context?
  5038. //
  5039. TableCtx = DbsCreateTableContext(ConfigTablex);
  5040. //
  5041. // Submitted to the db command server
  5042. //
  5043. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  5044. Replica, // Replica,
  5045. CMD_CREATE_REPLICA_SET_MEMBER, // CmdRequest,
  5046. TableCtx, // TableCtx,
  5047. NULL, // CallContext,
  5048. 0, // TableType,
  5049. 0, // AccessRequest,
  5050. 0, // IndexType,
  5051. NULL, // KeyValue,
  5052. 0, // KeyValueLength,
  5053. FALSE); // Submit
  5054. //
  5055. // Don't free the packet when the command completes.
  5056. //
  5057. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  5058. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_CREATE_REPLICA_SET_MEMBER");
  5059. //
  5060. // SUBMIT DB Cmd and wait for completion.
  5061. //
  5062. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  5063. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  5064. //
  5065. // If wait or database op failed
  5066. //
  5067. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  5068. //
  5069. // If wait / submit failed then let caller know cmd srv submit failed.
  5070. //
  5071. if (FRS_SUCCESS(Replica->FStatus)) {
  5072. Replica->FStatus = FrsErrorCmdSrvFailed;
  5073. }
  5074. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Create Replica failed;",
  5075. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  5076. DPRINT_WS(0, "ERROR: Create Replica DB Command failed", WStatus);
  5077. //
  5078. // Post the failure in the event log.
  5079. //
  5080. WStatusUStr = FrsAtoW(ErrLabelW32(WStatus));
  5081. FStatusUStr = FrsAtoW(ErrLabelFrs(Replica->FStatus));
  5082. EPRINT8(EVENT_FRS_REPLICA_SET_CREATE_FAIL,
  5083. Replica->SetName->Name,
  5084. ComputerDnsName,
  5085. Replica->MemberName->Name,
  5086. Replica->Root,
  5087. Replica->Stage,
  5088. JetPath,
  5089. WStatusUStr,
  5090. FStatusUStr);
  5091. FrsFree(WStatusUStr);
  5092. FrsFree(FStatusUStr);
  5093. goto out;
  5094. }
  5095. //
  5096. // Post the success in the event log.
  5097. //
  5098. EPRINT6(EVENT_FRS_REPLICA_SET_CREATE_OK,
  5099. Replica->SetName->Name,
  5100. ComputerDnsName,
  5101. Replica->MemberName->Name,
  5102. Replica->Root,
  5103. Replica->Stage,
  5104. JetPath);
  5105. //
  5106. // Increment the Replica Sets Created Counter
  5107. //
  5108. PM_INC_CTR_SERVICE(PMTotalInst, RSCreated, 1);
  5109. InWStr = FrsGetResourceStr(IDS_INBOUND);
  5110. OutWStr = FrsGetResourceStr(IDS_OUTBOUND);
  5111. i = 0;
  5112. //
  5113. // Create the cxtions
  5114. //
  5115. Key = NULL;
  5116. while (Cxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  5117. Key = NULL;
  5118. //
  5119. // Skip inconsistent cxtions and journal cxtions
  5120. //
  5121. if ((!Cxtion->JrnlCxtion) &&
  5122. CxtionFlagIs(Cxtion, CXTION_FLAGS_CONSISTENT)) {
  5123. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, submit cmd CMD_OUTLOG_ADD_NEW_PARTNER");
  5124. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_ADD_NEW_PARTNER);
  5125. CXTION_STATE_TRACE(3, Cxtion, Replica, FStatus, "F, CMD_OUTLOG_ADD_NEW_PARTNER return");
  5126. //
  5127. // Build a string for the event log.
  5128. //
  5129. if (Cxtion->PartnerDnsName != NULL) {
  5130. _snwprintf(CxtionStr, CXTION_STR_MAX, L"%ws \"%ws\"",
  5131. Cxtion->Inbound ? InWStr : OutWStr,
  5132. Cxtion->PartnerDnsName);
  5133. CxtionStr[CXTION_STR_MAX-1] = UNICODE_NULL;
  5134. WStrArray[i++] = FrsWcsDup(CxtionStr);
  5135. if (i == CXTION_EVENT_RPT_MAX) {
  5136. EPRINT9(EVENT_FRS_REPLICA_SET_CXTIONS, Replica->SetName->Name,
  5137. WStrArray[0], WStrArray[1], WStrArray[2], WStrArray[3],
  5138. WStrArray[4], WStrArray[5], WStrArray[6], WStrArray[7]);
  5139. for (i = 0; i < CXTION_EVENT_RPT_MAX; i++) {
  5140. WStrArray[i] = FrsFree(WStrArray[i]);
  5141. }
  5142. i = 0;
  5143. }
  5144. }
  5145. }
  5146. //
  5147. // Done with this cxtion
  5148. //
  5149. GTabDelete(Replica->Cxtions, Cxtion->Name->Guid, NULL, FrsFreeType);
  5150. }
  5151. if (i > 0) {
  5152. //
  5153. // print any left over.
  5154. //
  5155. Rest = i;
  5156. for (i = Rest; i < CXTION_EVENT_RPT_MAX; i++) {
  5157. WStrArray[i] = L" ";
  5158. }
  5159. EPRINT9(EVENT_FRS_REPLICA_SET_CXTIONS, Replica->SetName->Name,
  5160. WStrArray[0], WStrArray[1], WStrArray[2], WStrArray[3],
  5161. WStrArray[4], WStrArray[5], WStrArray[6], WStrArray[7]);
  5162. for (i = 0; i < Rest; i++) {
  5163. WStrArray[i] = FrsFree(WStrArray[i]);
  5164. }
  5165. }
  5166. FrsFree(InWStr);
  5167. FrsFree(OutWStr);
  5168. //
  5169. // Set the OID data structure which is a part of the
  5170. // counter data structure stored in the hash table
  5171. // Add ReplicaSet Instance to the registry
  5172. //
  5173. if (Replica->Root != NULL) {
  5174. DPRINT(5, "PERFMON:Adding Set:REPLICA.C:1\n");
  5175. AddPerfmonInstance(REPLICASET, Replica->PerfRepSetData, Replica->Root);
  5176. }
  5177. //
  5178. // Add to the replica tables (by guid and by number)
  5179. //
  5180. Replica->Queue = FrsAlloc(sizeof(FRS_QUEUE));
  5181. FrsInitializeQueue(Replica->Queue, &ReplicaCmdServer.Control);
  5182. GTabInsertEntry(ReplicasByGuid, Replica, Replica->ReplicaName->Guid, NULL);
  5183. GTabInsertEntry(ReplicasByNumber, Replica, &Replica->ReplicaNumber, NULL);
  5184. //
  5185. // WARNING: NO Failure return is allowed after this point because the
  5186. // Replica struct is pointed at by a number of other data structs like the
  5187. // Three above. A Failure return here causes our caller to free the replica
  5188. // struct but of course it does that without first pulling it out of any of
  5189. // the above or calling the DB Service to tell it that the replica struct is
  5190. // going away This is unfortunate but its 7/8/99 and too late to clean this up.
  5191. //
  5192. //
  5193. // Set registry value "FilesNotToBackup"
  5194. //
  5195. CfgFilesNotToBackup(ReplicasByGuid);
  5196. //
  5197. // Open the replica set
  5198. //
  5199. RcsOpenReplicaSetMember(Replica);
  5200. //
  5201. // See comment above.
  5202. //
  5203. Replica->FStatus = FrsErrorSuccess;
  5204. //if (Replica->FStatus != FrsErrorSuccess) {
  5205. // goto out;
  5206. //}
  5207. //
  5208. // Insert replica information into the registry
  5209. //
  5210. RcsReplicaSetRegistry(Replica);
  5211. out:
  5212. if (Cmd) {
  5213. FrsFreeCommand(Cmd, NULL);
  5214. }
  5215. if (TableCtx) {
  5216. DbsFreeTableContext(TableCtx, 0);
  5217. }
  5218. if (!FRS_SUCCESS(Replica->FStatus)) {
  5219. //
  5220. // Ds poll thread will restart the replica during the next
  5221. // polling cycle if ActiveChange is set to 0.
  5222. //
  5223. ActiveChange = 0;
  5224. }
  5225. return Replica->FStatus;
  5226. }
  5227. BOOL
  5228. RcsReplicaHasExpired(
  5229. IN PREPLICA Replica
  5230. )
  5231. /*++
  5232. Routine Description:
  5233. Has this replica's tombstone expired?
  5234. Arguments:
  5235. Replica
  5236. Return Value:
  5237. TRUE - Tombstone has expired.
  5238. FALSE - Not tombstoned or tombstone has not expired.
  5239. --*/
  5240. {
  5241. #undef DEBSUB
  5242. #define DEBSUB "RcsReplicaHasExpired:"
  5243. FILETIME FileTime;
  5244. ULONGLONG Now;
  5245. //
  5246. // Is it tombstoned?
  5247. //
  5248. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  5249. GetSystemTimeAsFileTime(&FileTime);
  5250. COPY_TIME(&Now, &FileTime);
  5251. //
  5252. // Has it expired?
  5253. //
  5254. if (Now > Replica->MembershipExpires) {
  5255. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Replica has expired");
  5256. return TRUE;
  5257. }
  5258. }
  5259. //
  5260. // Not expired
  5261. //
  5262. return FALSE;
  5263. }
  5264. PREPLICA
  5265. RcsFindSysVolByType(
  5266. IN DWORD ReplicaSetType
  5267. )
  5268. /*++
  5269. Routine Description:
  5270. Find the sysvol with the indicated type.
  5271. Arguments:
  5272. ReplicaSetType
  5273. Return Value:
  5274. None.
  5275. --*/
  5276. {
  5277. #undef DEBSUB
  5278. #define DEBSUB "RcsFindSysVolByType:"
  5279. PREPLICA Replica;
  5280. PVOID Key;
  5281. //
  5282. // Find a match for the sysvol by name
  5283. //
  5284. Key = NULL;
  5285. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  5286. if (!FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType)) {
  5287. continue;
  5288. }
  5289. //
  5290. // SysVol types match
  5291. //
  5292. if (Replica->ReplicaSetType == ReplicaSetType) {
  5293. //
  5294. // Don't return expired replicas
  5295. //
  5296. if (RcsReplicaHasExpired(Replica)) {
  5297. DPRINT2(4, ":S: %ws\\%ws: IGNORING, tombstoned expired.\n",
  5298. Replica->SetName->Name, Replica->MemberName->Name);
  5299. continue;
  5300. }
  5301. return Replica;
  5302. }
  5303. }
  5304. return NULL;
  5305. }
  5306. PREPLICA
  5307. RcsFindSysVolByName(
  5308. IN PWCHAR ReplicaSetName
  5309. )
  5310. /*++
  5311. Routine Description:
  5312. The replica set from the Ds could not be located by its Ds-object guid.
  5313. This may be a sysvol that has been seeded but hasn't picked up its
  5314. guids from its Ds objects. Try to find the sysvol by name.
  5315. Arguments:
  5316. ReplicaSetName
  5317. Return Value:
  5318. None.
  5319. --*/
  5320. {
  5321. #undef DEBSUB
  5322. #define DEBSUB "RcsFindSysVolByName:"
  5323. PREPLICA Replica;
  5324. PVOID Key;
  5325. FILETIME FileTime;
  5326. ULONGLONG Now;
  5327. //
  5328. // Find a match for the sysvol by name
  5329. //
  5330. Key = NULL;
  5331. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  5332. if (!FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType)) {
  5333. continue;
  5334. }
  5335. if (WSTR_EQ(ReplicaSetName, Replica->ReplicaName->Name)) {
  5336. //
  5337. // Don't return expired replicas
  5338. //
  5339. if (RcsReplicaHasExpired(Replica)) {
  5340. DPRINT2(4, ":S: %ws\\%ws: IGNORING, tombstoned expired.\n",
  5341. Replica->SetName->Name, Replica->MemberName->Name);
  5342. continue;
  5343. }
  5344. return Replica;
  5345. }
  5346. }
  5347. return NULL;
  5348. }
  5349. PREPLICA
  5350. RcsFindNextReplica(
  5351. IN PVOID *Key
  5352. )
  5353. /*++
  5354. Routine Description:
  5355. Return the next replica in the active replication subsystem.
  5356. Arguments:
  5357. Key
  5358. Return Value:
  5359. Replica or NULL.
  5360. --*/
  5361. {
  5362. #undef DEBSUB
  5363. #define DEBSUB "RcsFindNextReplica:"
  5364. //
  5365. // Next replica
  5366. //
  5367. return GTabNextDatum(ReplicasByGuid, Key);
  5368. }
  5369. VOID
  5370. RcsMergeReplicaFromDs(
  5371. IN PREPLICA DsReplica
  5372. )
  5373. /*++
  5374. Routine Description:
  5375. Merge this replica from the DS with the active replicas.
  5376. Arguments:
  5377. DsReplica
  5378. Return Value:
  5379. None.
  5380. --*/
  5381. {
  5382. #undef DEBSUB
  5383. #define DEBSUB "RcsMergeReplicaFromDs:"
  5384. PVOID Key;
  5385. PREPLICA Replica;
  5386. DPRINT(4, ":S: Merge Replica from the DS\n");
  5387. FRS_PRINT_TYPE(4, DsReplica);
  5388. //
  5389. // If the replica is not in the table, create it
  5390. //
  5391. Replica = GTabLookup(ReplicasByGuid, DsReplica->ReplicaName->Guid, NULL);
  5392. if (Replica && REPLICA_STATE_NEEDS_RESTORE(Replica->ServiceState)) {
  5393. //
  5394. // This replica is on the fault list and will be deleted at the end
  5395. // of poll when we process the fault list. We should not try to
  5396. // do anything with this replica. Just remove it from ReplicasNotInTheDs
  5397. // table and free the DsReplica structure.
  5398. //
  5399. GTabDelete(ReplicasNotInTheDs, Replica->ReplicaName->Guid, NULL, NULL);
  5400. FrsFreeType(DsReplica);
  5401. return;
  5402. }
  5403. //
  5404. // Might be a sysvol that has been seeded but hasn't picked up
  5405. // its final guids from its Ds objects. Try to find it by name.
  5406. //
  5407. if (!Replica &&
  5408. FRS_RSTYPE_IS_SYSVOL(DsReplica->ReplicaSetType)) {
  5409. //
  5410. // Pretend there isn't a match if the replica has already
  5411. // been merged with the info in the DS. We only want to merge once.
  5412. // We deduce that the merge hasn't occured if the replica set
  5413. // guid and the root guid are the same. They should be different
  5414. // since the replica set guid wasn't available when the root
  5415. // guid was created.
  5416. //
  5417. // Otherwise, we could end up with a sysvol replica that
  5418. // claims its root path is an old sysvol root instead of a new
  5419. // sysvol root (assuming ntfrsupg was run twice).
  5420. //
  5421. // The old sysvol will be tombstoned and will eventually
  5422. // be deleted.
  5423. //
  5424. // Note: seeding during dcpromo is now broken since root guid
  5425. // is created when set is created in the db and so
  5426. // never matches the set guid. fix if seeding during
  5427. // dcpromo is resurrected (with CnfFlag)
  5428. //
  5429. Replica = RcsFindSysVolByName(DsReplica->ReplicaName->Name);
  5430. if (Replica && !GUIDS_EQUAL(Replica->SetName->Guid,
  5431. Replica->ReplicaRootGuid)) {
  5432. Replica = NULL;
  5433. }
  5434. }
  5435. if (Replica) {
  5436. //
  5437. // Replica still exists in the DS; don't delete it
  5438. //
  5439. GTabDelete(ReplicasNotInTheDs, Replica->ReplicaName->Guid, NULL, NULL);
  5440. //
  5441. // Tell the replica to merge with the information from the DS
  5442. // and to retry any failed or new startup operations like
  5443. // starting the journal and joining new connections.
  5444. //
  5445. if (DsReplica->Consistent) {
  5446. (VOID) RcsSubmitReplicaSync(Replica, DsReplica, NULL, CMD_START);
  5447. } else {
  5448. //
  5449. // WARN: it looks like it gets freed here but still lives in the
  5450. // ReplicasByGuid table --- AV later if table enumed.
  5451. // RcsBeginMergeWithDs() does an enum of this table.
  5452. //
  5453. FrsFreeType(DsReplica);
  5454. }
  5455. } else {
  5456. //
  5457. // Insert the replica into the database and add it to the table
  5458. // of active replicas. Comm packets will continue to be discarded
  5459. // because the replica is not yet "accepting" remote change orders
  5460. //
  5461. // Replica sets for sysvols must exist in the database prior to
  5462. // the entries in the Ds. If the opposite is true then the entry
  5463. // in the Ds is bogus; probably the result of the Ds polling thread
  5464. // being unabled to delete the Ds objects after a dcdemote. In
  5465. // any case, ignore the Ds.
  5466. //
  5467. if (DsReplica->Consistent &&
  5468. FRS_SUCCESS(RcsCreateReplicaSetMember(DsReplica))) {
  5469. RcsSubmitReplicaSync(DsReplica, NULL, NULL, CMD_START);
  5470. } else {
  5471. //
  5472. // WARN: The above could happen here too if Consistent is false
  5473. // and DsReplica is in a table.
  5474. // Also happens if RcsCreateReplicaSetMember() fails.
  5475. // since it can fail after DsReplica is added to.
  5476. // the ReplicasByGuid and ReplicasByNumber tables. Sigh.
  5477. //
  5478. FrsFreeType(DsReplica);
  5479. }
  5480. }
  5481. }
  5482. VOID
  5483. RcsMergeReplicaGName(
  5484. IN PREPLICA Replica,
  5485. IN PWCHAR Tag,
  5486. IN PGNAME GName,
  5487. IN PGNAME NewGName
  5488. )
  5489. /*++
  5490. Routine Description:
  5491. Update the Replica with new information from NewReplica.
  5492. Arguments:
  5493. Replica
  5494. GName
  5495. NewGName
  5496. Return Value:
  5497. None.
  5498. --*/
  5499. {
  5500. #undef DEBSUB
  5501. #define DEBSUB "RcsMergeReplicaGName:"
  5502. //
  5503. // Name
  5504. //
  5505. if (WSTR_NE(GName->Name, NewGName->Name)) {
  5506. DPRINT5(0, "++ %ws\\%ws - Changing %ws name from %ws to %ws.\n",
  5507. Replica->ReplicaName->Name, Replica->MemberName->Name, Tag,
  5508. GName->Name, NewGName->Name);
  5509. FrsDsSwapPtrs(&GName->Name, &NewGName->Name);
  5510. Replica->NeedsUpdate = TRUE;
  5511. }
  5512. //
  5513. // Guid
  5514. //
  5515. if (!GUIDS_EQUAL(GName->Guid, NewGName->Guid)) {
  5516. DPRINT3(0, "++ %ws\\%ws - Changing guid for %ws.\n",
  5517. Replica->ReplicaName->Name, Replica->MemberName->Name, Tag);
  5518. FrsDsSwapPtrs(&GName->Guid, &NewGName->Guid);
  5519. Replica->NeedsUpdate = TRUE;
  5520. }
  5521. }
  5522. VOID
  5523. RcsMergeReplicaFields(
  5524. IN PREPLICA Replica,
  5525. IN PREPLICA NewReplica
  5526. )
  5527. /*++
  5528. Routine Description:
  5529. Update the Replica with new information from NewReplica.
  5530. Arguments:
  5531. Replica - active replica
  5532. NewReplica
  5533. Return Value:
  5534. None.
  5535. --*/
  5536. {
  5537. #undef DEBSUB
  5538. #define DEBSUB "RcsMergeReplicaFields:"
  5539. BOOL IsSysVol;
  5540. PWCHAR DirFilterList;
  5541. PWCHAR TmpList;
  5542. UNICODE_STRING TempUStr;
  5543. if (NewReplica == NULL) {
  5544. return;
  5545. }
  5546. //
  5547. // CHECK FIELDS THAT CAN'T CHANGE
  5548. //
  5549. //
  5550. // Replica type
  5551. //
  5552. if (Replica->ReplicaSetType != NewReplica->ReplicaSetType) {
  5553. DPRINT4(0, "++ ERROR - %ws\\%ws - Changing replica type from %d to %d is not allowed.\n",
  5554. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5555. Replica->ReplicaSetType, NewReplica->ReplicaSetType);
  5556. NewReplica->Consistent = FALSE;
  5557. return;
  5558. }
  5559. //
  5560. // ReplicaName Guid
  5561. //
  5562. IsSysVol = FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType);
  5563. if (!GUIDS_EQUAL(Replica->ReplicaName->Guid, NewReplica->ReplicaName->Guid)) {
  5564. if (!IsSysVol) {
  5565. DPRINT2(0, "++ ERROR - %ws\\%ws - Changing replica guid is not allowed.\n",
  5566. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5567. return;
  5568. }
  5569. }
  5570. //
  5571. // Set Guid
  5572. //
  5573. if (!GUIDS_EQUAL(Replica->SetName->Guid, NewReplica->SetName->Guid)) {
  5574. if (!IsSysVol) {
  5575. DPRINT2(0, "++ ERROR - %ws\\%ws - Changing set guid is not allowed.\n",
  5576. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5577. return;
  5578. }
  5579. }
  5580. //
  5581. // Root Guid
  5582. // Cannot be changed because it is created whenever the set
  5583. // is created in the DB. The root guid from the DS is always
  5584. // ignored.
  5585. //
  5586. // if (!GUIDS_EQUAL(Replica->ReplicaRootGuid, NewReplica->ReplicaRootGuid)) {
  5587. // if (!IsSysVol) {
  5588. // DPRINT2(0, "++ ERROR - %ws\\%ws - Changing root guid "
  5589. // "is not allowed.\n",
  5590. // Replica->ReplicaName->Name,
  5591. // Replica->MemberName->Name);
  5592. // return;
  5593. // }
  5594. // }
  5595. //
  5596. // Stage Path.
  5597. //
  5598. if (WSTR_NE(Replica->Stage, NewReplica->Stage)) {
  5599. DPRINT3(3, "The staging path for the replica set (%ws) has changed from (%ws) to (%ws).\n",
  5600. Replica->SetName->Name, Replica->Stage, NewReplica->Stage);
  5601. EPRINT3(EVENT_FRS_STAGE_HAS_CHANGED, Replica->SetName->Name, Replica->Stage,
  5602. NewReplica->Stage);
  5603. FrsFree(Replica->NewStage);
  5604. Replica->NewStage = FrsWcsDup(NewReplica->Stage);
  5605. Replica->NeedsUpdate = TRUE;
  5606. }
  5607. //
  5608. // Updating the replica's guid is tricky since the guid is
  5609. // used by the other subsystems, like RPC, to find a replica
  5610. // set. Both the old and new guid are temporarily in the
  5611. // lookup table. Once the guid is updated, the old entry is
  5612. // deleted.
  5613. //
  5614. if (!GUIDS_EQUAL(Replica->ReplicaName->Guid, NewReplica->ReplicaName->Guid)) {
  5615. DPRINT2(0, "++ %ws\\%ws - Changing guid for Replica.\n",
  5616. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5617. GTabInsertEntry(ReplicasByGuid, Replica, NewReplica->ReplicaName->Guid, NULL);
  5618. FrsDsSwapPtrs(&Replica->ReplicaName->Guid, &NewReplica->ReplicaName->Guid);
  5619. GTabDelete(ReplicasByGuid, NewReplica->ReplicaName->Guid, NULL, NULL);
  5620. COPY_GUID(NewReplica->ReplicaName->Guid, Replica->ReplicaName->Guid);
  5621. Replica->NeedsUpdate = TRUE;
  5622. }
  5623. //
  5624. // FIELDS THAT CAN CHANGE
  5625. //
  5626. //
  5627. // FrsRsoFlags
  5628. //
  5629. Replica->FrsRsoFlags = NewReplica->FrsRsoFlags;
  5630. //
  5631. // ReplicaName (note that the guid was handled above)
  5632. //
  5633. RcsMergeReplicaGName(Replica, L"Replica", Replica->ReplicaName, NewReplica->ReplicaName);
  5634. //
  5635. // MemberName
  5636. //
  5637. RcsMergeReplicaGName(Replica, L"Member", Replica->MemberName, NewReplica->MemberName);
  5638. //
  5639. // SetName
  5640. //
  5641. RcsMergeReplicaGName(Replica, L"Set", Replica->SetName, NewReplica->SetName);
  5642. //
  5643. // Schedule
  5644. //
  5645. if (Replica->Schedule || NewReplica->Schedule) {
  5646. if ((Replica->Schedule && !NewReplica->Schedule) ||
  5647. (!Replica->Schedule && NewReplica->Schedule) ||
  5648. (Replica->Schedule->Size != NewReplica->Schedule->Size) ||
  5649. (memcmp(Replica->Schedule,
  5650. NewReplica->Schedule,
  5651. Replica->Schedule->Size))) {
  5652. DPRINT2(0, "++ %ws\\%ws - Changing replica schedule.\n",
  5653. Replica->ReplicaName->Name, Replica->MemberName->Name);
  5654. FrsDsSwapPtrs(&Replica->Schedule, &NewReplica->Schedule);
  5655. Replica->NeedsUpdate = TRUE;
  5656. }
  5657. }
  5658. //
  5659. // File Exclusion Filter
  5660. //
  5661. if (Replica->FileFilterList || NewReplica->FileFilterList) {
  5662. if ((Replica->FileFilterList && !NewReplica->FileFilterList) ||
  5663. (!Replica->FileFilterList && NewReplica->FileFilterList) ||
  5664. WSTR_NE(Replica->FileFilterList, NewReplica->FileFilterList)) {
  5665. DPRINT4(0, "++ %ws\\%ws - Changing file filter from %ws to %ws.\n",
  5666. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5667. Replica->FileFilterList, NewReplica->FileFilterList);
  5668. FrsDsSwapPtrs(&Replica->FileFilterList, &NewReplica->FileFilterList);
  5669. if (!Replica->FileFilterList) {
  5670. Replica->FileFilterList = FRS_DS_COMPOSE_FILTER_LIST(
  5671. NULL,
  5672. RegistryFileExclFilterList,
  5673. DEFAULT_FILE_FILTER_LIST);
  5674. }
  5675. RtlInitUnicodeString(&TempUStr, Replica->FileFilterList);
  5676. LOCK_REPLICA(Replica);
  5677. FrsLoadNameFilter(&TempUStr, &Replica->FileNameFilterHead);
  5678. UNLOCK_REPLICA(Replica);
  5679. Replica->NeedsUpdate = TRUE;
  5680. }
  5681. }
  5682. //
  5683. // File Inclusion Filter (Registry only)
  5684. //
  5685. if (Replica->FileInclFilterList || NewReplica->FileInclFilterList) {
  5686. if ((Replica->FileInclFilterList && !NewReplica->FileInclFilterList) ||
  5687. (!Replica->FileInclFilterList && NewReplica->FileInclFilterList) ||
  5688. WSTR_NE(Replica->FileInclFilterList, NewReplica->FileInclFilterList)) {
  5689. DPRINT4(0, "++ %ws\\%ws - Changing file Inclusion filter from %ws to %ws.\n",
  5690. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5691. Replica->FileInclFilterList, NewReplica->FileInclFilterList);
  5692. FrsDsSwapPtrs(&Replica->FileInclFilterList, &NewReplica->FileInclFilterList);
  5693. RtlInitUnicodeString(&TempUStr, Replica->FileInclFilterList);
  5694. LOCK_REPLICA(Replica);
  5695. FrsLoadNameFilter(&TempUStr, &Replica->FileNameInclFilterHead);
  5696. UNLOCK_REPLICA(Replica);
  5697. Replica->NeedsUpdate = TRUE;
  5698. }
  5699. }
  5700. //
  5701. // Directory Filter
  5702. //
  5703. if (Replica->DirFilterList || NewReplica->DirFilterList) {
  5704. if ((Replica->DirFilterList && !NewReplica->DirFilterList) ||
  5705. (!Replica->DirFilterList && NewReplica->DirFilterList) ||
  5706. WSTR_NE(Replica->DirFilterList, NewReplica->DirFilterList)) {
  5707. DPRINT4(0, "++ %ws\\%ws - Changing dir filter from %ws to %ws.\n",
  5708. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5709. Replica->DirFilterList, NewReplica->DirFilterList);
  5710. FrsDsSwapPtrs(&Replica->DirFilterList, &NewReplica->DirFilterList);
  5711. if (!Replica->DirFilterList) {
  5712. Replica->DirFilterList = FRS_DS_COMPOSE_FILTER_LIST(
  5713. NULL,
  5714. RegistryDirExclFilterList,
  5715. DEFAULT_DIR_FILTER_LIST);
  5716. }
  5717. //
  5718. // Add the pre-install dir, the pre-existing dir and the
  5719. // replication suppression prefix name to the dir filter list.
  5720. //
  5721. DirFilterList = FrsWcsCat3(NTFRS_PREINSTALL_DIRECTORY,
  5722. L",",
  5723. Replica->DirFilterList);
  5724. TmpList = FrsWcsCat3(NTFRS_PREEXISTING_DIRECTORY, L",", DirFilterList);
  5725. FrsFree(DirFilterList);
  5726. DirFilterList = TmpList;
  5727. #if 0
  5728. //
  5729. // This workaround did not solve the DFS dir create problem because the
  5730. // later rename of the dir to the final target name is treated like
  5731. // a movein operation so the dir replicates which was what we were trying
  5732. // to avoid since that led to name morph collisions on other DFS alternates
  5733. // which were doing the same thing.
  5734. //
  5735. TmpList = FrsWcsCat3(NTFRS_REPL_SUPPRESS_PREFIX, L"*,", DirFilterList);
  5736. FrsFree(DirFilterList);
  5737. DirFilterList = TmpList;
  5738. #endif
  5739. DPRINT3(0, "++ %ws\\%ws - New dir filter: %ws\n",
  5740. Replica->ReplicaName->Name, Replica->MemberName->Name, DirFilterList);
  5741. RtlInitUnicodeString(&TempUStr, DirFilterList);
  5742. LOCK_REPLICA(Replica);
  5743. FrsLoadNameFilter(&TempUStr, &Replica->DirNameFilterHead);
  5744. UNLOCK_REPLICA(Replica);
  5745. FrsFree(DirFilterList);
  5746. Replica->NeedsUpdate = TRUE;
  5747. }
  5748. }
  5749. //
  5750. // Directory Inclusion Filter (Registry only)
  5751. //
  5752. if (Replica->DirInclFilterList || NewReplica->DirInclFilterList) {
  5753. if ((Replica->DirInclFilterList && !NewReplica->DirInclFilterList) ||
  5754. (!Replica->DirInclFilterList && NewReplica->DirInclFilterList) ||
  5755. WSTR_NE(Replica->DirInclFilterList, NewReplica->DirInclFilterList)) {
  5756. DPRINT4(0, "++ %ws\\%ws - Changing dir inclusion filter from %ws to %ws.\n",
  5757. Replica->ReplicaName->Name, Replica->MemberName->Name,
  5758. Replica->DirInclFilterList, NewReplica->DirInclFilterList);
  5759. FrsDsSwapPtrs(&Replica->DirInclFilterList, &NewReplica->DirInclFilterList);
  5760. RtlInitUnicodeString(&TempUStr, Replica->DirInclFilterList);
  5761. LOCK_REPLICA(Replica);
  5762. FrsLoadNameFilter(&TempUStr, &Replica->DirNameInclFilterHead);
  5763. UNLOCK_REPLICA(Replica);
  5764. Replica->NeedsUpdate = TRUE;
  5765. }
  5766. }
  5767. //
  5768. // The Replica->CnfFlags are only valid when the replica is created.
  5769. // They are ignored thereafter.
  5770. //
  5771. }
  5772. PCXTION
  5773. RcsCreateSeedingCxtion(
  5774. IN PREPLICA Replica,
  5775. IN PCXTION SeedingCxtion
  5776. )
  5777. /*++
  5778. Routine Description:
  5779. Create a seeding cxtion if needed.
  5780. This function may open and read the registry.
  5781. This function may RPC to another computer.
  5782. Arguments:
  5783. Replica - active replica
  5784. SeedingCxtion - seeding cxtion
  5785. Return Value:
  5786. NULL - no seeding cxtion needed (or possible)
  5787. Otherwise, a seeding cxtion with a matching cxtion on
  5788. another computer (specified by the registry).
  5789. --*/
  5790. {
  5791. #undef DEBSUB
  5792. #define DEBSUB "RcsCreateSeedingCxtion:"
  5793. DWORD WStatus;
  5794. PVOID Key;
  5795. ULONG ParentAuthLevel;
  5796. PWCHAR KeyName = NULL;
  5797. PWCHAR ParentComputer = NULL;
  5798. PWCHAR ParentPrincName = NULL;
  5799. PWCHAR ParentNT4Name = NULL;
  5800. handle_t ParentHandle = NULL;
  5801. PWCHAR LocalServerName = NULL;
  5802. GUID SeedingGuid;
  5803. GUID ParentGuid;
  5804. PSID pSid = NULL;
  5805. PWCHAR SidString = NULL;
  5806. PWCHAR DomainName = NULL;
  5807. DWORD ccDomainName = 0;
  5808. DWORD cbSid = 0;
  5809. SID_NAME_USE SidUse = SidTypeInvalid;
  5810. extern ULONGLONG ActiveChange;
  5811. //
  5812. // This operation is non-critical. The sysvol will eventually seed
  5813. // after the FRS and KCC information converges on the appropriate
  5814. // DCs. Hence, trap exceptions and ignore them.
  5815. //
  5816. try {
  5817. //
  5818. // Already created. Seeding during dcpromo.
  5819. //
  5820. if (SeedingCxtion) {
  5821. goto CLEANUP_OK;
  5822. }
  5823. //
  5824. // No seeding cxtion is needed
  5825. //
  5826. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  5827. goto CLEANUP_OK;
  5828. }
  5829. //
  5830. // Do not create another seeding cxtion. The sysvol will eventually
  5831. // be seeded from a KCC generated cxtion (from the DS). But it may
  5832. // take awhile because both the FRS objects and the KCC must converge
  5833. // after the KCC has run. And then the FRS service has to notice the
  5834. // convergence.
  5835. //
  5836. Key = NULL;
  5837. while (SeedingCxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  5838. if (CxtionFlagIs(SeedingCxtion, CXTION_FLAGS_VOLATILE)) {
  5839. break;
  5840. }
  5841. }
  5842. if (SeedingCxtion) {
  5843. SeedingCxtion = NULL;
  5844. goto CLEANUP_OK;
  5845. }
  5846. //
  5847. // Retrieve the parent computer's name
  5848. //
  5849. WStatus = CfgRegReadString(FKC_SYSVOL_SEEDING_N_PARENT,
  5850. Replica->ReplicaName->Name,
  5851. 0,
  5852. &ParentComputer);
  5853. CLEANUP1_WS(0, ":X: ERROR - no parent computer for %ws :",
  5854. Replica->ReplicaName->Name, WStatus, CLEANUP_OK);
  5855. //
  5856. // Bind to the parent
  5857. //
  5858. WStatus = NtFrsApi_Rpc_BindEx(ParentComputer,
  5859. &ParentPrincName,
  5860. &ParentHandle,
  5861. &ParentAuthLevel);
  5862. CLEANUP_WS(0, "ERROR - binding", WStatus, CLEANUP);
  5863. DPRINT3(4, ":X: Seeding cxtion has bound to %ws (princ name is %ws) auth level %d\n",
  5864. ParentComputer, ParentPrincName, ParentAuthLevel);
  5865. //
  5866. // Placeholder guid for the cxtion
  5867. // Updated once the Ds objects are created
  5868. //
  5869. FrsUuidCreate(&SeedingGuid);
  5870. //
  5871. // Get local computer's NT4 style name. Send ServerPrincName if
  5872. // conversion fails.
  5873. //
  5874. LocalServerName = FrsDsConvertName(DsHandle, ServerPrincName, DS_USER_PRINCIPAL_NAME, NULL, DS_NT4_ACCOUNT_NAME);
  5875. if (LocalServerName == NULL) {
  5876. LocalServerName = FrsWcsDup(ServerPrincName);
  5877. }
  5878. //
  5879. // Create volatile cxtion on the parent
  5880. //
  5881. try {
  5882. WStatus = FrsRpcStartPromotionParent(ParentHandle,
  5883. NULL,
  5884. NULL,
  5885. Replica->SetName->Name,
  5886. NTFRSAPI_REPLICA_SET_TYPE_DOMAIN,
  5887. ParentComputer,
  5888. // Change the following to ComputerName for old DNS behavior
  5889. ComputerDnsName,
  5890. LocalServerName, // NT$ style name or user principal name.
  5891. ParentAuthLevel,
  5892. sizeof(GUID),
  5893. (PUCHAR)&SeedingGuid,
  5894. (PUCHAR)Replica->MemberName->Guid,
  5895. (PUCHAR)&ParentGuid);
  5896. } except (EXCEPTION_EXECUTE_HANDLER) {
  5897. GET_EXCEPTION_CODE(WStatus);
  5898. }
  5899. CLEANUP1_WS(0, ":X: ERROR - Can't create seeding cxtion on parent %ws;",
  5900. ParentComputer, WStatus, CLEANUP);
  5901. DPRINT3(4, ":X: Seeding cxtion has been created on %ws (princ name is %ws) auth level %d\n",
  5902. ParentComputer, ParentPrincName, ParentAuthLevel);
  5903. ParentNT4Name = FrsDsConvertName(DsHandle, ParentPrincName, DS_USER_PRINCIPAL_NAME, NULL, DS_NT4_ACCOUNT_NAME);
  5904. if (ParentNT4Name == NULL) {
  5905. ParentNT4Name = FrsWcsDup(ParentPrincName);
  5906. }
  5907. if(!LookupAccountName(NULL,
  5908. ParentNT4Name,
  5909. NULL, // NULL means the function will give us the required size
  5910. &cbSid,
  5911. NULL, // NULL means the function will give us the required size
  5912. &ccDomainName,
  5913. &SidUse
  5914. )) {
  5915. //
  5916. // Couldn't find parent's sid!!
  5917. //
  5918. WStatus = GetLastError();
  5919. if(WStatus != ERROR_INSUFFICIENT_BUFFER) {
  5920. DPRINT2(0, "++ ERROR - Unable to get SID for %ws. WStatus = 0x%08x\n", ParentNT4Name, WStatus);
  5921. goto CLEANUP;
  5922. }
  5923. WStatus = ERROR_SUCCESS;
  5924. }
  5925. //
  5926. // Allocate the needed memory and make the call again.
  5927. //
  5928. DomainName = FrsAlloc(sizeof(WCHAR) * (ccDomainName + 1));
  5929. pSid = FrsAlloc(cbSid);
  5930. if(!LookupAccountName(NULL,
  5931. ParentNT4Name,
  5932. pSid,
  5933. &cbSid,
  5934. DomainName,
  5935. &ccDomainName,
  5936. &SidUse
  5937. )) {
  5938. //
  5939. // Couldn't find parent's sid!!
  5940. //
  5941. WStatus = GetLastError();
  5942. DPRINT2(0, "++ ERROR - Unable to get SID for %ws. WStatus = 0x%08x\n", ParentNT4Name, WStatus);
  5943. goto CLEANUP;
  5944. }
  5945. /*
  5946. if(SidUse != SidTypeComputer) {
  5947. //
  5948. // This Sid is the wrong type.
  5949. //
  5950. DPRINT2(4, "++ WARNING - SID for %ws is not SidTypeComputer. SidUse = %d\n", ParentNT4Name, SidUse);
  5951. }
  5952. */
  5953. if(!ConvertSidToStringSid(pSid, &SidString)) {
  5954. WStatus = GetLastError();
  5955. DPRINT1(0, "++ ERROR - Unable to convert SID to string. WStatus = 0x%08x\n", WStatus);
  5956. goto CLEANUP;
  5957. }
  5958. //
  5959. // Create local seeding cxtion
  5960. //
  5961. SeedingCxtion = FrsAllocType(CXTION_TYPE);
  5962. SeedingCxtion->PartnerSid = FrsWcsDup(SidString);
  5963. LocalFree(SidString);
  5964. SeedingCxtion->Inbound = TRUE;
  5965. SetCxtionFlag(SeedingCxtion, CXTION_FLAGS_CONSISTENT |
  5966. CXTION_FLAGS_VOLATILE);
  5967. SeedingCxtion->Name = FrsBuildGName(FrsDupGuid(&SeedingGuid),
  5968. FrsWcsDup(ParentComputer));
  5969. SeedingCxtion->Partner = FrsBuildGName(FrsDupGuid(&ParentGuid),
  5970. FrsWcsDup(ParentComputer));
  5971. SeedingCxtion->PartnerDnsName = FrsWcsDup(ParentComputer);
  5972. SeedingCxtion->PartnerPrincName = FrsWcsDup(ParentNT4Name);
  5973. SeedingCxtion->PartSrvName = FrsWcsDup(ParentComputer);
  5974. SeedingCxtion->PartnerAuthLevel = ParentAuthLevel;
  5975. SetCxtionState(SeedingCxtion, CxtionStateUnjoined);
  5976. CLEANUP_OK:
  5977. WStatus = ERROR_SUCCESS;
  5978. CLEANUP:;
  5979. } except (EXCEPTION_EXECUTE_HANDLER) {
  5980. GET_EXCEPTION_CODE(WStatus);
  5981. DPRINT_WS(0, "ERROR - Exception", WStatus);
  5982. }
  5983. try {
  5984. if (ParentHandle) {
  5985. RpcBindingFree(&ParentHandle);
  5986. }
  5987. FrsFree(KeyName);
  5988. FrsFree(ParentComputer);
  5989. FrsFree(ParentPrincName);
  5990. FrsFree(ParentNT4Name);
  5991. FrsFree(LocalServerName);
  5992. FrsFree(pSid);
  5993. FrsFree(DomainName);
  5994. } except (EXCEPTION_EXECUTE_HANDLER) {
  5995. GET_EXCEPTION_CODE(WStatus);
  5996. DPRINT_WS(0, "ERROR - Cleanup Exception", WStatus);
  5997. }
  5998. //
  5999. // Retry later. ERROR_SUCCESS means don't retry; there may have
  6000. // been errors that retrying is unlikely to fix.
  6001. //
  6002. if (!WIN_SUCCESS(WStatus)) {
  6003. //
  6004. // Ds poll thread will restart the replica during the next
  6005. // polling cycle if ActiveChange is set to 0.
  6006. //
  6007. ActiveChange = 0;
  6008. }
  6009. return SeedingCxtion;
  6010. }
  6011. VOID
  6012. RcsSetCxtionSchedule(
  6013. IN PREPLICA Replica,
  6014. IN PCXTION Cxtion,
  6015. IN DWORD ScheduleIndex,
  6016. IN DWORD ScheduleShift
  6017. )
  6018. /*++
  6019. Routine Description:
  6020. Set or clear the CXTION_FLAGS_SCHEDULE_OFF bit in the cxtion
  6021. depending on whether the 15min interval identified by
  6022. (ScheduleIndex, ScheduleShift) is set.
  6023. Trigger schedules use the bit differently. A triggered cxtion
  6024. may actually be joined and running even if the schedule is OFF
  6025. because the current set of cos haven't been received/sent, yet.
  6026. So, be careful. The interpretation of CXTION_FLAGS_SCHEDULE_OFF
  6027. varies with the type of schedule.
  6028. Arguments:
  6029. Replica
  6030. Return Value:
  6031. None.
  6032. --*/
  6033. {
  6034. #undef DEBSUB
  6035. #define DEBSUB "RcsSetCxtionSchedule:"
  6036. ULONG i;
  6037. BOOL On;
  6038. PSCHEDULE Schedule;
  6039. //
  6040. // Set or clear CXTION_FLAGS_SCHEDULE_OFF
  6041. //
  6042. //
  6043. // Inbound connection AND In seeding state AND option is set to
  6044. // ignore schedule.
  6045. //
  6046. if (Cxtion->Inbound &&
  6047. ((BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  6048. Replica->IsSeeding) &&
  6049. NTDSCONN_IGNORE_SCHEDULE(Cxtion->Options))
  6050. ) {
  6051. Schedule = NULL;
  6052. //
  6053. // Outbound connection AND (In vvjoin mode OR never joined) AND option is set to
  6054. // ignore schedule.
  6055. //
  6056. } else if (!Cxtion->Inbound &&
  6057. ((Cxtion->OLCtx == NULL) ||
  6058. WaitingToVVJoin(Cxtion->OLCtx) ||
  6059. InVVJoinMode(Cxtion->OLCtx)) &&
  6060. NTDSCONN_IGNORE_SCHEDULE(Cxtion->Options)
  6061. ) {
  6062. Schedule = NULL;
  6063. } else {
  6064. //
  6065. // No schedule == always on
  6066. //
  6067. Schedule = Cxtion->Schedule;
  6068. if (!Schedule) {
  6069. Schedule = Replica->Schedule;
  6070. }
  6071. }
  6072. //
  6073. // Is this 15minute interval ON or OFF?
  6074. //
  6075. On = TRUE;
  6076. if (Schedule) {
  6077. //
  6078. // Find the interval schedule
  6079. //
  6080. for (i = 0; i < Schedule->NumberOfSchedules; ++i) {
  6081. if (Schedule->Schedules[i].Type == SCHEDULE_INTERVAL) {
  6082. On = ((*(((PUCHAR)Schedule) +
  6083. Schedule->Schedules[i].Offset +
  6084. ScheduleIndex)) >> ScheduleShift) & 1;
  6085. break;
  6086. }
  6087. }
  6088. }
  6089. if (On) {
  6090. DPRINT1(0, ":X: %08x, schedule is on\n",
  6091. (Cxtion->Name && Cxtion->Name->Guid) ? Cxtion->Name->Guid->Data1 : 0);
  6092. ClearCxtionFlag(Cxtion, CXTION_FLAGS_SCHEDULE_OFF);
  6093. } else {
  6094. DPRINT1(0, ":X: %08x, schedule is off.\n",
  6095. (Cxtion->Name && Cxtion->Name->Guid) ? Cxtion->Name->Guid->Data1 : 0);
  6096. SetCxtionFlag(Cxtion, CXTION_FLAGS_SCHEDULE_OFF);
  6097. }
  6098. }
  6099. VOID
  6100. RcsCheckCxtionSchedule(
  6101. IN PREPLICA Replica,
  6102. IN PCXTION Cxtion
  6103. )
  6104. /*++
  6105. Routine Description:
  6106. Call the function to set or clear CXTION_FLAGS_SCHEDULE_OFF once
  6107. the current interval has been determined and the appropriate locks
  6108. acquired.
  6109. Called when a replica is "opened" (read from the DB) and when a
  6110. cxtion is created or its schedule altered in RcsMergeReplicaCxtions().
  6111. Arguments:
  6112. Cmd
  6113. Return Value:
  6114. None.
  6115. --*/
  6116. {
  6117. #undef DEBSUB
  6118. #define DEBSUB "RcsCheckCxtionSchedule:"
  6119. DWORD ScheduleIndex;
  6120. DWORD ScheduleShift;
  6121. SYSTEMTIME SystemTime;
  6122. DWORD ScheduleHour;
  6123. BOOL On;
  6124. //
  6125. // Find the current interval
  6126. //
  6127. GetSystemTime(&SystemTime);
  6128. ScheduleHour = (SystemTime.wDayOfWeek * 24) + SystemTime.wHour;
  6129. ScheduleShift = SystemTime.wMinute / MINUTES_IN_INTERVAL;
  6130. ScheduleIndex = ScheduleHour;
  6131. FRS_ASSERT(ScheduleIndex < SCHEDULE_DATA_BYTES);
  6132. //
  6133. // Set or clear CXTION_FLAGS_SCHEDULE_OFF
  6134. //
  6135. LOCK_CXTION_TABLE(Replica);
  6136. RcsSetCxtionSchedule(Replica, Cxtion, ScheduleIndex, ScheduleShift);
  6137. UNLOCK_CXTION_TABLE(Replica);
  6138. }
  6139. VOID
  6140. RcsCheckSchedules(
  6141. IN PCOMMAND_PACKET Cmd
  6142. )
  6143. /*++
  6144. Routine Description:
  6145. Check all schedules every so often.
  6146. There are three schedule protocols:
  6147. Sysvol cxtion within a site
  6148. ---------------------------
  6149. The cxtion is always on; any schedule is ignored. Normal join
  6150. retries apply. The normal join retry is to increase the timeout
  6151. by MinJoinTimeout every retry until the join succeeds. A
  6152. successful unjoin is followed by an immediate join.
  6153. Normal cxtion
  6154. -------------
  6155. The schedule is treated as a 15 minute interval stop/start
  6156. schedule. Normal join retries apply.
  6157. Sysvol cxtion between sites
  6158. ---------------------------
  6159. The cxtion is treated as a 15-minute interval trigger schedule.
  6160. The downstream partner initiates the join. The upstream partner
  6161. ignores its schedule and responds to any request by the downstream
  6162. partner. The upstream partner unjoins the cxtion when the current
  6163. contents of the outlog at the time of join have been sent and
  6164. acked.
  6165. For interoperability, the minor comm version was bumped and the
  6166. outbound trigger cxtion is not unjoined when the end-of-join
  6167. control co is encountered if the partner is downrev.
  6168. I.e., B2 <-> B3 systems behave like B2 systems wrt trigger
  6169. scheduled cxtions.
  6170. Arguments:
  6171. Cmd
  6172. Return Value:
  6173. None.
  6174. --*/
  6175. {
  6176. #undef DEBSUB
  6177. #define DEBSUB "RcsCheckSchedules:"
  6178. PVOID ReplicaKey;
  6179. PVOID CxtionKey;
  6180. PREPLICA Replica;
  6181. PCXTION Cxtion;
  6182. DWORD ScheduleIndex;
  6183. DWORD ScheduleShift;
  6184. SYSTEMTIME BeginSystemTime;
  6185. SYSTEMTIME EndSystemTime;
  6186. DWORD ScheduleHour;
  6187. DWORD MilliSeconds;
  6188. BOOL On;
  6189. DPRINT1(5, ":X: Command check schedules %08x\n", Cmd);
  6190. //
  6191. // Loop if the interval changes during processing
  6192. //
  6193. AGAIN:
  6194. //
  6195. // Current 15min interval
  6196. //
  6197. GetSystemTime(&BeginSystemTime);
  6198. ScheduleHour = (BeginSystemTime.wDayOfWeek * 24) + BeginSystemTime.wHour;
  6199. ScheduleShift = BeginSystemTime.wMinute / MINUTES_IN_INTERVAL;
  6200. ScheduleIndex = ScheduleHour;
  6201. FRS_ASSERT(ScheduleIndex < SCHEDULE_DATA_BYTES);
  6202. //
  6203. // For each replica (while not shutting down)
  6204. //
  6205. LOCK_REPLICA_TABLE(ReplicasByGuid);
  6206. ReplicaKey = NULL;
  6207. while ((!FrsIsShuttingDown) &&
  6208. (Replica = GTabNextDatumNoLock(ReplicasByGuid, &ReplicaKey))) {
  6209. //
  6210. // Replica hasn't been started or is deleted; ignore for now
  6211. //
  6212. if (!Replica->IsAccepting) {
  6213. continue;
  6214. }
  6215. //
  6216. // Don't bother; replica has been deleted
  6217. //
  6218. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  6219. continue;
  6220. }
  6221. //
  6222. // For each cxtion (while not shutting down)
  6223. //
  6224. LOCK_CXTION_TABLE(Replica);
  6225. CxtionKey = NULL;
  6226. while ((!FrsIsShuttingDown) &&
  6227. (Cxtion = GTabNextDatumNoLock(Replica->Cxtions, &CxtionKey))) {
  6228. //
  6229. // Ignore the (local) journal connection.
  6230. //
  6231. if (Cxtion->JrnlCxtion) {
  6232. continue;
  6233. }
  6234. //
  6235. // Set the cxtion flags related to schedules
  6236. //
  6237. RcsSetCxtionSchedule(Replica, Cxtion, ScheduleIndex, ScheduleShift);
  6238. //
  6239. // Schedule is off. Unjoin the cxtion UNLESS this is
  6240. // a trigger schedule, in which case the cxtion will
  6241. // turn itself off once the current set of changes
  6242. // have been sent.
  6243. //
  6244. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_SCHEDULE_OFF)) {
  6245. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  6246. !CxtionStateIs(Cxtion, CxtionStateDeleted) &&
  6247. !CxtionStateIs(Cxtion, CxtionStateStart) &&
  6248. !CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  6249. RcsSubmitReplicaCxtion(Replica, Cxtion, CMD_UNJOIN);
  6250. }
  6251. //
  6252. // Schedule is on. Join the cxtion unless it is already
  6253. // joined or is controlled by a trigger schedule. The
  6254. // join is needed for a trigger scheduled cxtion in case
  6255. // the upstream partner has sent its cos and is now
  6256. // unjoined.
  6257. //
  6258. // Do not send a CMD_JOIN if this replica set is still seeding and
  6259. // connection is in INIT_SYNC state and marked paused.
  6260. // Initial sync command server will unpause it when it is ready to join.
  6261. //
  6262. } else {
  6263. if ((!CxtionStateIs(Cxtion, CxtionStateJoined) ||
  6264. CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) &&
  6265. (!CxtionFlagIs(Cxtion, CXTION_FLAGS_PAUSED) ||
  6266. (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) ||
  6267. !CxtionFlagIs(Cxtion, CXTION_FLAGS_INIT_SYNC)))
  6268. ) {
  6269. RcsSubmitReplicaCxtion(Replica, Cxtion, CMD_JOIN_CXTION);
  6270. }
  6271. }
  6272. }
  6273. UNLOCK_CXTION_TABLE(Replica);
  6274. }
  6275. UNLOCK_REPLICA_TABLE(ReplicasByGuid);
  6276. //
  6277. // Has the clock ticked into the next interval? If so, check again
  6278. //
  6279. GetSystemTime(&EndSystemTime);
  6280. if (EndSystemTime.wDayOfWeek != BeginSystemTime.wDayOfWeek ||
  6281. EndSystemTime.wHour != BeginSystemTime.wHour ||
  6282. (EndSystemTime.wMinute / MINUTES_IN_INTERVAL) != (BeginSystemTime.wMinute / MINUTES_IN_INTERVAL)) {
  6283. goto AGAIN;
  6284. }
  6285. //
  6286. // Time until the beginning of the next 15 minute interval
  6287. //
  6288. MilliSeconds = ((((EndSystemTime.wMinute + MINUTES_IN_INTERVAL)
  6289. / MINUTES_IN_INTERVAL)
  6290. * MINUTES_IN_INTERVAL)
  6291. - EndSystemTime.wMinute);
  6292. DPRINT1(5, ":X: Check schedules in %d minutes\n", MilliSeconds);
  6293. MilliSeconds *= (60 * 1000);
  6294. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, MilliSeconds);
  6295. }
  6296. VOID
  6297. RcsMergeReplicaCxtions(
  6298. IN PREPLICA Replica,
  6299. IN PREPLICA NewReplica,
  6300. IN PCXTION VolatileCxtion
  6301. )
  6302. /*++
  6303. Routine Description:
  6304. Update the Replica's cxtions with information from NewReplica.
  6305. Arguments:
  6306. Replica - active replica
  6307. NewReplica
  6308. VolatileCxtion -- Ptr to a cxtion struct created for temporary connections.
  6309. Hence the name Volatile. Currently used for Sysvol Seeding.
  6310. Return Value:
  6311. TRUE - replica set was altered
  6312. FALSE - replica is unaltered
  6313. --*/
  6314. {
  6315. #undef DEBSUB
  6316. #define DEBSUB "RcsMergeReplicaCxtions:"
  6317. ULONG FStatus;
  6318. PVOID Key;
  6319. PCXTION Cxtion;
  6320. PCXTION NextCxtion;
  6321. BOOL UpdateNeeded;
  6322. PCXTION NewCxtion;
  6323. //
  6324. // Note: Review - There needs to be a lock on the table or the cxtion
  6325. // since the outlog, chgorder, and replica code may
  6326. // reference the cxtion struct in parallel.
  6327. //
  6328. //
  6329. // The cxtions are enumerated when the replica is opened. If the
  6330. // replica isn't opened then we don't know the state of the existing
  6331. // cxtions.
  6332. //
  6333. if (!Replica->IsOpen) {
  6334. return;
  6335. }
  6336. //
  6337. // The replica's config record can't be updated; ignore cxtion changes
  6338. //
  6339. if (Replica->NeedsUpdate) {
  6340. return;
  6341. }
  6342. //
  6343. // Add the seeding cxtion
  6344. // The seeding cxtion is created by the caller when the
  6345. // sysvol is seeded after dcpromo. Otherwise, it is created
  6346. // at this time.
  6347. //
  6348. // WARN - The function may open and read the registry and may
  6349. // RPC to another computer.
  6350. //
  6351. VolatileCxtion = RcsCreateSeedingCxtion(Replica, VolatileCxtion);
  6352. if (VolatileCxtion) {
  6353. //
  6354. // Update the cxtion table
  6355. //
  6356. // *NOTE* The following call is synchronous. If we have the Cxtion
  6357. // table lock then a hang is possible.
  6358. //
  6359. FStatus = OutLogSubmit(Replica, VolatileCxtion, CMD_OUTLOG_ADD_NEW_PARTNER);
  6360. if (FRS_SUCCESS(FStatus)) {
  6361. //
  6362. // Update the incore cxtion table
  6363. //
  6364. GTabInsertEntry(Replica->Cxtions, VolatileCxtion, VolatileCxtion->Name->Guid, NULL);
  6365. OutLogInitPartner(Replica, VolatileCxtion);
  6366. } else {
  6367. //
  6368. // Chuck the cxtion. We will retry the create during the
  6369. // next ds polling cycle.
  6370. //
  6371. FrsFreeType(VolatileCxtion);
  6372. }
  6373. }
  6374. //
  6375. // Done
  6376. //
  6377. if (!NewReplica) {
  6378. return;
  6379. }
  6380. //
  6381. // Check for altered or deleted cxtions
  6382. //
  6383. Key = NULL;
  6384. for (Cxtion = GTabNextDatum(Replica->Cxtions, &Key); Cxtion; Cxtion = NextCxtion) {
  6385. NextCxtion = GTabNextDatum(Replica->Cxtions, &Key);
  6386. //
  6387. // Ignore the (local) journal connection.
  6388. //
  6389. if (Cxtion->JrnlCxtion) {
  6390. continue;
  6391. }
  6392. //
  6393. // This cxtion is volatile, it will disappear after the sysvol is seeded.
  6394. // NOTE: the cxtion flags are not stored in the database so, at
  6395. // restart, this cxtion will not have the flag, CXTION_FLAGS_VOLATILE,
  6396. // set. The cxtion is deleted at restart because there isn't a
  6397. // corresponding DS entry.
  6398. //
  6399. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_VOLATILE)) {
  6400. continue;
  6401. }
  6402. NewCxtion = GTabLookup(NewReplica->Cxtions, Cxtion->Name->Guid, NULL);
  6403. //
  6404. // Delete the cxtion after unjoining. A Cxtion is deleted if it is not
  6405. // found in the DS. A connection can also be deleted if the outbound log cleanup
  6406. // decides that a particular outbound connection is holding up COs longer than
  6407. // the specified history time. (Outlog Change History In Minutes)
  6408. //
  6409. if (NewCxtion == NULL || (!Cxtion->Inbound && CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIM_OUTLOG))) {
  6410. //
  6411. // Unjoin the cxtion after setting the deferred delete bit.
  6412. // The deferred delete bit will keep the cxtion from re-joining
  6413. // before it can be deleted during the next pass of the ds
  6414. // polling thread. Warning - cxtion may reappear at any time!
  6415. //
  6416. if (!CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6417. LOCK_CXTION_TABLE(Replica);
  6418. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  6419. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  6420. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_DELETE);
  6421. UNLOCK_CXTION_TABLE(Replica);
  6422. RcsForceUnjoin(Replica, Cxtion);
  6423. }
  6424. //
  6425. // If successfully unjoined; move to the deleted-cxtion table
  6426. //
  6427. if (CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6428. RcsDeleteCxtionFromReplica(Replica, Cxtion);
  6429. }
  6430. continue;
  6431. //
  6432. // Deleted cxtion reappeared; reanimate it
  6433. //
  6434. // if the cxtion is deleted or marked for delete
  6435. // and new cxtion is consistent
  6436. // and partner's guid's match
  6437. // then reanimate
  6438. //
  6439. // Don't attempt to reanimate a cxtion if the info in the DS
  6440. // is inconsistent or the cxtion's partner has changed. The
  6441. // cxtion is deleted when its partner changes because the
  6442. // state kept per cxtion is partner specific.
  6443. //
  6444. } else if ((CxtionStateIs(Cxtion, CxtionStateDeleted) ||
  6445. CxtionFlagIs(Cxtion, CXTION_FLAGS_DEFERRED_DELETE)) &&
  6446. CxtionFlagIs(NewCxtion, CXTION_FLAGS_CONSISTENT) &&
  6447. GUIDS_EQUAL(Cxtion->Partner->Guid, NewCxtion->Partner->Guid)) {
  6448. LOCK_CXTION_TABLE(Replica);
  6449. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_DELETE);
  6450. if (CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6451. SetCxtionState(Cxtion, CxtionStateUnjoined);
  6452. }
  6453. UNLOCK_CXTION_TABLE(Replica);
  6454. }
  6455. //
  6456. // Check for altered fields; Ignore if not consistent
  6457. //
  6458. if (CxtionFlagIs(NewCxtion, CXTION_FLAGS_CONSISTENT)) {
  6459. //
  6460. // No changes, yet
  6461. //
  6462. UpdateNeeded = FALSE;
  6463. //
  6464. // Ignore all change is a field changed that isn't allowed
  6465. // to change.
  6466. //
  6467. //
  6468. // Cxtion Guid
  6469. //
  6470. if (!GUIDS_EQUAL(Cxtion->Name->Guid, NewCxtion->Name->Guid)) {
  6471. DPRINT2(0, ":X: ERROR - %ws\\%ws - Changing cxtion guid is not allowed.\n",
  6472. Replica->MemberName->Name, Cxtion->Name->Name);
  6473. goto DELETE_AND_CONTINUE;
  6474. }
  6475. //
  6476. // Partner Guid
  6477. //
  6478. // The cxtion is deleted when its partner changes because the
  6479. // state kept per cxtion is partner specific. If the cxtion
  6480. // has been newly altered so that its previous mismatched
  6481. // partner guid now matches then the check in the previous
  6482. // basic block would have reanimated the cxtion before getting
  6483. // to this code. Hence, the lack of an "else" clause.
  6484. //
  6485. if (!GUIDS_EQUAL(Cxtion->Partner->Guid, NewCxtion->Partner->Guid)) {
  6486. DPRINT2(0, ":X: ERROR - %ws\\%ws - Changing cxtion's partner guid "
  6487. "is not allowed. DELETING CURRENT CXTION!\n",
  6488. Replica->MemberName->Name, Cxtion->Name->Name);
  6489. //
  6490. // Unjoin the cxtion after setting the deferred delete bit.
  6491. // The deferred delete bit will keep the cxtion from re-joining
  6492. // before it can be deleted during the next pass of the ds
  6493. // polling thread. Warning - cxtion may reappear at any time!
  6494. //
  6495. if (!CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6496. LOCK_CXTION_TABLE(Replica);
  6497. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_JOIN);
  6498. ClearCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_UNJOIN);
  6499. SetCxtionFlag(Cxtion, CXTION_FLAGS_DEFERRED_DELETE);
  6500. UNLOCK_CXTION_TABLE(Replica);
  6501. RcsForceUnjoin(Replica, Cxtion);
  6502. }
  6503. //
  6504. // If successfully unjoined; move to the deleted-cxtion table
  6505. //
  6506. if (CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  6507. RcsDeleteCxtionFromReplica(Replica, Cxtion);
  6508. }
  6509. goto DELETE_AND_CONTINUE;
  6510. }
  6511. //
  6512. // Partner Name
  6513. //
  6514. if (WSTR_NE(Cxtion->Partner->Name, NewCxtion->Partner->Name)) {
  6515. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner name from %ws to %ws.\n",
  6516. Replica->MemberName->Name, Cxtion->Name->Name,
  6517. Cxtion->Partner->Name, NewCxtion->Partner->Name);
  6518. FrsDsSwapPtrs(&Cxtion->Partner->Name, &NewCxtion->Partner->Name);
  6519. UpdateNeeded = TRUE;
  6520. }
  6521. //
  6522. // Partner PrincName
  6523. //
  6524. if (WSTR_NE(Cxtion->PartnerPrincName, NewCxtion->PartnerPrincName)) {
  6525. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner princname from %ws to %ws.\n",
  6526. Replica->MemberName->Name, Cxtion->Name->Name,
  6527. Cxtion->PartnerPrincName, NewCxtion->PartnerPrincName);
  6528. FrsDsSwapPtrs(&Cxtion->PartnerPrincName, &NewCxtion->PartnerPrincName);
  6529. UpdateNeeded = TRUE;
  6530. }
  6531. //
  6532. // Partner Dns Name
  6533. //
  6534. if (WSTR_NE(Cxtion->PartnerDnsName, NewCxtion->PartnerDnsName)) {
  6535. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner DNS name from %ws to %ws.\n",
  6536. Replica->MemberName->Name, Cxtion->Name->Name,
  6537. Cxtion->PartnerDnsName, NewCxtion->PartnerDnsName);
  6538. FrsDsSwapPtrs(&Cxtion->PartnerDnsName, &NewCxtion->PartnerDnsName);
  6539. UpdateNeeded = TRUE;
  6540. }
  6541. //
  6542. // Partner SID
  6543. //
  6544. if (WSTR_NE(Cxtion->PartnerSid, NewCxtion->PartnerSid)) {
  6545. DPRINT4(4, ":X: %ws\\%ws - Changing cxtion's partner SID from %ws to %ws.\n",
  6546. Replica->MemberName->Name, Cxtion->Name->Name,
  6547. Cxtion->PartnerSid, NewCxtion->PartnerSid);
  6548. FrsDsSwapPtrs(&Cxtion->PartnerSid, &NewCxtion->PartnerSid);
  6549. UpdateNeeded = TRUE;
  6550. }
  6551. //
  6552. // Cxtion Schedule
  6553. //
  6554. if (Cxtion->Schedule || NewCxtion->Schedule) {
  6555. if ((Cxtion->Schedule && !NewCxtion->Schedule) ||
  6556. (!Cxtion->Schedule && NewCxtion->Schedule) ||
  6557. (Cxtion->Schedule->Size != NewCxtion->Schedule->Size) ||
  6558. (memcmp(Cxtion->Schedule,
  6559. NewCxtion->Schedule,
  6560. Cxtion->Schedule->Size))) {
  6561. DPRINT2(4, ":X: %ws\\%ws - Changing cxtion schedule.\n",
  6562. Replica->MemberName->Name, Cxtion->Name->Name);
  6563. FrsDsSwapPtrs(&Cxtion->Schedule, &NewCxtion->Schedule);
  6564. RcsCheckCxtionSchedule(Replica, Cxtion);
  6565. UpdateNeeded = TRUE;
  6566. }
  6567. }
  6568. //
  6569. // Partner Server Name
  6570. //
  6571. if (WSTR_NE(Cxtion->PartSrvName, NewCxtion->PartSrvName)) {
  6572. DPRINT4(4, ":X: %ws\\%ws - Changing partner's server name from %ws to %ws.\n",
  6573. Replica->MemberName->Name, Cxtion->Name->Name,
  6574. Cxtion->PartSrvName, NewCxtion->PartSrvName);
  6575. FrsDsSwapPtrs(&Cxtion->PartSrvName, &NewCxtion->PartSrvName);
  6576. UpdateNeeded = TRUE;
  6577. }
  6578. //
  6579. // Cxtion options.
  6580. //
  6581. if (Cxtion->Options != NewCxtion->Options) {
  6582. DPRINT4(4, ":X: %ws\\%ws - Changing Cxtion's options from 0x%08x to 0x%08x.\n",
  6583. Replica->MemberName->Name, Cxtion->Name->Name,
  6584. Cxtion->Options, NewCxtion->Options);
  6585. Cxtion->Options = NewCxtion->Options;
  6586. Cxtion->Priority = FRSCONN_GET_PRIORITY(Cxtion->Options);
  6587. UpdateNeeded = TRUE;
  6588. }
  6589. //
  6590. // Schedule type
  6591. //
  6592. if (CxtionFlagIs(NewCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) !=
  6593. CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  6594. DPRINT4(4, ":X: %ws\\%ws - Changing schedule type from %s to %s.\n",
  6595. Replica->MemberName->Name, Cxtion->Name->Name,
  6596. CxtionFlagIs(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) ?
  6597. "Trigger" : "Stop/Start",
  6598. CxtionFlagIs(NewCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE) ?
  6599. "Trigger" : "Stop/Start");
  6600. if (CxtionFlagIs(NewCxtion, CXTION_FLAGS_TRIGGER_SCHEDULE)) {
  6601. SetCxtionFlag(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE);
  6602. } else {
  6603. ClearCxtionFlag(Cxtion, CXTION_FLAGS_TRIGGER_SCHEDULE);
  6604. }
  6605. UpdateNeeded = TRUE;
  6606. }
  6607. //
  6608. // No changes, done
  6609. //
  6610. if (!UpdateNeeded) {
  6611. goto DELETE_AND_CONTINUE;
  6612. }
  6613. //
  6614. // Update the cxtion table in the DB
  6615. //
  6616. // *NOTE* The following call is synchronous. If we have the Cxtion
  6617. // table lock then a hang is possible.
  6618. //
  6619. FStatus = OutLogSubmit(Replica, Cxtion, CMD_OUTLOG_UPDATE_PARTNER);
  6620. if (!FRS_SUCCESS(FStatus)) {
  6621. DPRINT3(0, ":X: WARN changes to cxtion %ws (to %ws, %ws) not updated in database\n",
  6622. Cxtion->Name->Name, Cxtion->Partner->Name,
  6623. Replica->ReplicaName->Name);
  6624. //
  6625. // Ds poll thread will restart the replica during the next
  6626. // polling cycle if ActiveChange is set to 0.
  6627. //
  6628. ActiveChange = 0;
  6629. }
  6630. }
  6631. DELETE_AND_CONTINUE:
  6632. //
  6633. // Remove the cxtion from the new replica set. Anything left
  6634. // after this loop must be a new cxtion. Free the partner
  6635. // so that FrsFreeType() will not attempt to unbind our
  6636. // partner's handles.
  6637. //
  6638. NewCxtion->Partner = FrsFreeGName(NewCxtion->Partner);
  6639. GTabDelete(NewReplica->Cxtions, Cxtion->Name->Guid, NULL, FrsFreeType);
  6640. }
  6641. //
  6642. // New cxtions
  6643. //
  6644. for (Key = NULL;
  6645. NewCxtion = GTabNextDatum(NewReplica->Cxtions, &Key);
  6646. Key = NULL) {
  6647. //
  6648. // Remove the cxtion from the new replica
  6649. //
  6650. GTabDelete(NewReplica->Cxtions, NewCxtion->Name->Guid, NULL, NULL);
  6651. //
  6652. // Inconsistent cxtion; ignore
  6653. //
  6654. if (NewCxtion->JrnlCxtion ||
  6655. !CxtionFlagIs(NewCxtion, CXTION_FLAGS_CONSISTENT)) {
  6656. FrsFreeType(NewCxtion);
  6657. continue;
  6658. }
  6659. RcsCheckCxtionSchedule(Replica, NewCxtion);
  6660. //
  6661. // Update the cxtion table
  6662. //
  6663. // *NOTE* The following call is synchronous. If we have the Cxtion
  6664. // table lock then a hang is possible.
  6665. //
  6666. FStatus = OutLogSubmit(Replica, NewCxtion, CMD_OUTLOG_ADD_NEW_PARTNER);
  6667. if (FRS_SUCCESS(FStatus)) {
  6668. DPRINT2(4, ":X: %ws\\%ws - Created cxtion.\n",
  6669. Replica->MemberName->Name, NewCxtion->Name->Name);
  6670. //
  6671. // Update the incore cxtion table
  6672. //
  6673. GTabInsertEntry(Replica->Cxtions, NewCxtion, NewCxtion->Name->Guid, NULL);
  6674. DPRINT(5, ":X: PERFMON:Adding Connection:REPLICA.C:2\n");
  6675. RcsCreatePerfmonCxtionName(Replica, NewCxtion);
  6676. OutLogInitPartner(Replica, NewCxtion);
  6677. } else {
  6678. DPRINT2_FS(0, ":X: %ws\\%ws - ERROR creating cxtion;",
  6679. Replica->MemberName->Name, NewCxtion->Name->Name, FStatus);
  6680. //
  6681. // Chuck the cxtion. We will retry the create during the
  6682. // next ds polling cycle.
  6683. //
  6684. FrsFreeType(NewCxtion);
  6685. //
  6686. // Ds poll thread will restart the replica during the next
  6687. // polling cycle if ActiveChange is set to 0.
  6688. //
  6689. ActiveChange = 0;
  6690. }
  6691. }
  6692. }
  6693. VOID
  6694. RcsCreatePerfmonCxtionName(
  6695. PREPLICA Replica,
  6696. PCXTION Cxtion
  6697. )
  6698. /*++
  6699. Routine Description:
  6700. Set the OID data structure which is a part of the counter data structure
  6701. stored in the hash table.
  6702. Add ReplicaConn Instance to the registry
  6703. Arguments:
  6704. Replica - active replica
  6705. Cxtion - Connection being added.
  6706. Return Value:
  6707. None.
  6708. --*/
  6709. {
  6710. #undef DEBSUB
  6711. #define DEBSUB "RcsCreatePerfmonCxtionName:"
  6712. PWCHAR ToFrom;
  6713. ULONG NameLen;
  6714. PWCHAR CxNamePtr;
  6715. if ((Cxtion->PartSrvName != NULL) && (Replica->Root != NULL)) {
  6716. //
  6717. // The oid name used in the HT_REPLICA_CONN_DATA is of the form
  6718. // Replica->Root::FROM:Cxtion->PartSrvName or
  6719. // Replica->Root::TO:Cxtion->PartSrvName
  6720. //
  6721. WCHAR Tstr[256];
  6722. _snwprintf(Tstr, ARRAY_SZ(Tstr), L"%ws%ws%ws",
  6723. Replica->Root,
  6724. (Cxtion->Inbound) ? (L"::FROM:") : (L"::TO:"),
  6725. Cxtion->PartSrvName);
  6726. Tstr[ARRAY_SZ(Tstr)-1] = L'\0';
  6727. //
  6728. // Finally, add the REPLICACONN instance to the Registry
  6729. //
  6730. AddPerfmonInstance(REPLICACONN, Cxtion->PerfRepConnData, Tstr);
  6731. }
  6732. }
  6733. VOID
  6734. RcsSubmitStopReplicaToDb(
  6735. IN PREPLICA Replica
  6736. )
  6737. /*++
  6738. Routine Description:
  6739. Release the replica's journal state and outbound log state.
  6740. This will also close the replica set if it was open. The close happens
  6741. after the Journaling on the replica has stopped so we save the correct
  6742. Journal restart USN.
  6743. Arguments:
  6744. None.
  6745. Return Value:
  6746. None.
  6747. --*/
  6748. {
  6749. #undef DEBSUB
  6750. #define DEBSUB "RcsSubmitStopReplicaToDb:"
  6751. PCOMMAND_PACKET Cmd = NULL;
  6752. ULONG WStatus;
  6753. Replica->FStatus = FrsErrorSuccess;
  6754. //
  6755. // Abort promotion; if any
  6756. //
  6757. if (Replica->NtFrsApi_ServiceState == NTFRSAPI_SERVICE_PROMOTING) {
  6758. DPRINT1(4, ":S: Promotion aborted: stop for %ws.\n", Replica->SetName->Name);
  6759. Replica->NtFrsApi_ServiceWStatus = FRS_ERR_SYSVOL_POPULATE;
  6760. Replica->NtFrsApi_ServiceState = NTFRSAPI_SERVICE_DONE;
  6761. }
  6762. //
  6763. // Attempt to stop journaling even if "IsJournaling" is false because
  6764. // may have journal state even if it isn't journaling. The journal
  6765. // is kept in pVme.
  6766. //
  6767. if (Replica->pVme == NULL) {
  6768. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica->pVme == NULL");
  6769. //
  6770. // Close replica is OK here as long as the Journal has not
  6771. // been started on this replica set.
  6772. //
  6773. RcsCloseReplicaSetmember(Replica);
  6774. RcsCloseReplicaCxtions(Replica);
  6775. return;
  6776. }
  6777. //
  6778. // Submitted to the db command server
  6779. //
  6780. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  6781. Replica, // Replica,
  6782. CMD_STOP_REPLICATION_SINGLE_REPLICA, // CmdRequest,
  6783. NULL, // TableCtx,
  6784. NULL, // CallContext,
  6785. 0, // TableType,
  6786. 0, // AccessRequest,
  6787. 0, // IndexType,
  6788. NULL, // KeyValue,
  6789. 0, // KeyValueLength,
  6790. FALSE); // Submit
  6791. //
  6792. // Don't free the packet when the command completes.
  6793. //
  6794. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  6795. //
  6796. // SUBMIT DB Cmd and wait for completion.
  6797. //
  6798. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_STOP_REPLICATION_SINGLE_REPLICA");
  6799. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  6800. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  6801. //
  6802. // If wait or database op failed
  6803. //
  6804. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  6805. //
  6806. // If wait / submit failed then let caller know cmd srv submit failed.
  6807. //
  6808. if (FRS_SUCCESS(Replica->FStatus)) {
  6809. Replica->FStatus = FrsErrorCmdSrvFailed;
  6810. }
  6811. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Stop Replica failed;",
  6812. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  6813. DPRINT_WS(0, "ERROR: Stop Replica DB Command failed", WStatus);
  6814. goto out;
  6815. }
  6816. Replica->IsOpen = FALSE;
  6817. out:
  6818. if (Cmd) {
  6819. FrsFreeCommand(Cmd, NULL);
  6820. }
  6821. }
  6822. VOID
  6823. RcsCloseReplicaCxtions(
  6824. IN PREPLICA Replica
  6825. )
  6826. /*++
  6827. Routine Description:
  6828. "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  6829. generate new cxtion structs before active processing (aka joining)
  6830. occurs. The cxtions remain in the DeletedCxtions table so that
  6831. other threads that may have been time sliced just after acquiring
  6832. the cxtion pointer but before making use of it will not AV. We
  6833. could have put in locks but then there would be deadlock and
  6834. perf considerations; all for the sake of this seldom occuring
  6835. operation.
  6836. Arguments:
  6837. Replica
  6838. Return Value:
  6839. None.
  6840. --*/
  6841. {
  6842. #undef DEBSUB
  6843. #define DEBSUB "RcsCloseReplicaCxtions:"
  6844. PVOID Key;
  6845. PCXTION Cxtion;
  6846. //
  6847. // Open; ignore request
  6848. //
  6849. if (Replica->IsOpen) {
  6850. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Replica open at close cxtions");
  6851. return;
  6852. }
  6853. //
  6854. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  6855. // generate new cxtion structs before active processing (aka joining)
  6856. // occurs. The cxtions remain in the DeletedCxtions table so that
  6857. // other threads that may have been time sliced just after acquiring
  6858. // the cxtion pointer but before making use of it will not AV. We
  6859. // could have put in locks but then there would be deadlock and
  6860. // perf considerations; all for the sake of this seldom occuring
  6861. // operation.
  6862. //
  6863. if (Replica->Cxtions) {
  6864. Key = NULL;
  6865. while (Cxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  6866. Key = NULL;
  6867. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, GenTable Cxtion deleted");
  6868. GTabDelete(Replica->Cxtions, Cxtion->Name->Guid, NULL, NULL);
  6869. //
  6870. // Remove the connection from the perfmon tables so we stop returning
  6871. // data and allow a new connection with the same name to be established.
  6872. //
  6873. // Journal cxtion does not have a perfmon entry
  6874. //
  6875. if (!Cxtion->JrnlCxtion) {
  6876. DeletePerfmonInstance(REPLICACONN, Cxtion->PerfRepConnData);
  6877. }
  6878. GTabInsertEntry(DeletedCxtions, Cxtion, Cxtion->Name->Guid, NULL);
  6879. }
  6880. }
  6881. }
  6882. VOID
  6883. RcsCloseReplicaSetmember(
  6884. IN PREPLICA Replica
  6885. )
  6886. /*++
  6887. Routine Description:
  6888. Close an open replica
  6889. Arguments:
  6890. Replica
  6891. Return Value:
  6892. None.
  6893. --*/
  6894. {
  6895. #undef DEBSUB
  6896. #define DEBSUB "RcsCloseReplicaSetmember:"
  6897. PCOMMAND_PACKET Cmd = NULL;
  6898. ULONG WStatus;
  6899. PVOID Key;
  6900. PCXTION Cxtion;
  6901. Replica->FStatus = FrsErrorSuccess;
  6902. //
  6903. // Not open or still journaling; ignore request
  6904. //
  6905. if (!Replica->IsOpen) {
  6906. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not open");
  6907. return;
  6908. }
  6909. //
  6910. // Submitted to the db command server
  6911. //
  6912. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  6913. Replica, // Replica,
  6914. CMD_CLOSE_REPLICA_SET_MEMBER, // CmdRequest,
  6915. NULL, // TableCtx,
  6916. NULL, // CallContext,
  6917. 0, // TableType,
  6918. 0, // AccessRequest,
  6919. 0, // IndexType,
  6920. NULL, // KeyValue,
  6921. 0, // KeyValueLength,
  6922. FALSE); // Submit
  6923. //
  6924. // Don't free the packet when the command completes.
  6925. //
  6926. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  6927. //
  6928. // SUBMIT DB Cmd and wait for completion.
  6929. //
  6930. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_CLOSE_REPLICA_SET_MEMBER");
  6931. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  6932. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  6933. //
  6934. // If wait or database op failed
  6935. //
  6936. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  6937. //
  6938. // If wait / submit failed then let caller know cmd srv submit failed.
  6939. //
  6940. if (FRS_SUCCESS(Replica->FStatus)) {
  6941. Replica->FStatus = FrsErrorCmdSrvFailed;
  6942. }
  6943. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Close Replica failed;",
  6944. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  6945. DPRINT_WS(0, "ERROR: Close Replica DB Command failed", WStatus);
  6946. goto out;
  6947. }
  6948. Replica->IsOpen = FALSE;
  6949. out:
  6950. if (Cmd) {
  6951. FrsFreeCommand(Cmd, NULL);
  6952. }
  6953. }
  6954. VOID
  6955. RcsDeleteReplicaFromDb(
  6956. IN PREPLICA Replica
  6957. )
  6958. /*++
  6959. Routine Description:
  6960. Delete the replica from the database
  6961. Arguments:
  6962. Replica
  6963. Return Value:
  6964. winerror
  6965. --*/
  6966. {
  6967. #undef DEBSUB
  6968. #define DEBSUB "RcsDeleteReplicaFromDb:"
  6969. PCOMMAND_PACKET Cmd = NULL;
  6970. ULONG WStatus;
  6971. Replica->FStatus = FrsErrorSuccess;
  6972. //
  6973. // Replica must be closed to delete
  6974. //
  6975. if (Replica->IsOpen) {
  6976. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not closed.");
  6977. return;
  6978. }
  6979. //
  6980. // Submitted to the db command server
  6981. //
  6982. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  6983. Replica, // Replica,
  6984. CMD_DELETE_REPLICA_SET_MEMBER, // CmdRequest,
  6985. NULL, // TableCtx,
  6986. NULL, // CallContext,
  6987. 0, // TableType,
  6988. 0, // AccessRequest,
  6989. 0, // IndexType,
  6990. NULL, // KeyValue,
  6991. 0, // KeyValueLength,
  6992. FALSE); // Submit
  6993. //
  6994. // Don't free the packet when the command completes.
  6995. //
  6996. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  6997. //
  6998. // SUBMIT DB Cmd and wait for completion.
  6999. //
  7000. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Submit DB CMD_DELETE_REPLICA_SET_MEMBER");
  7001. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  7002. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  7003. //
  7004. // If wait or database op failed
  7005. //
  7006. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  7007. //
  7008. // If wait / submit failed then let caller know cmd srv submit failed.
  7009. //
  7010. if (FRS_SUCCESS(Replica->FStatus)) {
  7011. Replica->FStatus = FrsErrorCmdSrvFailed;
  7012. }
  7013. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Delete Replica failed;",
  7014. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  7015. DPRINT_WS(0, "ERROR: Delete Replica DB Command failed", WStatus);
  7016. goto out;
  7017. }
  7018. out:
  7019. if (Cmd) {
  7020. FrsFreeCommand(Cmd, NULL);
  7021. }
  7022. }
  7023. VOID
  7024. RcsUpdateReplicaSetMember(
  7025. IN PREPLICA Replica
  7026. )
  7027. /*++
  7028. Routine Description:
  7029. Update the database record for Replica.
  7030. *Note*
  7031. Perf: RcsUpdateReplicaSetMember() should return status as part
  7032. of the function call not use some side-effect flag(NeedsUpdate)
  7033. in the Replica struct.
  7034. Arguments:
  7035. Replica
  7036. Return Value:
  7037. winerror
  7038. --*/
  7039. {
  7040. #undef DEBSUB
  7041. #define DEBSUB "RcsUpdateReplicaSetMember:"
  7042. PCOMMAND_PACKET Cmd = NULL;
  7043. ULONG WStatus;
  7044. Replica->FStatus = FrsErrorSuccess;
  7045. //
  7046. // Replica is not dirty
  7047. //
  7048. if (!Replica->NeedsUpdate || !Replica->IsOpen) {
  7049. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica not open or not dirty");
  7050. return;
  7051. }
  7052. //
  7053. // Command packet
  7054. //
  7055. Cmd = DbsPrepareCmdPkt(NULL, // Cmd,
  7056. Replica, // Replica,
  7057. CMD_UPDATE_REPLICA_SET_MEMBER, // CmdRequest,
  7058. NULL, // TableCtx,
  7059. NULL, // CallContext,
  7060. 0, // TableType,
  7061. 0, // AccessRequest,
  7062. 0, // IndexType,
  7063. NULL, // KeyValue,
  7064. 0, // KeyValueLength,
  7065. FALSE); // Submit
  7066. //
  7067. // Don't free the packet when the command completes.
  7068. //
  7069. FrsSetCompletionRoutine(Cmd, FrsCompleteKeepPkt, NULL);
  7070. //
  7071. // SUBMIT DB Cmd and wait for completion.
  7072. //
  7073. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit DB CMD_UPDATE_REPLICA_SET_MEMBER");
  7074. WStatus = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, Cmd, INFINITE);
  7075. Replica->FStatus = Cmd->Parameters.DbsRequest.FStatus;
  7076. //
  7077. // If wait or database op failed
  7078. //
  7079. if (!WIN_SUCCESS(WStatus) || !FRS_SUCCESS(Replica->FStatus)) {
  7080. //
  7081. // If wait / submit failed then let caller know cmd srv submit failed.
  7082. //
  7083. if (FRS_SUCCESS(Replica->FStatus)) {
  7084. Replica->FStatus = FrsErrorCmdSrvFailed;
  7085. }
  7086. DPRINT2_FS(0, ":S: ERROR - %ws\\%ws: Update Replica failed;",
  7087. Replica->SetName->Name, Replica->MemberName->Name, Replica->FStatus);
  7088. DPRINT_WS(0, "ERROR: Update Replica DB Command failed", WStatus);
  7089. goto out;
  7090. }
  7091. Replica->NeedsUpdate = !FRS_SUCCESS(Replica->FStatus);
  7092. out:
  7093. if (Cmd) {
  7094. FrsFreeCommand(Cmd, NULL);
  7095. }
  7096. }
  7097. BOOL
  7098. RcsHasReplicaRootPathMoved(
  7099. IN PREPLICA Replica,
  7100. IN PREPLICA NewReplica,
  7101. OUT PDWORD ReplicaState
  7102. )
  7103. /*++
  7104. Routine Description:
  7105. Check if the replica root path has moved. Called at each poll.
  7106. The following checks are made to make sure that the volume and journal
  7107. info is not changed while the service was not running.
  7108. VOLUME SERIAL NUMBER MISMATCH CHECK:
  7109. In case of a mismatch the replica set is marked to be deleted.
  7110. REPLICA ROOT DIR OBJECTID MISMATCH CHECK:
  7111. In case of a mismatch the replica set is marked to be deleted.
  7112. REPLICA ROOT DIR FID MISMATCH CHECK:
  7113. In case of a mismatch the replica set is marked to be deleted.
  7114. Arguments:
  7115. Replica - Existing replica structure.
  7116. NewReplica - New replica structure from DS.
  7117. ReplicaState - Error state to move to if root has moved.
  7118. Return Value:
  7119. BOOL.
  7120. --*/
  7121. {
  7122. #undef DEBSUB
  7123. #define DEBSUB "RcsHasReplicaRootPathMoved:"
  7124. HANDLE NewRootHandle = INVALID_HANDLE_VALUE;
  7125. DWORD WStatus;
  7126. DWORD VolumeInfoLength;
  7127. PFILE_FS_VOLUME_INFORMATION VolumeInfo = NULL;
  7128. IO_STATUS_BLOCK Iosb;
  7129. NTSTATUS Status;
  7130. PCONFIG_TABLE_RECORD ConfigRecord = NULL;
  7131. CHAR GuidStr[GUID_CHAR_LEN];
  7132. BOOL Result = FALSE;
  7133. PCOMMAND_PACKET CmdPkt = NULL;
  7134. ULONG AccessRequest;
  7135. PDB_SERVICE_REQUEST DbsRequest = NULL;
  7136. FILE_OBJECTID_BUFFER ObjectIdBuffer;
  7137. FILE_INTERNAL_INFORMATION InternalFileInfo;
  7138. PREPLICA_THREAD_CTX RtCtx = NULL;
  7139. PTABLE_CTX IDTableCtx = NULL;
  7140. PVOID pKey = NULL;
  7141. PIDTABLE_RECORD IDTableRec = NULL;
  7142. //
  7143. // If this is the first time we are starting this replica set.
  7144. // Nothing to compare with.
  7145. //
  7146. if (NewReplica == NULL) {
  7147. goto RETURN;
  7148. }
  7149. ConfigRecord = (PCONFIG_TABLE_RECORD)Replica->ConfigTable.pDataRecord;
  7150. //
  7151. // Always open the path by masking off the FILE_OPEN_REPARSE_POINT flag
  7152. // because we want to open the destination dir not the junction if the root
  7153. // happens to be a mount point.
  7154. //
  7155. WStatus = FrsOpenSourceFileW(&NewRootHandle,
  7156. NewReplica->Root,
  7157. GENERIC_READ,
  7158. FILE_OPEN_FOR_BACKUP_INTENT);
  7159. if (!WIN_SUCCESS(WStatus)) {
  7160. DPRINT1_WS(0, "ERROR - Unable to open root path %ws. Retry as next poll.",
  7161. NewReplica->Root, WStatus);
  7162. goto RETURN;
  7163. }
  7164. //
  7165. // Get the volume information.
  7166. //
  7167. VolumeInfoLength = sizeof(FILE_FS_VOLUME_INFORMATION) +
  7168. MAXIMUM_VOLUME_LABEL_LENGTH;
  7169. VolumeInfo = FrsAlloc(VolumeInfoLength);
  7170. Status = NtQueryVolumeInformationFile(NewRootHandle,
  7171. &Iosb,
  7172. VolumeInfo,
  7173. VolumeInfoLength,
  7174. FileFsVolumeInformation);
  7175. if (!NT_SUCCESS(Status)) {
  7176. DPRINT2(0,"ERROR - Getting NtQueryVolumeInformationFile for %ws. NtStatus = %08x\n",
  7177. NewReplica->Root, Status);
  7178. goto RETURN;
  7179. }
  7180. //
  7181. // VOLUME SERIAL NUMBER MISMATCH CHECK:
  7182. //
  7183. // If LastShutdown is 0 then this is the very first time we have started
  7184. // replication on this replica set so save the volumeinformation in
  7185. // the config record. Even if Lastshutdown is not 0 CnfUsnJournalID could
  7186. // be 0 because it was not getting correctly updated in Win2K.. For sysvol replica sets the
  7187. // JournalID was getting updated correctly but not the volume information.
  7188. //
  7189. if ((ConfigRecord->LastShutdown == (ULONGLONG)0) ||
  7190. (ConfigRecord->ServiceState == CNF_SERVICE_STATE_CREATING) ||
  7191. (ConfigRecord->CnfUsnJournalID == (ULONGLONG)0) ||
  7192. (
  7193. (ConfigRecord->FSVolInfo != NULL) &&
  7194. (ConfigRecord->FSVolInfo->VolumeSerialNumber == 0)
  7195. )) {
  7196. CopyMemory(ConfigRecord->FSVolInfo,VolumeInfo,sizeof(FILE_FS_VOLUME_INFORMATION) + MAXIMUM_VOLUME_LABEL_LENGTH);
  7197. Replica->NeedsUpdate = TRUE;
  7198. } else
  7199. //
  7200. // Check if the VolumeSerialNumber for New Replica matches with the
  7201. // VolumeSerialNumber from the config record for this replica set. If
  7202. // it does not then it means that this replica set has been moved.
  7203. // Returning error here will trigger a deletion of the replica set. The set will
  7204. // be recreated at the next poll cycle and it will either be primary or non-auth
  7205. // depending on the case.
  7206. //
  7207. if (VolumeInfo->VolumeSerialNumber != ConfigRecord->FSVolInfo->VolumeSerialNumber) {
  7208. DPRINT1(0,"ERROR - VolumeSerialNumber mismatch for Replica Set (%ws)\n",Replica->ReplicaName->Name);
  7209. DPRINT2(0,"ERROR - VolumeSerialNumber %x(FS) != %x(DB)\n",
  7210. VolumeInfo->VolumeSerialNumber,ConfigRecord->FSVolInfo->VolumeSerialNumber);
  7211. DPRINT1(0,"ERROR - Replica Set (%ws) is marked to be deleted\n",Replica->ReplicaName->Name);
  7212. Replica->FStatus = FrsErrorMismatchedVolumeSerialNumber;
  7213. *ReplicaState = REPLICA_STATE_MISMATCHED_VOLUME_SERIAL_NO;
  7214. Result = TRUE;
  7215. goto RETURN;
  7216. }
  7217. VolumeInfo = FrsFree(VolumeInfo);
  7218. //
  7219. // Get the FID for the replica root.
  7220. //
  7221. //
  7222. // zero the buffer in case the data that comes back is short.
  7223. //
  7224. ZeroMemory(&InternalFileInfo, sizeof(FILE_INTERNAL_INFORMATION));
  7225. Status = NtQueryInformationFile(NewRootHandle,
  7226. &Iosb,
  7227. &InternalFileInfo,
  7228. sizeof(FILE_INTERNAL_INFORMATION),
  7229. FileInternalInformation);
  7230. if (!NT_SUCCESS(Status)) {
  7231. DPRINT1(0, "ERROR getting FID for %ws\n", NewReplica->Root);
  7232. goto RETURN;
  7233. }
  7234. //
  7235. // zero the buffer in case the data that comes back is short.
  7236. //
  7237. ZeroMemory(&ObjectIdBuffer, sizeof(FILE_OBJECTID_BUFFER));
  7238. //
  7239. // Get the Object ID from the replica root.
  7240. //
  7241. Status = NtFsControlFile(
  7242. NewRootHandle, // file handle
  7243. NULL, // event
  7244. NULL, // apc routine
  7245. NULL, // apc context
  7246. &Iosb, // iosb
  7247. FSCTL_GET_OBJECT_ID, // FsControlCode
  7248. &NewRootHandle, // input buffer
  7249. sizeof(HANDLE), // input buffer length
  7250. &ObjectIdBuffer, // OutputBuffer for data from the FS
  7251. sizeof(FILE_OBJECTID_BUFFER)); // OutputBuffer Length
  7252. if (NT_SUCCESS(Status)) {
  7253. GuidToStr((GUID *)ObjectIdBuffer.ObjectId, GuidStr);
  7254. DPRINT1(4, ":S: Oid for replica root is %s\n", GuidStr );
  7255. } else
  7256. if (Status == STATUS_NOT_IMPLEMENTED) {
  7257. DPRINT1(0, ":S: ERROR - FSCTL_GET_OBJECT_ID failed on file %ws. Object IDs are not enabled on the volume.\n",
  7258. NewReplica->Root);
  7259. DisplayNTStatus(Status);
  7260. }
  7261. FRS_CLOSE(NewRootHandle);
  7262. //
  7263. // REPLICA ROOT DIR OBJECTID MISMATCH CHECK:
  7264. //
  7265. // If LastShutdown is 0 then this is the very first time we have started replication on this replica set
  7266. // in that case skip this check.
  7267. //
  7268. if (ConfigRecord->LastShutdown != (ULONGLONG)0 &&
  7269. ConfigRecord->ServiceState != CNF_SERVICE_STATE_CREATING &&
  7270. ConfigRecord->CnfUsnJournalID != (ULONGLONG)0) {
  7271. //
  7272. // The replica root might have been recreated in which case it will might
  7273. // have a object ID. In that vase we want to recreate the replica set.
  7274. // Check if the ReplicaRootGuid from config record matches with the ReplicaRootGuid
  7275. // from the FileSystem. If it does not then it means that
  7276. // this replica set has been moved. Returning error here will trigger
  7277. // a deletion of the replica set. The set will be recreated at the next
  7278. // poll cycle and it will either be primary or non-auth depending on the
  7279. // case.
  7280. //
  7281. if (Status == STATUS_OBJECT_NAME_NOT_FOUND ||
  7282. Status == STATUS_OBJECTID_NOT_FOUND ||
  7283. !GUIDS_EQUAL(&(ObjectIdBuffer.ObjectId), &(ConfigRecord->ReplicaRootGuid))) {
  7284. DPRINT1(0,"ERROR - Replica root guid mismatch for Replica Set (%ws)\n",Replica->ReplicaName->Name);
  7285. GuidToStr((GUID *)ObjectIdBuffer.ObjectId, GuidStr);
  7286. DPRINT1(0,"ERROR - Replica root guid (FS) (%s)\n",GuidStr);
  7287. GuidToStr((GUID *)&(ConfigRecord->ReplicaRootGuid), GuidStr);
  7288. DPRINT1(0,"ERROR - Replica root guid (DB) (%s)\n",GuidStr);
  7289. DPRINT1(0,"ERROR - Replica Set (%ws) is marked to be deleted\n",Replica->ReplicaName->Name);
  7290. Replica->FStatus = FrsErrorMismatchedReplicaRootObjectId;
  7291. *ReplicaState = REPLICA_STATE_MISMATCHED_REPLICA_ROOT_OBJECT_ID;
  7292. Result = TRUE;
  7293. goto RETURN;
  7294. }
  7295. }
  7296. //
  7297. // REPLICA ROOT DIR FID MISMATCH CHECK:
  7298. //
  7299. // If LastShutdown is 0 then this is the very first time we have started replication on this replica set
  7300. // in that case skip this check.
  7301. //
  7302. if (ConfigRecord->LastShutdown != (ULONGLONG)0 &&
  7303. ConfigRecord->ServiceState != CNF_SERVICE_STATE_CREATING &&
  7304. ConfigRecord->CnfUsnJournalID != (ULONGLONG)0) {
  7305. //
  7306. // Open the ID table.
  7307. //
  7308. RtCtx = FrsAllocType(REPLICA_THREAD_TYPE);
  7309. IDTableCtx = &RtCtx->IDTable;
  7310. AccessRequest = DBS_ACCESS_BYKEY | DBS_ACCESS_CLOSE;
  7311. pKey = (PVOID)&(ConfigRecord->ReplicaRootGuid);
  7312. CmdPkt = DbsPrepareCmdPkt(CmdPkt, // CmdPkt,
  7313. Replica, // Replica,
  7314. CMD_READ_TABLE_RECORD, // CmdRequest,
  7315. IDTableCtx, // TableCtx,
  7316. NULL, // CallContext,
  7317. IDTablex, // TableType,
  7318. AccessRequest, // AccessRequest,
  7319. GuidIndexx, // IndexType,
  7320. pKey, // KeyValue,
  7321. sizeof(GUID), // KeyValueLength,
  7322. FALSE); // Submit
  7323. if (CmdPkt == NULL) {
  7324. DPRINT(0, "ERROR - Failed to init the cmd pkt\n");
  7325. RtCtx = FrsFreeType(RtCtx);
  7326. goto RETURN;;
  7327. }
  7328. FrsSetCompletionRoutine(CmdPkt, FrsCompleteKeepPkt, NULL);
  7329. Status = FrsSubmitCommandServerAndWait(&DBServiceCmdServer, CmdPkt, INFINITE);
  7330. DbsRequest = &CmdPkt->Parameters.DbsRequest;
  7331. IDTableCtx = DBS_GET_TABLECTX(DbsRequest);
  7332. IDTableRec = IDTableCtx->pDataRecord;
  7333. if (DbsRequest == NULL || DbsRequest->FStatus != FrsErrorSuccess) {
  7334. RtCtx = FrsFreeType(RtCtx);
  7335. FrsFreeCommand(CmdPkt, NULL);
  7336. goto RETURN;
  7337. }
  7338. //
  7339. // The replica root might have been recreated by a restore operation in which case
  7340. // it will have the same object ID but a different FID. In that case we want
  7341. // to recreate the replica set. Check if the FID from IDTable matches with the FID
  7342. // from the FileSystem. If it does not then it means that this replica set has been
  7343. // moved. Returning error here will trigger a deletion of the replica set. The set
  7344. // will be recreated at the next poll cycle and it will either be primary or non-auth
  7345. // depending on the case.
  7346. // This can also happen when a junction point is present in the initial path to the replica
  7347. // root. At a later time the junction points destination is changed and the replica rpot
  7348. // has been moved.
  7349. //
  7350. if (IDTableRec->FileID != InternalFileInfo.IndexNumber.QuadPart) {
  7351. DPRINT1(0,"ERROR - Replica root fid mismatch for Replica Set (%ws)\n",Replica->ReplicaName->Name);
  7352. DPRINT1(0,"ERROR - Replica root fid (FS) (%08x %08x)\n",PRINTQUAD(InternalFileInfo.IndexNumber.QuadPart));
  7353. DPRINT1(0,"ERROR - Replica root fid (DB) (%08x %08x)\n",PRINTQUAD(IDTableRec->FileID));
  7354. DPRINT1(0,"ERROR - Replica Set (%ws) is marked to be deleted\n",Replica->ReplicaName->Name);
  7355. RtCtx = FrsFreeType(RtCtx);
  7356. FrsFreeCommand(CmdPkt, NULL);
  7357. Replica->FStatus = FrsErrorMismatchedReplicaRootFileId;
  7358. *ReplicaState = REPLICA_STATE_MISMATCHED_REPLICA_ROOT_FILE_ID;
  7359. Result = TRUE;
  7360. goto RETURN;
  7361. }
  7362. RtCtx = FrsFreeType(RtCtx);
  7363. FrsFreeCommand(CmdPkt, NULL);
  7364. }
  7365. RETURN:
  7366. VolumeInfo = FrsFree(VolumeInfo);
  7367. FRS_CLOSE(NewRootHandle);
  7368. return Result;
  7369. }
  7370. VOID
  7371. RcsStartReplicaSetMember(
  7372. IN PCOMMAND_PACKET Cmd
  7373. )
  7374. /*++
  7375. Routine Description:
  7376. Bring the replica up to joined, active status.
  7377. Arguments:
  7378. Cmd.
  7379. Return Value:
  7380. None.
  7381. --*/
  7382. {
  7383. #undef DEBSUB
  7384. #define DEBSUB "RcsStartReplicaSetMember:"
  7385. PREPLICA Replica;
  7386. PCXTION Cxtion;
  7387. ULONGLONG MembershipExpires;
  7388. PVOID Key;
  7389. DWORD NumberOfCxtions;
  7390. DWORD ReplicaState;
  7391. ULONG FStatus;
  7392. PWCHAR CmdFile = NULL;
  7393. ULONG FileAttributes;
  7394. extern ULONGLONG ActiveChange;
  7395. extern ULONG DsPollingInterval;
  7396. WCHAR DsPollingIntervalStr[7]; // Max interval is NTFRSAPI_MAX_INTERVAL.
  7397. FRS_ERROR_CODE SavedFStatus;
  7398. //
  7399. // Check the command packet
  7400. //
  7401. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  7402. return;
  7403. }
  7404. Replica = RsReplica(Cmd);
  7405. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsStartReplicaSetMember entry");
  7406. FRS_PRINT_TYPE(4, Replica);
  7407. //
  7408. // Increment the Replica Sets started counter
  7409. //
  7410. PM_INC_CTR_SERVICE(PMTotalInst, RSStarted, 1);
  7411. //
  7412. // Someone is trying to start a deleted replica. This is either part
  7413. // of startup and we are simply trying to start replication on all
  7414. // replicas or a deleted replica has actually reappeared.
  7415. //
  7416. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  7417. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Tombstoned");
  7418. //
  7419. // The deletion hasn't completed processing. The jrnlcxtion cannot
  7420. // be restarted without restarting the entire replica set. The
  7421. // set needs to be "closed" and then "opened". Let the tombstoning
  7422. // finish before attempting to re-open. A completely closed
  7423. // replica set has IsOpen set to FALSE and no cxtions.
  7424. //
  7425. if (Replica->IsOpen || GTabNumberInTable(Replica->Cxtions)) {
  7426. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica tombstone in progress");
  7427. RcsSubmitTransferToRcs(Cmd, CMD_DELETE);
  7428. return;
  7429. }
  7430. //
  7431. // Don't start a deleted replica unless it has magically reappeared.
  7432. //
  7433. if (RsNewReplica(Cmd) == NULL) {
  7434. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7435. return;
  7436. }
  7437. //
  7438. // Don't reanimate if the tombstone has expired
  7439. //
  7440. if (RcsReplicaHasExpired(Replica)) {
  7441. //
  7442. // Remove registry entry
  7443. //
  7444. RcsReplicaDeleteRegistry(Replica);
  7445. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Expired");
  7446. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7447. return;
  7448. }
  7449. //
  7450. // A deleted replica has reappeared; undelete the replica
  7451. //
  7452. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Reanimating");
  7453. RcsOpenReplicaSetMember(Replica);
  7454. MembershipExpires = Replica->MembershipExpires;
  7455. Replica->MembershipExpires = 0;
  7456. Replica->NeedsUpdate = TRUE;
  7457. RcsUpdateReplicaSetMember(Replica);
  7458. //
  7459. // The above friggen call set NeedsUpdate to false if the update succeeded.
  7460. //
  7461. //
  7462. // Replica cannot be marked as "undeleted" in the DB; retry later
  7463. // and *don't* start. We wouldn't want to start replication only
  7464. // to have the replica disappear from the database at the next
  7465. // reboot or service startup because its timeout expired.
  7466. //
  7467. FStatus = DbsCheckForOverlapErrors(Replica);
  7468. if (Replica->NeedsUpdate || !FRS_SUCCESS(FStatus)) {
  7469. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica Reanimation failed");
  7470. Replica->MembershipExpires = MembershipExpires;
  7471. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7472. //
  7473. // Ds poll thread will restart the replica during the next
  7474. // polling cycle if ActiveChange is set to 0.
  7475. //
  7476. ActiveChange = 0;
  7477. //
  7478. // Note: Does there need to be a replica set close here?
  7479. // Need to check all use of Replica->IsOpen to figure this out.
  7480. //
  7481. return;
  7482. }
  7483. //
  7484. // The open above returned success so Replica->IsOpen would be set
  7485. // as expected but since the replica set was marked expired the actual
  7486. // service state for the replica set is STOPPED and the handles to
  7487. // The pre-install dir was never opened. The call to reopen later
  7488. // will fail if Replica->IsOpen is still TRUE. So close it for now.
  7489. //
  7490. // *Note*
  7491. // Perf: Get rid of the friggen Replica->IsOpen flag and use the service
  7492. // state as originally intended.
  7493. //
  7494. RcsCloseReplicaSetmember(Replica);
  7495. //
  7496. // No longer tombstoned; update the registry
  7497. //
  7498. RcsReplicaSetRegistry(Replica);
  7499. //
  7500. // Set registry value "FilesNotToBackup"
  7501. //
  7502. CfgFilesNotToBackup(ReplicasByGuid);
  7503. }
  7504. //
  7505. // If this replica is in the error state then first make sure it is closed.
  7506. // and reset its state to initializing.
  7507. //
  7508. if (REPLICA_IN_ERROR_STATE(Replica->ServiceState)) {
  7509. RcsCloseReplicaSetmember(Replica);
  7510. JrnlSetReplicaState(Replica, REPLICA_STATE_INITIALIZING);
  7511. }
  7512. //
  7513. // Check if the replica root path has moved between two polls.
  7514. //
  7515. if (RcsHasReplicaRootPathMoved(Replica, RsNewReplica(Cmd), &ReplicaState)) {
  7516. //
  7517. // Save the FStatus. We need the correct FStatus to report in the
  7518. // eventlog written in JrnlSetReplicaState(). FStatus set by
  7519. // RcsHasReplicaRootPathMoved() is overwritten when we stop and
  7520. // close the replica set.
  7521. //
  7522. //
  7523. SavedFStatus = Replica->FStatus;
  7524. //
  7525. // The replica root has moved. This could be a intentional move or
  7526. // it could be caused by change of drive letter. In any case we need a
  7527. // confirmation from the user to go ahead and trigger a non-auth restore
  7528. // of the replica set. We will look for a special file "NTFRS_CMD_FILE_MOVE_ROOT"
  7529. // under the new replica root. If this file is present we will go ahead and delete
  7530. // the replica set which will trigger a non-auth restore at the next poll.
  7531. // The command file is deleted when the replica set is initialized.
  7532. //
  7533. CmdFile = FrsWcsCat3((RsNewReplica(Cmd))->Root, L"\\", NTFRS_CMD_FILE_MOVE_ROOT);
  7534. FileAttributes = GetFileAttributes(CmdFile);
  7535. if ((FileAttributes == 0xffffffff) ||
  7536. (FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
  7537. //
  7538. // Get the DsPollingInteval in minutes.
  7539. //
  7540. _itow(DsPollingInterval / (60 * 1000), DsPollingIntervalStr, 10);
  7541. EPRINT4(EVENT_FRS_ROOT_HAS_MOVED, Replica->SetName->Name, Replica->Root,
  7542. (RsNewReplica(Cmd))->Root, DsPollingIntervalStr);
  7543. DPRINT1(0,"ERROR Command file not found at the new root %ws. Can not move root.\n",CmdFile);
  7544. //
  7545. // This replica state will not trigger a delete but it will still put it on
  7546. // the fault list.
  7547. //
  7548. ReplicaState = REPLICA_STATE_ERROR;
  7549. }
  7550. CmdFile = FrsFree(CmdFile);
  7551. RcsSubmitStopReplicaToDb(Replica);
  7552. RcsCloseReplicaSetmember(Replica);
  7553. RcsCloseReplicaCxtions(Replica);
  7554. //
  7555. // Write the saved FStatus back so we can write it to the eventlog.
  7556. //
  7557. Replica->FStatus = SavedFStatus;
  7558. JrnlSetReplicaState(Replica, ReplicaState);
  7559. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7560. ActiveChange = 0;
  7561. return;
  7562. }
  7563. //
  7564. // Retry the open
  7565. //
  7566. RcsOpenReplicaSetMember(Replica);
  7567. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "B, Replica opened");
  7568. //
  7569. // Pre-Install Dir should now be open.
  7570. //
  7571. if (!HANDLE_IS_VALID(Replica->PreInstallHandle) ||
  7572. !FRS_SUCCESS(Replica->FStatus)) {
  7573. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7574. ActiveChange = 0;
  7575. return;
  7576. }
  7577. //
  7578. // Retry the journal
  7579. //
  7580. RcsInitOneReplicaSet(Replica);
  7581. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsJournaling, "B, Journal opened");
  7582. //
  7583. // Update the database iff fields have changed
  7584. //
  7585. RcsMergeReplicaFields(Replica, RsNewReplica(Cmd));
  7586. //
  7587. // If needed, update the replica in the database
  7588. //
  7589. RcsUpdateReplicaSetMember(Replica);
  7590. //
  7591. // The above friggen call set Replica->NeedsUpdate to false if the update succeeded.
  7592. //
  7593. //
  7594. // Update the database iff cxtions have changed
  7595. //
  7596. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Merge Replica Cxtions");
  7597. NumberOfCxtions = GTabNumberInTable(Replica->Cxtions);
  7598. RcsMergeReplicaCxtions(Replica, RsNewReplica(Cmd), RsNewCxtion(Cmd));
  7599. RsNewCxtion(Cmd) = NULL;
  7600. if (NumberOfCxtions != GTabNumberInTable(Replica->Cxtions)) {
  7601. RcsReplicaSetRegistry(Replica);
  7602. }
  7603. //
  7604. // Accept remote change orders and join outbound connections.
  7605. //
  7606. if (Replica->IsOpen && Replica->IsJournaling) {
  7607. Replica->IsAccepting = TRUE;
  7608. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsAccepting, "B, Is Accepting");
  7609. }
  7610. //
  7611. // Retry the join
  7612. //
  7613. if (Replica->IsOpen && Replica->IsJournaling) {
  7614. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica accepting, Starting cxtions");
  7615. //
  7616. // If we are in the seeding state then let the Initial Sync command server
  7617. // control the joining.
  7618. //
  7619. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  7620. if (Replica->InitSyncQueue == NULL) {
  7621. //
  7622. // Initialize the queue for the InitSync Command server.
  7623. //
  7624. Replica->InitSyncQueue = FrsAlloc(sizeof(FRS_QUEUE));
  7625. FrsInitializeQueue(Replica->InitSyncQueue, &InitSyncCs.Control);
  7626. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, submit CMD_INITSYNC_START_SYNC");
  7627. InitSyncSubmitToInitSyncCs(Replica, CMD_INITSYNC_START_SYNC);
  7628. } else {
  7629. //
  7630. // Initial Sync command server is already working on this replica set.
  7631. //
  7632. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica in initial sync state");
  7633. }
  7634. }
  7635. //
  7636. // Process all the connections in the table by putting a command
  7637. // packet for each cxtion on this replica's command queue.
  7638. //
  7639. Key = NULL;
  7640. while (Cxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  7641. //
  7642. // If replica is in seeding state then skip the connections that have
  7643. // not completed their initial join. (CXTION_FLAGS_INIT_SYNC)
  7644. // These connections will be joined by the initial sync command server.
  7645. //
  7646. if (BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  7647. CxtionFlagIs(Cxtion, CXTION_FLAGS_INIT_SYNC)) {
  7648. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, skip cxtion join");
  7649. continue;
  7650. }
  7651. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, submit cxtion join");
  7652. RcsSubmitReplicaCxtionJoin(Replica, Cxtion, FALSE);
  7653. }
  7654. } else {
  7655. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT accepting");
  7656. //
  7657. // Ds poll thread will restart the replica during the next
  7658. // polling cycle if ActiveChange is set to 0.
  7659. //
  7660. ActiveChange = 0;
  7661. }
  7662. //
  7663. // Check if this replica set is journaling and is not seeding or is online.
  7664. //
  7665. if (Replica->IsJournaling &&
  7666. ((!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING) &&
  7667. !Replica->IsSeeding) ||
  7668. BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE))){
  7669. //
  7670. // If this is a sysvol replica set then set sysvol ready if not already set.
  7671. //
  7672. if (FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType) &&
  7673. !Replica->IsSysvolReady) {
  7674. Replica->IsSysvolReady = RcsSetSysvolReady(1);
  7675. if (!Replica->IsSysvolReady) {
  7676. //
  7677. // Ds poll thread will restart the replica during the next
  7678. // polling cycle if ActiveChange is set to 0.
  7679. //
  7680. ActiveChange = 0;
  7681. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica sysvol not ready");
  7682. } else {
  7683. RcsReplicaSetRegistry(Replica);
  7684. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica sysvol is ready");
  7685. }
  7686. }
  7687. //
  7688. // Also make this set online if not already set.
  7689. //
  7690. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_ONLINE)) {
  7691. SetFlag(Replica->CnfFlags, CONFIG_FLAG_ONLINE);
  7692. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is Online");
  7693. Replica->NeedsUpdate = TRUE;
  7694. }
  7695. }
  7696. if (Replica->NeedsUpdate) {
  7697. //
  7698. // Ds poll thread will restart the replica during the next
  7699. // polling cycle if ActiveChange is set to 0.
  7700. //
  7701. ActiveChange = 0;
  7702. }
  7703. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7704. }
  7705. VOID
  7706. RcsDeleteReplicaRetry(
  7707. IN PCOMMAND_PACKET Cmd
  7708. )
  7709. /*++
  7710. Routine Description:
  7711. Retry bringing the replica down to an unjoined, idle status.
  7712. Arguments:
  7713. Cmd.
  7714. Return Value:
  7715. None.
  7716. --*/
  7717. {
  7718. #undef DEBSUB
  7719. #define DEBSUB "RcsDeleteReplicaRetry:"
  7720. FILETIME FileTime;
  7721. ULONGLONG Now;
  7722. PREPLICA Replica;
  7723. PVOID CxtionKey;
  7724. PCXTION Cxtion;
  7725. //
  7726. // Check the command packet
  7727. //
  7728. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  7729. return;
  7730. }
  7731. Replica = RsReplica(Cmd);
  7732. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsDeleteReplicaRetry entry");
  7733. //
  7734. // No longer tombstoned; done
  7735. //
  7736. if (IS_TIME_ZERO(Replica->MembershipExpires)) {
  7737. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7738. return;
  7739. }
  7740. //
  7741. // Start the unjoin process on all cxtions
  7742. //
  7743. CxtionKey = NULL;
  7744. while ((!FrsIsShuttingDown) &&
  7745. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7746. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Force unjoin cxtion");
  7747. RcsForceUnjoin(Replica, Cxtion);
  7748. }
  7749. //
  7750. // Are all cxtions unjoined?
  7751. //
  7752. CxtionKey = NULL;
  7753. Cxtion = NULL;
  7754. while ((!FrsIsShuttingDown) &&
  7755. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7756. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  7757. !CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  7758. break;
  7759. }
  7760. }
  7761. //
  7762. // Not all cxtions are unjoined (or deleted). Retry this command
  7763. // in a bit if the replica set ramains tombstoned.
  7764. //
  7765. if (Cxtion) {
  7766. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Retry delete later, again");
  7767. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CMD_DELETE_RETRY_LONG_TIMEOUT);
  7768. return;
  7769. }
  7770. //
  7771. // All of the cxtions were successfully unjoined. Shut down the replica.
  7772. //
  7773. //
  7774. // Stop accepting comm packets. Errors are returned to our partner.
  7775. //
  7776. // IsAccepting will become TRUE again in RcsStartReplicaSetMember() before
  7777. // any cxtion rejoins.
  7778. //
  7779. Replica->IsAccepting = FALSE;
  7780. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT Accepting");
  7781. //
  7782. // Stop journal processing and close the replica.
  7783. //
  7784. RcsSubmitStopReplicaToDb(Replica);
  7785. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "IsOpen, Replica closed");
  7786. if (Replica->IsOpen) {
  7787. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, Replica still open");
  7788. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7789. return;
  7790. } else {
  7791. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica closed");
  7792. }
  7793. //
  7794. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  7795. // generate new cxtion structs before active processing (aka joining)
  7796. // occurs. The cxtions remain in the DeletedCxtions table so that
  7797. // other threads that may have been time sliced just after acquiring
  7798. // the cxtion pointer but before making use of it will not AV. We
  7799. // could have put in locks but then there would be deadlock and
  7800. // perf considerations; all for the sake of this seldom occuring
  7801. // operation.
  7802. //
  7803. RcsCloseReplicaCxtions(Replica);
  7804. //
  7805. // Increment the Replica Sets deleted counter
  7806. //
  7807. PM_INC_CTR_SERVICE(PMTotalInst, RSDeleted, 1);
  7808. //
  7809. // Has the tombstone expired?
  7810. //
  7811. if (RcsReplicaHasExpired(Replica)) {
  7812. RcsSubmitTransferToRcs(Cmd, CMD_DELETE_NOW);
  7813. } else {
  7814. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7815. }
  7816. return;
  7817. }
  7818. VOID
  7819. RcsDeleteReplicaSetMember(
  7820. IN PCOMMAND_PACKET Cmd
  7821. )
  7822. /*++
  7823. Routine Description:
  7824. Bring the replica down to an unjoined, idle status.
  7825. Arguments:
  7826. Cmd.
  7827. Return Value:
  7828. None.
  7829. --*/
  7830. {
  7831. #undef DEBSUB
  7832. #define DEBSUB "RcsDeleteReplicaSetMember:"
  7833. FILETIME FileTime;
  7834. ULONGLONG Now;
  7835. PREPLICA Replica;
  7836. PVOID CxtionKey;
  7837. PCXTION Cxtion;
  7838. //
  7839. // Check the command packet
  7840. //
  7841. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  7842. return;
  7843. }
  7844. Replica = RsReplica(Cmd);
  7845. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsDeleteReplicaSetMember entry");
  7846. //
  7847. // Time in 100nsec tics since Jan 1, 1601
  7848. //
  7849. GetSystemTimeAsFileTime(&FileTime);
  7850. COPY_TIME(&Now, &FileTime);
  7851. //
  7852. // SET THE TOMBSTONE
  7853. //
  7854. if (IS_TIME_ZERO(Replica->MembershipExpires)) {
  7855. //
  7856. // Set the timeout
  7857. //
  7858. Replica->MembershipExpires = Now + ReplicaTombstoneInFileTime;
  7859. //
  7860. // Update the database record
  7861. //
  7862. Replica->NeedsUpdate = TRUE;
  7863. RcsUpdateReplicaSetMember(Replica);
  7864. //
  7865. // The above friggen call set NeedsUpdate to false if the update succeeded.
  7866. //
  7867. //
  7868. // Couldn't update; reset the timeout and retry at the next ds poll
  7869. //
  7870. if (Replica->NeedsUpdate) {
  7871. Replica->MembershipExpires = 0;
  7872. FrsCompleteCommand(Cmd, ERROR_RETRY);
  7873. return;
  7874. }
  7875. }
  7876. //
  7877. // Set registry value "FilesNotToBackup"
  7878. //
  7879. CfgFilesNotToBackup(ReplicasByGuid);
  7880. //
  7881. // Tombstoned; update the registry
  7882. //
  7883. RcsReplicaSetRegistry(Replica);
  7884. //
  7885. // Start the unjoin process on all cxtions
  7886. //
  7887. CxtionKey = NULL;
  7888. while ((!FrsIsShuttingDown) &&
  7889. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7890. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Force unjoin cxtion");
  7891. RcsForceUnjoin(Replica, Cxtion);
  7892. }
  7893. //
  7894. // Are all cxtions unjoined?
  7895. //
  7896. CxtionKey = NULL;
  7897. Cxtion = NULL;
  7898. while ((!FrsIsShuttingDown) &&
  7899. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  7900. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  7901. !CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  7902. break;
  7903. }
  7904. }
  7905. //
  7906. // Not all cxtions are unjoined (or deleted). Try again at the
  7907. // next ds polling cycle IFF the set is still deleted. Return
  7908. // success since the set has been successfully marked as
  7909. // tombstoned.
  7910. if (Cxtion) {
  7911. //
  7912. // Complete the old command packet in case another thread
  7913. // is waiting on it (like FrsDsStartDemotion()).
  7914. //
  7915. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Retry delete later");
  7916. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7917. //
  7918. // Allocate a new command packet that will retry the delete
  7919. // as long as the replica set remains tombstoned.
  7920. //
  7921. Cmd = FrsAllocCommand(Replica->Queue, CMD_DELETE_RETRY);
  7922. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  7923. RsReplica(Cmd) = Replica;
  7924. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CMD_DELETE_RETRY_SHORT_TIMEOUT);
  7925. return;
  7926. }
  7927. //
  7928. // All of the cxtions were successfully unjoined. Shut down the replica.
  7929. //
  7930. //
  7931. // Stop accepting comm packets. Errors are returned to our partner.
  7932. //
  7933. // IsAccepting will become TRUE again in RcsStartReplicaSetMember() before
  7934. // any cxtion rejoins.
  7935. //
  7936. Replica->IsAccepting = FALSE;
  7937. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT Accepting");
  7938. //
  7939. // Stop journal processing and close the replica.
  7940. //
  7941. RcsSubmitStopReplicaToDb(Replica);
  7942. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "IsOpen, Replica closed");
  7943. if (Replica->IsOpen) {
  7944. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, Replica still open");
  7945. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7946. return;
  7947. } else {
  7948. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica closed");
  7949. }
  7950. //
  7951. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  7952. // generate new cxtion structs before active processing (aka joining)
  7953. // occurs. The cxtions remain in the DeletedCxtions table so that
  7954. // other threads that may have been time sliced just after acquiring
  7955. // the cxtion pointer but before making use of it will not AV. We
  7956. // could have put in locks but then there would be deadlock and
  7957. // perf considerations; all for the sake of this seldom occuring
  7958. // operation.
  7959. //
  7960. RcsCloseReplicaCxtions(Replica);
  7961. //
  7962. // Increment the Replica Sets deleted counter
  7963. //
  7964. PM_INC_CTR_SERVICE(PMTotalInst, RSDeleted, 1);
  7965. //
  7966. // Has the tombstone expired?
  7967. //
  7968. if (RcsReplicaHasExpired(Replica)) {
  7969. RcsSubmitTransferToRcs(Cmd, CMD_DELETE_NOW);
  7970. } else {
  7971. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  7972. }
  7973. return;
  7974. }
  7975. VOID
  7976. RcsDeleteReplicaSetMemberNow(
  7977. IN PCOMMAND_PACKET Cmd
  7978. )
  7979. /*++
  7980. Routine Description:
  7981. Bring the replica down to an unjoined, idle status. Don't reanimate.
  7982. Arguments:
  7983. Cmd.
  7984. Return Value:
  7985. None.
  7986. --*/
  7987. {
  7988. #undef DEBSUB
  7989. #define DEBSUB "RcsDeleteReplicaSetMemberNow:"
  7990. FILETIME FileTime;
  7991. ULONGLONG Now;
  7992. PREPLICA Replica;
  7993. PVOID CxtionKey;
  7994. PCXTION Cxtion;
  7995. ULONGLONG OldMembershipExpires;
  7996. //
  7997. // Check the command packet
  7998. //
  7999. if (!RcsCheckCmd(Cmd, DEBSUB, CHECK_CMD_REPLICA)) {
  8000. return;
  8001. }
  8002. Replica = RsReplica(Cmd);
  8003. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, RcsDeleteReplicaSetMemberNow entry");
  8004. //
  8005. // Time in 100nsec tics since Jan 1, 1601
  8006. //
  8007. GetSystemTimeAsFileTime(&FileTime);
  8008. COPY_TIME(&Now, &FileTime);
  8009. if (IS_TIME_ZERO(Replica->MembershipExpires) || Replica->MembershipExpires >= Now) {
  8010. //
  8011. // Never reanimate this replica.
  8012. //
  8013. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Marking Replica expired");
  8014. RcsOpenReplicaSetMember(Replica);
  8015. OldMembershipExpires = Replica->MembershipExpires;
  8016. Replica->MembershipExpires = Now - ONEDAY;
  8017. Replica->NeedsUpdate = TRUE;
  8018. RcsUpdateReplicaSetMember(Replica);
  8019. //
  8020. // The above friggen call set NeedsUpdate to false if the update succeeded.
  8021. //
  8022. //
  8023. // Replica cannot be updated in the DB. Give up.
  8024. //
  8025. if (Replica->NeedsUpdate) {
  8026. Replica->MembershipExpires = OldMembershipExpires;
  8027. FrsCompleteCommand(Cmd, ERROR_RETRY);
  8028. return;
  8029. }
  8030. }
  8031. //
  8032. // Set registry value "FilesNotToBackup"
  8033. //
  8034. CfgFilesNotToBackup(ReplicasByGuid);
  8035. //
  8036. // Remove registry entry
  8037. //
  8038. RcsReplicaDeleteRegistry(Replica);
  8039. //
  8040. // Start the unjoin process on all cxtions
  8041. //
  8042. CxtionKey = NULL;
  8043. while ((!FrsIsShuttingDown) &&
  8044. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  8045. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Force unjoin cxtion");
  8046. RcsForceUnjoin(Replica, Cxtion);
  8047. }
  8048. //
  8049. // Are all cxtions unjoined?
  8050. //
  8051. CxtionKey = NULL;
  8052. Cxtion = NULL;
  8053. while ((!FrsIsShuttingDown) &&
  8054. (Cxtion = GTabNextDatum(Replica->Cxtions, &CxtionKey))) {
  8055. if (!CxtionStateIs(Cxtion, CxtionStateUnjoined) &&
  8056. !CxtionStateIs(Cxtion, CxtionStateDeleted)) {
  8057. break;
  8058. }
  8059. }
  8060. //
  8061. // Not all cxtions are unjoined (or deleted). Try again at the
  8062. // next ds polling cycle IFF the set is still deleted. Return
  8063. // success since the set has been successfully marked as
  8064. // do-not-animate.
  8065. //
  8066. if (Cxtion) {
  8067. //
  8068. // Complete the old command packet in case another thread
  8069. // is waiting on it (like FrsDsStartDemotion()).
  8070. //
  8071. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Retry delete later");
  8072. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  8073. //
  8074. // Allocate a new command packet that will retry the delete
  8075. // as long as the replica set remains tombstoned.
  8076. //
  8077. Cmd = FrsAllocCommand(Replica->Queue, CMD_DELETE_RETRY);
  8078. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  8079. RsReplica(Cmd) = Replica;
  8080. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, CMD_DELETE_RETRY_SHORT_TIMEOUT);
  8081. return;
  8082. }
  8083. //
  8084. // All of the cxtions were successfully unjoined. Shut down the replica.
  8085. //
  8086. //
  8087. // Stop accepting comm packets. Errors are returned to our partner.
  8088. //
  8089. Replica->IsAccepting = FALSE;
  8090. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica is NOT Accepting");
  8091. //
  8092. // Stop journal processing and close the replica.
  8093. //
  8094. RcsSubmitStopReplicaToDb(Replica);
  8095. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->IsOpen, "IsOpen, Replica closed");
  8096. if (Replica->IsOpen) {
  8097. REPLICA_STATE_TRACE(3, Cmd, Replica, Replica->FStatus, "F, Replica still open");
  8098. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  8099. return;
  8100. } else {
  8101. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Replica closed");
  8102. }
  8103. //
  8104. // "Delete" the cxtions from active processing. RcsOpenReplicaSetMember() will
  8105. // generate new cxtion structs before active processing (aka joining)
  8106. // occurs. The cxtions remain in the DeletedCxtions table so that
  8107. // other threads that may have been time sliced just after acquiring
  8108. // the cxtion pointer but before making use of it will not AV. We
  8109. // could have put in locks but then there would be deadlock and
  8110. // perf considerations; all for the sake of this seldom occuring
  8111. // operation.
  8112. //
  8113. RcsCloseReplicaCxtions(Replica);
  8114. //
  8115. // Delete the replica set tables in the db.
  8116. //
  8117. RcsDeleteReplicaFromDb(Replica);
  8118. //
  8119. // Remove the replica from any in-memory tables that it might be in.
  8120. //
  8121. if (RcsFindReplicaByGuid(Replica->ReplicaName->Guid) != NULL) {
  8122. GTabDelete(ReplicasByGuid, Replica->ReplicaName->Guid, NULL, NULL);
  8123. }
  8124. if (RcsFindReplicaByNumber(Replica->ReplicaNumber) != NULL) {
  8125. GTabDelete(ReplicasByNumber, &Replica->ReplicaNumber, NULL, NULL);
  8126. }
  8127. //
  8128. // Increment the Replica Sets removed counter
  8129. //
  8130. PM_INC_CTR_SERVICE(PMTotalInst, RSRemoved, 1);
  8131. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  8132. return;
  8133. }
  8134. VOID
  8135. RcsStartValidReplicaSetMembers(
  8136. IN PCOMMAND_PACKET Cmd
  8137. )
  8138. /*++
  8139. Routine Description:
  8140. Tell the replicas to bring themselves up to joined, active status.
  8141. This includes the journal and joining with inbound partners.
  8142. This routine is run once at service startup and then once
  8143. an hour to check the schedule.
  8144. Arguments:
  8145. None.
  8146. Return Value:
  8147. None.
  8148. --*/
  8149. {
  8150. #undef DEBSUB
  8151. #define DEBSUB "RcsStartValidReplicaSetMembers:"
  8152. PVOID Key;
  8153. PREPLICA Replica;
  8154. ULONG TimeOut;
  8155. SYSTEMTIME SystemTime;
  8156. DPRINT1(4, ":S: Command start replicas waiting %08x\n", Cmd);
  8157. WaitForSingleObject(ReplicaEvent, INFINITE);
  8158. DPRINT1(4, ":S: Command start replicas %08x\n", Cmd);
  8159. //
  8160. // Send a start command to each replica. Replicas that are already
  8161. // started or starting will ignore the command. The replicas will
  8162. // check their join status and rejoin if needed.
  8163. //
  8164. Key = NULL;
  8165. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  8166. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Submit Start Replica");
  8167. RcsSubmitReplica(Replica, NULL, CMD_START);
  8168. }
  8169. //
  8170. // Milliseconds till the next hour
  8171. //
  8172. GetSystemTime(&SystemTime);
  8173. TimeOut = ((60 - SystemTime.wMinute) * 60000) +
  8174. ((60 - SystemTime.wSecond) * 1000) +
  8175. (1000 - SystemTime.wMilliseconds);
  8176. DPRINT1(4, "Check schedules in %d seconds\n", TimeOut / 1000);
  8177. #if DBG
  8178. if (DebugInfo.Interval) {
  8179. TimeOut = DebugInfo.Interval * 1000;
  8180. DPRINT1(0, ":X: DEBUG - toggle schedules in %d seconds\n", TimeOut / 1000);
  8181. }
  8182. #endif DBG
  8183. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, TimeOut);
  8184. }
  8185. ULONG
  8186. RcsSubmitCmdPktToRcsQueue(
  8187. IN PCOMMAND_PACKET Cmd,
  8188. IN PCOMM_PACKET CommPkt,
  8189. IN PWCHAR AuthClient,
  8190. IN PWCHAR AuthName,
  8191. IN PWCHAR AuthSid,
  8192. IN DWORD AuthLevel,
  8193. IN DWORD AuthN,
  8194. IN DWORD AuthZ
  8195. )
  8196. /*++
  8197. Routine Description:
  8198. Convert a comm packet into a command packet and send
  8199. it to the correct replica set. NOTE - RPC owns the comm
  8200. packet.
  8201. Arguments:
  8202. CommPkt
  8203. AuthClient
  8204. AuthName
  8205. AuthSid
  8206. AuthLevel
  8207. AuthN
  8208. AuthZ
  8209. Return Value:
  8210. Error status to be propagated to the sender
  8211. --*/
  8212. {
  8213. #undef DEBSUB
  8214. #define DEBSUB "RcsSubmitCmdPktToRcsQueue:"
  8215. DWORD WStatus;
  8216. PREPLICA Replica;
  8217. PCXTION Cxtion = NULL;
  8218. ULONG WaitTime;
  8219. ULONG NumWaitingCOs;
  8220. ULONGLONG *pFileTime = NULL;
  8221. //
  8222. // Must have the replica's name in order to queue the command
  8223. //
  8224. if (RsReplicaName(Cmd) == NULL || RsReplicaName(Cmd)->Name == NULL ) {
  8225. COMMAND_RCV_TRACE(3, Cmd, Cxtion, ERROR_INVALID_NAME, "RcvFail - no replica name");
  8226. FrsCompleteCommand(Cmd, ERROR_INVALID_NAME);
  8227. return ERROR_INVALID_NAME;
  8228. }
  8229. //
  8230. // Find the target replica
  8231. //
  8232. Replica = GTabLookup(ReplicasByGuid, RsReplicaName(Cmd)->Guid, NULL);
  8233. if (Replica == NULL) {
  8234. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_FILE_NOT_FOUND, "RcvFail - replica not found");
  8235. FrsCompleteCommand(Cmd, ERROR_FILE_NOT_FOUND);
  8236. return ERROR_FILE_NOT_FOUND;
  8237. }
  8238. //
  8239. // The target replica may not be accepting comm packets
  8240. //
  8241. if (!Replica->IsAccepting) {
  8242. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_RETRY, "RcvFail - not accepting");
  8243. FrsCompleteCommand(Cmd, ERROR_RETRY);
  8244. return ERROR_RETRY;
  8245. }
  8246. //
  8247. // Find the cxtion
  8248. //
  8249. if (RsCxtion(Cmd)) {
  8250. LOCK_CXTION_TABLE(Replica);
  8251. Cxtion = GTabLookupNoLock(Replica->Cxtions, RsCxtion(Cmd)->Guid, NULL);
  8252. if (Cxtion != NULL) {
  8253. Cxtion->PartnerMajor = CommPkt->Major;
  8254. Cxtion->PartnerMinor = CommPkt->Minor;
  8255. //
  8256. // The count of comm packets is used to detect a hung outbound
  8257. // cxtion (See CMD_HUNG_CXTION). The hang is most likely caused by
  8258. // a dropped ack.
  8259. //
  8260. Cxtion->CommPkts++;
  8261. //
  8262. // This change order may already exist on this machine. If so,
  8263. // use its change order entry because we will need its database
  8264. // context for updates.
  8265. //
  8266. LOCK_CXTION_COE_TABLE(Replica, Cxtion);
  8267. if (RsCoGuid(Cmd)) {
  8268. RsCoe(Cmd) = GTabLookupNoLock(Cxtion->CoeTable, RsCoGuid(Cmd), NULL);
  8269. //
  8270. // Note this command should be a response to a stage file
  8271. // fetch request. As such the Command code should be one of
  8272. // the following:
  8273. // CMD_RECEIVING_STAGE, CMD_RETRY_FETCH, or CMD_ABORT_FETCH.
  8274. //
  8275. // Also this response should have the same data that we are expecting.
  8276. // Consider a case of a outstanding request for staging data. Now we
  8277. // rejoin and send the request again (Win2K SP3 and greater), now
  8278. // we can get responses to both the requests. We do not want to start
  8279. // two parallel chain of requests for subsequent data in the staging file.
  8280. //
  8281. // If it is anything else then don't pull it out of the table.
  8282. //
  8283. // This check is needed because if we have just restarted this
  8284. // connection then this CO could be a resend of a CO that was
  8285. // already restarted from the Inbound log. Without the Command
  8286. // check we would incorrectly attach this Coe state to the wrong
  8287. // command packet and possibly cancel the timeout check.
  8288. //
  8289. if (RsCoe(Cmd) && ((Cmd->Command == CMD_RECEIVING_STAGE) ||
  8290. (Cmd->Command == CMD_RETRY_FETCH) ||
  8291. (Cmd->Command == CMD_ABORT_FETCH))) {
  8292. GTabDeleteNoLock(Cxtion->CoeTable, RsCoGuid(Cmd), NULL, NULL);
  8293. } else {
  8294. RsCoe(Cmd) = NULL;
  8295. }
  8296. }
  8297. NumWaitingCOs = GTabNumberInTable(Cxtion->CoeTable);
  8298. UNLOCK_CXTION_COE_TABLE(Replica, Cxtion);
  8299. //
  8300. // There is no need to keep a timeout pending if there are no
  8301. // idle change orders. Otherwise, bump the timeout since we
  8302. // have received something from our partner.
  8303. //
  8304. // Note: Need better filter for commands that aren't ACKs.
  8305. //
  8306. if (CxtionFlagIs(Cxtion, CXTION_FLAGS_TIMEOUT_SET)) {
  8307. //
  8308. // :SP1: Volatile connection cleanup.
  8309. //
  8310. // A volatile connection is used to seed sysvols after dcpromo.
  8311. // If there is inactivity on a volatile outbound connection for
  8312. // more than FRS_VOLATILE_CONNECTION_MAX_IDLE_TIME then this
  8313. // connection is unjoined. An unjoin on a volatile outbound
  8314. // connection triggers a delete on that connection. This is to
  8315. // prevent the case where staging files are kept for ever on the
  8316. // parent for a volatile connection.
  8317. //
  8318. WaitTime = (VOLATILE_OUTBOUND_CXTION(Cxtion) ?
  8319. FRS_VOLATILE_CONNECTION_MAX_IDLE_TIME :
  8320. CommTimeoutInMilliSeconds);
  8321. if (VOLATILE_OUTBOUND_CXTION(Cxtion)) {
  8322. GetSystemTimeAsFileTime((PFILETIME)&SRTimeoutSetTime(Cxtion->CommTimeoutCmd));
  8323. SRLastJoinTime(Cxtion->CommTimeoutCmd) = Cxtion->LastJoinTime;
  8324. WaitSubmit(Cxtion->CommTimeoutCmd, WaitTime, CMD_DELAYED_COMPLETE);
  8325. } else
  8326. if (NumWaitingCOs > 0) {
  8327. if (RsCoe(Cmd) != NULL) {
  8328. //
  8329. // Extend the timer since we still have outstanding
  8330. // change orders that need a response from our partner
  8331. // and the current comm packet is responding to one of
  8332. // those change orders.
  8333. //
  8334. GetSystemTimeAsFileTime((PFILETIME)&SRTimeoutSetTime(Cxtion->CommTimeoutCmd));
  8335. SRLastJoinTime(Cxtion->CommTimeoutCmd) = Cxtion->LastJoinTime;
  8336. WaitSubmit(Cxtion->CommTimeoutCmd, WaitTime, CMD_DELAYED_COMPLETE);
  8337. }
  8338. } else
  8339. if (Cmd->Command != CMD_START_JOIN) {
  8340. //
  8341. // Not volatile outbound and no COs in CoeTable waiting for
  8342. // a response so disable the cxtion timer... but
  8343. // CMD_START_JOIN's do not disable the join timer because
  8344. // they aren't sent in response to a request by this
  8345. // service. Disabling the timer might hang the service as
  8346. // it waits for a response that never comes and a timeout
  8347. // that never hits.
  8348. //
  8349. ClearCxtionFlag(Cxtion, CXTION_FLAGS_TIMEOUT_SET);
  8350. }
  8351. }
  8352. } else {
  8353. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_SUCCESS, "RcvFail - cxtion not found");
  8354. }
  8355. UNLOCK_CXTION_TABLE(Replica);
  8356. if (Cxtion != NULL) {
  8357. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_SUCCESS, "RcvSuccess");
  8358. }
  8359. } else {
  8360. COMMAND_RCV_TRACE(4, Cmd, Cxtion, ERROR_SUCCESS, "RcvFail - no cxtion");
  8361. }
  8362. //
  8363. // Update the command with the replica pointer and the change order
  8364. // command with the local the replica number.
  8365. //
  8366. if (RsPartnerCoc(Cmd)) {
  8367. RsPartnerCoc(Cmd)->NewReplicaNum = ReplicaAddrToId(Replica);
  8368. //
  8369. // We will never see a remotely generated MOVERS. We always
  8370. // see a delete to the old RS followed by a create in the
  8371. // new RS. So set both replica ptrs to our Replica struct.
  8372. //
  8373. RsPartnerCoc(Cmd)->OriginalReplicaNum = ReplicaAddrToId(Replica);
  8374. }
  8375. RsReplica(Cmd) = Replica;
  8376. //
  8377. // Authentication info
  8378. //
  8379. RsAuthClient(Cmd) = FrsWcsDup(AuthClient);
  8380. RsAuthName(Cmd) = FrsWcsDup(AuthName);
  8381. RsAuthLevel(Cmd) = AuthLevel;
  8382. RsAuthN(Cmd) = AuthN;
  8383. RsAuthZ(Cmd) = AuthZ;
  8384. switch(Cmd->Command) {
  8385. case CMD_JOINING:
  8386. //
  8387. // This is a Joining packet so save the current time
  8388. // in the Cmd as the receive time. This time is used to make
  8389. // the time skew check.
  8390. //
  8391. pFileTime = FrsAlloc(sizeof(FILETIME));
  8392. GetSystemTimeAsFileTime((FILETIME *)pFileTime);
  8393. RsCommPktRcvTime(Cmd) = pFileTime;
  8394. // Intentional fall through.
  8395. case CMD_NEED_JOIN:
  8396. case CMD_START_JOIN:
  8397. case CMD_JOINED:
  8398. case CMD_UNJOIN_REMOTE:
  8399. //
  8400. // Set user sid
  8401. //
  8402. RsAuthSid(Cmd) = FrsWcsDup(AuthSid);
  8403. break;
  8404. default:
  8405. break;
  8406. }
  8407. //
  8408. // Put the command on the replica's queue
  8409. //
  8410. Cmd->TargetQueue = Replica->Queue;
  8411. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  8412. return ERROR_SUCCESS;
  8413. }
  8414. VOID
  8415. RcsInitKnownReplicaSetMembers(
  8416. IN PCOMMAND_PACKET Cmd
  8417. )
  8418. /*++
  8419. Routine Description:
  8420. Wait for the database to be initialized and then take the
  8421. replicas that were retrieved from the database and put them
  8422. into the table that the replica control command server
  8423. uses. Open the replicas. The journal will be started when
  8424. a replica successfully joins with an outbound partner.
  8425. Arguments:
  8426. Cmd
  8427. Return Value:
  8428. winerror
  8429. --*/
  8430. {
  8431. #undef DEBSUB
  8432. #define DEBSUB "RcsInitKnownReplicaSetMembers:"
  8433. FILETIME FileTime;
  8434. ULONGLONG Now;
  8435. GUID Record0Guid;
  8436. PREPLICA Replica, NextReplica;
  8437. PVOID Key;
  8438. ULONG RootLen;
  8439. //
  8440. // Time in 100nsec tics since Jan 1, 1601
  8441. //
  8442. GetSystemTimeAsFileTime(&FileTime);
  8443. COPY_TIME(&Now, &FileTime);
  8444. //
  8445. // A non-empty table implies multiple calls to this
  8446. // routine our an out-of-sequence call to this routine.
  8447. //
  8448. FRS_ASSERT(GTabNumberInTable(ReplicasByGuid) == 0);
  8449. FRS_ASSERT(GTabNumberInTable(ReplicasByNumber) == 0);
  8450. //
  8451. // Wait for the database, journal, and comm subsystem to start up
  8452. //
  8453. WaitForSingleObject(CommEvent, INFINITE);
  8454. WaitForSingleObject(DataBaseEvent, INFINITE);
  8455. WaitForSingleObject(JournalEvent, INFINITE);
  8456. WaitForSingleObject(ChgOrdEvent, INFINITE);
  8457. if (FrsIsShuttingDown) {
  8458. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  8459. return;
  8460. }
  8461. //
  8462. // Delete the contents of the Replica Set key in the registry
  8463. // and refresh with the current info in the database.
  8464. //
  8465. RcsReplicaClearRegistry();
  8466. //
  8467. // The database built a list of replicas. Insert them into the tables
  8468. //
  8469. ForEachListEntry(&ReplicaListHead, REPLICA, ReplicaList,
  8470. // loop iterator pE is of type REPLICA
  8471. //
  8472. // Replica was opened as part of the database initialization
  8473. //
  8474. pE->IsOpen = TRUE;
  8475. REPLICA_STATE_TRACE(3, Cmd, pE, pE->IsOpen, "B, Replica opened");
  8476. //
  8477. // The timeout for the deleted replica has expired; attempt to
  8478. // delete the replica from the database. The delete will be
  8479. // retried at the next startup if this delete fails. In any case,
  8480. // the replica does not show up in the active set of replicas
  8481. // and so is ignored by all further processing except for shutdown.
  8482. //
  8483. if (RcsReplicaIsRestored(pE) ||
  8484. (!IS_TIME_ZERO(pE->MembershipExpires) && pE->MembershipExpires < Now)) {
  8485. GTabInsertEntry(DeletedReplicas, pE, pE->ReplicaName->Guid, NULL);
  8486. continue;
  8487. }
  8488. //
  8489. // Insert replica information into the registry
  8490. //
  8491. RcsReplicaSetRegistry(pE);
  8492. //
  8493. // Create a queue
  8494. //
  8495. pE->Queue = FrsAlloc(sizeof(FRS_QUEUE));
  8496. FrsInitializeQueue(pE->Queue, &ReplicaCmdServer.Control);
  8497. REPLICA_STATE_TRACE(3, Cmd, pE, 0, "F, Replica added to GUID table");
  8498. //
  8499. // Table by guid
  8500. //
  8501. GTabInsertEntry(ReplicasByGuid, pE, pE->ReplicaName->Guid, NULL);
  8502. //
  8503. // Add ReplicaSet Instance to the registry
  8504. //
  8505. if (pE->Root != NULL) {
  8506. DPRINT(5, ":S: PERFMON:Adding Set:REPLICA.C:2\n");
  8507. AddPerfmonInstance(REPLICASET, pE->PerfRepSetData, pE->Root);
  8508. }
  8509. //
  8510. // Table by number
  8511. //
  8512. GTabInsertEntry(ReplicasByNumber, pE, &pE->ReplicaNumber, NULL);
  8513. );
  8514. //
  8515. // Now account for the replica sets that are on the fault list.
  8516. //
  8517. ForEachListEntry(&ReplicaFaultListHead, REPLICA, ReplicaList,
  8518. // loop iterator pE is of type REPLICA
  8519. //
  8520. // Replica was opened as part of the database initialization
  8521. //
  8522. pE->IsOpen = FALSE;
  8523. REPLICA_STATE_TRACE(3, Cmd, pE, pE->IsOpen, "B, Replica not opened");
  8524. //
  8525. // The timeout for the deleted replica has expired; attempt to
  8526. // delete the replica from the database. The delete will be
  8527. // retried at the next startup if this delete fails. In any case,
  8528. // the replica does not show up in the active set of replicas
  8529. // and so is ignored by all further processing except for shutdown.
  8530. //
  8531. if (RcsReplicaIsRestored(pE) ||
  8532. (!IS_TIME_ZERO(pE->MembershipExpires) && pE->MembershipExpires < Now)) {
  8533. GTabInsertEntry(DeletedReplicas, pE, pE->ReplicaName->Guid, NULL);
  8534. continue;
  8535. }
  8536. //
  8537. // Insert replica information into the registry
  8538. //
  8539. RcsReplicaSetRegistry(pE);
  8540. //
  8541. // Create a queue
  8542. //
  8543. pE->Queue = FrsAlloc(sizeof(FRS_QUEUE));
  8544. FrsInitializeQueue(pE->Queue, &ReplicaCmdServer.Control);
  8545. REPLICA_STATE_TRACE(3, Cmd, pE, 0, "F, Replica added to GUID table");
  8546. //
  8547. // Table by guid
  8548. //
  8549. GTabInsertEntry(ReplicasByGuid, pE, pE->ReplicaName->Guid, NULL);
  8550. //
  8551. // Table by number
  8552. //
  8553. GTabInsertEntry(ReplicasByNumber, pE, &pE->ReplicaNumber, NULL);
  8554. );
  8555. //
  8556. // Set the registry value "FilesNotToBackup"
  8557. //
  8558. CfgFilesNotToBackup(ReplicasByGuid);
  8559. //
  8560. // Close the expired replica sets
  8561. //
  8562. Key = NULL;
  8563. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  8564. if (!IS_TIME_ZERO(Replica->MembershipExpires)) {
  8565. //
  8566. // Close replica is OK here as long as the Journal has not been started
  8567. // on this replica set.
  8568. //
  8569. RcsCloseReplicaSetmember(Replica);
  8570. RcsCloseReplicaCxtions(Replica);
  8571. }
  8572. }
  8573. //
  8574. // Delete the replica sets with expired tombstones
  8575. //
  8576. Key = NULL;
  8577. for (Replica = GTabNextDatum(DeletedReplicas, &Key);
  8578. Replica;
  8579. Replica = NextReplica) {
  8580. NextReplica = GTabNextDatum(DeletedReplicas, &Key);
  8581. //
  8582. // Replica number 0 is reserved for the template tables in post
  8583. // WIN2K but Databases built with Win2K can still use replica
  8584. // number 0.
  8585. //
  8586. // Record 0 contains the DB templates. Don't delete it but
  8587. // change its fields so that it won't interfere with the
  8588. // creation of other replica set.
  8589. // Note: New databases will not use replica number zero but old
  8590. // databases will. To avoid name conflicts with replica sets
  8591. // created in the future we still need to overwrite a few
  8592. // fields in config record zero.
  8593. //
  8594. if (Replica->ReplicaNumber == DBS_TEMPLATE_TABLE_NUMBER) {
  8595. if (WSTR_NE(Replica->ReplicaName->Name, NTFRS_RECORD_0)) {
  8596. //
  8597. // Pull the entry out of the table since we are changing the
  8598. // replica guid below. (makes the saved guid ptr in the entry
  8599. // invalid and can lead to access violation).
  8600. //
  8601. GTabDelete(DeletedReplicas, Replica->ReplicaName->Guid, NULL, NULL);
  8602. FrsUuidCreate(&Record0Guid);
  8603. //
  8604. // ReplicaName
  8605. //
  8606. FrsFreeGName(Replica->ReplicaName);
  8607. Replica->ReplicaName = FrsBuildGName(FrsDupGuid(&Record0Guid),
  8608. FrsWcsDup(NTFRS_RECORD_0));
  8609. //
  8610. // MemberName
  8611. //
  8612. FrsFreeGName(Replica->MemberName);
  8613. Replica->MemberName = FrsBuildGName(FrsDupGuid(&Record0Guid),
  8614. FrsWcsDup(NTFRS_RECORD_0));
  8615. //
  8616. // SetName
  8617. //
  8618. FrsFreeGName(Replica->SetName);
  8619. Replica->SetName = FrsBuildGName(FrsDupGuid(&Record0Guid),
  8620. FrsWcsDup(NTFRS_RECORD_0));
  8621. //
  8622. // SetType
  8623. //
  8624. Replica->ReplicaSetType = FRS_RSTYPE_OTHER;
  8625. //
  8626. // Root (to avoid failing a replica create because of
  8627. // overlapping roots)
  8628. //
  8629. FrsFree(Replica->Root);
  8630. Replica->Root = FrsWcsDup(NTFRS_RECORD_0_ROOT);
  8631. //
  8632. // Stage (to avoid failing a replica create because of
  8633. // overlapping Stages)
  8634. //
  8635. FrsFree(Replica->Stage);
  8636. Replica->Stage = FrsWcsDup(NTFRS_RECORD_0_STAGE);
  8637. //
  8638. // Update
  8639. //
  8640. Replica->NeedsUpdate = TRUE;
  8641. RcsUpdateReplicaSetMember(Replica);
  8642. //
  8643. // The above friggen call set NeedsUpdate to false if the update succeeded.
  8644. //
  8645. if (Replica->NeedsUpdate) {
  8646. DPRINT(0, ":S: ERROR - Can't update record 0.\n");
  8647. }
  8648. //
  8649. // Insert the entry back into the table with the new Guid index.
  8650. //
  8651. GTabInsertEntry(DeletedReplicas,
  8652. Replica,
  8653. Replica->ReplicaName->Guid,
  8654. NULL);
  8655. }
  8656. RcsCloseReplicaSetmember(Replica);
  8657. RcsCloseReplicaCxtions(Replica);
  8658. } else {
  8659. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, Deleting Tombstoned replica");
  8660. //
  8661. // Close replica is OK here as long as the Journal has not
  8662. // been started on this replica set.
  8663. //
  8664. RcsCloseReplicaSetmember(Replica);
  8665. RcsCloseReplicaCxtions(Replica);
  8666. RcsDeleteReplicaFromDb(Replica);
  8667. }
  8668. }
  8669. SetEvent(ReplicaEvent);
  8670. //
  8671. // Check the schedules every so often
  8672. //
  8673. Cmd->Command = CMD_CHECK_SCHEDULES;
  8674. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  8675. //
  8676. // Free up memory by reducing our working set size
  8677. //
  8678. SetProcessWorkingSetSize(ProcessHandle, (SIZE_T)-1, (SIZE_T)-1);
  8679. }
  8680. DWORD
  8681. RcsExitThread(
  8682. PFRS_THREAD FrsThread
  8683. )
  8684. /*++
  8685. Routine Description:
  8686. Immediate cancel of all outstanding RPC calls for the thread
  8687. identified by FrsThread. Set the tombstone to 5 seconds from
  8688. now. If this thread does not exit within that time, any calls
  8689. to ThSupWaitThread() will return a timeout error.
  8690. Arguments:
  8691. FrsThread
  8692. Return Value:
  8693. ERROR_SUCCESS
  8694. --*/
  8695. {
  8696. #undef DEBSUB
  8697. #define DEBSUB "RcsExitThread:"
  8698. ULONG WStatus;
  8699. if (HANDLE_IS_VALID(FrsThread->Handle)) {
  8700. DPRINT1(4, ":S: Canceling RPC requests for thread %ws\n", FrsThread->Name);
  8701. WStatus = RpcCancelThread(FrsThread->Handle);
  8702. if (!RPC_SUCCESS(WStatus)) {
  8703. DPRINT_WS(0, ":S: RpcCancelThread failed.", WStatus);
  8704. }
  8705. }
  8706. return ThSupExitWithTombstone(FrsThread);
  8707. }
  8708. #if _MSC_FULL_VER >= 13008827
  8709. #pragma warning(push)
  8710. #pragma warning(disable:4715) // Not all control paths return (due to infinite loop)
  8711. #endif
  8712. DWORD
  8713. RcsMain(
  8714. PVOID Arg
  8715. )
  8716. /*++
  8717. Routine Description:
  8718. Entry point for replica control command server thread
  8719. Arguments:
  8720. Arg - thread
  8721. Return Value:
  8722. None.
  8723. --*/
  8724. {
  8725. #undef DEBSUB
  8726. #define DEBSUB "RcsMain:"
  8727. PCOMMAND_PACKET Cmd;
  8728. PCOMMAND_SERVER Cs;
  8729. PFRS_QUEUE IdledQueue;
  8730. ULONG Status;
  8731. PFRS_THREAD FrsThread = (PFRS_THREAD)Arg;
  8732. DWORD WStatus = ERROR_SUCCESS;
  8733. //
  8734. // Try-Finally
  8735. //
  8736. try {
  8737. //
  8738. // Capture exception.
  8739. //
  8740. try {
  8741. FRS_ASSERT(FrsThread->Data == &ReplicaCmdServer);
  8742. //
  8743. // Immediate cancel of outstanding RPC calls during shutdown
  8744. //
  8745. WStatus = RpcMgmtSetCancelTimeout(0);
  8746. DPRINT_WS(0, "Timeout cancel failed.", WStatus);
  8747. FrsThread->Exit = RcsExitThread;
  8748. cant_exit_yet:
  8749. //
  8750. // Replica Control Command Server
  8751. // Controls access to the database entries
  8752. //
  8753. while (Cmd = FrsGetCommandServerIdled(&ReplicaCmdServer, &IdledQueue)) {
  8754. switch (Cmd->Command) {
  8755. //
  8756. // INITIALIZATION, STARTUP, AND CONFIGURATION
  8757. //
  8758. case CMD_INIT_SUBSYSTEM:
  8759. DPRINT(0, ":S: Replica subsystem is starting.\n");
  8760. DPRINT1(4, ":S: Command init subsystem %08x\n", Cmd);
  8761. RcsInitKnownReplicaSetMembers(Cmd);
  8762. if (!FrsIsShuttingDown) {
  8763. DPRINT(0, ":S: Replica subsystem has started.\n");
  8764. }
  8765. break;
  8766. case CMD_CHECK_SCHEDULES:
  8767. RcsCheckSchedules(Cmd);
  8768. break;
  8769. case CMD_START_REPLICAS:
  8770. RcsStartValidReplicaSetMembers(Cmd);
  8771. break;
  8772. case CMD_START:
  8773. RcsStartReplicaSetMember(Cmd);
  8774. break;
  8775. case CMD_DELETE:
  8776. RcsDeleteReplicaSetMember(Cmd);
  8777. break;
  8778. case CMD_DELETE_RETRY:
  8779. RcsDeleteReplicaRetry(Cmd);
  8780. break;
  8781. case CMD_DELETE_NOW:
  8782. RcsDeleteReplicaSetMemberNow(Cmd);
  8783. break;
  8784. //
  8785. // CHANGE ORDERS
  8786. //
  8787. case CMD_LOCAL_CO_ACCEPTED:
  8788. RcsLocalCoAccepted(Cmd);
  8789. break;
  8790. case CMD_REMOTE_CO:
  8791. RcsRemoteCoReceived(Cmd);
  8792. break;
  8793. case CMD_REMOTE_CO_ACCEPTED:
  8794. RcsRemoteCoAccepted(Cmd);
  8795. break;
  8796. case CMD_SEND_STAGE:
  8797. RcsSendStageFile(Cmd);
  8798. break;
  8799. case CMD_SENDING_STAGE:
  8800. RcsSendingStageFile(Cmd);
  8801. break;
  8802. case CMD_RECEIVING_STAGE:
  8803. RcsReceivingStageFile(Cmd);
  8804. break;
  8805. case CMD_CREATED_EXISTING:
  8806. RcsSendStageFileRequest(Cmd);
  8807. break;
  8808. case CMD_RECEIVED_STAGE:
  8809. RcsReceivedStageFile(Cmd, CHECK_CXTION_AUTH);
  8810. break;
  8811. case CMD_REMOTE_CO_DONE:
  8812. RcsRemoteCoDoneRvcd(Cmd);
  8813. break;
  8814. case CMD_SEND_ABORT_FETCH:
  8815. RcsSendAbortFetch(Cmd);
  8816. break;
  8817. case CMD_ABORT_FETCH:
  8818. RcsAbortFetch(Cmd);
  8819. break;
  8820. case CMD_SEND_RETRY_FETCH:
  8821. RcsSendRetryFetch(Cmd);
  8822. break;
  8823. case CMD_RETRY_STAGE:
  8824. RcsRetryStageFileCreate(Cmd);
  8825. break;
  8826. case CMD_RETRY_FETCH:
  8827. RcsRetryFetch(Cmd);
  8828. break;
  8829. //
  8830. // JOINING
  8831. //
  8832. case CMD_NEED_JOIN:
  8833. RcsNeedJoin(Cmd);
  8834. break;
  8835. case CMD_START_JOIN:
  8836. RcsStartJoin(Cmd);
  8837. break;
  8838. case CMD_JOIN_CXTION:
  8839. RcsJoinCxtion(Cmd);
  8840. break;
  8841. case CMD_JOINING_AFTER_FLUSH:
  8842. RcsJoiningAfterFlush(Cmd);
  8843. break;
  8844. case CMD_JOINING:
  8845. RcsJoining(Cmd);
  8846. break;
  8847. case CMD_JOINED:
  8848. RcsInboundJoined(Cmd);
  8849. break;
  8850. case CMD_UNJOIN:
  8851. RcsUnJoinCxtion(Cmd, FALSE);
  8852. break;
  8853. case CMD_UNJOIN_REMOTE:
  8854. RcsUnJoinCxtion(Cmd, TRUE);
  8855. break;
  8856. case CMD_HUNG_CXTION:
  8857. RcsHungCxtion(Cmd);
  8858. break;
  8859. //
  8860. // VVJOIN
  8861. //
  8862. case CMD_VVJOIN_SUCCESS:
  8863. RcsVvJoinSuccess(Cmd);
  8864. break;
  8865. case CMD_VVJOIN_DONE:
  8866. RcsVvJoinDone(Cmd);
  8867. break;
  8868. case CMD_VVJOIN_DONE_UNJOIN:
  8869. RcsVvJoinDoneUnJoin(Cmd);
  8870. break;
  8871. case CMD_CHECK_PROMOTION:
  8872. RcsCheckPromotion(Cmd);
  8873. break;
  8874. default:
  8875. DPRINT1(0, "Replica Control: unknown command 0x%x\n", Cmd->Command);
  8876. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  8877. break;
  8878. }
  8879. FrsRtlUnIdledQueue(IdledQueue);
  8880. }
  8881. //
  8882. // Exit
  8883. //
  8884. FrsExitCommandServer(&ReplicaCmdServer, FrsThread);
  8885. goto cant_exit_yet;
  8886. //
  8887. // Get exception status.
  8888. //
  8889. } except (EXCEPTION_EXECUTE_HANDLER) {
  8890. GET_EXCEPTION_CODE(WStatus);
  8891. }
  8892. } finally {
  8893. if (WIN_SUCCESS(WStatus)) {
  8894. if (AbnormalTermination()) {
  8895. WStatus = ERROR_OPERATION_ABORTED;
  8896. }
  8897. }
  8898. DPRINT_WS(0, "RcsMain finally.", WStatus);
  8899. //
  8900. // Trigger FRS shutdown if we terminated abnormally.
  8901. //
  8902. if (!WIN_SUCCESS(WStatus) && (WStatus != ERROR_PROCESS_ABORTED)) {
  8903. DPRINT(0, "RcsMain terminated abnormally, forcing service shutdown.\n");
  8904. FrsIsShuttingDown = TRUE;
  8905. SetEvent(ShutDownEvent);
  8906. } else {
  8907. WStatus = ERROR_SUCCESS;
  8908. }
  8909. }
  8910. return WStatus;
  8911. }
  8912. #if _MSC_FULL_VER >= 13008827
  8913. #pragma warning(pop)
  8914. #endif
  8915. VOID
  8916. RcsInitializeReplicaCmdServer(
  8917. VOID
  8918. )
  8919. /*++
  8920. Routine Description:
  8921. Initialize the replica set command server and idle it until the
  8922. database is initialized.
  8923. Arguments:
  8924. None.
  8925. Return Value:
  8926. None.
  8927. --*/
  8928. {
  8929. #undef DEBSUB
  8930. #define DEBSUB "RcsInitializeReplicaCmdServer:"
  8931. ULONG Status;
  8932. PCOMMAND_PACKET Cmd;
  8933. DWORD MaxRepThreads;
  8934. //
  8935. // Retry a join every MinJoinRetry milliseconds, doubling the interval
  8936. // every retry. Stop retrying when the interval is greater than
  8937. // MaxJoinRetry.
  8938. //
  8939. CfgRegReadDWord(FKC_MIN_JOIN_RETRY, NULL, 0, &MinJoinRetry);
  8940. DPRINT1(0, ":S: Min Join Retry : %d\n", MinJoinRetry);
  8941. CfgRegReadDWord(FKC_MAX_JOIN_RETRY, NULL, 0, &MaxJoinRetry);
  8942. DPRINT1(0, ":S: Max Join Retry : %d\n", MaxJoinRetry);
  8943. //
  8944. // The replica command server services commands for configuration changes
  8945. // and REPLICATION.
  8946. //
  8947. CfgRegReadDWord(FKC_MAX_REPLICA_THREADS, NULL, 0, &MaxRepThreads);
  8948. DPRINT1(0, ":S: Max Replica Threads : %d\n", MaxRepThreads);
  8949. //
  8950. // Start replication even if the DS could not be accessed
  8951. //
  8952. CfgRegReadDWord(FKC_REPLICA_START_TIMEOUT, NULL, 0, &ReplicaStartTimeout);
  8953. DPRINT1(0, ":S: Replica Start Timeout: %d\n", ReplicaStartTimeout);
  8954. //
  8955. // Partners are not allowed to join if their clocks are out-of-sync
  8956. //
  8957. CfgRegReadDWord(FKC_PARTNER_CLOCK_SKEW, NULL, 0, &PartnerClockSkew);
  8958. DPRINT1(0, ":S: Partner Clock Skew : %d\n", PartnerClockSkew);
  8959. MaxPartnerClockSkew = (ULONGLONG)PartnerClockSkew *
  8960. CONVERT_FILETIME_TO_MINUTES;
  8961. //
  8962. // Replica tombstone in days
  8963. //
  8964. CfgRegReadDWord(FKC_REPLICA_TOMBSTONE, NULL, 0, &ReplicaTombstone);
  8965. DPRINT1(0, ":S: Replica Tombstone : %d\n", ReplicaTombstone);
  8966. ReplicaTombstoneInFileTime = (ULONGLONG)ReplicaTombstone *
  8967. CONVERT_FILETIME_TO_DAYS;
  8968. //
  8969. // Start the Replica command server
  8970. //
  8971. FrsInitializeCommandServer(&ReplicaCmdServer, MaxRepThreads, L"ReplicaCs", RcsMain);
  8972. //
  8973. // Empty table of replicas. Existing replicas will be filled in after
  8974. // the database has started up.
  8975. //
  8976. DeletedReplicas = GTabAllocTable();
  8977. DeletedCxtions = GTabAllocTable();
  8978. ReplicasByNumber = GTabAllocNumberTable();
  8979. //
  8980. // Tell the replica command server to init.
  8981. //
  8982. Cmd = FrsAllocCommand(&ReplicaCmdServer.Queue, CMD_INIT_SUBSYSTEM);
  8983. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  8984. //
  8985. // The DS may have changed while the service was down. In fact, the
  8986. // service may have been down because the DS was being changed. The
  8987. // current state of the configuration in the DS should be merged
  8988. // with the state in the database before replication begins. But
  8989. // the DS may not be reachable. We don't want to delay replication
  8990. // in the off chance that the DS changed, but we do want to pick
  8991. // up any changes before replication begins. Our compromise is to
  8992. // allow a few minutes for the DS to come online and then start
  8993. // replication anyway.
  8994. //
  8995. if (ReplicaStartTimeout) {
  8996. Cmd = FrsAllocCommand(&ReplicaCmdServer.Queue, CMD_START_REPLICAS);
  8997. FrsDelCsSubmitSubmit(&ReplicaCmdServer, Cmd, ReplicaStartTimeout);
  8998. }
  8999. }
  9000. VOID
  9001. RcsFrsUnInitializeReplicaCmdServer(
  9002. VOID
  9003. )
  9004. /*++
  9005. Routine Description:
  9006. Free up the RCS memory.
  9007. Arguments:
  9008. None.
  9009. Return Value:
  9010. None.
  9011. --*/
  9012. {
  9013. #undef DEBSUB
  9014. #define DEBSUB "RcsFrsUnInitializeReplicaCmdServer:"
  9015. GTabFreeTable(ReplicasByNumber, NULL);
  9016. GTabFreeTable(ReplicasByGuid, FrsFreeType);
  9017. GTabFreeTable(DeletedReplicas, FrsFreeType);
  9018. GTabFreeTable(DeletedCxtions, FrsFreeType);
  9019. }
  9020. VOID
  9021. RcsShutDownReplicaCmdServer(
  9022. VOID
  9023. )
  9024. /*++
  9025. Routine Description:
  9026. Abort the replica control command server
  9027. Arguments:
  9028. None.
  9029. Return Value:
  9030. None.
  9031. --*/
  9032. {
  9033. #undef DEBSUB
  9034. #define DEBSUB "RcsShutDownReplicaCmdServer:"
  9035. PVOID Key;
  9036. PVOID SubKey;
  9037. PREPLICA Replica;
  9038. PCXTION Cxtion;
  9039. //
  9040. // Rundown all known queues. New queue entries will bounce.
  9041. //
  9042. Key = NULL;
  9043. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  9044. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Rundown replica cmd srv");
  9045. FrsRunDownCommandServer(&ReplicaCmdServer, Replica->Queue);
  9046. SubKey = NULL;
  9047. while (Cxtion = GTabNextDatum(Replica->Cxtions, &SubKey)) {
  9048. if (Cxtion->VvJoinCs) {
  9049. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Rundown replica VVJoin srv");
  9050. FrsRunDownCommandServer(Cxtion->VvJoinCs, &Cxtion->VvJoinCs->Queue);
  9051. }
  9052. }
  9053. }
  9054. FrsRunDownCommandServer(&ReplicaCmdServer, &ReplicaCmdServer.Queue);
  9055. }
  9056. VOID
  9057. RcsCmdPktCompletionRoutine(
  9058. IN PCOMMAND_PACKET Cmd,
  9059. IN PVOID Arg
  9060. )
  9061. /*++
  9062. Routine Description:
  9063. Completion routine for Replica. Free the replica set info
  9064. and send the command on to the generic command packet
  9065. completion routine for freeing.
  9066. Arguments:
  9067. Cmd
  9068. Arg - Cmd->CompletionArg
  9069. Return Value:
  9070. None.
  9071. --*/
  9072. {
  9073. #undef DEBSUB
  9074. #define DEBSUB "RcsCmdPktCompletionRoutine:"
  9075. PCHANGE_ORDER_ENTRY Coe;
  9076. DPRINT1(5, "Replica completion %08x\n", Cmd);
  9077. //
  9078. // To preserve order among change orders all subsequent change orders
  9079. // from this connection are going to the Inbound log (as a consequence
  9080. // of the Unjoin below). We will retry them later when the connection
  9081. // is restarted.
  9082. //
  9083. if (RsCoe(Cmd)) {
  9084. Coe = RsCoe(Cmd);
  9085. RsCoe(Cmd) = NULL;
  9086. //
  9087. // Unjoin if possible
  9088. // The unjoin will fail if there isn't a cxtion or
  9089. // the join guid is out-of-date. Which is what we
  9090. // want -- we don't want a lot of unjoins flooding
  9091. // the replica queue and wrecking havoc with future
  9092. // joins.
  9093. //
  9094. // WARN: Must happen before the call to ChgOrdInboundRetry below.
  9095. //
  9096. if (RsReplica(Cmd)) {
  9097. CHANGE_ORDER_TRACE(3, Coe, "Retry/Unjoin");
  9098. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  9099. Cmd = NULL;
  9100. }
  9101. //
  9102. // Retry the change order. This must happen *AFTER* issueing
  9103. // the unjoin above so that any change orders kicked loose by
  9104. // the following retry will be pushed into the retry path because
  9105. // their join guid will be invalidated during the unjoin.
  9106. //
  9107. SET_COE_FLAG(Coe, COE_FLAG_NO_INBOUND);
  9108. if (CO_STATE_IS_LE(Coe, IBCO_STAGING_RETRY)) {
  9109. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to staging retry");
  9110. ChgOrdInboundRetry(Coe, IBCO_STAGING_RETRY);
  9111. } else
  9112. if (CO_STATE_IS_LE(Coe, IBCO_FETCH_RETRY)) {
  9113. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to fetch retry");
  9114. ChgOrdInboundRetry(Coe, IBCO_FETCH_RETRY);
  9115. } else
  9116. if (CO_STATE_IS_LE(Coe, IBCO_INSTALL_RETRY)) {
  9117. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to install retry");
  9118. ChgOrdInboundRetry(Coe, IBCO_INSTALL_RETRY);
  9119. } else {
  9120. CHANGE_ORDER_TRACE(3, Coe, "Submit CO to retry");
  9121. ChgOrdInboundRetry(Coe, CO_STATE(Coe));
  9122. }
  9123. //
  9124. // Command was transfered to the replica command server for unjoin
  9125. //
  9126. if (!Cmd) {
  9127. return;
  9128. }
  9129. }
  9130. //
  9131. // The originator owns the disposition of this command packet
  9132. //
  9133. if (HANDLE_IS_VALID(RsCompletionEvent(Cmd))) {
  9134. SetEvent(RsCompletionEvent(Cmd));
  9135. return;
  9136. }
  9137. //
  9138. // Free up the "address" portion of the command
  9139. //
  9140. FrsFreeGName(RsTo(Cmd));
  9141. FrsFreeGName(RsFrom(Cmd));
  9142. FrsFreeGName(RsReplicaName(Cmd));
  9143. FrsFreeGName(RsCxtion(Cmd));
  9144. FrsFree(RsBlock(Cmd));
  9145. FrsFree(RsGVsn(Cmd));
  9146. FrsFree(RsCoGuid(Cmd));
  9147. FrsFree(RsJoinGuid(Cmd));
  9148. FrsFree(RsJoinTime(Cmd));
  9149. FrsFree(RsCommPktRcvTime(Cmd));
  9150. FrsFree(RsReplicaVersionGuid(Cmd));
  9151. //
  9152. // Free the copy of our partner's change order command and the data extension.
  9153. //
  9154. if (RsPartnerCoc(Cmd) != NULL) {
  9155. FrsFree(RsPartnerCocExt(Cmd));
  9156. FrsFree(RsPartnerCoc(Cmd));
  9157. }
  9158. //
  9159. // a replica (never free the RsReplica(Cmd) field; it addresses
  9160. // an active replica in the Replicas table).
  9161. //
  9162. FrsFreeType(RsNewReplica(Cmd));
  9163. //
  9164. // Seeding cxtion
  9165. // Delete the connection from the perfmon tables.
  9166. //
  9167. if (RsNewCxtion(Cmd) != NULL) {
  9168. FrsFreeType(RsNewCxtion(Cmd));
  9169. }
  9170. //
  9171. // Free the compression table, if any.
  9172. //
  9173. if (RsCompressionTable(Cmd)) {
  9174. GTabFreeTable(RsCompressionTable(Cmd), FrsFree);
  9175. }
  9176. //
  9177. // Free the version vector, if any
  9178. //
  9179. RsVVector(Cmd) = VVFreeOutbound(RsVVector(Cmd));
  9180. RsReplicaVv(Cmd) = VVFreeOutbound(RsReplicaVv(Cmd));
  9181. //
  9182. // Authentication info
  9183. //
  9184. FrsFree(RsAuthClient(Cmd));
  9185. FrsFree(RsAuthName(Cmd));
  9186. FrsFree(RsAuthSid(Cmd));
  9187. //
  9188. // Md5 Digest
  9189. //
  9190. FrsFree(RsMd5Digest(Cmd));
  9191. //
  9192. // Send the packet on to the generic completion routine for freeing
  9193. //
  9194. FrsSetCompletionRoutine(Cmd, FrsFreeCommand, NULL);
  9195. FrsCompleteCommand(Cmd, Cmd->ErrorStatus);
  9196. }
  9197. VOID
  9198. RcsSubmitTransferToRcs(
  9199. IN PCOMMAND_PACKET Cmd,
  9200. IN USHORT Command
  9201. )
  9202. /*++
  9203. Routine Description:
  9204. Transfer a request to the replica command server
  9205. Arguments:
  9206. Cmd
  9207. Command
  9208. Return Value:
  9209. None.
  9210. --*/
  9211. {
  9212. #undef DEBSUB
  9213. #define DEBSUB "RcsSubmitTransferToRcs:"
  9214. Cmd->TargetQueue = RsReplica(Cmd)->Queue;
  9215. Cmd->Command = Command;
  9216. RsTimeout(Cmd) = 0;
  9217. DPRINT3(5, "Transfer %08x (%08x) to %ws\n",
  9218. Command, Cmd, RsReplica(Cmd)->SetName->Name);
  9219. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  9220. }
  9221. VOID
  9222. RcsSubmitRemoteCoInstallRetry(
  9223. IN PCHANGE_ORDER_ENTRY Coe
  9224. )
  9225. /*++
  9226. Routine Description:
  9227. Submit a remote change order to retry the file install.
  9228. Arguments:
  9229. Coe - Change order entry.
  9230. Return Value:
  9231. None.
  9232. --*/
  9233. {
  9234. #undef DEBSUB
  9235. #define DEBSUB "RcsSubmitRemoteCoInstallRetry:"
  9236. PCOMMAND_PACKET Cmd;
  9237. PREPLICA Replica;
  9238. Replica = Coe->NewReplica;
  9239. Cmd = FrsAllocCommand(Replica->Queue, 0);
  9240. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  9241. //
  9242. // Address of change order entry
  9243. //
  9244. RsCoe(Cmd) = Coe;
  9245. //
  9246. // Mask out the irrelevant usn reasons
  9247. //
  9248. RsCoc(Cmd)->ContentCmd &= CO_CONTENT_MASK;
  9249. //
  9250. // Guid of the change order entry
  9251. //
  9252. RsCoGuid(Cmd) = FrsDupGuid(&RsCoc(Cmd)->ChangeOrderGuid);
  9253. //
  9254. // Initialize the command packet for eventual transfer to
  9255. // the replica set command server
  9256. //
  9257. RsReplica(Cmd) = Replica;
  9258. //
  9259. // Cxtion's guid (note - we lose the printable name for now)
  9260. //
  9261. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coe->Cmd.CxtionGuid), NULL);
  9262. DPRINT3(5, "Submit %08x (%08x) to %ws\n",
  9263. CMD_REMOTE_CO_ACCEPTED, Cmd, Replica->SetName->Name);
  9264. FrsInstallCsSubmitTransfer(Cmd, CMD_INSTALL_STAGE);
  9265. }
  9266. VOID
  9267. RcsSubmitRemoteCoAccepted(
  9268. IN PCHANGE_ORDER_ENTRY Coe
  9269. )
  9270. /*++
  9271. Routine Description:
  9272. Submit a remote change order to the staging file generator.
  9273. Arguments:
  9274. Co
  9275. Return Value:
  9276. None.
  9277. --*/
  9278. {
  9279. #undef DEBSUB
  9280. #define DEBSUB "RcsSubmitRemoteCoAccepted:"
  9281. PCOMMAND_PACKET Cmd;
  9282. PREPLICA Replica;
  9283. Replica = Coe->NewReplica;
  9284. Cmd = FrsAllocCommand(Replica->Queue, CMD_REMOTE_CO_ACCEPTED);
  9285. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  9286. //
  9287. // Address of change order entry
  9288. //
  9289. RsCoe(Cmd) = Coe;
  9290. //
  9291. // Mask out the irrelevant usn reasons
  9292. //
  9293. RsCoc(Cmd)->ContentCmd &= CO_CONTENT_MASK;
  9294. //
  9295. // Guid of the change order entry
  9296. //
  9297. RsCoGuid(Cmd) = FrsDupGuid(&RsCoc(Cmd)->ChangeOrderGuid);
  9298. //
  9299. // Initialize the command packet for eventual transfer to
  9300. // the replica set command server
  9301. //
  9302. RsReplica(Cmd) = Replica;
  9303. //
  9304. // Cxtion's guid (note - we lose the printable name for now)
  9305. //
  9306. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coe->Cmd.CxtionGuid), NULL);
  9307. //
  9308. // Join guid
  9309. //
  9310. RsJoinGuid(Cmd) = FrsDupGuid(&Coe->JoinGuid);
  9311. DPRINT1(5, "Submit %08x\n", Cmd);
  9312. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  9313. }
  9314. VOID
  9315. RcsSubmitLocalCoAccepted(
  9316. IN PCHANGE_ORDER_ENTRY Coe
  9317. )
  9318. /*++
  9319. Routine Description:
  9320. Submit a local change order to the staging file generator.
  9321. Arguments:
  9322. Coe
  9323. Return Value:
  9324. None.
  9325. --*/
  9326. {
  9327. #undef DEBSUB
  9328. #define DEBSUB "RcsSubmitLocalCoAccepted:"
  9329. PCOMMAND_PACKET Cmd;
  9330. PREPLICA Replica;
  9331. //
  9332. // NewReplica?
  9333. //
  9334. Replica = Coe->NewReplica;
  9335. Cmd = FrsAllocCommand(Replica->Queue, CMD_LOCAL_CO_ACCEPTED);
  9336. FrsSetCompletionRoutine(Cmd, RcsCmdPktCompletionRoutine, NULL);
  9337. //
  9338. // Address of the change order entry
  9339. //
  9340. RsCoe(Cmd) = Coe;
  9341. //
  9342. // Mask out the irrelevant usn reasons
  9343. //
  9344. RsCoc(Cmd)->ContentCmd &= CO_CONTENT_MASK;
  9345. //
  9346. // Guid of the change order entry
  9347. //
  9348. RsCoGuid(Cmd) = FrsDupGuid(&RsCoc(Cmd)->ChangeOrderGuid);
  9349. //
  9350. // Initialize the command packet for eventual transfer to
  9351. // the replica set command server
  9352. //
  9353. RsReplica(Cmd) = Replica;
  9354. //
  9355. // Cxtion's guid (note - we lose the printable name for now)
  9356. //
  9357. RsCxtion(Cmd) = FrsBuildGName(FrsDupGuid(&Coe->Cmd.CxtionGuid), NULL);
  9358. DPRINT1(5, "Submit %08x\n", Cmd);
  9359. FrsSubmitCommandServer(&ReplicaCmdServer, Cmd);
  9360. }
  9361. ULONG
  9362. RcsSubmitCommPktWithErrorToRcs(
  9363. IN PCOMM_PACKET CommPkt
  9364. )
  9365. /*++
  9366. Routine Description:
  9367. A comm packet could not be sent because of an error. If the
  9368. comm packet was for a joined cxtion then the affected
  9369. replica\cxtion is unjoined.
  9370. Arguments:
  9371. CommPkt - Comm packet that couldn't be sent
  9372. Return Value:
  9373. Error status to be propagated to the sender
  9374. --*/
  9375. {
  9376. #undef DEBSUB
  9377. #define DEBSUB "RcsSubmitCommPktWithErrorToRcs:"
  9378. PCOMMAND_PACKET Cmd;
  9379. PREPLICA Replica;
  9380. PGNAME TmpGName;
  9381. //
  9382. // Convert the comm packet into a command packet
  9383. //
  9384. Cmd = CommPktToCmd(CommPkt);
  9385. FRS_ASSERT(Cmd != NULL);
  9386. FRS_ASSERT(RsTo(Cmd));
  9387. FRS_ASSERT(RsFrom(Cmd));
  9388. FRS_ASSERT(RsReplicaName(Cmd));
  9389. //
  9390. // Rebuild the replica name to address the originating, or local, replica
  9391. //
  9392. TmpGName = RsReplicaName(Cmd);
  9393. RsReplicaName(Cmd) = FrsBuildGName(FrsDupGuid(RsFrom(Cmd)->Guid),
  9394. FrsWcsDup(RsReplicaName(Cmd)->Name));
  9395. FrsFreeGName(TmpGName);
  9396. //
  9397. // Adjust the "to" and "from" addresses
  9398. //
  9399. TmpGName = RsTo(Cmd);
  9400. RsTo(Cmd) = RsFrom(Cmd);
  9401. RsFrom(Cmd) = TmpGName;
  9402. //
  9403. // Find the target replica
  9404. //
  9405. Replica = GTabLookup(ReplicasByGuid, RsReplicaName(Cmd)->Guid, NULL);
  9406. if (Replica == NULL) {
  9407. DPRINT1(4, ":S: WARN - Submit comm pkt w/error: Replica not found: %ws\n",
  9408. RsReplicaName(Cmd)->Name);
  9409. FrsCompleteCommand(Cmd, ERROR_FILE_NOT_FOUND);
  9410. return ERROR_FILE_NOT_FOUND;
  9411. }
  9412. RsReplica(Cmd) = Replica;
  9413. //
  9414. // The target replica may not be accepting comm packets. The
  9415. // target replica will reset itself before accepting
  9416. // commpkts again.
  9417. //
  9418. if (!Replica->IsAccepting) {
  9419. DPRINT1(4, ":S: WARN - Submit comm pkt w/error: Replica is not accepting: %ws\n",
  9420. Replica->ReplicaName->Name);
  9421. FrsCompleteCommand(Cmd, ERROR_RETRY);
  9422. return ERROR_RETRY;
  9423. }
  9424. switch (Cmd->Command) {
  9425. //
  9426. // NEVER SENT VIA A COMM PKT
  9427. //
  9428. case CMD_INIT_SUBSYSTEM:
  9429. case CMD_CHECK_SCHEDULES:
  9430. case CMD_START_REPLICAS:
  9431. // case CMD_STOP:
  9432. case CMD_START:
  9433. case CMD_DELETE:
  9434. case CMD_DELETE_NOW:
  9435. case CMD_LOCAL_CO_ACCEPTED:
  9436. case CMD_REMOTE_CO_ACCEPTED:
  9437. case CMD_SENDING_STAGE:
  9438. case CMD_RECEIVED_STAGE:
  9439. case CMD_CREATED_EXISTING:
  9440. case CMD_SEND_ABORT_FETCH:
  9441. case CMD_SEND_RETRY_FETCH:
  9442. case CMD_JOIN_CXTION:
  9443. case CMD_UNJOIN:
  9444. case CMD_VVJOIN_START:
  9445. case CMD_VVJOIN_SUCCESS:
  9446. case CMD_HUNG_CXTION:
  9447. case CMD_JOINING_AFTER_FLUSH:
  9448. FRS_ASSERT(!"RcsSubmitCommPktWithErrorToRcs: invalid cmd for comm pkt");
  9449. break;
  9450. //
  9451. // There is other retry code in replica.c that will take care of these
  9452. //
  9453. case CMD_UNJOIN_REMOTE:
  9454. case CMD_JOINED:
  9455. case CMD_NEED_JOIN:
  9456. case CMD_START_JOIN:
  9457. DPRINT3(5, ":X: Ignore commpkt with error Command:%08x Cmd:%08x CommPkt:%08x\n",
  9458. Cmd->Command, Cmd, CommPkt);
  9459. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  9460. break;
  9461. //
  9462. // SENT VIA COMM PKT; UNJOIN
  9463. //
  9464. case CMD_JOINING:
  9465. case CMD_REMOTE_CO:
  9466. case CMD_SEND_STAGE:
  9467. case CMD_RECEIVING_STAGE:
  9468. case CMD_REMOTE_CO_DONE:
  9469. case CMD_ABORT_FETCH:
  9470. case CMD_RETRY_FETCH:
  9471. case CMD_VVJOIN_DONE:
  9472. //
  9473. // Put the unjoin command on the replica's queue
  9474. //
  9475. DPRINT3(5, ":X: Submit commpkt with error Command:%08x Cmd:%08x CommPkt:%08x\n",
  9476. Cmd->Command, Cmd, CommPkt);
  9477. RcsSubmitTransferToRcs(Cmd, CMD_UNJOIN);
  9478. break;
  9479. default:
  9480. break;
  9481. }
  9482. return ERROR_SUCCESS;
  9483. }