cannam@147
|
1 # Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
cannam@147
|
2 # Licensed under the MIT License:
|
cannam@147
|
3 #
|
cannam@147
|
4 # Permission is hereby granted, free of charge, to any person obtaining a copy
|
cannam@147
|
5 # of this software and associated documentation files (the "Software"), to deal
|
cannam@147
|
6 # in the Software without restriction, including without limitation the rights
|
cannam@147
|
7 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
cannam@147
|
8 # copies of the Software, and to permit persons to whom the Software is
|
cannam@147
|
9 # furnished to do so, subject to the following conditions:
|
cannam@147
|
10 #
|
cannam@147
|
11 # The above copyright notice and this permission notice shall be included in
|
cannam@147
|
12 # all copies or substantial portions of the Software.
|
cannam@147
|
13 #
|
cannam@147
|
14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
cannam@147
|
15 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
cannam@147
|
16 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
cannam@147
|
17 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
cannam@147
|
18 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
cannam@147
|
19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
cannam@147
|
20 # THE SOFTWARE.
|
cannam@147
|
21
|
cannam@147
|
22 @0xb312981b2552a250;
|
cannam@147
|
23 # Recall that Cap'n Proto RPC allows messages to contain references to remote objects that
|
cannam@147
|
24 # implement interfaces. These references are called "capabilities", because they both designate
|
cannam@147
|
25 # the remote object to use and confer permission to use it.
|
cannam@147
|
26 #
|
cannam@147
|
27 # Recall also that Cap'n Proto RPC has the feature that when a method call itself returns a
|
cannam@147
|
28 # capability, the caller can begin calling methods on that capability _before the first call has
|
cannam@147
|
29 # returned_. The caller essentially sends a message saying "Hey server, as soon as you finish
|
cannam@147
|
30 # that previous call, do this with the result!". Cap'n Proto's RPC protocol makes this possible.
|
cannam@147
|
31 #
|
cannam@147
|
32 # The protocol is significantly more complicated than most RPC protocols. However, this is
|
cannam@147
|
33 # implementation complexity that underlies an easy-to-grasp higher-level model of object oriented
|
cannam@147
|
34 # programming. That is, just like TCP is a surprisingly complicated protocol that implements a
|
cannam@147
|
35 # conceptually-simple byte stream abstraction, Cap'n Proto is a surprisingly complicated protocol
|
cannam@147
|
36 # that implements a conceptually-simple object abstraction.
|
cannam@147
|
37 #
|
cannam@147
|
38 # Cap'n Proto RPC is based heavily on CapTP, the object-capability protocol used by the E
|
cannam@147
|
39 # programming language:
|
cannam@147
|
40 # http://www.erights.org/elib/distrib/captp/index.html
|
cannam@147
|
41 #
|
cannam@147
|
42 # Cap'n Proto RPC takes place between "vats". A vat hosts some set of objects and talks to other
|
cannam@147
|
43 # vats through direct bilateral connections. Typically, there is a 1:1 correspondence between vats
|
cannam@147
|
44 # and processes (in the unix sense of the word), although this is not strictly always true (one
|
cannam@147
|
45 # process could run multiple vats, or a distributed virtual vat might live across many processes).
|
cannam@147
|
46 #
|
cannam@147
|
47 # Cap'n Proto does not distinguish between "clients" and "servers" -- this is up to the application.
|
cannam@147
|
48 # Either end of any connection can potentially hold capabilities pointing to the other end, and
|
cannam@147
|
49 # can call methods on those capabilities. In the doc comments below, we use the words "sender"
|
cannam@147
|
50 # and "receiver". These refer to the sender and receiver of an instance of the struct or field
|
cannam@147
|
51 # being documented. Sometimes we refer to a "third-party" that is neither the sender nor the
|
cannam@147
|
52 # receiver. Documentation is generally written from the point of view of the sender.
|
cannam@147
|
53 #
|
cannam@147
|
54 # It is generally up to the vat network implementation to securely verify that connections are made
|
cannam@147
|
55 # to the intended vat as well as to encrypt transmitted data for privacy and integrity. See the
|
cannam@147
|
56 # `VatNetwork` example interface near the end of this file.
|
cannam@147
|
57 #
|
cannam@147
|
58 # When a new connection is formed, the only interesting things that can be done are to send a
|
cannam@147
|
59 # `Bootstrap` (level 0) or `Accept` (level 3) message.
|
cannam@147
|
60 #
|
cannam@147
|
61 # Unless otherwise specified, messages must be delivered to the receiving application in the same
|
cannam@147
|
62 # order in which they were initiated by the sending application. The goal is to support "E-Order",
|
cannam@147
|
63 # which states that two calls made on the same reference must be delivered in the order which they
|
cannam@147
|
64 # were made:
|
cannam@147
|
65 # http://erights.org/elib/concurrency/partial-order.html
|
cannam@147
|
66 #
|
cannam@147
|
67 # Since the full protocol is complicated, we define multiple levels of support that an
|
cannam@147
|
68 # implementation may target. For many applications, level 1 support will be sufficient.
|
cannam@147
|
69 # Comments in this file indicate which level requires the corresponding feature to be
|
cannam@147
|
70 # implemented.
|
cannam@147
|
71 #
|
cannam@147
|
72 # * **Level 0:** The implementation does not support object references. Only the bootstrap interface
|
cannam@147
|
73 # can be called. At this level, the implementation does not support object-oriented protocols and
|
cannam@147
|
74 # is similar in complexity to JSON-RPC or Protobuf services. This level should be considered only
|
cannam@147
|
75 # a temporary stepping-stone toward level 1 as the lack of object references drastically changes
|
cannam@147
|
76 # how protocols are designed. Applications _should not_ attempt to design their protocols around
|
cannam@147
|
77 # the limitations of level 0 implementations.
|
cannam@147
|
78 #
|
cannam@147
|
79 # * **Level 1:** The implementation supports simple bilateral interaction with object references
|
cannam@147
|
80 # and promise pipelining, but interactions between three or more parties are supported only via
|
cannam@147
|
81 # proxying of objects. E.g. if Alice (in Vat A) wants to send Bob (in Vat B) a capability
|
cannam@147
|
82 # pointing to Carol (in Vat C), Alice must create a proxy of Carol within Vat A and send Bob a
|
cannam@147
|
83 # reference to that; Bob cannot form a direct connection to Carol. Level 1 implementations do
|
cannam@147
|
84 # not support checking if two capabilities received from different vats actually point to the
|
cannam@147
|
85 # same object ("join"), although they should be able to do this check on capabilities received
|
cannam@147
|
86 # from the same vat.
|
cannam@147
|
87 #
|
cannam@147
|
88 # * **Level 2:** The implementation supports saving persistent capabilities -- i.e. capabilities
|
cannam@147
|
89 # that remain valid even after disconnect, and can be restored on a future connection. When a
|
cannam@147
|
90 # capability is saved, the requester receives a `SturdyRef`, which is a token that can be used
|
cannam@147
|
91 # to restore the capability later.
|
cannam@147
|
92 #
|
cannam@147
|
93 # * **Level 3:** The implementation supports three-way interactions. That is, if Alice (in Vat A)
|
cannam@147
|
94 # sends Bob (in Vat B) a capability pointing to Carol (in Vat C), then Vat B will automatically
|
cannam@147
|
95 # form a direct connection to Vat C rather than have requests be proxied through Vat A.
|
cannam@147
|
96 #
|
cannam@147
|
97 # * **Level 4:** The entire protocol is implemented, including joins (checking if two capabilities
|
cannam@147
|
98 # are equivalent).
|
cannam@147
|
99 #
|
cannam@147
|
100 # Note that an implementation must also support specific networks (transports), as described in
|
cannam@147
|
101 # the "Network-specific Parameters" section below. An implementation might have different levels
|
cannam@147
|
102 # depending on the network used.
|
cannam@147
|
103 #
|
cannam@147
|
104 # New implementations of Cap'n Proto should start out targeting the simplistic two-party network
|
cannam@147
|
105 # type as defined in `rpc-twoparty.capnp`. With this network type, level 3 is irrelevant and
|
cannam@147
|
106 # levels 2 and 4 are much easier than usual to implement. When such an implementation is paired
|
cannam@147
|
107 # with a container proxy, the contained app effectively gets to make full use of the proxy's
|
cannam@147
|
108 # network at level 4. And since Cap'n Proto IPC is extremely fast, it may never make sense to
|
cannam@147
|
109 # bother implementing any other vat network protocol -- just use the correct container type and get
|
cannam@147
|
110 # it for free.
|
cannam@147
|
111
|
cannam@147
|
112 using Cxx = import "/capnp/c++.capnp";
|
cannam@147
|
113 $Cxx.namespace("capnp::rpc");
|
cannam@147
|
114
|
cannam@147
|
115 # ========================================================================================
|
cannam@147
|
116 # The Four Tables
|
cannam@147
|
117 #
|
cannam@147
|
118 # Cap'n Proto RPC connections are stateful (although an application built on Cap'n Proto could
|
cannam@147
|
119 # export a stateless interface). As in CapTP, for each open connection, a vat maintains four state
|
cannam@147
|
120 # tables: questions, answers, imports, and exports. See the diagram at:
|
cannam@147
|
121 # http://www.erights.org/elib/distrib/captp/4tables.html
|
cannam@147
|
122 #
|
cannam@147
|
123 # The question table corresponds to the other end's answer table, and the imports table corresponds
|
cannam@147
|
124 # to the other end's exports table.
|
cannam@147
|
125 #
|
cannam@147
|
126 # The entries in each table are identified by ID numbers (defined below as 32-bit integers). These
|
cannam@147
|
127 # numbers are always specific to the connection; a newly-established connection starts with no
|
cannam@147
|
128 # valid IDs. Since low-numbered IDs will pack better, it is suggested that IDs be assigned like
|
cannam@147
|
129 # Unix file descriptors -- prefer the lowest-number ID that is currently available.
|
cannam@147
|
130 #
|
cannam@147
|
131 # IDs in the questions/answers tables are chosen by the questioner and generally represent method
|
cannam@147
|
132 # calls that are in progress.
|
cannam@147
|
133 #
|
cannam@147
|
134 # IDs in the imports/exports tables are chosen by the exporter and generally represent objects on
|
cannam@147
|
135 # which methods may be called. Exports may be "settled", meaning the exported object is an actual
|
cannam@147
|
136 # object living in the exporter's vat, or they may be "promises", meaning the exported object is
|
cannam@147
|
137 # the as-yet-unknown result of an ongoing operation and will eventually be resolved to some other
|
cannam@147
|
138 # object once that operation completes. Calls made to a promise will be forwarded to the eventual
|
cannam@147
|
139 # target once it is known. The eventual replacement object does *not* get the same ID as the
|
cannam@147
|
140 # promise, as it may turn out to be an object that is already exported (so already has an ID) or
|
cannam@147
|
141 # may even live in a completely different vat (and so won't get an ID on the same export table
|
cannam@147
|
142 # at all).
|
cannam@147
|
143 #
|
cannam@147
|
144 # IDs can be reused over time. To make this safe, we carefully define the lifetime of IDs. Since
|
cannam@147
|
145 # messages using the ID could be traveling in both directions simultaneously, we must define the
|
cannam@147
|
146 # end of life of each ID _in each direction_. The ID is only safe to reuse once it has been
|
cannam@147
|
147 # released by both sides.
|
cannam@147
|
148 #
|
cannam@147
|
149 # When a Cap'n Proto connection is lost, everything on the four tables is lost. All questions are
|
cannam@147
|
150 # canceled and throw exceptions. All imports become broken (all future calls to them throw
|
cannam@147
|
151 # exceptions). All exports and answers are implicitly released. The only things not lost are
|
cannam@147
|
152 # persistent capabilities (`SturdyRef`s). The application must plan for this and should respond by
|
cannam@147
|
153 # establishing a new connection and restoring from these persistent capabilities.
|
cannam@147
|
154
|
cannam@147
|
155 using QuestionId = UInt32;
|
cannam@147
|
156 # **(level 0)**
|
cannam@147
|
157 #
|
cannam@147
|
158 # Identifies a question in the sender's question table (which corresponds to the receiver's answer
|
cannam@147
|
159 # table). The questioner (caller) chooses an ID when making a call. The ID remains valid in
|
cannam@147
|
160 # caller -> callee messages until a Finish message is sent, and remains valid in callee -> caller
|
cannam@147
|
161 # messages until a Return message is sent.
|
cannam@147
|
162
|
cannam@147
|
163 using AnswerId = QuestionId;
|
cannam@147
|
164 # **(level 0)**
|
cannam@147
|
165 #
|
cannam@147
|
166 # Identifies an answer in the sender's answer table (which corresponds to the receiver's question
|
cannam@147
|
167 # table).
|
cannam@147
|
168 #
|
cannam@147
|
169 # AnswerId is physically equivalent to QuestionId, since the question and answer tables correspond,
|
cannam@147
|
170 # but we define a separate type for documentation purposes: we always use the type representing
|
cannam@147
|
171 # the sender's point of view.
|
cannam@147
|
172
|
cannam@147
|
173 using ExportId = UInt32;
|
cannam@147
|
174 # **(level 1)**
|
cannam@147
|
175 #
|
cannam@147
|
176 # Identifies an exported capability or promise in the sender's export table (which corresponds
|
cannam@147
|
177 # to the receiver's import table). The exporter chooses an ID before sending a capability over the
|
cannam@147
|
178 # wire. If the capability is already in the table, the exporter should reuse the same ID. If the
|
cannam@147
|
179 # ID is a promise (as opposed to a settled capability), this must be indicated at the time the ID
|
cannam@147
|
180 # is introduced (e.g. by using `senderPromise` instead of `senderHosted` in `CapDescriptor`); in
|
cannam@147
|
181 # this case, the importer shall expect a later `Resolve` message that replaces the promise.
|
cannam@147
|
182 #
|
cannam@147
|
183 # ExportId/ImportIds are subject to reference counting. Whenever an `ExportId` is sent over the
|
cannam@147
|
184 # wire (from the exporter to the importer), the export's reference count is incremented (unless
|
cannam@147
|
185 # otherwise specified). The reference count is later decremented by a `Release` message. Since
|
cannam@147
|
186 # the `Release` message can specify an arbitrary number by which to reduce the reference count, the
|
cannam@147
|
187 # importer should usually batch reference decrements and only send a `Release` when it believes the
|
cannam@147
|
188 # reference count has hit zero. Of course, it is possible that a new reference to the export is
|
cannam@147
|
189 # in-flight at the time that the `Release` message is sent, so it is necessary for the exporter to
|
cannam@147
|
190 # keep track of the reference count on its end as well to avoid race conditions.
|
cannam@147
|
191 #
|
cannam@147
|
192 # When a connection is lost, all exports are implicitly released. It is not possible to restore
|
cannam@147
|
193 # a connection state after disconnect (although a transport layer could implement a concept of
|
cannam@147
|
194 # persistent connections if it is transparent to the RPC layer).
|
cannam@147
|
195
|
cannam@147
|
196 using ImportId = ExportId;
|
cannam@147
|
197 # **(level 1)**
|
cannam@147
|
198 #
|
cannam@147
|
199 # Identifies an imported capability or promise in the sender's import table (which corresponds to
|
cannam@147
|
200 # the receiver's export table).
|
cannam@147
|
201 #
|
cannam@147
|
202 # ImportId is physically equivalent to ExportId, since the export and import tables correspond,
|
cannam@147
|
203 # but we define a separate type for documentation purposes: we always use the type representing
|
cannam@147
|
204 # the sender's point of view.
|
cannam@147
|
205 #
|
cannam@147
|
206 # An `ImportId` remains valid in importer -> exporter messages until the importer has sent
|
cannam@147
|
207 # `Release` messages that (it believes) have reduced the reference count to zero.
|
cannam@147
|
208
|
cannam@147
|
209 # ========================================================================================
|
cannam@147
|
210 # Messages
|
cannam@147
|
211
|
cannam@147
|
212 struct Message {
|
cannam@147
|
213 # An RPC connection is a bi-directional stream of Messages.
|
cannam@147
|
214
|
cannam@147
|
215 union {
|
cannam@147
|
216 unimplemented @0 :Message;
|
cannam@147
|
217 # The sender previously received this message from the peer but didn't understand it or doesn't
|
cannam@147
|
218 # yet implement the functionality that was requested. So, the sender is echoing the message
|
cannam@147
|
219 # back. In some cases, the receiver may be able to recover from this by pretending the sender
|
cannam@147
|
220 # had taken some appropriate "null" action.
|
cannam@147
|
221 #
|
cannam@147
|
222 # For example, say `resolve` is received by a level 0 implementation (because a previous call
|
cannam@147
|
223 # or return happened to contain a promise). The level 0 implementation will echo it back as
|
cannam@147
|
224 # `unimplemented`. The original sender can then simply release the cap to which the promise
|
cannam@147
|
225 # had resolved, thus avoiding a leak.
|
cannam@147
|
226 #
|
cannam@147
|
227 # For any message type that introduces a question, if the message comes back unimplemented,
|
cannam@147
|
228 # the original sender may simply treat it as if the question failed with an exception.
|
cannam@147
|
229 #
|
cannam@147
|
230 # In cases where there is no sensible way to react to an `unimplemented` message (without
|
cannam@147
|
231 # resource leaks or other serious problems), the connection may need to be aborted. This is
|
cannam@147
|
232 # a gray area; different implementations may take different approaches.
|
cannam@147
|
233
|
cannam@147
|
234 abort @1 :Exception;
|
cannam@147
|
235 # Sent when a connection is being aborted due to an unrecoverable error. This could be e.g.
|
cannam@147
|
236 # because the sender received an invalid or nonsensical message (`isCallersFault` is true) or
|
cannam@147
|
237 # because the sender had an internal error (`isCallersFault` is false). The sender will shut
|
cannam@147
|
238 # down the outgoing half of the connection after `abort` and will completely close the
|
cannam@147
|
239 # connection shortly thereafter (it's up to the sender how much of a time buffer they want to
|
cannam@147
|
240 # offer for the client to receive the `abort` before the connection is reset).
|
cannam@147
|
241
|
cannam@147
|
242 # Level 0 features -----------------------------------------------
|
cannam@147
|
243
|
cannam@147
|
244 bootstrap @8 :Bootstrap; # Request the peer's bootstrap interface.
|
cannam@147
|
245 call @2 :Call; # Begin a method call.
|
cannam@147
|
246 return @3 :Return; # Complete a method call.
|
cannam@147
|
247 finish @4 :Finish; # Release a returned answer / cancel a call.
|
cannam@147
|
248
|
cannam@147
|
249 # Level 1 features -----------------------------------------------
|
cannam@147
|
250
|
cannam@147
|
251 resolve @5 :Resolve; # Resolve a previously-sent promise.
|
cannam@147
|
252 release @6 :Release; # Release a capability so that the remote object can be deallocated.
|
cannam@147
|
253 disembargo @13 :Disembargo; # Lift an embargo used to enforce E-order over promise resolution.
|
cannam@147
|
254
|
cannam@147
|
255 # Level 2 features -----------------------------------------------
|
cannam@147
|
256
|
cannam@147
|
257 obsoleteSave @7 :AnyPointer;
|
cannam@147
|
258 # Obsolete request to save a capability, resulting in a SturdyRef. This has been replaced
|
cannam@147
|
259 # by the `Persistent` interface defined in `persistent.capnp`. This operation was never
|
cannam@147
|
260 # implemented.
|
cannam@147
|
261
|
cannam@147
|
262 obsoleteDelete @9 :AnyPointer;
|
cannam@147
|
263 # Obsolete way to delete a SturdyRef. This operation was never implemented.
|
cannam@147
|
264
|
cannam@147
|
265 # Level 3 features -----------------------------------------------
|
cannam@147
|
266
|
cannam@147
|
267 provide @10 :Provide; # Provide a capability to a third party.
|
cannam@147
|
268 accept @11 :Accept; # Accept a capability provided by a third party.
|
cannam@147
|
269
|
cannam@147
|
270 # Level 4 features -----------------------------------------------
|
cannam@147
|
271
|
cannam@147
|
272 join @12 :Join; # Directly connect to the common root of two or more proxied caps.
|
cannam@147
|
273 }
|
cannam@147
|
274 }
|
cannam@147
|
275
|
cannam@147
|
276 # Level 0 message types ----------------------------------------------
|
cannam@147
|
277
|
cannam@147
|
278 struct Bootstrap {
|
cannam@147
|
279 # **(level 0)**
|
cannam@147
|
280 #
|
cannam@147
|
281 # Get the "bootstrap" interface exported by the remote vat.
|
cannam@147
|
282 #
|
cannam@147
|
283 # For level 0, 1, and 2 implementations, the "bootstrap" interface is simply the main interface
|
cannam@147
|
284 # exported by a vat. If the vat acts as a server fielding connections from clients, then the
|
cannam@147
|
285 # bootstrap interface defines the basic functionality available to a client when it connects.
|
cannam@147
|
286 # The exact interface definition obviously depends on the application.
|
cannam@147
|
287 #
|
cannam@147
|
288 # We call this a "bootstrap" because in an ideal Cap'n Proto world, bootstrap interfaces would
|
cannam@147
|
289 # never be used. In such a world, any time you connect to a new vat, you do so because you
|
cannam@147
|
290 # received an introduction from some other vat (see `ThirdPartyCapId`). Thus, the first message
|
cannam@147
|
291 # you send is `Accept`, and further communications derive from there. `Bootstrap` is not used.
|
cannam@147
|
292 #
|
cannam@147
|
293 # In such an ideal world, DNS itself would support Cap'n Proto -- performing a DNS lookup would
|
cannam@147
|
294 # actually return a new Cap'n Proto capability, thus introducing you to the target system via
|
cannam@147
|
295 # level 3 RPC. Applications would receive the capability to talk to DNS in the first place as
|
cannam@147
|
296 # an initial endowment or part of a Powerbox interaction. Therefore, an app can form arbitrary
|
cannam@147
|
297 # connections without ever using `Bootstrap`.
|
cannam@147
|
298 #
|
cannam@147
|
299 # Of course, in the real world, DNS is not Cap'n-Proto-based, and we don't want Cap'n Proto to
|
cannam@147
|
300 # require a whole new internet infrastructure to be useful. Therefore, we offer bootstrap
|
cannam@147
|
301 # interfaces as a way to get up and running without a level 3 introduction. Thus, bootstrap
|
cannam@147
|
302 # interfaces are used to "bootstrap" from other, non-Cap'n-Proto-based means of service discovery,
|
cannam@147
|
303 # such as legacy DNS.
|
cannam@147
|
304 #
|
cannam@147
|
305 # Note that a vat need not provide a bootstrap interface, and in fact many vats (especially those
|
cannam@147
|
306 # acting as clients) do not. In this case, the vat should either reply to `Bootstrap` with a
|
cannam@147
|
307 # `Return` indicating an exception, or should return a dummy capability with no methods.
|
cannam@147
|
308
|
cannam@147
|
309 questionId @0 :QuestionId;
|
cannam@147
|
310 # A new question ID identifying this request, which will eventually receive a Return message
|
cannam@147
|
311 # containing the restored capability.
|
cannam@147
|
312
|
cannam@147
|
313 deprecatedObjectId @1 :AnyPointer;
|
cannam@147
|
314 # ** DEPRECATED **
|
cannam@147
|
315 #
|
cannam@147
|
316 # A Vat may export multiple bootstrap interfaces. In this case, `deprecatedObjectId` specifies
|
cannam@147
|
317 # which one to return. If this pointer is null, then the default bootstrap interface is returned.
|
cannam@147
|
318 #
|
cannam@147
|
319 # As of verison 0.5, use of this field is deprecated. If a service wants to export multiple
|
cannam@147
|
320 # bootstrap interfaces, it should instead define a single bootstarp interface that has methods
|
cannam@147
|
321 # that return each of the other interfaces.
|
cannam@147
|
322 #
|
cannam@147
|
323 # **History**
|
cannam@147
|
324 #
|
cannam@147
|
325 # In the first version of Cap'n Proto RPC (0.4.x) the `Bootstrap` message was called `Restore`.
|
cannam@147
|
326 # At the time, it was thought that this would eventually serve as the way to restore SturdyRefs
|
cannam@147
|
327 # (level 2). Meanwhile, an application could offer its "main" interface on a well-known
|
cannam@147
|
328 # (non-secret) SturdyRef.
|
cannam@147
|
329 #
|
cannam@147
|
330 # Since level 2 RPC was not implemented at the time, the `Restore` message was in practice only
|
cannam@147
|
331 # used to obtain the main interface. Since most applications had only one main interface that
|
cannam@147
|
332 # they wanted to restore, they tended to designate this with a null `objectId`.
|
cannam@147
|
333 #
|
cannam@147
|
334 # Unfortunately, the earliest version of the EZ RPC interfaces set a precedent of exporting
|
cannam@147
|
335 # multiple main interfaces by allowing them to be exported under string names. In this case,
|
cannam@147
|
336 # `objectId` was a Text value specifying the name.
|
cannam@147
|
337 #
|
cannam@147
|
338 # All of this proved problematic for several reasons:
|
cannam@147
|
339 #
|
cannam@147
|
340 # - The arrangement assumed that a client wishing to restore a SturdyRef would know exactly what
|
cannam@147
|
341 # machine to connect to and would be able to immediately restore a SturdyRef on connection.
|
cannam@147
|
342 # However, in practice, the ability to restore SturdyRefs is itself a capability that may
|
cannam@147
|
343 # require going through an authentication process to obtain. Thus, it makes more sense to
|
cannam@147
|
344 # define a "restorer service" as a full Cap'n Proto interface. If this restorer interface is
|
cannam@147
|
345 # offered as the vat's bootstrap interface, then this is equivalent to the old arrangement.
|
cannam@147
|
346 #
|
cannam@147
|
347 # - Overloading "Restore" for the purpose of obtaining well-known capabilities encouraged the
|
cannam@147
|
348 # practice of exporting singleton services with string names. If singleton services are desired,
|
cannam@147
|
349 # it is better to have one main interface that has methods that can be used to obtain each
|
cannam@147
|
350 # service, in order to get all the usual benefits of schemas and type checking.
|
cannam@147
|
351 #
|
cannam@147
|
352 # - Overloading "Restore" also had a security problem: Often, "main" or "well-known"
|
cannam@147
|
353 # capabilities exported by a vat are in fact not public: they are intended to be accessed only
|
cannam@147
|
354 # by clients who are capable of forming a connection to the vat. This can lead to trouble if
|
cannam@147
|
355 # the client itself has other clients and wishes to foward some `Restore` requests from those
|
cannam@147
|
356 # external clients -- it has to be very careful not to allow through `Restore` requests
|
cannam@147
|
357 # addressing the default capability.
|
cannam@147
|
358 #
|
cannam@147
|
359 # For example, consider the case of a sandboxed Sandstorm application and its supervisor. The
|
cannam@147
|
360 # application exports a default capability to its supervisor that provides access to
|
cannam@147
|
361 # functionality that only the supervisor is supposed to access. Meanwhile, though, applications
|
cannam@147
|
362 # may publish other capabilities that may be persistent, in which case the application needs
|
cannam@147
|
363 # to field `Restore` requests that could come from anywhere. These requests of course have to
|
cannam@147
|
364 # pass through the supervisor, as all communications with the outside world must. But, the
|
cannam@147
|
365 # supervisor has to be careful not to honor an external request addressing the application's
|
cannam@147
|
366 # default capability, since this capability is privileged. Unfortunately, the default
|
cannam@147
|
367 # capability cannot be given an unguessable name, because then the supervisor itself would not
|
cannam@147
|
368 # be able to address it!
|
cannam@147
|
369 #
|
cannam@147
|
370 # As of Cap'n Proto 0.5, `Restore` has been renamed to `Bootstrap` and is no longer planned for
|
cannam@147
|
371 # use in restoring SturdyRefs.
|
cannam@147
|
372 #
|
cannam@147
|
373 # Note that 0.4 also defined a message type called `Delete` that, like `Restore`, addressed a
|
cannam@147
|
374 # SturdyRef, but indicated that the client would not restore the ref again in the future. This
|
cannam@147
|
375 # operation was never implemented, so it was removed entirely. If a "delete" operation is desired,
|
cannam@147
|
376 # it should exist as a method on the same interface that handles restoring SturdyRefs. However,
|
cannam@147
|
377 # the utility of such an operation is questionable. You wouldn't be able to rely on it for
|
cannam@147
|
378 # garbage collection since a client could always disappear permanently without remembering to
|
cannam@147
|
379 # delete all its SturdyRefs, thus leaving them dangling forever. Therefore, it is advisable to
|
cannam@147
|
380 # design systems such that SturdyRefs never represent "owned" pointers.
|
cannam@147
|
381 #
|
cannam@147
|
382 # For example, say a SturdyRef points to an image file hosted on some server. That image file
|
cannam@147
|
383 # should also live inside a collection (a gallery, perhaps) hosted on the same server, owned by
|
cannam@147
|
384 # a user who can delete the image at any time. If the user deletes the image, the SturdyRef
|
cannam@147
|
385 # stops working. On the other hand, if the SturdyRef is discarded, this has no effect on the
|
cannam@147
|
386 # existence of the image in its collection.
|
cannam@147
|
387 }
|
cannam@147
|
388
|
cannam@147
|
389 struct Call {
|
cannam@147
|
390 # **(level 0)**
|
cannam@147
|
391 #
|
cannam@147
|
392 # Message type initiating a method call on a capability.
|
cannam@147
|
393
|
cannam@147
|
394 questionId @0 :QuestionId;
|
cannam@147
|
395 # A number, chosen by the caller, that identifies this call in future messages. This number
|
cannam@147
|
396 # must be different from all other calls originating from the same end of the connection (but
|
cannam@147
|
397 # may overlap with question IDs originating from the opposite end). A fine strategy is to use
|
cannam@147
|
398 # sequential question IDs, but the recipient should not assume this.
|
cannam@147
|
399 #
|
cannam@147
|
400 # A question ID can be reused once both:
|
cannam@147
|
401 # - A matching Return has been received from the callee.
|
cannam@147
|
402 # - A matching Finish has been sent from the caller.
|
cannam@147
|
403
|
cannam@147
|
404 target @1 :MessageTarget;
|
cannam@147
|
405 # The object that should receive this call.
|
cannam@147
|
406
|
cannam@147
|
407 interfaceId @2 :UInt64;
|
cannam@147
|
408 # The type ID of the interface being called. Each capability may implement multiple interfaces.
|
cannam@147
|
409
|
cannam@147
|
410 methodId @3 :UInt16;
|
cannam@147
|
411 # The ordinal number of the method to call within the requested interface.
|
cannam@147
|
412
|
cannam@147
|
413 allowThirdPartyTailCall @8 :Bool = false;
|
cannam@147
|
414 # Indicates whether or not the receiver is allowed to send a `Return` containing
|
cannam@147
|
415 # `acceptFromThirdParty`. Level 3 implementations should set this true. Otherwise, the callee
|
cannam@147
|
416 # will have to proxy the return in the case of a tail call to a third-party vat.
|
cannam@147
|
417
|
cannam@147
|
418 params @4 :Payload;
|
cannam@147
|
419 # The call parameters. `params.content` is a struct whose fields correspond to the parameters of
|
cannam@147
|
420 # the method.
|
cannam@147
|
421
|
cannam@147
|
422 sendResultsTo :union {
|
cannam@147
|
423 # Where should the return message be sent?
|
cannam@147
|
424
|
cannam@147
|
425 caller @5 :Void;
|
cannam@147
|
426 # Send the return message back to the caller (the usual).
|
cannam@147
|
427
|
cannam@147
|
428 yourself @6 :Void;
|
cannam@147
|
429 # **(level 1)**
|
cannam@147
|
430 #
|
cannam@147
|
431 # Don't actually return the results to the sender. Instead, hold on to them and await
|
cannam@147
|
432 # instructions from the sender regarding what to do with them. In particular, the sender
|
cannam@147
|
433 # may subsequently send a `Return` for some other call (which the receiver had previously made
|
cannam@147
|
434 # to the sender) with `takeFromOtherQuestion` set. The results from this call are then used
|
cannam@147
|
435 # as the results of the other call.
|
cannam@147
|
436 #
|
cannam@147
|
437 # When `yourself` is used, the receiver must still send a `Return` for the call, but sets the
|
cannam@147
|
438 # field `resultsSentElsewhere` in that `Return` rather than including the results.
|
cannam@147
|
439 #
|
cannam@147
|
440 # This feature can be used to implement tail calls in which a call from Vat A to Vat B ends up
|
cannam@147
|
441 # returning the result of a call from Vat B back to Vat A.
|
cannam@147
|
442 #
|
cannam@147
|
443 # In particular, the most common use case for this feature is when Vat A makes a call to a
|
cannam@147
|
444 # promise in Vat B, and then that promise ends up resolving to a capability back in Vat A.
|
cannam@147
|
445 # Vat B must forward all the queued calls on that promise back to Vat A, but can set `yourself`
|
cannam@147
|
446 # in the calls so that the results need not pass back through Vat B.
|
cannam@147
|
447 #
|
cannam@147
|
448 # For example:
|
cannam@147
|
449 # - Alice, in Vat A, call foo() on Bob in Vat B.
|
cannam@147
|
450 # - Alice makes a pipelined call bar() on the promise returned by foo().
|
cannam@147
|
451 # - Later on, Bob resolves the promise from foo() to point at Carol, who lives in Vat A (next
|
cannam@147
|
452 # to Alice).
|
cannam@147
|
453 # - Vat B dutifully forwards the bar() call to Carol. Let us call this forwarded call bar'().
|
cannam@147
|
454 # Notice that bar() and bar'() are travelling in opposite directions on the same network
|
cannam@147
|
455 # link.
|
cannam@147
|
456 # - The `Call` for bar'() has `sendResultsTo` set to `yourself`, with the value being the
|
cannam@147
|
457 # question ID originally assigned to the bar() call.
|
cannam@147
|
458 # - Vat A receives bar'() and delivers it to Carol.
|
cannam@147
|
459 # - When bar'() returns, Vat A immediately takes the results and returns them from bar().
|
cannam@147
|
460 # - Meanwhile, Vat A sends a `Return` for bar'() to Vat B, with `resultsSentElsewhere` set in
|
cannam@147
|
461 # place of results.
|
cannam@147
|
462 # - Vat A sends a `Finish` for that call to Vat B.
|
cannam@147
|
463 # - Vat B receives the `Return` for bar'() and sends a `Return` for bar(), with
|
cannam@147
|
464 # `receivedFromYourself` set in place of the results.
|
cannam@147
|
465 # - Vat B receives the `Finish` for bar() and sends a `Finish` to bar'().
|
cannam@147
|
466
|
cannam@147
|
467 thirdParty @7 :RecipientId;
|
cannam@147
|
468 # **(level 3)**
|
cannam@147
|
469 #
|
cannam@147
|
470 # The call's result should be returned to a different vat. The receiver (the callee) expects
|
cannam@147
|
471 # to receive an `Accept` message from the indicated vat, and should return the call's result
|
cannam@147
|
472 # to it, rather than to the sender of the `Call`.
|
cannam@147
|
473 #
|
cannam@147
|
474 # This operates much like `yourself`, above, except that Carol is in a separate Vat C. `Call`
|
cannam@147
|
475 # messages are sent from Vat A -> Vat B and Vat B -> Vat C. A `Return` message is sent from
|
cannam@147
|
476 # Vat B -> Vat A that contains `acceptFromThirdParty` in place of results. When Vat A sends
|
cannam@147
|
477 # an `Accept` to Vat C, it receives back a `Return` containing the call's actual result. Vat C
|
cannam@147
|
478 # also sends a `Return` to Vat B with `resultsSentElsewhere`.
|
cannam@147
|
479 }
|
cannam@147
|
480 }
|
cannam@147
|
481
|
cannam@147
|
482 struct Return {
|
cannam@147
|
483 # **(level 0)**
|
cannam@147
|
484 #
|
cannam@147
|
485 # Message type sent from callee to caller indicating that the call has completed.
|
cannam@147
|
486
|
cannam@147
|
487 answerId @0 :AnswerId;
|
cannam@147
|
488 # Equal to the QuestionId of the corresponding `Call` message.
|
cannam@147
|
489
|
cannam@147
|
490 releaseParamCaps @1 :Bool = true;
|
cannam@147
|
491 # If true, all capabilities that were in the params should be considered released. The sender
|
cannam@147
|
492 # must not send separate `Release` messages for them. Level 0 implementations in particular
|
cannam@147
|
493 # should always set this true. This defaults true because if level 0 implementations forget to
|
cannam@147
|
494 # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget
|
cannam@147
|
495 # to set it to false they'll quickly get errors.
|
cannam@147
|
496
|
cannam@147
|
497 union {
|
cannam@147
|
498 results @2 :Payload;
|
cannam@147
|
499 # The result.
|
cannam@147
|
500 #
|
cannam@147
|
501 # For regular method calls, `results.content` points to the result struct.
|
cannam@147
|
502 #
|
cannam@147
|
503 # For a `Return` in response to an `Accept`, `results` contains a single capability (rather
|
cannam@147
|
504 # than a struct), and `results.content` is just a capability pointer with index 0. A `Finish`
|
cannam@147
|
505 # is still required in this case.
|
cannam@147
|
506
|
cannam@147
|
507 exception @3 :Exception;
|
cannam@147
|
508 # Indicates that the call failed and explains why.
|
cannam@147
|
509
|
cannam@147
|
510 canceled @4 :Void;
|
cannam@147
|
511 # Indicates that the call was canceled due to the caller sending a Finish message
|
cannam@147
|
512 # before the call had completed.
|
cannam@147
|
513
|
cannam@147
|
514 resultsSentElsewhere @5 :Void;
|
cannam@147
|
515 # This is set when returning from a `Call` that had `sendResultsTo` set to something other
|
cannam@147
|
516 # than `caller`.
|
cannam@147
|
517
|
cannam@147
|
518 takeFromOtherQuestion @6 :QuestionId;
|
cannam@147
|
519 # The sender has also sent (before this message) a `Call` with the given question ID and with
|
cannam@147
|
520 # `sendResultsTo.yourself` set, and the results of that other call should be used as the
|
cannam@147
|
521 # results here.
|
cannam@147
|
522
|
cannam@147
|
523 acceptFromThirdParty @7 :ThirdPartyCapId;
|
cannam@147
|
524 # **(level 3)**
|
cannam@147
|
525 #
|
cannam@147
|
526 # The caller should contact a third-party vat to pick up the results. An `Accept` message
|
cannam@147
|
527 # sent to the vat will return the result. This pairs with `Call.sendResultsTo.thirdParty`.
|
cannam@147
|
528 # It should only be used if the corresponding `Call` had `allowThirdPartyTailCall` set.
|
cannam@147
|
529 }
|
cannam@147
|
530 }
|
cannam@147
|
531
|
cannam@147
|
532 struct Finish {
|
cannam@147
|
533 # **(level 0)**
|
cannam@147
|
534 #
|
cannam@147
|
535 # Message type sent from the caller to the callee to indicate:
|
cannam@147
|
536 # 1) The questionId will no longer be used in any messages sent by the callee (no further
|
cannam@147
|
537 # pipelined requests).
|
cannam@147
|
538 # 2) If the call has not returned yet, the caller no longer cares about the result. If nothing
|
cannam@147
|
539 # else cares about the result either (e.g. there are no other outstanding calls pipelined on
|
cannam@147
|
540 # the result of this one) then the callee may wish to immediately cancel the operation and
|
cannam@147
|
541 # send back a Return message with "canceled" set. However, implementations are not required
|
cannam@147
|
542 # to support premature cancellation -- instead, the implementation may wait until the call
|
cannam@147
|
543 # actually completes and send a normal `Return` message.
|
cannam@147
|
544 #
|
cannam@147
|
545 # TODO(someday): Should we separate (1) and implicitly releasing result capabilities? It would be
|
cannam@147
|
546 # possible and useful to notify the server that it doesn't need to keep around the response to
|
cannam@147
|
547 # service pipeline requests even though the caller still wants to receive it / hasn't yet
|
cannam@147
|
548 # finished processing it. It could also be useful to notify the server that it need not marshal
|
cannam@147
|
549 # the results because the caller doesn't want them anyway, even if the caller is still sending
|
cannam@147
|
550 # pipelined calls, although this seems less useful (just saving some bytes on the wire).
|
cannam@147
|
551
|
cannam@147
|
552 questionId @0 :QuestionId;
|
cannam@147
|
553 # ID of the call whose result is to be released.
|
cannam@147
|
554
|
cannam@147
|
555 releaseResultCaps @1 :Bool = true;
|
cannam@147
|
556 # If true, all capabilities that were in the results should be considered released. The sender
|
cannam@147
|
557 # must not send separate `Release` messages for them. Level 0 implementations in particular
|
cannam@147
|
558 # should always set this true. This defaults true because if level 0 implementations forget to
|
cannam@147
|
559 # set it they'll never notice (just silently leak caps), but if level >=1 implementations forget
|
cannam@147
|
560 # set it false they'll quickly get errors.
|
cannam@147
|
561 }
|
cannam@147
|
562
|
cannam@147
|
563 # Level 1 message types ----------------------------------------------
|
cannam@147
|
564
|
cannam@147
|
565 struct Resolve {
|
cannam@147
|
566 # **(level 1)**
|
cannam@147
|
567 #
|
cannam@147
|
568 # Message type sent to indicate that a previously-sent promise has now been resolved to some other
|
cannam@147
|
569 # object (possibly another promise) -- or broken, or canceled.
|
cannam@147
|
570 #
|
cannam@147
|
571 # Keep in mind that it's possible for a `Resolve` to be sent to a level 0 implementation that
|
cannam@147
|
572 # doesn't implement it. For example, a method call or return might contain a capability in the
|
cannam@147
|
573 # payload. Normally this is fine even if the receiver is level 0, because they will implicitly
|
cannam@147
|
574 # release all such capabilities on return / finish. But if the cap happens to be a promise, then
|
cannam@147
|
575 # a follow-up `Resolve` may be sent regardless of this release. The level 0 receiver will reply
|
cannam@147
|
576 # with an `unimplemented` message, and the sender (of the `Resolve`) can respond to this as if the
|
cannam@147
|
577 # receiver had immediately released any capability to which the promise resolved.
|
cannam@147
|
578 #
|
cannam@147
|
579 # When implementing promise resolution, it's important to understand how embargos work and the
|
cannam@147
|
580 # tricky case of the Tribble 4-way race condition. See the comments for the Disembargo message,
|
cannam@147
|
581 # below.
|
cannam@147
|
582
|
cannam@147
|
583 promiseId @0 :ExportId;
|
cannam@147
|
584 # The ID of the promise to be resolved.
|
cannam@147
|
585 #
|
cannam@147
|
586 # Unlike all other instances of `ExportId` sent from the exporter, the `Resolve` message does
|
cannam@147
|
587 # _not_ increase the reference count of `promiseId`. In fact, it is expected that the receiver
|
cannam@147
|
588 # will release the export soon after receiving `Resolve`, and the sender will not send this
|
cannam@147
|
589 # `ExportId` again until it has been released and recycled.
|
cannam@147
|
590 #
|
cannam@147
|
591 # When an export ID sent over the wire (e.g. in a `CapDescriptor`) is indicated to be a promise,
|
cannam@147
|
592 # this indicates that the sender will follow up at some point with a `Resolve` message. If the
|
cannam@147
|
593 # same `promiseId` is sent again before `Resolve`, still only one `Resolve` is sent. If the
|
cannam@147
|
594 # same ID is sent again later _after_ a `Resolve`, it can only be because the export's
|
cannam@147
|
595 # reference count hit zero in the meantime and the ID was re-assigned to a new export, therefore
|
cannam@147
|
596 # this later promise does _not_ correspond to the earlier `Resolve`.
|
cannam@147
|
597 #
|
cannam@147
|
598 # If a promise ID's reference count reaches zero before a `Resolve` is sent, the `Resolve`
|
cannam@147
|
599 # message may or may not still be sent (the `Resolve` may have already been in-flight when
|
cannam@147
|
600 # `Release` was sent, but if the `Release` is received before `Resolve` then there is no longer
|
cannam@147
|
601 # any reason to send a `Resolve`). Thus a `Resolve` may be received for a promise of which
|
cannam@147
|
602 # the receiver has no knowledge, because it already released it earlier. In this case, the
|
cannam@147
|
603 # receiver should simply release the capability to which the promise resolved.
|
cannam@147
|
604
|
cannam@147
|
605 union {
|
cannam@147
|
606 cap @1 :CapDescriptor;
|
cannam@147
|
607 # The object to which the promise resolved.
|
cannam@147
|
608 #
|
cannam@147
|
609 # The sender promises that from this point forth, until `promiseId` is released, it shall
|
cannam@147
|
610 # simply forward all messages to the capability designated by `cap`. This is true even if
|
cannam@147
|
611 # `cap` itself happens to desigate another promise, and that other promise later resolves --
|
cannam@147
|
612 # messages sent to `promiseId` shall still go to that other promise, not to its resolution.
|
cannam@147
|
613 # This is important in the case that the receiver of the `Resolve` ends up sending a
|
cannam@147
|
614 # `Disembargo` message towards `promiseId` in order to control message ordering -- that
|
cannam@147
|
615 # `Disembargo` really needs to reflect back to exactly the object designated by `cap` even
|
cannam@147
|
616 # if that object is itself a promise.
|
cannam@147
|
617
|
cannam@147
|
618 exception @2 :Exception;
|
cannam@147
|
619 # Indicates that the promise was broken.
|
cannam@147
|
620 }
|
cannam@147
|
621 }
|
cannam@147
|
622
|
cannam@147
|
623 struct Release {
|
cannam@147
|
624 # **(level 1)**
|
cannam@147
|
625 #
|
cannam@147
|
626 # Message type sent to indicate that the sender is done with the given capability and the receiver
|
cannam@147
|
627 # can free resources allocated to it.
|
cannam@147
|
628
|
cannam@147
|
629 id @0 :ImportId;
|
cannam@147
|
630 # What to release.
|
cannam@147
|
631
|
cannam@147
|
632 referenceCount @1 :UInt32;
|
cannam@147
|
633 # The amount by which to decrement the reference count. The export is only actually released
|
cannam@147
|
634 # when the reference count reaches zero.
|
cannam@147
|
635 }
|
cannam@147
|
636
|
cannam@147
|
637 struct Disembargo {
|
cannam@147
|
638 # **(level 1)**
|
cannam@147
|
639 #
|
cannam@147
|
640 # Message sent to indicate that an embargo on a recently-resolved promise may now be lifted.
|
cannam@147
|
641 #
|
cannam@147
|
642 # Embargos are used to enforce E-order in the presence of promise resolution. That is, if an
|
cannam@147
|
643 # application makes two calls foo() and bar() on the same capability reference, in that order,
|
cannam@147
|
644 # the calls should be delivered in the order in which they were made. But if foo() is called
|
cannam@147
|
645 # on a promise, and that promise happens to resolve before bar() is called, then the two calls
|
cannam@147
|
646 # may travel different paths over the network, and thus could arrive in the wrong order. In
|
cannam@147
|
647 # this case, the call to `bar()` must be embargoed, and a `Disembargo` message must be sent along
|
cannam@147
|
648 # the same path as `foo()` to ensure that the `Disembargo` arrives after `foo()`. Once the
|
cannam@147
|
649 # `Disembargo` arrives, `bar()` can then be delivered.
|
cannam@147
|
650 #
|
cannam@147
|
651 # There are two particular cases where embargos are important. Consider object Alice, in Vat A,
|
cannam@147
|
652 # who holds a promise P, pointing towards Vat B, that eventually resolves to Carol. The two
|
cannam@147
|
653 # cases are:
|
cannam@147
|
654 # - Carol lives in Vat A, i.e. next to Alice. In this case, Vat A needs to send a `Disembargo`
|
cannam@147
|
655 # message that echos through Vat B and back, to ensure that all pipelined calls on the promise
|
cannam@147
|
656 # have been delivered.
|
cannam@147
|
657 # - Carol lives in a different Vat C. When the promise resolves, a three-party handoff occurs
|
cannam@147
|
658 # (see `Provide` and `Accept`, which constitute level 3 of the protocol). In this case, we
|
cannam@147
|
659 # piggyback on the state that has already been set up to handle the handoff: the `Accept`
|
cannam@147
|
660 # message (from Vat A to Vat C) is embargoed, as are all pipelined messages sent to it, while
|
cannam@147
|
661 # a `Disembargo` message is sent from Vat A through Vat B to Vat C. See `Accept.embargo` for
|
cannam@147
|
662 # an example.
|
cannam@147
|
663 #
|
cannam@147
|
664 # Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise
|
cannam@147
|
665 # already pointed at), no embargo is needed, because the pipelined calls are delivered over the
|
cannam@147
|
666 # same path as the later direct calls.
|
cannam@147
|
667 #
|
cannam@147
|
668 # Keep in mind that promise resolution happens both in the form of Resolve messages as well as
|
cannam@147
|
669 # Return messages (which resolve PromisedAnswers). Embargos apply in both cases.
|
cannam@147
|
670 #
|
cannam@147
|
671 # An alternative strategy for enforcing E-order over promise resolution could be for Vat A to
|
cannam@147
|
672 # implement the embargo internally. When Vat A is notified of promise resolution, it could
|
cannam@147
|
673 # send a dummy no-op call to promise P and wait for it to complete. Until that call completes,
|
cannam@147
|
674 # all calls to the capability are queued locally. This strategy works, but is pessimistic:
|
cannam@147
|
675 # in the three-party case, it requires an A -> B -> C -> B -> A round trip before calls can start
|
cannam@147
|
676 # being delivered directly to from Vat A to Vat C. The `Disembargo` message allows latency to be
|
cannam@147
|
677 # reduced. (In the two-party loopback case, the `Disembargo` message is just a more explicit way
|
cannam@147
|
678 # of accomplishing the same thing as a no-op call, but isn't any faster.)
|
cannam@147
|
679 #
|
cannam@147
|
680 # *The Tribble 4-way Race Condition*
|
cannam@147
|
681 #
|
cannam@147
|
682 # Any implementation of promise resolution and embargos must be aware of what we call the
|
cannam@147
|
683 # "Tribble 4-way race condition", after Dean Tribble, who explained the problem in a lively
|
cannam@147
|
684 # Friam meeting.
|
cannam@147
|
685 #
|
cannam@147
|
686 # Embargos are designed to work in the case where a two-hop path is being shortened to one hop.
|
cannam@147
|
687 # But sometimes there are more hops. Imagine that Alice has a reference to a remote promise P1
|
cannam@147
|
688 # that eventually resolves to _another_ remote promise P2 (in a third vat), which _at the same
|
cannam@147
|
689 # time_ happens to resolve to Bob (in a fourth vat). In this case, we're shortening from a 3-hop
|
cannam@147
|
690 # path (with four parties) to a 1-hop path (Alice -> Bob).
|
cannam@147
|
691 #
|
cannam@147
|
692 # Extending the embargo/disembargo protocol to be able to shorted multiple hops at once seems
|
cannam@147
|
693 # difficult. Instead, we make a rule that prevents this case from coming up:
|
cannam@147
|
694 #
|
cannam@147
|
695 # One a promise P has been resolved to a remove object reference R, then all further messages
|
cannam@147
|
696 # received addressed to P will be forwarded strictly to R. Even if it turns out later that R is
|
cannam@147
|
697 # itself a promise, and has resolved to some other object Q, messages sent to P will still be
|
cannam@147
|
698 # forwarded to R, not directly to Q (R will of course further forward the messages to Q).
|
cannam@147
|
699 #
|
cannam@147
|
700 # This rule does not cause a significant performance burden because once P has resolved to R, it
|
cannam@147
|
701 # is expected that people sending messages to P will shortly start sending them to R instead and
|
cannam@147
|
702 # drop P. P is at end-of-life anyway, so it doesn't matter if it ignores chances to further
|
cannam@147
|
703 # optimize its path.
|
cannam@147
|
704
|
cannam@147
|
705 target @0 :MessageTarget;
|
cannam@147
|
706 # What is to be disembargoed.
|
cannam@147
|
707
|
cannam@147
|
708 using EmbargoId = UInt32;
|
cannam@147
|
709 # Used in `senderLoopback` and `receiverLoopback`, below.
|
cannam@147
|
710
|
cannam@147
|
711 context :union {
|
cannam@147
|
712 senderLoopback @1 :EmbargoId;
|
cannam@147
|
713 # The sender is requesting a disembargo on a promise that is known to resolve back to a
|
cannam@147
|
714 # capability hosted by the sender. As soon as the receiver has echoed back all pipelined calls
|
cannam@147
|
715 # on this promise, it will deliver the Disembargo back to the sender with `receiverLoopback`
|
cannam@147
|
716 # set to the same value as `senderLoopback`. This value is chosen by the sender, and since
|
cannam@147
|
717 # it is also consumed be the sender, the sender can use whatever strategy it wants to make sure
|
cannam@147
|
718 # the value is unambiguous.
|
cannam@147
|
719 #
|
cannam@147
|
720 # The receiver must verify that the target capability actually resolves back to the sender's
|
cannam@147
|
721 # vat. Otherwise, the sender has committed a protocol error and should be disconnected.
|
cannam@147
|
722
|
cannam@147
|
723 receiverLoopback @2 :EmbargoId;
|
cannam@147
|
724 # The receiver previously sent a `senderLoopback` Disembargo towards a promise resolving to
|
cannam@147
|
725 # this capability, and that Disembargo is now being echoed back.
|
cannam@147
|
726
|
cannam@147
|
727 accept @3 :Void;
|
cannam@147
|
728 # **(level 3)**
|
cannam@147
|
729 #
|
cannam@147
|
730 # The sender is requesting a disembargo on a promise that is known to resolve to a third-party
|
cannam@147
|
731 # capability that the sender is currently in the process of accepting (using `Accept`).
|
cannam@147
|
732 # The receiver of this `Disembargo` has an outstanding `Provide` on said capability. The
|
cannam@147
|
733 # receiver should now send a `Disembargo` with `provide` set to the question ID of that
|
cannam@147
|
734 # `Provide` message.
|
cannam@147
|
735 #
|
cannam@147
|
736 # See `Accept.embargo` for an example.
|
cannam@147
|
737
|
cannam@147
|
738 provide @4 :QuestionId;
|
cannam@147
|
739 # **(level 3)**
|
cannam@147
|
740 #
|
cannam@147
|
741 # The sender is requesting a disembargo on a capability currently being provided to a third
|
cannam@147
|
742 # party. The question ID identifies the `Provide` message previously sent by the sender to
|
cannam@147
|
743 # this capability. On receipt, the receiver (the capability host) shall release the embargo
|
cannam@147
|
744 # on the `Accept` message that it has received from the third party. See `Accept.embargo` for
|
cannam@147
|
745 # an example.
|
cannam@147
|
746 }
|
cannam@147
|
747 }
|
cannam@147
|
748
|
cannam@147
|
749 # Level 2 message types ----------------------------------------------
|
cannam@147
|
750
|
cannam@147
|
751 # See persistent.capnp.
|
cannam@147
|
752
|
cannam@147
|
753 # Level 3 message types ----------------------------------------------
|
cannam@147
|
754
|
cannam@147
|
755 struct Provide {
|
cannam@147
|
756 # **(level 3)**
|
cannam@147
|
757 #
|
cannam@147
|
758 # Message type sent to indicate that the sender wishes to make a particular capability implemented
|
cannam@147
|
759 # by the receiver available to a third party for direct access (without the need for the third
|
cannam@147
|
760 # party to proxy through the sender).
|
cannam@147
|
761 #
|
cannam@147
|
762 # (In CapTP, `Provide` and `Accept` are methods of the global `NonceLocator` object exported by
|
cannam@147
|
763 # every vat. In Cap'n Proto, we bake this into the core protocol.)
|
cannam@147
|
764
|
cannam@147
|
765 questionId @0 :QuestionId;
|
cannam@147
|
766 # Question ID to be held open until the recipient has received the capability. A result will be
|
cannam@147
|
767 # returned once the third party has successfully received the capability. The sender must at some
|
cannam@147
|
768 # point send a `Finish` message as with any other call, and that message can be used to cancel the
|
cannam@147
|
769 # whole operation.
|
cannam@147
|
770
|
cannam@147
|
771 target @1 :MessageTarget;
|
cannam@147
|
772 # What is to be provided to the third party.
|
cannam@147
|
773
|
cannam@147
|
774 recipient @2 :RecipientId;
|
cannam@147
|
775 # Identity of the third party that is expected to pick up the capability.
|
cannam@147
|
776 }
|
cannam@147
|
777
|
cannam@147
|
778 struct Accept {
|
cannam@147
|
779 # **(level 3)**
|
cannam@147
|
780 #
|
cannam@147
|
781 # Message type sent to pick up a capability hosted by the receiving vat and provided by a third
|
cannam@147
|
782 # party. The third party previously designated the capability using `Provide`.
|
cannam@147
|
783 #
|
cannam@147
|
784 # This message is also used to pick up a redirected return -- see `Return.redirect`.
|
cannam@147
|
785
|
cannam@147
|
786 questionId @0 :QuestionId;
|
cannam@147
|
787 # A new question ID identifying this accept message, which will eventually receive a Return
|
cannam@147
|
788 # message containing the provided capability (or the call result in the case of a redirected
|
cannam@147
|
789 # return).
|
cannam@147
|
790
|
cannam@147
|
791 provision @1 :ProvisionId;
|
cannam@147
|
792 # Identifies the provided object to be picked up.
|
cannam@147
|
793
|
cannam@147
|
794 embargo @2 :Bool;
|
cannam@147
|
795 # If true, this accept shall be temporarily embargoed. The resulting `Return` will not be sent,
|
cannam@147
|
796 # and any pipelined calls will not be delivered, until the embargo is released. The receiver
|
cannam@147
|
797 # (the capability host) will expect the provider (the vat that sent the `Provide` message) to
|
cannam@147
|
798 # eventually send a `Disembargo` message with the field `context.provide` set to the question ID
|
cannam@147
|
799 # of the original `Provide` message. At that point, the embargo is released and the queued
|
cannam@147
|
800 # messages are delivered.
|
cannam@147
|
801 #
|
cannam@147
|
802 # For example:
|
cannam@147
|
803 # - Alice, in Vat A, holds a promise P, which currently points toward Vat B.
|
cannam@147
|
804 # - Alice calls foo() on P. The `Call` message is sent to Vat B.
|
cannam@147
|
805 # - The promise P in Vat B ends up resolving to Carol, in Vat C.
|
cannam@147
|
806 # - Vat B sends a `Provide` message to Vat C, identifying Vat A as the recipient.
|
cannam@147
|
807 # - Vat B sends a `Resolve` message to Vat A, indicating that the promise has resolved to a
|
cannam@147
|
808 # `ThirdPartyCapId` identifying Carol in Vat C.
|
cannam@147
|
809 # - Vat A sends an `Accept` message to Vat C to pick up the capability. Since Vat A knows that
|
cannam@147
|
810 # it has an outstanding call to the promise, it sets `embargo` to `true` in the `Accept`
|
cannam@147
|
811 # message.
|
cannam@147
|
812 # - Vat A sends a `Disembargo` message to Vat B on promise P, with `context.accept` set.
|
cannam@147
|
813 # - Alice makes a call bar() to promise P, which is now pointing towards Vat C. Alice doesn't
|
cannam@147
|
814 # know anything about the mechanics of promise resolution happening under the hood, but she
|
cannam@147
|
815 # expects that bar() will be delivered after foo() because that is the order in which she
|
cannam@147
|
816 # initiated the calls.
|
cannam@147
|
817 # - Vat A sends the bar() call to Vat C, as a pipelined call on the result of the `Accept` (which
|
cannam@147
|
818 # hasn't returned yet, due to the embargo). Since calls to the newly-accepted capability
|
cannam@147
|
819 # are embargoed, Vat C does not deliver the call yet.
|
cannam@147
|
820 # - At some point, Vat B forwards the foo() call from the beginning of this example on to Vat C.
|
cannam@147
|
821 # - Vat B forwards the `Disembargo` from Vat A on to vat C. It sets `context.provide` to the
|
cannam@147
|
822 # question ID of the `Provide` message it had sent previously.
|
cannam@147
|
823 # - Vat C receives foo() before `Disembargo`, thus allowing it to correctly deliver foo()
|
cannam@147
|
824 # before delivering bar().
|
cannam@147
|
825 # - Vat C receives `Disembargo` from Vat B. It can now send a `Return` for the `Accept` from
|
cannam@147
|
826 # Vat A, as well as deliver bar().
|
cannam@147
|
827 }
|
cannam@147
|
828
|
cannam@147
|
829 # Level 4 message types ----------------------------------------------
|
cannam@147
|
830
|
cannam@147
|
831 struct Join {
|
cannam@147
|
832 # **(level 4)**
|
cannam@147
|
833 #
|
cannam@147
|
834 # Message type sent to implement E.join(), which, given a number of capabilities that are
|
cannam@147
|
835 # expected to be equivalent, finds the underlying object upon which they all agree and forms a
|
cannam@147
|
836 # direct connection to it, skipping any proxies that may have been constructed by other vats
|
cannam@147
|
837 # while transmitting the capability. See:
|
cannam@147
|
838 # http://erights.org/elib/equality/index.html
|
cannam@147
|
839 #
|
cannam@147
|
840 # Note that this should only serve to bypass fully-transparent proxies -- proxies that were
|
cannam@147
|
841 # created merely for convenience, without any intention of hiding the underlying object.
|
cannam@147
|
842 #
|
cannam@147
|
843 # For example, say Bob holds two capabilities hosted by Alice and Carol, but he expects that both
|
cannam@147
|
844 # are simply proxies for a capability hosted elsewhere. He then issues a join request, which
|
cannam@147
|
845 # operates as follows:
|
cannam@147
|
846 # - Bob issues Join requests on both Alice and Carol. Each request contains a different piece
|
cannam@147
|
847 # of the JoinKey.
|
cannam@147
|
848 # - Alice is proxying a capability hosted by Dana, so forwards the request to Dana's cap.
|
cannam@147
|
849 # - Dana receives the first request and sees that the JoinKeyPart is one of two. She notes that
|
cannam@147
|
850 # she doesn't have the other part yet, so she records the request and responds with a
|
cannam@147
|
851 # JoinResult.
|
cannam@147
|
852 # - Alice relays the JoinAswer back to Bob.
|
cannam@147
|
853 # - Carol is also proxying a capability from Dana, and so forwards her Join request to Dana as
|
cannam@147
|
854 # well.
|
cannam@147
|
855 # - Dana receives Carol's request and notes that she now has both parts of a JoinKey. She
|
cannam@147
|
856 # combines them in order to form information needed to form a secure connection to Bob. She
|
cannam@147
|
857 # also responds with another JoinResult.
|
cannam@147
|
858 # - Bob receives the responses from Alice and Carol. He uses the returned JoinResults to
|
cannam@147
|
859 # determine how to connect to Dana and attempts to form the connection. Since Bob and Dana now
|
cannam@147
|
860 # agree on a secret key that neither Alice nor Carol ever saw, this connection can be made
|
cannam@147
|
861 # securely even if Alice or Carol is conspiring against the other. (If Alice and Carol are
|
cannam@147
|
862 # conspiring _together_, they can obviously reproduce the key, but this doesn't matter because
|
cannam@147
|
863 # the whole point of the join is to verify that Alice and Carol agree on what capability they
|
cannam@147
|
864 # are proxying.)
|
cannam@147
|
865 #
|
cannam@147
|
866 # If the two capabilities aren't actually proxies of the same object, then the join requests
|
cannam@147
|
867 # will come back with conflicting `hostId`s and the join will fail before attempting to form any
|
cannam@147
|
868 # connection.
|
cannam@147
|
869
|
cannam@147
|
870 questionId @0 :QuestionId;
|
cannam@147
|
871 # Question ID used to respond to this Join. (Note that this ID only identifies one part of the
|
cannam@147
|
872 # request for one hop; each part has a different ID and relayed copies of the request have
|
cannam@147
|
873 # (probably) different IDs still.)
|
cannam@147
|
874 #
|
cannam@147
|
875 # The receiver will reply with a `Return` whose `results` is a JoinResult. This `JoinResult`
|
cannam@147
|
876 # is relayed from the joined object's host, possibly with transformation applied as needed
|
cannam@147
|
877 # by the network.
|
cannam@147
|
878 #
|
cannam@147
|
879 # Like any return, the result must be released using a `Finish`. However, this release
|
cannam@147
|
880 # should not occur until the joiner has either successfully connected to the joined object.
|
cannam@147
|
881 # Vats relaying a `Join` message similarly must not release the result they receive until the
|
cannam@147
|
882 # return they relayed back towards the joiner has itself been released. This allows the
|
cannam@147
|
883 # joined object's host to detect when the Join operation is canceled before completing -- if
|
cannam@147
|
884 # it receives a `Finish` for one of the join results before the joiner successfully
|
cannam@147
|
885 # connects. It can then free any resources it had allocated as part of the join.
|
cannam@147
|
886
|
cannam@147
|
887 target @1 :MessageTarget;
|
cannam@147
|
888 # The capability to join.
|
cannam@147
|
889
|
cannam@147
|
890 keyPart @2 :JoinKeyPart;
|
cannam@147
|
891 # A part of the join key. These combine to form the complete join key, which is used to establish
|
cannam@147
|
892 # a direct connection.
|
cannam@147
|
893
|
cannam@147
|
894 # TODO(before implementing): Change this so that multiple parts can be sent in a single Join
|
cannam@147
|
895 # message, so that if multiple join parts are going to cross the same connection they can be sent
|
cannam@147
|
896 # together, so that the receive can potentially optimize its handling of them. In the case where
|
cannam@147
|
897 # all parts are bundled together, should the recipient be expected to simply return a cap, so
|
cannam@147
|
898 # that the caller can immediately start pipelining to it?
|
cannam@147
|
899 }
|
cannam@147
|
900
|
cannam@147
|
901 # ========================================================================================
|
cannam@147
|
902 # Common structures used in messages
|
cannam@147
|
903
|
cannam@147
|
904 struct MessageTarget {
|
cannam@147
|
905 # The target of a `Call` or other messages that target a capability.
|
cannam@147
|
906
|
cannam@147
|
907 union {
|
cannam@147
|
908 importedCap @0 :ImportId;
|
cannam@147
|
909 # This message is to a capability or promise previously imported by the caller (exported by
|
cannam@147
|
910 # the receiver).
|
cannam@147
|
911
|
cannam@147
|
912 promisedAnswer @1 :PromisedAnswer;
|
cannam@147
|
913 # This message is to a capability that is expected to be returned by another call that has not
|
cannam@147
|
914 # yet been completed.
|
cannam@147
|
915 #
|
cannam@147
|
916 # At level 0, this is supported only for addressing the result of a previous `Bootstrap`, so
|
cannam@147
|
917 # that initial startup doesn't require a round trip.
|
cannam@147
|
918 }
|
cannam@147
|
919 }
|
cannam@147
|
920
|
cannam@147
|
921 struct Payload {
|
cannam@147
|
922 # Represents some data structure that might contain capabilities.
|
cannam@147
|
923
|
cannam@147
|
924 content @0 :AnyPointer;
|
cannam@147
|
925 # Some Cap'n Proto data structure. Capability pointers embedded in this structure index into
|
cannam@147
|
926 # `capTable`.
|
cannam@147
|
927
|
cannam@147
|
928 capTable @1 :List(CapDescriptor);
|
cannam@147
|
929 # Descriptors corresponding to the cap pointers in `content`.
|
cannam@147
|
930 }
|
cannam@147
|
931
|
cannam@147
|
932 struct CapDescriptor {
|
cannam@147
|
933 # **(level 1)**
|
cannam@147
|
934 #
|
cannam@147
|
935 # When an application-defined type contains an interface pointer, that pointer contains an index
|
cannam@147
|
936 # into the message's capability table -- i.e. the `capTable` part of the `Payload`. Each
|
cannam@147
|
937 # capability in the table is represented as a `CapDescriptor`. The runtime API should not reveal
|
cannam@147
|
938 # the CapDescriptor directly to the application, but should instead wrap it in some kind of
|
cannam@147
|
939 # callable object with methods corresponding to the interface that the capability implements.
|
cannam@147
|
940 #
|
cannam@147
|
941 # Keep in mind that `ExportIds` in a `CapDescriptor` are subject to reference counting. See the
|
cannam@147
|
942 # description of `ExportId`.
|
cannam@147
|
943
|
cannam@147
|
944 union {
|
cannam@147
|
945 none @0 :Void;
|
cannam@147
|
946 # There is no capability here. This `CapDescriptor` should not appear in the payload content.
|
cannam@147
|
947 # A `none` CapDescriptor can be generated when an application inserts a capability into a
|
cannam@147
|
948 # message and then later changes its mind and removes it -- rewriting all of the other
|
cannam@147
|
949 # capability pointers may be hard, so instead a tombstone is left, similar to the way a removed
|
cannam@147
|
950 # struct or list instance is zeroed out of the message but the space is not reclaimed.
|
cannam@147
|
951 # Hopefully this is unusual.
|
cannam@147
|
952
|
cannam@147
|
953 senderHosted @1 :ExportId;
|
cannam@147
|
954 # A capability newly exported by the sender. This is the ID of the new capability in the
|
cannam@147
|
955 # sender's export table (receiver's import table).
|
cannam@147
|
956
|
cannam@147
|
957 senderPromise @2 :ExportId;
|
cannam@147
|
958 # A promise that the sender will resolve later. The sender will send exactly one Resolve
|
cannam@147
|
959 # message at a future point in time to replace this promise. Note that even if the same
|
cannam@147
|
960 # `senderPromise` is received multiple times, only one `Resolve` is sent to cover all of
|
cannam@147
|
961 # them. If `senderPromise` is released before the `Resolve` is sent, the sender (of this
|
cannam@147
|
962 # `CapDescriptor`) may choose not to send the `Resolve` at all.
|
cannam@147
|
963
|
cannam@147
|
964 receiverHosted @3 :ImportId;
|
cannam@147
|
965 # A capability (or promise) previously exported by the receiver (imported by the sender).
|
cannam@147
|
966
|
cannam@147
|
967 receiverAnswer @4 :PromisedAnswer;
|
cannam@147
|
968 # A capability expected to be returned in the results of a currently-outstanding call posed
|
cannam@147
|
969 # by the sender.
|
cannam@147
|
970
|
cannam@147
|
971 thirdPartyHosted @5 :ThirdPartyCapDescriptor;
|
cannam@147
|
972 # **(level 3)**
|
cannam@147
|
973 #
|
cannam@147
|
974 # A capability that lives in neither the sender's nor the receiver's vat. The sender needs
|
cannam@147
|
975 # to form a direct connection to a third party to pick up the capability.
|
cannam@147
|
976 #
|
cannam@147
|
977 # Level 1 and 2 implementations that receive a `thirdPartyHosted` may simply send calls to its
|
cannam@147
|
978 # `vine` instead.
|
cannam@147
|
979 }
|
cannam@147
|
980 }
|
cannam@147
|
981
|
cannam@147
|
982 struct PromisedAnswer {
|
cannam@147
|
983 # **(mostly level 1)**
|
cannam@147
|
984 #
|
cannam@147
|
985 # Specifies how to derive a promise from an unanswered question, by specifying the path of fields
|
cannam@147
|
986 # to follow from the root of the eventual result struct to get to the desired capability. Used
|
cannam@147
|
987 # to address method calls to a not-yet-returned capability or to pass such a capability as an
|
cannam@147
|
988 # input to some other method call.
|
cannam@147
|
989 #
|
cannam@147
|
990 # Level 0 implementations must support `PromisedAnswer` only for the case where the answer is
|
cannam@147
|
991 # to a `Bootstrap` message. In this case, `path` is always empty since `Bootstrap` always returns
|
cannam@147
|
992 # a raw capability.
|
cannam@147
|
993
|
cannam@147
|
994 questionId @0 :QuestionId;
|
cannam@147
|
995 # ID of the question (in the sender's question table / receiver's answer table) whose answer is
|
cannam@147
|
996 # expected to contain the capability.
|
cannam@147
|
997
|
cannam@147
|
998 transform @1 :List(Op);
|
cannam@147
|
999 # Operations / transformations to apply to the result in order to get the capability actually
|
cannam@147
|
1000 # being addressed. E.g. if the result is a struct and you want to call a method on a capability
|
cannam@147
|
1001 # pointed to by a field of the struct, you need a `getPointerField` op.
|
cannam@147
|
1002
|
cannam@147
|
1003 struct Op {
|
cannam@147
|
1004 union {
|
cannam@147
|
1005 noop @0 :Void;
|
cannam@147
|
1006 # Does nothing. This member is mostly defined so that we can make `Op` a union even
|
cannam@147
|
1007 # though (as of this writing) only one real operation is defined.
|
cannam@147
|
1008
|
cannam@147
|
1009 getPointerField @1 :UInt16;
|
cannam@147
|
1010 # Get a pointer field within a struct. The number is an index into the pointer section, NOT
|
cannam@147
|
1011 # a field ordinal, so that the receiver does not need to understand the schema.
|
cannam@147
|
1012
|
cannam@147
|
1013 # TODO(someday): We could add:
|
cannam@147
|
1014 # - For lists, the ability to address every member of the list, or a slice of the list, the
|
cannam@147
|
1015 # result of which would be another list. This is useful for implementing the equivalent of
|
cannam@147
|
1016 # a SQL table join (not to be confused with the `Join` message type).
|
cannam@147
|
1017 # - Maybe some ability to test a union.
|
cannam@147
|
1018 # - Probably not a good idea: the ability to specify an arbitrary script to run on the
|
cannam@147
|
1019 # result. We could define a little stack-based language where `Op` specifies one
|
cannam@147
|
1020 # "instruction" or transformation to apply. Although this is not a good idea
|
cannam@147
|
1021 # (over-engineered), any narrower additions to `Op` should be designed as if this
|
cannam@147
|
1022 # were the eventual goal.
|
cannam@147
|
1023 }
|
cannam@147
|
1024 }
|
cannam@147
|
1025 }
|
cannam@147
|
1026
|
cannam@147
|
1027 struct ThirdPartyCapDescriptor {
|
cannam@147
|
1028 # **(level 3)**
|
cannam@147
|
1029 #
|
cannam@147
|
1030 # Identifies a capability in a third-party vat that the sender wants the receiver to pick up.
|
cannam@147
|
1031
|
cannam@147
|
1032 id @0 :ThirdPartyCapId;
|
cannam@147
|
1033 # Identifies the third-party host and the specific capability to accept from it.
|
cannam@147
|
1034
|
cannam@147
|
1035 vineId @1 :ExportId;
|
cannam@147
|
1036 # A proxy for the third-party object exported by the sender. In CapTP terminology this is called
|
cannam@147
|
1037 # a "vine", because it is an indirect reference to the third-party object that snakes through the
|
cannam@147
|
1038 # sender vat. This serves two purposes:
|
cannam@147
|
1039 #
|
cannam@147
|
1040 # * Level 1 and 2 implementations that don't understand how to connect to a third party may
|
cannam@147
|
1041 # simply send calls to the vine. Such calls will be forwarded to the third-party by the
|
cannam@147
|
1042 # sender.
|
cannam@147
|
1043 #
|
cannam@147
|
1044 # * Level 3 implementations must release the vine once they have successfully picked up the
|
cannam@147
|
1045 # object from the third party. This ensures that the capability is not released by the sender
|
cannam@147
|
1046 # prematurely.
|
cannam@147
|
1047 #
|
cannam@147
|
1048 # The sender will close the `Provide` request that it has sent to the third party as soon as
|
cannam@147
|
1049 # it receives either a `Call` or a `Release` message directed at the vine.
|
cannam@147
|
1050 }
|
cannam@147
|
1051
|
cannam@147
|
1052 struct Exception {
|
cannam@147
|
1053 # **(level 0)**
|
cannam@147
|
1054 #
|
cannam@147
|
1055 # Describes an arbitrary error that prevented an operation (e.g. a call) from completing.
|
cannam@147
|
1056 #
|
cannam@147
|
1057 # Cap'n Proto exceptions always indicate that something went wrong. In other words, in a fantasy
|
cannam@147
|
1058 # world where everything always works as expected, no exceptions would ever be thrown. Clients
|
cannam@147
|
1059 # should only ever catch exceptions as a means to implement fault-tolerance, where "fault" can
|
cannam@147
|
1060 # mean:
|
cannam@147
|
1061 # - Bugs.
|
cannam@147
|
1062 # - Invalid input.
|
cannam@147
|
1063 # - Configuration errors.
|
cannam@147
|
1064 # - Network problems.
|
cannam@147
|
1065 # - Insufficient resources.
|
cannam@147
|
1066 # - Version skew (unimplemented functionality).
|
cannam@147
|
1067 # - Other logistical problems.
|
cannam@147
|
1068 #
|
cannam@147
|
1069 # Exceptions should NOT be used to flag application-specific conditions that a client is expected
|
cannam@147
|
1070 # to handle in an application-specific way. Put another way, in the Cap'n Proto world,
|
cannam@147
|
1071 # "checked exceptions" (where an interface explicitly defines the exceptions it throws and
|
cannam@147
|
1072 # clients are forced by the type system to handle those exceptions) do NOT make sense.
|
cannam@147
|
1073
|
cannam@147
|
1074 reason @0 :Text;
|
cannam@147
|
1075 # Human-readable failure description.
|
cannam@147
|
1076
|
cannam@147
|
1077 type @3 :Type;
|
cannam@147
|
1078 # The type of the error. The purpose of this enum is not to describe the error itself, but
|
cannam@147
|
1079 # rather to describe how the client might want to respond to the error.
|
cannam@147
|
1080
|
cannam@147
|
1081 enum Type {
|
cannam@147
|
1082 failed @0;
|
cannam@147
|
1083 # A generic problem occurred, and it is believed that if the operation were repeated without
|
cannam@147
|
1084 # any change in the state of the world, the problem would occur again.
|
cannam@147
|
1085 #
|
cannam@147
|
1086 # A client might respond to this error by logging it for investigation by the developer and/or
|
cannam@147
|
1087 # displaying it to the user.
|
cannam@147
|
1088
|
cannam@147
|
1089 overloaded @1;
|
cannam@147
|
1090 # The request was rejected due to a temporary lack of resources.
|
cannam@147
|
1091 #
|
cannam@147
|
1092 # Examples include:
|
cannam@147
|
1093 # - There's not enough CPU time to keep up with incoming requests, so some are rejected.
|
cannam@147
|
1094 # - The server ran out of RAM or disk space during the request.
|
cannam@147
|
1095 # - The operation timed out (took significantly longer than it should have).
|
cannam@147
|
1096 #
|
cannam@147
|
1097 # A client might respond to this error by scheduling to retry the operation much later. The
|
cannam@147
|
1098 # client should NOT retry again immediately since this would likely exacerbate the problem.
|
cannam@147
|
1099
|
cannam@147
|
1100 disconnected @2;
|
cannam@147
|
1101 # The method failed because a connection to some necessary capability was lost.
|
cannam@147
|
1102 #
|
cannam@147
|
1103 # Examples include:
|
cannam@147
|
1104 # - The client introduced the server to a third-party capability, the connection to that third
|
cannam@147
|
1105 # party was subsequently lost, and then the client requested that the server use the dead
|
cannam@147
|
1106 # capability for something.
|
cannam@147
|
1107 # - The client previously requested that the server obtain a capability from some third party.
|
cannam@147
|
1108 # The server returned a capability to an object wrapping the third-party capability. Later,
|
cannam@147
|
1109 # the server's connection to the third party was lost.
|
cannam@147
|
1110 # - The capability has been revoked. Revocation does not necessarily mean that the client is
|
cannam@147
|
1111 # no longer authorized to use the capability; it is often used simply as a way to force the
|
cannam@147
|
1112 # client to repeat the setup process, perhaps to efficiently move them to a new back-end or
|
cannam@147
|
1113 # get them to recognize some other change that has occurred.
|
cannam@147
|
1114 #
|
cannam@147
|
1115 # A client should normally respond to this error by releasing all capabilities it is currently
|
cannam@147
|
1116 # holding related to the one it called and then re-creating them by restoring SturdyRefs and/or
|
cannam@147
|
1117 # repeating the method calls used to create them originally. In other words, disconnect and
|
cannam@147
|
1118 # start over. This should in turn cause the server to obtain a new copy of the capability that
|
cannam@147
|
1119 # it lost, thus making everything work.
|
cannam@147
|
1120 #
|
cannam@147
|
1121 # If the client receives another `disconnencted` error in the process of rebuilding the
|
cannam@147
|
1122 # capability and retrying the call, it should treat this as an `overloaded` error: the network
|
cannam@147
|
1123 # is currently unreliable, possibly due to load or other temporary issues.
|
cannam@147
|
1124
|
cannam@147
|
1125 unimplemented @3;
|
cannam@147
|
1126 # The server doesn't implement the requested method. If there is some other method that the
|
cannam@147
|
1127 # client could call (perhaps an older and/or slower interface), it should try that instead.
|
cannam@147
|
1128 # Otherwise, this should be treated like `failed`.
|
cannam@147
|
1129 }
|
cannam@147
|
1130
|
cannam@147
|
1131 obsoleteIsCallersFault @1 :Bool;
|
cannam@147
|
1132 # OBSOLETE. Ignore.
|
cannam@147
|
1133
|
cannam@147
|
1134 obsoleteDurability @2 :UInt16;
|
cannam@147
|
1135 # OBSOLETE. See `type` instead.
|
cannam@147
|
1136 }
|
cannam@147
|
1137
|
cannam@147
|
1138 # ========================================================================================
|
cannam@147
|
1139 # Network-specific Parameters
|
cannam@147
|
1140 #
|
cannam@147
|
1141 # Some parts of the Cap'n Proto RPC protocol are not specified here because different vat networks
|
cannam@147
|
1142 # may wish to use different approaches to solving them. For example, on the public internet, you
|
cannam@147
|
1143 # may want to authenticate vats using public-key cryptography, but on a local intranet with trusted
|
cannam@147
|
1144 # infrastructure, you may be happy to authenticate based on network address only, or some other
|
cannam@147
|
1145 # lightweight mechanism.
|
cannam@147
|
1146 #
|
cannam@147
|
1147 # To accommodate this, we specify several "parameter" types. Each type is defined here as an
|
cannam@147
|
1148 # alias for `AnyPointer`, but a specific network will want to define a specific set of types to use.
|
cannam@147
|
1149 # All vats in a vat network must agree on these parameters in order to be able to communicate.
|
cannam@147
|
1150 # Inter-network communication can be accomplished through "gateways" that perform translation
|
cannam@147
|
1151 # between the primitives used on each network; these gateways may need to be deeply stateful,
|
cannam@147
|
1152 # depending on the translations they perform.
|
cannam@147
|
1153 #
|
cannam@147
|
1154 # For interaction over the global internet between parties with no other prior arrangement, a
|
cannam@147
|
1155 # particular set of bindings for these types is defined elsewhere. (TODO(someday): Specify where
|
cannam@147
|
1156 # these common definitions live.)
|
cannam@147
|
1157 #
|
cannam@147
|
1158 # Another common network type is the two-party network, in which one of the parties typically
|
cannam@147
|
1159 # interacts with the outside world entirely through the other party. In such a connection between
|
cannam@147
|
1160 # Alice and Bob, all objects that exist on Bob's other networks appear to Alice as if they were
|
cannam@147
|
1161 # hosted by Bob himself, and similarly all objects on Alice's network (if she even has one) appear
|
cannam@147
|
1162 # to Bob as if they were hosted by Alice. This network type is interesting because from the point
|
cannam@147
|
1163 # of view of a simple application that communicates with only one other party via the two-party
|
cannam@147
|
1164 # protocol, there are no three-party interactions at all, and joins are unusually simple to
|
cannam@147
|
1165 # implement, so implementing at level 4 is barely more complicated than implementing at level 1.
|
cannam@147
|
1166 # Moreover, if you pair an app implementing the two-party network with a container that implements
|
cannam@147
|
1167 # some other network, the app can then participate on the container's network just as if it
|
cannam@147
|
1168 # implemented that network directly. The types used by the two-party network are defined in
|
cannam@147
|
1169 # `rpc-twoparty.capnp`.
|
cannam@147
|
1170 #
|
cannam@147
|
1171 # The things that we need to parameterize are:
|
cannam@147
|
1172 # - How to store capabilities long-term without holding a connection open (mostly level 2).
|
cannam@147
|
1173 # - How to authenticate vats in three-party introductions (level 3).
|
cannam@147
|
1174 # - How to implement `Join` (level 4).
|
cannam@147
|
1175 #
|
cannam@147
|
1176 # Persistent references
|
cannam@147
|
1177 # ---------------------
|
cannam@147
|
1178 #
|
cannam@147
|
1179 # **(mostly level 2)**
|
cannam@147
|
1180 #
|
cannam@147
|
1181 # We want to allow some capabilities to be stored long-term, even if a connection is lost and later
|
cannam@147
|
1182 # recreated. ExportId is a short-term identifier that is specific to a connection, so it doesn't
|
cannam@147
|
1183 # help here. We need a way to specify long-term identifiers, as well as a strategy for
|
cannam@147
|
1184 # reconnecting to a referenced capability later.
|
cannam@147
|
1185 #
|
cannam@147
|
1186 # Three-party interactions
|
cannam@147
|
1187 # ------------------------
|
cannam@147
|
1188 #
|
cannam@147
|
1189 # **(level 3)**
|
cannam@147
|
1190 #
|
cannam@147
|
1191 # In cases where more than two vats are interacting, we have situations where VatA holds a
|
cannam@147
|
1192 # capability hosted by VatB and wants to send that capability to VatC. This can be accomplished
|
cannam@147
|
1193 # by VatA proxying requests on the new capability, but doing so has two big problems:
|
cannam@147
|
1194 # - It's inefficient, requiring an extra network hop.
|
cannam@147
|
1195 # - If VatC receives another capability to the same object from VatD, it is difficult for VatC to
|
cannam@147
|
1196 # detect that the two capabilities are really the same and to implement the E "join" operation,
|
cannam@147
|
1197 # which is necessary for certain four-or-more-party interactions, such as the escrow pattern.
|
cannam@147
|
1198 # See: http://www.erights.org/elib/equality/grant-matcher/index.html
|
cannam@147
|
1199 #
|
cannam@147
|
1200 # Instead, we want a way for VatC to form a direct, authenticated connection to VatB.
|
cannam@147
|
1201 #
|
cannam@147
|
1202 # Join
|
cannam@147
|
1203 # ----
|
cannam@147
|
1204 #
|
cannam@147
|
1205 # **(level 4)**
|
cannam@147
|
1206 #
|
cannam@147
|
1207 # The `Join` message type and corresponding operation arranges for a direct connection to be formed
|
cannam@147
|
1208 # between the joiner and the host of the joined object, and this connection must be authenticated.
|
cannam@147
|
1209 # Thus, the details are network-dependent.
|
cannam@147
|
1210
|
cannam@147
|
1211 using SturdyRef = AnyPointer;
|
cannam@147
|
1212 # **(level 2)**
|
cannam@147
|
1213 #
|
cannam@147
|
1214 # Identifies a persisted capability that can be restored in the future. How exactly a SturdyRef
|
cannam@147
|
1215 # is restored to a live object is specified along with the SturdyRef definition (i.e. not by
|
cannam@147
|
1216 # rpc.capnp).
|
cannam@147
|
1217 #
|
cannam@147
|
1218 # Generally a SturdyRef needs to specify three things:
|
cannam@147
|
1219 # - How to reach the vat that can restore the ref (e.g. a hostname or IP address).
|
cannam@147
|
1220 # - How to authenticate the vat after connecting (e.g. a public key fingerprint).
|
cannam@147
|
1221 # - The identity of a specific object hosted by the vat. Generally, this is an opaque pointer whose
|
cannam@147
|
1222 # format is defined by the specific vat -- the client has no need to inspect the object ID.
|
cannam@147
|
1223 # It is important that the objec ID be unguessable if the object is not public (and objects
|
cannam@147
|
1224 # should almost never be public).
|
cannam@147
|
1225 #
|
cannam@147
|
1226 # The above are only suggestions. Some networks might work differently. For example, a private
|
cannam@147
|
1227 # network might employ a special restorer service whose sole purpose is to restore SturdyRefs.
|
cannam@147
|
1228 # In this case, the entire contents of SturdyRef might be opaque, because they are intended only
|
cannam@147
|
1229 # to be forwarded to the restorer service.
|
cannam@147
|
1230
|
cannam@147
|
1231 using ProvisionId = AnyPointer;
|
cannam@147
|
1232 # **(level 3)**
|
cannam@147
|
1233 #
|
cannam@147
|
1234 # The information that must be sent in an `Accept` message to identify the object being accepted.
|
cannam@147
|
1235 #
|
cannam@147
|
1236 # In a network where each vat has a public/private key pair, this could simply be the public key
|
cannam@147
|
1237 # fingerprint of the provider vat along with the question ID used in the `Provide` message sent from
|
cannam@147
|
1238 # that provider.
|
cannam@147
|
1239
|
cannam@147
|
1240 using RecipientId = AnyPointer;
|
cannam@147
|
1241 # **(level 3)**
|
cannam@147
|
1242 #
|
cannam@147
|
1243 # The information that must be sent in a `Provide` message to identify the recipient of the
|
cannam@147
|
1244 # capability.
|
cannam@147
|
1245 #
|
cannam@147
|
1246 # In a network where each vat has a public/private key pair, this could simply be the public key
|
cannam@147
|
1247 # fingerprint of the recipient. (CapTP also calls for a nonce to identify the object. In our
|
cannam@147
|
1248 # case, the `Provide` message's `questionId` can serve as the nonce.)
|
cannam@147
|
1249
|
cannam@147
|
1250 using ThirdPartyCapId = AnyPointer;
|
cannam@147
|
1251 # **(level 3)**
|
cannam@147
|
1252 #
|
cannam@147
|
1253 # The information needed to connect to a third party and accept a capability from it.
|
cannam@147
|
1254 #
|
cannam@147
|
1255 # In a network where each vat has a public/private key pair, this could be a combination of the
|
cannam@147
|
1256 # third party's public key fingerprint, hints on how to connect to the third party (e.g. an IP
|
cannam@147
|
1257 # address), and the question ID used in the corresponding `Provide` message sent to that third party
|
cannam@147
|
1258 # (used to identify which capability to pick up).
|
cannam@147
|
1259
|
cannam@147
|
1260 using JoinKeyPart = AnyPointer;
|
cannam@147
|
1261 # **(level 4)**
|
cannam@147
|
1262 #
|
cannam@147
|
1263 # A piece of a secret key. One piece is sent along each path that is expected to lead to the same
|
cannam@147
|
1264 # place. Once the pieces are combined, a direct connection may be formed between the sender and
|
cannam@147
|
1265 # the receiver, bypassing any men-in-the-middle along the paths. See the `Join` message type.
|
cannam@147
|
1266 #
|
cannam@147
|
1267 # The motivation for Joins is discussed under "Supporting Equality" in the "Unibus" protocol
|
cannam@147
|
1268 # sketch: http://www.erights.org/elib/distrib/captp/unibus.html
|
cannam@147
|
1269 #
|
cannam@147
|
1270 # In a network where each vat has a public/private key pair and each vat forms no more than one
|
cannam@147
|
1271 # connection to each other vat, Joins will rarely -- perhaps never -- be needed, as objects never
|
cannam@147
|
1272 # need to be transparently proxied and references to the same object sent over the same connection
|
cannam@147
|
1273 # have the same export ID. Thus, a successful join requires only checking that the two objects
|
cannam@147
|
1274 # come from the same connection and have the same ID, and then completes immediately.
|
cannam@147
|
1275 #
|
cannam@147
|
1276 # However, in networks where two vats may form more than one connection between each other, or
|
cannam@147
|
1277 # where proxying of objects occurs, joins are necessary.
|
cannam@147
|
1278 #
|
cannam@147
|
1279 # Typically, each JoinKeyPart would include a fixed-length data value such that all value parts
|
cannam@147
|
1280 # XOR'd together forms a shared secret that can be used to form an encrypted connection between
|
cannam@147
|
1281 # the joiner and the joined object's host. Each JoinKeyPart should also include an indication of
|
cannam@147
|
1282 # how many parts to expect and a hash of the shared secret (used to match up parts).
|
cannam@147
|
1283
|
cannam@147
|
1284 using JoinResult = AnyPointer;
|
cannam@147
|
1285 # **(level 4)**
|
cannam@147
|
1286 #
|
cannam@147
|
1287 # Information returned as the result to a `Join` message, needed by the joiner in order to form a
|
cannam@147
|
1288 # direct connection to a joined object. This might simply be the address of the joined object's
|
cannam@147
|
1289 # host vat, since the `JoinKey` has already been communicated so the two vats already have a shared
|
cannam@147
|
1290 # secret to use to authenticate each other.
|
cannam@147
|
1291 #
|
cannam@147
|
1292 # The `JoinResult` should also contain information that can be used to detect when the Join
|
cannam@147
|
1293 # requests ended up reaching different objects, so that this situation can be detected easily.
|
cannam@147
|
1294 # This could be a simple matter of including a sequence number -- if the joiner receives two
|
cannam@147
|
1295 # `JoinResult`s with sequence number 0, then they must have come from different objects and the
|
cannam@147
|
1296 # whole join is a failure.
|
cannam@147
|
1297
|
cannam@147
|
1298 # ========================================================================================
|
cannam@147
|
1299 # Network interface sketch
|
cannam@147
|
1300 #
|
cannam@147
|
1301 # The interfaces below are meant to be pseudo-code to illustrate how the details of a particular
|
cannam@147
|
1302 # vat network might be abstracted away. They are written like Cap'n Proto interfaces, but in
|
cannam@147
|
1303 # practice you'd probably define these interfaces manually in the target programming language. A
|
cannam@147
|
1304 # Cap'n Proto RPC implementation should be able to use these interfaces without knowing the
|
cannam@147
|
1305 # definitions of the various network-specific parameters defined above.
|
cannam@147
|
1306
|
cannam@147
|
1307 # interface VatNetwork {
|
cannam@147
|
1308 # # Represents a vat network, with the ability to connect to particular vats and receive
|
cannam@147
|
1309 # # connections from vats.
|
cannam@147
|
1310 # #
|
cannam@147
|
1311 # # Note that methods returning a `Connection` may return a pre-existing `Connection`, and the
|
cannam@147
|
1312 # # caller is expected to find and share state with existing users of the connection.
|
cannam@147
|
1313 #
|
cannam@147
|
1314 # # Level 0 features -----------------------------------------------
|
cannam@147
|
1315 #
|
cannam@147
|
1316 # connect(vatId :VatId) :Connection;
|
cannam@147
|
1317 # # Connect to the given vat. The transport should return a promise that does not
|
cannam@147
|
1318 # # resolve until authentication has completed, but allows messages to be pipelined in before
|
cannam@147
|
1319 # # that; the transport either queues these messages until authenticated, or sends them encrypted
|
cannam@147
|
1320 # # such that only the authentic vat would be able to decrypt them. The latter approach avoids a
|
cannam@147
|
1321 # # round trip for authentication.
|
cannam@147
|
1322 #
|
cannam@147
|
1323 # accept() :Connection;
|
cannam@147
|
1324 # # Wait for the next incoming connection and return it. Only connections formed by
|
cannam@147
|
1325 # # connect() are returned by this method.
|
cannam@147
|
1326 #
|
cannam@147
|
1327 # # Level 4 features -----------------------------------------------
|
cannam@147
|
1328 #
|
cannam@147
|
1329 # newJoiner(count :UInt32) :NewJoinerResponse;
|
cannam@147
|
1330 # # Prepare a new Join operation, which will eventually lead to forming a new direct connection
|
cannam@147
|
1331 # # to the host of the joined capability. `count` is the number of capabilities to join.
|
cannam@147
|
1332 #
|
cannam@147
|
1333 # struct NewJoinerResponse {
|
cannam@147
|
1334 # joinKeyParts :List(JoinKeyPart);
|
cannam@147
|
1335 # # Key parts to send in Join messages to each capability.
|
cannam@147
|
1336 #
|
cannam@147
|
1337 # joiner :Joiner;
|
cannam@147
|
1338 # # Used to establish the final connection.
|
cannam@147
|
1339 # }
|
cannam@147
|
1340 #
|
cannam@147
|
1341 # interface Joiner {
|
cannam@147
|
1342 # addJoinResult(result :JoinResult) :Void;
|
cannam@147
|
1343 # # Add a JoinResult received in response to one of the `Join` messages. All `JoinResult`s
|
cannam@147
|
1344 # # returned from all paths must be added before trying to connect.
|
cannam@147
|
1345 #
|
cannam@147
|
1346 # connect() :ConnectionAndProvisionId;
|
cannam@147
|
1347 # # Try to form a connection to the joined capability's host, verifying that it has received
|
cannam@147
|
1348 # # all of the JoinKeyParts. Once the connection is formed, the caller should send an `Accept`
|
cannam@147
|
1349 # # message on it with the specified `ProvisionId` in order to receive the final capability.
|
cannam@147
|
1350 # }
|
cannam@147
|
1351 #
|
cannam@147
|
1352 # acceptConnectionFromJoiner(parts :List(JoinKeyPart), paths :List(VatPath))
|
cannam@147
|
1353 # :ConnectionAndProvisionId;
|
cannam@147
|
1354 # # Called on a joined capability's host to receive the connection from the joiner, once all
|
cannam@147
|
1355 # # key parts have arrived. The caller should expect to receive an `Accept` message over the
|
cannam@147
|
1356 # # connection with the given ProvisionId.
|
cannam@147
|
1357 # }
|
cannam@147
|
1358 #
|
cannam@147
|
1359 # interface Connection {
|
cannam@147
|
1360 # # Level 0 features -----------------------------------------------
|
cannam@147
|
1361 #
|
cannam@147
|
1362 # send(message :Message) :Void;
|
cannam@147
|
1363 # # Send the message. Returns successfully when the message (and all preceding messages) has
|
cannam@147
|
1364 # # been acknowledged by the recipient.
|
cannam@147
|
1365 #
|
cannam@147
|
1366 # receive() :Message;
|
cannam@147
|
1367 # # Receive the next message, and acknowledges receipt to the sender. Messages are received in
|
cannam@147
|
1368 # # the order in which they are sent.
|
cannam@147
|
1369 #
|
cannam@147
|
1370 # # Level 3 features -----------------------------------------------
|
cannam@147
|
1371 #
|
cannam@147
|
1372 # introduceTo(recipient :Connection) :IntroductionInfo;
|
cannam@147
|
1373 # # Call before starting a three-way introduction, assuming a `Provide` message is to be sent on
|
cannam@147
|
1374 # # this connection and a `ThirdPartyCapId` is to be sent to `recipient`.
|
cannam@147
|
1375 #
|
cannam@147
|
1376 # struct IntroductionInfo {
|
cannam@147
|
1377 # sendToRecipient :ThirdPartyCapId;
|
cannam@147
|
1378 # sendToTarget :RecipientId;
|
cannam@147
|
1379 # }
|
cannam@147
|
1380 #
|
cannam@147
|
1381 # connectToIntroduced(capId :ThirdPartyCapId) :ConnectionAndProvisionId;
|
cannam@147
|
1382 # # Given a ThirdPartyCapId received over this connection, connect to the third party. The
|
cannam@147
|
1383 # # caller should then send an `Accept` message over the new connection.
|
cannam@147
|
1384 #
|
cannam@147
|
1385 # acceptIntroducedConnection(recipientId :RecipientId) :Connection;
|
cannam@147
|
1386 # # Given a RecipientId received in a `Provide` message on this `Connection`, wait for the
|
cannam@147
|
1387 # # recipient to connect, and return the connection formed. Usually, the first message received
|
cannam@147
|
1388 # # on the new connection will be an `Accept` message.
|
cannam@147
|
1389 # }
|
cannam@147
|
1390 #
|
cannam@147
|
1391 # struct ConnectionAndProvisionId {
|
cannam@147
|
1392 # # **(level 3)**
|
cannam@147
|
1393 #
|
cannam@147
|
1394 # connection :Connection;
|
cannam@147
|
1395 # # Connection on which to issue `Accept` message.
|
cannam@147
|
1396 #
|
cannam@147
|
1397 # provision :ProvisionId;
|
cannam@147
|
1398 # # `ProvisionId` to send in the `Accept` message.
|
cannam@147
|
1399 # }
|