Files
nt-lite/code/user/system/rssrv/resource_service.c
T
maksw 73abd6f90d isolate POSIX builds from the host UCRT, wire lwext4 and ntfs-3g as ext4.sys and ntfs.sys, split the FAT driver into directory/file/async/driver/mount units, add posixsrv and dwm plus input/console/desktop syscall clients and a pile of new smoke targets, rename serial.sys to cereal.sys, name HDA/USB/lwIP/AHCI workers, harden ATA probing/reset/removal around actual hardware deadlines, absent-channel detection, diagnostics and explicit worker lifetime, redo ACPI S5 shutdown around GAS/MMIO and HW-reduced firmware, scan SSDTs for _S5 and deal with Intel SMI sleep trapping, make serial and SMP timeouts use real monotonic deadlines, add thread names and fix terminal thread teardown, scheduler and APC prepare/commit races, make advisory file locks queryable and preserve split ranges and add mutable file append state, add shared-memory pipes with kernel-assisted wait/wake, introduce capability-scoped input and display managers, split surface map rights into read/write, add explicit unmap and replace present with commit/generation/damage tracking while keeping physical presentation under the display manager, decouple native exception classes from Win32 exception numbers and translate them in kernel32, add opaque process startup data, bump the resource protocol to v3 with namespace directories, symlinks and enumeration and service control to v2 with generic READY handle exports, add the new POSIX errno/status surface and rebuild fds around posixsrv-owned shared open descriptions, descriptor-local flags, exact inheritance snapshots, dup/fcntl/record locks and shared-ring pipes, add waitpid, POSIX credentials/groups/sessions/passwd/group lookups and move sockets onto stable open descriptions, port the shells and apps to the new console/input services and surface commit API, teach init to load services.ini and start/supervise RSSRV, DWM and generic services under restricted capabilities while publishing their endpoints through RSSRV, split RSSRV into namespace, volume, display, session, input, console and resource components and make /SystemRoot a real symlink to the independently published system volume, shift the syscall table again, expand lock/resource/surface/POSIX/service/thread smoke coverage, make docs scream ASK QUESTIONS and DISCUSS at LLMs, replace MIT No Attribution with WTFPL+.
2026-09-16 10:33:20 +02:00

561 lines
25 KiB
C

// RSSRV resource protocol listeners, sessions, request validation, and capability transfer.
#include "rssrv_internal.h"
#include <stdlib.h>
#include <string.h>
typedef struct RSSRV_SESSION {
RSSRV_RESOURCE_SERVICE* Service;
SYS_HANDLE Endpoint;
uint32_t Administrative;
} RSSRV_SESSION;
// Replies with one fixed resource-protocol reply and no handle transfer.
static KSTATUS RssrvReplyStatus(SYS_HANDLE endpoint,
uint32_t messageId,
uint32_t operation,
KSTATUS status,
uint32_t kind) {
NTL_RESOURCE_REPLY reply;
memset(&reply, 0, sizeof(reply));
reply.Size = sizeof(reply);
reply.Version = NTL_RESOURCE_PROTOCOL_VERSION;
reply.Operation = operation;
reply.Flags = NTL_RESOURCE_FLAG_NONE;
reply.Status = status;
reply.Kind = kind;
SYS_REPLY_PORT_REQUEST request;
memset(&request, 0, sizeof(request));
request.Size = sizeof(request);
request.EndpointHandle = endpoint;
request.MessageId = messageId;
request.Flags = SYS_PORT_FLAG_NONE;
request.Payload = &reply;
request.PayloadLength = sizeof(reply);
return SysReplyPort(&request);
}
// Handles one exact capability lookup while retaining the namespace lock through transfer.
static KSTATUS RssrvHandleLookup(RSSRV_RESOURCE_SERVICE* service,
SYS_HANDLE endpoint,
uint32_t messageId,
const NTL_RESOURCE_REQUEST* request,
const char* path) {
if (!request->Rights)
return RssrvReplyStatus(endpoint, messageId, request->Operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
RSSRV_NAMESPACE_BINDING_VIEW view;
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
KSTATUS status = RssrvNamespaceBeginLookup(service->Namespace,
path,
request->PathLength,
&view,
&kind);
if (!KSUCCESS(status))
return RssrvReplyStatus(endpoint, messageId, request->Operation, status, kind);
kind = view.Kind;
if ((request->Rights & ~view.ExportRights) != 0) {
RssrvNamespaceEndBinding(&view);
return RssrvReplyStatus(endpoint, messageId, request->Operation,
NTLSTATUS_ACCESS_DENIED, kind);
}
NTL_RESOURCE_REPLY reply;
memset(&reply, 0, sizeof(reply));
reply.Size = sizeof(reply);
reply.Version = NTL_RESOURCE_PROTOCOL_VERSION;
reply.Operation = NTL_RESOURCE_OP_LOOKUP;
reply.Status = NTLSTATUS_SUCCESS;
reply.Kind = kind;
SYS_PORT_HANDLE_TRANSFER transfer;
transfer.Handle = view.Handle;
transfer.DesiredRights = request->Rights;
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
SYS_REPLY_PORT_REQUEST out;
memset(&out, 0, sizeof(out));
out.Size = sizeof(out);
out.EndpointHandle = endpoint;
out.MessageId = messageId;
out.Flags = SYS_PORT_FLAG_NONE;
out.Payload = &reply;
out.PayloadLength = sizeof(reply);
out.Handles = &transfer;
out.HandleCount = 1;
status = SysReplyPort(&out);
RssrvNamespaceEndBinding(&view);
// A transfer failure leaves the synchronous call pending, so complete it with the precise status.
if (!KSUCCESS(status))
return RssrvReplyStatus(endpoint, messageId, request->Operation, status, kind);
return NTLSTATUS_SUCCESS;
}
// Resolves the first bound namespace object and transfers its traversal authority.
static KSTATUS RssrvHandleResolve(RSSRV_RESOURCE_SERVICE* service,
SYS_HANDLE endpoint,
uint32_t messageId,
const NTL_RESOURCE_REQUEST* request,
const char* path) {
if ((request->Flags & ~NTL_RESOURCE_RESOLVE_FLAG_MODIFY) != 0)
return RssrvReplyStatus(endpoint, messageId, request->Operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
RSSRV_NAMESPACE_BINDING_VIEW view;
KSTATUS status = RssrvNamespaceBeginResolve(service->Namespace,
path,
request->PathLength,
&view);
if (!KSUCCESS(status))
return RssrvReplyStatus(endpoint, messageId, request->Operation,
status, NTL_RESOURCE_KIND_INVALID);
SYS_RIGHTS desiredRights = 0;
if (view.Kind == NTL_RESOURCE_KIND_VOLUME) {
desiredRights = SYS_VOLUME_RIGHT_OPEN;
if (request->Flags & NTL_RESOURCE_RESOLVE_FLAG_MODIFY)
desiredRights |= SYS_VOLUME_RIGHT_MODIFY;
} else if (view.Kind == NTL_RESOURCE_KIND_DIRECTORY) {
desiredRights = SYS_DIR_RIGHT_OPEN;
if (request->Flags & NTL_RESOURCE_RESOLVE_FLAG_MODIFY)
desiredRights |= SYS_DIR_RIGHT_MODIFY;
} else {
uint32_t kind = view.Kind;
RssrvNamespaceEndBinding(&view);
return RssrvReplyStatus(endpoint, messageId, request->Operation,
NTLSTATUS_NOT_SUPPORTED, kind);
}
uint32_t kind = view.Kind;
if ((desiredRights & ~view.ExportRights) != 0) {
RssrvNamespaceEndBinding(&view);
return RssrvReplyStatus(endpoint, messageId, request->Operation,
NTLSTATUS_ACCESS_DENIED, kind);
}
NTL_RESOURCE_REPLY reply;
memset(&reply, 0, sizeof(reply));
reply.Size = sizeof(reply);
reply.Version = NTL_RESOURCE_PROTOCOL_VERSION;
reply.Operation = NTL_RESOURCE_OP_RESOLVE;
reply.Flags = request->Flags;
reply.Status = NTLSTATUS_SUCCESS;
reply.Kind = kind;
reply.ResolvedLength = view.ResolvedLength;
SYS_PORT_HANDLE_TRANSFER transfer;
transfer.Handle = view.Handle;
transfer.DesiredRights = desiredRights;
transfer.Flags = SYS_PORT_TRANSFER_FLAG_NONE;
SYS_REPLY_PORT_REQUEST out;
memset(&out, 0, sizeof(out));
out.Size = sizeof(out);
out.EndpointHandle = endpoint;
out.MessageId = messageId;
out.Flags = SYS_PORT_FLAG_NONE;
out.Payload = &reply;
out.PayloadLength = sizeof(reply);
out.Handles = &transfer;
out.HandleCount = 1;
status = SysReplyPort(&out);
RssrvNamespaceEndBinding(&view);
if (!KSUCCESS(status))
return RssrvReplyStatus(endpoint, messageId, request->Operation, status, kind);
return NTLSTATUS_SUCCESS;
}
// Handles one exact metadata query without following the final symbolic link.
static KSTATUS RssrvHandleQuery(RSSRV_RESOURCE_SERVICE* service,
SYS_HANDLE endpoint,
uint32_t messageId,
const NTL_RESOURCE_REQUEST* request,
const char* path) {
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
KSTATUS status = RssrvNamespaceQuery(service->Namespace, path, request->PathLength, &kind);
return RssrvReplyStatus(endpoint, messageId, request->Operation, status, kind);
}
// Returns one immediate namespace child after the supplied bytewise cursor name.
static KSTATUS RssrvHandleEnumerate(RSSRV_RESOURCE_SERVICE* service,
SYS_HANDLE endpoint,
uint32_t messageId,
const NTL_RESOURCE_REQUEST* request,
const char* path,
const char* after) {
RSSRV_NAMESPACE_ENTRY entry;
KSTATUS status = RssrvNamespaceEnumerate(service->Namespace,
path,
request->PathLength,
after,
request->AuxLength,
&entry);
if (!KSUCCESS(status))
return RssrvReplyStatus(endpoint, messageId, request->Operation, status, entry.Kind);
uint8_t payload[sizeof(NTL_RESOURCE_REPLY) + NTL_RESOURCE_NAME_MAX];
NTL_RESOURCE_REPLY reply;
memset(&reply, 0, sizeof(reply));
reply.Size = sizeof(reply);
reply.Version = NTL_RESOURCE_PROTOCOL_VERSION;
reply.Operation = NTL_RESOURCE_OP_ENUMERATE;
reply.Status = NTLSTATUS_SUCCESS;
reply.Kind = entry.Kind;
reply.NameLength = entry.NameLength;
memcpy(payload, &reply, sizeof(reply));
memcpy(payload + sizeof(reply), entry.Name, entry.NameLength);
uint32_t payloadLength = (uint32_t)sizeof(reply) + entry.NameLength;
SYS_REPLY_PORT_REQUEST out;
memset(&out, 0, sizeof(out));
out.Size = sizeof(out);
out.EndpointHandle = endpoint;
out.MessageId = messageId;
out.Flags = SYS_PORT_FLAG_NONE;
out.Payload = payload;
out.PayloadLength = payloadLength;
return SysReplyPort(&out);
}
// Handles one administrative bind. On success the namespace takes ownership of receivedHandle.
static KSTATUS RssrvHandleBind(RSSRV_RESOURCE_SERVICE* service,
SYS_HANDLE endpoint,
uint32_t messageId,
const NTL_RESOURCE_REQUEST* request,
const char* path,
uint32_t administrative,
SYS_HANDLE receivedHandle,
uint32_t* consumedOut) {
if (!consumedOut) return NTLSTATUS_INVALID_PARAMETER;
*consumedOut = 0;
if (!administrative || RssrvVolumesOwnPath(path, request->PathLength))
return RssrvReplyStatus(endpoint, messageId, request->Operation,
NTLSTATUS_ACCESS_DENIED, NTL_RESOURCE_KIND_INVALID);
KSTATUS bindStatus = RssrvNamespaceBindOwned(service->Namespace,
path,
request->PathLength,
request->Kind,
receivedHandle,
request->ExportRights);
if (KSUCCESS(bindStatus)) *consumedOut = 1;
KSTATUS replyStatus = RssrvReplyStatus(endpoint, messageId, request->Operation, bindStatus,
KSUCCESS(bindStatus) ? request->Kind : NTL_RESOURCE_KIND_INVALID);
return KSUCCESS(replyStatus) ? bindStatus : replyStatus;
}
// Dispatches one received resource request and returns whether a received handle was consumed.
static uint32_t RssrvDispatchRequest(RSSRV_RESOURCE_SERVICE* service,
SYS_HANDLE endpoint,
uint32_t administrative,
const uint8_t* payload,
uint32_t payloadLength,
const SYS_PORT_MESSAGE_INFO* info,
SYS_HANDLE receivedHandle) {
uint32_t operation = 0;
if (!service || payloadLength < sizeof(NTL_RESOURCE_REQUEST)) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
NTL_RESOURCE_REQUEST request;
memcpy(&request, payload, sizeof(request));
operation = request.Operation;
size_t expectedLength = sizeof(request) + (size_t)request.PathLength + (size_t)request.AuxLength;
if (request.Size != sizeof(request) || request.Version != NTL_RESOURCE_PROTOCOL_VERSION ||
request.PathLength == 0 || expectedLength != payloadLength || expectedLength > SYS_PORT_MAX_INLINE_BYTES) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
const char* path = (const char*)(payload + sizeof(request));
const char* aux = path + request.PathLength;
KSTATUS status = RssrvNamespaceValidatePath(path, request.PathLength);
if (!KSUCCESS(status)) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation, status, NTL_RESOURCE_KIND_INVALID);
return 0;
}
switch (operation) {
case NTL_RESOURCE_OP_LOOKUP:
if (request.Flags != NTL_RESOURCE_FLAG_NONE || request.AuxLength != 0 || info->HandleCount != 0 ||
request.ExportRights != 0 || request.Kind != NTL_RESOURCE_KIND_INVALID) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
(void)RssrvHandleLookup(service, endpoint, info->MessageId, &request, path);
return 0;
case NTL_RESOURCE_OP_QUERY:
if (request.Flags != NTL_RESOURCE_FLAG_NONE || request.AuxLength != 0 || info->HandleCount != 0 ||
request.Rights != 0 || request.ExportRights != 0 || request.Kind != NTL_RESOURCE_KIND_INVALID) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
(void)RssrvHandleQuery(service, endpoint, info->MessageId, &request, path);
return 0;
case NTL_RESOURCE_OP_RESOLVE:
if (request.AuxLength != 0 || info->HandleCount != 0 || request.Rights != 0 ||
request.ExportRights != 0 || request.Kind != NTL_RESOURCE_KIND_INVALID ||
(request.Flags & ~NTL_RESOURCE_RESOLVE_FLAG_MODIFY) != 0) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
(void)RssrvHandleResolve(service, endpoint, info->MessageId, &request, path);
return 0;
case NTL_RESOURCE_OP_ENUMERATE:
if (request.Flags != NTL_RESOURCE_FLAG_NONE || info->HandleCount != 0 || request.Rights != 0 ||
request.ExportRights != 0 || request.Kind != NTL_RESOURCE_KIND_INVALID ||
request.AuxLength > NTL_RESOURCE_NAME_MAX) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
for (uint32_t i = 0; i < request.AuxLength; ++i) {
if (aux[i] == '/' || aux[i] == '\\' || aux[i] == '\0') {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
}
(void)RssrvHandleEnumerate(service, endpoint, info->MessageId, &request, path, aux);
return 0;
case NTL_RESOURCE_OP_CREATE_DIRECTORY:
if (!administrative || request.Flags != NTL_RESOURCE_FLAG_NONE || request.AuxLength != 0 ||
info->HandleCount != 0 || request.Rights != 0 || request.ExportRights != 0 ||
request.Kind != NTL_RESOURCE_KIND_INVALID || RssrvVolumesOwnPath(path, request.PathLength)) {
status = administrative ? NTLSTATUS_INVALID_PARAMETER : NTLSTATUS_ACCESS_DENIED;
(void)RssrvReplyStatus(endpoint, info->MessageId, operation, status, NTL_RESOURCE_KIND_INVALID);
return 0;
}
status = RssrvNamespaceCreateDirectory(service->Namespace, path, request.PathLength);
(void)RssrvReplyStatus(endpoint, info->MessageId, operation, status,
KSUCCESS(status) ? NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY : NTL_RESOURCE_KIND_INVALID);
return 0;
case NTL_RESOURCE_OP_CREATE_SYMBOLIC_LINK:
if (!administrative || request.Flags != NTL_RESOURCE_FLAG_NONE || request.AuxLength == 0 ||
info->HandleCount != 0 || request.Rights != 0 || request.ExportRights != 0 ||
request.Kind != NTL_RESOURCE_KIND_INVALID || RssrvVolumesOwnPath(path, request.PathLength)) {
status = administrative ? NTLSTATUS_INVALID_PARAMETER : NTLSTATUS_ACCESS_DENIED;
(void)RssrvReplyStatus(endpoint, info->MessageId, operation, status, NTL_RESOURCE_KIND_INVALID);
return 0;
}
status = RssrvNamespaceValidatePath(aux, request.AuxLength);
if (KSUCCESS(status))
status = RssrvNamespaceCreateSymbolicLink(service->Namespace,
path,
request.PathLength,
aux,
request.AuxLength);
(void)RssrvReplyStatus(endpoint, info->MessageId, operation, status,
KSUCCESS(status) ? NTL_RESOURCE_KIND_SYMBOLIC_LINK : NTL_RESOURCE_KIND_INVALID);
return 0;
case NTL_RESOURCE_OP_BIND:
if (request.Flags != NTL_RESOURCE_FLAG_NONE || request.AuxLength != 0 || info->HandleCount != 1 ||
!(request.Rights & SYS_RIGHT_TRANSFER) || request.ExportRights == 0 ||
(request.ExportRights & ~request.Rights) != 0 || request.Kind == NTL_RESOURCE_KIND_INVALID ||
request.Kind == NTL_RESOURCE_KIND_NAMESPACE_DIRECTORY || request.Kind == NTL_RESOURCE_KIND_SYMBOLIC_LINK ||
receivedHandle == SYS_HANDLE_INVALID) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
{
uint32_t consumed = 0;
(void)RssrvHandleBind(service, endpoint, info->MessageId, &request, path, administrative,
receivedHandle, &consumed);
return consumed;
}
case NTL_RESOURCE_OP_UNBIND:
if (request.Flags != NTL_RESOURCE_FLAG_NONE || request.AuxLength != 0 || info->HandleCount != 0 ||
request.Rights != 0 || request.ExportRights != 0 || request.Kind != NTL_RESOURCE_KIND_INVALID) {
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_INVALID_PARAMETER, NTL_RESOURCE_KIND_INVALID);
return 0;
}
status = administrative && !RssrvVolumesOwnPath(path, request.PathLength)
? RssrvNamespaceUnbind(service->Namespace, path, request.PathLength)
: NTLSTATUS_ACCESS_DENIED;
(void)RssrvReplyStatus(endpoint, info->MessageId, operation, status, NTL_RESOURCE_KIND_INVALID);
return 0;
default:
(void)RssrvReplyStatus(endpoint, info->MessageId, operation,
NTLSTATUS_NOT_SUPPORTED, NTL_RESOURCE_KIND_INVALID);
return 0;
}
}
// Serves one connected resource session until the peer disconnects.
static void RssrvSessionThread(uintptr_t argument) {
RSSRV_SESSION* session = (RSSRV_SESSION*)argument;
if (!session || !session->Service) {
if (session) free(session);
SysExitThread(1);
return;
}
RSSRV_RESOURCE_SERVICE* service = session->Service;
SYS_HANDLE endpoint = session->Endpoint;
uint32_t administrative = session->Administrative;
RssrvSetCurrentThreadName(administrative ? "rssrv.session.admin" : "rssrv.session.public");
free(session);
uint8_t payload[SYS_PORT_MAX_INLINE_BYTES];
SYS_HANDLE handles[SYS_PORT_MAX_TRANSFER_HANDLES];
for (;;) {
memset(handles, 0, sizeof(handles));
SYS_PORT_MESSAGE_INFO info;
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 = payload;
receive.PayloadCapacity = sizeof(payload);
receive.HandlesOut = handles;
receive.HandleCapacity = SYS_PORT_MAX_TRANSFER_HANDLES;
receive.InfoOut = &info;
receive.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
KSTATUS status = SysReceivePort(&receive);
if (status == NTLSTATUS_PORT_DISCONNECTED)
break;
if (!KSUCCESS(status))
break;
uint32_t consumed = 0;
if (info.Type == SYS_PORT_MESSAGE_REQUEST)
consumed = RssrvDispatchRequest(service,
endpoint,
administrative,
payload,
info.PayloadLength,
&info,
info.HandleCount == 1 ? handles[0] : SYS_HANDLE_INVALID);
for (uint32_t i = consumed ? 1u : 0u; i < info.HandleCount; ++i) {
if (handles[i] != SYS_HANDLE_INVALID) (void)SysCloseHandle(handles[i]);
}
}
(void)SysCloseHandle(endpoint);
SysExitThread(0);
}
// Accepts sessions from one listener and gives every connection its own worker thread.
static void RssrvListenerThread(uintptr_t argument) {
RSSRV_LISTENER_WORKER* worker = (RSSRV_LISTENER_WORKER*)argument;
if (!worker || !worker->Service) {
SysExitThread(1);
return;
}
RssrvSetCurrentThreadName(worker->Administrative ? "rssrv.listen.admin" : "rssrv.listen.public");
for (;;) {
SYS_HANDLE endpoint = SYS_HANDLE_INVALID;
SYS_ACCEPT_PORT_REQUEST accept;
memset(&accept, 0, sizeof(accept));
accept.Size = sizeof(accept);
accept.ListenerHandle = worker->Listener;
accept.Flags = SYS_PORT_ACCEPT_FLAG_NONE;
accept.TimeoutMilliseconds = SYS_PORT_TIMEOUT_INFINITE;
accept.EndpointHandleOut = &endpoint;
KSTATUS status = SysAcceptPort(&accept);
if (!KSUCCESS(status))
break;
RSSRV_SESSION* session = (RSSRV_SESSION*)malloc(sizeof(*session));
if (!session) {
(void)SysDisconnectPort(endpoint);
(void)SysCloseHandle(endpoint);
continue;
}
session->Service = worker->Service;
session->Endpoint = endpoint;
session->Administrative = worker->Administrative;
SYS_CREATE_THREAD_REQUEST create;
memset(&create, 0, sizeof(create));
create.Size = sizeof(create);
create.Entry = (uintptr_t)RssrvSessionThread;
create.Argument = (uintptr_t)session;
create.Priority = 1;
create.Flags = SYS_CREATE_THREAD_FLAG_NONE;
status = SysCreateThread(&create);
if (!KSUCCESS(status)) {
free(session);
(void)SysDisconnectPort(endpoint);
(void)SysCloseHandle(endpoint);
}
}
SysExitThread(0);
}
// Creates one listener using the service's bounded default backlog.
static KSTATUS RssrvCreateListener(SYS_HANDLE* listenerOut) {
SYS_CREATE_PORT_REQUEST create;
memset(&create, 0, sizeof(create));
create.Size = sizeof(create);
create.Flags = SYS_PORT_FLAG_NONE;
create.Backlog = RSSRV_LISTENER_BACKLOG;
create.HandleOut = listenerOut;
return SysCreatePort(&create);
}
// Starts one resource listener worker thread.
static KSTATUS RssrvStartListenerWorker(RSSRV_RESOURCE_SERVICE* service,
RSSRV_LISTENER_WORKER* worker,
SYS_HANDLE listener,
uint32_t administrative) {
if (!service || !worker || listener == SYS_HANDLE_INVALID)
return NTLSTATUS_INVALID_PARAMETER;
worker->Service = service;
worker->Listener = listener;
worker->Administrative = administrative;
SYS_CREATE_THREAD_REQUEST create;
memset(&create, 0, sizeof(create));
create.Size = sizeof(create);
create.Entry = (uintptr_t)RssrvListenerThread;
create.Argument = (uintptr_t)worker;
create.Priority = 1;
create.Flags = SYS_CREATE_THREAD_FLAG_NONE;
return SysCreateThread(&create);
}
// Initializes the public/admin resource protocol component around existing namespace state.
KSTATUS RssrvResourceInitialize(RSSRV_RESOURCE_SERVICE* service,
RSSRV_NAMESPACE* namespaceState) {
if (!service || !namespaceState)
return NTLSTATUS_INVALID_PARAMETER;
memset(service, 0, sizeof(*service));
service->Namespace = namespaceState;
service->PublicListener = SYS_HANDLE_INVALID;
service->AdminListener = SYS_HANDLE_INVALID;
service->PublicWorker.Listener = SYS_HANDLE_INVALID;
service->AdminWorker.Listener = SYS_HANDLE_INVALID;
return NTLSTATUS_SUCCESS;
}
// Creates the resource listeners and starts their accept workers.
KSTATUS RssrvResourceStart(RSSRV_RESOURCE_SERVICE* service) {
if (!service || !service->Namespace)
return NTLSTATUS_INVALID_PARAMETER;
KSTATUS status = RssrvCreateListener(&service->PublicListener);
if (!KSUCCESS(status)) return status;
status = RssrvCreateListener(&service->AdminListener);
if (!KSUCCESS(status)) {
(void)SysCloseHandle(service->PublicListener);
service->PublicListener = SYS_HANDLE_INVALID;
return status;
}
status = RssrvStartListenerWorker(service, &service->PublicWorker, service->PublicListener, 0);
if (!KSUCCESS(status)) return status;
status = RssrvStartListenerWorker(service, &service->AdminWorker, service->AdminListener, 1);
return status;
}