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.

344 lines
7.9 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. timer.c
  5. Abstract:
  6. This module contains code which implements the receive and send timeouts
  7. for each connection. Netbios timeouts are specified in 0.5 second units.
  8. For each application using Netbios there is a single timer started
  9. when the first connection specifies a non-zero rto or sto. This regular
  10. 1 second pulse is used for all connections by this application. It
  11. is stopped when the application exits (and closes the connection to
  12. \Device\Netbios).
  13. If a send timesout the connection is disconnected as per Netbios 3.0.
  14. Individual receives can timeout without affecting the session.
  15. Author:
  16. Colin Watson (ColinW) 15-Sep-1991
  17. Environment:
  18. Kernel mode
  19. Revision History:
  20. --*/
  21. #include "nb.h"
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, NbStartTimer)
  24. #pragma alloc_text(PAGE, NbTimer)
  25. #endif
  26. VOID
  27. RunTimerForLana(
  28. PFCB pfcb,
  29. PLANA_INFO plana,
  30. int index
  31. );
  32. VOID
  33. NbStartTimer(
  34. IN PFCB pfcb
  35. )
  36. /*++
  37. Routine Description:
  38. This routine starts the timer ticking for this FCB.
  39. Arguments:
  40. pfcb - Pointer to our FCB.
  41. Return Value:
  42. none.
  43. --*/
  44. {
  45. LARGE_INTEGER DueTime;
  46. PAGED_CODE();
  47. DueTime.QuadPart = Int32x32To64( 500, -MILLISECONDS );
  48. // This is the first connection with timeouts specified.
  49. //
  50. // set up the timer so that every 500 milliseconds we scan all the
  51. // connections for timed out receive and sends.
  52. //
  53. IF_NBDBG (NB_DEBUG_CALL) {
  54. NbPrint( ("Start the timer for fcb: %lx\n", pfcb));
  55. }
  56. if ( pfcb->TimerRunning == TRUE ) {
  57. return;
  58. }
  59. KeInitializeDpc (
  60. &pfcb->Dpc,
  61. NbTimerDPC,
  62. pfcb);
  63. KeInitializeTimer (&pfcb->Timer);
  64. pfcb->TimerRunning = TRUE;
  65. (VOID)KeSetTimer (
  66. &pfcb->Timer,
  67. DueTime,
  68. &pfcb->Dpc);
  69. }
  70. VOID
  71. NbTimerDPC(
  72. IN PKDPC Dpc,
  73. IN PVOID Context,
  74. IN PVOID SystemArgument1,
  75. IN PVOID SystemArgument2
  76. )
  77. /*++
  78. Routine Description:
  79. This routine is called to search for timed out send and receive
  80. requests. This routine is called at raised Irql.
  81. Arguments:
  82. Context - Pointer to our FCB.
  83. Return Value:
  84. none.
  85. --*/
  86. {
  87. PFCB pfcb = (PFCB) Context;
  88. IoQueueWorkItem(
  89. pfcb->WorkEntry, NbTimer, DelayedWorkQueue, pfcb
  90. );
  91. UNREFERENCED_PARAMETER (Dpc);
  92. UNREFERENCED_PARAMETER (SystemArgument1);
  93. UNREFERENCED_PARAMETER (SystemArgument2);
  94. }
  95. VOID
  96. NbTimer(
  97. PDEVICE_OBJECT DeviceObject,
  98. PVOID Context
  99. )
  100. {
  101. ULONG lana_index;
  102. int index;
  103. PFCB pfcb = (PFCB) Context;
  104. LARGE_INTEGER DueTime;
  105. PAGED_CODE();
  106. //
  107. // For each network adapter that is allocated, scan each connection.
  108. //
  109. LOCK_RESOURCE(pfcb);
  110. IF_NBDBG (NB_DEBUG_TIMER) {
  111. NbPrint((" NbTimeout\n" ));
  112. }
  113. if ( pfcb->TimerRunning != TRUE ) {
  114. //
  115. // Driver is being closed. We are trying to cancel the timer
  116. // but the dpc was already fired. Set the timer cancelled event
  117. // to the signalled state and exit.
  118. //
  119. UNLOCK_RESOURCE(pfcb);
  120. KeSetEvent( pfcb->TimerCancelled, 0, FALSE);
  121. return;
  122. }
  123. for ( lana_index = 0; lana_index <= pfcb->MaxLana; lana_index++ ) {
  124. // For each network.
  125. PLANA_INFO plana = pfcb->ppLana[lana_index];
  126. if (( plana != NULL ) &&
  127. ( plana->Status == NB_INITIALIZED)) {
  128. // For each connection on that network.
  129. for ( index = 1; index <= MAXIMUM_CONNECTION; index++) {
  130. if ( plana->ConnectionBlocks[index] != NULL ) {
  131. RunTimerForLana(pfcb, plana, index);
  132. }
  133. }
  134. }
  135. }
  136. DueTime.QuadPart = Int32x32To64( 500, -MILLISECONDS );
  137. (VOID)KeSetTimer (
  138. &pfcb->Timer,
  139. DueTime,
  140. &pfcb->Dpc);
  141. UNLOCK_RESOURCE(pfcb);
  142. }
  143. VOID
  144. RunTimerForLana(
  145. PFCB pfcb,
  146. PLANA_INFO plana,
  147. int index
  148. )
  149. {
  150. KIRQL OldIrql; // Used when SpinLock held.
  151. PPCB ppcb;
  152. PCB pcb;
  153. ppcb = &plana->ConnectionBlocks[index];
  154. pcb = *ppcb;
  155. if (( pcb->Status != SESSION_ESTABLISHED ) &&
  156. ( pcb->Status != HANGUP_PENDING )) {
  157. // Only examine valid connections.
  158. return;
  159. }
  160. LOCK_SPINLOCK( pfcb, OldIrql );
  161. if (( pcb->ReceiveTimeout != 0 ) &&
  162. ( !IsListEmpty( &pcb->ReceiveList))) {
  163. PDNCB pdncb;
  164. PLIST_ENTRY ReceiveEntry = pcb->ReceiveList.Flink;
  165. pdncb = CONTAINING_RECORD( ReceiveEntry, DNCB, ncb_next);
  166. if ( pdncb->tick_count <= 1) {
  167. PIRP Irp = pdncb->irp;
  168. // Read request timed out.
  169. IF_NBDBG (NB_DEBUG_TIMER) {
  170. NbPrint(("Timeout Read pncb: %lx\n", pdncb));
  171. }
  172. NCB_COMPLETE( pdncb, NRC_CMDTMO );
  173. RemoveEntryList( &pdncb->ncb_next );
  174. IoAcquireCancelSpinLock(&Irp->CancelIrql);
  175. //
  176. // Remove the cancel request for this IRP. If its cancelled then its
  177. // ok to just process it because we will be returning it to the caller.
  178. //
  179. Irp->Cancel = FALSE;
  180. IoSetCancelRoutine(Irp, NULL);
  181. IoReleaseCancelSpinLock(Irp->CancelIrql);
  182. // repair the Irp so that the NCB gets copied back.
  183. Irp->IoStatus.Status = STATUS_SUCCESS;
  184. Irp->IoStatus.Information =
  185. FIELD_OFFSET( DNCB, ncb_cmd_cplt );
  186. IoCompleteRequest( Irp, IO_NETWORK_INCREMENT);
  187. } else {
  188. IF_NBDBG (NB_DEBUG_TIMER) {
  189. NbPrint(("Tick Read pdncb: %lx, count: %x\n", pdncb, pdncb->tick_count));
  190. }
  191. pdncb->tick_count -= 1;
  192. }
  193. }
  194. if (( pcb->SendTimeout != 0 ) &&
  195. (!IsListEmpty( &pcb->SendList))) {
  196. PDNCB pdncb;
  197. PLIST_ENTRY SendEntry = pcb->SendList.Flink;
  198. pdncb = CONTAINING_RECORD( SendEntry, DNCB, ncb_next);
  199. if ( pdncb->tick_count <= 1) {
  200. // Send request timed out- hangup connection.
  201. IF_NBDBG (NB_DEBUG_TIMER) {
  202. NbPrint(("Timeout send pncb: %lx\n", pdncb));
  203. }
  204. NCB_COMPLETE( pdncb, NRC_CMDTMO );
  205. pcb->Status = SESSION_ABORTED;
  206. UNLOCK_SPINLOCK( pfcb, OldIrql );
  207. CloseConnection( ppcb, 1000 );
  208. //
  209. // No need to worry about looking for a timed out hangup, the session
  210. // will be closed as soon as the transport cancels the send.
  211. //
  212. return;
  213. } else {
  214. IF_NBDBG (NB_DEBUG_TIMER) {
  215. NbPrint(("Tick Write pdncb: %lx, count: %x\n", pdncb, pdncb->tick_count));
  216. }
  217. pdncb->tick_count -= 1;
  218. }
  219. }
  220. if (( pcb->pdncbHangup != NULL ) &&
  221. ( pcb->Status == HANGUP_PENDING )) {
  222. if ( pcb->pdncbHangup->tick_count <= 1) {
  223. IF_NBDBG (NB_DEBUG_TIMER) {
  224. NbPrint(("Timeout send pncb: %lx\n", pcb->pdncbHangup));
  225. }
  226. NCB_COMPLETE( pcb->pdncbHangup, NRC_CMDTMO );
  227. UNLOCK_SPINLOCK( pfcb, OldIrql );
  228. AbandonConnection( ppcb );
  229. LOCK_SPINLOCK( pfcb, OldIrql );
  230. } else {
  231. IF_NBDBG (NB_DEBUG_TIMER) {
  232. NbPrint(("Tick Hangup pdncb: %lx, count: %x\n",
  233. pcb->pdncbHangup,
  234. pcb->pdncbHangup->tick_count));
  235. }
  236. pcb->pdncbHangup->tick_count -= 1;
  237. }
  238. }
  239. UNLOCK_SPINLOCK( pfcb, OldIrql );
  240. }