Mercurial > hg > sv-dependency-builds
comparison osx/include/capnp/membrane.h @ 134:41e769c91eca
Add Capnp and KJ builds for OSX
author | Chris Cannam <cannam@all-day-breakfast.com> |
---|---|
date | Tue, 25 Oct 2016 14:48:23 +0100 |
parents | |
children | 0994c39f1e94 |
comparison
equal
deleted
inserted
replaced
133:1ac99bfc383d | 134:41e769c91eca |
---|---|
1 // Copyright (c) 2015 Sandstorm Development Group, Inc. and contributors | |
2 // Licensed under the MIT License: | |
3 // | |
4 // Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 // of this software and associated documentation files (the "Software"), to deal | |
6 // in the Software without restriction, including without limitation the rights | |
7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 // copies of the Software, and to permit persons to whom the Software is | |
9 // furnished to do so, subject to the following conditions: | |
10 // | |
11 // The above copyright notice and this permission notice shall be included in | |
12 // all copies or substantial portions of the Software. | |
13 // | |
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
20 // THE SOFTWARE. | |
21 | |
22 #ifndef CAPNP_MEMBRANE_H_ | |
23 #define CAPNP_MEMBRANE_H_ | |
24 // In capability theory, a "membrane" is a wrapper around a capability which (usually) forwards | |
25 // calls but recursively wraps capabilities in those calls in the same membrane. The purpose of a | |
26 // membrane is to enforce a barrier between two capabilities that cannot be bypassed by merely | |
27 // introducing new objects. | |
28 // | |
29 // The most common use case for a membrane is revocation: Say Alice wants to give Bob a capability | |
30 // to access Carol, but wants to be able to revoke this capability later. Alice can accomplish this | |
31 // by wrapping Carol in a revokable wrapper which passes through calls until such a time as Alice | |
32 // indicates it should be revoked, after which all calls through the wrapper will throw exceptions. | |
33 // However, a naive wrapper approach has a problem: if Bob makes a call to Carol and sends a new | |
34 // capability in that call, or if Carol returns a capability to Bob in the response to a call, then | |
35 // the two are now able to communicate using this new capability, which Alice cannot revoke. In | |
36 // order to avoid this problem, Alice must use not just a wrapper but a "membrane", which | |
37 // recursively wraps all objects that pass through it in either direction. Thus, all connections | |
38 // formed between Bob and Carol (originating from Alice's original introduction) can be revoked | |
39 // together by revoking the membrane. | |
40 // | |
41 // Note that when a capability is passed into a membrane and then passed back out, the result is | |
42 // the original capability, not a double-membraned capability. This means that in our revocation | |
43 // example, if Bob uses his capability to Carol to obtain another capability from her, then send | |
44 // it back to her, the capability Carol receives back will NOT be revoked when Bob's access to | |
45 // Carol is revoked. Thus Bob can create long-term irrevocable connections. In most practical use | |
46 // cases, this is what you want. APIs commonly rely on the fact that a capability obtained and then | |
47 // passed back can be recognized as the original capability. | |
48 // | |
49 // Mark Miller on membranes: http://www.eros-os.org/pipermail/e-lang/2003-January/008434.html | |
50 | |
51 #include "capability.h" | |
52 | |
53 namespace capnp { | |
54 | |
55 class MembranePolicy { | |
56 // Applications may implement this interface to define a membrane policy, which allows some | |
57 // calls crossing the membrane to be blocked or redirected. | |
58 | |
59 public: | |
60 virtual kj::Maybe<Capability::Client> inboundCall( | |
61 uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; | |
62 // Given an inbound call (a call originating "outside" the membrane destined for an object | |
63 // "inside" the membrane), decides what to do with it. The policy may: | |
64 // | |
65 // - Return null to indicate that the call should proceed to the destination. All capabilities | |
66 // in the parameters or result will be properly wrapped in the same membrane. | |
67 // - Return a capability to have the call redirected to that capability. Note that the redirect | |
68 // capability will be treated as outside the membrane, so the params and results will not be | |
69 // auto-wrapped; however, the callee can easily wrap the returned capability in the membrane | |
70 // itself before returning to achieve this effect. | |
71 // - Throw an exception to cause the call to fail with that exception. | |
72 // | |
73 // `target` is the underlying capability (*inside* the membrane) for which the call is destined. | |
74 // Generally, the only way you should use `target` is to wrap it in some capability which you | |
75 // return as a redirect. The redirect capability may modify the call in some way and send it to | |
76 // `target`. Be careful to use `copyIntoMembrane()` and `copyOutOfMembrane()` as appropriate when | |
77 // copying parameters or results across the membrane. | |
78 // | |
79 // Note that since `target` is inside the capability, if you were to directly return it (rather | |
80 // than return null), the effect would be that the membrane would be broken: the call would | |
81 // proceed directly and any new capabilities introduced through it would not be membraned. You | |
82 // generally should not do that. | |
83 | |
84 virtual kj::Maybe<Capability::Client> outboundCall( | |
85 uint64_t interfaceId, uint16_t methodId, Capability::Client target) = 0; | |
86 // Like `inboundCall()`, but applies to calls originating *inside* the membrane and terminating | |
87 // outside. | |
88 // | |
89 // Note: It is strongly recommended that `outboundCall()` returns null in exactly the same cases | |
90 // that `inboundCall()` return null. Conversely, for any case where `inboundCall()` would | |
91 // redirect or throw, `outboundCall()` should also redirect or throw. Otherwise, you can run | |
92 // into inconsistent behavion when a promise is returned across a membrane, and that promise | |
93 // later resolves to a capability on the other side of the membrane: calls on the promise | |
94 // will enter and then exit the membrane, but calls on the eventual resolution will not cross | |
95 // the membrane at all, so it is important that these two cases behave the same. | |
96 | |
97 virtual kj::Own<MembranePolicy> addRef() = 0; | |
98 // Return a new owned pointer to the same policy. | |
99 // | |
100 // Typically an implementation of MembranePolicy should also inherit kj::Refcounted and implement | |
101 // `addRef()` as `return kj::addRef(*this);`. | |
102 // | |
103 // Note that the membraning system considers two membranes created with the same MembranePolicy | |
104 // object actually to be the *same* membrane. This is relevant when an object passes into the | |
105 // membrane and then back out (or out and then back in): instead of double-wrapping the object, | |
106 // the wrapping will be removed. | |
107 }; | |
108 | |
109 Capability::Client membrane(Capability::Client inner, kj::Own<MembranePolicy> policy); | |
110 // Wrap `inner` in a membrane specified by `policy`. `inner` is considered "inside" the membrane, | |
111 // while the returned capability should only be called from outside the membrane. | |
112 | |
113 Capability::Client reverseMembrane(Capability::Client outer, kj::Own<MembranePolicy> policy); | |
114 // Like `membrane` but treat the input capability as "outside" the membrane, and return a | |
115 // capability appropriate for use inside. | |
116 // | |
117 // Applications typically won't use this directly; the membraning code automatically sets up | |
118 // reverse membranes where needed. | |
119 | |
120 template <typename ClientType> | |
121 ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy); | |
122 template <typename ClientType> | |
123 ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy); | |
124 // Convenience templates which return the same interface type as the input. | |
125 | |
126 template <typename ServerType> | |
127 typename ServerType::Serves::Client membrane( | |
128 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy); | |
129 template <typename ServerType> | |
130 typename ServerType::Serves::Client reverseMembrane( | |
131 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy); | |
132 // Convenience templates which input a capability server type and return the appropriate client | |
133 // type. | |
134 | |
135 template <typename Reader> | |
136 Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane( | |
137 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy); | |
138 // Copy a Cap'n Proto object (e.g. struct or list), adding the given membrane to any capabilities | |
139 // found within it. `from` is interpreted as "outside" the membrane while `to` is "inside". | |
140 | |
141 template <typename Reader> | |
142 Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane( | |
143 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy); | |
144 // Like copyIntoMembrane() except that `from` is "inside" the membrane and `to` is "outside". | |
145 | |
146 // ======================================================================================= | |
147 // inline implementation details | |
148 | |
149 template <typename ClientType> | |
150 ClientType membrane(ClientType inner, kj::Own<MembranePolicy> policy) { | |
151 return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) | |
152 .castAs<typename ClientType::Calls>(); | |
153 } | |
154 template <typename ClientType> | |
155 ClientType reverseMembrane(ClientType inner, kj::Own<MembranePolicy> policy) { | |
156 return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) | |
157 .castAs<typename ClientType::Calls>(); | |
158 } | |
159 | |
160 template <typename ServerType> | |
161 typename ServerType::Serves::Client membrane( | |
162 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) { | |
163 return membrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) | |
164 .castAs<typename ServerType::Serves::Client>(); | |
165 } | |
166 template <typename ServerType> | |
167 typename ServerType::Serves::Client reverseMembrane( | |
168 kj::Own<ServerType> inner, kj::Own<MembranePolicy> policy) { | |
169 return reverseMembrane(Capability::Client(kj::mv(inner)), kj::mv(policy)) | |
170 .castAs<typename ServerType::Serves::Client>(); | |
171 } | |
172 | |
173 namespace _ { // private | |
174 | |
175 OrphanBuilder copyOutOfMembrane(PointerReader from, Orphanage to, | |
176 kj::Own<MembranePolicy> policy, bool reverse); | |
177 OrphanBuilder copyOutOfMembrane(StructReader from, Orphanage to, | |
178 kj::Own<MembranePolicy> policy, bool reverse); | |
179 OrphanBuilder copyOutOfMembrane(ListReader from, Orphanage to, | |
180 kj::Own<MembranePolicy> policy, bool reverse); | |
181 | |
182 } // namespace _ (private) | |
183 | |
184 template <typename Reader> | |
185 Orphan<typename kj::Decay<Reader>::Reads> copyIntoMembrane( | |
186 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) { | |
187 return _::copyOutOfMembrane( | |
188 _::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from), | |
189 to, kj::mv(policy), true); | |
190 } | |
191 | |
192 template <typename Reader> | |
193 Orphan<typename kj::Decay<Reader>::Reads> copyOutOfMembrane( | |
194 Reader&& from, Orphanage to, kj::Own<MembranePolicy> policy) { | |
195 return _::copyOutOfMembrane( | |
196 _::PointerHelpers<typename kj::Decay<Reader>::Reads>::getInternalReader(from), | |
197 to, kj::mv(policy), false); | |
198 } | |
199 | |
200 } // namespace capnp | |
201 | |
202 #endif // CAPNP_MEMBRANE_H_ |