SM: change the way sessions are managed.
[reactos.git] / reactos / subsys / smss / client.c
index 212e333..94e52b7 100644 (file)
@@ -39,9 +39,11 @@ struct _SM_CLIENT_DIRECTORY
        RTL_CRITICAL_SECTION  Lock;\r
        ULONG                 Count;\r
        PSM_CLIENT_DATA       Client;\r
+       PSM_CLIENT_DATA       CandidateClient;\r
 \r
 } SmpClientDirectory;\r
 \r
+\r
 /**********************************************************************\r
  *     SmInitializeClientManagement/0\r
  */\r
@@ -52,56 +54,41 @@ SmInitializeClientManagement (VOID)
        RtlInitializeCriticalSection(& SmpClientDirectory.Lock);\r
        SmpClientDirectory.Count = 0;\r
        SmpClientDirectory.Client = NULL;\r
+       SmpClientDirectory.CandidateClient = NULL;\r
        return STATUS_SUCCESS;\r
 \r
 }\r
-\r
 /**********************************************************************\r
- *     SmCompleteClientInitialization/1\r
- *\r
- * DESCRIPTION\r
- *     Lookup the subsystem server descriptor given the process handle\r
- *     of the subsystem server process.\r
+ * SmpSetClientInitialized/1\r
  */\r
-NTSTATUS STDCALL\r
-SmCompleteClientInitialization (HANDLE hProcess)\r
+VOID FASTCALL\r
+SmpSetClientInitialized (PSM_CLIENT_DATA Client)\r
 {\r
-       NTSTATUS        Status = STATUS_SUCCESS;\r
-       PSM_CLIENT_DATA Client = NULL;\r
-\r
-       DPRINT("SM: %s called\n", __FUNCTION__);\r
-\r
-       RtlEnterCriticalSection (& SmpClientDirectory.Lock);\r
-       if (SmpClientDirectory.Count > 0)\r
-       {\r
-               Client = SmpClientDirectory.Client;\r
-               while (NULL != Client)\r
-               {\r
-                       if (hProcess == Client->ServerProcess)\r
-                       {\r
-                               Client->Initialized = TRUE;\r
-                               break;\r
-                       }\r
-                       Client = Client->Next;\r
-               }\r
-               Status = STATUS_NOT_FOUND;\r
-       }\r
-       RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
-       return Status;\r
+       Client->Flags |= SM_CLIENT_FLAG_INITIALIZED;\r
 }\r
-\r
 /**********************************************************************\r
- *     SmpLookupClient/1                                       PRIVATE\r
+ *     SmpLookupClient/2                                       PRIVATE\r
  *\r
  * DESCRIPTION\r
  *     Lookup the subsystem server descriptor given its image ID.\r
  *\r
- * SIDE EFFECTS\r
- *     SmpClientDirectory.Lock is released only on success.\r
+ * ARGUMENTS\r
+ *     SubsystemId: IMAGE_SUBSYSTEM_xxx\r
+ *     Parent: optional: caller provided storage for the\r
+ *             the pointer to the SM_CLIENT_DATA which\r
+ *             Next field contains the value returned by\r
+ *             the function (on success).\r
+ *\r
+ * RETURN VALUES\r
+ *     NULL on error; otherwise a pointer to the SM_CLIENT_DATA\r
+ *     looked up object.\r
+ *\r
+ * WARNING\r
+ *     SmpClientDirectory.Lock must be held by the caller.\r
  */\r
 static PSM_CLIENT_DATA FASTCALL\r
-SmpLookupClientUnsafe (USHORT           SubsystemId,\r
-                      PSM_CLIENT_DATA  * Parent)\r
+SmpLookupClient (USHORT           SubsystemId,\r
+                PSM_CLIENT_DATA  * Parent)\r
 {\r
        PSM_CLIENT_DATA Client = NULL;\r
 \r
@@ -129,72 +116,86 @@ SmpLookupClientUnsafe (USHORT           SubsystemId,
        }\r
        return Client;\r
 }\r
-\r
-static PSM_CLIENT_DATA STDCALL\r
-SmpLookupClient (USHORT SubsystemId)\r
-{\r
-       PSM_CLIENT_DATA Client = NULL;\r
-\r
-       DPRINT("SM: %s called\n", __FUNCTION__);\r
-\r
-       RtlEnterCriticalSection (& SmpClientDirectory.Lock);\r
-       Client = SmpLookupClientUnsafe (SubsystemId, NULL);\r
-       if(NULL != Client)\r
-       {\r
-               RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
-       }\r
-       /*\r
-        * Note that we do *not* release SmpClientDirectory.Lock here\r
-        * because SmpLookupClient is called to FAIL when SubsystemId\r
-        * is not registered yet.\r
-        */\r
-       return Client;\r
-}\r
-\r
 /**********************************************************************\r
- *     SmpCreateClient/2\r
+ *     SmBeginClientInitialization/1\r
+ *\r
+ * DESCRIPTION\r
+ *     Check if the candidate client matches the begin session\r
+ *     message from the subsystem process.\r
+ *\r
+ * ARGUMENTS\r
+ *     Request: message received by \SmApiPort\r
+ *     ClientData:\r
+ *             \r
+ * RETURN VALUES\r
+ *     NTSTATUS\r
  */\r
 NTSTATUS STDCALL\r
-SmCreateClient(PSM_PORT_MESSAGE Request, PSM_CLIENT_DATA * ClientData)\r
+SmBeginClientInitialization (IN  PSM_PORT_MESSAGE Request,\r
+                            OUT PSM_CLIENT_DATA  * ClientData)\r
 {\r
-       PSM_CLIENT_DATA pClient = NULL;\r
+       NTSTATUS Status = STATUS_SUCCESS;\r
        PSM_CONNECT_DATA ConnectData = SmpGetConnectData (Request);\r
        ULONG SbApiPortNameSize = SM_CONNECT_DATA_SIZE(*Request);\r
 \r
-       DPRINT("SM: %s called\n", __FUNCTION__);\r
 \r
+       DPRINT("SM: %s called\n", __FUNCTION__);\r
+       \r
+       RtlEnterCriticalSection (& SmpClientDirectory.Lock);\r
+       /*\r
+        * Is there a subsystem bootstrap in progress?\r
+        */\r
+       if (SmpClientDirectory.CandidateClient)\r
+       {\r
+               PROCESS_BASIC_INFORMATION pbi;\r
+               \r
+               RtlZeroMemory (& pbi, sizeof pbi);\r
+               Status = NtQueryInformationProcess (Request->Header.ClientId.UniqueProcess,\r
+                                                   ProcessBasicInformation,\r
+                                                   & pbi,\r
+                                                   sizeof pbi,\r
+                                                   NULL);\r
+               if (NT_SUCCESS(Status))\r
+               {\r
+                       SmpClientDirectory.CandidateClient->ServerProcessId =\r
+                               (ULONG) pbi.UniqueProcessId;\r
+               }\r
+       }\r
+       else\r
+       {\r
+               RtlFreeHeap (SmpHeap, 0, SmpClientDirectory.CandidateClient);\r
+               DPRINT1("SM: %s: subsys booting with no descriptor!\n", __FUNCTION__);\r
+               Status = STATUS_NOT_FOUND;\r
+               RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
+               return Status;          \r
+       }\r
        /*\r
         * Check if a client for the ID already exist.\r
         */\r
-       if (SmpLookupClient(ConnectData->SubSystemId))\r
+       if (SmpLookupClient(ConnectData->SubSystemId, NULL))\r
        {\r
                DPRINT("SM: %s: attempt to register again subsystem %d.\n",\r
                        __FUNCTION__,\r
                        ConnectData->SubSystemId);\r
                return STATUS_UNSUCCESSFUL;\r
        }\r
-       DPRINT("SM: %s: registering subsystem ID=%d \n", __FUNCTION__, ConnectData->SubSystemId);\r
-       /*\r
-        * Allocate the storage for client data\r
-        */\r
-       pClient = RtlAllocateHeap (SmpHeap,\r
-                                  HEAP_ZERO_MEMORY,\r
-                                  sizeof (SM_CLIENT_DATA));\r
-       if (NULL == pClient)\r
-       {\r
-               DPRINT("SM: %s: out of memory!\n",__FUNCTION__);\r
-               return STATUS_NO_MEMORY;\r
-       }\r
+       DPRINT("SM: %s: registering subsystem ID=%d \n",\r
+               __FUNCTION__, ConnectData->SubSystemId);\r
+\r
        /*\r
         * Initialize the client data\r
         */\r
-       pClient->SubsystemId = ConnectData->SubSystemId;\r
-       /* SM auto-initializes; other subsystems are required to call\r
+       SmpClientDirectory.CandidateClient->SubsystemId = ConnectData->SubSystemId;\r
+       /* SM && DBG auto-initializes; other subsystems are required to call\r
         * SM_API_COMPLETE_SESSION via SMDLL. */\r
-       pClient->Initialized = (IMAGE_SUBSYSTEM_NATIVE == pClient->SubsystemId);\r
+       if ((IMAGE_SUBSYSTEM_NATIVE == SmpClientDirectory.CandidateClient->SubsystemId) ||\r
+           (IMAGE_SUBSYSTEM_UNKNOWN == SmpClientDirectory.CandidateClient->SubsystemId))\r
+       {\r
+               SmpSetClientInitialized (SmpClientDirectory.CandidateClient);\r
+       }\r
        if (SbApiPortNameSize > 0)\r
        {\r
-               RtlCopyMemory (pClient->SbApiPortName,\r
+               RtlCopyMemory (SmpClientDirectory.CandidateClient->SbApiPortName,\r
                               ConnectData->SbName,\r
                               SbApiPortNameSize);\r
        }\r
@@ -204,28 +205,132 @@ SmCreateClient(PSM_PORT_MESSAGE Request, PSM_CLIENT_DATA * ClientData)
         */\r
        if (NULL == SmpClientDirectory.Client)\r
        {\r
-               SmpClientDirectory.Client = pClient;\r
+               SmpClientDirectory.Client = SmpClientDirectory.CandidateClient;\r
        } else {\r
                PSM_CLIENT_DATA pCD = NULL;\r
 \r
                for (pCD=SmpClientDirectory.Client;\r
                        (NULL != pCD->Next);\r
                        pCD = pCD->Next);\r
-               pCD->Next = pClient;\r
+               pCD->Next = SmpClientDirectory.CandidateClient;\r
        }\r
-       pClient->Next = NULL;\r
+       SmpClientDirectory.CandidateClient->Next = NULL;\r
+       /*\r
+        * Increment the number of active subsystems.\r
+        */\r
        ++ SmpClientDirectory.Count;\r
        /*\r
-        * Note we unlock the client directory here, because\r
-        * it was locked by SmpLookupClient on failure.\r
+        * Notify to the caller the reference to the client data.\r
         */\r
-       RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
        if (ClientData) \r
        {\r
-               *ClientData = pClient;\r
+               *ClientData = SmpClientDirectory.CandidateClient;\r
        }\r
+       /*\r
+        * Free the slot for the candidate subsystem.\r
+        */\r
+       SmpClientDirectory.CandidateClient = NULL;\r
+\r
+       RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
+       \r
        return STATUS_SUCCESS;\r
 }\r
+/**********************************************************************\r
+ *     SmCompleteClientInitialization/1\r
+ *\r
+ * DESCRIPTION\r
+ *     Lookup the subsystem server descriptor given the process ID\r
+ *     of the subsystem server process.\r
+ */\r
+NTSTATUS STDCALL\r
+SmCompleteClientInitialization (ULONG ProcessId)\r
+{\r
+       NTSTATUS        Status = STATUS_SUCCESS;\r
+       PSM_CLIENT_DATA Client = NULL;\r
+\r
+       DPRINT("SM: %s called\n", __FUNCTION__);\r
+\r
+       RtlEnterCriticalSection (& SmpClientDirectory.Lock);\r
+       if (SmpClientDirectory.Count > 0)\r
+       {\r
+               Client = SmpClientDirectory.Client;\r
+               while (NULL != Client)\r
+               {\r
+                       if (ProcessId == Client->ServerProcessId)\r
+                       {\r
+                               SmpSetClientInitialized (Client);\r
+                               break;\r
+                       }\r
+                       Client = Client->Next;\r
+               }\r
+               Status = STATUS_NOT_FOUND;\r
+       }\r
+       RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
+       return Status;\r
+}\r
+\r
+/**********************************************************************\r
+ *     SmpCreateClient/1\r
+ *\r
+ * DESCRIPTION\r
+ *     Create a "candidate" client. Client descriptor will enter the\r
+ *     client directory only at the end of the registration\r
+ *     procedure. Otherwise, we will kill the associated process.\r
+ *\r
+ * ARGUMENTS\r
+ *     ProcessHandle: handle of the subsystem server process.\r
+ *\r
+ * RETURN VALUE\r
+ *     NTSTATUS:\r
+ */\r
+NTSTATUS STDCALL\r
+SmCreateClient (PRTL_PROCESS_INFO ProcessInfo, PWSTR ProgramName)\r
+{\r
+       NTSTATUS Status = STATUS_SUCCESS;\r
+\r
+       \r
+       DPRINT("SM: %s(%lx) called\n", __FUNCTION__, ProcessInfo->ProcessHandle);\r
+       RtlEnterCriticalSection (& SmpClientDirectory.Lock);\r
+       /*\r
+        * Check if the candidate client slot is empty.\r
+        */\r
+       if (NULL != SmpClientDirectory.CandidateClient)\r
+       {\r
+               DPRINT1("SM: %s: CandidateClient pending!\n", __FUNCTION__);\r
+               RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
+               return STATUS_UNSUCCESSFUL;\r
+       }\r
+       /*\r
+        * Allocate the storage for client data\r
+        */\r
+       SmpClientDirectory.CandidateClient =\r
+               RtlAllocateHeap (SmpHeap,\r
+                                HEAP_ZERO_MEMORY,\r
+                                sizeof (SM_CLIENT_DATA));\r
+       if (NULL == SmpClientDirectory.CandidateClient)\r
+       {\r
+               DPRINT("SM: %s(%lx): out of memory!\n",\r
+                       __FUNCTION__, ProcessInfo->ProcessHandle);\r
+               Status = STATUS_NO_MEMORY;\r
+       }\r
+       else\r
+       {\r
+               /* Initialize the candidate client. */\r
+               RtlInitializeCriticalSection(& SmpClientDirectory.CandidateClient->Lock);\r
+               SmpClientDirectory.CandidateClient->ServerProcess =\r
+                       (HANDLE) ProcessInfo->ProcessHandle;\r
+               SmpClientDirectory.CandidateClient->ServerProcessId = \r
+                       (ULONG) ProcessInfo->ClientId.UniqueProcess;\r
+       }\r
+       /*\r
+        * Copy the program name\r
+        */\r
+       RtlCopyMemory (SmpClientDirectory.CandidateClient->ProgramName,\r
+                      ProgramName,\r
+                      SM_SB_NAME_MAX_LENGTH);\r
+       RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
+       return Status;\r
+}\r
 \r
 /**********************************************************************\r
  *     SmpDestroyClient/1\r
@@ -244,7 +349,7 @@ SmDestroyClient (ULONG SubsystemId)
        DPRINT("SM: %s called\n", __FUNCTION__);\r
 \r
        RtlEnterCriticalSection (& SmpClientDirectory.Lock);\r
-       Client = SmpLookupClientUnsafe (SubsystemId, & Parent);\r
+       Client = SmpLookupClient (SubsystemId, & Parent);\r
        if(NULL == Client)\r
        {\r
                DPRINT1("SM: %s: del req for non existent subsystem (id=%d)\n",\r
@@ -269,6 +374,7 @@ SmDestroyClient (ULONG SubsystemId)
                        }\r
                }\r
                /* TODO: send shutdown or kill */\r
+               NtTerminateProcess (Client->ServerProcess, 0); //FIXME\r
                RtlFreeHeap (SmpHeap, 0, Client);\r
                -- SmpClientDirectory.Count;\r
        }\r
@@ -285,7 +391,7 @@ NTSTATUS FASTCALL
 SmGetClientBasicInformation (PSM_BASIC_INFORMATION i)\r
 {\r
        INT              Index = 0;\r
-       PSM_CLIENT_DATA  Client = NULL;\r
+       PSM_CLIENT_DATA  ClientData = NULL;\r
 \r
        DPRINT("SM: %s called\n", __FUNCTION__);\r
 \r
@@ -296,13 +402,13 @@ SmGetClientBasicInformation (PSM_BASIC_INFORMATION i)
        \r
        if (SmpClientDirectory.Count > 0)\r
        {\r
-               Client = SmpClientDirectory.Client;\r
-               while ((NULL != Client) && (Index < SM_QRYINFO_MAX_SS_COUNT))\r
+               ClientData = SmpClientDirectory.Client;\r
+               while ((NULL != ClientData) && (Index < SM_QRYINFO_MAX_SS_COUNT))\r
                {\r
-                       i->SubSystem[Index].Id        = Client->SubsystemId;\r
-                       i->SubSystem[Index].Flags     = 0; /* TODO */\r
-                       i->SubSystem[Index].ProcessId = 0; /* TODO */\r
-                       Client = Client->Next;\r
+                       i->SubSystem[Index].Id        = ClientData->SubsystemId;\r
+                       i->SubSystem[Index].Flags     = ClientData->Flags;\r
+                       i->SubSystem[Index].ProcessId = ClientData->ServerProcessId;\r
+                       ClientData = ClientData->Next;\r
                }\r
        }\r
 \r
@@ -316,9 +422,27 @@ SmGetClientBasicInformation (PSM_BASIC_INFORMATION i)
 NTSTATUS FASTCALL\r
 SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION i)\r
 {\r
+       NTSTATUS         Status = STATUS_SUCCESS;\r
+       PSM_CLIENT_DATA  ClientData = NULL;\r
+       \r
        DPRINT("SM: %s called\n", __FUNCTION__);\r
 \r
-       return STATUS_NOT_IMPLEMENTED;\r
+       RtlEnterCriticalSection (& SmpClientDirectory.Lock);\r
+       ClientData = SmpLookupClient (i->SubSystemId, NULL);\r
+       if (NULL == ClientData)\r
+       {\r
+               Status = STATUS_NOT_FOUND;\r
+       }\r
+       else\r
+       {\r
+               i->Flags     = ClientData->Flags;\r
+               i->ProcessId = ClientData->ServerProcessId;\r
+               RtlCopyMemory (i->NameSpaceRootNode,\r
+                               ClientData->SbApiPortName,\r
+                               (SM_QRYINFO_MAX_ROOT_NODE * sizeof(i->NameSpaceRootNode[0])));\r
+       }\r
+       RtlLeaveCriticalSection (& SmpClientDirectory.Lock);\r
+       return Status;\r
 }\r
 \r
 /* EOF */\r