RPC¶
Two-party Cap’n Proto RPC, level 1: bootstrap, calls on imported and
promised (pipelined) capabilities, returns with capability tables,
finish/release bookkeeping, disembargo echo, abort, and the
spec-mandated unimplemented reply for level 3+ messages. The vat
is single-threaded and message-driven – see :doc:`architecture`
section 4 for how rpc_pump_once dispatches one message at a time
and what state it updates.
1 Call sequence¶
sequenceDiagram
participant C as Client vat
participant S as Server vat
C->>S: Bootstrap
Note over C: rpc_bootstrap_send returns a pipeline cap<br/>immediately, before any reply arrives
S->>S: rpc_pump_once: export bootstrap_srv
S-->>C: Return (capability descriptor)
C->>S: Call add(19, 23) on the pipeline cap
Note over C: sent right after bootstrap_send;<br/>does not wait for the Bootstrap Return
S->>S: rpc_pump_once: dispatch routes to adder_server_t%add
S-->>C: Return (sum = 42)
C->>C: rpc_wait / rpc_result_content settle the answer
Note over C: rpc_result_cap later turns the pipeline<br/>reference into a settled RPC_CAP_IMPORT
A pipeline capability (RPC_CAP_PIPELINE) references a
question that has not returned yet, plus a chain of pointer-field
hops into its eventual results (rpc_pipeline_cap). Calls on it go
out immediately; the peer resolves the hop chain against its own
in-flight answer when the dependency completes. Generated client code
(:doc:`tutorial`, part 2) always returns a pipeline-capable cap from
a bootstrap or a call that yields a capability result, so pipelining
needs no separate opt-in.
2 Writing a server¶
Extend rpc_server_t and implement dispatch, or – for
schema-generated interfaces – extend the generated
<interface>_server_t base and implement its one deferred
per-method procedure (:doc:`tutorial`, part 2.1). A capability object
stays alive as long as it has a nonzero refcount in some vat’s export
table; rpc_ctx_export_cap stages a freshly minted capability
(e.g. one method’s result is itself a capability) into the current
call’s results.
To opt a capability into level 2 persistence, recognize
ctx%interface_id = RPCPERSISTENTIFACE= in dispatch and
answer RPC_PERSISTENT_SAVE with an application-defined SturdyRef
(any content the application chooses to write into the results
struct). Level 3/4 messages (Provide, Accept, Join) need
no application code; the vat answers them with
Message.unimplemented on its own, matching capnp-C++.
3 Writing a client¶
call rpc_bootstrap_send(conn, cap, err) ! pipeline cap, usable now
call rpc_call_begin(conn, target, iface_id, method_id, m, params, qid, err)
! ... fill params content ...
call rpc_call_send(conn, m, err)
call rpc_wait(conn, qid, err) ! pumps until qid returns
call rpc_result_content(conn, qid, content, err)
Schema-generated client procedures (<method>_begin /
<method>_wait) wrap exactly this sequence with typed parameter
and result handles; use them instead of the untyped calls above
whenever a schema is available (:doc:`tutorial`, part 2.2).
4 Transport¶
capnp_rpc_transport frames each RPC message with the same
segment-table framing plain serialization uses
(:doc:`reference`, “Serialization”), over a file descriptor from
capnp_posix. capnp_posix is a thin bind(c) surface over
POSIX sockets – no C sources, only iso_c_binding interfaces into
libc – covering stream sockets (TCP and Unix-domain), socketpair
loopbacks for tests, and poll-based readiness.
5 Procedure reference¶
Procedure |
Signature |
Notes |
|---|---|---|
|
|
|
|
|
half-closes and frees tables |
|
|
returns a pipeline cap, usable immediately |
|
|
fill |
|
|
|
|
|
promise pipelining into unreturned results |
|
|
pumps until the question returns |
|
|
|
|
|
settles a result capability into an import |
|
|
|
|
|
|
|
|
handle exactly one incoming message (servers loop on this) |
|
|
stage a capability in a dispatch’s results |
|
|
capability pointer for content slots |
The full public surface, including the umbrella serialization API and the C ABI shim, is in :doc:`reference`.