Ejemplo n.º 1
0
NTSTATUS PhpServiceNonPollThreadStart(
    _In_ PVOID Parameter
    )
{
    ULONG result;
    SC_HANDLE scManagerHandle;
    LPENUM_SERVICE_STATUS_PROCESS services;
    ULONG numberOfServices;
    ULONG i;
    PLIST_ENTRY listEntry;
    PPHP_SERVICE_NOTIFY_CONTEXT notifyContext;

    if (!NT_SUCCESS(NtCreateEvent(&PhpNonPollEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))
    {
        PhpNonPollActive = FALSE;
        PhpNonPollGate = 1;
        return STATUS_UNSUCCESSFUL;
    }

    while (TRUE)
    {
        scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);

        if (!scManagerHandle)
            goto ErrorExit;

        InitializeListHead(&PhpNonPollServiceListHead);
        InitializeListHead(&PhpNonPollServicePendingListHead);

        if (!(services = PhEnumServices(scManagerHandle, 0, 0, &numberOfServices)))
            goto ErrorExit;

        for (i = 0; i < numberOfServices; i++)
        {
            SC_HANDLE serviceHandle;

            if (serviceHandle = OpenService(scManagerHandle, services[i].lpServiceName, SERVICE_QUERY_STATUS))
            {
                notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT));
                memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT));
                notifyContext->ServiceHandle = serviceHandle;
                notifyContext->State = SnNotify;
                InsertTailList(&PhpNonPollServicePendingListHead, &notifyContext->ListEntry);
            }
        }

        PhFree(services);

        notifyContext = PhAllocate(sizeof(PHP_SERVICE_NOTIFY_CONTEXT));
        memset(notifyContext, 0, sizeof(PHP_SERVICE_NOTIFY_CONTEXT));
        notifyContext->ServiceHandle = scManagerHandle;
        notifyContext->IsServiceManager = TRUE;
        notifyContext->State = SnNotify;
        InsertTailList(&PhpNonPollServicePendingListHead, &notifyContext->ListEntry);

        while (TRUE)
        {
            BOOLEAN lagging = FALSE;

            listEntry = PhpNonPollServicePendingListHead.Flink;

            while (listEntry != &PhpNonPollServicePendingListHead)
            {
                notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry);
                listEntry = listEntry->Flink;

                switch (notifyContext->State)
                {
                case SnNone:
                    break;
                case SnAdding:
                    notifyContext->ServiceHandle =
                        OpenService(scManagerHandle, notifyContext->ServiceName->Buffer, SERVICE_QUERY_STATUS);

                    if (!notifyContext->ServiceHandle)
                    {
                        RemoveEntryList(&notifyContext->ListEntry);
                        PhpDestroyServiceNotifyContext(notifyContext);
                        continue;
                    }

                    PhClearReference(&notifyContext->ServiceName);
                    notifyContext->State = SnNotify;
                    goto NotifyCase;
                case SnRemoving:
                    RemoveEntryList(&notifyContext->ListEntry);
                    PhpDestroyServiceNotifyContext(notifyContext);
                    break;
                case SnNotify:
NotifyCase:
                    memset(&notifyContext->Buffer, 0, sizeof(SERVICE_NOTIFY));
                    notifyContext->Buffer.dwVersion = SERVICE_NOTIFY_STATUS_CHANGE;
                    notifyContext->Buffer.pfnNotifyCallback = PhpServiceNonPollScNotifyCallback;
                    notifyContext->Buffer.pContext = notifyContext;
                    result = NotifyServiceStatusChangeW_I(
                        notifyContext->ServiceHandle,
                        notifyContext->IsServiceManager
                        ? (SERVICE_NOTIFY_CREATED | SERVICE_NOTIFY_DELETED)
                        : (SERVICE_NOTIFY_STOPPED | SERVICE_NOTIFY_START_PENDING | SERVICE_NOTIFY_STOP_PENDING |
                        SERVICE_NOTIFY_RUNNING | SERVICE_NOTIFY_CONTINUE_PENDING | SERVICE_NOTIFY_PAUSE_PENDING |
                        SERVICE_NOTIFY_PAUSED | SERVICE_NOTIFY_DELETE_PENDING),
                        &notifyContext->Buffer
                        );

                    switch (result)
                    {
                    case ERROR_SUCCESS:
                        notifyContext->State = SnNone;
                        RemoveEntryList(&notifyContext->ListEntry);
                        InsertTailList(&PhpNonPollServiceListHead, &notifyContext->ListEntry);
                        break;
                    case ERROR_SERVICE_NOTIFY_CLIENT_LAGGING:
                        // We are lagging behind. Re-open the handle to the SCM as soon as possible.
                        lagging = TRUE;
                        break;
                    case ERROR_SERVICE_MARKED_FOR_DELETE:
                    default:
                        RemoveEntryList(&notifyContext->ListEntry);
                        PhpDestroyServiceNotifyContext(notifyContext);
                        break;
                    }

                    break;
                }
            }

            while (NtWaitForSingleObject(PhpNonPollEventHandle, TRUE, NULL) != STATUS_WAIT_0)
                NOTHING;

            if (lagging)
                break;
        }

        // Execute all pending callbacks.
        NtTestAlert();

        listEntry = PhpNonPollServiceListHead.Flink;

        while (listEntry != &PhpNonPollServiceListHead)
        {
            notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry);
            listEntry = listEntry->Flink;
            PhpDestroyServiceNotifyContext(notifyContext);
        }

        listEntry = PhpNonPollServicePendingListHead.Flink;

        while (listEntry != &PhpNonPollServicePendingListHead)
        {
            notifyContext = CONTAINING_RECORD(listEntry, PHP_SERVICE_NOTIFY_CONTEXT, ListEntry);
            listEntry = listEntry->Flink;
            PhpDestroyServiceNotifyContext(notifyContext);
        }

        CloseServiceHandle(scManagerHandle);
    }

    NtClose(PhpNonPollEventHandle);

    return STATUS_SUCCESS;

ErrorExit:
    PhpNonPollActive = FALSE;
    PhpNonPollGate = 1;
    NtClose(PhpNonPollEventHandle);
    return STATUS_UNSUCCESSFUL;
}
Ejemplo n.º 2
0
void
main(
    int argc,
    char *argv[]
    )
{
    NTSTATUS status;
    OBJECT_ATTRIBUTES ObjectAttributes;
    HANDLE          BaseHandle;
    HANDLE          EventHandle;
    PIO_APC_ROUTINE ApcRoutine;

    //
    // Process args
    //

    KeyName.MaximumLength = WORK_SIZE;
    KeyName.Length = 0L;
    KeyName.Buffer = &(workbuffer[0]);

    processargs(argc, argv);

    //
    // Set up and open KeyPath
    //

    printf("rtnotify: starting\n");

    InitializeObjectAttributes(
        &ObjectAttributes,
        &KeyName,
        0,
        (HANDLE)NULL,
        NULL
        );
    ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE;

    status = NtOpenKey(
                &BaseHandle,
                KEY_NOTIFY,
                &ObjectAttributes
                );
    if (!NT_SUCCESS(status)) {
        printf("rtnotify: t0: %08lx\n", status);
        exit(1);
    }

    EventHandle = (HANDLE)NULL;
    if (UseEvent == TRUE) {
        status = NtCreateEvent(
                    &EventHandle,
                    GENERIC_READ | GENERIC_WRITE  | SYNCHRONIZE,
                    NULL,
                    NotificationEvent,
                    FALSE
                    );
        if (!NT_SUCCESS(status)) {
            printf("rtnotify: t1: %08lx\n", status);
            exit(1);
        }
    }

    ApcRoutine = NULL;
    if (UseApc) {
        ApcRoutine = ApcTest;
    }

    printf("rtnotify:\n");
    printf("\tUseEvent = %08lx\n", UseEvent);
    printf("\tApcRoutine = %08lx\n", ApcRoutine);
    printf("\tHold = %08lx\n", Hold);
    printf("\tFilter = %08lx\n", Filter);
    printf("\tWatchTree = %08lx\n", WatchTree);

    while (TRUE) {
        ApcSeen = FALSE;
        printf("\nCallCount = %dt\n", CallCount);
        CallCount++;
        status = NtNotifyChangeKey(
                    BaseHandle,
                    EventHandle,
                    ApcRoutine,
                    (PVOID)1992,           // arbitrary context value
                    &RtIoStatusBlock,
                    Filter,
                    WatchTree,
                    NULL,
                    0,
                    ! Hold
                    );

        exit(0);

        if ( ! NT_SUCCESS(status)) {
            printf("rtnotify: t2: %08lx\n", status);
            exit(1);
        }

        if (Hold) {
            printf("rtnotify: Synchronous Status = %08lx\n", RtIoStatusBlock.Status);
        }

        if (UseEvent) {
            status = NtWaitForSingleObject(
                        EventHandle,
                        TRUE,
                        NULL
                        );
            if (!NT_SUCCESS(status)) {
                printf("rtnotify: t3: status = %08lx\n", status);
                exit(1);
            }
            printf("rtnotify: Event Status = %08lx\n", RtIoStatusBlock.Status);
        }

        if (UseApc) {
            while ((volatile)ApcSeen == FALSE) {
                NtTestAlert();
            }
        }
    }

    NtClose(BaseHandle);
    exit(0);
}