1 | // Copyright (c) 2013-2014 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 | #pragma once |
23 | |
24 | #if defined(__GNUC__) && !defined(CAPNP_HEADER_WARNINGS) |
25 | #pragma GCC system_header |
26 | #endif |
27 | |
28 | #if CAPNP_LITE |
29 | #error "RPC APIs, including this header, are not available in lite mode." |
30 | #endif |
31 | |
32 | #include <kj/async.h> |
33 | #include <kj/vector.h> |
34 | #include "raw-schema.h" |
35 | #include "any.h" |
36 | #include "pointer-helpers.h" |
37 | |
38 | namespace capnp { |
39 | |
40 | template <typename Results> |
41 | class Response; |
42 | |
43 | template <typename T> |
44 | class RemotePromise: public kj::Promise<Response<T>>, public T::Pipeline { |
45 | // A Promise which supports pipelined calls. T is typically a struct type. T must declare |
46 | // an inner "mix-in" type "Pipeline" which implements pipelining; RemotePromise simply |
47 | // multiply-inherits that type along with Promise<Response<T>>. T::Pipeline must be movable, |
48 | // but does not need to be copyable (i.e. just like Promise<T>). |
49 | // |
50 | // The promise is for an owned pointer so that the RPC system can allocate the MessageReader |
51 | // itself. |
52 | |
53 | public: |
54 | inline RemotePromise(kj::Promise<Response<T>>&& promise, typename T::Pipeline&& pipeline) |
55 | : kj::Promise<Response<T>>(kj::mv(promise)), |
56 | T::Pipeline(kj::mv(pipeline)) {} |
57 | inline RemotePromise(decltype(nullptr)) |
58 | : kj::Promise<Response<T>>(nullptr), |
59 | T::Pipeline(nullptr) {} |
60 | KJ_DISALLOW_COPY(RemotePromise); |
61 | RemotePromise(RemotePromise&& other) = default; |
62 | RemotePromise& operator=(RemotePromise&& other) = default; |
63 | |
64 | static RemotePromise<T> reducePromise(kj::Promise<RemotePromise>&& promise); |
65 | // Hook for KJ so that Promise<RemotePromise<T>> automatically reduces to RemotePromise<T>. |
66 | }; |
67 | |
68 | class LocalClient; |
69 | namespace _ { // private |
70 | extern const RawSchema NULL_INTERFACE_SCHEMA; // defined in schema.c++ |
71 | class CapabilityServerSetBase; |
72 | } // namespace _ (private) |
73 | |
74 | struct Capability { |
75 | // A capability without type-safe methods. Typed capability clients wrap `Client` and typed |
76 | // capability servers subclass `Server` to dispatch to the regular, typed methods. |
77 | |
78 | class Client; |
79 | class Server; |
80 | |
81 | struct _capnpPrivate { |
82 | struct IsInterface; |
83 | static constexpr uint64_t typeId = 0x3; |
84 | static constexpr Kind kind = Kind::INTERFACE; |
85 | static constexpr _::RawSchema const* schema = &_::NULL_INTERFACE_SCHEMA; |
86 | |
87 | static const _::RawBrandedSchema* brand() { |
88 | return &_::NULL_INTERFACE_SCHEMA.defaultBrand; |
89 | } |
90 | }; |
91 | }; |
92 | |
93 | // ======================================================================================= |
94 | // Capability clients |
95 | |
96 | class RequestHook; |
97 | class ResponseHook; |
98 | class PipelineHook; |
99 | class ClientHook; |
100 | |
101 | template <typename Params, typename Results> |
102 | class Request: public Params::Builder { |
103 | // A call that hasn't been sent yet. This class extends a Builder for the call's "Params" |
104 | // structure with a method send() that actually sends it. |
105 | // |
106 | // Given a Cap'n Proto method `foo(a :A, b :B): C`, the generated client interface will have |
107 | // a method `Request<FooParams, C> fooRequest()` (as well as a convenience method |
108 | // `RemotePromise<C> foo(A::Reader a, B::Reader b)`). |
109 | |
110 | public: |
111 | inline Request(typename Params::Builder builder, kj::Own<RequestHook>&& hook) |
112 | : Params::Builder(builder), hook(kj::mv(hook)) {} |
113 | inline Request(decltype(nullptr)): Params::Builder(nullptr) {} |
114 | |
115 | RemotePromise<Results> send() KJ_WARN_UNUSED_RESULT; |
116 | // Send the call and return a promise for the results. |
117 | |
118 | private: |
119 | kj::Own<RequestHook> hook; |
120 | |
121 | friend class Capability::Client; |
122 | friend struct DynamicCapability; |
123 | template <typename, typename> |
124 | friend class CallContext; |
125 | friend class RequestHook; |
126 | }; |
127 | |
128 | template <typename Results> |
129 | class Response: public Results::Reader { |
130 | // A completed call. This class extends a Reader for the call's answer structure. The Response |
131 | // is move-only -- once it goes out-of-scope, the underlying message will be freed. |
132 | |
133 | public: |
134 | inline Response(typename Results::Reader reader, kj::Own<ResponseHook>&& hook) |
135 | : Results::Reader(reader), hook(kj::mv(hook)) {} |
136 | |
137 | private: |
138 | kj::Own<ResponseHook> hook; |
139 | |
140 | template <typename, typename> |
141 | friend class Request; |
142 | friend class ResponseHook; |
143 | }; |
144 | |
145 | class Capability::Client { |
146 | // Base type for capability clients. |
147 | |
148 | public: |
149 | typedef Capability Reads; |
150 | typedef Capability Calls; |
151 | |
152 | Client(decltype(nullptr)); |
153 | // If you need to declare a Client before you have anything to assign to it (perhaps because |
154 | // the assignment is going to occur in an if/else scope), you can start by initializing it to |
155 | // `nullptr`. The resulting client is not meant to be called and throws exceptions from all |
156 | // methods. |
157 | |
158 | template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Capability::Server*>()>> |
159 | Client(kj::Own<T>&& server); |
160 | // Make a client capability that wraps the given server capability. The server's methods will |
161 | // only be executed in the given EventLoop, regardless of what thread calls the client's methods. |
162 | |
163 | template <typename T, typename = kj::EnableIf<kj::canConvert<T*, Client*>()>> |
164 | Client(kj::Promise<T>&& promise); |
165 | // Make a client from a promise for a future client. The resulting client queues calls until the |
166 | // promise resolves. |
167 | |
168 | Client(kj::Exception&& exception); |
169 | // Make a broken client that throws the given exception from all calls. |
170 | |
171 | Client(Client& other); |
172 | Client& operator=(Client& other); |
173 | // Copies by reference counting. Warning: This refcounting is not thread-safe. All copies of |
174 | // the client must remain in one thread. |
175 | |
176 | Client(Client&&) = default; |
177 | Client& operator=(Client&&) = default; |
178 | // Move constructor avoids reference counting. |
179 | |
180 | explicit Client(kj::Own<ClientHook>&& hook); |
181 | // For use by the RPC implementation: Wrap a ClientHook. |
182 | |
183 | template <typename T> |
184 | typename T::Client castAs(); |
185 | // Reinterpret the capability as implementing the given interface. Note that no error will occur |
186 | // here if the capability does not actually implement this interface, but later method calls will |
187 | // fail. It's up to the application to decide how indicate that additional interfaces are |
188 | // supported. |
189 | // |
190 | // TODO(perf): GCC 4.8 / Clang 3.3: rvalue-qualified version for better performance. |
191 | |
192 | template <typename T> |
193 | typename T::Client castAs(InterfaceSchema schema); |
194 | // Dynamic version. `T` must be `DynamicCapability`, and you must `#include <capnp/dynamic.h>`. |
195 | |
196 | kj::Promise<void> whenResolved(); |
197 | // If the capability is actually only a promise, the returned promise resolves once the |
198 | // capability itself has resolved to its final destination (or propagates the exception if |
199 | // the capability promise is rejected). This is mainly useful for error-checking in the case |
200 | // where no calls are being made. There is no reason to wait for this before making calls; if |
201 | // the capability does not resolve, the call results will propagate the error. |
202 | |
203 | Request<AnyPointer, AnyPointer> typelessRequest( |
204 | uint64_t interfaceId, uint16_t methodId, |
205 | kj::Maybe<MessageSize> sizeHint); |
206 | // Make a request without knowing the types of the params or results. You specify the type ID |
207 | // and method number manually. |
208 | |
209 | // TODO(someday): method(s) for Join |
210 | |
211 | protected: |
212 | Client() = default; |
213 | |
214 | template <typename Params, typename Results> |
215 | Request<Params, Results> newCall(uint64_t interfaceId, uint16_t methodId, |
216 | kj::Maybe<MessageSize> sizeHint); |
217 | |
218 | private: |
219 | kj::Own<ClientHook> hook; |
220 | |
221 | static kj::Own<ClientHook> makeLocalClient(kj::Own<Capability::Server>&& server); |
222 | |
223 | template <typename, Kind> |
224 | friend struct _::PointerHelpers; |
225 | friend struct DynamicCapability; |
226 | friend class Orphanage; |
227 | friend struct DynamicStruct; |
228 | friend struct DynamicList; |
229 | template <typename, Kind> |
230 | friend struct List; |
231 | friend class _::CapabilityServerSetBase; |
232 | friend class ClientHook; |
233 | }; |
234 | |
235 | // ======================================================================================= |
236 | // Capability servers |
237 | |
238 | class CallContextHook; |
239 | |
240 | template <typename Params, typename Results> |
241 | class CallContext: public kj::DisallowConstCopy { |
242 | // Wrapper around CallContextHook with a specific return type. |
243 | // |
244 | // Methods of this class may only be called from within the server's event loop, not from other |
245 | // threads. |
246 | // |
247 | // The CallContext becomes invalid as soon as the call reports completion. |
248 | |
249 | public: |
250 | explicit CallContext(CallContextHook& hook); |
251 | |
252 | typename Params::Reader getParams(); |
253 | // Get the params payload. |
254 | |
255 | void releaseParams(); |
256 | // Release the params payload. getParams() will throw an exception after this is called. |
257 | // Releasing the params may allow the RPC system to free up buffer space to handle other |
258 | // requests. Long-running asynchronous methods should try to call this as early as is |
259 | // convenient. |
260 | |
261 | typename Results::Builder getResults(kj::Maybe<MessageSize> sizeHint = nullptr); |
262 | typename Results::Builder initResults(kj::Maybe<MessageSize> sizeHint = nullptr); |
263 | void setResults(typename Results::Reader value); |
264 | void adoptResults(Orphan<Results>&& value); |
265 | Orphanage getResultsOrphanage(kj::Maybe<MessageSize> sizeHint = nullptr); |
266 | // Manipulate the results payload. The "Return" message (part of the RPC protocol) will |
267 | // typically be allocated the first time one of these is called. Some RPC systems may |
268 | // allocate these messages in a limited space (such as a shared memory segment), therefore the |
269 | // application should delay calling these as long as is convenient to do so (but don't delay |
270 | // if doing so would require extra copies later). |
271 | // |
272 | // `sizeHint` indicates a guess at the message size. This will usually be used to decide how |
273 | // much space to allocate for the first message segment (don't worry: only space that is actually |
274 | // used will be sent on the wire). If omitted, the system decides. The message root pointer |
275 | // should not be included in the size. So, if you are simply going to copy some existing message |
276 | // directly into the results, just call `.totalSize()` and pass that in. |
277 | |
278 | template <typename SubParams> |
279 | kj::Promise<void> tailCall(Request<SubParams, Results>&& tailRequest); |
280 | // Resolve the call by making a tail call. `tailRequest` is a request that has been filled in |
281 | // but not yet sent. The context will send the call, then fill in the results with the result |
282 | // of the call. If tailCall() is used, {get,init,set,adopt}Results (above) *must not* be called. |
283 | // |
284 | // The RPC implementation may be able to optimize a tail call to another machine such that the |
285 | // results never actually pass through this machine. Even if no such optimization is possible, |
286 | // `tailCall()` may allow pipelined calls to be forwarded optimistically to the new call site. |
287 | // |
288 | // In general, this should be the last thing a method implementation calls, and the promise |
289 | // returned from `tailCall()` should then be returned by the method implementation. |
290 | |
291 | void allowCancellation(); |
292 | // Indicate that it is OK for the RPC system to discard its Promise for this call's result if |
293 | // the caller cancels the call, thereby transitively canceling any asynchronous operations the |
294 | // call implementation was performing. This is not done by default because it could represent a |
295 | // security risk: applications must be carefully written to ensure that they do not end up in |
296 | // a bad state if an operation is canceled at an arbitrary point. However, for long-running |
297 | // method calls that hold significant resources, prompt cancellation is often useful. |
298 | // |
299 | // Keep in mind that asynchronous cancellation cannot occur while the method is synchronously |
300 | // executing on a local thread. The method must perform an asynchronous operation or call |
301 | // `EventLoop::current().evalLater()` to yield control. |
302 | // |
303 | // Note: You might think that we should offer `onCancel()` and/or `isCanceled()` methods that |
304 | // provide notification when the caller cancels the request without forcefully killing off the |
305 | // promise chain. Unfortunately, this composes poorly with promise forking: the canceled |
306 | // path may be just one branch of a fork of the result promise. The other branches still want |
307 | // the call to continue. Promise forking is used within the Cap'n Proto implementation -- in |
308 | // particular each pipelined call forks the result promise. So, if a caller made a pipelined |
309 | // call and then dropped the original object, the call should not be canceled, but it would be |
310 | // excessively complicated for the framework to avoid notififying of cancellation as long as |
311 | // pipelined calls still exist. |
312 | |
313 | private: |
314 | CallContextHook* hook; |
315 | |
316 | friend class Capability::Server; |
317 | friend struct DynamicCapability; |
318 | }; |
319 | |
320 | class Capability::Server { |
321 | // Objects implementing a Cap'n Proto interface must subclass this. Typically, such objects |
322 | // will instead subclass a typed Server interface which will take care of implementing |
323 | // dispatchCall(). |
324 | |
325 | public: |
326 | typedef Capability Serves; |
327 | |
328 | virtual kj::Promise<void> dispatchCall(uint64_t interfaceId, uint16_t methodId, |
329 | CallContext<AnyPointer, AnyPointer> context) = 0; |
330 | // Call the given method. `params` is the input struct, and should be released as soon as it |
331 | // is no longer needed. `context` may be used to allocate the output struct and deal with |
332 | // cancellation. |
333 | |
334 | // TODO(someday): Method which can optionally be overridden to implement Join when the object is |
335 | // a proxy. |
336 | |
337 | protected: |
338 | inline Capability::Client thisCap(); |
339 | // Get a capability pointing to this object, much like the `this` keyword. |
340 | // |
341 | // The effect of this method is undefined if: |
342 | // - No capability client has been created pointing to this object. (This is always the case in |
343 | // the server's constructor.) |
344 | // - The capability client pointing at this object has been destroyed. (This is always the case |
345 | // in the server's destructor.) |
346 | // - Multiple capability clients have been created around the same server (possible if the server |
347 | // is refcounted, which is not recommended since the client itself provides refcounting). |
348 | |
349 | template <typename Params, typename Results> |
350 | CallContext<Params, Results> internalGetTypedContext( |
351 | CallContext<AnyPointer, AnyPointer> typeless); |
352 | kj::Promise<void> internalUnimplemented(const char* actualInterfaceName, |
353 | uint64_t requestedTypeId); |
354 | kj::Promise<void> internalUnimplemented(const char* interfaceName, |
355 | uint64_t typeId, uint16_t methodId); |
356 | kj::Promise<void> internalUnimplemented(const char* interfaceName, const char* methodName, |
357 | uint64_t typeId, uint16_t methodId); |
358 | |
359 | private: |
360 | ClientHook* thisHook = nullptr; |
361 | friend class LocalClient; |
362 | }; |
363 | |
364 | // ======================================================================================= |
365 | |
366 | class ReaderCapabilityTable: private _::CapTableReader { |
367 | // Class which imbues Readers with the ability to read capabilities. |
368 | // |
369 | // In Cap'n Proto format, the encoding of a capability pointer is simply an integer index into |
370 | // an external table. Since these pointers fundamentally point outside the message, a |
371 | // MessageReader by default has no idea what they point at, and therefore reading capabilities |
372 | // from such a reader will throw exceptions. |
373 | // |
374 | // In order to be able to read capabilities, you must first attach a capability table, using |
375 | // this class. By "imbuing" a Reader, you get a new Reader which will interpret capability |
376 | // pointers by treating them as indexes into the ReaderCapabilityTable. |
377 | // |
378 | // Note that when using Cap'n Proto's RPC system, this is handled automatically. |
379 | |
380 | public: |
381 | explicit ReaderCapabilityTable(kj::Array<kj::Maybe<kj::Own<ClientHook>>> table); |
382 | KJ_DISALLOW_COPY(ReaderCapabilityTable); |
383 | |
384 | template <typename T> |
385 | T imbue(T reader); |
386 | // Return a reader equivalent to `reader` except that when reading capability-valued fields, |
387 | // the capabilities are looked up in this table. |
388 | |
389 | private: |
390 | kj::Array<kj::Maybe<kj::Own<ClientHook>>> table; |
391 | |
392 | kj::Maybe<kj::Own<ClientHook>> (uint index) override; |
393 | }; |
394 | |
395 | class BuilderCapabilityTable: private _::CapTableBuilder { |
396 | // Class which imbues Builders with the ability to read and write capabilities. |
397 | // |
398 | // This is much like ReaderCapabilityTable, except for builders. The table starts out empty, |
399 | // but capabilities can be added to it over time. |
400 | |
401 | public: |
402 | BuilderCapabilityTable(); |
403 | KJ_DISALLOW_COPY(BuilderCapabilityTable); |
404 | |
405 | inline kj::ArrayPtr<kj::Maybe<kj::Own<ClientHook>>> getTable() { return table; } |
406 | |
407 | template <typename T> |
408 | T imbue(T builder); |
409 | // Return a builder equivalent to `builder` except that when reading capability-valued fields, |
410 | // the capabilities are looked up in this table. |
411 | |
412 | private: |
413 | kj::Vector<kj::Maybe<kj::Own<ClientHook>>> table; |
414 | |
415 | kj::Maybe<kj::Own<ClientHook>> (uint index) override; |
416 | uint injectCap(kj::Own<ClientHook>&& cap) override; |
417 | void dropCap(uint index) override; |
418 | }; |
419 | |
420 | // ======================================================================================= |
421 | |
422 | namespace _ { // private |
423 | |
424 | class CapabilityServerSetBase { |
425 | public: |
426 | Capability::Client addInternal(kj::Own<Capability::Server>&& server, void* ptr); |
427 | kj::Promise<void*> getLocalServerInternal(Capability::Client& client); |
428 | }; |
429 | |
430 | } // namespace _ (private) |
431 | |
432 | template <typename T> |
433 | class CapabilityServerSet: private _::CapabilityServerSetBase { |
434 | // Allows a server to recognize its own capabilities when passed back to it, and obtain the |
435 | // underlying Server objects associated with them. |
436 | // |
437 | // All objects in the set must have the same interface type T. The objects may implement various |
438 | // interfaces derived from T (and in fact T can be `capnp::Capability` to accept all objects), |
439 | // but note that if you compile with RTTI disabled then you will not be able to down-cast through |
440 | // virtual inheritance, and all inheritance between server interfaces is virtual. So, with RTTI |
441 | // disabled, you will likely need to set T to be the most-derived Cap'n Proto interface type, |
442 | // and you server class will need to be directly derived from that, so that you can use |
443 | // static_cast (or kj::downcast) to cast to it after calling getLocalServer(). (If you compile |
444 | // with RTTI, then you can freely dynamic_cast and ignore this issue!) |
445 | |
446 | public: |
447 | CapabilityServerSet() = default; |
448 | KJ_DISALLOW_COPY(CapabilityServerSet); |
449 | |
450 | typename T::Client add(kj::Own<typename T::Server>&& server); |
451 | // Create a new capability Client for the given Server and also add this server to the set. |
452 | |
453 | kj::Promise<kj::Maybe<typename T::Server&>> getLocalServer(typename T::Client& client); |
454 | // Given a Client pointing to a server previously passed to add(), return the corresponding |
455 | // Server. This returns a promise because if the input client is itself a promise, this must |
456 | // wait for it to resolve. Keep in mind that the server will be deleted when all clients are |
457 | // gone, so the caller should make sure to keep the client alive (hence why this method only |
458 | // accepts an lvalue input). |
459 | }; |
460 | |
461 | // ======================================================================================= |
462 | // Hook interfaces which must be implemented by the RPC system. Applications never call these |
463 | // directly; the RPC system implements them and the types defined earlier in this file wrap them. |
464 | |
465 | class RequestHook { |
466 | // Hook interface implemented by RPC system representing a request being built. |
467 | |
468 | public: |
469 | virtual RemotePromise<AnyPointer> send() = 0; |
470 | // Send the call and return a promise for the result. |
471 | |
472 | virtual const void* getBrand() = 0; |
473 | // Returns a void* that identifies who made this request. This can be used by an RPC adapter to |
474 | // discover when tail call is going to be sent over its own connection and therefore can be |
475 | // optimized into a remote tail call. |
476 | |
477 | template <typename T, typename U> |
478 | inline static kj::Own<RequestHook> from(Request<T, U>&& request) { |
479 | return kj::mv(request.hook); |
480 | } |
481 | }; |
482 | |
483 | class ResponseHook { |
484 | // Hook interface implemented by RPC system representing a response. |
485 | // |
486 | // At present this class has no methods. It exists only for garbage collection -- when the |
487 | // ResponseHook is destroyed, the results can be freed. |
488 | |
489 | public: |
490 | virtual ~ResponseHook() noexcept(false); |
491 | // Just here to make sure the type is dynamic. |
492 | |
493 | template <typename T> |
494 | inline static kj::Own<ResponseHook> from(Response<T>&& response) { |
495 | return kj::mv(response.hook); |
496 | } |
497 | }; |
498 | |
499 | // class PipelineHook is declared in any.h because it is needed there. |
500 | |
501 | class ClientHook { |
502 | public: |
503 | ClientHook(); |
504 | |
505 | virtual Request<AnyPointer, AnyPointer> newCall( |
506 | uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) = 0; |
507 | // Start a new call, allowing the client to allocate request/response objects as it sees fit. |
508 | // This version is used when calls are made from application code in the local process. |
509 | |
510 | struct VoidPromiseAndPipeline { |
511 | kj::Promise<void> promise; |
512 | kj::Own<PipelineHook> pipeline; |
513 | }; |
514 | |
515 | virtual VoidPromiseAndPipeline call(uint64_t interfaceId, uint16_t methodId, |
516 | kj::Own<CallContextHook>&& context) = 0; |
517 | // Call the object, but the caller controls allocation of the request/response objects. If the |
518 | // callee insists on allocating these objects itself, it must make a copy. This version is used |
519 | // when calls come in over the network via an RPC system. Note that even if the returned |
520 | // `Promise<void>` is discarded, the call may continue executing if any pipelined calls are |
521 | // waiting for it. |
522 | // |
523 | // Since the caller of this method chooses the CallContext implementation, it is the caller's |
524 | // responsibility to ensure that the returned promise is not canceled unless allowed via |
525 | // the context's `allowCancellation()`. |
526 | // |
527 | // The call must not begin synchronously; the callee must arrange for the call to begin in a |
528 | // later turn of the event loop. Otherwise, application code may call back and affect the |
529 | // callee's state in an unexpected way. |
530 | |
531 | virtual kj::Maybe<ClientHook&> getResolved() = 0; |
532 | // If this ClientHook is a promise that has already resolved, returns the inner, resolved version |
533 | // of the capability. The caller may permanently replace this client with the resolved one if |
534 | // desired. Returns null if the client isn't a promise or hasn't resolved yet -- use |
535 | // `whenMoreResolved()` to distinguish between them. |
536 | |
537 | virtual kj::Maybe<kj::Promise<kj::Own<ClientHook>>> whenMoreResolved() = 0; |
538 | // If this client is a settled reference (not a promise), return nullptr. Otherwise, return a |
539 | // promise that eventually resolves to a new client that is closer to being the final, settled |
540 | // client (i.e. the value eventually returned by `getResolved()`). Calling this repeatedly |
541 | // should eventually produce a settled client. |
542 | |
543 | kj::Promise<void> whenResolved(); |
544 | // Repeatedly calls whenMoreResolved() until it returns nullptr. |
545 | |
546 | virtual kj::Own<ClientHook> addRef() = 0; |
547 | // Return a new reference to the same capability. |
548 | |
549 | virtual const void* getBrand() = 0; |
550 | // Returns a void* that identifies who made this client. This can be used by an RPC adapter to |
551 | // discover when a capability it needs to marshal is one that it created in the first place, and |
552 | // therefore it can transfer the capability without proxying. |
553 | |
554 | static const uint NULL_CAPABILITY_BRAND; |
555 | // Value is irrelevant; used for pointer. |
556 | |
557 | inline bool isNull() { return getBrand() == &NULL_CAPABILITY_BRAND; } |
558 | // Returns true if the capability was created as a result of assigning a Client to null or by |
559 | // reading a null pointer out of a Cap'n Proto message. |
560 | |
561 | virtual void* getLocalServer(_::CapabilityServerSetBase& capServerSet); |
562 | // If this is a local capability created through `capServerSet`, return the underlying Server. |
563 | // Otherwise, return nullptr. Default implementation (which everyone except LocalClient should |
564 | // use) always returns nullptr. |
565 | |
566 | static kj::Own<ClientHook> from(Capability::Client client) { return kj::mv(client.hook); } |
567 | }; |
568 | |
569 | class CallContextHook { |
570 | // Hook interface implemented by RPC system to manage a call on the server side. See |
571 | // CallContext<T>. |
572 | |
573 | public: |
574 | virtual AnyPointer::Reader getParams() = 0; |
575 | virtual void releaseParams() = 0; |
576 | virtual AnyPointer::Builder getResults(kj::Maybe<MessageSize> sizeHint) = 0; |
577 | virtual kj::Promise<void> tailCall(kj::Own<RequestHook>&& request) = 0; |
578 | virtual void allowCancellation() = 0; |
579 | |
580 | virtual kj::Promise<AnyPointer::Pipeline> onTailCall() = 0; |
581 | // If `tailCall()` is called, resolves to the PipelineHook from the tail call. An |
582 | // implementation of `ClientHook::call()` is allowed to call this at most once. |
583 | |
584 | virtual ClientHook::VoidPromiseAndPipeline directTailCall(kj::Own<RequestHook>&& request) = 0; |
585 | // Call this when you would otherwise call onTailCall() immediately followed by tailCall(). |
586 | // Implementations of tailCall() should typically call directTailCall() and then fulfill the |
587 | // promise fulfiller for onTailCall() with the returned pipeline. |
588 | |
589 | virtual kj::Own<CallContextHook> addRef() = 0; |
590 | }; |
591 | |
592 | kj::Own<ClientHook> newLocalPromiseClient(kj::Promise<kj::Own<ClientHook>>&& promise); |
593 | // Returns a ClientHook that queues up calls until `promise` resolves, then forwards them to |
594 | // the new client. This hook's `getResolved()` and `whenMoreResolved()` methods will reflect the |
595 | // redirection to the eventual replacement client. |
596 | |
597 | kj::Own<PipelineHook> newLocalPromisePipeline(kj::Promise<kj::Own<PipelineHook>>&& promise); |
598 | // Returns a PipelineHook that queues up calls until `promise` resolves, then forwards them to |
599 | // the new pipeline. |
600 | |
601 | kj::Own<ClientHook> newBrokenCap(kj::StringPtr reason); |
602 | kj::Own<ClientHook> newBrokenCap(kj::Exception&& reason); |
603 | // Helper function that creates a capability which simply throws exceptions when called. |
604 | |
605 | kj::Own<PipelineHook> newBrokenPipeline(kj::Exception&& reason); |
606 | // Helper function that creates a pipeline which simply throws exceptions when called. |
607 | |
608 | Request<AnyPointer, AnyPointer> newBrokenRequest( |
609 | kj::Exception&& reason, kj::Maybe<MessageSize> sizeHint); |
610 | // Helper function that creates a Request object that simply throws exceptions when sent. |
611 | |
612 | // ======================================================================================= |
613 | // Extend PointerHelpers for interfaces |
614 | |
615 | namespace _ { // private |
616 | |
617 | template <typename T> |
618 | struct PointerHelpers<T, Kind::INTERFACE> { |
619 | static inline typename T::Client get(PointerReader reader) { |
620 | return typename T::Client(reader.getCapability()); |
621 | } |
622 | static inline typename T::Client get(PointerBuilder builder) { |
623 | return typename T::Client(builder.getCapability()); |
624 | } |
625 | static inline void set(PointerBuilder builder, typename T::Client&& value) { |
626 | builder.setCapability(kj::mv(value.Capability::Client::hook)); |
627 | } |
628 | static inline void set(PointerBuilder builder, typename T::Client& value) { |
629 | builder.setCapability(value.Capability::Client::hook->addRef()); |
630 | } |
631 | static inline void adopt(PointerBuilder builder, Orphan<T>&& value) { |
632 | builder.adopt(kj::mv(value.builder)); |
633 | } |
634 | static inline Orphan<T> disown(PointerBuilder builder) { |
635 | return Orphan<T>(builder.disown()); |
636 | } |
637 | }; |
638 | |
639 | } // namespace _ (private) |
640 | |
641 | // ======================================================================================= |
642 | // Extend List for interfaces |
643 | |
644 | template <typename T> |
645 | struct List<T, Kind::INTERFACE> { |
646 | List() = delete; |
647 | |
648 | class Reader { |
649 | public: |
650 | typedef List<T> Reads; |
651 | |
652 | Reader() = default; |
653 | inline explicit Reader(_::ListReader reader): reader(reader) {} |
654 | |
655 | inline uint size() const { return unbound(reader.size() / ELEMENTS); } |
656 | inline typename T::Client operator[](uint index) const { |
657 | KJ_IREQUIRE(index < size()); |
658 | return typename T::Client(reader.getPointerElement( |
659 | bounded(index) * ELEMENTS).getCapability()); |
660 | } |
661 | |
662 | typedef _::IndexingIterator<const Reader, typename T::Client> Iterator; |
663 | inline Iterator begin() const { return Iterator(this, 0); } |
664 | inline Iterator end() const { return Iterator(this, size()); } |
665 | |
666 | inline MessageSize totalSize() const { |
667 | return reader.totalSize().asPublic(); |
668 | } |
669 | |
670 | private: |
671 | _::ListReader reader; |
672 | template <typename U, Kind K> |
673 | friend struct _::PointerHelpers; |
674 | template <typename U, Kind K> |
675 | friend struct List; |
676 | friend class Orphanage; |
677 | template <typename U, Kind K> |
678 | friend struct ToDynamic_; |
679 | }; |
680 | |
681 | class Builder { |
682 | public: |
683 | typedef List<T> Builds; |
684 | |
685 | Builder() = delete; |
686 | inline Builder(decltype(nullptr)) {} |
687 | inline explicit Builder(_::ListBuilder builder): builder(builder) {} |
688 | |
689 | inline operator Reader() const { return Reader(builder.asReader()); } |
690 | inline Reader asReader() const { return Reader(builder.asReader()); } |
691 | |
692 | inline uint size() const { return unbound(builder.size() / ELEMENTS); } |
693 | inline typename T::Client operator[](uint index) { |
694 | KJ_IREQUIRE(index < size()); |
695 | return typename T::Client(builder.getPointerElement( |
696 | bounded(index) * ELEMENTS).getCapability()); |
697 | } |
698 | inline void set(uint index, typename T::Client value) { |
699 | KJ_IREQUIRE(index < size()); |
700 | builder.getPointerElement(bounded(index) * ELEMENTS).setCapability(kj::mv(value.hook)); |
701 | } |
702 | inline void adopt(uint index, Orphan<T>&& value) { |
703 | KJ_IREQUIRE(index < size()); |
704 | builder.getPointerElement(bounded(index) * ELEMENTS).adopt(kj::mv(value)); |
705 | } |
706 | inline Orphan<T> disown(uint index) { |
707 | KJ_IREQUIRE(index < size()); |
708 | return Orphan<T>(builder.getPointerElement(bounded(index) * ELEMENTS).disown()); |
709 | } |
710 | |
711 | typedef _::IndexingIterator<Builder, typename T::Client> Iterator; |
712 | inline Iterator begin() { return Iterator(this, 0); } |
713 | inline Iterator end() { return Iterator(this, size()); } |
714 | |
715 | private: |
716 | _::ListBuilder builder; |
717 | friend class Orphanage; |
718 | template <typename U, Kind K> |
719 | friend struct ToDynamic_; |
720 | }; |
721 | |
722 | private: |
723 | inline static _::ListBuilder initPointer(_::PointerBuilder builder, uint size) { |
724 | return builder.initList(ElementSize::POINTER, bounded(size) * ELEMENTS); |
725 | } |
726 | inline static _::ListBuilder getFromPointer(_::PointerBuilder builder, const word* defaultValue) { |
727 | return builder.getList(ElementSize::POINTER, defaultValue); |
728 | } |
729 | inline static _::ListReader getFromPointer( |
730 | const _::PointerReader& reader, const word* defaultValue) { |
731 | return reader.getList(ElementSize::POINTER, defaultValue); |
732 | } |
733 | |
734 | template <typename U, Kind k> |
735 | friend struct List; |
736 | template <typename U, Kind K> |
737 | friend struct _::PointerHelpers; |
738 | }; |
739 | |
740 | // ======================================================================================= |
741 | // Inline implementation details |
742 | |
743 | template <typename T> |
744 | RemotePromise<T> RemotePromise<T>::reducePromise(kj::Promise<RemotePromise>&& promise) { |
745 | kj::Tuple<kj::Promise<Response<T>>, kj::Promise<kj::Own<PipelineHook>>> splitPromise = |
746 | promise.then([](RemotePromise&& inner) { |
747 | // `inner` is multiply-inherited, and we want to move away each superclass separately. |
748 | // Let's create two references to make clear what we're doing (though this is not strictly |
749 | // necessary). |
750 | kj::Promise<Response<T>>& innerPromise = inner; |
751 | typename T::Pipeline& innerPipeline = inner; |
752 | return kj::tuple(kj::mv(innerPromise), PipelineHook::from(kj::mv(innerPipeline))); |
753 | }).split(); |
754 | |
755 | return RemotePromise(kj::mv(kj::get<0>(splitPromise)), |
756 | typename T::Pipeline(AnyPointer::Pipeline( |
757 | newLocalPromisePipeline(kj::mv(kj::get<1>(splitPromise)))))); |
758 | } |
759 | |
760 | template <typename Params, typename Results> |
761 | RemotePromise<Results> Request<Params, Results>::send() { |
762 | auto typelessPromise = hook->send(); |
763 | hook = nullptr; // prevent reuse |
764 | |
765 | // Convert the Promise to return the correct response type. |
766 | // Explicitly upcast to kj::Promise to make clear that calling .then() doesn't invalidate the |
767 | // Pipeline part of the RemotePromise. |
768 | auto typedPromise = kj::implicitCast<kj::Promise<Response<AnyPointer>>&>(typelessPromise) |
769 | .then([](Response<AnyPointer>&& response) -> Response<Results> { |
770 | return Response<Results>(response.getAs<Results>(), kj::mv(response.hook)); |
771 | }); |
772 | |
773 | // Wrap the typeless pipeline in a typed wrapper. |
774 | typename Results::Pipeline typedPipeline( |
775 | kj::mv(kj::implicitCast<AnyPointer::Pipeline&>(typelessPromise))); |
776 | |
777 | return RemotePromise<Results>(kj::mv(typedPromise), kj::mv(typedPipeline)); |
778 | } |
779 | |
780 | inline Capability::Client::Client(kj::Own<ClientHook>&& hook): hook(kj::mv(hook)) {} |
781 | template <typename T, typename> |
782 | inline Capability::Client::Client(kj::Own<T>&& server) |
783 | : hook(makeLocalClient(kj::mv(server))) {} |
784 | template <typename T, typename> |
785 | inline Capability::Client::Client(kj::Promise<T>&& promise) |
786 | : hook(newLocalPromiseClient(promise.then([](T&& t) { return kj::mv(t.hook); }))) {} |
787 | inline Capability::Client::Client(Client& other): hook(other.hook->addRef()) {} |
788 | inline Capability::Client& Capability::Client::operator=(Client& other) { |
789 | hook = other.hook->addRef(); |
790 | return *this; |
791 | } |
792 | template <typename T> |
793 | inline typename T::Client Capability::Client::castAs() { |
794 | return typename T::Client(hook->addRef()); |
795 | } |
796 | inline kj::Promise<void> Capability::Client::whenResolved() { |
797 | return hook->whenResolved(); |
798 | } |
799 | inline Request<AnyPointer, AnyPointer> Capability::Client::typelessRequest( |
800 | uint64_t interfaceId, uint16_t methodId, |
801 | kj::Maybe<MessageSize> sizeHint) { |
802 | return newCall<AnyPointer, AnyPointer>(interfaceId, methodId, sizeHint); |
803 | } |
804 | template <typename Params, typename Results> |
805 | inline Request<Params, Results> Capability::Client::newCall( |
806 | uint64_t interfaceId, uint16_t methodId, kj::Maybe<MessageSize> sizeHint) { |
807 | auto typeless = hook->newCall(interfaceId, methodId, sizeHint); |
808 | return Request<Params, Results>(typeless.template getAs<Params>(), kj::mv(typeless.hook)); |
809 | } |
810 | |
811 | template <typename Params, typename Results> |
812 | inline CallContext<Params, Results>::CallContext(CallContextHook& hook): hook(&hook) {} |
813 | template <typename Params, typename Results> |
814 | inline typename Params::Reader CallContext<Params, Results>::getParams() { |
815 | return hook->getParams().template getAs<Params>(); |
816 | } |
817 | template <typename Params, typename Results> |
818 | inline void CallContext<Params, Results>::releaseParams() { |
819 | hook->releaseParams(); |
820 | } |
821 | template <typename Params, typename Results> |
822 | inline typename Results::Builder CallContext<Params, Results>::getResults( |
823 | kj::Maybe<MessageSize> sizeHint) { |
824 | // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 |
825 | return hook->getResults(sizeHint).template getAs<Results>(); |
826 | } |
827 | template <typename Params, typename Results> |
828 | inline typename Results::Builder CallContext<Params, Results>::initResults( |
829 | kj::Maybe<MessageSize> sizeHint) { |
830 | // `template` keyword needed due to: http://llvm.org/bugs/show_bug.cgi?id=17401 |
831 | return hook->getResults(sizeHint).template initAs<Results>(); |
832 | } |
833 | template <typename Params, typename Results> |
834 | inline void CallContext<Params, Results>::setResults(typename Results::Reader value) { |
835 | hook->getResults(value.totalSize()).template setAs<Results>(value); |
836 | } |
837 | template <typename Params, typename Results> |
838 | inline void CallContext<Params, Results>::adoptResults(Orphan<Results>&& value) { |
839 | hook->getResults(nullptr).adopt(kj::mv(value)); |
840 | } |
841 | template <typename Params, typename Results> |
842 | inline Orphanage CallContext<Params, Results>::getResultsOrphanage( |
843 | kj::Maybe<MessageSize> sizeHint) { |
844 | return Orphanage::getForMessageContaining(hook->getResults(sizeHint)); |
845 | } |
846 | template <typename Params, typename Results> |
847 | template <typename SubParams> |
848 | inline kj::Promise<void> CallContext<Params, Results>::tailCall( |
849 | Request<SubParams, Results>&& tailRequest) { |
850 | return hook->tailCall(kj::mv(tailRequest.hook)); |
851 | } |
852 | template <typename Params, typename Results> |
853 | inline void CallContext<Params, Results>::allowCancellation() { |
854 | hook->allowCancellation(); |
855 | } |
856 | |
857 | template <typename Params, typename Results> |
858 | CallContext<Params, Results> Capability::Server::internalGetTypedContext( |
859 | CallContext<AnyPointer, AnyPointer> typeless) { |
860 | return CallContext<Params, Results>(*typeless.hook); |
861 | } |
862 | |
863 | Capability::Client Capability::Server::thisCap() { |
864 | return Client(thisHook->addRef()); |
865 | } |
866 | |
867 | template <typename T> |
868 | T ReaderCapabilityTable::imbue(T reader) { |
869 | return T(_::PointerHelpers<FromReader<T>>::getInternalReader(reader).imbue(this)); |
870 | } |
871 | |
872 | template <typename T> |
873 | T BuilderCapabilityTable::imbue(T builder) { |
874 | return T(_::PointerHelpers<FromBuilder<T>>::getInternalBuilder(kj::mv(builder)).imbue(this)); |
875 | } |
876 | |
877 | template <typename T> |
878 | typename T::Client CapabilityServerSet<T>::add(kj::Own<typename T::Server>&& server) { |
879 | void* ptr = reinterpret_cast<void*>(server.get()); |
880 | // Clang insists that `castAs` is a template-dependent member and therefore we need the |
881 | // `template` keyword here, but AFAICT this is wrong: addImpl() is not a template. |
882 | return addInternal(kj::mv(server), ptr).template castAs<T>(); |
883 | } |
884 | |
885 | template <typename T> |
886 | kj::Promise<kj::Maybe<typename T::Server&>> CapabilityServerSet<T>::getLocalServer( |
887 | typename T::Client& client) { |
888 | return getLocalServerInternal(client) |
889 | .then([](void* server) -> kj::Maybe<typename T::Server&> { |
890 | if (server == nullptr) { |
891 | return nullptr; |
892 | } else { |
893 | return *reinterpret_cast<typename T::Server*>(server); |
894 | } |
895 | }); |
896 | } |
897 | |
898 | template <typename T> |
899 | struct Orphanage::GetInnerReader<T, Kind::INTERFACE> { |
900 | static inline kj::Own<ClientHook> apply(typename T::Client t) { |
901 | return ClientHook::from(kj::mv(t)); |
902 | } |
903 | }; |
904 | |
905 | #define CAPNP_CAPABILITY_H_INCLUDED // for testing includes in unit test |
906 | |
907 | } // namespace capnp |
908 | |