/************************************************************************* * * watchdog.c * * IPX Transport Driver - Watch Dog Rouines * * Copyright 1998, Microsoft * *************************************************************************/ #include #include /* * The following defines are necessary since they are referenced in * afd.h but defined in sdk/inc/winsock2.h, which we can't include here. */ #define SG_UNCONSTRAINED_GROUP 0x01 #define SG_CONSTRAINED_GROUP 0x02 #include #include #include #include #include #define _DEFCHARINFO_ #include #include #include //#include #include #include #include "tdtdi.h" #include "tdipx.h" /*============================================================================= == External Functions Defined =============================================================================*/ NTSTATUS InitializeWatchDog( PTD ); VOID WatchDogTimer( PTD, PVOID ); /*============================================================================= == Internel Functions Defined =============================================================================*/ VOID _GetTimeoutValue( PTD, ULONG, PULONG ); /*============================================================================= == External Functions used =============================================================================*/ NTSTATUS _DoTdiAction( PFILE_OBJECT, ULONG, PCHAR, ULONG ); NTSTATUS _TdiSendDatagram( IN PTD pTd, IN PIRP Irp OPTIONAL, IN PFILE_OBJECT FileObject, IN PDEVICE_OBJECT DeviceObject, IN PTRANSPORT_ADDRESS pRemoteAddress, IN ULONG RemoteAddressLength, IN PVOID pBuffer, IN ULONG BufferLength ); /******************************************************************************* * * InitializeWatchDog * * Initialize watch dog * * ENTRY: * pTd (input) * Pointer to td data structure * * EXIT: * STATUS_SUCCESS - no error, non-error match found * ******************************************************************************/ NTSTATUS InitializeWatchDog( PTD pTd ) { ULONG Timeout; NTSTATUS Status; PTDIPX pTdIpx; TRACE(( pTd->pContext, TC_TD, TT_API1, "TDIPX: InitializeWatchDog\n" )); /* * Get pointer to IPX structure */ pTdIpx = (PTDIPX) pTd->pPrivate; /* * If we really want a timer. */ if ( !pTdIpx->AliveTime ) return( STATUS_SUCCESS ); /* * Create watch dog */ ASSERT( pTdIpx->pAliveTimer == NULL ); Status = IcaTimerCreate( pTd->pContext, &pTdIpx->pAliveTimer ); if ( !NT_SUCCESS(Status) ) goto badtimer; /* * Arm timer */ _GetTimeoutValue( pTd, pTdIpx->AliveTime, &Timeout ); IcaTimerStart( pTdIpx->pAliveTimer, WatchDogTimer, NULL, Timeout, ICALOCK_DRIVER ); badtimer: TRACE(( pTd->pContext, TC_TD, TT_API1, "TDIPX: InitializeWatchDog %u, Status=0x%x\n", Timeout, Status )); return( Status ); } /******************************************************************************* * * _GetTimeoutValue * * algorithm to calculate the poll timeout value * * * ENTRY: * pTd (input) * pointer to TD data structure * PollTime (input) * time gap between two pollings (msec) * pTimeOut (output) * timeout value for next poll (msec) * ******************************************************************************/ VOID _GetTimeoutValue( PTD pTd, ULONG PollTime, PULONG pTimeOut ) { LARGE_INTEGER CurrentTime; LARGE_INTEGER Ticks; ULONG Time; ULONG Remain; KeQuerySystemTime( &CurrentTime ); /* The currentTime is in 100nsec units and need convert to msec units. */ Ticks = RtlExtendedLargeIntegerDivide( CurrentTime, 10000, &Remain ); RtlExtendedLargeIntegerDivide( Ticks, PollTime, &Remain ); *pTimeOut = PollTime - Remain; TRACE(( pTd->pContext, TC_TD, TT_API3, "TDIPX: _GetTimeoutValue %u -> %u\n", PollTime, *pTimeOut)); } /******************************************************************************* * * WatchDogTimer * * * ENTRY: * pTd (input) * pointer to TD data structure * pParam (input) * not used * * EXIT: * nothing * ******************************************************************************/ VOID WatchDogTimer( PTD pTd, PVOID pParam ) { ICA_CHANNEL_COMMAND Command; CHAR ptype; ULONG Timeout; BYTE Buffer[1]; NTSTATUS Status; PTDIPX pTdIpx; PTDTDI pTdTdi; PTD_ENDPOINT pEndpoint; /* * Get the connection endpoint for the remote system. * If there is none, then the endpoint must have been closed * so there is nothing to do. */ pTdTdi = (PTDTDI)pTd->pAfd; if ( (pEndpoint = pTdTdi->pConnectionEndpoint) == NULL ) return; ASSERT( pEndpoint->EndpointType == TdiConnectionDatagram ); /* * Get pointer to IPX structure */ pTdIpx = (PTDIPX) pTd->pPrivate; ASSERT( pTdIpx ); TRACE(( pTd->pContext, TC_TD, TT_API4, "TDIPX: WatchDogTimer\n" )); /* * Get time for next watchdog event */ _GetTimeoutValue( pTd, pTdIpx->AliveTime, &Timeout ); /* * Check if client has sent data recently */ if ( pTdIpx->fClientAlive ) goto clientok; /* * Check the poll count */ if ( pTdIpx->AlivePoll ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDIPX: no response for %u pings\n", pTdIpx->AlivePoll )); /* * Check timeout retry count */ if ( pTdIpx->AlivePoll > 6 ) { TRACE(( pTd->pContext, TC_TD, TT_ERROR, "TDIPX: client declared dead\n" )); /* * Report broken connection */ Command.Header.Command = ICA_COMMAND_BROKEN_CONNECTION; Command.BrokenConnection.Reason = Broken_Unexpected; (void) IcaChannelInput( pTd->pContext, Channel_Command, 0, NULL, (PCHAR) &Command, sizeof(Command) ); /* * Do not re-arm timer */ return; } /* * Make timeout 10 seconds */ Timeout = 10 * 1000; } /* * Check for valid file object */ if ( pTd->pFileObject == NULL ) goto badopen; ObReferenceObject(pTd->pFileObject); //Fix 416142 /* * Set up the default packet send type to be control */ ptype = IPX_TYPE_CONTROL; Status = _DoTdiAction( pTd->pFileObject, MIPX_SETSENDPTYPE, &ptype, 1 ); ASSERT( Status == STATUS_SUCCESS ); if ( !NT_SUCCESS( Status ) ) goto badtype; /* * Write ping to network */ Buffer[0] = IPX_CTRL_PACKET_PING; Status = _TdiSendDatagram( pTd, NULL, // Irp pTd->pFileObject, pTd->pDeviceObject, pEndpoint->SendInfo.RemoteAddress, pEndpoint->SendInfo.RemoteAddressLength, Buffer, 1 ); ASSERT( Status == STATUS_SUCCESS || Status == STATUS_CTX_CLOSE_PENDING ); TRACEBUF(( pTd->pContext, TC_TD, TT_ORAW, Buffer, 1 )); /* * Reset address endpoint to send data packets */ ptype = IPX_TYPE_DATA; Status = _DoTdiAction( pTd->pFileObject, MIPX_SETSENDPTYPE, &ptype, 1 ); ASSERT( Status == STATUS_SUCCESS ); /* * Dereference the TDI file object and close the handle */ ObDereferenceObject(pTd->pFileObject); //Fix 416142 badtype: /* * Increment counter */ pTdIpx->AlivePoll++; /* * Increment number of byte written */ pTd->pStatus->Output.Bytes++; /* * Reset alive bit */ clientok: pTdIpx->fClientAlive = FALSE; /* * Re-arm timer */ badopen: IcaTimerStart( pTdIpx->pAliveTimer, WatchDogTimer, NULL, Timeout, ICALOCK_DRIVER ); }