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.

1451 lines
43 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. frssndcs.c
  5. Abstract:
  6. This command server sends packets over the comm layer.
  7. SndCsInitialize: - Alloc handle table, read reg pars, Create/init SndCs,
  8. Alloc comm queue array, attach comm queues to SndCs
  9. control queue.
  10. SndCsUnInitialize: - Free handle table, delete comm queues.
  11. SndCsShutDown: - Run Down Comm queues, Run down SndCs.
  12. SndCsExit: - Cancel all RPC calls on the FrsThread->Handle.
  13. SndCsAssignCommQueue: - Assign a comm queue to cxtion.
  14. SndCsCreateCxtion: - Create a join Guid for connection, assign comm queue
  15. SndCsDestroyCxtion: - Invalidate cxtion join guid and umbind RPC handle
  16. SndCsUnBindHandles: - Unbind all RPC handles associated with given target server
  17. SndCsCxtionTimeout: - No activity on this connection, request an UNJOIN.
  18. SndCsCheckCxtion: - Check that the join guid is still valid, set the timer if needed.
  19. SndCsDispatchCommError: - Transfer a comm packet to the appropriate command server
  20. for error processing.
  21. SndCsCommTimeout: - Cancel hung RPC send threads and age the RPC handle cache.
  22. SndCsSubmitCommPkt: - Submit comm packet to the Send Cs comm queue for the
  23. target Cxtion.
  24. SndCsSubmitCommPkt2: - Ditto (with arg variation)
  25. SndCsSubmitCmd: - Used for submitting a CMD_JOINING_AFTER_FLUSH to a Send Cs queue.
  26. SndCsMain: - Send command server processing loop. Dispatches requests
  27. off the comm queues.
  28. Author:
  29. Billy J. Fuller 28-May-1997
  30. Environment
  31. User mode winnt
  32. --*/
  33. #include <ntreppch.h>
  34. #pragma hdrstop
  35. #include <frs.h>
  36. #include <perrepsr.h>
  37. //
  38. // Struct for the Send Command Server
  39. // Contains info about the queues and the threads
  40. //
  41. COMMAND_SERVER SndCs;
  42. //
  43. // Comm queues are attached to the SndCs command server above.
  44. // A cxtion is assigned a comm queue when its creates or assigns a join guid
  45. // (session). The cxtion uses that comm queue for as long as the join guid is
  46. // valid. This insures packet order through the comm layer.
  47. //
  48. // Reserve comm queue 0 for join requests to partners whose previous rpc call
  49. // took longer than MinJoinRetry to error off.
  50. //
  51. #define MAX_COMM_QUEUE_NUMBER (32)
  52. FRS_QUEUE CommQueues[MAX_COMM_QUEUE_NUMBER];
  53. DWORD CommQueueRoundRobin = 1;
  54. //
  55. // Cxtion times out if partner response takes too long
  56. //
  57. DWORD CommTimeoutInMilliSeconds; // timeout in msec
  58. ULONGLONG CommTimeoutCheck; // timeout in 100 nsec units
  59. //
  60. // Maximum time to wait for upstream partner to respond to fetch before unjoining
  61. // connection. If the upstream partner is down (server or service) then the connection
  62. // is unjoined after CommTimeoutInMilliSeconds. 10 hours.
  63. //
  64. #define FRS_MAX_FETCH_WAIT_TIME_IN_MINUTES 10 * 60
  65. //
  66. // rpc handle cache.
  67. //
  68. // Each entry contains a connection guid and a list of handles protected by
  69. // a lock. Each comm packet sent to a given connection first tries to get
  70. // previously bound handle from the handle cache, creating a new one if necc.
  71. //
  72. // Note: DAO, I don't understand why this is needed, Mario says RPC already
  73. // allows multiple RPC calls on the same binding handle. Ask Billy.
  74. //
  75. PGEN_TABLE GHandleTable;
  76. VOID
  77. CommCompletionRoutine(
  78. PCOMMAND_PACKET,
  79. PVOID
  80. );
  81. VOID
  82. FrsCreateJoinGuid(
  83. OUT GUID *OutGuid
  84. );
  85. VOID
  86. FrsDelCsCompleteSubmit(
  87. IN PCOMMAND_PACKET DelCmd,
  88. IN ULONG Timeout
  89. );
  90. PFRS_THREAD
  91. ThSupEnumThreads(
  92. PFRS_THREAD FrsThread
  93. );
  94. DWORD
  95. NtFrsApi_Rpc_Bind(
  96. IN PWCHAR MachineName,
  97. OUT PWCHAR *OutPrincName,
  98. OUT handle_t *OutHandle,
  99. OUT ULONG *OutParentAuthLevel
  100. );
  101. VOID
  102. SndCsUnBindHandles(
  103. IN PGNAME To
  104. )
  105. /*++
  106. Routine Description:
  107. Unbind any handles associated with To in preparation for "join".
  108. Arguments:
  109. To
  110. Return Value:
  111. None.
  112. --*/
  113. {
  114. #undef DEBSUB
  115. #define DEBSUB "SndCsUnBindHandles:"
  116. PGHANDLE GHandle;
  117. PHANDLE_LIST HandleList;
  118. DPRINT1(4, "Unbinding all handles for %ws\n", To->Name);
  119. //
  120. // Find the anchor for all of the bound, rpc handles to the server "To"
  121. //
  122. GHandle = GTabLookup(GHandleTable, To->Guid, NULL);
  123. if (GHandle == NULL) {
  124. return;
  125. }
  126. //
  127. // Unbind the handles
  128. //
  129. EnterCriticalSection(&GHandle->Lock);
  130. while (HandleList = GHandle->HandleList) {
  131. GHandle->HandleList = HandleList->Next;
  132. FrsRpcUnBindFromServer(&HandleList->RpcHandle);
  133. FrsFree(HandleList);
  134. }
  135. LeaveCriticalSection(&GHandle->Lock);
  136. }
  137. DWORD
  138. SndCsAssignCommQueue(
  139. VOID
  140. )
  141. /*++
  142. Routine Description:
  143. A cxtion is assigned a comm queue when its creates or assigns a join guid
  144. (session). The cxtion uses that comm queue for as long as the join guid is
  145. valid. This insures packet order through the comm layer. Old packets have
  146. an invalid join guid and are either not sent or ignored on the receiving side.
  147. Reserve comm queue 0 for join requests to partners whose previous rpc call
  148. took longer than MinJoinRetry to error off.
  149. Arguments:
  150. None.
  151. Return Value:
  152. Comm queue number (1 .. MAX_COMM_QUEUE_NUMBER - 1).
  153. --*/
  154. {
  155. #undef DEBSUB
  156. #define DEBSUB "SndCsAssignCommQueue:"
  157. DWORD CommQueueIndex;
  158. //
  159. // Pseudo round robin. Avoid locks by checking bounds.
  160. //
  161. CommQueueIndex = CommQueueRoundRobin++;
  162. if (CommQueueRoundRobin >= MAX_COMM_QUEUE_NUMBER) {
  163. CommQueueRoundRobin = 1;
  164. }
  165. if (CommQueueIndex >= MAX_COMM_QUEUE_NUMBER) {
  166. CommQueueIndex = 1;
  167. }
  168. DPRINT1(4, "Assigned Comm Queue %d\n", CommQueueIndex);
  169. return CommQueueIndex;
  170. }
  171. VOID
  172. SndCsCreateCxtion(
  173. IN OUT PCXTION Cxtion
  174. )
  175. /*++
  176. Routine Description:
  177. Create a new join guid and comm queue for this cxtion.
  178. Assumes: Caller has CXTION_TABLE lock.
  179. Arguments:
  180. Cxtion
  181. Return Value:
  182. None.
  183. --*/
  184. {
  185. #undef DEBSUB
  186. #define DEBSUB "SndCsCreateCxtion:"
  187. DPRINT1(4, ":X: %ws: Creating join guid.\n", Cxtion->Name->Name);
  188. FrsCreateJoinGuid(&Cxtion->JoinGuid);
  189. SetCxtionFlag(Cxtion, CXTION_FLAGS_JOIN_GUID_VALID |
  190. CXTION_FLAGS_UNJOIN_GUID_VALID);
  191. //
  192. // Assign a comm queue. A cxtion must use the same comm queue for a given
  193. // session (join guid) to maintain packet order. Old packets have an
  194. // invalid join guid and are either not sent or ignored on the receiving side.
  195. //
  196. Cxtion->CommQueueIndex = SndCsAssignCommQueue();
  197. }
  198. VOID
  199. SndCsDestroyCxtion(
  200. IN PCXTION Cxtion,
  201. IN DWORD CxtionFlags
  202. )
  203. /*++
  204. Routine Description:
  205. Destroy a cxtion's join guid and unbind handles.
  206. Assumes: Caller has CXTION_TABLE lock.
  207. Arguments:
  208. Cxtion - Cxtion being destroyed.
  209. CxtionFlags - Caller specifies which state flags are cleared.
  210. Return Value:
  211. None.
  212. --*/
  213. {
  214. #undef DEBSUB
  215. #define DEBSUB "SndCsDestroyCxtion:"
  216. //
  217. // Nothing to do
  218. //
  219. if (Cxtion == NULL) {
  220. return;
  221. }
  222. //
  223. // Invalidate the join guid. Packets to be sent to this connection are
  224. // errored off because of their invalid join guid.
  225. // Packets received are errored off for the same reason.
  226. //
  227. DPRINT2(4, ":X: %ws: Destroying join guid (%08x)\n", Cxtion->Name->Name, CxtionFlags);
  228. ClearCxtionFlag(Cxtion, CxtionFlags |
  229. CXTION_FLAGS_JOIN_GUID_VALID |
  230. CXTION_FLAGS_TIMEOUT_SET);
  231. //
  232. // Unbind the old handles. They aren't very useful without a
  233. // valid join guid. This function is called out of FrsFreeType() when
  234. // freeing a cxtion; hence the partner field may not be filled in. Don't
  235. // unbind handles if there is no partner.
  236. //
  237. if ((Cxtion->Partner != NULL) &&
  238. (Cxtion->Partner->Guid != NULL) &&
  239. !Cxtion->JrnlCxtion) {
  240. SndCsUnBindHandles(Cxtion->Partner);
  241. }
  242. }
  243. VOID
  244. SndCsCxtionTimeout(
  245. IN PCOMMAND_PACKET TimeoutCmd,
  246. IN PVOID Ignore
  247. )
  248. /*++
  249. Routine Description:
  250. The cxtion has not received a reply from its partner for quite
  251. awhile. Unjoin the cxtion.
  252. Arguments:
  253. TimeoutCmd -- Timeout command packet
  254. Ignore
  255. Return Value:
  256. None.
  257. --*/
  258. {
  259. #undef DEBSUB
  260. #define DEBSUB "SndCsCxtionTimeout:"
  261. PREPLICA Replica;
  262. PCXTION Cxtion;
  263. PWCHAR ParentPrincName = NULL;
  264. handle_t ParentHandle = NULL;
  265. ULONG ParentAuthLevel;
  266. DWORD WStatus;
  267. CHAR TimeStr[TIME_STRING_LENGTH];
  268. ULONGLONG CurrentTime;
  269. LONGLONG TimeDelta;
  270. //
  271. // Not a true timeout; just some error condition. Probably
  272. // shutdown. Ignore it.
  273. //
  274. if (!WIN_SUCCESS(TimeoutCmd->ErrorStatus)) {
  275. return;
  276. }
  277. //
  278. // Pull out params from command packet
  279. //
  280. Replica = SRReplica(TimeoutCmd);
  281. Cxtion = SRCxtion(TimeoutCmd);
  282. LOCK_CXTION_TABLE(Replica);
  283. //
  284. // The timeout is associated with a different join guid; ignore it
  285. //
  286. if (!CxtionFlagIs(Cxtion, CXTION_FLAGS_TIMEOUT_SET) ||
  287. !CxtionFlagIs(Cxtion, CXTION_FLAGS_JOIN_GUID_VALID) ||
  288. !GUIDS_EQUAL(&SRJoinGuid(TimeoutCmd), &Cxtion->JoinGuid)) {
  289. ClearCxtionFlag(Cxtion, CXTION_FLAGS_TIMEOUT_SET);
  290. UNLOCK_CXTION_TABLE(Replica);
  291. return;
  292. }
  293. //
  294. // Check if the inbound partner is still up. If the partner is up then do not unjoin the
  295. // connection. The partner could be working on genenrating staging file for
  296. // a huge file and so we do not want to unjoin the connection but rather wait
  297. // for the partner to finish.
  298. //
  299. // FileTimeToString((PFILETIME)&SRLastJoinTime(TimeoutCmd), TimeStr);
  300. // DPRINT1(4, "SRLastJoinTime(TimeoutCmd) %s\n", TimeStr);
  301. // FileTimeToString((PFILETIME)&Cxtion->LastJoinTime, TimeStr);
  302. // DPRINT1(4, "Cxtion->LastJoinTime %s\n", TimeStr);
  303. if (Cxtion->Inbound == TRUE) {
  304. WStatus = NtFrsApi_Rpc_Bind(Cxtion->PartnerDnsName,
  305. &ParentPrincName,
  306. &ParentHandle,
  307. &ParentAuthLevel);
  308. FrsFree(ParentPrincName);
  309. if (ParentHandle) {
  310. RpcBindingFree(&ParentHandle);
  311. }
  312. if (WIN_SUCCESS(WStatus)) {
  313. FileTimeToString((PFILETIME)&SRTimeoutSetTime(TimeoutCmd), TimeStr);
  314. DPRINT1(4, "Timeout set time %s\n", TimeStr);
  315. GetSystemTimeAsFileTime((PFILETIME)&CurrentTime);
  316. FileTimeToString((PFILETIME)&CurrentTime, TimeStr);
  317. DPRINT1(4, "Current time %s\n", TimeStr);
  318. TimeDelta = CurrentTime - SRTimeoutSetTime(TimeoutCmd);
  319. TimeDelta = TimeDelta / CONVERT_FILETIME_TO_MINUTES;
  320. DPRINT1(4, "TimeDelta is %d minutes\n", TimeDelta);
  321. //
  322. // Setting an upper limit on how long to wait.
  323. // FRS_MAX_FETCH_WAIT_TIME_IN_MINUTES is set to 10 hours (10 * 60)
  324. //
  325. if (TimeDelta <= FRS_MAX_FETCH_WAIT_TIME_IN_MINUTES) {
  326. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Extend timer");
  327. WaitSubmit(TimeoutCmd, CommTimeoutInMilliSeconds, CMD_DELAYED_COMPLETE);
  328. UNLOCK_CXTION_TABLE(Replica);
  329. return;
  330. }
  331. }
  332. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, Timeout expired, Unjoin Cxtion");
  333. }
  334. //
  335. // Increment the Communication Timeouts counter for both the
  336. // replica set and the connection.
  337. //
  338. PM_INC_CTR_REPSET(Replica, CommTimeouts, 1);
  339. PM_INC_CTR_CXTION(Cxtion, CommTimeouts, 1);
  340. ClearCxtionFlag(Cxtion, CXTION_FLAGS_TIMEOUT_SET);
  341. UNLOCK_CXTION_TABLE(Replica);
  342. RcsSubmitReplicaCxtion(Replica, Cxtion, CMD_UNJOIN);
  343. return;
  344. }
  345. BOOL
  346. SndCsCheckCxtion(
  347. IN PCOMMAND_PACKET Cmd
  348. )
  349. /*++
  350. Routine Description:
  351. Check that the join guid is still valid, set the timer if needed.
  352. Arguments:
  353. Cmd
  354. Return Value:
  355. None.
  356. --*/
  357. {
  358. #undef DEBSUB
  359. #define DEBSUB "SndCsCheckCxtion:"
  360. PREPLICA Replica;
  361. PCXTION Cxtion;
  362. ULONG WaitTime;
  363. Replica = SRReplica(Cmd);
  364. Cxtion = SRCxtion(Cmd);
  365. //
  366. // Nothing to check
  367. //
  368. if (!SRJoinGuidValid(Cmd) &&
  369. !SRSetTimeout(Cmd) &&
  370. !VOLATILE_OUTBOUND_CXTION(Cxtion)) {
  371. return TRUE;
  372. }
  373. LOCK_CXTION_TABLE(Replica);
  374. //
  375. // Check that our session id (join guid) is still valid
  376. //
  377. if (SRJoinGuidValid(Cmd)) {
  378. if (!CxtionFlagIs(Cxtion, CXTION_FLAGS_JOIN_GUID_VALID) ||
  379. !GUIDS_EQUAL(&SRJoinGuid(Cmd), &Cxtion->JoinGuid)) {
  380. DPRINT1(4, "++ %ws: Join guid is INVALID.\n", Cxtion->Name->Name);
  381. UNLOCK_CXTION_TABLE(Replica);
  382. return FALSE;
  383. }
  384. }
  385. //
  386. // If our partner doesn't respond in time, unjoin the cxtion.
  387. //
  388. // *** NOTE *** Since the following is using state in the Cxtion struct
  389. // to record timeout info, only one fetch request can be active at a time.
  390. // Look at the timeout code to see what it will do.
  391. //
  392. // :SP1: Volatile connection cleanup.
  393. //
  394. // A volatile connection is used to seed sysvols after dcpromo. If there
  395. // is inactivity on a volatile outbound connection for more than
  396. // FRS_VOLATILE_CONNECTION_MAX_IDLE_TIME then this connection is unjoined.
  397. // An unjoin on a volatile outbound connection triggers a delete on that
  398. // connection. This is to prevent the case where staging files are kept
  399. // for ever on the parent for a volatile connection.
  400. //
  401. if (SRSetTimeout(Cmd) || VOLATILE_OUTBOUND_CXTION(Cxtion)) {
  402. if (!CxtionFlagIs(Cxtion, CXTION_FLAGS_TIMEOUT_SET)) {
  403. if (Cxtion->CommTimeoutCmd == NULL) {
  404. Cxtion->CommTimeoutCmd = FrsAllocCommand(NULL, CMD_UNKNOWN);
  405. FrsSetCompletionRoutine(Cxtion->CommTimeoutCmd, SndCsCxtionTimeout, NULL);
  406. SRCxtion(Cxtion->CommTimeoutCmd) = Cxtion;
  407. SRReplica(Cxtion->CommTimeoutCmd) = Replica;
  408. }
  409. //
  410. // Update join guid, cmd packet may be left over from previous join.
  411. //
  412. COPY_GUID(&SRJoinGuid(Cxtion->CommTimeoutCmd), &Cxtion->JoinGuid);
  413. GetSystemTimeAsFileTime((PFILETIME)&SRTimeoutSetTime(Cxtion->CommTimeoutCmd));
  414. SRLastJoinTime(Cxtion->CommTimeoutCmd) = Cxtion->LastJoinTime;
  415. WaitTime = (VOLATILE_OUTBOUND_CXTION(Cxtion) ?
  416. FRS_VOLATILE_CONNECTION_MAX_IDLE_TIME : CommTimeoutInMilliSeconds);
  417. WaitSubmit(Cxtion->CommTimeoutCmd, WaitTime, CMD_DELAYED_COMPLETE);
  418. SetCxtionFlag(Cxtion, CXTION_FLAGS_TIMEOUT_SET);
  419. }
  420. }
  421. UNLOCK_CXTION_TABLE(Replica);
  422. return TRUE;
  423. }
  424. DWORD
  425. SndCsDispatchCommError(
  426. PCOMM_PACKET CommPkt
  427. )
  428. /*++
  429. Routine Description:
  430. Transfering a comm packet to the appropriate command server
  431. for error processing.
  432. Arguments:
  433. CommPkt - comm packet that couldn't be sent
  434. Return Value:
  435. WIN32 Status
  436. --*/
  437. {
  438. #undef DEBSUB
  439. #define DEBSUB "SndCsDispatchCommError:"
  440. DWORD WStatus;
  441. DPRINT1(4, "Comm pkt in error %08x\n", CommPkt);
  442. switch(CommPkt->CsId) {
  443. case CS_RS:
  444. WStatus = RcsSubmitCommPktWithErrorToRcs(CommPkt);
  445. break;
  446. default:
  447. DPRINT1(0, "Unknown command server id %d\n", CommPkt->CsId);
  448. WStatus = ERROR_INVALID_FUNCTION;
  449. }
  450. DPRINT1_WS(0, "Could not process comm pkt with error %08x;", CommPkt, WStatus);
  451. return WStatus;
  452. }
  453. DWORD
  454. SndCsExit(
  455. PFRS_THREAD FrsThread
  456. )
  457. /*++
  458. Routine Description:
  459. Immediate cancel of all outstanding RPC calls for the thread
  460. identified by FrsThread. Set the tombstone to 5 seconds from
  461. now. If this thread does not exit within that time, any calls
  462. to ThSupWaitThread() will return a timeout error.
  463. Arguments:
  464. FrsThread
  465. Return Value:
  466. ERROR_SUCCESS
  467. --*/
  468. {
  469. #undef DEBSUB
  470. #define DEBSUB "SndCsExit:"
  471. if (HANDLE_IS_VALID(FrsThread->Handle)) {
  472. DPRINT1(4, ":X: Canceling RPC requests for thread %ws\n", FrsThread->Name);
  473. RpcCancelThreadEx(FrsThread->Handle, 0);
  474. }
  475. return ThSupExitWithTombstone(FrsThread);
  476. }
  477. LONG
  478. SndCsMainFilter(
  479. IN PEXCEPTION_POINTERS ExceptionPointer
  480. )
  481. {
  482. NTSTATUS ExceptionCode = ExceptionPointer->ExceptionRecord->ExceptionCode;
  483. return EXCEPTION_EXECUTE_HANDLER;
  484. }
  485. DWORD
  486. SndCsMain(
  487. PVOID Arg
  488. )
  489. /*++
  490. Routine Description:
  491. Entry point for a thread serving the Send Command Server.
  492. Arguments:
  493. Arg - thread
  494. Return Value:
  495. None.
  496. --*/
  497. {
  498. #undef DEBSUB
  499. #define DEBSUB "SndCsMain:"
  500. DWORD WStatus;
  501. PFRS_QUEUE IdledQueue;
  502. PCOMMAND_PACKET Cmd;
  503. PGHANDLE GHandle;
  504. PHANDLE_LIST HandleList;
  505. PCXTION Cxtion;
  506. PREPLICA Replica;
  507. ULARGE_INTEGER Now;
  508. PFRS_THREAD FrsThread = (PFRS_THREAD)Arg;
  509. //
  510. // Thread is pointing at the correct command server
  511. //
  512. FRS_ASSERT(FrsThread->Data == &SndCs);
  513. //
  514. // Immediate cancel of outstanding RPC calls during shutdown
  515. //
  516. RpcMgmtSetCancelTimeout(0);
  517. FrsThread->Exit = SndCsExit;
  518. //
  519. // Try-Finally
  520. //
  521. try {
  522. //
  523. // Capture exception.
  524. //
  525. try {
  526. //
  527. // Pull entries off the "send" queue and send them on
  528. //
  529. cant_exit_yet:
  530. while (Cmd = FrsGetCommandServerIdled(&SndCs, &IdledQueue)) {
  531. Cxtion = SRCxtion(Cmd);
  532. Replica = SRReplica(Cmd);
  533. COMMAND_SND_COMM_TRACE(4, Cmd, ERROR_SUCCESS, "SndDeQ");
  534. //
  535. // The RPC interface was initialized at this time but the
  536. // advent of the API RPC interfaces necessitated moving
  537. // the RPC initialization into MainMustInit. The event
  538. // and the CMD_INIT_SUBSYSTEM command are left intact
  539. // until such time as they are deemed completely unneeded.
  540. //
  541. if (Cmd->Command == CMD_INIT_SUBSYSTEM) {
  542. //
  543. // All done
  544. //
  545. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  546. FrsRtlUnIdledQueue(IdledQueue);
  547. SetEvent(CommEvent);
  548. continue;
  549. }
  550. //
  551. // Send the Cmd to Cs
  552. //
  553. if (Cmd->Command == CMD_SND_CMD) {
  554. FrsSubmitCommandServer(SRCs(Cmd), SRCmd(Cmd));
  555. SRCmd(Cmd) = NULL;
  556. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  557. FrsRtlUnIdledQueue(IdledQueue);
  558. continue;
  559. }
  560. FRS_ASSERT(SRCommPkt(Cmd));
  561. FRS_ASSERT(SRTo(Cmd));
  562. COMMAND_SND_COMM_TRACE(4, Cmd, ERROR_SUCCESS, "SndStart");
  563. if (FrsIsShuttingDown) {
  564. //
  565. // Complete w/error
  566. //
  567. WStatus = ERROR_PROCESS_ABORTED;
  568. COMMAND_SND_COMM_TRACE(4, Cmd, WStatus, "SndFail - shutting down");
  569. FrsCompleteCommand(Cmd, WStatus);
  570. FrsRtlUnIdledQueue(IdledQueue);
  571. continue;
  572. }
  573. //
  574. // Check that the join guid (if any) is still valid
  575. //
  576. if (!SndCsCheckCxtion(Cmd)) {
  577. COMMAND_SND_COMM_TRACE(4, Cmd, WStatus, "SndFail - stale join guid");
  578. //
  579. // Unjoin the replica\cxtion (if applicable)
  580. //
  581. SndCsDispatchCommError(SRCommPkt(Cmd));
  582. //
  583. // Complete w/error
  584. //
  585. FrsCompleteCommand(Cmd, ERROR_OPERATION_ABORTED);
  586. FrsRtlUnIdledQueue(IdledQueue);
  587. continue;
  588. }
  589. //
  590. // Grab a bound rpc handle for this connection target.
  591. //
  592. GTabLockTable(GHandleTable);
  593. GHandle = GTabLookupNoLock(GHandleTable, SRTo(Cmd)->Guid, NULL);
  594. if (GHandle == NULL) {
  595. GHandle = FrsAllocType(GHANDLE_TYPE);
  596. COPY_GUID(&GHandle->Guid, SRTo(Cmd)->Guid);
  597. GTabInsertEntryNoLock(GHandleTable, GHandle, &GHandle->Guid, NULL);
  598. }
  599. GTabUnLockTable(GHandleTable);
  600. //
  601. // Grab the first handle entry off the list
  602. //
  603. EnterCriticalSection(&GHandle->Lock);
  604. GHandle->Ref = TRUE;
  605. HandleList = GHandle->HandleList;
  606. if (HandleList != NULL) {
  607. GHandle->HandleList = HandleList->Next;
  608. }
  609. LeaveCriticalSection(&GHandle->Lock);
  610. WStatus = ERROR_SUCCESS;
  611. if (HandleList == NULL) {
  612. //
  613. // No free handles bound to the destination server available.
  614. // Allocate a new one.
  615. // Note: Need to add a binding handle throttle.
  616. // Note: Why don't we use the same handle for multiple calls?
  617. //
  618. HandleList = FrsAlloc(sizeof(HANDLE_LIST));
  619. if (FrsIsShuttingDown) {
  620. WStatus = ERROR_PROCESS_ABORTED;
  621. COMMAND_SND_COMM_TRACE(4, Cmd, WStatus, "SndFail - shutting down");
  622. } else {
  623. //
  624. // Rpc call is cancelled if it doesn't return from
  625. // the rpc runtime in time. This is because TCP/IP
  626. // doesn't timeout if the server reboots.
  627. //
  628. GetSystemTimeAsFileTime((FILETIME *)&FrsThread->StartTime);
  629. WStatus = FrsRpcBindToServer(SRTo(Cmd),
  630. SRPrincName(Cmd),
  631. SRAuthLevel(Cmd),
  632. &HandleList->RpcHandle);
  633. //
  634. // Associate a penalty with the cxtion based on the
  635. // time needed to fail the rpc bind call. The penalty
  636. // is applied against joins to prevent a dead machine
  637. // from tying up Snd threads as they wait to timeout
  638. // repeated joins.
  639. //
  640. if (Cxtion != NULL) {
  641. if (!WIN_SUCCESS(WStatus)) {
  642. GetSystemTimeAsFileTime((FILETIME *)&Now);
  643. if (Now.QuadPart > FrsThread->StartTime.QuadPart) {
  644. Cxtion->Penalty += (ULONG)(Now.QuadPart -
  645. FrsThread->StartTime.QuadPart) /
  646. (1000 * 10);
  647. COMMAND_SND_COMM_TRACE(4, Cmd, WStatus, "SndFail - Binding Penalty");
  648. DPRINT1(4, "++ SndFail - Binding Penalty - %d\n", Cxtion->Penalty);
  649. }
  650. }
  651. }
  652. //
  653. // Reset RPC Cancel timeout for thread. No longer in rpc call.
  654. //
  655. FrsThread->StartTime.QuadPart = QUADZERO;
  656. }
  657. if (!WIN_SUCCESS(WStatus)) {
  658. HandleList = FrsFree(HandleList);
  659. COMMAND_SND_COMM_TRACE(0, Cmd, WStatus, "SndFail - binding");
  660. //
  661. // Increment the Bindings in error counter for both the
  662. // replica set and the connection.
  663. //
  664. PM_INC_CTR_REPSET(Replica, BindingsError, 1);
  665. PM_INC_CTR_CXTION(Cxtion, BindingsError, 1);
  666. } else {
  667. //
  668. // Increment the Bindings counter for both the
  669. // replica set and the connection.
  670. //
  671. PM_INC_CTR_REPSET(Replica, Bindings, 1);
  672. PM_INC_CTR_CXTION(Cxtion, Bindings, 1);
  673. }
  674. }
  675. if (WIN_SUCCESS(WStatus)) {
  676. //
  677. // Bind was successful and join guid is okay; send it on
  678. //
  679. try {
  680. //
  681. // Rpc call is cancelled if it doesn't return from
  682. // the rpc runtime in time. This is because TCP/IP
  683. // doesn't timeout if the server reboots.
  684. //
  685. GetSystemTimeAsFileTime((FILETIME *)&FrsThread->StartTime);
  686. if (FrsIsShuttingDown) {
  687. WStatus = ERROR_PROCESS_ABORTED;
  688. COMMAND_SND_COMM_TRACE(4, Cmd, WStatus, "SndFail - shutting down");
  689. } else {
  690. WStatus = FrsRpcSendCommPkt(HandleList->RpcHandle, SRCommPkt(Cmd));
  691. if (!WIN_SUCCESS(WStatus)) {
  692. COMMAND_SND_COMM_TRACE(0, Cmd, WStatus, "SndFail - rpc call");
  693. } else {
  694. COMMAND_SND_COMM_TRACE(4, Cmd, WStatus, "SndSuccess");
  695. }
  696. }
  697. } except (EXCEPTION_EXECUTE_HANDLER) {
  698. GET_EXCEPTION_CODE(WStatus);
  699. COMMAND_SND_COMM_TRACE(0, Cmd, WStatus, "SndFail - rpc exception");
  700. }
  701. //
  702. // Associate a penalty with the cxtion based on the time needed
  703. // to fail the rpc call. The penalty is applied against joins
  704. // to prevent a dead machine from tying up Snd threads as they
  705. // wait to timeout repeated joins.
  706. //
  707. if (Cxtion != NULL) {
  708. if (!WIN_SUCCESS(WStatus)) {
  709. GetSystemTimeAsFileTime((FILETIME *)&Now);
  710. if (Now.QuadPart > FrsThread->StartTime.QuadPart) {
  711. Cxtion->Penalty += (ULONG)(Now.QuadPart -
  712. FrsThread->StartTime.QuadPart) /
  713. (1000 * 10);
  714. COMMAND_SND_COMM_TRACE(0, Cmd, WStatus, "SndFail - Send Penalty");
  715. DPRINT1(4, "++ SndFail - Send Penalty - %d\n", Cxtion->Penalty);
  716. }
  717. } else {
  718. Cxtion->Penalty = 0;
  719. }
  720. }
  721. //
  722. // Reset RPC Cancel timeout for thread. No longer in rpc call.
  723. //
  724. FrsThread->StartTime.QuadPart = QUADZERO;
  725. //
  726. // The binding may be out of date; discard it
  727. //
  728. if (!WIN_SUCCESS(WStatus)) {
  729. //
  730. // Increment the Packets sent with error counter for both the
  731. // replica set and the connection.
  732. //
  733. PM_INC_CTR_REPSET(Replica, PacketsSentError, 1);
  734. PM_INC_CTR_CXTION(Cxtion, PacketsSentError, 1);
  735. if (!FrsIsShuttingDown) {
  736. FrsRpcUnBindFromServer(&HandleList->RpcHandle);
  737. }
  738. HandleList = FrsFree(HandleList);
  739. } else {
  740. //
  741. // Increment the Packets sent and bytes sent counter for both the
  742. // replica set and the connection.
  743. //
  744. PM_INC_CTR_REPSET(Replica, PacketsSent, 1);
  745. PM_INC_CTR_CXTION(Cxtion, PacketsSent, 1);
  746. PM_INC_CTR_REPSET(Replica, PacketsSentBytes, SRCommPkt(Cmd)->PktLen);
  747. PM_INC_CTR_CXTION(Cxtion, PacketsSentBytes, SRCommPkt(Cmd)->PktLen);
  748. }
  749. }
  750. //
  751. // We are done with the rpc handle. Return it to the list for
  752. // another thread to use. This saves rebinding for every call.
  753. //
  754. if (HandleList) {
  755. EnterCriticalSection(&GHandle->Lock);
  756. GHandle->Ref = TRUE;
  757. HandleList->Next = GHandle->HandleList;
  758. GHandle->HandleList = HandleList;
  759. LeaveCriticalSection(&GHandle->Lock);
  760. }
  761. //
  762. // Don't retry. The originator of the command packet is
  763. // responsible for retry. We DO NOT want multiple layers of
  764. // retries because that can lead to frustratingly long timeouts.
  765. //
  766. if (!WIN_SUCCESS(WStatus)) {
  767. //
  768. // Discard future packets that depend on this join
  769. //
  770. LOCK_CXTION_TABLE(Replica);
  771. SndCsDestroyCxtion(Cxtion, 0);
  772. UNLOCK_CXTION_TABLE(Replica);
  773. //
  774. // Unjoin the replica\cxtion (if applicable)
  775. //
  776. SndCsDispatchCommError(SRCommPkt(Cmd));
  777. }
  778. FrsCompleteCommand(Cmd, WStatus);
  779. FrsRtlUnIdledQueue(IdledQueue);
  780. } // end of while()
  781. //
  782. // Exit
  783. //
  784. FrsExitCommandServer(&SndCs, FrsThread);
  785. goto cant_exit_yet;
  786. //
  787. // Get exception status.
  788. //
  789. } except (SndCsMainFilter(GetExceptionInformation())) {
  790. GET_EXCEPTION_CODE(WStatus);
  791. }
  792. } finally {
  793. if (WIN_SUCCESS(WStatus)) {
  794. if (AbnormalTermination()) {
  795. WStatus = ERROR_OPERATION_ABORTED;
  796. }
  797. }
  798. DPRINT_WS(0, "SndCsMain finally.", WStatus);
  799. //
  800. // Trigger FRS shutdown if we terminated abnormally.
  801. //
  802. if (!WIN_SUCCESS(WStatus) && (WStatus != ERROR_PROCESS_ABORTED)) {
  803. DPRINT(0, "SndCsMain terminated abnormally, forcing service shutdown.\n");
  804. FrsIsShuttingDown = TRUE;
  805. SetEvent(ShutDownEvent);
  806. } else {
  807. WStatus = ERROR_SUCCESS;
  808. }
  809. }
  810. return WStatus;
  811. }
  812. VOID
  813. SndCsCommTimeout(
  814. IN PCOMMAND_PACKET Cmd,
  815. IN PVOID Arg
  816. )
  817. /*++
  818. Routine Description:
  819. Age the handle cache and cancel hung rpc requests every so often.
  820. Submit Cmd back onto the Delayed-Command-Server's queue.
  821. Arguments:
  822. Cmd - delayed command packet
  823. Arg - Unused
  824. Return Value:
  825. None. Cmd is submitted to DelCs.
  826. --*/
  827. {
  828. #undef DEBSUB
  829. #define DEBSUB "SndCsCommTimeout:"
  830. DWORD WStatus;
  831. PFRS_THREAD FrsThread;
  832. ULARGE_INTEGER Now;
  833. PVOID Key;
  834. PGHANDLE GHandle;
  835. PHANDLE_LIST HandleList;
  836. extern ULONG RpcAgedBinds;
  837. COMMAND_SND_COMM_TRACE(4, Cmd, ERROR_SUCCESS, "SndChk - Age and Hung");
  838. //
  839. // Age the handle cache
  840. //
  841. GTabLockTable(GHandleTable);
  842. Key = NULL;
  843. while (GHandle = GTabNextDatumNoLock(GHandleTable, &Key)) {
  844. EnterCriticalSection(&GHandle->Lock);
  845. if (!GHandle->Ref) {
  846. while (HandleList = GHandle->HandleList) {
  847. GHandle->HandleList = HandleList->Next;
  848. ++RpcAgedBinds;
  849. FrsRpcUnBindFromServer(&HandleList->RpcHandle);
  850. FrsFree(HandleList);
  851. DPRINT(5, "++ FrsRpcUnBindFromServer\n");
  852. }
  853. }
  854. GHandle->Ref = FALSE;
  855. LeaveCriticalSection(&GHandle->Lock);
  856. }
  857. GTabUnLockTable(GHandleTable);
  858. //
  859. // Cancel hung rpc requests
  860. //
  861. GetSystemTimeAsFileTime((FILETIME *)&Now);
  862. FrsThread = NULL;
  863. while (FrsThread = ThSupEnumThreads(FrsThread)) {
  864. //
  865. // If frs is shutting down; skip it
  866. //
  867. if (FrsIsShuttingDown) {
  868. continue;
  869. }
  870. //
  871. // Some other thread; skip it
  872. //
  873. if (FrsThread->Main != SndCsMain) {
  874. continue;
  875. }
  876. //
  877. // SndCs thread; Is it in an rpc call?
  878. //
  879. if (FrsThread->StartTime.QuadPart == QUADZERO) {
  880. continue;
  881. }
  882. //
  883. // Is the thread running? If not, skip it
  884. //
  885. if (!FrsThread->Running ||
  886. !HANDLE_IS_VALID(FrsThread->Handle)) {
  887. continue;
  888. }
  889. //
  890. // Is it hung in an rpc call?
  891. //
  892. if ((FrsThread->StartTime.QuadPart < Now.QuadPart) &&
  893. ((Now.QuadPart - FrsThread->StartTime.QuadPart) >= CommTimeoutCheck)) {
  894. //
  895. // Yep, cancel the rpc call
  896. //
  897. WStatus = RpcCancelThreadEx(FrsThread->Handle, 0);
  898. DPRINT1_WS(4, "++ RpcCancelThread(%d);", FrsThread->Id, WStatus);
  899. COMMAND_SND_COMM_TRACE(4, Cmd, WStatus, "SndChk - Cancel");
  900. }
  901. }
  902. //
  903. // Re-submit the command packet to the delayed command server
  904. //
  905. if (!FrsIsShuttingDown) {
  906. FrsDelCsCompleteSubmit(Cmd, CommTimeoutInMilliSeconds << 1);
  907. } else {
  908. //
  909. // Send the packet on to the generic completion routine
  910. //
  911. FrsSetCompletionRoutine(Cmd, FrsFreeCommand, NULL);
  912. FrsCompleteCommand(Cmd, Cmd->ErrorStatus);
  913. }
  914. }
  915. VOID
  916. SndCsInitialize(
  917. VOID
  918. )
  919. /*++
  920. Routine Description:
  921. Initialize the send command server subsystem.
  922. Alloc handle table, read reg pars, Create/init SndCs Alloc comm queue
  923. array, attach comm queues to SndCs control queue.
  924. Arguments:
  925. None.
  926. Return Value:
  927. TRUE - command server has been started
  928. FALSE - Not
  929. --*/
  930. {
  931. #undef DEBSUB
  932. #define DEBSUB "SndCsInitialize:"
  933. ULONG Status;
  934. DWORD i;
  935. PCOMMAND_PACKET Cmd;
  936. ULONG MaxThreads;
  937. //
  938. // Get the timeout value and convert to 100 nsec units.
  939. //
  940. CfgRegReadDWord(FKC_COMM_TIMEOUT, NULL, 0, &CommTimeoutInMilliSeconds);
  941. DPRINT1(4, ":S: CommTimeout is %d msec\n", CommTimeoutInMilliSeconds);
  942. CommTimeoutCheck = ((ULONGLONG)CommTimeoutInMilliSeconds) * 1000 * 10;
  943. DPRINT1(4, ":S: CommTimeout is %08x %08x 100-nsec\n",
  944. PRINTQUAD(CommTimeoutCheck));
  945. //
  946. // Binding handle table
  947. //
  948. GHandleTable = GTabAllocTable();
  949. //
  950. // Comm layer command server
  951. //
  952. CfgRegReadDWord(FKC_SNDCS_MAXTHREADS_PAR, NULL, 0, &MaxThreads);
  953. FrsInitializeCommandServer(&SndCs, MaxThreads, L"SndCs", SndCsMain);
  954. //
  955. // A short array of comm queues to increase parallelism. Each Comm queue
  956. // is attached to the Send cmd server control queue. Each cxtion gets
  957. // assigned to a comm queue when it "JOINS" to preserve packet order.
  958. //
  959. for (i = 0; i < MAX_COMM_QUEUE_NUMBER; ++i) {
  960. FrsInitializeQueue(&CommQueues[i], &SndCs.Control);
  961. }
  962. //
  963. // Start the comm layer
  964. //
  965. Cmd = FrsAllocCommand(&SndCs.Queue, CMD_INIT_SUBSYSTEM);
  966. FrsSubmitCommandServer(&SndCs, Cmd);
  967. //
  968. // Age the handle cache and check for hung rpc calls
  969. //
  970. Cmd = FrsAllocCommand(&SndCs.Queue, CMD_VERIFY_SERVICE);
  971. FrsSetCompletionRoutine(Cmd, SndCsCommTimeout, NULL);
  972. FrsDelCsCompleteSubmit(Cmd, CommTimeoutInMilliSeconds << 1);
  973. }
  974. VOID
  975. SndCsUnInitialize(
  976. VOID
  977. )
  978. /*++
  979. Routine Description:
  980. Uninitialize the send command server subsystem.
  981. Arguments:
  982. None.
  983. Return Value:
  984. TRUE - command server has been started
  985. FALSE - Not
  986. --*/
  987. {
  988. #undef DEBSUB
  989. #define DEBSUB "SndCsUnInitialize:"
  990. DWORD i;
  991. GTabFreeTable(GHandleTable, FrsFreeType);
  992. //
  993. // A short array of comm queues to increase parallelism.
  994. //
  995. for (i = 0; i < MAX_COMM_QUEUE_NUMBER; ++i) {
  996. FrsRtlDeleteQueue(&CommQueues[i]);
  997. }
  998. }
  999. VOID
  1000. SndCsSubmitCommPkt(
  1001. IN PREPLICA Replica,
  1002. IN PCXTION Cxtion,
  1003. IN PCHANGE_ORDER_ENTRY Coe,
  1004. IN GUID *JoinGuid,
  1005. IN BOOL SetTimeout,
  1006. IN PCOMM_PACKET CommPkt,
  1007. IN DWORD CommQueueIndex
  1008. )
  1009. /*++
  1010. Routine Description:
  1011. Submit a comm packet to the "send" command server for the target Cxtion.
  1012. Arguments:
  1013. Replica - Replica struct ptr
  1014. Cxtion - Target connection for comm packet.
  1015. Coe - Change order entry for related stage file fetch comm packet.
  1016. This is used track the change orders that have a fetch request outstanding
  1017. on a given inbound connection. Used by Forced Unjoins to send the
  1018. CO thru the Retry path.
  1019. NOTE: When Coe is supplied then SetTimeout should also be TRUE.
  1020. JoinGuid - Current join Guid from Cxtion or null if starting join seq.
  1021. SetTimeout - TRUE if caller wants a timeout set on this send request.
  1022. It means that the caller is eventually expecting a response
  1023. back. E.G. usually set on stage file fetch requests.
  1024. CommPkt - Communication packet data to send.
  1025. CommQueueIndex - Index of communication queue to use, generally allocated
  1026. for each Cxtion struct.
  1027. Return Value:
  1028. None.
  1029. --*/
  1030. {
  1031. #undef DEBSUB
  1032. #define DEBSUB "SndCsSubmitCommPkt:"
  1033. PCOMMAND_PACKET Cmd;
  1034. FRS_ASSERT(CommQueueIndex < MAX_COMM_QUEUE_NUMBER);
  1035. //
  1036. // WARN: we assume that this function is called single-threaded per replica.
  1037. // Davidor - Would be nice if the friggen comment above said why? I
  1038. // currently don't see the reason for this.
  1039. // Maybe: its the time out code in SndCsCheckCxtion()?
  1040. //
  1041. if (Coe != NULL) {
  1042. //
  1043. // Anytime we are supplying a Coe argument we are expecting a response
  1044. // so verify that SetTimeout was requested and put the Coe in the
  1045. // Cxtion's Coe table so we can send it through the retry path at
  1046. // unjoin (or timeout).
  1047. //
  1048. FRS_ASSERT(SetTimeout);
  1049. LOCK_CXTION_COE_TABLE(Replica, Cxtion);
  1050. FRS_ASSERT(GTabLookupNoLock(Cxtion->CoeTable, &Coe->Cmd.ChangeOrderGuid, NULL) == NULL);
  1051. GTabInsertEntry(Cxtion->CoeTable, Coe, &Coe->Cmd.ChangeOrderGuid, NULL);
  1052. UNLOCK_CXTION_COE_TABLE(Replica, Cxtion);
  1053. }
  1054. Cmd = FrsAllocCommand(&CommQueues[CommQueueIndex], CMD_SND_COMM_PACKET);
  1055. SRTo(Cmd) = FrsBuildGName(FrsDupGuid(Cxtion->Partner->Guid),
  1056. FrsWcsDup(Cxtion->PartnerDnsName));
  1057. SRReplica(Cmd) = Replica;
  1058. SRCxtion(Cmd) = Cxtion;
  1059. if (JoinGuid) {
  1060. COPY_GUID(&SRJoinGuid(Cmd), JoinGuid);
  1061. SRJoinGuidValid(Cmd) = TRUE;
  1062. }
  1063. //
  1064. // Partner principal name and Authentication level.
  1065. //
  1066. SRPrincName(Cmd) = FrsWcsDup(Cxtion->PartnerPrincName);
  1067. SRAuthLevel(Cmd) = Cxtion->PartnerAuthLevel;
  1068. SRSetTimeout(Cmd) = SetTimeout;
  1069. SRCommPkt(Cmd) = CommPkt;
  1070. FrsSetCompletionRoutine(Cmd, CommCompletionRoutine, NULL);
  1071. //
  1072. // Check Comm packet consistency and put Send cmd on sent CS queue.
  1073. //
  1074. if (CommCheckPkt(CommPkt)) {
  1075. COMMAND_SND_COMM_TRACE(4, Cmd, ERROR_SUCCESS, "SndEnQComm");
  1076. FrsSubmitCommandServer(&SndCs, Cmd);
  1077. } else {
  1078. COMMAND_SND_COMM_TRACE(4, Cmd, ERROR_SUCCESS, "SndEnQERROR");
  1079. FrsCompleteCommand(Cmd, ERROR_INVALID_BLOCK);
  1080. }
  1081. }
  1082. VOID
  1083. SndCsSubmitCommPkt2(
  1084. IN PREPLICA Replica,
  1085. IN PCXTION Cxtion,
  1086. IN PCHANGE_ORDER_ENTRY Coe,
  1087. IN BOOL SetTimeout,
  1088. IN PCOMM_PACKET CommPkt
  1089. )
  1090. /*++
  1091. Routine Description:
  1092. Submit a comm packet to the "send" command server using the assigned
  1093. comm queue for the target Cxtion.
  1094. The Comm queue index and the join Guid come from the cxtion struct.
  1095. Arguments:
  1096. See arg description for SndCsSubmitCommPkt.
  1097. Return Value:
  1098. None.
  1099. --*/
  1100. {
  1101. #undef DEBSUB
  1102. #define DEBSUB "SndCsSubmitCommPkt2:"
  1103. SndCsSubmitCommPkt(Replica,
  1104. Cxtion,
  1105. Coe,
  1106. &Cxtion->JoinGuid,
  1107. SetTimeout,
  1108. CommPkt,
  1109. Cxtion->CommQueueIndex);
  1110. }
  1111. VOID
  1112. SndCsSubmitCmd(
  1113. IN PREPLICA Replica,
  1114. IN PCXTION Cxtion,
  1115. IN PCOMMAND_SERVER FlushCs,
  1116. IN PCOMMAND_PACKET FlushCmd,
  1117. IN DWORD CommQueueIndex
  1118. )
  1119. /*++
  1120. Routine Description:
  1121. Submit the FlushCmd packet to the "send" command server for the
  1122. target Cxtion. The FlushCmd packet will be submitted to
  1123. FlushCs once it bubbles to the top of the queue. I.e., once
  1124. the queue has been flushed.
  1125. Arguments:
  1126. Replica - replica set
  1127. Cxtion - cxtion identifies send queue
  1128. FlushCs - Command server to receive Cmd
  1129. FlushCmd - Command packet to send to Cs
  1130. CommQueueIndex - Identifies the comm queue
  1131. Return Value:
  1132. None.
  1133. --*/
  1134. {
  1135. #undef DEBSUB
  1136. #define DEBSUB "SndCsSubmitCmd:"
  1137. PCOMMAND_PACKET Cmd;
  1138. FRS_ASSERT(CommQueueIndex < MAX_COMM_QUEUE_NUMBER);
  1139. //
  1140. // Alloc the cmd packet and set the target queue and the command.
  1141. //
  1142. Cmd = FrsAllocCommand(&CommQueues[CommQueueIndex], CMD_SND_CMD);
  1143. //
  1144. // Destination Partner Guid / Dns Name
  1145. //
  1146. SRTo(Cmd) = FrsBuildGName(FrsDupGuid(Cxtion->Partner->Guid),
  1147. FrsWcsDup(Cxtion->PartnerDnsName));
  1148. SRReplica(Cmd) = Replica;
  1149. SRCxtion(Cmd) = Cxtion;
  1150. SRCs(Cmd) = FlushCs;
  1151. SRCmd(Cmd) = FlushCmd;
  1152. SRPrincName(Cmd) = FrsWcsDup(Cxtion->PartnerPrincName);
  1153. SRAuthLevel(Cmd) = Cxtion->PartnerAuthLevel;
  1154. FrsSetCompletionRoutine(Cmd, CommCompletionRoutine, NULL);
  1155. COMMAND_SND_COMM_TRACE(4, Cmd, ERROR_SUCCESS, "SndEnQCmd");
  1156. FrsSubmitCommandServer(&SndCs, Cmd);
  1157. }
  1158. VOID
  1159. SndCsShutDown(
  1160. VOID
  1161. )
  1162. /*++
  1163. Routine Description:
  1164. Shutdown the send command server
  1165. Arguments:
  1166. None.
  1167. Return Value:
  1168. None.
  1169. --*/
  1170. {
  1171. #undef DEBSUB
  1172. #define DEBSUB "SndCsShutDown:"
  1173. DWORD i;
  1174. //
  1175. // A short array of comm queues to increase parallelism.
  1176. //
  1177. for (i = 0; i < MAX_COMM_QUEUE_NUMBER; ++i) {
  1178. FrsRunDownCommandServer(&SndCs, &CommQueues[i]);
  1179. }
  1180. FrsRunDownCommandServer(&SndCs, &SndCs.Queue);
  1181. }