Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_rpc / docs.rst
1 .. _module-pw_rpc:
2
3 ------
4 pw_rpc
5 ------
6 The ``pw_rpc`` module provides a system for defining and invoking remote
7 procedure calls (RPCs) on a device.
8
9 .. admonition:: Try it out!
10
11   For a quick intro to ``pw_rpc``, see the
12   :ref:`module-pw_hdlc-rpc-example` in the :ref:`module-pw_hdlc` module.
13
14 .. attention::
15
16   This documentation is under construction.
17
18 Creating an RPC
19 ===============
20
21 1. RPC service declaration
22 --------------------------
23 Pigweed RPCs are declared in a protocol buffer service definition.
24
25 * `Protocol Buffer service documentation
26   <https://developers.google.com/protocol-buffers/docs/proto3#services>`_
27 * `gRPC service definition documentation
28   <https://grpc.io/docs/what-is-grpc/core-concepts/#service-definition>`_
29
30 .. code-block:: protobuf
31
32   syntax = "proto3";
33
34   package foo.bar;
35
36   message Request {}
37
38   message Response {
39     int32 number = 1;
40   }
41
42   service TheService {
43     rpc MethodOne(Request) returns (Response) {}
44     rpc MethodTwo(Request) returns (stream Response) {}
45   }
46
47 This protocol buffer is declared in a ``BUILD.gn`` file as follows:
48
49 .. code-block:: python
50
51   import("//build_overrides/pigweed.gni")
52   import("$dir_pw_protobuf_compiler/proto.gni")
53
54   pw_proto_library("the_service_proto") {
55     sources = [ "foo_bar/the_service.proto" ]
56   }
57
58 2. RPC code generation
59 ----------------------
60 ``pw_rpc`` generates a C++ header file for each ``.proto`` file. This header is
61 generated in the build output directory. Its exact location varies by build
62 system and toolchain, but the C++ include path always matches the sources
63 declaration in the ``pw_proto_library``. The ``.proto`` extension is replaced
64 with an extension corresponding to the protobuf library in use.
65
66 ================== =============== =============== =============
67 Protobuf libraries Build subtarget Protobuf header pw_rpc header
68 ================== =============== =============== =============
69 Raw only           .raw_rpc        (none)          .raw_rpc.pb.h
70 Nanopb or raw      .nanopb_rpc     .pb.h           .rpc.pb.h
71 pw_protobuf or raw .pwpb_rpc       .pwpb.h         .rpc.pwpb.h
72 ================== =============== =============== =============
73
74 For example, the generated RPC header for ``"foo_bar/the_service.proto"`` is
75 ``"foo_bar/the_service.rpc.pb.h"`` for Nanopb or
76 ``"foo_bar/the_service.raw_rpc.pb.h"`` for raw RPCs.
77
78 The generated header defines a base class for each RPC service declared in the
79 ``.proto`` file. A service named ``TheService`` in package ``foo.bar`` would
80 generate the following base class:
81
82 .. cpp:class:: template <typename Implementation> foo::bar::generated::TheService
83
84 3. RPC service definition
85 -------------------------
86 The serivce class is implemented by inheriting from the generated RPC service
87 base class and defining a method for each RPC. The methods must match the name
88 and function signature for one of the supported protobuf implementations.
89 Services may mix and match protobuf implementations within one service.
90
91 .. tip::
92
93   The generated code includes RPC service implementation stubs. You can
94   reference or copy and paste these to get started with implementing a service.
95   These stub classes are generated at the bottom of the pw_rpc proto header.
96
97 A Nanopb implementation of this service would be as follows:
98
99 .. code-block:: cpp
100
101   #include "foo_bar/the_service.rpc.pb.h"
102
103   namespace foo::bar {
104
105   class TheService : public generated::TheService<TheService> {
106    public:
107     pw::Status MethodOne(ServerContext& ctx,
108                          const foo_bar_Request& request,
109                          foo_bar_Response& response) {
110       // implementation
111       return pw::OkStatus();
112     }
113
114     void MethodTwo(ServerContext& ctx,
115                    const foo_bar_Request& request,
116                    ServerWriter<foo_bar_Response>& response) {
117       // implementation
118       response.Write(foo_bar_Response{.number = 123});
119     }
120   };
121
122   }  // namespace foo::bar
123
124 The Nanopb implementation would be declared in a ``BUILD.gn``:
125
126 .. code-block:: python
127
128   import("//build_overrides/pigweed.gni")
129
130   import("$dir_pw_build/target_types.gni")
131
132   pw_source_set("the_service") {
133     public_configs = [ ":public" ]
134     public = [ "public/foo_bar/service.h" ]
135     public_deps = [ ":the_service_proto.nanopb_rpc" ]
136   }
137
138 .. attention::
139
140   pw_rpc's generated classes will support using ``pw_protobuf`` or raw buffers
141   (no protobuf library) in the future.
142
143 4. Register the service with a server
144 -------------------------------------
145 This example code sets up an RPC server with an :ref:`HDLC<module-pw_hdlc>`
146 channel output and the example service.
147
148 .. code-block:: cpp
149
150   // Set up the output channel for the pw_rpc server to use. This configures the
151   // pw_rpc server to use HDLC over UART; projects not using UART and HDLC must
152   // adapt this as necessary.
153   pw::stream::SysIoWriter writer;
154   pw::rpc::RpcChannelOutput<kMaxTransmissionUnit> hdlc_channel_output(
155       writer, pw::hdlc::kDefaultRpcAddress, "HDLC output");
156
157   pw::rpc::Channel channels[] = {
158       pw::rpc::Channel::Create<1>(&hdlc_channel_output)};
159
160   // Declare the pw_rpc server with the HDLC channel.
161   pw::rpc::Server server(channels);
162
163   pw::rpc::TheService the_service;
164
165   void RegisterServices() {
166     // Register the foo.bar.TheService example service.
167     server.Register(the_service);
168
169     // Register other services
170   }
171
172   int main() {
173     // Set up the server.
174     RegisterServices();
175
176     // Declare a buffer for decoding incoming HDLC frames.
177     std::array<std::byte, kMaxTransmissionUnit> input_buffer;
178
179     PW_LOG_INFO("Starting pw_rpc server");
180     pw::hdlc::ReadAndProcessPackets(
181         server, hdlc_channel_output, input_buffer);
182   }
183
184 Services
185 ========
186 A service is a logical grouping of RPCs defined within a .proto file. ``pw_rpc``
187 uses these .proto definitions to generate code for a base service, from which
188 user-defined RPCs are implemented.
189
190 ``pw_rpc`` supports multiple protobuf libraries, and the generated code API
191 depends on which is used.
192
193 .. _module-pw_rpc-protobuf-library-apis:
194
195 Protobuf library APIs
196 =====================
197
198 .. toctree::
199   :maxdepth: 1
200
201   nanopb/docs
202
203 Testing a pw_rpc integration
204 ============================
205 After setting up a ``pw_rpc`` server in your project, you can test that it is
206 working as intended by registering the provided ``EchoService``, defined in
207 ``pw_rpc_protos/echo.proto``, which echoes back a message that it receives.
208
209 .. literalinclude:: pw_rpc_protos/echo.proto
210   :language: protobuf
211   :lines: 14-
212
213 For example, in C++ with nanopb:
214
215 .. code:: c++
216
217   #include "pw_rpc/server.h"
218
219   // Include the apporpriate header for your protobuf library.
220   #include "pw_rpc/echo_service_nanopb.h"
221
222   constexpr pw::rpc::Channel kChannels[] = { /* ... */ };
223   static pw::rpc::Server server(kChannels);
224
225   static pw::rpc::EchoService echo_service;
226
227   void Init() {
228     server.RegisterService(&echo_service);
229   }
230
231 Protocol description
232 ====================
233 Pigweed RPC servers and clients communicate using ``pw_rpc`` packets. These
234 packets are used to send requests and responses, control streams, cancel ongoing
235 RPCs, and report errors.
236
237 Packet format
238 -------------
239 Pigweed RPC packets consist of a type and a set of fields. The packets are
240 encoded as protocol buffers. The full packet format is described in
241 ``pw_rpc/pw_rpc_protos/internal/packet.proto``.
242
243 .. literalinclude:: pw_rpc_protos/internal/packet.proto
244   :language: protobuf
245   :lines: 14-
246
247 The packet type and RPC type determine which fields are present in a Pigweed RPC
248 packet. Each packet type is only sent by either the client or the server.
249 These tables describe the meaning of and fields included with each packet type.
250
251 Client-to-server packets
252 ^^^^^^^^^^^^^^^^^^^^^^^^
253 +---------------------------+----------------------------------+
254 | packet type               | description                      |
255 +===========================+==================================+
256 | REQUEST                   | RPC request                      |
257 |                           |                                  |
258 |                           | .. code-block:: text             |
259 |                           |                                  |
260 |                           |   - channel_id                   |
261 |                           |   - service_id                   |
262 |                           |   - method_id                    |
263 |                           |   - payload                      |
264 |                           |     (unless first client stream) |
265 |                           |                                  |
266 +---------------------------+----------------------------------+
267 | CLIENT_STREAM_END         | Client stream finished           |
268 |                           |                                  |
269 |                           | .. code-block:: text             |
270 |                           |                                  |
271 |                           |   - channel_id                   |
272 |                           |   - service_id                   |
273 |                           |   - method_id                    |
274 |                           |                                  |
275 |                           |                                  |
276 +---------------------------+----------------------------------+
277 | CLIENT_ERROR              | Received unexpected packet       |
278 |                           |                                  |
279 |                           | .. code-block:: text             |
280 |                           |                                  |
281 |                           |   - channel_id                   |
282 |                           |   - service_id                   |
283 |                           |   - method_id                    |
284 |                           |   - status                       |
285 +---------------------------+----------------------------------+
286 | CANCEL_SERVER_STREAM      | Cancel a server stream           |
287 |                           |                                  |
288 |                           | .. code-block:: text             |
289 |                           |                                  |
290 |                           |   - channel_id                   |
291 |                           |   - service_id                   |
292 |                           |   - method_id                    |
293 |                           |                                  |
294 +---------------------------+----------------------------------+
295
296 **Errors**
297
298 The client sends ``CLIENT_ERROR`` packets to a server when it receives a packet
299 it did not request. If the RPC is a streaming RPC, the server should abort it.
300
301 The status code indicates the type of error. If the client does not distinguish
302 between the error types, it can send whichever status is most relevant. The
303 status code is logged, but all status codes result in the same action by the
304 server: aborting the RPC.
305
306 * ``NOT_FOUND`` -- Received a packet for a service method the client does not
307   recognize.
308 * ``FAILED_PRECONDITION`` -- Received a packet for a service method that the
309   client did not invoke.
310
311 Server-to-client packets
312 ^^^^^^^^^^^^^^^^^^^^^^^^
313 +-------------------+--------------------------------+
314 | packet type       | description                    |
315 +===================+================================+
316 | RESPONSE          | RPC response                   |
317 |                   |                                |
318 |                   | .. code-block:: text           |
319 |                   |                                |
320 |                   |   - channel_id                 |
321 |                   |   - service_id                 |
322 |                   |   - method_id                  |
323 |                   |   - payload                    |
324 |                   |   - status                     |
325 |                   |     (unless in server stream)  |
326 +-------------------+--------------------------------+
327 | SERVER_STREAM_END | Server stream and RPC finished |
328 |                   |                                |
329 |                   | .. code-block:: text           |
330 |                   |                                |
331 |                   |   - channel_id                 |
332 |                   |   - service_id                 |
333 |                   |   - method_id                  |
334 |                   |   - status                     |
335 +-------------------+--------------------------------+
336 | SERVER_ERROR      | Received unexpected packet     |
337 |                   |                                |
338 |                   | .. code-block:: text           |
339 |                   |                                |
340 |                   |   - channel_id                 |
341 |                   |   - service_id (if relevant)   |
342 |                   |   - method_id (if relevant)    |
343 |                   |   - status                     |
344 +-------------------+--------------------------------+
345
346 **Errors**
347
348 The server sends ``SERVER_ERROR`` packets when it receives a packet it cannot
349 process. The client should abort any RPC for which it receives an error. The
350 status field indicates the type of error.
351
352 * ``NOT_FOUND`` -- The requested service or method does not exist.
353 * ``FAILED_PRECONDITION`` -- Attempted to cancel an RPC that is not pending.
354 * ``RESOURCE_EXHAUSTED`` -- The request came on a new channel, but a channel
355   could not be allocated for it.
356 * ``INTERNAL`` -- The server was unable to respond to an RPC due to an
357   unrecoverable internal error.
358
359 Inovking a service method
360 -------------------------
361 Calling an RPC requires a specific sequence of packets. This section describes
362 the protocol for calling service methods of each type: unary, server streaming,
363 client streaming, and bidirectional streaming.
364
365 Unary RPC
366 ^^^^^^^^^
367 In a unary RPC, the client sends a single request and the server sends a single
368 response.
369
370 .. seqdiag::
371   :scale: 110
372
373   seqdiag {
374     default_note_color = aliceblue;
375
376     client -> server [
377         label = "request",
378         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID\npayload"
379     ];
380
381     client <- server [
382         label = "response",
383         rightnote = "PacketType.RESPONSE\nchannel ID\nservice ID\nmethod ID\npayload\nstatus"
384     ];
385   }
386
387 Server streaming RPC
388 ^^^^^^^^^^^^^^^^^^^^
389 In a server streaming RPC, the client sends a single request and the server
390 sends any number of responses followed by a ``SERVER_STREAM_END`` packet.
391
392 .. seqdiag::
393   :scale: 110
394
395   seqdiag {
396     default_note_color = aliceblue;
397
398     client -> server [
399         label = "request",
400         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID\npayload"
401     ];
402
403     client <-- server [
404         noactivate,
405         label = "responses (zero or more)",
406         rightnote = "PacketType.RESPONSE\nchannel ID\nservice ID\nmethod ID\npayload"
407     ];
408
409     client <- server [
410         label = "done",
411         rightnote = "PacketType.SERVER_STREAM_END\nchannel ID\nservice ID\nmethod ID\nstatus"
412     ];
413   }
414
415 Server streaming RPCs may be cancelled by the client. The client sends a
416 ``CANCEL_SERVER_STREAM`` packet to terminate the RPC.
417
418 .. seqdiag::
419   :scale: 110
420
421   seqdiag {
422     default_note_color = aliceblue;
423
424     client -> server [
425         label = "request",
426         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID\npayload"
427     ];
428
429     client <-- server [
430         noactivate,
431         label = "responses (zero or more)",
432         rightnote = "PacketType.RESPONSE\nchannel ID\nservice ID\nmethod ID\npayload"
433     ];
434
435     client -> server [
436         noactivate,
437         label = "cancel",
438         leftnote  = "PacketType.CANCEL_SERVER_STREAM\nchannel ID\nservice ID\nmethod ID"
439     ];
440
441     client <- server [
442         label = "done",
443         rightnote = "PacketType.SERVER_STREAM_END\nchannel ID\nservice ID\nmethod ID\nstatus"
444     ];
445   }
446
447 Client streaming RPC
448 ^^^^^^^^^^^^^^^^^^^^
449 In a client streaming RPC, the client sends any number of RPC requests followed
450 by a ``CLIENT_STREAM_END`` packet. The server then sends a single response.
451
452 The first client-to-server RPC packet does not include a payload.
453
454 .. attention::
455
456   ``pw_rpc`` does not yet support client streaming RPCs.
457
458 .. seqdiag::
459   :scale: 110
460
461   seqdiag {
462     default_note_color = aliceblue;
463
464     client -> server [
465         label = "start",
466         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID"
467     ];
468
469     client --> server [
470         noactivate,
471         label = "requests (zero or more)",
472         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID\npayload"
473     ];
474
475     client -> server [
476         noactivate,
477         label = "done",
478         leftnote = "PacketType.CLIENT_STREAM_END\nchannel ID\nservice ID\nmethod ID"
479     ];
480
481     client <- server [
482         label = "response",
483         rightnote = "PacketType.RESPONSE\nchannel ID\nservice ID\nmethod ID\npayload\nstatus"
484     ];
485   }
486
487 The server may terminate a client streaming RPC at any time by sending its
488 response packet.
489
490 .. seqdiag::
491   :scale: 110
492
493   seqdiag {
494     default_note_color = aliceblue;
495
496     client -> server [
497         label = "start",
498         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID"
499     ];
500
501     client --> server [
502         noactivate,
503         label = "requests (zero or more)",
504         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID\npayload"
505     ];
506
507     client <- server [
508         label = "response",
509         rightnote = "PacketType.RESPONSE\nchannel ID\nservice ID\nmethod ID\npayload\nstatus"
510     ];
511   }
512
513 Bidirectional streaming RPC
514 ^^^^^^^^^^^^^^^^^^^^^^^^^^^
515 In a bidirectional streaming RPC, the client sends any number of requests and
516 the server sends any number of responses. The client sends a
517 ``CLIENT_STREAM_END`` packet when it has finished sending requests. The server
518 sends a ``SERVER_STREAM_END`` packet after it receives the client's
519 ``CLIENT_STREAM_END`` and finished sending its responses.
520
521 The first client-to-server RPC packet does not include a payload.
522
523 .. attention::
524
525   ``pw_rpc`` does not yet support bidirectional streaming RPCs.
526
527 .. seqdiag::
528   :scale: 110
529
530   seqdiag {
531     default_note_color = aliceblue;
532
533     client -> server [
534         label = "start",
535         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID"
536     ];
537
538     client --> server [
539         noactivate,
540         label = "requests (zero or more)",
541         leftnote = "PacketType.REQUEST\nchannel ID\nservice ID\nmethod ID\npayload"
542     ];
543
544     ... (messages in any order) ...
545
546     client <-- server [
547         noactivate,
548         label = "responses (zero or more)",
549         rightnote = "PacketType.RESPONSE\nchannel ID\nservice ID\nmethod ID\npayload"
550     ];
551
552     client -> server [
553         noactivate,
554         label = "done",
555         leftnote = "PacketType.CLIENT_STREAM_END\nchannel ID\nservice ID\nmethod ID"
556     ];
557
558     client <-- server [
559         noactivate,
560         label = "responses (zero or more)",
561         rightnote = "PacketType.RPC\nchannel ID\nservice ID\nmethod ID\npayload"
562     ];
563
564     client <- server [
565         label = "done",
566         rightnote = "PacketType.SERVER_STREAM_END\nchannel ID\nservice ID\nmethod ID\nstatus"
567     ];
568   }
569
570 The server may terminate the RPC at any time by sending a ``SERVER_STREAM_END``
571 packet with the status, even if the client has not sent its ``STREAM_END``. The
572 client may cancel the RPC at any time by sending a ``CANCEL_SERVER_STREAM``
573 packet.
574
575 .. seqdiag::
576   :scale: 110
577
578   seqdiag {
579     default_note_color = aliceblue;
580
581     client -> server [
582         label = "start",
583         leftnote = "PacketType.RPC\nchannel ID\nservice ID\nmethod ID"
584     ];
585
586     client --> server [
587         noactivate,
588         label = "requests (zero or more)",
589         leftnote = "PacketType.RPC\nchannel ID\nservice ID\nmethod ID\npayload"
590     ];
591
592     client <-- server [
593         noactivate,
594         label = "responses (zero or more)",
595         rightnote = "PacketType.RPC\nchannel ID\nservice ID\nmethod ID\npayload"
596     ];
597
598     client -> server [
599         noactivate,
600         label = "cancel",
601         leftnote = "PacketType.CANCEL_SERVER_STREAM\nchannel ID\nservice ID\nmethod ID"
602     ];
603
604     client <- server [
605         label = "done",
606         rightnote = "PacketType.STREAM_END\nchannel ID\nservice ID\nmethod ID\nstatus"
607     ];
608   }
609
610 RPC server
611 ==========
612 Declare an instance of ``rpc::Server`` and register services with it.
613
614 .. admonition:: TODO
615
616   Document the public interface
617
618 Size report
619 -----------
620 The following size report showcases the memory usage of the core RPC server. It
621 is configured with a single channel using a basic transport interface that
622 directly reads from and writes to ``pw_sys_io``. The transport has a 128-byte
623 packet buffer, which comprises the plurality of the example's RAM usage. This is
624 not a suitable transport for an actual product; a real implementation would have
625 additional overhead proportional to the complexity of the transport.
626
627 .. include:: server_size
628
629 RPC server implementation
630 -------------------------
631
632 The Method class
633 ^^^^^^^^^^^^^^^^
634 The RPC Server depends on the ``pw::rpc::internal::Method`` class. ``Method``
635 serves as the bridge between the ``pw_rpc`` server library and the user-defined
636 RPC functions. Each supported protobuf implementation extends ``Method`` to
637 implement its request and response proto handling. The ``pw_rpc`` server
638 calls into the ``Method`` implementation through the base class's ``Invoke``
639 function.
640
641 ``Method`` implementations store metadata about each method, including a
642 function pointer to the user-defined method implementation. They also provide
643 ``static constexpr`` functions for creating each type of method. ``Method``
644 implementations must satisfy the ``MethodImplTester`` test class in
645 ``pw_rpc_private/method_impl_tester.h``.
646
647 See ``pw_rpc/internal/method.h`` for more details about ``Method``.
648
649 Packet flow
650 ^^^^^^^^^^^
651
652 Requests
653 ~~~~~~~~
654
655 .. blockdiag::
656
657   blockdiag {
658     packets [shape = beginpoint];
659
660     group {
661       label = "pw_rpc library";
662
663       server [label = "Server"];
664       service [label = "Service"];
665       method [label = "internal::Method"];
666     }
667
668     stubs [label = "generated services", shape = ellipse];
669     user [label = "user-defined RPCs", shape = roundedbox];
670
671     packets -> server -> service -> method -> stubs -> user;
672     packets -> server [folded];
673     method -> stubs [folded];
674   }
675
676 Responses
677 ~~~~~~~~~
678
679 .. blockdiag::
680
681   blockdiag {
682     user -> stubs [folded];
683
684     group {
685       label = "pw_rpc library";
686
687       server [label = "Server"];
688       method [label = "internal::Method"];
689       channel [label = "Channel"];
690     }
691
692     stubs [label = "generated services", shape = ellipse];
693     user [label = "user-defined RPCs", shape = roundedbox];
694     packets [shape = beginpoint];
695
696     user -> stubs -> method [folded];
697     method -> server -> channel;
698     channel -> packets [folded];
699   }
700
701 RPC client
702 ==========
703 The RPC client is used to send requests to a server and manages the contexts of
704 ongoing RPCs.
705
706 Setting up a client
707 -------------------
708 The ``pw::rpc::Client`` class is instantiated with a list of channels that it
709 uses to communicate. These channels can be shared with a server, but multiple
710 clients cannot use the same channels.
711
712 To send incoming RPC packets from the transport layer to be processed by a
713 client, the client's ``ProcessPacket`` function is called with the packet data.
714
715 .. code:: c++
716
717   #include "pw_rpc/client.h"
718
719   namespace {
720
721   pw::rpc::Channel my_channels[] = {
722       pw::rpc::Channel::Create<1>(&my_channel_output)};
723   pw::rpc::Client my_client(my_channels);
724
725   }  // namespace
726
727   // Called when the transport layer receives an RPC packet.
728   void ProcessRpcPacket(ConstByteSpan packet) {
729     my_client.ProcessPacket(packet);
730   }
731
732 .. _module-pw_rpc-making-calls:
733
734 Making RPC calls
735 ----------------
736 RPC calls are not made directly through the client, but using one of its
737 registered channels instead. A service client class is generated from a .proto
738 file for each selected protobuf library, which is then used to send RPC requests
739 through a given channel. The API for this depends on the protobuf library;
740 please refer to the
741 :ref:`appropriate documentation<module-pw_rpc-protobuf-library-apis>`. Multiple
742 service client implementations can exist simulatenously and share the same
743 ``Client`` class.
744
745 When a call is made, a ``pw::rpc::ClientCall`` object is returned to the caller.
746 This object tracks the ongoing RPC call, and can be used to manage it. An RPC
747 call is only active as long as its ``ClientCall`` object is alive.
748
749 .. tip::
750   Use ``std::move`` when passing around ``ClientCall`` objects to keep RPCs
751   alive.
752
753 Client implementation details
754 -----------------------------
755
756 The ClientCall class
757 ^^^^^^^^^^^^^^^^^^^^
758 ``ClientCall`` stores the context of an active RPC, and serves as the user's
759 interface to the RPC client. The core RPC library provides a base ``ClientCall``
760 class with common functionality, which is then extended for RPC client
761 implementations tied to different protobuf libraries to provide convenient
762 interfaces for working with RPCs.
763
764 The RPC server stores a list of all of active ``ClientCall`` objects. When an
765 incoming packet is recieved, it dispatches to one of its active calls, which
766 then decodes the payload and presents it to the user.