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.

241 lines
8.5 KiB

  1. /*++ BUILD Version: 0009 // Increment this if a change has global effect
  2. Copyright (c) 1987-1998 Microsoft Corporation
  3. Module Name:
  4. remoteboot.c
  5. Abstract:
  6. This is the source file that implements the silent reconnection form the client to the server.
  7. Author:
  8. Yun Lin (YunLin) 21-April-98 Created
  9. Notes:
  10. The remote boot client is the workstation that boots up from the boot server. The connection
  11. between the remote boot client and server is different from the one between ordinary client
  12. server in such a way that losing the connection to the boot server, the remote boot client
  13. may not function properly, sometime even crash.
  14. The make the connection between the remote boot client and server more relaible, we introduce
  15. a machanism that in case of connection fails, the RDR try to reconnect to the boot server
  16. transparently to the applications.
  17. The reconnection can be initiated in three places: initialize a exchange, in the middle of read
  18. and write. The reconnection is triggered by the mis-matching of server verion stored on the
  19. server and the one stored on smbSrvOpen which happens on a remote boot session.
  20. The reconnection process starts with seting up a new session to the boot server. If it succeed,
  21. it checks if the paging file is on the boot (in case of diskless client). If ture, it re-opens
  22. the paging file with the same create options stored on the deferred open context created. When
  23. a file is successful opened on the boot server at first time, the client creates a open context
  24. for the file storing all the desired access and create options.
  25. After re-opens the paging file or it is on the local disk, the reconnection code re-opens the
  26. file as if it is a deferred open file. As the file is successfully opened, the old FID and the
  27. server version are updated. The operation on the file can be resumed without noticing of the
  28. user.
  29. --*/
  30. #include "precomp.h"
  31. #pragma hdrstop
  32. RXDT_DefineCategory(RECONNECT);
  33. #define Dbg (DEBUG_TRACE_RECONNECT)
  34. BOOLEAN PagedFileReconnectInProgress = FALSE;
  35. LIST_ENTRY PagedFileReconnectSynchronizationExchanges;
  36. extern LIST_ENTRY MRxSmbPagingFilesSrvOpenList;
  37. NTSTATUS
  38. SmbCeRemoteBootReconnect(
  39. PSMB_EXCHANGE pExchange,
  40. PRX_CONTEXT RxContext)
  41. /*++
  42. Routine Description:
  43. This routine reconnects the paged file first, and then re-open the given file on the server
  44. in case of remote boot client.
  45. Arguments:
  46. pExchange - the placeholder for the exchange instance.
  47. pRxContext - the associated RxContext
  48. Return Value:
  49. RXSTATUS - The return status for the operation
  50. --*/
  51. {
  52. NTSTATUS Status = STATUS_SUCCESS;
  53. RxCaptureFcb;
  54. RxCaptureFobx;
  55. PLIST_ENTRY pListHead;
  56. PLIST_ENTRY pListEntry;
  57. KAPC_STATE ApcState;
  58. PRX_CONTEXT RxContextOfPagedFile;
  59. BOOLEAN AttachToSystemProcess = FALSE;
  60. PMRX_SRV_OPEN SrvOpen = capFobx->pSrvOpen;
  61. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  62. PSMBCEDB_SERVER_ENTRY pServerEntry = SmbCeGetExchangeServerEntry(pExchange);
  63. DbgPrint("Re-open %wZ\n",GET_ALREADY_PREFIXED_NAME_FROM_CONTEXT(RxContext));
  64. if (pServerEntry->Server.CscState == ServerCscDisconnected) {
  65. return STATUS_CONNECTION_DISCONNECTED;
  66. }
  67. if (IoGetCurrentProcess() != RxGetRDBSSProcess()) {
  68. KeStackAttachProcess(RxGetRDBSSProcess(),&ApcState);
  69. AttachToSystemProcess = TRUE;
  70. }
  71. SmbCeAcquireResource();
  72. SmbCeAcquireSpinLock();
  73. if (!PagedFileReconnectInProgress) {
  74. InitializeListHead(&PagedFileReconnectSynchronizationExchanges);
  75. PagedFileReconnectInProgress = TRUE;
  76. SmbCeReleaseSpinLock();
  77. SmbCeReleaseResource();
  78. SmbCeUninitializeExchangeTransport(pExchange);
  79. SmbCeReferenceServerEntry(pServerEntry);
  80. SmbCeResumeAllOutstandingRequestsOnError(pServerEntry);
  81. if (pServerEntry->Header.State == SMBCEDB_INVALID &&
  82. pServerEntry->Server.CscState != ServerCscDisconnected) {
  83. do {
  84. SmbCeUpdateServerEntryState(pServerEntry,
  85. SMBCEDB_CONSTRUCTION_IN_PROGRESS);
  86. Status = SmbCeInitializeServerTransport(pServerEntry,NULL,NULL);
  87. if (Status == STATUS_SUCCESS) {
  88. Status = SmbCeNegotiate(
  89. pServerEntry,
  90. pServerEntry->pRdbssSrvCall,
  91. pServerEntry->Server.IsRemoteBootServer
  92. );
  93. }
  94. } while ((Status == STATUS_IO_TIMEOUT ||
  95. Status == STATUS_BAD_NETWORK_PATH ||
  96. Status == STATUS_NETWORK_UNREACHABLE ||
  97. Status == STATUS_USER_SESSION_DELETED ||
  98. Status == STATUS_REMOTE_NOT_LISTENING ||
  99. Status == STATUS_CONNECTION_DISCONNECTED) &&
  100. pServerEntry->Server.CscState != ServerCscDisconnected);
  101. SmbCeCompleteServerEntryInitialization(pServerEntry,Status);
  102. }
  103. if (pServerEntry->Server.CscState == ServerCscDisconnected) {
  104. Status = STATUS_CONNECTION_DISCONNECTED;
  105. }
  106. SmbCeAcquireResource();
  107. SmbCeAcquireSpinLock();
  108. pListHead = &PagedFileReconnectSynchronizationExchanges;
  109. pListEntry = pListHead->Flink;
  110. while (pListEntry != pListHead) {
  111. PSMB_EXCHANGE pWaitingExchange;
  112. pWaitingExchange = (PSMB_EXCHANGE)CONTAINING_RECORD(pListEntry,SMB_EXCHANGE,ExchangeList);
  113. pListEntry = pListEntry->Flink;
  114. RemoveEntryList(&pWaitingExchange->ExchangeList);
  115. InitializeListHead(&pWaitingExchange->ExchangeList);
  116. pWaitingExchange->SmbStatus = Status;
  117. //DbgPrint("Signal Exchange %x after reconnect.\n",pWaitingExchange);
  118. RxSignalSynchronousWaiter(pWaitingExchange->RxContext);
  119. }
  120. PagedFileReconnectInProgress = FALSE;
  121. SmbCeReleaseSpinLock();
  122. SmbCeReleaseResource();
  123. } else {
  124. InsertTailList(
  125. &PagedFileReconnectSynchronizationExchanges,
  126. &pExchange->ExchangeList);
  127. SmbCeReleaseSpinLock();
  128. SmbCeReleaseResource();
  129. SmbCeUninitializeExchangeTransport(pExchange);
  130. //DbgPrint("Exchange %x waits for re-open paged file on %wZ\n",pExchange,&pServerEntry->Name);
  131. RxWaitSync(RxContext);
  132. //DbgPrint("Resume exchange %x\n",pExchange);
  133. KeInitializeEvent(
  134. &RxContext->SyncEvent,
  135. SynchronizationEvent,
  136. FALSE);
  137. Status = pExchange->SmbStatus;
  138. }
  139. if (Status == STATUS_SUCCESS &&
  140. !FlagOn(capFcb->FcbState, FCB_STATE_PAGING_FILE) &&
  141. pServerEntry->Server.CscState != ServerCscDisconnected) {
  142. LONG HotReconnecteInProgress;
  143. HotReconnecteInProgress = InterlockedExchange(&smbSrvOpen->HotReconnectInProgress,1);
  144. do {
  145. Status = MRxSmbDeferredCreate(RxContext);
  146. if (Status == STATUS_CONNECTION_DISCONNECTED) {
  147. SmbCeTransportDisconnectIndicated(pServerEntry);
  148. }
  149. if (Status != STATUS_SUCCESS) {
  150. LARGE_INTEGER time;
  151. LARGE_INTEGER Delay = {0,-1};
  152. ULONG Interval;
  153. // Select a random delay within 6 seconds.
  154. KeQuerySystemTime(&time);
  155. Interval = RtlRandom(&time.LowPart) % 60000000;
  156. Delay.LowPart = MAXULONG - Interval;
  157. KeDelayExecutionThread(KernelMode, FALSE, &Delay);
  158. }
  159. } while ((Status == STATUS_RETRY ||
  160. Status == STATUS_IO_TIMEOUT ||
  161. Status == STATUS_BAD_NETWORK_PATH ||
  162. Status == STATUS_NETWORK_UNREACHABLE ||
  163. Status == STATUS_USER_SESSION_DELETED ||
  164. Status == STATUS_REMOTE_NOT_LISTENING ||
  165. Status == STATUS_CONNECTION_DISCONNECTED) &&
  166. pServerEntry->Server.CscState != ServerCscDisconnected);
  167. if (HotReconnecteInProgress == 0) {
  168. smbSrvOpen->HotReconnectInProgress = 0;
  169. }
  170. }
  171. if (AttachToSystemProcess) {
  172. KeUnstackDetachProcess(&ApcState);
  173. }
  174. DbgPrint("Re-open return %x\n", Status);
  175. return Status;
  176. }