From 83ce6de11a91841b19c694f1c97fcd0aeef9d06a Mon Sep 17 00:00:00 2001 From: Mario Fetka Date: Tue, 2 Jun 2026 06:13:07 +0000 Subject: [PATCH] docs: expand NCP provider/process redesign notes --- REDESIGN.md | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) diff --git a/REDESIGN.md b/REDESIGN.md index 3dbefcd..5a3442e 100644 --- a/REDESIGN.md +++ b/REDESIGN.md @@ -294,6 +294,185 @@ This is a design target, not a demand to move files immediately. The important part is that future code should avoid making `nwbind` a catch-all sink for unrelated NCPs just because it already has an IPC path. + +## Provider boundary versus process boundary + +A provider boundary is not the same thing as a Unix process boundary. This is +an important distinction because splitting every NCP family into a separate +process would make the server harder to debug and could introduce new ordering, +locking, and reply-ownership bugs. + +The preferred rule is: + +```text +first define logical providers; +only later promote the few large stateful providers to separate processes. +``` + +A logical provider can start as an ordinary C module called from the existing +process path. It becomes valuable as soon as the dispatch table can say "this +endpoint belongs to the queue provider" or "this endpoint belongs to the +connection-local provider", even if no new process exists yet. A process split +should be treated as an implementation detail that is only justified when the +provider has enough independent state and lifecycle to benefit from isolation. + +This keeps the redesign incremental: + +```text +now: + nwconn switch -> existing local code or nwbind handoff + +first cleanup: + nwconn switch -> provider-named helper/module + +later, only where useful: + nwconn/dispatcher -> IPC -> provider process +``` + +### Good process candidates + +#### Bindery + +Bindery is already a natural service boundary. It owns long-lived server state: +objects, properties, sets, security, password/login/key handling, and object +lookup. Keeping bindery behind a clear provider boundary is appropriate, and the +existing `nwbind` process can remain that boundary while the dispatch layer is +cleaned up. + +The main cleanup is not to remove `nwbind`, but to stop treating it as a generic +catch-all for unrelated forwarded requests. A future endpoint table should mark +true bindery calls as `bindery`, and queue or management calls should not be +classified as bindery merely because their current implementation lives in +`nwbind.c`. + +#### Queue / possible `nwqueue` + +Queue management is the strongest candidate for a future separate process after +bindery. Queue handling has its own domain state: + +- queue objects and queue metadata; +- queue job lifecycle; +- queue server attach/detach state; +- service, finish, and abort state; +- job position and priority; +- client-rights transitions during job servicing; +- queue directories and spool/job files. + +That is large enough to deserve a logical `queue` provider even before any +runtime split. A future `nwqueue` process can be considered once request/reply +ownership and bindery access are explicit. + +The first step should only be a provider split: + +```text +0x2222/23 queue subfunctions -> queue provider +queue provider -> bindery provider/library for object/security/property checks +queue provider -> file/path helpers for queue job files +``` + +A real `nwqueue` process should not be created by simply moving the current queue +cases out of `nwbind.c`. It needs an explicit contract for: + +- which process owns the final NCP reply; +- how queue calls read bindery objects and properties; +- how queue job files are opened and handed back to the connection process; +- how connection cleanup affects attached queue servers and in-service jobs; +- how old 16-bit job-number calls and newer 32-bit job-number calls are kept + compatible. + +Until those contracts are clear, `nwqueue` should remain a design target, not an +immediate functional change. + +### Possible but risky process candidates + +#### File and volume subsystem + +The file/volume/name-space area is large and stateful, so it can look like a +candidate for a separate process. It owns or touches directory handles, file +handles, locks, trustee evaluation, volume information, name spaces, salvage and +purge operations, and Unix filesystem mapping. + +However, this area is also tightly coupled to connection state and existing file +descriptor ownership. Moving it behind IPC too early could create more problems +than it solves. The safer path is: + +```text +first: file/volume/name-space provider modules inside the current process model +later: consider a process split only after handle ownership is explicit +``` + +A file provider boundary is useful for documentation and dispatch cleanup. A +separate file process is optional and should be considered high-risk. + +#### Accounting + +Accounting is a maybe. It has a separate protocol domain, but in many setups it +may be small enough to stay as an in-process provider. A process boundary only +makes sense if accounting grows into a real persistent service with charges, +holds, notes, audit records, and recovery behavior that should be isolated from +connection handlers. + +### Poor process candidates + +#### Semaphore + +Semaphore calls should have a clean provider boundary, but a dedicated process is +probably overkill. The old semaphore group is small: open, examine, wait, +signal, and close. It needs shared state, but not necessarily a standalone +process. A `sema` provider module with clear request/reply ownership should be +enough unless later testing shows that cross-connection semaphore state cannot be +managed safely in the existing process model. + +#### Connection lifecycle and session-local calls + +Connection lifecycle operations should stay with `nwconn` or a connection-local +provider. Calls such as Logout, End Of Job, watchdog handling, buffer +negotiation, and connection-state cleanup are fundamentally tied to the session +that received the packet. Moving them into another process would make cleanup +ordering and error handling harder. + +#### Simple server-management calls + +Simple management and information calls should not become their own process. +Examples include login-status queries, server description strings, server time, +console-privilege checks, and small broadcast/control helpers. These can be +represented as a `servermgmt` provider for dispatch clarity, but they should stay +in-process unless a specific call requires an existing backend service. + +### Suggested provider map + +The endpoint audit table should be able to use provider names like these: + +```text +local packet/session-local handling in nwconn +bindery object/property/security/login backend +queue queue objects, jobs, queue servers, spool/job lifecycle +filesystem file, directory, volume, namespace, trustee, salvage helpers +semaphore semaphore state and old 0x2222/32 calls +message station messaging and broadcast helpers +servermgmt small server-management and information calls +accounting account status, charges, holds, notes +AFP AFP namespace and metadata helpers +unknown documented but not yet mapped +``` + +Only some providers should ever become processes: + +```text +already process-like: bindery / nwbind +likely future process: queue / possible nwqueue +maybe, high risk: filesystem +usually in-process: semaphore, message, servermgmt, accounting, AFP helpers +``` + +The practical design rule is: + +```text +Use provider names everywhere in documentation and endpoint tables. +Use new processes only where shared state, isolation, and lifecycle justify the +extra IPC complexity. +``` + ## Logging connection The dispatch redesign also supports the desired log cleanup. If every request