⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 api.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * COPYRIGHT:       See COPYING in the top level directory
 * PROJECT:         ReactOS CSR Sub System
 * FILE:            subsys/csr/csrsrv/api.c
 * PURPOSE:         CSR Server DLL API LPC Implementation
 * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
 */

/* INCLUDES ******************************************************************/

#include "srv.h"

#define NDEBUG
#include <debug.h>

/* DATA **********************************************************************/
BOOLEAN (*CsrClientThreadSetup)(VOID) = NULL;
ULONG CsrMaxApiRequestThreads;
UNICODE_STRING CsrSbApiPortName;
UNICODE_STRING CsrApiPortName;
HANDLE CsrSbApiPort;
HANDLE CsrApiPort;
PCSR_THREAD CsrSbApiRequestThreadPtr;
ULONG CsrpStaticThreadCount;
ULONG CsrpDynamicThreadTotal;

/* PRIVATE FUNCTIONS *********************************************************/

/*++
 * @name CsrCheckRequestThreads
 *
 * The CsrCheckRequestThreads routine checks if there are no more threads
 * to handle CSR API Requests, and creates a new thread if possible, to
 * avoid starvation.
 *
 * @param None.
 *
 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
 *         if a new thread couldn't be created.
 *
 * @remarks None.
 *
 *--*/
NTSTATUS
NTAPI
CsrCheckRequestThreads(VOID)
{
    HANDLE hThread;
    CLIENT_ID ClientId;
    NTSTATUS Status;

    /* Decrease the count, and see if we're out */
    if (!(InterlockedDecrement(&CsrpStaticThreadCount)))
    {
        /* Check if we've still got space for a Dynamic Thread */
        if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads)
        {
            /* Create a new dynamic thread */
            Status = RtlCreateUserThread(NtCurrentProcess(),
                                         NULL,
                                         TRUE,
                                         0,
                                         0,
                                         0,
                                         (PVOID)CsrApiRequestThread,
                                         NULL,
                                         &hThread,
                                         &ClientId);
            /* Check success */
            if(NT_SUCCESS(Status))
            {
                /* Increase the thread counts */
                CsrpStaticThreadCount++;
                CsrpDynamicThreadTotal++;

                /* Add a new server thread */
                if (CsrAddStaticServerThread(hThread,
                                             &ClientId,
                                             CsrThreadIsServerThread))
                {
                    /* Activate it */
                    NtResumeThread(hThread,NULL);
                }
                else
                {
                    /* Failed to create a new static thread */
                    CsrpStaticThreadCount--;
                    CsrpDynamicThreadTotal--;

                    /* Terminate it */
                    NtTerminateThread(hThread,0);
                    NtClose(hThread);

                    /* Return */
                    return STATUS_UNSUCCESSFUL;
                }
            }
        }
    }

    /* Success */
    return STATUS_SUCCESS;
}

/*++
 * @name CsrSbApiPortInitialize
 *
 * The CsrSbApiPortInitialize routine initializes the LPC Port used for
 * communications with the Session Manager (SM) and initializes the static
 * thread that will handle connection requests and APIs.
 *
 * @param None
 *
 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
 *         othwerwise.
 *
 * @remarks None.
 *
 *--*/
NTSTATUS
NTAPI
CsrSbApiPortInitialize(VOID)
{
    ULONG Size;
    PSECURITY_DESCRIPTOR PortSd;
    OBJECT_ATTRIBUTES ObjectAttributes;
    NTSTATUS Status;
    HANDLE hRequestThread;
    CLIENT_ID ClientId;

    /* Calculate how much space we'll need for the Port Name */
    Size = CsrDirectoryName.Length + sizeof(SB_PORT_NAME) + sizeof(WCHAR);

    /* Allocate space for it, and create it */
    CsrSbApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
    CsrSbApiPortName.Length = 0;
    CsrSbApiPortName.MaximumLength = (USHORT)Size;
    RtlAppendUnicodeStringToString(&CsrSbApiPortName, &CsrDirectoryName);
    RtlAppendUnicodeToString(&CsrSbApiPortName, UNICODE_PATH_SEP);
    RtlAppendUnicodeToString(&CsrSbApiPortName, SB_PORT_NAME);

    /* Create Security Descriptor for this Port */
    CsrCreateLocalSystemSD(&PortSd);

    /* Initialize the Attributes */
    InitializeObjectAttributes(&ObjectAttributes,
                               &CsrSbApiPortName,
                               0,
                               PortSd,
                               NULL);

    /* Create the Port Object */
    Status = NtCreatePort(&CsrSbApiPort,
                          &ObjectAttributes,
                          sizeof(SB_CONNECTION_INFO),
                          sizeof(SB_API_MESSAGE),
                          32 * sizeof(SB_API_MESSAGE));
    if(!NT_SUCCESS(Status))
    {

    }

    /* Create the Thread to handle the API Requests */
    Status = RtlCreateUserThread(NtCurrentProcess(),
                                 NULL,
                                 TRUE,
                                 0,
                                 0,
                                 0,
                                 (PVOID)CsrSbApiRequestThread,
                                 NULL,
                                 &hRequestThread,
                                 &ClientId);
    if(!NT_SUCCESS(Status))
    {

    }

    /* Add it as a Static Server Thread */
    CsrSbApiRequestThreadPtr = CsrAddStaticServerThread(hRequestThread,
                                                        &ClientId,
                                                        0);

    /* Activate it */
    return NtResumeThread(hRequestThread, NULL);
}

/*++
 * @name CsrApiPortInitialize
 *
 * The CsrApiPortInitialize routine initializes the LPC Port used for
 * communications with the Client/Server Runtime (CSR) and initializes the
 * static thread that will handle connection requests and APIs.
 *
 * @param None
 *
 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
 *         othwerwise.
 *
 * @remarks None.
 *
 *--*/
NTSTATUS
NTAPI
CsrApiPortInitialize(VOID)
{
    ULONG Size;
    OBJECT_ATTRIBUTES ObjectAttributes;
    NTSTATUS Status;
    HANDLE hRequestEvent, hThread;
    CLIENT_ID ClientId;
    PLIST_ENTRY ListHead, NextEntry;
    PCSR_THREAD ServerThread;

    /* Calculate how much space we'll need for the Port Name */
    Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);

    /* Allocate space for it, and create it */
    CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
    CsrApiPortName.Length = 0;
    CsrApiPortName.MaximumLength = (USHORT)Size;
    RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
    RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
    RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);

    /* FIXME: Create a Security Descriptor */

    /* Initialize the Attributes */
    InitializeObjectAttributes(&ObjectAttributes,
                               &CsrApiPortName,
                               0,
                               NULL,
                               NULL /* FIXME*/);

    /* Create the Port Object */
    Status = NtCreatePort(&CsrApiPort,
                          &ObjectAttributes,
                          sizeof(CSR_CONNECTION_INFO),
                          sizeof(CSR_API_MESSAGE),
                          16 * PAGE_SIZE);
    if(!NT_SUCCESS(Status))
    {

    }

    /* Create the event the Port Thread will use */
    Status = NtCreateEvent(&hRequestEvent,
                           EVENT_ALL_ACCESS,
                           NULL,
                           SynchronizationEvent,
                           FALSE);
    if(!NT_SUCCESS(Status))
    {

    }

    /* Create the Request Thread */
    Status = RtlCreateUserThread(NtCurrentProcess(),
                                 NULL,
                                 TRUE,
                                 0,
                                 0,
                                 0,
                                 (PVOID)CsrApiRequestThread,
                                 (PVOID)hRequestEvent,
                                 &hThread,
                                 &ClientId);
    if(!NT_SUCCESS(Status))
    {

    }

    /* Add this as a static thread to CSRSRV */
    CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);

    /* Get the Thread List Pointers */
    ListHead = &CsrRootProcess->ThreadList;
    NextEntry = ListHead->Flink;

    /* Start looping the list */
    while (NextEntry != ListHead)
    {
        /* Get the Thread */
        ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);

        /* Start it up */
        Status = NtResumeThread(ServerThread->ThreadHandle, NULL);

        /* Is this a Server Thread? */
        if (ServerThread->Flags & CsrThreadIsServerThread)
        {
            /* If so, then wait for it to initialize */
            NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
        }

        /* Next thread */
        NextEntry = NextEntry->Flink;
    }

    /* We don't need this anymore */
    NtClose(hRequestEvent);

    /* Return */
    return Status;
}

/*++
 * @name CsrApiRequestThread
 *
 * The CsrApiRequestThread routine handles incoming messages or connection
 * requests on the CSR API LPC Port.
 *
 * @param Parameter
 *        System-default user-defined parameter. Unused.
 *
 * @return The thread exit code, if the thread is terminated.
 *
 * @remarks Before listening on the port, the routine will first attempt
 *          to connect to the user subsystem.
 *
 *--*/
NTSTATUS
NTAPI
CsrApiRequestThread(IN PVOID Parameter)
{
    PTEB Teb = NtCurrentTeb();
    LARGE_INTEGER TimeOut;
    PCSR_THREAD CurrentThread;
    NTSTATUS Status;
    PCSR_API_MESSAGE ReplyMsg = NULL;
    CSR_API_MESSAGE ReceiveMsg;
    PCSR_THREAD CsrThread;
    PCSR_PROCESS CsrProcess;
    PHARDERROR_MSG HardErrorMsg;
    PVOID PortContext;
    ULONG MessageType;
    ULONG i;
    PCSR_SERVER_DLL ServerDll;
    PCLIENT_DIED_MSG ClientDiedMsg;
    PDBGKM_MSG DebugMessage;
    ULONG ServerId, ApiId;
    ULONG Reply;

    /* Probably because of the way GDI is loaded, this has to be done here */
    Teb->GdiClientPID = HandleToUlong(Teb->Cid.UniqueProcess);
    Teb->GdiClientTID = HandleToUlong(Teb->Cid.UniqueThread);

    /* Set up the timeout for the connect (30 seconds) */
    TimeOut.QuadPart = -30 * 1000 * 1000 * 10;

    /* Connect to user32 */
    while (!CsrConnectToUser())
    {
        /* Keep trying until we get a response */
        Teb->Win32ClientInfo[0] = 0;
        NtDelayExecution(FALSE, &TimeOut);
    }

    /* Get our thread */
    CurrentThread = Teb->CsrClientThread;

    /* If we got an event... */
    if (Parameter)
    {
        /* Set it, to let stuff waiting on us load */
        NtSetEvent((HANDLE)Parameter, NULL);

        /* Increase the Thread Counts */
        InterlockedIncrement(&CsrpStaticThreadCount);
        InterlockedIncrement(&CsrpDynamicThreadTotal);
    }

    /* Now start the loop */
    while (TRUE)
    {
        /* Make sure the real CID is set */
        Teb->RealClientId = Teb->Cid;

        /* Wait for a message to come through */
        Status = NtReplyWaitReceivePort(CsrApiPort,
                                        &PortContext,
                                        (PPORT_MESSAGE)ReplyMsg,
                                        (PPORT_MESSAGE)&ReceiveMsg);

        /* Check if we didn't get success */
        if(Status != STATUS_SUCCESS)
        {
            /* If we only got a warning, keep going */
            if (NT_SUCCESS(Status)) continue;

            /* We failed big time, so start out fresh */
            ReplyMsg = NULL;
            continue;
        }

        /* Use whatever Client ID we got */
        Teb->RealClientId = ReceiveMsg.Header.ClientId;

        /* Get the Message Type */
        MessageType = ReceiveMsg.Header.u2.s2.Type;

        /* Handle connection requests */
        if (MessageType == LPC_CONNECTION_REQUEST)
        {
            /* Handle the Connection Request */
            CsrApiHandleConnectionRequest(&ReceiveMsg);
            ReplyMsg = NULL;
            continue;
        }

        /* It's some other kind of request. Get the lock for the lookup*/
        CsrAcquireProcessLock();

        /* Now do the lookup to get the CSR_THREAD */
        CsrThread = CsrLocateThreadByClientId(&CsrProcess,
                                              &ReceiveMsg.Header.ClientId);

        /* Did we find a thread? */
        if(!CsrThread)
        {
            /* This wasn't a CSR Thread, release lock */
            CsrReleaseProcessLock();

            /* If this was an exception, handle it */
            if (MessageType == LPC_EXCEPTION)
            {
                ReplyMsg = &ReceiveMsg;
                ReplyMsg->Status = DBG_CONTINUE;
            }
            else if (MessageType == LPC_PORT_CLOSED ||
                     MessageType == LPC_CLIENT_DIED)
            {
                /* The Client or Port are gone, loop again */
                ReplyMsg = NULL;
            }
            else if (MessageType == LPC_ERROR_EVENT)
            {
                /* If it's a hard error, handle this too */
                HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;

                /* Default it to unhandled */
                HardErrorMsg->Response = ResponseNotHandled;

                /* Check if there are free api threads */
                CsrCheckRequestThreads();
                if (CsrpStaticThreadCount)
                {
                    /* Loop every Server DLL */
                    for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
                    {
                        /* Get the Server DLL */
                        ServerDll = CsrLoadedServerDll[i];

                        /* Check if it's valid and if it has a Hard Error Callback */
                        if (ServerDll && ServerDll->HardErrorCallback)
                        {
                            /* Call it */
                            (*ServerDll->HardErrorCallback)(CsrThread, HardErrorMsg);

                            /* If it's handled, get out of here */
                            if (HardErrorMsg->Response != ResponseNotHandled) break;
                        }
                    }
                }

                /* Increase the thread count */
                InterlockedIncrement(&CsrpStaticThreadCount);

                /* If the response was 0xFFFFFFFF, we'll ignore it */
                if (HardErrorMsg->Response == 0xFFFFFFFF)
                {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -