// RSSRV interactive-session policy. Session 0 owns display routing, activation, focus, pointer capture, and DWM authority. #include "rssrv_internal.h" #include #include #include #define RSSRV_SESSION_ZERO_PATH "/Sessions/0" #define RSSRV_SESSION_ZERO_CONSOLE_PATH "/Sessions/0/Console" #define RSSRV_CURRENT_CONSOLE_PATH "/Console" #define RSSRV_DWM_LISTENER_BACKLOG 1u // Acquires the session-state mutex. static KSTATUS RssrvSessionLock(RSSRV_SESSION_STATE* session) { if (!session || session->Mutex == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER; return SysWait(session->Mutex, SYS_WAIT_FLAG_NONE); } // Releases the session-state mutex. static void RssrvSessionUnlock(RSSRV_SESSION_STATE* session) { if (session && session->Mutex != SYS_HANDLE_INVALID) (void)SysReleaseMutex(session->Mutex); } // Advances the session generation while preserving zero as an uninitialized value. static void RssrvSessionChangedLocked(RSSRV_SESSION_STATE* session) { session->Generation++; if (session->Generation == 0) session->Generation = 1; } // Sends one best-effort DWM input notification while holding the session mutex. static void RssrvSessionSendDwmEventLocked(RSSRV_SESSION_STATE* session, uint32_t type, const INPUT_KEY_RECORD* key, const INPUT_MOUSE_EVENT* mouse, int32_t x, int32_t y) { if (!session || session->DwmEndpoint == SYS_HANDLE_INVALID) return; NTL_SESSION_DWM_EVENT event; memset(&event, 0, sizeof(event)); event.Size = sizeof(event); event.Version = NTL_SESSION_DWM_PROTOCOL_VERSION; event.Type = type; event.Flags = NTL_SESSION_DWM_FLAG_NONE; event.PointerX = x; event.PointerY = y; if (key) event.Key = *key; if (mouse) event.Mouse = *mouse; SYS_SEND_PORT_REQUEST send; memset(&send, 0, sizeof(send)); send.Size = sizeof(send); send.EndpointHandle = session->DwmEndpoint; send.Flags = SYS_PORT_FLAG_NONE; send.Payload = &event; send.PayloadLength = sizeof(event); send.TimeoutMilliseconds = 0; (void)SysSendPort(&send); } // Routes one focused keyboard record into the connected DWM desktop target. static void RssrvSessionDwmRouteKey(void* context, const INPUT_KEY_RECORD* record) { RSSRV_SESSION_STATE* session = (RSSRV_SESSION_STATE*)context; if (!session || !record) return; if (!KSUCCESS(RssrvSessionLock(session))) return; RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_DELIVER_KEY, record, 0, 0, 0); RssrvSessionUnlock(session); } // Routes one focused/captured mouse record into the connected DWM desktop target. static void RssrvSessionDwmRouteMouse(void* context, const INPUT_MOUSE_EVENT* event, int32_t x, int32_t y) { RSSRV_SESSION_STATE* session = (RSSRV_SESSION_STATE*)context; if (!session || !event) return; if (!KSUCCESS(RssrvSessionLock(session))) return; RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_DELIVER_MOUSE, 0, event, x, y); RssrvSessionUnlock(session); } // Replies to one private DWM session-control request. static void RssrvSessionReplyDwm(SYS_HANDLE endpoint, uint32_t messageId, uint32_t operation, KSTATUS status) { NTL_SESSION_DWM_REPLY reply; memset(&reply, 0, sizeof(reply)); reply.Size = sizeof(reply); reply.Version = NTL_SESSION_DWM_PROTOCOL_VERSION; reply.Operation = operation; reply.Flags = NTL_SESSION_DWM_FLAG_NONE; reply.Status = status; SYS_REPLY_PORT_REQUEST send; memset(&send, 0, sizeof(send)); send.Size = sizeof(send); send.EndpointHandle = endpoint; send.MessageId = messageId; send.Flags = SYS_PORT_FLAG_NONE; send.Payload = &reply; send.PayloadLength = sizeof(reply); (void)SysReplyPort(&send); } // Applies one DWM focus/capture request while preserving RSSRV as the session authority owner. static KSTATUS RssrvSessionApplyDwmRequest(RSSRV_SESSION_STATE* session, const NTL_SESSION_DWM_REQUEST* request) { if (!session || !request || request->Enabled > 1u) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionLock(session); if (!KSUCCESS(status)) return status; RSSRV_INPUT_TARGET* desktop = &session->DesktopTarget; RSSRV_INPUT_TARGET* fallback = session->ActiveTarget == desktop ? (RSSRV_INPUT_TARGET*)0 : session->ActiveTarget; switch (request->Operation) { case NTL_SESSION_DWM_OP_SET_KEYBOARD_FOCUS: if (request->Enabled) { if (session->KeyboardFocus != desktop) { session->KeyboardFocus = desktop; RssrvSessionChangedLocked(session); } } else if (session->KeyboardFocus == desktop) { session->KeyboardFocus = fallback; RssrvSessionChangedLocked(session); } break; case NTL_SESSION_DWM_OP_SET_POINTER_FOCUS: if (request->Enabled) { if (session->PointerFocus != desktop) { session->PointerFocus = desktop; RssrvSessionChangedLocked(session); } } else if (session->PointerFocus == desktop) { session->PointerFocus = fallback; RssrvSessionChangedLocked(session); } break; case NTL_SESSION_DWM_OP_SET_POINTER_CAPTURE: if (request->Enabled) { if (session->PointerCapture != desktop) { session->PointerCapture = desktop; RssrvSessionChangedLocked(session); } } else if (session->PointerCapture == desktop) { session->PointerCapture = (RSSRV_INPUT_TARGET*)0; RssrvSessionChangedLocked(session); } break; default: status = NTLSTATUS_INVALID_PARAMETER; break; } RssrvSessionUnlock(session); return status; } // Restores non-DWM routing after one DWM control connection disappears. static void RssrvSessionDisconnectDwm(RSSRV_SESSION_STATE* session, SYS_HANDLE endpoint) { if (!session) return; if (!KSUCCESS(RssrvSessionLock(session))) return; if (session->DwmEndpoint == endpoint) { RSSRV_INPUT_TARGET* desktop = &session->DesktopTarget; RSSRV_INPUT_TARGET* fallback = session->ActiveTarget == desktop ? (RSSRV_INPUT_TARGET*)0 : session->ActiveTarget; if (session->KeyboardFocus == desktop) session->KeyboardFocus = fallback; if (session->PointerFocus == desktop) session->PointerFocus = fallback; if (session->PointerCapture == desktop) session->PointerCapture = (RSSRV_INPUT_TARGET*)0; session->DwmEndpoint = SYS_HANDLE_INVALID; RssrvSessionChangedLocked(session); } RssrvSessionUnlock(session); } // Accepts replaceable DWM connections and serves the private Session 0 authority protocol. static void RssrvSessionDwmListenerThread(uintptr_t argument) { RSSRV_SESSION_STATE* session = (RSSRV_SESSION_STATE*)argument; RssrvSetCurrentThreadName("rssrv.session.dwm"); if (!session) SysExitThread(1); for (;;) { SYS_HANDLE endpoint = SYS_HANDLE_INVALID; SYS_ACCEPT_PORT_REQUEST accept; memset(&accept, 0, sizeof(accept)); accept.Size = sizeof(accept); accept.ListenerHandle = session->DwmListener; accept.Flags = SYS_PORT_ACCEPT_FLAG_NONE; accept.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; accept.EndpointHandleOut = &endpoint; KSTATUS status = SysAcceptPort(&accept); if (!KSUCCESS(status)) RssrvExit(16); status = RssrvSessionLock(session); if (!KSUCCESS(status)) { (void)SysCloseHandle(endpoint); continue; } if (session->DwmEndpoint != SYS_HANDLE_INVALID) { RssrvSessionUnlock(session); (void)SysDisconnectPort(endpoint); (void)SysCloseHandle(endpoint); continue; } session->DwmEndpoint = endpoint; RssrvSessionChangedLocked(session); RssrvSessionUnlock(session); for (;;) { NTL_SESSION_DWM_REQUEST request; SYS_PORT_MESSAGE_INFO info; memset(&request, 0, sizeof(request)); memset(&info, 0, sizeof(info)); info.Size = sizeof(info); SYS_RECEIVE_PORT_REQUEST receive; memset(&receive, 0, sizeof(receive)); receive.Size = sizeof(receive); receive.EndpointHandle = endpoint; receive.Flags = SYS_PORT_FLAG_NONE; receive.Payload = &request; receive.PayloadCapacity = sizeof(request); receive.InfoOut = &info; receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE; status = SysReceivePort(&receive); if (status == NTLSTATUS_PORT_DISCONNECTED || !KSUCCESS(status)) break; if (info.Type != SYS_PORT_MESSAGE_REQUEST || info.HandleCount != 0 || info.PayloadLength != sizeof(request) || request.Size != sizeof(request) || request.Version != NTL_SESSION_DWM_PROTOCOL_VERSION || request.Flags != NTL_SESSION_DWM_FLAG_NONE || request.Reserved[0] != 0 || request.Reserved[1] != 0 || request.Reserved[2] != 0) { RssrvSessionReplyDwm(endpoint, info.MessageId, request.Operation, NTLSTATUS_INVALID_PARAMETER); continue; } status = RssrvSessionApplyDwmRequest(session, &request); RssrvSessionReplyDwm(endpoint, info.MessageId, request.Operation, status); } RssrvSessionDisconnectDwm(session, endpoint); (void)SysDisconnectPort(endpoint); (void)SysCloseHandle(endpoint); } } // Initializes Session 0 and creates the private listener that init may delegate only to DWM. KSTATUS RssrvSessionInitialize(RSSRV_SESSION_STATE* session, RSSRV_NAMESPACE* namespaceState, RSSRV_DISPLAY_STATE* display) { if (!session || !namespaceState || !display) return NTLSTATUS_INVALID_PARAMETER; memset(session, 0, sizeof(*session)); session->Mutex = SYS_HANDLE_INVALID; session->DwmListener = SYS_HANDLE_INVALID; session->DwmEndpoint = SYS_HANDLE_INVALID; session->Namespace = namespaceState; session->Display = display; session->Id = 0; session->Generation = 1; session->NextTargetId = 1; SYS_DISPLAY_INFO info; memset(&info, 0, sizeof(info)); KSTATUS status = RssrvDisplayQueryInfo(display, &info); if (!KSUCCESS(status)) return status; session->DisplayWidth = info.Mode.Width ? (int32_t)info.Mode.Width : 1; session->DisplayHeight = info.Mode.Height ? (int32_t)info.Mode.Height : 1; status = SysCreateMutex(&session->Mutex); if (!KSUCCESS(status)) return status; status = RssrvNamespaceCreateDirectory(namespaceState, RSSRV_SESSION_ZERO_PATH, sizeof(RSSRV_SESSION_ZERO_PATH) - 1u); if (!KSUCCESS(status)) return status; SYS_CREATE_PORT_REQUEST create; memset(&create, 0, sizeof(create)); create.Size = sizeof(create); create.Flags = SYS_PORT_FLAG_NONE; create.Backlog = RSSRV_DWM_LISTENER_BACKLOG; create.HandleOut = &session->DwmListener; return SysCreatePort(&create); } // Registers one stable in-process input target with Session 0. KSTATUS RssrvSessionRegisterInputTarget(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target, uint32_t kind, void* context, RSSRV_INPUT_TARGET_KEY_ROUTINE keyRoutine, RSSRV_INPUT_TARGET_MOUSE_ROUTINE mouseRoutine) { if (!session || !target || kind == RSSRV_INPUT_TARGET_KIND_NONE || !context) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionLock(session); if (!KSUCCESS(status)) return status; if (target->Id != 0) { RssrvSessionUnlock(session); return NTLSTATUS_OBJECT_NAME_COLLISION; } memset(target, 0, sizeof(*target)); target->Id = session->NextTargetId++; if (target->Id == 0) target->Id = session->NextTargetId++; target->Kind = kind; target->Session = session; target->Context = context; target->KeyRoutine = keyRoutine; target->MouseRoutine = mouseRoutine; RssrvSessionChangedLocked(session); RssrvSessionUnlock(session); return NTLSTATUS_SUCCESS; } // Activates one registered target and gives it ordinary keyboard and pointer focus. KSTATUS RssrvSessionActivateInputTarget(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) { if (!session || !target || target->Id == 0 || target->Session != session) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionLock(session); if (!KSUCCESS(status)) return status; session->ActiveTarget = target; session->KeyboardFocus = target; session->PointerFocus = target; RssrvSessionChangedLocked(session); RssrvSessionUnlock(session); return NTLSTATUS_SUCCESS; } // Sets keyboard focus without changing activation or pointer routing. KSTATUS RssrvSessionSetKeyboardFocus(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) { if (!session || (target && (target->Id == 0 || target->Session != session))) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionLock(session); if (!KSUCCESS(status)) return status; if (session->KeyboardFocus != target) { session->KeyboardFocus = target; RssrvSessionChangedLocked(session); } RssrvSessionUnlock(session); return NTLSTATUS_SUCCESS; } // Sets ordinary pointer focus without disturbing an active pointer capture. KSTATUS RssrvSessionSetPointerFocus(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) { if (!session || (target && (target->Id == 0 || target->Session != session))) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionLock(session); if (!KSUCCESS(status)) return status; if (session->PointerFocus != target) { session->PointerFocus = target; RssrvSessionChangedLocked(session); } RssrvSessionUnlock(session); return NTLSTATUS_SUCCESS; } // Sets or releases pointer capture independently of ordinary pointer focus. KSTATUS RssrvSessionSetPointerCapture(RSSRV_SESSION_STATE* session, RSSRV_INPUT_TARGET* target) { if (!session || (target && (target->Id == 0 || target->Session != session))) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionLock(session); if (!KSUCCESS(status)) return status; if (session->PointerCapture != target) { session->PointerCapture = target; RssrvSessionChangedLocked(session); } RssrvSessionUnlock(session); return NTLSTATUS_SUCCESS; } // Returns the active session display bounds used to clamp the logical pointer. KSTATUS RssrvSessionQueryDisplayBounds(RSSRV_SESSION_STATE* session, int32_t* widthOut, int32_t* heightOut) { if (!session || !widthOut || !heightOut) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionLock(session); if (!KSUCCESS(status)) return status; *widthOut = session->DisplayWidth; *heightOut = session->DisplayHeight; RssrvSessionUnlock(session); return NTLSTATUS_SUCCESS; } // Gives DWM a non-consuming observation of one logical key before authoritative session routing occurs. void RssrvSessionObserveKey(RSSRV_SESSION_STATE* session, const INPUT_KEY_RECORD* record) { if (!session || !record) return; if (!KSUCCESS(RssrvSessionLock(session))) return; RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_OBSERVE_KEY, record, 0, 0, 0); RssrvSessionUnlock(session); } // Gives DWM a non-consuming observation of one logical mouse event for hit testing and cursor policy. void RssrvSessionObserveMouse(RSSRV_SESSION_STATE* session, const INPUT_MOUSE_EVENT* event, int32_t x, int32_t y) { if (!session || !event) return; if (!KSUCCESS(RssrvSessionLock(session))) return; RssrvSessionSendDwmEventLocked(session, NTL_SESSION_DWM_EVENT_OBSERVE_MOUSE, 0, event, x, y); RssrvSessionUnlock(session); } // Routes one logical keyboard record to the current keyboard-focus target. void RssrvSessionRouteKey(RSSRV_SESSION_STATE* session, const INPUT_KEY_RECORD* record) { if (!session || !record) return; RSSRV_INPUT_TARGET* target = (RSSRV_INPUT_TARGET*)0; if (KSUCCESS(RssrvSessionLock(session))) { target = session->KeyboardFocus; RssrvSessionUnlock(session); } if (target && target->KeyRoutine) target->KeyRoutine(target->Context, record); } // Routes one logical mouse event through capture or pointer focus; DWM owns visible cursor policy. void RssrvSessionRouteMouse(RSSRV_SESSION_STATE* session, const INPUT_MOUSE_EVENT* event, int32_t x, int32_t y) { if (!session || !event) return; RSSRV_INPUT_TARGET* target = (RSSRV_INPUT_TARGET*)0; if (KSUCCESS(RssrvSessionLock(session))) { target = session->PointerCapture ? session->PointerCapture : session->PointerFocus; RssrvSessionUnlock(session); } if (target && target->MouseRoutine) target->MouseRoutine(target->Context, event, x, y); } // Publishes Session 0's console alias and starts the private DWM authority listener. KSTATUS RssrvSessionStart(RSSRV_SESSION_STATE* session, RSSRV_CONSOLE_STATE* console) { if (!session || !console || console->Listener == SYS_HANDLE_INVALID || !session->ActiveTarget || session->DwmListener == SYS_HANDLE_INVALID) return NTLSTATUS_INVALID_PARAMETER; KSTATUS status = RssrvSessionRegisterInputTarget(session, &session->DesktopTarget, RSSRV_INPUT_TARGET_KIND_DESKTOP, session, RssrvSessionDwmRouteKey, RssrvSessionDwmRouteMouse); if (!KSUCCESS(status)) return status; SYS_HANDLE sessionConsole = SYS_HANDLE_INVALID; SYS_DERIVE_HANDLE_REQUEST derive; memset(&derive, 0, sizeof(derive)); derive.Size = sizeof(derive); derive.SourceHandle = console->Listener; derive.DesiredRights = SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT; derive.DerivedHandleOut = &sessionConsole; status = SysDeriveHandle(&derive); if (!KSUCCESS(status)) return status; status = RssrvNamespaceBindOwned(session->Namespace, RSSRV_SESSION_ZERO_CONSOLE_PATH, sizeof(RSSRV_SESSION_ZERO_CONSOLE_PATH) - 1u, NTL_RESOURCE_KIND_CAPABILITY, sessionConsole, SYS_RIGHT_QUERY | SYS_PORT_RIGHT_CONNECT); if (!KSUCCESS(status)) { (void)SysCloseHandle(sessionConsole); return status; } status = RssrvNamespaceCreateSymbolicLink(session->Namespace, RSSRV_CURRENT_CONSOLE_PATH, sizeof(RSSRV_CURRENT_CONSOLE_PATH) - 1u, RSSRV_SESSION_ZERO_CONSOLE_PATH, sizeof(RSSRV_SESSION_ZERO_CONSOLE_PATH) - 1u); if (!KSUCCESS(status)) return status; SYS_CREATE_THREAD_REQUEST create; memset(&create, 0, sizeof(create)); create.Size = sizeof(create); create.Entry = (uintptr_t)RssrvSessionDwmListenerThread; create.Argument = (uintptr_t)session; create.Priority = 1u; create.Flags = SYS_CREATE_THREAD_FLAG_NONE; return SysCreateThread(&create); }