Load 57 into trunk.
[nativeclient.git] / tools / libsrpc / imc_buffer.c
blob7d7b0e3a0890d42f2c5fb91eef45023c620efa9f
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
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
14 * distribution.
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"
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <errno.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;
61 if (is_write_buf) {
62 buffer->header.desc_length = 0;
63 } else {
64 buffer->header.desc_length =
65 sizeof(buffer->descs) / sizeof(buffer->descs[0]);
67 buffer->header.flags = 0;
68 #else
69 buffer->header.ndescv = buffer->descs;
70 if (is_write_buf) {
71 buffer->header.ndesc_length = 0;
72 } else {
73 buffer->header.ndesc_length =
74 sizeof(buffer->descs) / sizeof(buffer->descs[0]);
76 buffer->header.flags = 0;
77 #endif
78 /* Buffers start out empty */
79 buffer->next_byte = 0;
80 buffer->last_byte = 0;
83 NaClSrpcImcDescType NaClSrpcImcDescTypeFromHandle(NaClHandle handle) {
84 #ifdef __native_client__
85 return handle;
86 #else
87 struct NaClDescImcDesc* desc =
88 (struct NaClDescImcDesc*) malloc(sizeof(struct NaClDescImcDesc));
89 if (desc == NULL) {
90 return NULL;
92 if (!NaClDescImcDescCtor(desc, handle)) {
93 free(desc);
94 return NULL;
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) {
110 int retval;
111 double start_usec = 0.0;
112 double this_usec;
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);
124 #else
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,
130 #endif
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));
137 if (retval >= 0) {
138 channel->receive_buf.next_byte = 0;
139 channel->receive_buf.last_byte = retval;
140 } else {
141 dprintf((SIDE "READ: read failed.\n"));
142 return 0;
144 return 1;
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,
150 * and -1 otherwise.
152 int __NaClSrpcImcRead(void* buffer,
153 size_t elt_size,
154 size_t n_elt,
155 NaClSrpcChannel* channel) {
156 size_t request_bytes = n_elt * elt_size;
157 size_t avail_bytes;
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)) {
163 return -1;
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 */
171 memcpy(buffer,
172 (void*)(channel->receive_buf.bytes + channel->receive_buf.next_byte),
173 request_bytes);
174 channel->receive_buf.next_byte += request_bytes;
175 return n_elt;
176 } else {
177 dprintf((SIDE "READ: insufficient bytes read to satisfy request.\n"));
178 return -1;
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) {
189 int retval;
190 int server_protocol;
191 int tmp_rpc_num;
192 retval = __NaClSrpcImcRead(&server_protocol,
193 sizeof(server_protocol),
195 channel);
196 if (retval != 1) {
197 return 0;
199 if (server_protocol != kSrpcProtocolVersion) {
200 return 0;
202 retval = __NaClSrpcImcRead(&tmp_rpc_num, sizeof(tmp_rpc_num), 1, channel);
203 if (retval != 1) {
204 return 0;
206 *rpc_number = tmp_rpc_num;
207 return 1;
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) {
217 int retval;
218 int server_protocol;
219 int tmp_app_error;
221 retval = __NaClSrpcImcRead(&server_protocol,
222 sizeof(server_protocol),
224 channel);
225 if (retval != 1) {
226 return 0;
228 if (server_protocol != kSrpcProtocolVersion) {
229 return 0;
231 retval = __NaClSrpcImcRead(&tmp_app_error, sizeof(tmp_app_error), 1, channel);
232 if (retval != 1) {
233 return 0;
235 *app_error = tmp_app_error;
236 return 1;
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) {
249 return -1;
251 #else
252 if (desc_index >= channel->receive_buf.header.ndesc_length) {
253 return NULL;
255 #endif
256 else {
257 NaClSrpcImcDescType desc = channel->receive_buf.descs[desc_index];
258 channel->receive_buf.next_desc++;
259 return 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,
269 size_t elt_size,
270 size_t n_elt,
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"));
280 return -1;
281 } else {
282 memcpy((void*)(channel->send_buf.bytes + channel->send_buf.next_byte),
283 buffer,
284 request_bytes);
285 channel->send_buf.next_byte += request_bytes;
286 dprintf((SIDE "WRITE: wrote %u bytes.\n", (unsigned) request_bytes));
287 return n_elt;
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),
300 channel);
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),
313 channel);
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;
325 #else
326 int desc_index = channel->send_buf.header.ndesc_length;
327 #endif
329 if (desc_index >= SRPC_DESC_MAX) {
330 return 0;
331 } else {
332 channel->send_buf.descs[desc_index] = desc;
333 #ifdef __native_client__
334 channel->send_buf.header.desc_length++;
335 #else
336 channel->send_buf.header.ndesc_length++;
337 #endif
338 return 1;
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
345 * otherwise.
347 int __NaClSrpcImcFlush(NaClSrpcChannel* channel) {
348 int retval;
349 double start_usec = 0.0;
350 double this_usec;
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;
360 #else
361 retval = NaClImcSendTypedMessage(channel->imc_handle,
362 (struct NaClDescEffector*) &channel->eff,
363 &channel->send_buf.header,
365 channel->send_buf.header.ndesc_length = 0;
366 #endif
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"));
377 return 0;
379 dprintf((SIDE "FLUSH: complete send.\n"));
380 return 1;