summaryrefslogblamecommitdiffstats
path: root/private/ntos/tdi/acd/timer.c
blob: cf4f3ab633588d23835b2609a3e16af6fe44ef08 (plain) (tree)
















































































































































                                                                                                          
/*++

Copyright (c) 1995 Microsoft Corporation

Module Name:

    timer.c

Abstract:

    Timer thread to monitor connection progress in the
    automatic connection driver (acd.sys).

Author:

    Anthony Discolo (adiscolo)  25-Apr-1995

Environment:

    Kernel Mode

Revision History:

--*/

#include <ndis.h>
#include <cxport.h>
#include <tdi.h>
#include <tdikrnl.h>
#include <tdistat.h>
#include <tdiinfo.h>
#include <acd.h>

#include "acdapi.h"
#include "table.h"
#include "acddefs.h"
#include "debug.h"

//
// Imported routines.
//
VOID
AcdSignalCompletionCommon(
    IN PACD_CONNECTION pConnection,
    IN BOOLEAN fSuccess
    );

//
// Keep track how long the user-space
// process has been attempting a connection.
//
#define ACD_MAX_TIMER_CALLS    3*60     // 3 minutes

//
// We give the user-space process
// some slack on missed pings.
//
#define ACD_MAX_MISSED_PINGS   40       // 20 seconds



VOID
AcdConnectionTimer(
    IN PDEVICE_OBJECT pDeviceObject,
    IN PVOID          pContext
    )
{
    PLIST_ENTRY pEntry;
    PACD_CONNECTION pConnection;
    BOOLEAN bCancel = FALSE;

    //
    // Acquire the spin lock.
    // We're guaranteed to be at DPC
    // since this is a timer routine.
    //
    KeAcquireSpinLockAtDpcLevel(&AcdSpinLockG);
    //
    // If the user-space process responsible
    // for creating the connection hasn't
    // pinged us in a while, or if it hasn't
    // created a connection in 3 minutes,
    // cancel all the pending requests.
    //
    for (pEntry = AcdConnectionQueueG.Flink;
         pEntry != &AcdConnectionQueueG;
         pEntry = pEntry->Flink)
    {
        pConnection = CONTAINING_RECORD(pEntry, ACD_CONNECTION, ListEntry);

        IF_ACDDBG(ACD_DEBUG_TIMER) {
            PACD_COMPLETION pCompletion;

            AcdPrint((
              "AcdConnectionTimer: pConnection=0x%x, fNotif=%d, szAddr=",
              pConnection,
              pConnection->fNotif));
            pCompletion = CONTAINING_RECORD(pConnection->CompletionList.Flink, ACD_COMPLETION, ListEntry);
            AcdPrintAddress(&pCompletion->notif.addr);
            AcdPrint((", nTimerCalls=%d, nMissedPings=%d\n",
              pConnection->ulTimerCalls,
              pConnection->ulMissedPings));
        }
        //
        // If we haven't reported the connection to
        // user space yet, or it is in the process of
        // being completed, then don't time it out.
        //
        if (!pConnection->fNotif || pConnection->fCompleting)
            continue;

        pConnection->ulTimerCalls++;
        if (pConnection->fProgressPing)
            pConnection->ulMissedPings = 0;
        else
            pConnection->ulMissedPings++;
        if (pConnection->ulTimerCalls >= ACD_MAX_TIMER_CALLS ||
            pConnection->ulMissedPings >= ACD_MAX_MISSED_PINGS)
        {
            IF_ACDDBG(ACD_DEBUG_TIMER) {
                AcdPrint((
                  "AcdConnectionTimer: canceling pConnection=0x%x\n",
                  pConnection));
            }
            //
            // Set the completion-in-progress flag so
            // this request cannot be completed after
            // we release the spin lock.
            //
            pConnection->fCompleting = TRUE;
            bCancel = TRUE;
            break;
        }
    }
    //
    // Release the spin lock.
    //
    KeReleaseSpinLockFromDpcLevel(&AcdSpinLockG);
    //
    // We now process all the canceled requests.
    //
    if (bCancel)
        AcdSignalCompletionCommon(pConnection, FALSE);
} // AcdConnectionTimer