2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/csrsrv/session.c
5 * PURPOSE: CSR Server DLL Session Implementation
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES *******************************************************************/
16 /* DATA ***********************************************************************/
18 RTL_CRITICAL_SECTION CsrNtSessionLock
;
19 LIST_ENTRY CsrNtSessionList
;
21 PSB_API_ROUTINE CsrServerSbApiDispatch
[SbpMaxApiNumber
- SbpCreateSession
] =
24 CsrSbTerminateSession
,
25 CsrSbForeignSessionComplete
,
29 PCHAR CsrServerSbApiName
[SbpMaxApiNumber
- SbpCreateSession
] =
33 "SbForeignSessionComplete",
37 /* PRIVATE FUNCTIONS **********************************************************/
40 * @name CsrInitializeNtSessionList
42 * The CsrInitializeNtSessionList routine sets up support for CSR Sessions.
53 CsrInitializeNtSessionList(VOID
)
55 /* Initialize the Session List */
56 InitializeListHead(&CsrNtSessionList
);
58 /* Initialize the Session Lock */
59 return RtlInitializeCriticalSection(&CsrNtSessionLock
);
63 * @name CsrAllocateNtSession
65 * The CsrAllocateNtSession routine allocates a new CSR NT Session.
68 * Session ID of the CSR NT Session to allocate.
70 * @return Pointer to the newly allocated CSR NT Session.
77 CsrAllocateNtSession(IN ULONG SessionId
)
79 PCSR_NT_SESSION NtSession
;
81 /* Allocate an NT Session Object */
82 NtSession
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, sizeof(CSR_NT_SESSION
));
85 /* Setup the Session Object */
86 NtSession
->SessionId
= SessionId
;
87 NtSession
->ReferenceCount
= 1;
89 /* Insert it into the Session List */
90 CsrAcquireNtSessionLock();
91 InsertHeadList(&CsrNtSessionList
, &NtSession
->SessionLink
);
92 CsrReleaseNtSessionLock();
96 ASSERT(NtSession
!= NULL
);
99 /* Return the Session (or NULL) */
104 * @name CsrReferenceNtSession
106 * The CsrReferenceNtSession increases the reference count of a CSR NT Session.
109 * Pointer to the CSR NT Session to reference.
118 CsrReferenceNtSession(IN PCSR_NT_SESSION Session
)
120 /* Acquire the lock */
121 CsrAcquireNtSessionLock();
124 ASSERT(!IsListEmpty(&Session
->SessionLink
));
125 ASSERT(Session
->SessionId
!= 0);
126 ASSERT(Session
->ReferenceCount
!= 0);
128 /* Increase the reference count */
129 Session
->ReferenceCount
++;
131 /* Release the lock */
132 CsrReleaseNtSessionLock();
136 * @name CsrDereferenceNtSession
138 * The CsrDereferenceNtSession decreases the reference count of a
142 * Pointer to the CSR NT Session to reference.
145 * If this is the last reference to the session, this argument
146 * specifies the exit status.
150 * @remarks CsrDereferenceNtSession will complete the session if
151 * the last reference to it has been closed.
156 CsrDereferenceNtSession(IN PCSR_NT_SESSION Session
,
157 IN NTSTATUS ExitStatus
)
159 /* Acquire the lock */
160 CsrAcquireNtSessionLock();
163 ASSERT(!IsListEmpty(&Session
->SessionLink
));
164 ASSERT(Session
->SessionId
!= 0);
165 ASSERT(Session
->ReferenceCount
!= 0);
167 /* Dereference the Session Object */
168 if ((--Session
->ReferenceCount
) == 0)
170 /* Remove it from the list */
171 RemoveEntryList(&Session
->SessionLink
);
173 /* Release the lock */
174 CsrReleaseNtSessionLock();
176 /* Tell SM that we're done here */
177 SmSessionComplete(CsrSmApiPort
, Session
->SessionId
, ExitStatus
);
179 /* Free the Session Object */
180 RtlFreeHeap(CsrHeap
, 0, Session
);
184 /* Release the lock, the Session is still active */
185 CsrReleaseNtSessionLock();
189 /* SESSION MANAGER FUNCTIONS **************************************************/
192 * @name CsrSbCreateSession
194 * The CsrSbCreateSession API is called by the Session Manager whenever a new
195 * session is created.
198 * Pointer to the Session Manager API Message.
200 * @return TRUE in case of success, FALSE otherwise.
202 * @remarks The CsrSbCreateSession routine will initialize a new CSR NT
203 * Session and allocate a new CSR Process for the subsystem process.
208 CsrSbCreateSession(IN PSB_API_MSG ApiMessage
)
210 PSB_CREATE_SESSION_MSG CreateSession
= &ApiMessage
->CreateSession
;
211 HANDLE hProcess
, hThread
;
212 PCSR_PROCESS CsrProcess
;
213 PCSR_THREAD CsrThread
;
214 PCSR_SERVER_DLL ServerDll
;
217 KERNEL_USER_TIMES KernelTimes
;
220 /* Save the Process and Thread Handles */
221 hProcess
= CreateSession
->ProcessInfo
.ProcessHandle
;
222 hThread
= CreateSession
->ProcessInfo
.ThreadHandle
;
224 /* Lock the Processes */
225 CsrAcquireProcessLock();
227 /* Allocate a new process */
228 CsrProcess
= CsrAllocateProcess();
232 ApiMessage
->ReturnValue
= STATUS_NO_MEMORY
;
233 CsrReleaseProcessLock();
237 /* Set the exception port */
238 Status
= NtSetInformationProcess(hProcess
,
239 ProcessExceptionPort
,
243 /* Check for success */
244 if (!NT_SUCCESS(Status
))
246 /* Fail the request */
247 CsrDeallocateProcess(CsrProcess
);
248 CsrReleaseProcessLock();
250 /* Strange as it seems, NTSTATUSes are actually returned */
251 return (BOOLEAN
)STATUS_NO_MEMORY
;
254 /* Get the Create Time */
255 Status
= NtQueryInformationThread(hThread
,
258 sizeof(KERNEL_USER_TIMES
),
261 /* Check for success */
262 if (!NT_SUCCESS(Status
))
264 /* Fail the request */
265 CsrDeallocateProcess(CsrProcess
);
266 CsrReleaseProcessLock();
268 /* Strange as it seems, NTSTATUSes are actually returned */
269 return (BOOLEAN
)Status
;
272 /* Allocate a new Thread */
273 CsrThread
= CsrAllocateThread(CsrProcess
);
276 /* Fail the request */
277 CsrDeallocateProcess(CsrProcess
);
278 CsrReleaseProcessLock();
280 ApiMessage
->ReturnValue
= STATUS_NO_MEMORY
;
284 /* Setup the Thread Object */
285 CsrThread
->CreateTime
= KernelTimes
.CreateTime
;
286 CsrThread
->ClientId
= CreateSession
->ProcessInfo
.ClientId
;
287 CsrThread
->ThreadHandle
= hThread
;
288 ProtectHandle(hThread
);
289 CsrThread
->Flags
= 0;
291 /* Insert it into the Process List */
292 Status
= CsrInsertThread(CsrProcess
, CsrThread
);
293 if (!NT_SUCCESS(Status
))
296 CsrDeallocateProcess(CsrProcess
);
297 CsrDeallocateThread(CsrThread
);
298 CsrReleaseProcessLock();
300 /* Strange as it seems, NTSTATUSes are actually returned */
301 return (BOOLEAN
)Status
;
304 /* Setup Process Data */
305 CsrProcess
->ClientId
= CreateSession
->ProcessInfo
.ClientId
;
306 CsrProcess
->ProcessHandle
= hProcess
;
307 CsrProcess
->NtSession
= CsrAllocateNtSession(CreateSession
->SessionId
);
309 /* Set the Process Priority */
310 CsrSetBackgroundPriority(CsrProcess
);
312 /* Get the first data location */
313 ProcessData
= &CsrProcess
->ServerData
[CSR_SERVER_DLL_MAX
];
316 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
318 /* Get the current Server */
319 ServerDll
= CsrLoadedServerDll
[i
];
321 /* Check if the DLL is loaded and has Process Data */
322 if (ServerDll
&& ServerDll
->SizeOfProcessData
)
324 /* Write the pointer to the data */
325 CsrProcess
->ServerData
[i
] = ProcessData
;
327 /* Move to the next data location */
328 ProcessData
= (PVOID
)((ULONG_PTR
)ProcessData
+
329 ServerDll
->SizeOfProcessData
);
333 /* Nothing for this Process */
334 CsrProcess
->ServerData
[i
] = NULL
;
338 /* Insert the Process */
339 CsrInsertProcess(NULL
, CsrProcess
);
341 /* Activate the Thread */
342 ApiMessage
->ReturnValue
= NtResumeThread(hThread
, NULL
);
344 /* Release lock and return */
345 CsrReleaseProcessLock();
350 * @name CsrSbForeignSessionComplete
352 * The CsrSbForeignSessionComplete API is called by the Session Manager
353 * whenever a foreign session is completed (ie: terminated).
356 * Pointer to the Session Manager API Message.
358 * @return TRUE in case of success, FALSE otherwise.
360 * @remarks The CsrSbForeignSessionComplete API is not yet implemented.
365 CsrSbForeignSessionComplete(IN PSB_API_MSG ApiMessage
)
367 /* Deprecated/Unimplemented in NT */
368 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
373 * @name CsrSbTerminateSession
375 * The CsrSbTerminateSession API is called by the Session Manager
376 * whenever a foreign session should be destroyed.
379 * Pointer to the Session Manager API Message.
381 * @return TRUE in case of success, FALSE otherwise.
383 * @remarks The CsrSbTerminateSession API is not yet implemented.
388 CsrSbTerminateSession(IN PSB_API_MSG ApiMessage
)
390 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
395 * @name CsrSbCreateProcess
397 * The CsrSbCreateProcess API is called by the Session Manager
398 * whenever a foreign session is created and a new process should be started.
401 * Pointer to the Session Manager API Message.
403 * @return TRUE in case of success, FALSE otherwise.
405 * @remarks The CsrSbCreateProcess API is not yet implemented.
410 CsrSbCreateProcess(IN PSB_API_MSG ApiMessage
)
412 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
417 * @name CsrSbApiHandleConnectionRequest
419 * The CsrSbApiHandleConnectionRequest routine handles and accepts a new
420 * connection request to the SM API LPC Port.
423 * Pointer to the incoming CSR API Message which contains the
424 * connection request.
426 * @return STATUS_SUCCESS in case of success, or status code which caused
427 * the routine to error.
434 CsrSbApiHandleConnectionRequest(IN PSB_API_MSG Message
)
437 REMOTE_PORT_VIEW RemotePortView
;
440 /* Set the Port View Structure Length */
441 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
443 /* Accept the connection */
444 Status
= NtAcceptConnectPort(&hPort
,
446 (PPORT_MESSAGE
)Message
,
450 if (!NT_SUCCESS(Status
))
452 DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status
);
456 /* Complete the Connection */
457 Status
= NtCompleteConnectPort(hPort
);
458 if (!NT_SUCCESS(Status
))
460 DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status
);
468 * @name CsrSbApiRequestThread
470 * The CsrSbApiRequestThread routine handles incoming messages or connection
471 * requests on the SM API LPC Port.
474 * System-default user-defined parameter. Unused.
476 * @return The thread exit code, if the thread is terminated.
478 * @remarks Before listening on the port, the routine will first attempt
479 * to connect to the user subsystem.
484 CsrSbApiRequestThread(IN PVOID Parameter
)
487 SB_API_MSG ReceiveMsg
;
488 PSB_API_MSG ReplyMsg
= NULL
;
495 /* Wait for a message to come in */
496 Status
= NtReplyWaitReceivePort(CsrSbApiPort
,
501 /* Check if we didn't get success */
502 if (Status
!= STATUS_SUCCESS
)
504 /* If we only got a warning, keep going */
505 if (NT_SUCCESS(Status
)) continue;
507 /* We failed big time, so start out fresh */
509 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
513 /* Save the message type */
514 MessageType
= ReceiveMsg
.h
.u2
.s2
.Type
;
516 /* Check if this is a connection request */
517 if (MessageType
== LPC_CONNECTION_REQUEST
)
519 /* Handle connection request */
520 CsrSbApiHandleConnectionRequest(&ReceiveMsg
);
527 /* Check if the port died */
528 if (MessageType
== LPC_PORT_CLOSED
)
530 /* Close the handle if we have one */
531 if (PortContext
) NtClose((HANDLE
)PortContext
);
533 /* Client died, start over */
537 else if (MessageType
== LPC_CLIENT_DIED
)
539 /* Client died, start over */
545 * It's an API Message, check if it's within limits. If it's not,
546 * the NT Behaviour is to set this to the Maximum API.
548 if (ReceiveMsg
.ApiNumber
> SbpMaxApiNumber
)
550 ReceiveMsg
.ApiNumber
= SbpMaxApiNumber
;
551 DPRINT1("CSRSS: %lx is invalid Sb ApiNumber\n", ReceiveMsg
.ApiNumber
);
554 /* Reuse the message */
555 ReplyMsg
= &ReceiveMsg
;
557 /* Make sure that the message is supported */
558 if (ReceiveMsg
.ApiNumber
< SbpMaxApiNumber
)
561 if (!CsrServerSbApiDispatch
[ReceiveMsg
.ApiNumber
](&ReceiveMsg
))
563 DPRINT1("CSRSS: %s Session Api called and failed\n",
564 CsrServerSbApiName
[ReceiveMsg
.ApiNumber
]);
566 /* It failed, so return nothing */
572 /* We don't support this API Number */
573 ReplyMsg
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;