Commit dd9038ab authored by Kenton Varda's avatar Kenton Varda

Split into more levels; add Save and Delete to complement Restore.

parent 4707ede6
...@@ -31,16 +31,17 @@ ...@@ -31,16 +31,17 @@
# the world only sees the container, and treats it as if it were itself the host of all of the # the world only sees the container, and treats it as if it were itself the host of all of the
# containee's objects. # containee's objects.
# #
# Since there are only two vats in this network, there is never a need for three-way introductions. # Since there are only two vats in this network, there is never a need for three-way introductions,
# Joins _could_ be needed in cases where the container itself participates in a network that uses # so level 3 is free. Joins _could_ be needed in cases where the container itself participates in
# joins, as the container may export two objects to the containee which, unbeknownst to it, are # a network that uses joins, as the container may export two objects to the containee which,
# actually proxies of the same remote object. However, from the containee's point of view, such # unbeknownst to it, are actually proxies of the same remote object. However, from the containee's
# a join is trivial to request, and the containee never needs to receive join requests. # point of view, such a join is trivial to request, and the containee never needs to receive join
# requests.
# #
# Therefore, a level 3 implementation of the confined network is barely more complicated than a # Therefore, a level 4 implementation of the confined network is barely more complicated than a
# level 1 implementation. However, such an implementation is able to make use of the container's # level 1 implementation. However, such an implementation is able to make use of the container's
# implementation of whatever network it lives in. Thus, if you have an application that implements # implementation of whatever network it lives in. Thus, if you have an application that implements
# the confined network at level 3, your application can participate in _any_ network at level 3 so # the confined network at level 4, your application can participate in _any_ network at level 4 so
# long as you pair it with the appropriate container. # long as you pair it with the appropriate container.
# #
# The "confined" network protocol may also be a reasonable basis for simple two-party client-server # The "confined" network protocol may also be a reasonable basis for simple two-party client-server
...@@ -53,18 +54,20 @@ struct SturdyRef { ...@@ -53,18 +54,20 @@ struct SturdyRef {
union { union {
external @0 :Object; external @0 :Object;
# The object lives outside the container. The container can handle `Restore` requests for this # The object lives outside the container. The container can handle `Restore` requests for this
# ref. The content of the ref is defined by the container implementation and opaque to the # ref. The content of the ref is defined by the container implementation and configuration.
# containee. The container ensures that the ref is encoded in such a way that the containee # It may simply be a SturdyRef in the format of the container's external network. However,
# cannot possibly derive the original bits of the external-world reference, probably by storing # some containers may actually encrypt external references in order to support distributed
# the external ref on a table somewhere. See: # confinement:
# http://www.erights.org/elib/capability/dist-confine.html # http://www.erights.org/elib/capability/dist-confine.html
confined @1 :Object; confined @1 :Object;
# The object lives inside the container -- it is implemented by the contained app. That app # The object lives inside the container -- it is implemented by the contained app. That app
# handles `Restore` requests for this ref. The content of the ref is defined by the app # handles `Restore` requests for this ref. The content of the ref is defined by the app
# and opaque to the container. The container shall ensure that the raw bits of this ref are # and opaque to the container. The container may offer the ability to encrypt outgoing
# not revealed to the outside world, so as long as the app trusts the container, it need not # `SturdyRefs` so that their content is opaque to the outside world; in this case, so long as
# worry about encrypting or signing the ref. # the app trusts the container, it need not encrypt nor sign the ref itself. However, this
# may be undesirable for level 1 applications that only export non-secret singletons anyway,
# so it should be configurable.
} }
} }
......
...@@ -59,31 +59,45 @@ ...@@ -59,31 +59,45 @@
# http://erights.org/elib/concurrency/partial-order.html # http://erights.org/elib/concurrency/partial-order.html
# #
# Since the full protocol is complicated, we define multiple levels of support which an # Since the full protocol is complicated, we define multiple levels of support which an
# implementation may target. Comments in this file indicate which level requires the corresponding # implementation may target. For typical applications, level 1 support will be sufficient.
# feature to be implemented -- if unspecified, the feature must be implemented at level 1. # Comments in this file indicate which level requires the corresponding feature to be
# # implemented.
# * **Level 1:** The implementation supports simple bilateral interaction, but interactions between #
# three or more parties are supported only via proxying of objects. E.g. if Alice wants to send # * **Level 0:** The implementation does not support object references. `Restore` is supported
# Bob a capability pointing to Carol, Alice must host a local proxy of Carol and send Bob a # only for looking up singleton objects which exist for the lifetime of the server, and only
# reference to that; Bob cannot form a direct connection to Carol. Level 1 implementations do # these singleton objects can receive calls. At this level, the implementation does not support
# not support "join" or "eq" across capabilities received from different vats, although they # object-oriented protocols and is similar in complexity to JSON-RPC or Protobuf "generic
# should be supported on capabilities received from the same vat. # services". This level should be considered only a temporary stepping-stone toward level 1 as
# # the lack of object references drastically changes how protocols are designed. Applications
# * **Level 2:** The implementation supports three-way interactions but does not implement "Join" # _should not_ attempt to design their protocols around the limitations of level 0
# implementations.
#
# * **Level 1:** The implementation supports simple bilateral interaction with object references
# and promise pipelining, but interactions between three or more parties are supported only via
# proxying of objects. E.g. if Alice wants to send Bob a capability pointing to Carol, Alice
# must host a local proxy of Carol and send Bob a reference to that; Bob cannot form a direct
# connection to Carol. Level 1 implementations do not support "join" or "eq" across capabilities
# received from different vats, although they should be supported on capabilities received from
# the same vat. `Restore` is supported only for looking up singleton objects as in level 0.
#
# * **Level 2:** The implementation supports saving, restoring, and deleting persistent
# capabilities.
#
# * **Level 3:** The implementation supports three-way interactions but does not implement "Join"
# operations. The implementation can be used effectively on networks that do not require joins, # operations. The implementation can be used effectively on networks that do not require joins,
# or to implement objects that never need to be joined. # or to implement objects that never need to be joined.
# #
# * **Level 3:** The entire protocol is implemented, including joins. # * **Level 4:** The entire protocol is implemented, including joins.
# #
# Note that an implementation must also support specific networks (transports), as described in # Note that an implementation must also support specific networks (transports), as described in
# the "Network-specific Parameters" section below. An implementation might have different levels # the "Network-specific Parameters" section below. An implementation might have different levels
# depending on the network used. # depending on the network used.
# #
# New implementations of Cap'n Proto should start out targeting the simplistic "confined" network # New implementations of Cap'n Proto should start out targeting the simplistic "confined" network
# type as defined in `rpc-confined.capnp`. With this network type, "Level 2" is irrelevant and # type as defined in `rpc-confined.capnp`. With this network type, level 3 is irrelevant and
# "Level 3" is much easier than usual to implement. When such an implementation is actually run # levels 2 and 4 are much easier than usual to implement. When such an implementation is actually
# inside a container, the contained app effectively gets to make full use of the container's # run inside a container, the contained app effectively gets to make full use of the container's
# network at level 3. And since Cap'n Proto IPC is extremely fast, it may never make sense to # network at level 4. And since Cap'n Proto IPC is extremely fast, it may never make sense to
# bother implementing any other vat network protocol -- just use the correct container type and get # bother implementing any other vat network protocol -- just use the correct container type and get
# it for free. # it for free.
...@@ -125,11 +139,15 @@ $Cxx.namespace("capnp::rpc"); ...@@ -125,11 +139,15 @@ $Cxx.namespace("capnp::rpc");
# establishing a new connection and restoring from these persistent capabilities. # establishing a new connection and restoring from these persistent capabilities.
using QuestionId = UInt32; using QuestionId = UInt32;
# **(level 0)**
#
# Identifies a question in the questions/answers table. The questioner (caller) chooses an ID # Identifies a question in the questions/answers table. The questioner (caller) chooses an ID
# when making a call. The ID remains valid in caller -> callee messages until a ReleaseAnswer # when making a call. The ID remains valid in caller -> callee messages until a Finish
# message is sent, and remains valid in callee -> caller messages until a Return message is sent. # message is sent, and remains valid in callee -> caller messages until a Return message is sent.
using ExportId = UInt32; using ExportId = UInt32;
# **(level 1)**
#
# Identifies an exported capability or promise in the exports/imports table. The exporter chooses # Identifies an exported capability or promise in the exports/imports table. The exporter chooses
# an ID before sending a capability over the wire. If the capability is already in the table, the # an ID before sending a capability over the wire. If the capability is already in the table, the
# exporter should reuse the same ID. If the ID is a promise (as opposed to a settled capability), # exporter should reuse the same ID. If the ID is a promise (as opposed to a settled capability),
...@@ -138,7 +156,7 @@ using ExportId = UInt32; ...@@ -138,7 +156,7 @@ using ExportId = UInt32;
# #
# ExportIds are subject to reference counting. When an `ExportId` is received embedded in an # ExportIds are subject to reference counting. When an `ExportId` is received embedded in an
# question or answer, the export has an implicit reference until that question or answer is # question or answer, the export has an implicit reference until that question or answer is
# released (questions are released by `Return`, answers are released by `ReleaseAnswer`). Such an # released (questions are released by `Return`, answers are released by `Finish`). Such an
# export can be retained beyond that point by including it in the `retainedCaps` list at the time # export can be retained beyond that point by including it in the `retainedCaps` list at the time
# the question/answer is released, thus incrementing its reference count. The reference count is # the question/answer is released, thus incrementing its reference count. The reference count is
# later decremented by a `Release` message. Since the `Release` message can specify an arbitrary # later decremented by a `Release` message. Since the `Release` message can specify an arbitrary
...@@ -165,29 +183,39 @@ struct Message { ...@@ -165,29 +183,39 @@ struct Message {
# An RPC connection is a bi-directional stream of Messages. # An RPC connection is a bi-directional stream of Messages.
union { union {
# Level 1 features ----------------------------------------------- # Level 0 features -----------------------------------------------
call @0 :Call; # Begin a method call. call @0 :Call; # Begin a method call.
return @1 :Return; # Complete a method call. return @1 :Return; # Complete a method call.
resolve @2 :Resolve; # Resolve a previously-sent promise. finish @2 :Finish; # Release a returned answer / cancel a call.
release @3 :Release; # Release a capability so that the remote object can be deallocated. # Level 1 features -----------------------------------------------
releaseAnswer @4 :ReleaseAnswer; # Release a returned answer / cancel a call.
restore @5 :Restore; # Restore a persistent capability from a previous connection. resolve @3 :Resolve; # Resolve a previously-sent promise.
release @4 :Release; # Release a capability so that the remote object can be deallocated.
# Level 2 features ----------------------------------------------- # Level 2 features -----------------------------------------------
provide @6 :Provide; # Provide a capability to a third party. save @5 :Save; # Save a capability persistently.
accept @7 :Accept; # Accept a capability provided by a third party. restore @6 :Restore; # Restore a persistent capability from a previous connection.
delete @7 :Delete; # Delete a persistent capability.
# Level 3 features ----------------------------------------------- # Level 3 features -----------------------------------------------
join @8 :Join; # Directly connect to the common root of two or more proxied caps. provide @8 :Provide; # Provide a capability to a third party.
accept @9 :Accept; # Accept a capability provided by a third party.
# Level 4 features -----------------------------------------------
join @10 :Join; # Directly connect to the common root of two or more proxied caps.
} }
} }
# Level 0 message types ----------------------------------------------
struct Call { struct Call {
# **(level 0)**
#
# Message type initiating a method call on a capability. # Message type initiating a method call on a capability.
questionId @0 :QuestionId; questionId @0 :QuestionId;
...@@ -198,7 +226,7 @@ struct Call { ...@@ -198,7 +226,7 @@ struct Call {
# #
# A question ID can be reused once both: # A question ID can be reused once both:
# - A matching Return has been received from the callee. # - A matching Return has been received from the callee.
# - A matching ReleaseAnswer has been sent from the caller. # - A matching Finish has been sent from the caller.
target :union { target :union {
exportedCap @1 :ExportId; exportedCap @1 :ExportId;
...@@ -207,6 +235,9 @@ struct Call { ...@@ -207,6 +235,9 @@ struct Call {
promisedAnswer @2 :PromisedAnswer; promisedAnswer @2 :PromisedAnswer;
# This call is to a capability that is expected to be returned by another call that has not # This call is to a capability that is expected to be returned by another call that has not
# yet been completed. # yet been completed.
#
# At level 0, this is supported only for addressing the result of a previous `Restore`, so that
# initial startup doesn't require a round trip.
} }
interfaceId @3 :UInt64; interfaceId @3 :UInt64;
...@@ -223,12 +254,16 @@ struct Call { ...@@ -223,12 +254,16 @@ struct Call {
} }
struct Return { struct Return {
# **(level 0)**
#
# Message type sent from callee to caller indicating that the call has completed. # Message type sent from callee to caller indicating that the call has completed.
questionId @0 :QuestionId; questionId @0 :QuestionId;
# Question ID which is being answered, as specified in the corresponding Call. # Question ID which is being answered, as specified in the corresponding Call.
retainedCaps @1 :List(ExportId); retainedCaps @1 :List(ExportId);
# **(level 1)**
#
# List of capabilities from the request to which the callee continues to hold references. Any # List of capabilities from the request to which the callee continues to hold references. Any
# other capabilities from the request are implicitly released. # other capabilities from the request are implicitly released.
...@@ -241,21 +276,52 @@ struct Return { ...@@ -241,21 +276,52 @@ struct Return {
# #
# For a `Return` in response to an `Accept`, `answer` is a capability pointer (and therefore # For a `Return` in response to an `Accept`, `answer` is a capability pointer (and therefore
# points to a `CapDescriptor`, but is tagged as a capability rather than a struct). A # points to a `CapDescriptor`, but is tagged as a capability rather than a struct). A
# `ReleaseAnswer` is still required in this case, and the capability must still be listed in # `Finish` is still required in this case, and the capability must still be listed in
# `retainedCaps` if it is to be retained. # `retainedCaps` if it is to be retained.
exception @3 :Exception; exception @3 :Exception;
# Indicates that the call failed and explains why. # Indicates that the call failed and explains why.
canceled @4 :Void; canceled @4 :Void;
# Indicates that the call was canceled due to the caller sending a ReleaseAnswer message # Indicates that the call was canceled due to the caller sending a Finish message
# before the call had completed. # before the call had completed.
} }
} }
struct Finish {
# **(level 0)**
#
# Message type sent from the caller to the callee to indicate:
# 1) The questionId will no longer be used in any messages sent by the callee (no further
# pipelined requests).
# 2) Any capabilities in the answer other than the ones listed below should be implicitly
# released.
# 3) If the answer has not returned yet, the caller no longer cares about the answer, so the
# callee may wish to immediately cancel the operation and send back a Return message with
# "canceled" set.
questionId @0 :QuestionId;
# ID of the question whose answer is to be released.
retainedCaps @1 :List(ExportId);
# **(level 1)**
#
# List of capabilities from the answer to which the callee continues to hold references. Any
# other capabilities from the answer that need to be released are implicitly released along
# with the answer itself.
}
# Level 1 message types ----------------------------------------------
struct Resolve { struct Resolve {
# **(level 1)**
#
# Message type sent to indicate that a previously-sent promise has now been resolved to some other # Message type sent to indicate that a previously-sent promise has now been resolved to some other
# object (possibly another promise) -- or broken, or canceled. # object (possibly another promise) -- or broken, or canceled.
#
# Level 0 implementations may want to respond to a `Resolve` by sending an appropriate `Release`
# message, otherwise the object will stick around until the connection is closed even though
# it will never be used.
promiseId @0 :ExportId; promiseId @0 :ExportId;
# The ID of the promise to be resolved. # The ID of the promise to be resolved.
...@@ -299,6 +365,8 @@ struct Resolve { ...@@ -299,6 +365,8 @@ struct Resolve {
} }
struct Release { struct Release {
# **(level 1)**
#
# Message type sent to indicate that the sender is done with the given capability and the receiver # Message type sent to indicate that the sender is done with the given capability and the receiver
# can free resources allocated to it. # can free resources allocated to it.
...@@ -310,39 +378,83 @@ struct Release { ...@@ -310,39 +378,83 @@ struct Release {
# when the reference count reaches zero. # when the reference count reaches zero.
} }
struct ReleaseAnswer { # Level 2 message types ----------------------------------------------
# Message type sent from the caller to the callee to indicate:
# 1) The questionId will no longer be used in any messages sent by the callee (no further struct Save {
# pipelined requests). # **(level 2)**
# 2) Any capabilities in the answer other than the ones listed below should be implicitly #
# released. # Message type sent to save a capability persistently so that it can be restored by a future
# 3) If the answer has not returned yet, the caller no longer cares about the answer, so the # connection. Not all capabilities can be saved -- application interfaces should define which
# callee may wish to immediately cancel the operation and send back a Return message with # capabilities support this and which do not.
# "canceled" set.
questionId @0 :QuestionId; questionId @0 :QuestionId;
# ID of the question whose answer is to be released. # A new question ID identifying this request, which will eventually receive a Return
# message whose `answer` is a SturdyRef.
retainedCaps @1 :List(ExportId); target :union {
# List of capabilities from the answer to which the callee continues to hold references. Any # What is to be saved.
# other capabilities from the answer that need to be released are implicitly released along
# with the answer itself. exportedCap @1 :ExportId;
# An exported capability.
promisedAnswer @2 :PromisedAnswer;
# A capability expected to be returned in the answer to an outstanding question.
}
} }
struct Restore { struct Restore {
# **(mostly level 2)**
#
# Message type sent to restore a persistent capability obtained during a previous connection, or # Message type sent to restore a persistent capability obtained during a previous connection, or
# through other means. # through other means.
#
# Level 0/1 implementations need to implement a limited version of `Restore` only for the purpose
# of bootstrapping a new connection (otherwise, there would be no objects to which to address
# methods). These levels may simply implement singleton services that exist for the lifetime of
# the host process and probably have non-secret names. A level 0 receiver of `Restore` should
# never actually send a `Return` message, but should simply expect `Call` messages addressed to
# the `PromisedAnswer` corresponding to the `Restore`. A level 0 sender of `Restore` can ignore
# the corresponding `Return` and just keep addressing the `PromisedAnswer`.
questionId @0 :QuestionId; questionId @0 :QuestionId;
# A new question ID identifying this restore message, which will eventually receive a Return # A new question ID identifying this request, which will eventually receive a Return message
# message containing the restored capability. # containing the restored capability.
ref @1 :SturdyRef; ref @1 :SturdyRef;
# Designates the capability to restore. # Designates the capability to restore.
} }
struct Delete {
# **(level 2)**
#
# Message type sent to delete a previously-saved persistent capability. In other words, this
# means "this ref will no longer be used in the future", so that the host can potentially
# garbage collect resources associated with it. Note that if any ExportId still refers to a
# capability restored from this ref, that export should still remain valid until released.
#
# Different applications may define different policies regarding saved capability lifetimes that
# may or may not rely on `Delete`. For the purpose of implementation freedom, a receiver is
# allowed to silently ignore a delete request for a reference it doesn't recognize. This way,
# a persistent capability could be given an expiration time, after which the capability is
# automatically deleted, and any future `Delete` message is ignored.
#
# A client must send no more than one `Delete` message for any given `Save`, so that a host
# can potentially implement reference counting. However, hosts should be wary of reference
# counting across multiple clients, as a malicious client could of course send multiple
# `Delete`s.
questionId @0 :QuestionId;
# A new question ID identifying this request, which will eventually receive a Return message
# with an empty answer.
ref @1 :SturdyRef;
# Designates the capability to delete.
}
# Level 3 message types ----------------------------------------------
struct Provide { struct Provide {
# **Level 2 feature** # **(level 3)**
# #
# Message type sent to indicate that the sender wishes to make a particular capability implemented # Message type sent to indicate that the sender wishes to make a particular capability implemented
# by the receiver available to a third party for direct access (without the need for the third # by the receiver available to a third party for direct access (without the need for the third
...@@ -354,7 +466,7 @@ struct Provide { ...@@ -354,7 +466,7 @@ struct Provide {
questionId @0 :QuestionId; questionId @0 :QuestionId;
# Question ID to be held open until the recipient has received the capability. An answer will # Question ID to be held open until the recipient has received the capability. An answer will
# be returned once the third party has successfully received the capability. The sender must # be returned once the third party has successfully received the capability. The sender must
# at some point send a ReleaseAnswer message as with any other call, and such a message can be # at some point send a `Finish` message as with any other call, and such a message can be
# used to cancel the whole operation. # used to cancel the whole operation.
target :union { target :union {
...@@ -372,7 +484,7 @@ struct Provide { ...@@ -372,7 +484,7 @@ struct Provide {
} }
struct Accept { struct Accept {
# **Level 2 feature** # **(level 3)**
# #
# Message type sent to pick up a capability hosted by the receiving vat and provided by a third # Message type sent to pick up a capability hosted by the receiving vat and provided by a third
# party. The third party previously designated the capability using `Provide`. # party. The third party previously designated the capability using `Provide`.
...@@ -385,8 +497,10 @@ struct Accept { ...@@ -385,8 +497,10 @@ struct Accept {
# Identifies the provided object to be picked up. # Identifies the provided object to be picked up.
} }
# Level 4 message types ----------------------------------------------
struct Join { struct Join {
# **Level 3 feature** # **(level 4)**
# #
# Message type sent to implement E.join(), which, given a number of capabilities which are # Message type sent to implement E.join(), which, given a number of capabilities which are
# expected to be equivalent, finds the underlying object upon which they all agree and forms a # expected to be equivalent, finds the underlying object upon which they all agree and forms a
...@@ -433,12 +547,12 @@ struct Join { ...@@ -433,12 +547,12 @@ struct Join {
# is relayed from the joined object's host, possibly with transformation applied as needed # is relayed from the joined object's host, possibly with transformation applied as needed
# by the network. # by the network.
# #
# Like any answer, the answer must be released using a `ReleaseAnswer`. However, this release # Like any answer, the answer must be released using a `Finish`. However, this release
# should not occur until the joiner has either successfully connected to the joined object. # should not occur until the joiner has either successfully connected to the joined object.
# Vats relaying a `Join` message similarly must not release the answer they receive until the # Vats relaying a `Join` message similarly must not release the answer they receive until the
# answer they relayed back towards the joiner has itself been released. This allows the # answer they relayed back towards the joiner has itself been released. This allows the
# joined object's host to detect when the Join operation is canceled before completing -- if # joined object's host to detect when the Join operation is canceled before completing -- if
# it receives a `ReleaseAnswer` for one of the join answers before the joiner successfully # it receives a `Finish` for one of the join answers before the joiner successfully
# connects. It can then free any resources it had allocated as part of the join. # connects. It can then free any resources it had allocated as part of the join.
capId @1 :ExportId; capId @1 :ExportId;
...@@ -453,6 +567,8 @@ struct Join { ...@@ -453,6 +567,8 @@ struct Join {
# Common structures used in messages # Common structures used in messages
struct CapDescriptor { struct CapDescriptor {
# **(level 1)**
#
# When an application-defined type contains an interface pointer, that pointer's encoding is the # When an application-defined type contains an interface pointer, that pointer's encoding is the
# same as a struct pointer except that the bottom two bits are 1's instead of 0's. The pointer # same as a struct pointer except that the bottom two bits are 1's instead of 0's. The pointer
# actually points to an instance of `CapDescriptor`. The runtime API should not reveal the # actually points to an instance of `CapDescriptor`. The runtime API should not reveal the
...@@ -488,27 +604,24 @@ struct CapDescriptor { ...@@ -488,27 +604,24 @@ struct CapDescriptor {
# by the sender. # by the sender.
thirdPartyHosted @5 :ThirdPartyCapDescriptor; thirdPartyHosted @5 :ThirdPartyCapDescriptor;
# **Level 2 feature** # **(level 3)**
# #
# A capability that lives in neither the sender's nor the receiver's vat. The sender needs # A capability that lives in neither the sender's nor the receiver's vat. The sender needs
# to form a direct connection to a third party to pick up the capability. # to form a direct connection to a third party to pick up the capability.
} }
sturdyRef @6 :SturdyRef;
# If non-null, this is a SturdyRef that can be used to store this capability persistently and
# restore access to in in the future (using a `Restore` message). If null, this capability will
# be lost if the connection dies. Generally, application interfaces should define when a client
# can expect a capability to be persistent (and therefore have a SturdyRef attached). However,
# application protocols should never embed SturdyRefs directly, as various infrastructure like
# transports, gateways, and sandboxes may need to be aware of SturdyRefs being passed over the
# wire in order to transform them into different namespaces.
} }
struct PromisedAnswer { struct PromisedAnswer {
# **(mostly level 1)**
#
# Specifies how to derive a promise from an unanswered question, by specifying the path of fields # Specifies how to derive a promise from an unanswered question, by specifying the path of fields
# to follow from the root of the eventual answer struct to get to the desired capability. Used # to follow from the root of the eventual answer struct to get to the desired capability. Used
# to address method calls to a not-yet-returned capability or to pass such a capability as an # to address method calls to a not-yet-returned capability or to pass such a capability as an
# input to some other method call. # input to some other method call.
#
# Level 0 implementations must support `PromisedAnswer` only for the case where the answer is
# to a `Restore` message. In this case, `path` is always empty since `Restore` always returns
# a raw capability.
questionId @0 :QuestionId; questionId @0 :QuestionId;
# ID of the question (in the sender's question table / receiver's answer table) whose answer is # ID of the question (in the sender's question table / receiver's answer table) whose answer is
...@@ -530,7 +643,7 @@ struct PromisedAnswer { ...@@ -530,7 +643,7 @@ struct PromisedAnswer {
} }
struct ThirdPartyCapDescriptor { struct ThirdPartyCapDescriptor {
# **Level 2 feature** # **(level 3)**
# #
# Identifies a capability in a third-party vat which the sender wants the receiver to pick up. # Identifies a capability in a third-party vat which the sender wants the receiver to pick up.
...@@ -546,6 +659,10 @@ struct ThirdPartyCapDescriptor { ...@@ -546,6 +659,10 @@ struct ThirdPartyCapDescriptor {
} }
struct Exception { struct Exception {
# **(level 0)**
#
# Describes an arbitrary error that prevented an operation (e.g. a call) from completing.
reason @0 :Text; reason @0 :Text;
# Human-readable failure description. # Human-readable failure description.
...@@ -598,21 +715,31 @@ struct Exception { ...@@ -598,21 +715,31 @@ struct Exception {
# the outside world entirely through a container/supervisor. All objects in the world that aren't # the outside world entirely through a container/supervisor. All objects in the world that aren't
# hosted by the contained vat appear as if they were hosted by the container. This network type is # hosted by the contained vat appear as if they were hosted by the container. This network type is
# interesting because from the containee's point of view, there are no three-party interactions at # interesting because from the containee's point of view, there are no three-party interactions at
# all, and joins are unusually simple to implement, so implementing at level 3 is barely more # all, and joins are unusually simple to implement, so implementing at level 4 is barely more
# complicated than implementing at level 1. Moreover, if you pair an app implementing the confined # complicated than implementing at level 1. Moreover, if you pair an app implementing the confined
# network with a container that implements some other network, the app can then participate on # network with a container that implements some other network, the app can then participate on
# the container's network just as if it implemented that network directly. The types used by the # the container's network just as if it implemented that network directly. The types used by the
# "confined" network are defined in `rpc-confined.capnp`. # "confined" network are defined in `rpc-confined.capnp`.
# #
# The things which we need to parameterize are: # The things which we need to parameterize are:
# - How to authenticate vats in three-party introductions. # - How to store capabilities long-term without holding a connection open (mostly level 2).
# - How to implement `Join`. # - How to authenticate vats in three-party introductions (level 3).
# - How to store capabilities long-term without holding a connection open. # - How to implement `Join` (level 4).
#
# Persistent references
# ---------------------
#
# **(mostly level 2)**
#
# We want to allow some capabilities to be stored long-term, even if a connection is lost and later
# recreated. ExportId is a short-term identifier that is specific to a connection, so it doesn't
# help here. We need a way to specify long-term identifiers, as well as a strategy for
# reconnecting to a referenced capability later.
# #
# Three-party interactions # Three-party interactions
# ------------------------ # ------------------------
# #
# **Level 2 feature** # **(level 3)**
# #
# In cases where more than two vats are interacting, we have situations where VatA holds a # In cases where more than two vats are interacting, we have situations where VatA holds a
# capability hosted by VatB and wants to send that capability to VatC. This can be accomplished # capability hosted by VatB and wants to send that capability to VatC. This can be accomplished
...@@ -628,21 +755,15 @@ struct Exception { ...@@ -628,21 +755,15 @@ struct Exception {
# Join # Join
# ---- # ----
# #
# **Level 3 feature** # **(level 4)**
# #
# The `Join` message type and corresponding operation arranges for a direct connection to be formed # The `Join` message type and corresponding operation arranges for a direct connection to be formed
# between the joiner and the host of the joined object, and this connection must be authenticated. # between the joiner and the host of the joined object, and this connection must be authenticated.
# Thus, the details are network-dependent. # Thus, the details are network-dependent.
#
# Persistent references
# ---------------------
#
# We want to allow some capabilities to be stored long-term, even if a connection is lost and later
# recreated. ExportId is a short-term identifier that is specific to a connection, so it doesn't
# help here. We need a way to specify long-term identifiers, as well as a strategy for
# reconnecting to a referenced capability later.
using SturdyRef = Object; using SturdyRef = Object;
# **(mostly level 2)**
#
# Identifies a long-lived capability which can be obtained again in a future connection by sending # Identifies a long-lived capability which can be obtained again in a future connection by sending
# a `Restore` message. A SturdyRef is a lot like a URL, but possibly with additional # a `Restore` message. A SturdyRef is a lot like a URL, but possibly with additional
# considerations e.g. to support authentication without a certificate authority. # considerations e.g. to support authentication without a certificate authority.
...@@ -672,7 +793,7 @@ using SturdyRef = Object; ...@@ -672,7 +793,7 @@ using SturdyRef = Object;
# can solve these problems but these are beyond the scope of this protocol. # can solve these problems but these are beyond the scope of this protocol.
using ProvisionId = Object; using ProvisionId = Object;
# **Level 2 feature** # **(level 3)**
# #
# The information which must be sent in an `Accept` message to identify the object being accepted. # The information which must be sent in an `Accept` message to identify the object being accepted.
# #
...@@ -681,7 +802,7 @@ using ProvisionId = Object; ...@@ -681,7 +802,7 @@ using ProvisionId = Object;
# that provider. # that provider.
using RecipientId = Object; using RecipientId = Object;
# **Level 2 feature** # **(level 3)**
# #
# The information which must be sent in a `Provide` message to identify the recipient of the # The information which must be sent in a `Provide` message to identify the recipient of the
# capability. # capability.
...@@ -690,7 +811,7 @@ using RecipientId = Object; ...@@ -690,7 +811,7 @@ using RecipientId = Object;
# fingerprint of the recipient. # fingerprint of the recipient.
using ThirdPartyCapId = Object; using ThirdPartyCapId = Object;
# **Level 2 feature** # **(level 3)**
# #
# The information needed to connect to a third party and accept a capability from it. # The information needed to connect to a third party and accept a capability from it.
# #
...@@ -700,6 +821,8 @@ using ThirdPartyCapId = Object; ...@@ -700,6 +821,8 @@ using ThirdPartyCapId = Object;
# (used to identify which capability to pick up). # (used to identify which capability to pick up).
using JoinKeyPart = Object; using JoinKeyPart = Object;
# **(level 4)**
#
# A piece of a secret key. One piece is sent along each path that is expected to lead to the same # A piece of a secret key. One piece is sent along each path that is expected to lead to the same
# place. Once the pieces are combined, a direct connection may be formed between the sender and # place. Once the pieces are combined, a direct connection may be formed between the sender and
# the receiver, bypassing any men-in-the-middle along the paths. See the `Join` message type. # the receiver, bypassing any men-in-the-middle along the paths. See the `Join` message type.
...@@ -722,6 +845,8 @@ using JoinKeyPart = Object; ...@@ -722,6 +845,8 @@ using JoinKeyPart = Object;
# how many parts to expect and a hash of the shared secret (used to match up parts). # how many parts to expect and a hash of the shared secret (used to match up parts).
using JoinAnswer = Object; using JoinAnswer = Object;
# **(level 4)**
#
# Information returned in the answer to a `Join` message, needed by the joiner in order to form a # Information returned in the answer to a `Join` message, needed by the joiner in order to form a
# direct connection to a joined object. This might simply be the address of the joined object's # direct connection to a joined object. This might simply be the address of the joined object's
# host vat, since the `JoinKey` has already been communicated so the two vats already have a shared # host vat, since the `JoinKey` has already been communicated so the two vats already have a shared
...@@ -749,7 +874,7 @@ using JoinAnswer = Object; ...@@ -749,7 +874,7 @@ using JoinAnswer = Object;
# # Note that methods returning a `Connection` may return a pre-existing `Connection`, and the # # Note that methods returning a `Connection` may return a pre-existing `Connection`, and the
# # caller is expected to find and share state with existing users of the connection. # # caller is expected to find and share state with existing users of the connection.
# #
# # Level 1 features ----------------------------------------------- # # Level 0 features -----------------------------------------------
# #
# connectToHostOf(ref :SturdyRef) :Connection; # connectToHostOf(ref :SturdyRef) :Connection;
# # Connect to a host which can restore the given SturdyRef. The transport should return a # # Connect to a host which can restore the given SturdyRef. The transport should return a
...@@ -766,7 +891,7 @@ using JoinAnswer = Object; ...@@ -766,7 +891,7 @@ using JoinAnswer = Object;
# # # #
# # Once connected, the first received message will usually be a `Restore`. # # Once connected, the first received message will usually be a `Restore`.
# #
# # Level 3 features ----------------------------------------------- # # Level 4 features -----------------------------------------------
# #
# newJoiner(count :UInt32): NewJoinerResponse; # newJoiner(count :UInt32): NewJoinerResponse;
# # Prepare a new Join operation, which will eventually lead to forming a new direct connection # # Prepare a new Join operation, which will eventually lead to forming a new direct connection
...@@ -799,7 +924,7 @@ using JoinAnswer = Object; ...@@ -799,7 +924,7 @@ using JoinAnswer = Object;
# } # }
# #
# interface Connection { # interface Connection {
# # Level 1 features ----------------------------------------------- # # Level 0 features -----------------------------------------------
# #
# send(message :Message) :Void; # send(message :Message) :Void;
# # Send the message. Returns successfully when the message (and all preceding messages) has # # Send the message. Returns successfully when the message (and all preceding messages) has
...@@ -809,7 +934,7 @@ using JoinAnswer = Object; ...@@ -809,7 +934,7 @@ using JoinAnswer = Object;
# # Receive the next message, and acknowledges receipt to the sender. Messages are received in # # Receive the next message, and acknowledges receipt to the sender. Messages are received in
# # the order in which they are sent. # # the order in which they are sent.
# #
# # Level 2 features ----------------------------------------------- # # Level 3 features -----------------------------------------------
# #
# introduceTo(recipient :Connection) :IntroductionInfo; # introduceTo(recipient :Connection) :IntroductionInfo;
# # Call before starting a three-way introduction, assuming a `Provide` message is to be sent on # # Call before starting a three-way introduction, assuming a `Provide` message is to be sent on
...@@ -831,6 +956,8 @@ using JoinAnswer = Object; ...@@ -831,6 +956,8 @@ using JoinAnswer = Object;
# } # }
# #
# sturct ConnectionAndProvisionId { # sturct ConnectionAndProvisionId {
# # **(level 3)**
#
# connection :Connection; # connection :Connection;
# # Connection on which to issue `Accept` message. # # Connection on which to issue `Accept` message.
# #
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment