2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsystems/win32/csrss/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 PCHAR CsrServerSbApiName
[5] =
25 "SbForeignSessionComplete",
27 "Unknown Csr Sb Api Number"
30 /* PRIVATE FUNCTIONS *********************************************************/
33 * @name CsrInitializeNtSessionList
35 * The CsrInitializeNtSessionList routine sets up support for CSR Sessions.
46 CsrInitializeNtSessionList(VOID
)
48 DPRINT("CSRSRV: %s called\n", __FUNCTION__
);
50 /* Initialize the Session List */
51 InitializeListHead(&CsrNtSessionList
);
53 /* Initialize the Session Lock */
54 return RtlInitializeCriticalSection(&CsrNtSessionLock
);
58 * @name CsrAllocateNtSession
60 * The CsrAllocateNtSession routine allocates a new CSR NT Session.
63 * Session ID of the CSR NT Session to allocate.
65 * @return Pointer to the newly allocated CSR NT Session.
72 CsrAllocateNtSession(IN ULONG SessionId
)
74 PCSR_NT_SESSION NtSession
;
76 /* Allocate an NT Session Object */
77 NtSession
= RtlAllocateHeap(CsrHeap
, 0, sizeof(CSR_NT_SESSION
));
80 /* Setup the Session Object */
81 NtSession
->SessionId
= SessionId
;
82 NtSession
->ReferenceCount
= 1;
84 /* Insert it into the Session List */
85 CsrAcquireNtSessionLock();
86 InsertHeadList(&CsrNtSessionList
, &NtSession
->SessionLink
);
87 CsrReleaseNtSessionLock();
91 ASSERT(NtSession
!= NULL
);
94 /* Return the Session (or NULL) */
99 * @name CsrReferenceNtSession
101 * The CsrReferenceNtSession increases the reference count of a CSR NT Session.
104 * Pointer to the CSR NT Session to reference.
113 CsrReferenceNtSession(IN PCSR_NT_SESSION Session
)
115 /* Acquire the lock */
116 CsrAcquireNtSessionLock();
119 ASSERT(!IsListEmpty(&Session
->SessionLink
));
120 ASSERT(Session
->SessionId
!= 0);
121 ASSERT(Session
->ReferenceCount
!= 0);
123 /* Increase the reference count */
124 Session
->ReferenceCount
++;
126 /* Release the lock */
127 CsrReleaseNtSessionLock();
131 * @name CsrDereferenceNtSession
133 * The CsrDereferenceNtSession decreases the reference count of a
137 * Pointer to the CSR NT Session to reference.
140 * If this is the last reference to the session, this argument
141 * specifies the exit status.
145 * @remarks CsrDereferenceNtSession will complete the session if
146 * the last reference to it has been closed.
151 CsrDereferenceNtSession(IN PCSR_NT_SESSION Session
,
152 IN NTSTATUS ExitStatus
)
154 /* Acquire the lock */
155 CsrAcquireNtSessionLock();
158 ASSERT(!IsListEmpty(&Session
->SessionLink
));
159 ASSERT(Session
->SessionId
!= 0);
160 ASSERT(Session
->ReferenceCount
!= 0);
162 /* Dereference the Session Object */
163 if (!(--Session
->ReferenceCount
))
165 /* Remove it from the list */
166 RemoveEntryList(&Session
->SessionLink
);
168 /* Release the lock */
169 CsrReleaseNtSessionLock();
171 /* Tell SM that we're done here */
172 SmSessionComplete(CsrSmApiPort
, Session
->SessionId
, ExitStatus
);
174 /* Free the Session Object */
175 RtlFreeHeap(CsrHeap
, 0, Session
);
179 /* Release the lock, the Session is still active */
180 CsrReleaseNtSessionLock();
184 /* SESSION MANAGER FUNCTIONS**************************************************/
187 * @name CsrSbCreateSession
189 * The CsrSbCreateSession API is called by the Session Manager whenever a new
190 * session is created.
193 * Pointer to the Session Manager API Message.
195 * @return TRUE in case of success, FALSE otherwise.
197 * @remarks The CsrSbCreateSession routine will initialize a new CSR NT
198 * Session and allocate a new CSR Process for the subsystem process.
203 CsrSbCreateSession(IN PSB_API_MSG ApiMessage
)
205 PSB_CREATE_SESSION_MSG CreateSession
= &ApiMessage
->CreateSession
;
206 HANDLE hProcess
, hThread
;
207 PCSR_PROCESS CsrProcess
;
209 KERNEL_USER_TIMES KernelTimes
;
210 PCSR_THREAD CsrThread
;
214 /* Save the Process and Thread Handles */
215 hProcess
= CreateSession
->ProcessInfo
.ProcessHandle
;
216 hThread
= CreateSession
->ProcessInfo
.ThreadHandle
;
218 /* Lock the Processes */
219 CsrAcquireProcessLock();
221 /* Allocate a new process */
222 CsrProcess
= CsrAllocateProcess();
226 ApiMessage
->ReturnValue
= STATUS_NO_MEMORY
;
227 CsrReleaseProcessLock();
231 /* Set the exception port */
232 Status
= NtSetInformationProcess(hProcess
,
233 ProcessExceptionPort
,
237 /* Check for success */
238 if (!NT_SUCCESS(Status
))
240 /* Fail the request */
241 CsrDeallocateProcess(CsrProcess
);
242 CsrReleaseProcessLock();
244 /* Strange as it seems, NTSTATUSes are actually returned */
245 return (BOOLEAN
)STATUS_NO_MEMORY
;
248 /* Get the Create Time */
249 Status
= NtQueryInformationThread(hThread
,
252 sizeof(KERNEL_USER_TIMES
),
255 /* Check for success */
256 if (!NT_SUCCESS(Status
))
258 /* Fail the request */
259 CsrDeallocateProcess(CsrProcess
);
260 CsrReleaseProcessLock();
262 /* Strange as it seems, NTSTATUSes are actually returned */
263 return (BOOLEAN
)Status
;
266 /* Allocate a new Thread */
267 CsrThread
= CsrAllocateThread(CsrProcess
);
270 /* Fail the request */
271 CsrDeallocateProcess(CsrProcess
);
272 CsrReleaseProcessLock();
274 ApiMessage
->ReturnValue
= STATUS_NO_MEMORY
;
278 /* Setup the Thread Object */
279 CsrThread
->CreateTime
= KernelTimes
.CreateTime
;
280 CsrThread
->ClientId
= CreateSession
->ProcessInfo
.ClientId
;
281 CsrThread
->ThreadHandle
= hThread
;
282 ProtectHandle(hThread
);
283 CsrThread
->Flags
= 0;
285 /* Insert it into the Process List */
286 CsrInsertThread(CsrProcess
, CsrThread
);
288 /* Setup Process Data */
289 CsrProcess
->ClientId
= CreateSession
->ProcessInfo
.ClientId
;
290 CsrProcess
->ProcessHandle
= hProcess
;
291 CsrProcess
->NtSession
= CsrAllocateNtSession(CreateSession
->SessionId
);
293 /* Set the Process Priority */
294 CsrSetBackgroundPriority(CsrProcess
);
296 /* Get the first data location */
297 ProcessData
= &CsrProcess
->ServerData
[CSR_SERVER_DLL_MAX
];
300 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
302 /* Check if the DLL is loaded and has Process Data */
303 if (CsrLoadedServerDll
[i
] && CsrLoadedServerDll
[i
]->SizeOfProcessData
)
305 /* Write the pointer to the data */
306 CsrProcess
->ServerData
[i
] = ProcessData
;
308 /* Move to the next data location */
309 ProcessData
= (PVOID
)((ULONG_PTR
)ProcessData
+
310 CsrLoadedServerDll
[i
]->SizeOfProcessData
);
314 /* Nothing for this Process */
315 CsrProcess
->ServerData
[i
] = NULL
;
319 /* HACKZ: should go in BaseSrv part of CreateCallback done in Insert below */
320 RtlInitializeCriticalSection(&CsrProcess
->HandleTableLock
);
322 /* Insert the Process */
323 CsrInsertProcess(NULL
, NULL
, CsrProcess
);
325 /* Activate the Thread */
326 ApiMessage
->ReturnValue
= NtResumeThread(hThread
, NULL
);
328 /* Release lock and return */
329 CsrReleaseProcessLock();
334 * @name CsrSbForeignSessionComplete
336 * The CsrSbForeignSessionComplete API is called by the Session Manager
337 * whenever a foreign session is completed (ie: terminated).
340 * Pointer to the Session Manager API Message.
342 * @return TRUE in case of success, FALSE otherwise.
344 * @remarks The CsrSbForeignSessionComplete API is not yet implemented.
349 CsrSbForeignSessionComplete(IN PSB_API_MSG ApiMessage
)
351 /* Deprecated/Unimplemented in NT */
352 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
357 * @name CsrSbTerminateSession
359 * The CsrSbTerminateSession API is called by the Session Manager
360 * whenever a foreign session should be destroyed.
363 * Pointer to the Session Manager API Message.
365 * @return TRUE in case of success, FALSE otherwise.
367 * @remarks The CsrSbTerminateSession API is not yet implemented.
372 CsrSbTerminateSession(IN PSB_API_MSG ApiMessage
)
374 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
379 * @name CsrSbCreateProcess
381 * The CsrSbCreateProcess API is called by the Session Manager
382 * whenever a foreign session is created and a new process should be started.
385 * Pointer to the Session Manager API Message.
387 * @return TRUE in case of success, FALSE otherwise.
389 * @remarks The CsrSbCreateProcess API is not yet implemented.
394 CsrSbCreateProcess(IN PSB_API_MSG ApiMessage
)
396 ApiMessage
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;
400 PSB_API_ROUTINE CsrServerSbApiDispatch
[5] =
403 CsrSbTerminateSession
,
404 CsrSbForeignSessionComplete
,
410 * @name CsrSbApiHandleConnectionRequest
412 * The CsrSbApiHandleConnectionRequest routine handles and accepts a new
413 * connection request to the SM API LPC Port.
416 * Pointer to the incoming CSR API Message which contains the
417 * connection request.
419 * @return STATUS_SUCCESS in case of success, or status code which caused
420 * the routine to error.
427 CsrSbApiHandleConnectionRequest(IN PSB_API_MSG Message
)
430 REMOTE_PORT_VIEW RemotePortView
;
433 /* Set the Port View Structure Length */
434 RemotePortView
.Length
= sizeof(REMOTE_PORT_VIEW
);
436 /* Accept the connection */
437 Status
= NtAcceptConnectPort(&hPort
,
439 (PPORT_MESSAGE
)Message
,
443 if (!NT_SUCCESS(Status
))
445 DPRINT1("CSRSS: Sb Accept Connection failed %lx\n", Status
);
449 /* Complete the Connection */
450 Status
= NtCompleteConnectPort(hPort
);
451 if (!NT_SUCCESS(Status
))
453 DPRINT1("CSRSS: Sb Complete Connection failed %lx\n",Status
);
461 * @name CsrSbApiRequestThread
463 * The CsrSbApiRequestThread routine handles incoming messages or connection
464 * requests on the SM API LPC Port.
467 * System-default user-defined parameter. Unused.
469 * @return The thread exit code, if the thread is terminated.
471 * @remarks Before listening on the port, the routine will first attempt
472 * to connect to the user subsystem.
477 CsrSbApiRequestThread(IN PVOID Parameter
)
480 SB_API_MSG ReceiveMsg
;
481 PSB_API_MSG ReplyMsg
= NULL
;
488 /* Wait for a message to come in */
489 Status
= NtReplyWaitReceivePort(CsrSbApiPort
,
494 /* Check if we didn't get success */
495 if (Status
!= STATUS_SUCCESS
)
497 /* If we only got a warning, keep going */
498 if (NT_SUCCESS(Status
)) continue;
500 /* We failed big time, so start out fresh */
502 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status
);
506 /* Save the message type */
507 MessageType
= ReceiveMsg
.h
.u2
.s2
.Type
;
509 /* Check if this is a connection request */
510 if (MessageType
== LPC_CONNECTION_REQUEST
)
512 /* Handle connection request */
513 CsrSbApiHandleConnectionRequest(&ReceiveMsg
);
520 /* Check if the port died */
521 if (MessageType
== LPC_PORT_CLOSED
)
523 /* Close the handle if we have one */
524 if (PortContext
) NtClose((HANDLE
)PortContext
);
526 /* Client died, start over */
530 else if (MessageType
== LPC_CLIENT_DIED
)
532 /* Client died, start over */
538 * It's an API Message, check if it's within limits. If it's not, the
539 * NT Behaviour is to set this to the Maximum API.
541 if (ReceiveMsg
.ApiNumber
> SbpMaxApiNumber
)
543 ReceiveMsg
.ApiNumber
= SbpMaxApiNumber
;
544 DPRINT1("CSRSS: %lx is invalid Sb ApiNumber\n", ReceiveMsg
.ApiNumber
);
547 /* Reuse the message */
548 ReplyMsg
= &ReceiveMsg
;
550 /* Make sure that the message is supported */
551 if (ReceiveMsg
.ApiNumber
< SbpMaxApiNumber
)
554 if (!CsrServerSbApiDispatch
[ReceiveMsg
.ApiNumber
](&ReceiveMsg
))
556 /* It failed, so return nothing */
562 /* We don't support this API Number */
563 ReplyMsg
->ReturnValue
= STATUS_NOT_IMPLEMENTED
;