Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / base / system / smss / smsessn.c
diff --git a/base/system/smss/smsessn.c b/base/system/smss/smsessn.c
new file mode 100644 (file)
index 0000000..077fa9e
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ * PROJECT:         ReactOS Windows-Compatible Session Manager
+ * LICENSE:         BSD 2-Clause License
+ * FILE:            base/system/smss/smsessn.c
+ * PURPOSE:         Main SMSS Code
+ * PROGRAMMERS:     Alex Ionescu
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include "smss.h"
+
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+typedef struct _SMP_SESSION
+{
+    LIST_ENTRY Entry;
+    ULONG SessionId;
+    PSMP_SUBSYSTEM Subsystem;
+    PSMP_SUBSYSTEM OtherSubsystem;
+} SMP_SESSION, *PSMP_SESSION;
+
+RTL_CRITICAL_SECTION SmpSessionListLock;
+LIST_ENTRY SmpSessionListHead;
+ULONG SmpNextSessionId;
+ULONG SmpNextSessionIdScanMode;
+BOOLEAN SmpDbgSsLoaded;
+HANDLE SmpSessionsObjectDirectory;
+
+/* FUNCTIONS ******************************************************************/
+
+BOOLEAN
+NTAPI
+SmpCheckDuplicateMuSessionId(IN ULONG MuSessionId)
+{
+    PSMP_SUBSYSTEM Subsystem;
+    BOOLEAN FoundDuplicate = FALSE;
+    PLIST_ENTRY NextEntry;
+
+    /* Lock the subsystem database */
+    RtlEnterCriticalSection(&SmpKnownSubSysLock);
+
+    /* Scan each entry */
+    NextEntry = SmpKnownSubSysHead.Flink;
+    while (NextEntry != &SmpKnownSubSysHead)
+    {
+        /* Check if this entry has the same session ID */
+        Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry);
+        if (Subsystem->MuSessionId == MuSessionId)
+        {
+            /* Break out of here! */
+            FoundDuplicate = TRUE;
+            break;
+        }
+        
+        /* Keep going */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Release the database and return the result */
+    RtlLeaveCriticalSection(&SmpKnownSubSysLock);
+    return FoundDuplicate;
+}
+
+PSMP_SESSION
+NTAPI
+SmpSessionIdToSession(IN ULONG SessionId)
+{
+    PSMP_SESSION Session, FoundSession = NULL;
+    PLIST_ENTRY NextEntry;
+
+    /* Loop the session list -- lock must already be held! */
+    NextEntry = SmpSessionListHead.Flink;
+    while (NextEntry != &SmpSessionListHead)
+    {
+        /* Check if this session's ID matches */
+        Session = CONTAINING_RECORD(NextEntry, SMP_SESSION, Entry);
+        if (Session->SessionId == SessionId)
+        {
+            /* Set this as the found session and break out */
+            FoundSession = Session;
+            break;
+        }
+
+        /* Keep going */
+        NextEntry = NextEntry->Flink;
+    }
+
+    /* Return the session that was found and exit */
+    return FoundSession;
+}
+
+VOID
+NTAPI
+SmpDeleteSession(IN ULONG SessionId)
+{
+    PSMP_SESSION Session;
+
+    /* Enter the lock and get the session structure */
+    RtlEnterCriticalSection(&SmpSessionListLock);
+    Session = SmpSessionIdToSession(SessionId);
+    if (Session)
+    {
+        /* Remove it from the list */
+        RemoveEntryList(&Session->Entry);
+        RtlLeaveCriticalSection(&SmpSessionListLock);
+
+        /* Now free the structure outside of the lock */
+        RtlFreeHeap(SmpHeap, 0, Session);
+    }
+    else
+    {
+        /* ID doesn't map to one of our structures, nothing to do... */
+        RtlLeaveCriticalSection(&SmpSessionListLock);
+    }
+}
+
+ULONG
+NTAPI
+SmpAllocateSessionId(IN PSMP_SUBSYSTEM Subsystem,
+                     IN PSMP_SUBSYSTEM OtherSubsystem)
+{
+    ULONG SessionId;
+    PSMP_SESSION Session;
+
+    /* Allocate a new ID while under the lock */
+    RtlEnterCriticalSection(&SmpSessionListLock);
+    SessionId = SmpNextSessionId++;
+
+    /* Check for overflow */
+    if (SmpNextSessionIdScanMode)
+    {
+        /* Break if it happened */
+        DbgPrint("SMSS: SessionId's Wrapped\n");
+        DbgBreakPoint();
+    }
+    else
+    {
+        /* Detect it for next time */
+        if (!SmpNextSessionId) SmpNextSessionIdScanMode = 1;
+    }
+
+    /* Allocate a session structure */
+    Session = RtlAllocateHeap(SmpHeap, 0, sizeof(SMP_SESSION));
+    if (Session)
+    {
+        /* Write the session data and insert it into the session list */
+        Session->Subsystem = Subsystem;
+        Session->SessionId = SessionId;
+        Session->OtherSubsystem = OtherSubsystem;
+        InsertTailList(&SmpSessionListHead, &Session->Entry);
+    }
+    else
+    {
+        DPRINT1("SMSS: Unable to keep track of session ID -- no memory available\n");
+    }
+
+    /* Release the session lock */
+    RtlLeaveCriticalSection(&SmpSessionListLock);
+    return SessionId;
+}
+
+NTSTATUS
+NTAPI
+SmpGetProcessMuSessionId(IN HANDLE ProcessHandle,
+                         OUT PULONG SessionId)
+{
+    NTSTATUS Status;
+    ULONG ProcessSession;
+
+    /* Query the kernel for the session ID */
+    Status = NtQueryInformationProcess(ProcessHandle,
+                                       ProcessSessionInformation,
+                                       &ProcessSession,
+                                       sizeof(ProcessSession),
+                                       NULL);
+    if (NT_SUCCESS(Status))
+    {
+        /* Copy it back into the buffer */
+        *SessionId = ProcessSession;
+    }
+    else
+    {
+        /* Failure -- assume session zero */
+        DPRINT1("SMSS: GetProcessMuSessionId, Process=%p, Status=%x\n",
+                ProcessHandle, Status);
+        *SessionId = 0;
+    }
+
+    /* Return result */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+SmpSetProcessMuSessionId(IN HANDLE ProcessHandle,
+                         IN ULONG SessionId)
+{
+    NTSTATUS Status;
+
+    /* Tell the kernel about the session ID */
+    Status = NtSetInformationProcess(ProcessHandle,
+                                     ProcessSessionInformation,
+                                     &SessionId,
+                                     sizeof(SessionId));
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("SMSS: SetProcessMuSessionId, Process=%p, Status=%x\n",
+                ProcessHandle, Status);
+    }
+
+    /* Return */
+    return Status;
+}