3 * client.c - Session Manager client Management
5 * ReactOS Operating System
7 * --------------------------------------------------------------------
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
24 * --------------------------------------------------------------------
27 #include <sm/helper.h>
35 struct _SM_CLIENT_DIRECTORY
37 RTL_CRITICAL_SECTION Lock
;
39 PSM_CLIENT_DATA Client
;
40 PSM_CLIENT_DATA CandidateClient
;
45 /**********************************************************************
46 * SmInitializeClientManagement/0
49 SmInitializeClientManagement (VOID
)
51 DPRINT("SM: %s called\n", __FUNCTION__
);
52 RtlInitializeCriticalSection(& SmpClientDirectory
.Lock
);
53 SmpClientDirectory
.Count
= 0;
54 SmpClientDirectory
.Client
= NULL
;
55 SmpClientDirectory
.CandidateClient
= NULL
;
56 return STATUS_SUCCESS
;
59 /**********************************************************************
60 * SmpSetClientInitialized/1
63 SmpSetClientInitialized (PSM_CLIENT_DATA Client
)
65 DPRINT("SM: %s(%08lx) called\n", __FUNCTION__
, Client
);
66 Client
->Flags
|= SM_CLIENT_FLAG_INITIALIZED
;
68 /**********************************************************************
69 * SmpLookupClient/2 PRIVATE
72 * Lookup the subsystem server descriptor given its image ID.
75 * SubsystemId: IMAGE_SUBSYSTEM_xxx
76 * Parent: optional: caller provided storage for the
77 * the pointer to the SM_CLIENT_DATA which
78 * Next field contains the value returned by
79 * the function (on success).
82 * NULL on error; otherwise a pointer to the SM_CLIENT_DATA
86 * SmpClientDirectory.Lock must be held by the caller.
88 static PSM_CLIENT_DATA FASTCALL
89 SmpLookupClient (USHORT SubsystemId
,
90 PSM_CLIENT_DATA
* Parent
)
92 PSM_CLIENT_DATA Client
= NULL
;
94 DPRINT("SM: %s(%d) called\n", __FUNCTION__
, SubsystemId
);
100 if (SmpClientDirectory
.Count
> 0)
102 Client
= SmpClientDirectory
.Client
;
103 while (NULL
!= Client
)
105 DPRINT("SM: %s: Client==%08lx\n", __FUNCTION__
, Client
);
106 if (SubsystemId
== Client
->SubsystemId
)
108 DPRINT("SM: %s: FOUND Client==%08lx\n", __FUNCTION__
, Client
);
115 Client
= Client
->Next
;
120 /**********************************************************************
121 * SmBeginClientInitialization/1
124 * Check if the candidate client matches the begin session
125 * message from the subsystem process.
128 * Request: message received by \SmApiPort
135 SmBeginClientInitialization (IN PSM_PORT_MESSAGE Request
,
136 OUT PSM_CLIENT_DATA
* ClientData
)
138 NTSTATUS Status
= STATUS_SUCCESS
;
139 PSM_CONNECT_DATA ConnectData
= SmpGetConnectData (Request
);
140 ULONG SbApiPortNameSize
= SM_CONNECT_DATA_SIZE(*Request
);
143 DPRINT("SM: %s called\n", __FUNCTION__
);
145 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
147 * Is there a subsystem bootstrap in progress?
149 if (SmpClientDirectory
.CandidateClient
)
151 PROCESS_BASIC_INFORMATION pbi
;
153 RtlZeroMemory (& pbi
, sizeof pbi
);
154 Status
= NtQueryInformationProcess (Request
->Header
.ClientId
.UniqueProcess
,
155 ProcessBasicInformation
,
159 if (NT_SUCCESS(Status
))
161 SmpClientDirectory
.CandidateClient
->ServerProcessId
=
162 (ULONG
) pbi
.UniqueProcessId
;
167 RtlFreeHeap (SmpHeap
, 0, SmpClientDirectory
.CandidateClient
);
168 DPRINT1("SM: %s: subsys booting with no descriptor!\n", __FUNCTION__
);
169 Status
= STATUS_NOT_FOUND
;
170 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
174 * Check if a client for the ID already exist.
176 if (SmpLookupClient(ConnectData
->SubSystemId
, NULL
))
178 DPRINT("SM: %s: attempt to register again subsystem %d.\n",
180 ConnectData
->SubSystemId
);
181 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
182 return STATUS_UNSUCCESSFUL
;
184 DPRINT("SM: %s: registering subsystem ID=%d \n",
185 __FUNCTION__
, ConnectData
->SubSystemId
);
188 * Initialize the client data
190 SmpClientDirectory
.CandidateClient
->SubsystemId
= ConnectData
->SubSystemId
;
191 /* SM && DBG auto-initializes; other subsystems are required to call
192 * SM_API_COMPLETE_SESSION via SMDLL. */
193 if ((IMAGE_SUBSYSTEM_NATIVE
== SmpClientDirectory
.CandidateClient
->SubsystemId
) ||
194 (IMAGE_SUBSYSTEM_UNKNOWN
== SmpClientDirectory
.CandidateClient
->SubsystemId
))
196 SmpSetClientInitialized (SmpClientDirectory
.CandidateClient
);
198 if (SbApiPortNameSize
> 0)
200 RtlCopyMemory (SmpClientDirectory
.CandidateClient
->SbApiPortName
,
205 * Insert the new descriptor in the
208 if (NULL
== SmpClientDirectory
.Client
)
210 SmpClientDirectory
.Client
= SmpClientDirectory
.CandidateClient
;
212 PSM_CLIENT_DATA pCD
= NULL
;
214 for (pCD
=SmpClientDirectory
.Client
;
217 pCD
->Next
= SmpClientDirectory
.CandidateClient
;
219 SmpClientDirectory
.CandidateClient
->Next
= NULL
;
221 * Increment the number of active subsystems.
223 ++ SmpClientDirectory
.Count
;
225 * Notify to the caller the reference to the client data.
229 *ClientData
= SmpClientDirectory
.CandidateClient
;
232 * Free the slot for the candidate subsystem.
234 SmpClientDirectory
.CandidateClient
= NULL
;
236 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
238 return STATUS_SUCCESS
;
240 /**********************************************************************
241 * SmCompleteClientInitialization/1
244 * Lookup the subsystem server descriptor given the process ID
245 * of the subsystem server process.
248 SmCompleteClientInitialization (ULONG ProcessId
)
250 NTSTATUS Status
= STATUS_NOT_FOUND
;
251 PSM_CLIENT_DATA Client
= NULL
;
253 DPRINT("SM: %s(%lu) called\n", __FUNCTION__
, ProcessId
);
255 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
256 if (SmpClientDirectory
.Count
> 0)
258 Client
= SmpClientDirectory
.Client
;
259 while (NULL
!= Client
)
261 if (ProcessId
== Client
->ServerProcessId
)
263 SmpSetClientInitialized (Client
);
264 Status
= STATUS_SUCCESS
;
267 Client
= Client
->Next
;
270 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
274 /**********************************************************************
278 * Create a "candidate" client. Client descriptor will enter the
279 * client directory only at the end of the registration
280 * procedure. Otherwise, we will kill the associated process.
283 * ProcessHandle: handle of the subsystem server process.
287 * STATUS_SUCCESS if all OK;
288 * STATUS_DEVICE_BUSY if another SS is still booting;
289 * STATUS_NO_MEMORY if client descriptor allocation failed;
294 SmCreateClient (PRTL_USER_PROCESS_INFORMATION ProcessInfo
, PWSTR ProgramName
)
296 NTSTATUS Status
= STATUS_SUCCESS
;
299 DPRINT("SM: %s(%lx) called\n", __FUNCTION__
, ProcessInfo
->ProcessHandle
);
301 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
303 * Check if the candidate client slot is empty.
305 if (NULL
== SmpClientDirectory
.CandidateClient
)
308 * Allocate the storage for client data
310 SmpClientDirectory
.CandidateClient
=
311 RtlAllocateHeap (SmpHeap
,
313 sizeof (SM_CLIENT_DATA
));
314 if (NULL
== SmpClientDirectory
.CandidateClient
)
316 DPRINT("SM: %s(%lx): out of memory!\n",
317 __FUNCTION__
, ProcessInfo
->ProcessHandle
);
318 Status
= STATUS_NO_MEMORY
;
322 /* Initialize the candidate client. */
323 RtlInitializeCriticalSection(& SmpClientDirectory
.CandidateClient
->Lock
);
324 SmpClientDirectory
.CandidateClient
->ServerProcess
=
325 (HANDLE
) ProcessInfo
->ProcessHandle
;
326 SmpClientDirectory
.CandidateClient
->ServerProcessId
=
327 (ULONG
) ProcessInfo
->ClientId
.UniqueProcess
;
329 * Copy the program name
331 RtlCopyMemory (SmpClientDirectory
.CandidateClient
->ProgramName
,
333 SM_SB_NAME_MAX_LENGTH
);
336 DPRINT1("SM: %s: CandidateClient pending!\n", __FUNCTION__
);
337 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
338 Status
= STATUS_DEVICE_BUSY
;
341 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
346 /**********************************************************************
349 * 1. close any handle
350 * 2. kill client process
351 * 3. release resources
354 SmDestroyClient (ULONG SubsystemId
)
356 NTSTATUS Status
= STATUS_SUCCESS
;
357 PSM_CLIENT_DATA Parent
= NULL
;
358 PSM_CLIENT_DATA Client
= NULL
;
360 DPRINT("SM: %s called\n", __FUNCTION__
);
362 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
363 Client
= SmpLookupClient (SubsystemId
, & Parent
);
366 DPRINT1("SM: %s: del req for non existent subsystem (id=%d)\n",
367 __FUNCTION__
, SubsystemId
);
368 Status
= STATUS_NOT_FOUND
;
372 /* 1st in the list? */
375 SmpClientDirectory
.Client
= Client
->Next
;
381 Parent
->Next
= Client
->Next
;
383 DPRINT1("SM: %s: n-th has no parent!\n", __FUNCTION__
);
384 Status
= STATUS_UNSUCCESSFUL
; /* FIXME */
387 /* TODO: send shutdown or kill */
388 NtTerminateProcess (Client
->ServerProcess
, 0); //FIXME
389 RtlFreeHeap (SmpHeap
, 0, Client
);
390 -- SmpClientDirectory
.Count
;
392 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
396 /* === Utilities for SmQryInfo === */
398 /**********************************************************************
399 * SmGetClientBasicInformation/1
402 SmGetClientBasicInformation (PSM_BASIC_INFORMATION i
)
405 PSM_CLIENT_DATA ClientData
= NULL
;
407 DPRINT("SM: %s called\n", __FUNCTION__
);
409 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
411 i
->SubSystemCount
= SmpClientDirectory
.Count
;
414 if (SmpClientDirectory
.Count
> 0)
416 ClientData
= SmpClientDirectory
.Client
;
417 while ((NULL
!= ClientData
) && (Index
< SM_QRYINFO_MAX_SS_COUNT
))
419 i
->SubSystem
[Index
].Id
= ClientData
->SubsystemId
;
420 i
->SubSystem
[Index
].Flags
= ClientData
->Flags
;
421 i
->SubSystem
[Index
].ProcessId
= ClientData
->ServerProcessId
;
422 ClientData
= ClientData
->Next
;
426 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);
427 return STATUS_SUCCESS
;
430 /**********************************************************************
431 * SmGetSubSystemInformation/1
434 SmGetSubSystemInformation (PSM_SUBSYSTEM_INFORMATION i
)
436 NTSTATUS Status
= STATUS_SUCCESS
;
437 PSM_CLIENT_DATA ClientData
= NULL
;
439 DPRINT("SM: %s called\n", __FUNCTION__
);
441 RtlEnterCriticalSection (& SmpClientDirectory
.Lock
);
442 ClientData
= SmpLookupClient (i
->SubSystemId
, NULL
);
443 if (NULL
== ClientData
)
445 Status
= STATUS_NOT_FOUND
;
449 i
->Flags
= ClientData
->Flags
;
450 i
->ProcessId
= ClientData
->ServerProcessId
;
451 RtlCopyMemory (i
->NameSpaceRootNode
,
452 ClientData
->SbApiPortName
,
453 (SM_QRYINFO_MAX_ROOT_NODE
* sizeof(i
->NameSpaceRootNode
[0])));
455 RtlLeaveCriticalSection (& SmpClientDirectory
.Lock
);