cannam@147
|
1 ---
|
cannam@147
|
2 layout: page
|
cannam@147
|
3 title: FAQ
|
cannam@147
|
4 ---
|
cannam@147
|
5
|
cannam@147
|
6 # FAQ
|
cannam@147
|
7
|
cannam@147
|
8 ## Design
|
cannam@147
|
9
|
cannam@147
|
10 ### Isn't I/O bandwidth more important than CPU usage? Is Cap'n Proto barking up the wrong tree?
|
cannam@147
|
11
|
cannam@147
|
12 It depends. What is your use case?
|
cannam@147
|
13
|
cannam@147
|
14 Are you communicating between two processes on the same machine? If so, you have unlimited
|
cannam@147
|
15 bandwidth, and you should be entirely concerned with CPU.
|
cannam@147
|
16
|
cannam@147
|
17 Are you communicating between two machines within the same datacenter? If so, it's unlikely that
|
cannam@147
|
18 you will saturate your network connection before your CPU. Possible, but unlikely.
|
cannam@147
|
19
|
cannam@147
|
20 Are you communicating across the general internet? In that case, bandwidth is probably your main
|
cannam@147
|
21 concern. Luckily, Cap'n Proto lets you choose to enable "packing" in this case, achieving similar
|
cannam@147
|
22 encoding size to Protocol Buffers while still being faster. And you can always add extra
|
cannam@147
|
23 compression on top of that.
|
cannam@147
|
24
|
cannam@147
|
25 ### Have you considered building the RPC system on ZeroMQ?
|
cannam@147
|
26
|
cannam@147
|
27 ZeroMQ (and its successor, Nanomsg) is a powerful technology for distributed computing. Its
|
cannam@147
|
28 design focuses on scenarios involving lots of stateless, fault-tolerant worker processes
|
cannam@147
|
29 communicating via various patterns, such as request/response, produce/consume, and
|
cannam@147
|
30 publish/subscribe. For big data processing where armies of stateless nodes make sense, pairing
|
cannam@147
|
31 Cap'n Proto with ZeroMQ would be an excellent choice -- and this is easy to do today, as ZeroMQ
|
cannam@147
|
32 is entirely serialization-agnostic.
|
cannam@147
|
33
|
cannam@147
|
34 That said, Cap'n Proto RPC takes a very different approach. Cap'n Proto's model focuses on
|
cannam@147
|
35 stateful servers interacting in complex, object-oriented ways. The model is better suited to
|
cannam@147
|
36 tasks involving applications with many heterogeneous components and interactions between
|
cannam@147
|
37 mutually-distrusting parties. Requests and responses can go in any direction. Objects have
|
cannam@147
|
38 state and so two calls to the same object had best go to the same machine. Load balancing and
|
cannam@147
|
39 fault tolerance is pushed up the stack, because without a large pool of homogeneous work there's
|
cannam@147
|
40 just no way to make them transparent at a low level.
|
cannam@147
|
41
|
cannam@147
|
42 Put concretely, you might build a search engine indexing pipeline on ZeroMQ, but an online
|
cannam@147
|
43 interactive spreadsheet editor would be better built on Cap'n Proto RPC.
|
cannam@147
|
44
|
cannam@147
|
45 (Actually, a distributed programming framework providing similar features to ZeroMQ could itself be
|
cannam@147
|
46 built on top of Cap'n Proto RPC.)
|
cannam@147
|
47
|
cannam@147
|
48 ### Aren't messages that contain pointers a huge security problem?
|
cannam@147
|
49
|
cannam@147
|
50 Not at all. Cap'n Proto bounds-checks each pointer when it is read and throws an exception or
|
cannam@147
|
51 returns a safe dummy value (your choice) if the pointer is out-of-bounds.
|
cannam@147
|
52
|
cannam@147
|
53 ### So it's not that you've eliminated parsing, you've just moved it to happen lazily?
|
cannam@147
|
54
|
cannam@147
|
55 No. Compared to Protobuf decoding, the time spent validating pointers while traversing a Cap'n
|
cannam@147
|
56 Proto message is negligible.
|
cannam@147
|
57
|
cannam@147
|
58 ### I think I heard somewhere that capability-based security doesn't work?
|
cannam@147
|
59
|
cannam@147
|
60 This was a popular myth in security circles way back in the 80's and 90's, based on an incomplete
|
cannam@147
|
61 understanding of what capabilities are and how to use them effectively. Read
|
cannam@147
|
62 [Capability Myths Demolished](http://zesty.ca/capmyths/usenix.pdf). (No really, read it;
|
cannam@147
|
63 it's awesome.)
|
cannam@147
|
64
|
cannam@147
|
65 ## Usage
|
cannam@147
|
66
|
cannam@147
|
67 ### How do I make a field "required", like in Protocol Buffers?
|
cannam@147
|
68
|
cannam@147
|
69 You don't. You may find this surprising, but the "required" keyword in Protocol Buffers turned
|
cannam@147
|
70 out to be a horrible mistake.
|
cannam@147
|
71
|
cannam@147
|
72 For background, in protocol buffers, a field could be marked "required" to indicate that parsing
|
cannam@147
|
73 should fail if the sender forgot to set the field before sending the message. Required fields were
|
cannam@147
|
74 encoded exactly the same as optional ones; the only difference was the extra validation.
|
cannam@147
|
75
|
cannam@147
|
76 The problem with this is, validation is sometimes more subtle than that. Sometimes, different
|
cannam@147
|
77 applications -- or different parts of the same application, or different versions of the same
|
cannam@147
|
78 application -- place different requirements on the same protocol. An application may want to
|
cannam@147
|
79 pass around partially-complete messages internally. A particular field that used to be required
|
cannam@147
|
80 might become optional. A new use case might call for almost exactly the same message type, minus
|
cannam@147
|
81 one field, at which point it may make more sense to reuse the type than to define a new one.
|
cannam@147
|
82
|
cannam@147
|
83 A field declared required, unfortunately, is required everywhere. The validation is baked into
|
cannam@147
|
84 the parser, and there's nothing you can do about it. Nothing, that is, except change the field
|
cannam@147
|
85 from "required" to "optional". But that's where the _real_ problems start.
|
cannam@147
|
86
|
cannam@147
|
87 Imagine a production environment in which two servers, Alice and Bob, exchange messages through a
|
cannam@147
|
88 message bus infrastructure running on a big corporate network. The message bus parses each message
|
cannam@147
|
89 just to examine the envelope and decide how to route it, without paying attention to any other
|
cannam@147
|
90 content. Often, messages from various applications are batched together and then split up again
|
cannam@147
|
91 downstream.
|
cannam@147
|
92
|
cannam@147
|
93 Now, at some point, Alice's developers decide that one of the fields in a deeply-nested message
|
cannam@147
|
94 commonly sent to Bob has become obsolete. To clean things up, they decide to remove it, so they
|
cannam@147
|
95 change the field from "required" to "optional". The developers aren't idiots, so they realize that
|
cannam@147
|
96 Bob needs to be updated as well. They make the changes to Bob, and just to be thorough they
|
cannam@147
|
97 run an integration test with Alice and Bob running in a test environment. The test environment
|
cannam@147
|
98 is always running the latest build of the message bus, but that's irrelevant anyway because the
|
cannam@147
|
99 message bus doesn't actually care about message contents; it only does routing. Protocols are
|
cannam@147
|
100 modified all the time without updating the message bus.
|
cannam@147
|
101
|
cannam@147
|
102 Satisfied with their testing, the devs push a new version of Alice to prod. Immediately,
|
cannam@147
|
103 everything breaks. And by "everything" I don't just mean Alice and Bob. Completely unrelated
|
cannam@147
|
104 servers are getting strange errors or failing to receive messages. The whole data center has
|
cannam@147
|
105 ground to a halt and the sysadmins are running around with their hair on fire.
|
cannam@147
|
106
|
cannam@147
|
107 What happened? Well, the message bus running in prod was still an older build from before the
|
cannam@147
|
108 protocol change. And even though the message bus doesn't care about message content, it _does_
|
cannam@147
|
109 need to parse every message just to read the envelope. And the protobuf parser checks the _entire_
|
cannam@147
|
110 message for missing required fields. So when Alice stopped sending that newly-optional field, the
|
cannam@147
|
111 whole message failed to parse, envelope and all. And to make matters worse, any other messages
|
cannam@147
|
112 that happened to be in the same batch _also_ failed to parse, causing errors in seemingly-unrelated
|
cannam@147
|
113 systems that share the bus.
|
cannam@147
|
114
|
cannam@147
|
115 Things like this have actually happened. At Google. Many times.
|
cannam@147
|
116
|
cannam@147
|
117 The right answer is for applications to do validation as-needed in application-level code. If you
|
cannam@147
|
118 want to detect when a client fails to set a particular field, give the field an invalid default
|
cannam@147
|
119 value and then check for that value on the server. Low-level infrastructure that doesn't care
|
cannam@147
|
120 about message content should not validate it at all.
|
cannam@147
|
121
|
cannam@147
|
122 Oh, and also, Cap'n Proto doesn't have any parsing step during which to check for required
|
cannam@147
|
123 fields. :)
|
cannam@147
|
124
|
cannam@147
|
125 ### How do I make a field optional?
|
cannam@147
|
126
|
cannam@147
|
127 Cap'n Proto has no notion of "optional" fields.
|
cannam@147
|
128
|
cannam@147
|
129 A primitive field always takes space on the wire whether you set it or not (although default-valued
|
cannam@147
|
130 fields will be compressed away if you enable packing). Such a field can be made semantically
|
cannam@147
|
131 optional by placing it in a union with a `Void` field:
|
cannam@147
|
132
|
cannam@147
|
133 {% highlight capnp %}
|
cannam@147
|
134 union {
|
cannam@147
|
135 age @0 :Int32;
|
cannam@147
|
136 ageUnknown @1 :Void;
|
cannam@147
|
137 }
|
cannam@147
|
138 {% endhighlight %}
|
cannam@147
|
139
|
cannam@147
|
140 However, this field still takes space on the wire, and in fact takes an extra 16 bits of space
|
cannam@147
|
141 for the union tag. A better approach may be to give the field a bogus default value and interpret
|
cannam@147
|
142 that value to mean "not present".
|
cannam@147
|
143
|
cannam@147
|
144 Pointer fields are a bit different. They start out "null", and you can check for nullness using
|
cannam@147
|
145 the `hasFoo()` accessor. You could use a null pointer to mean "not present". Note, though, that
|
cannam@147
|
146 calling `getFoo()` on a null pointer returns the default value, which is indistinguishable from a
|
cannam@147
|
147 legitimate value, so checking `hasFoo()` is in fact the _only_ way to detect nullness.
|
cannam@147
|
148
|
cannam@147
|
149 ### How do I resize a list?
|
cannam@147
|
150
|
cannam@147
|
151 Unfortunately, you can't. You have to know the size of your list upfront, before you initialize
|
cannam@147
|
152 any of the elements. This is an annoying side effect of arena allocation, which is a fundamental
|
cannam@147
|
153 part of Cap'n Proto's design: in order to avoid making a copy later, all of the pieces of the
|
cannam@147
|
154 message must be allocated in a tightly-packed segment of memory, with each new piece being added
|
cannam@147
|
155 to the end. If a previously-allocated piece is discarded, it leaves a hole, which wastes space.
|
cannam@147
|
156 Since Cap'n Proto lists are flat arrays, the only way to resize a list would be to discard the
|
cannam@147
|
157 existing list and allocate a new one, which would thus necessarily waste space.
|
cannam@147
|
158
|
cannam@147
|
159 In theory, a more complicated memory allocation algorithm could attempt to reuse the "holes" left
|
cannam@147
|
160 behind by discarded message pieces. However, it would be hard to make sure any new data inserted
|
cannam@147
|
161 into the space is exactly the right size. Fragmentation would result. And the allocator would
|
cannam@147
|
162 have to do a lot of extra bookkeeping that could be expensive. This would be sad, as arena
|
cannam@147
|
163 allocation is supposed to be cheap!
|
cannam@147
|
164
|
cannam@147
|
165 The only solution is to temporarily place your data into some other data structure (an
|
cannam@147
|
166 `std::vector`, perhaps) until you know how many elements you have, then allocate the list and copy.
|
cannam@147
|
167 On the bright side, you probably aren't losing much performance this way -- using vectors already
|
cannam@147
|
168 involves making copies every time the backing array grows. It's just annoying to code.
|
cannam@147
|
169
|
cannam@147
|
170 Keep in mind that you can use [orphans](cxx.html#orphans) to allocate sub-objects before you have
|
cannam@147
|
171 a place to put them. But, also note that you cannot allocate elements of a struct list as orphans
|
cannam@147
|
172 and then put them together as a list later, because struct lists are encoded as a flat array of
|
cannam@147
|
173 struct values, not an array of pointers to struct values. You can, however, allocate any inner
|
cannam@147
|
174 objects embedded within those structs as orphans.
|
cannam@147
|
175
|
cannam@147
|
176 ## Security
|
cannam@147
|
177
|
cannam@147
|
178 ### Is Cap'n Proto secure?
|
cannam@147
|
179
|
cannam@147
|
180 What is your threat model?
|
cannam@147
|
181
|
cannam@147
|
182 ### Sorry. Can Cap'n Proto be used to deserialize malicious messages?
|
cannam@147
|
183
|
cannam@147
|
184 Cap'n Proto's serialization layer is designed to be safe against malicious input. The Cap'n Proto implementation should never segfault, corrupt memory, leak secrets, execute attacker-specified code, consume excessive resources, etc. as a result of any sequence of input bytes. Moreover, the API is carefully designed to avoid putting app developers into situations where it is easy to write insecure code -- we consider it a bug in Cap'n Proto if apps commonly misuse it in a way that is a security problem.
|
cannam@147
|
185
|
cannam@147
|
186 With all that said, Cap'n Proto's C++ reference implementation has not yet undergone a formal security review. It may have bugs.
|
cannam@147
|
187
|
cannam@147
|
188 ### Is it safe to use Cap'n Proto RPC with a malicious peer?
|
cannam@147
|
189
|
cannam@147
|
190 Cap'n Proto's RPC layer is explicitly designed to be useful for interactions between mutually-distrusting parties. Its capability-based security model makes it easy to express complex interactions securely.
|
cannam@147
|
191
|
cannam@147
|
192 At this time, the RPC layer is not robust against resource exhaustion attacks, possibly allowing denials of service.
|
cannam@147
|
193
|
cannam@147
|
194 ### Is Cap'n Proto encrypted?
|
cannam@147
|
195
|
cannam@147
|
196 Cap'n Proto may be layered on top of an existing encrypted transport, such as TLS, but at this time it is the application's responsibility to add this layer. We plan to integrate this into the Cap'n Proto library proper in the future.
|
cannam@147
|
197
|
cannam@147
|
198 ### How do I report security bugs?
|
cannam@147
|
199
|
cannam@147
|
200 Please email [security@sandstorm.io](mailto:security@sandstorm.io).
|
cannam@147
|
201
|
cannam@147
|
202 ## Sandstorm
|
cannam@147
|
203
|
cannam@147
|
204 ### How does Cap'n Proto relate to Sandstorm.io?
|
cannam@147
|
205
|
cannam@147
|
206 [Sandstorm.io](https://sandstorm.io) is an Open Source project and startup founded by Kenton, the author of Cap'n Proto. Cap'n Proto is owned and developed by Sandstorm the company and heavily used in Sandstorm the project.
|
cannam@147
|
207
|
cannam@147
|
208 ### How does Sandstorm use Cap'n Proto?
|
cannam@147
|
209
|
cannam@147
|
210 See [this Sandstorm blog post](https://blog.sandstorm.io/news/2014-12-15-capnproto-0.5.html).
|
cannam@147
|
211
|