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 CsrInsertThread(CsrProcess
, CsrThread
);
294 /* Setup Process Data */
295 CsrProcess
->ClientId
= CreateSession
->ProcessInfo
.ClientId
;
296 CsrProcess
->ProcessHandle
= hProcess
;
297 CsrProcess
->NtSession
= CsrAllocateNtSession(CreateSession
->SessionId
);
299 /* Set the Process Priority */
300 CsrSetBackgroundPriority(CsrProcess
);
302 /* Get the first data location */
303 ProcessData
= &CsrProcess
->ServerData
[CSR_SERVER_DLL_MAX
];
306 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
308 /* Get the current Server */
309 ServerDll
= CsrLoadedServerDll
[i
];
311 /* Check if the DLL is loaded and has Process Data */
312 if (ServerDll
&& ServerDll
->SizeOfProcessData
)
314 /* Write the pointer to the data */
315 CsrProcess
->ServerData
[i
] = ProcessData
;
317 /* Move to the next data location */
318 ProcessData
= (PVOID
)((ULONG_PTR
)ProcessData
+
319 ServerDll
->SizeOfProcessData
);
323 /* Nothing for this Process */
324 CsrProcess
->ServerData
[i
] = NULL
;
328 /* Insert the Process */
329 CsrInsertProcess(NULL
, CsrProcess
);
331 /* Activate the Thread */
332 ApiMessage
->ReturnValue
= NtResumeThread(hThread
, NULL
);
334 /* Release lock and return */
335 CsrReleaseProcessLock();
340 * @name CsrSbForeignSessionComplete
342 * The CsrSbForeignSessionComplete API is called by the Session Manager
343 * whenever a foreign session is completed (ie: terminated).
346 * Pointer to the Session Manager API Message.
348 * @return TRUE in case of success, FALSE otherwise.
350 * @remarks The CsrSbForeignSessionComplete API is not yet implemented.
355 CsrSbForeignSessionComplete(IN PSB_API_MSG ApiMessage
)
357 /* Deprecated/Unimplemented in NT */
358 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
363 * @name CsrSbTerminateSession
365 * The CsrSbTerminateSession API is called by the Session Manager
366 * whenever a foreign session should be destroyed.
369 * Pointer to the Session Manager API Message.
371 * @return TRUE in case of success, FALSE otherwise.
373 * @remarks The CsrSbTerminateSession API is not yet implemented.
378 CsrSbTerminateSession(IN PSB_API_MSG ApiMessage
)
380 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
385 * @name CsrSbCreateProcess
387 * The CsrSbCreateProcess API is called by the Session Manager
388 * whenever a foreign session is created and a new process should be started.
391 * Pointer to the Session Manager API Message.
393 * @return TRUE in case of success, FALSE otherwise.
395 * @remarks The CsrSbCreateProcess API is not yet implemented.
400 CsrSbCreateProcess(IN PSB_API_MSG ApiMessage
)
402 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
407 * @name CsrSbApiHandleConnectionRequest
409 * The CsrSbApiHandleConnectionRequest routine handles and accepts a new
410 * connection request to the SM API LPC Port.
413 * Pointer to the incoming CSR API Message which contains the
414 * connection request.
416 * @return STATUS_SUCCESS in case of success, or status code which caused
417 * the routine to error.
424 CsrSbApiHandleConnectionRequest(IN PSB_API_MSG Message
)
427 REMOTE_PORT_VIEW RemotePortView
;
430 /* Set the Port View Structure Length */
431 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
433 /* Accept the connection */
434 Status
= NtAcceptConnectPort(&hPort
,
436 (PPORT_MESSAGE
)Message
,
440 if (!NT_SUCCESS(Status
))
442 DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status
);
446 /* Complete the Connection */
447 Status
= NtCompleteConnectPort(hPort
);
448 if (!NT_SUCCESS(Status
))
450 DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status
);
458 * @name CsrSbApiRequestThread
460 * The CsrSbApiRequestThread routine handles incoming messages or connection
461 * requests on the SM API LPC Port.
464 * System-default user-defined parameter. Unused.
466 * @return The thread exit code, if the thread is terminated.
468 * @remarks Before listening on the port, the routine will first attempt
469 * to connect to the user subsystem.
474 CsrSbApiRequestThread(IN PVOID Parameter
)
477 SB_API_MSG ReceiveMsg
;
478 PSB_API_MSG ReplyMsg
= NULL
;
485 /* Wait for a message to come in */
486 Status
= NtReplyWaitReceivePort(CsrSbApiPort
,
491 /* Check if we didn't get success */
492 if (Status
!= STATUS_SUCCESS
)
494 /* If we only got a warning, keep going */
495 if (NT_SUCCESS(Status
)) continue;
497 /* We failed big time, so start out fresh */
499 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
503 /* Save the message type */
504 MessageType
= ReceiveMsg
.h
.u2
.s2
.Type
;
506 /* Check if this is a connection request */
507 if (MessageType
== LPC_CONNECTION_REQUEST
)
509 /* Handle connection request */
510 CsrSbApiHandleConnectionRequest(&ReceiveMsg
);
517 /* Check if the port died */
518 if (MessageType
== LPC_PORT_CLOSED
)
520 /* Close the handle if we have one */
521 if (PortContext
) NtClose((HANDLE
)PortContext
);
523 /* Client died, start over */
527 else if (MessageType
== LPC_CLIENT_DIED
)
529 /* Client died, start over */
535 * It's an API Message, check if it's within limits. If it's not,
536 * the NT Behaviour is to set this to the Maximum API.
538 if (ReceiveMsg
.ApiNumber
> SbpMaxApiNumber
)
540 ReceiveMsg
.ApiNumber
= SbpMaxApiNumber
;
541 DPRINT1("CSRSS: %lx is invalid Sb ApiNumber\n", ReceiveMsg
.ApiNumber
);
544 /* Reuse the message */
545 ReplyMsg
= &ReceiveMsg
;
547 /* Make sure that the message is supported */
548 if (ReceiveMsg
.ApiNumber
< SbpMaxApiNumber
)
551 if (!CsrServerSbApiDispatch
[ReceiveMsg
.ApiNumber
](&ReceiveMsg
))
553 DPRINT1("CSRSS: %s Session Api called and failed\n",
554 CsrServerSbApiName
[ReceiveMsg
.ApiNumber
]);
556 /* It failed, so return nothing */
562 /* We don't support this API Number */
563 ReplyMsg
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;