Authenticated loopback control endpoints for Lisp image daemons.
The library defines the wire protocol shared by a detached Lisp image and the terminals controlling it: bounded length-prefixed readable packet frames with reader evaluation disabled, capability tokens, timestamp-bearing session identifiers with legacy compatibility, and deadline-bounded loopback connection and call primitives. Load the optional runtime for private endpoint discovery, persistent request services, terminal relay ownership, bounded replay and attachment client loops.
- ASDF system:
image-daemon - Optional SBCL runtime system:
image-daemon/runtime - Test system:
image-daemon/tests - Package:
IMAGE-DAEMON
Install the locked dependencies and run all tests:
./script/bootstrap
./script/check(image-daemon:daemon-call port token ':status)
(multiple-value-bind (socket stream)
(image-daemon:daemon-connect port)
(image-daemon:daemon-write-packet stream packet)
(image-daemon:daemon-read-response stream ':attach))Packets are proper lists written readably and framed by one decimal
character count. Reading rejects reader evaluation, unbalanced
payloads, and frames above *DAEMON-PACKET-CHARACTER-LIMIT*. Every
required response is bounded by *DAEMON-CONNECT-TIMEOUT-SECONDS*.
Request frames keep the historical :LOCALGROUP-REQUEST tag for
compatibility with deployed endpoints.
Create an unpublished endpoint with DAEMON-RUNTIME-CREATE, supplying an explicit
registry directory, identifier and request callback. After your own startup
transaction, call DAEMON-RUNTIME-START. Stop and unpublish with
DAEMON-RUNTIME-STOP. The callback receives (runtime request &key socket stream)
after protocol and capability validation; write the response with the packet API.
You may subclass DAEMON-RUNTIME and supply application-neutral initargs.
Use DAEMON-REGISTRY-DISCOVER to inspect complete discovery records. Registry
writers serialize with a directory file lock; publication retains live or
uncertain ownership unless the capability matches. Reconciliation deletes only
definitely dead records that still equal the inspected value. Shutdown likewise
compares the complete record, preserving an intervening replacement.
Create a RELAY with RELAY-CREATE. Implement the TRANSPORT- protocol for your
foreground transport, or specialize it on a relay subclass to synchronize your
UI’s state. RELAY-ATTACH queues the handshake and replay before live output,
allows multiple observers and one controller, and revokes the former controller
on takeover. Read semantic packets with RELAY-READ-ATTACHMENT. Resizes run under
the relay lock, so a host resize method should publish to its UI thread without
reacquiring that lock. Hosts decide when input readers may pause and whether
releasing a foreground terminal requires process handoff.
ATTACHMENT-CREATE owns an asynchronous output writer. Pending output and replay
have independent character limits. On overflow, shut down socket I/O before
abortive stream close and join the writer with a bounded wait. The client-side
DAEMON-ATTACH-CLIENT-RUN accepts input-readiness, event-read and resize callbacks;
supply its socket or a shutdown callback that unblocks concurrent reads.
Failures signal DAEMON-ERROR carrying a message, the failing
operation, and the session identifier when known. Hosts may substitute
a subclass through *DAEMON-ERROR-CLASS* to join their own condition
hierarchy.
Thread stops use one deadline across graceful exit and forced termination. If
unwind cleanup cannot finish, handle DAEMON-ERROR with operation :STOP-THREAD.
Recover the target with SB-THREAD:THREAD-ERROR-THREAD on DAEMON-ERROR-CAUSE,
release the blocked cleanup, and retry DAEMON-STOP-THREAD. Attachment and runtime
owners retain their thread references when a stop fails.
COLL-Attribution. See LICENSE.lisp.