2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * NaCl simple RPC over IMC mechanism.
37 #include "nacl_srpc.h"
38 #include "nacl_srpc_internal.h"
43 #include <sys/types.h>
46 * SRPC headers include a protocol (version) number.
49 static const int kSrpcProtocolVersion
= 0xc0da0001;
52 * IMC wrapper functions.
54 void __NaClSrpcImcBufferCtor(NaClSrpcImcBuffer
* buffer
, int is_write_buf
) {
55 buffer
->iovec
[0].base
= buffer
->bytes
;
56 buffer
->iovec
[0].length
= sizeof(buffer
->bytes
);
57 buffer
->header
.iov
= buffer
->iovec
;
58 buffer
->header
.iov_length
= sizeof(buffer
->iovec
) / sizeof(buffer
->iovec
[0]);
59 #ifdef __native_client__
60 buffer
->header
.descv
= buffer
->descs
;
62 buffer
->header
.desc_length
= 0;
64 buffer
->header
.desc_length
=
65 sizeof(buffer
->descs
) / sizeof(buffer
->descs
[0]);
67 buffer
->header
.flags
= 0;
69 buffer
->header
.ndescv
= buffer
->descs
;
71 buffer
->header
.ndesc_length
= 0;
73 buffer
->header
.ndesc_length
=
74 sizeof(buffer
->descs
) / sizeof(buffer
->descs
[0]);
76 buffer
->header
.flags
= 0;
78 /* Buffers start out empty */
79 buffer
->next_byte
= 0;
80 buffer
->last_byte
= 0;
83 NaClSrpcImcDescType
NaClSrpcImcDescTypeFromHandle(NaClHandle handle
) {
84 #ifdef __native_client__
87 struct NaClDescImcDesc
* desc
=
88 (struct NaClDescImcDesc
*) malloc(sizeof(struct NaClDescImcDesc
));
92 if (!NaClDescImcDescCtor(desc
, handle
)) {
96 return (struct NaClDesc
*) desc
;
97 #endif /* __native_client__ */
100 void __NaClSrpcImcMarkReadBufferEmpty(NaClSrpcChannel
* channel
) {
101 channel
->receive_buf
.last_byte
= 0;
102 channel
->receive_buf
.next_byte
= 0;
106 * __NaClSrpcImcFillBuf fills the read buffer from an IMC channel.
107 * It returns 1 if successful, and 0 otherwise.
109 int __NaClSrpcImcFillbuf(NaClSrpcChannel
* channel
) {
111 double start_usec
= 0.0;
114 channel
->receive_buf
.iovec
[0].base
= channel
->receive_buf
.bytes
;
115 channel
->receive_buf
.iovec
[0].length
= sizeof(channel
->receive_buf
.bytes
);
116 dprintf((SIDE
"READ: filling buffer from %x.\n",
117 (unsigned) channel
->imc_handle
));
118 if (channel
->timing_enabled
) {
119 start_usec
= __NaClSrpcGetUsec();
121 #ifdef __native_client__
122 channel
->receive_buf
.header
.desc_length
= SRPC_DESC_MAX
;
123 retval
= imc_recvmsg(channel
->imc_handle
, &channel
->receive_buf
.header
, 0);
125 channel
->receive_buf
.header
.ndesc_length
= SRPC_DESC_MAX
;
126 retval
= NaClImcRecvTypedMessage(channel
->imc_handle
,
127 (struct NaClDescEffector
*) &channel
->eff
,
128 &channel
->receive_buf
.header
,
131 channel
->receive_buf
.next_desc
= 0;
132 if (channel
->timing_enabled
) {
133 this_usec
= __NaClSrpcGetUsec();
134 channel
->imc_read_usec
+= this_usec
;
136 dprintf((SIDE
"READ: received %d bytes\n", retval
));
138 channel
->receive_buf
.next_byte
= 0;
139 channel
->receive_buf
.last_byte
= retval
;
141 dprintf((SIDE
"READ: read failed.\n"));
148 * __NaClSrpcImcRead attempts to read n_elt entities of size elt_size into
149 * buffer from channel. It returns the number of elements read if successful,
152 int __NaClSrpcImcRead(void* buffer
,
155 NaClSrpcChannel
* channel
) {
156 size_t request_bytes
= n_elt
* elt_size
;
159 * Reads must be satisfiable from exactly one datagram receive for now.
161 if (channel
->receive_buf
.last_byte
<= channel
->receive_buf
.next_byte
) {
162 if (1 != __NaClSrpcImcFillbuf(channel
)) {
167 avail_bytes
= channel
->receive_buf
.last_byte
- channel
->receive_buf
.next_byte
;
168 if (avail_bytes
>= request_bytes
) {
169 dprintf((SIDE
"READ: satisfying request from buffer.\n"));
170 /* Channel receive buffer contains enough data to fully satisfy request */
172 (void*)(channel
->receive_buf
.bytes
+ channel
->receive_buf
.next_byte
),
174 channel
->receive_buf
.next_byte
+= request_bytes
;
177 dprintf((SIDE
"READ: insufficient bytes read to satisfy request.\n"));
183 * __NaClSrpcImcReadRequestHeader attempts to a request header from the
184 * specified channel. It returns 1 and sets the rpc_number from the request
185 * if successful, and 0 otherwise.
187 int __NaClSrpcImcReadRequestHeader(NaClSrpcChannel
* channel
,
188 unsigned int* rpc_number
) {
192 retval
= __NaClSrpcImcRead(&server_protocol
,
193 sizeof(server_protocol
),
199 if (server_protocol
!= kSrpcProtocolVersion
) {
202 retval
= __NaClSrpcImcRead(&tmp_rpc_num
, sizeof(tmp_rpc_num
), 1, channel
);
206 *rpc_number
= tmp_rpc_num
;
211 * __NaClSrpcImcReadResponseHeader attempts to a response header from the
212 * specified channel. It returns 1 and sets the app_error from the request
213 * if successful, and 0 otherwise.
215 int __NaClSrpcImcReadResponseHeader(NaClSrpcChannel
* channel
,
216 NaClSrpcError
* app_error
) {
221 retval
= __NaClSrpcImcRead(&server_protocol
,
222 sizeof(server_protocol
),
228 if (server_protocol
!= kSrpcProtocolVersion
) {
231 retval
= __NaClSrpcImcRead(&tmp_app_error
, sizeof(tmp_app_error
), 1, channel
);
235 *app_error
= tmp_app_error
;
240 * __NaClSrpcImcReadDesc reads a NaCl resource descriptor from the specified
241 * channel. It returns a valid descriptor if successful and -1 (untrusted)
242 * or NULL (trusted) otherwise.
244 NaClSrpcImcDescType
__NaClSrpcImcReadDesc(NaClSrpcChannel
* channel
) {
245 uint32_t desc_index
= channel
->receive_buf
.next_desc
;
247 #ifdef __native_client__
248 if (desc_index
>= channel
->receive_buf
.header
.desc_length
) {
252 if (desc_index
>= channel
->receive_buf
.header
.ndesc_length
) {
257 NaClSrpcImcDescType desc
= channel
->receive_buf
.descs
[desc_index
];
258 channel
->receive_buf
.next_desc
++;
264 * __NaClSrpcImcReadResponseHeader attempts to write n_elt elements of size
265 * elt_size from buffer to the specified channel. It returns the number of
266 * elements it wrote if successful, and -1 otherwise.
268 int __NaClSrpcImcWrite(const void* buffer
,
271 NaClSrpcChannel
* channel
) {
272 size_t request_bytes
= n_elt
* elt_size
;
273 size_t avail_bytes
= sizeof(channel
->send_buf
.bytes
) -
274 channel
->send_buf
.next_byte
;
276 * Writes are not broken into multiple datagram sends for now either.
278 if (avail_bytes
< request_bytes
) {
279 dprintf((SIDE
"WRITE: insufficient space available to satisfy request.\n"));
282 memcpy((void*)(channel
->send_buf
.bytes
+ channel
->send_buf
.next_byte
),
285 channel
->send_buf
.next_byte
+= request_bytes
;
286 dprintf((SIDE
"WRITE: wrote %u bytes.\n", (unsigned) request_bytes
));
292 * __NaClSrpcImcWriteRequestHeader writes a request header on the channel
293 * the header contains an rpc_number.
295 void __NaClSrpcImcWriteRequestHeader(NaClSrpcChannel
* channel
,
296 unsigned int rpc_number
) {
297 __NaClSrpcImcWrite(&kSrpcProtocolVersion
,
298 sizeof(kSrpcProtocolVersion
),
301 __NaClSrpcImcWrite(&rpc_number
, sizeof(rpc_number
), 1, channel
);
305 * __NaClSrpcImcWriteResponseHeader writes a response header on the channel
306 * the header contains an app_error.
308 void __NaClSrpcImcWriteResponseHeader(NaClSrpcChannel
* channel
,
309 NaClSrpcError app_error
) {
310 __NaClSrpcImcWrite(&kSrpcProtocolVersion
,
311 sizeof(kSrpcProtocolVersion
),
314 __NaClSrpcImcWrite(&app_error
, sizeof(app_error
), 1, channel
);
318 * __NaClSrpcImcWriteDesc writes a NaCl resource descriptor to the specified
319 * channel. It returns 1 if successful, 0 otherwise.
321 int __NaClSrpcImcWriteDesc(NaClSrpcChannel
* channel
,
322 NaClSrpcImcDescType desc
) {
323 #ifdef __native_client__
324 int desc_index
= channel
->send_buf
.header
.desc_length
;
326 int desc_index
= channel
->send_buf
.header
.ndesc_length
;
329 if (desc_index
>= SRPC_DESC_MAX
) {
332 channel
->send_buf
.descs
[desc_index
] = desc
;
333 #ifdef __native_client__
334 channel
->send_buf
.header
.desc_length
++;
336 channel
->send_buf
.header
.ndesc_length
++;
343 * __NaClSrpcImcFlush send the contents of the write buffer in channel
344 * over the IMC channel it contains. It returns 1 if successful, or 0
347 int __NaClSrpcImcFlush(NaClSrpcChannel
* channel
) {
349 double start_usec
= 0.0;
352 dprintf((SIDE
"FLUSH: imc_handle %x\n", (unsigned) channel
->imc_handle
));
353 channel
->send_buf
.iovec
[0].length
= channel
->send_buf
.next_byte
;
354 if (channel
->timing_enabled
) {
355 start_usec
= __NaClSrpcGetUsec();
357 #ifdef __native_client__
358 retval
= imc_sendmsg(channel
->imc_handle
, &channel
->send_buf
.header
, 0);
359 channel
->send_buf
.header
.desc_length
= 0;
361 retval
= NaClImcSendTypedMessage(channel
->imc_handle
,
362 (struct NaClDescEffector
*) &channel
->eff
,
363 &channel
->send_buf
.header
,
365 channel
->send_buf
.header
.ndesc_length
= 0;
367 channel
->send_buf
.next_desc
= 0;
368 if (channel
->timing_enabled
) {
369 this_usec
= __NaClSrpcGetUsec();
370 channel
->imc_write_usec
+= this_usec
;
372 dprintf((SIDE
"FLUSH: retval %d, expected %d, errno %d\n",
373 retval
, (int) channel
->send_buf
.iovec
[0].length
, errno
));
374 channel
->send_buf
.next_byte
= 0;
375 if (retval
!= channel
->send_buf
.iovec
[0].length
) {
376 dprintf((SIDE
"FLUSH: send error.\n"));
379 dprintf((SIDE
"FLUSH: complete send.\n"));