1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : /*
8 : * NaCl simple RPC over IMC mechanism.
9 : */
10 :
11 : #include <errno.h>
12 : #include <stdio.h>
13 : #include <stdlib.h>
14 : #include <string.h>
15 : #include <sys/types.h>
16 :
17 : #include "native_client/src/include/portability.h"
18 : #include "native_client/src/include/nacl_macros.h"
19 : #include "native_client/src/shared/srpc/nacl_srpc.h"
20 : #include "native_client/src/shared/srpc/nacl_srpc_internal.h"
21 : #include "native_client/src/shared/srpc/nacl_srpc_message.h"
22 :
23 : #ifdef __native_client__
24 : #define NaClImcMsgIoVec NaClAbiNaClImcMsgIoVec
25 : #define NACL_ABI_EIO EIO
26 : #define NACL_ABI_EINVAL EINVAL
27 : #else
28 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
29 : #endif
30 :
31 : #ifndef SIZE_T_MAX
32 : # define SIZE_T_MAX (~((size_t) 0))
33 : #endif
34 :
35 : /*
36 : * Message formats:
37 : *
38 : * SRPC communicates using two message types, requests and responses.
39 : * Both are communicated with a header (NaClSrpcHeader below) prepended.
40 : *
41 : * Requests and responses also convey vectors of parameters that are
42 : * represented in memory by NaClSrpcArg. Because NaClSrpcArgs may have a
43 : * non-fixed amount of additional memory associated (strings, arrays, etc.),
44 : * the form communicated separates the vectors of NaClSrpcArgs into a vector
45 : * of fixed length structs (ArgFixed) and a region of non-fixed memory.
46 : *
47 : * request:
48 : * RpcHeader header
49 : * -- header info, value_len and template_len
50 : * where value_len <= NACL_SRPC_MAX_ARGS, and
51 : * template_len <= NACL_SRPC_MAX_ARGS
52 : * ArgFixed templates[template_len]
53 : * -- conveys the types and sizes of rets
54 : * ArgFixed values[value_len]
55 : * -- conveys the scalar values, and array types and sizes of args
56 : * char nonfixed[]
57 : * -- the bytes used by strings, arrays, etc., in the elements of args in
58 : * the order seen in args
59 : *
60 : * response:
61 : * RpcHeader header
62 : * -- header info, value_len and template_len
63 : * where value_len <= NACL_SRPC_MAX_ARGS, and template_len == 0
64 : * ArgFixed values[value_len]
65 : * -- conveys the scalar values, and array types and sizes of rets
66 : * char nonfixed[]
67 : * -- the bytes used by strings, arrays, etc., in the elements of rets in
68 : * the order seen in rets
69 : */
70 :
71 : #define HEADER_IOV_ENTRY_MAX 1
72 : #define TEMPLATE_IOV_ENTRY_MAX NACL_SRPC_MAX_ARGS
73 : #define VALUE_IOV_ENTRY_MAX NACL_SRPC_MAX_ARGS
74 : #define NONFIXED_IOV_ENTRY_MAX NACL_SRPC_MAX_ARGS
75 : #define IOV_ENTRY_MAX (HEADER_IOV_ENTRY_MAX + \
76 : TEMPLATE_IOV_ENTRY_MAX + \
77 : VALUE_IOV_ENTRY_MAX + \
78 : NONFIXED_IOV_ENTRY_MAX)
79 :
80 : /*
81 : * RpcFixed is the fixed portion of NaClSrpcRpc serialized to the channel.
82 : */
83 : struct RpcFixed {
84 : NACL_SRPC_RPC_SERIALIZED_FIELDS;
85 : };
86 : static const size_t kRpcSize = sizeof(struct RpcFixed);
87 :
88 : /*
89 : * ArgFixed is the fixed portion of NaClSrpcArg serialized to the channel.
90 : */
91 : struct ArgFixed {
92 : NACL_SRPC_ARG_SERIALIZED_FIELDS;
93 : };
94 : static const size_t kArgSize = sizeof(struct ArgFixed);
95 :
96 : typedef enum {
97 : BoolFalse = 0,
98 : BoolTrue = 1,
99 : } BoolValue;
100 :
101 19 : static ssize_t ErrnoFromImcRet(ssize_t imc_ret) {
102 19 : if (0 > imc_ret) {
103 19 : return imc_ret;
104 : } else {
105 0 : return -NACL_ABI_EIO;
106 : }
107 19 : }
108 :
109 2114 : static void AddIovEntry(void* base,
110 2114 : size_t length,
111 2114 : size_t max_iov_len,
112 2114 : struct NaClImcMsgIoVec* iov,
113 2114 : size_t* iov_len,
114 2114 : size_t* total_bytes) {
115 2114 : if (length == 0) {
116 0 : return;
117 : }
118 2114 : if (*iov_len >= max_iov_len) {
119 0 : return;
120 : }
121 2114 : iov[*iov_len].base = base;
122 2114 : iov[*iov_len].length = length;
123 2114 : ++*iov_len;
124 2114 : *total_bytes += length;
125 4228 : }
126 :
127 576 : static nacl_abi_size_t VectorLen(NaClSrpcArg** vec) {
128 576 : nacl_abi_size_t len = 0;
129 2396 : for (len = 0; len <= NACL_SRPC_MAX_ARGS; ++len) {
130 1198 : if (vec[len] == NULL) {
131 576 : return len;
132 : }
133 622 : }
134 0 : return NACL_SRPC_MAX_ARGS;
135 576 : }
136 :
137 357 : static size_t ArrayElementSize(NaClSrpcArg* arg) {
138 357 : switch (arg->tag) {
139 : case NACL_SRPC_ARG_TYPE_BOOL:
140 : case NACL_SRPC_ARG_TYPE_DOUBLE:
141 : case NACL_SRPC_ARG_TYPE_HANDLE:
142 : case NACL_SRPC_ARG_TYPE_INT:
143 : case NACL_SRPC_ARG_TYPE_INVALID:
144 : case NACL_SRPC_ARG_TYPE_LONG:
145 : case NACL_SRPC_ARG_TYPE_OBJECT:
146 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
147 : /* These are all scalar types. */
148 207 : return 0;
149 :
150 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
151 129 : return sizeof *arg->arrays.carr;
152 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
153 2 : return sizeof *arg->arrays.darr;
154 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
155 6 : return sizeof *arg->arrays.iarr;
156 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
157 2 : return sizeof *arg->arrays.larr;
158 : case NACL_SRPC_ARG_TYPE_STRING:
159 11 : return sizeof *arg->arrays.str;
160 : }
161 : /* UNREACHED */
162 0 : return 0;
163 357 : }
164 :
165 65 : static void ClearTemplateStringLengths(NaClSrpcArg** vec,
166 65 : size_t vec_len) {
167 65 : size_t i;
168 274 : for (i = 0; i < vec_len; ++i) {
169 72 : if (vec[i]->tag == NACL_SRPC_ARG_TYPE_STRING) {
170 0 : vec[i]->u.count = 0;
171 0 : }
172 72 : }
173 65 : }
174 :
175 : /*
176 : * Adds the IOV entries for the fixed portion of the arguments in vec.
177 : */
178 836 : static void AddFixed(NaClSrpcArg** vec,
179 836 : size_t vec_len,
180 836 : size_t max_iov_len,
181 836 : struct NaClImcMsgIoVec* iov,
182 836 : size_t* iov_len,
183 836 : size_t* expected_bytes) {
184 836 : size_t i;
185 3308 : for (i = 0; i < vec_len; ++i) {
186 818 : AddIovEntry(vec[i], kArgSize, max_iov_len, iov, iov_len, expected_bytes);
187 818 : }
188 836 : }
189 :
190 : /*
191 : * Copies the handles/descriptors from descs into the appropriately typed
192 : * elements of vec.
193 : */
194 234 : static BoolValue GetHandles(NaClSrpcArg** vec,
195 234 : size_t vec_len,
196 234 : NaClSrpcImcDescType* descs,
197 234 : size_t desc_len) {
198 234 : size_t i;
199 234 : size_t handle_index = 0;
200 936 : for (i = 0; i < vec_len; ++i) {
201 234 : if (vec[i]->tag != NACL_SRPC_ARG_TYPE_HANDLE) {
202 201 : continue;
203 : }
204 33 : if (handle_index >= desc_len) {
205 0 : return BoolFalse;
206 : }
207 33 : vec[i]->u.hval = descs[handle_index];
208 33 : ++handle_index;
209 33 : }
210 234 : return BoolTrue;
211 234 : }
212 :
213 : /*
214 : * Reads the header of the message to determine whether to call RecvRequest or
215 : * RecvResponse.
216 : */
217 253 : static ssize_t SrpcPeekMessage(struct NaClSrpcMessageChannel* channel,
218 253 : NaClSrpcRpc* rpc) {
219 253 : struct NaClImcMsgIoVec iov[1];
220 253 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
221 253 : size_t iov_len;
222 253 : NaClSrpcMessageHeader header;
223 253 : size_t expected_bytes;
224 253 : ssize_t retval;
225 :
226 253 : iov_len = 0;
227 253 : expected_bytes = 0;
228 253 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
229 253 : header.iov = iov;
230 253 : header.iov_length = NACL_ARRAY_SIZE(iov);
231 253 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
232 253 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
233 253 : retval = NaClSrpcMessageChannelPeek(channel, &header);
234 : /*
235 : * Check that the peek read the RPC and that the argument lengths are sane.
236 : */
237 253 : if (retval < (ssize_t) expected_bytes) {
238 19 : retval = ErrnoFromImcRet(retval);
239 19 : }
240 468 : else if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
241 : rpc->template_len > NACL_SRPC_MAX_ARGS) {
242 0 : retval = -NACL_ABI_EIO;
243 0 : }
244 253 : return retval;
245 : }
246 :
247 : /*
248 : * Adds the IOV entries for the nonfixed portions of an argument vector to
249 : * read. For receiving requests we need to allocate memory for the nonfixed
250 : * portions of both the inputs and results, but we do not read the results
251 : * vector's nonfixed portion. For receiving responses we do not allocate
252 : * memory for the nonfixed portion (the caller has already done that), but we
253 : * read the nonfixed portion of results.
254 : * If it returns BoolFalse, some memory may have been allocated. It is the
255 : * caller's responsibility to clean up in that case.
256 : */
257 299 : static BoolValue AddNonfixedForRead(NaClSrpcArg** vec,
258 299 : size_t vec_len,
259 299 : size_t max_iov_len,
260 299 : BoolValue alloc_value,
261 299 : BoolValue read_value,
262 299 : struct NaClImcMsgIoVec* iov,
263 299 : size_t* iov_len,
264 299 : size_t* expected_bytes) {
265 299 : size_t i;
266 :
267 : /* Initialize the array pointers to allow cleanup if errors happen. */
268 299 : if (alloc_value) {
269 456 : for (i = 0; i < vec_len; ++i) {
270 98 : vec[i]->arrays.oval = NULL;
271 98 : }
272 130 : }
273 :
274 1210 : for (i = 0; i < vec_len; ++i) {
275 306 : size_t count = vec[i]->u.count;
276 306 : void* base = 0;
277 306 : size_t element_size = ArrayElementSize(vec[i]);
278 :
279 306 : if (element_size == 0) {
280 : /* Skip fixed size arguments. */
281 207 : continue;
282 : }
283 99 : if (SIZE_T_MAX / element_size < count) {
284 0 : return BoolFalse;
285 : }
286 99 : base = vec[i]->arrays.oval;
287 99 : if (alloc_value) {
288 36 : base = malloc(element_size * count);
289 36 : if (base == 0) {
290 0 : return BoolFalse;
291 : }
292 36 : vec[i]->arrays.oval = base;
293 36 : }
294 99 : if (read_value) {
295 72 : AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
296 : expected_bytes);
297 72 : }
298 99 : }
299 299 : return BoolTrue;
300 299 : }
301 :
302 : /*
303 : * Minimal initialization of SRPC argument vectors declared as
304 : * NaClSrpcArg *arg_pointers[];
305 : * so that they will be compatible with FreeArgs below.
306 : */
307 819 : static void NaClSrpcArgVectorInit(NaClSrpcArg** arg_pointers) {
308 819 : arg_pointers[0] = NULL;
309 819 : }
310 :
311 299 : static BoolValue AllocateArgs(NaClSrpcArg** arg_pointers, size_t length) {
312 299 : NaClSrpcArg* arg_array;
313 299 : nacl_abi_size_t i;
314 :
315 : /* Initialize the array pointers to allow cleanup if errors happen. */
316 1808 : for (i = 0; i < length + 1; ++i) {
317 605 : arg_pointers[i] = NULL;
318 605 : }
319 299 : if (length == 0) {
320 80 : return BoolTrue;
321 : }
322 :
323 219 : if (SIZE_T_MAX / sizeof **arg_pointers < length) {
324 0 : return BoolFalse;
325 : }
326 219 : arg_array = (NaClSrpcArg*) malloc(length * sizeof **arg_pointers);
327 219 : if (arg_array == NULL) {
328 0 : return BoolFalse;
329 : }
330 : /* Initialize the individual args. */
331 1050 : for (i = 0; i < length; ++i) {
332 306 : NaClSrpcArgCtor(&arg_array[i]);
333 306 : }
334 : /* Set each array pointer to point to the respective arg. */
335 1050 : for (i = 0; i < length; ++i) {
336 306 : arg_pointers[i] = &arg_array[i];
337 306 : }
338 219 : return BoolTrue;
339 299 : }
340 :
341 425 : static void FreeArgs(NaClSrpcArg** vec) {
342 425 : nacl_abi_size_t i;
343 425 : NaClSrpcArg* args;
344 :
345 425 : if (vec == NULL) {
346 130 : return;
347 : }
348 295 : args = vec[0];
349 :
350 1202 : for (i = 0; i <= NACL_SRPC_MAX_ARGS; ++i) {
351 601 : if (vec[i] == NULL) {
352 295 : break;
353 : }
354 612 : switch (vec[i]->tag) {
355 : case NACL_SRPC_ARG_TYPE_BOOL:
356 : case NACL_SRPC_ARG_TYPE_DOUBLE:
357 : case NACL_SRPC_ARG_TYPE_HANDLE:
358 : case NACL_SRPC_ARG_TYPE_INT:
359 : case NACL_SRPC_ARG_TYPE_INVALID:
360 : case NACL_SRPC_ARG_TYPE_LONG:
361 : case NACL_SRPC_ARG_TYPE_OBJECT:
362 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
363 207 : break;
364 :
365 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
366 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
367 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
368 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
369 : case NACL_SRPC_ARG_TYPE_STRING:
370 99 : free(vec[i]->arrays.oval);
371 99 : break;
372 : }
373 306 : vec[i] = NULL;
374 306 : }
375 295 : free(args);
376 720 : }
377 :
378 65 : static ssize_t RecvRequest(struct NaClSrpcMessageChannel* channel,
379 65 : NaClSrpcRpc* rpc,
380 65 : NaClSrpcArg** inputs,
381 65 : NaClSrpcArg** results) {
382 65 : struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
383 65 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
384 65 : size_t iov_len;
385 65 : NaClSrpcMessageHeader header;
386 65 : NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
387 65 : size_t expected_bytes;
388 65 : ssize_t retval;
389 :
390 65 : NaClSrpcArgVectorInit(results);
391 65 : NaClSrpcArgVectorInit(inputs);
392 :
393 : /*
394 : * SrpcPeekMessage should have been called before this function, and should
395 : * have populated rpc. Make sure that rpc points to a sane header.
396 : */
397 195 : if (!rpc->is_request ||
398 : rpc->template_len > NACL_SRPC_MAX_ARGS ||
399 : rpc->value_len > NACL_SRPC_MAX_ARGS) {
400 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
401 : "RecvRequest: rpc header invalid: is_request %"NACL_PRIu32", "
402 : "template_len %"NACL_PRIu32", value_len %"NACL_PRIu32"\n",
403 : rpc->is_request,
404 : rpc->template_len,
405 : rpc->value_len);
406 0 : retval = -NACL_ABI_EINVAL;
407 0 : goto done;
408 : }
409 : /*
410 : * A request will contain two vectors of NaClSrpcArgs. Set the index
411 : * pointers passed in to new argument vectors that will be filled during
412 : * the next peek.
413 : */
414 65 : if (!AllocateArgs(results, rpc->template_len) ||
415 65 : !AllocateArgs(inputs, rpc->value_len)) {
416 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
417 : "RecvRequest: AllocateArgs failed\n");
418 0 : retval = -NACL_ABI_EINVAL;
419 0 : goto done;
420 : }
421 :
422 : /*
423 : * Having read the header we know how many elements each argument vector
424 : * contains. The next peek reads the fixed portion of these argument vectors,
425 : * but cannot yet read the variable length portion, because we do not yet
426 : * know the counts of array types or strings.
427 : */
428 65 : iov_len = 0;
429 65 : expected_bytes = 0;
430 65 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
431 65 : AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
432 : &expected_bytes);
433 65 : AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
434 65 : header.iov = iov;
435 65 : header.iov_length = (nacl_abi_size_t) iov_len;
436 65 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
437 65 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
438 65 : retval = NaClSrpcMessageChannelPeek(channel, &header);
439 65 : if (retval < (ssize_t) expected_bytes) {
440 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
441 : "RecvRequest:"
442 : "NaClSrpcMessageChannelPeek incomplete: expected %"
443 : NACL_PRIuS", got %"NACL_PRIdS"\n",
444 : expected_bytes,
445 : retval);
446 0 : retval = ErrnoFromImcRet(retval);
447 0 : goto done;
448 : }
449 :
450 : /*
451 : * After peeking the fixed portion of the argument vectors we are ready to
452 : * read the nonfixed portions as well. So the read just adds the IOV entries
453 : * for the nonfixed portions of the arguments.
454 : */
455 65 : iov_len = 0;
456 65 : expected_bytes = 0;
457 65 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
458 65 : ClearTemplateStringLengths(results, rpc->template_len);
459 65 : AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
460 : &expected_bytes);
461 65 : AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
462 65 : if (!AddNonfixedForRead(results, rpc->template_len, kMaxIovLen,
463 : 1, 0, iov, &iov_len, &expected_bytes)) {
464 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
465 : "RecvRequest: AllocateArgs failed for results\n");
466 0 : retval = -NACL_ABI_EIO;
467 0 : goto done;
468 : }
469 65 : if (!AddNonfixedForRead(inputs, rpc->value_len, kMaxIovLen,
470 : 1, 1, iov, &iov_len, &expected_bytes)) {
471 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
472 : "RecvRequest: AllocateArgs failed for inputs\n");
473 0 : retval = -NACL_ABI_EIO;
474 0 : goto done;
475 : }
476 65 : header.iov = iov;
477 65 : header.iov_length = (nacl_abi_size_t) iov_len;
478 65 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
479 65 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
480 65 : retval = NaClSrpcMessageChannelReceive(channel, &header);
481 65 : if (retval < (ssize_t) expected_bytes) {
482 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
483 : "RecvRequest:"
484 : " NaClSrpcMessageChannelReceive incomplete: expected %"
485 : NACL_PRIuS", got %"NACL_PRIdS"\n",
486 : expected_bytes,
487 : retval);
488 0 : retval = ErrnoFromImcRet(retval);
489 0 : goto done;
490 : }
491 :
492 : /*
493 : * The read left any descriptors passed in the descs array. We need to
494 : * copy those descriptors to the inputs vector.
495 : */
496 65 : if (!GetHandles(inputs, rpc->value_len,
497 : descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
498 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
499 : "RecvRequest: GetHandles failed\n");
500 0 : retval = -NACL_ABI_EIO;
501 0 : goto done;
502 : }
503 : /*
504 : * Success, the caller has taken ownership of the memory we allocated
505 : * for inputs and results.
506 : */
507 65 : inputs = NULL;
508 65 : results = NULL;
509 :
510 : done:
511 65 : FreeArgs(inputs);
512 65 : FreeArgs(results);
513 65 : return retval;
514 : }
515 :
516 : /*
517 : * Checks for type conformance between a peeked results vector and the caller's
518 : * results vector. If the types agree then nonfixed sizes are checked to
519 : * ensure that the caller's buffers are large enough to receive the peeked
520 : * nonfixed size objects. If this agrees, then the caller's size is updated
521 : * to reflect how many elements were actually received.
522 : */
523 169 : static BoolValue CheckMatchAndCopyCounts(size_t vec_len,
524 169 : NaClSrpcArg** expected,
525 169 : NaClSrpcArg** peeked) {
526 169 : size_t i;
527 :
528 754 : for (i = 0; i < vec_len; ++i) {
529 208 : if (expected[i]->tag != peeked[i]->tag) {
530 0 : return BoolFalse;
531 : }
532 416 : switch (expected[i]->tag) {
533 : case NACL_SRPC_ARG_TYPE_BOOL:
534 : case NACL_SRPC_ARG_TYPE_DOUBLE:
535 : case NACL_SRPC_ARG_TYPE_HANDLE:
536 : case NACL_SRPC_ARG_TYPE_INT:
537 : case NACL_SRPC_ARG_TYPE_INVALID:
538 : case NACL_SRPC_ARG_TYPE_LONG:
539 : case NACL_SRPC_ARG_TYPE_OBJECT:
540 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
541 145 : break;
542 :
543 : case NACL_SRPC_ARG_TYPE_STRING:
544 : /*
545 : * Returned strings are allocated by the SRPC transport mechanism,
546 : * whereas all the other "array" types are allocated by the caller
547 : * of the respective Invoke routine. The caller does allocate a
548 : * stub "template" string, which is strdup("") and needs to be freed.
549 : */
550 : {
551 3 : void *buffer = malloc(peeked[i]->u.count);
552 3 : if (buffer == NULL) {
553 0 : return BoolFalse;
554 : }
555 3 : free(expected[i]->arrays.oval);
556 3 : expected[i]->arrays.oval = buffer;
557 3 : expected[i]->u.count = peeked[i]->u.count;
558 : }
559 3 : break;
560 :
561 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
562 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
563 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
564 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
565 60 : if (peeked[i]->u.count > expected[i]->u.count) {
566 0 : return BoolFalse;
567 : }
568 60 : expected[i]->u.count = peeked[i]->u.count;
569 60 : break;
570 : }
571 208 : }
572 169 : return BoolTrue;
573 169 : }
574 :
575 169 : static ssize_t RecvResponse(struct NaClSrpcMessageChannel* channel,
576 169 : NaClSrpcRpc* rpc,
577 169 : NaClSrpcArg** results) {
578 169 : NaClSrpcArg* result_copy[NACL_SRPC_MAX_ARGS + 1];
579 169 : struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
580 169 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
581 169 : size_t iov_len = 0;
582 169 : NaClSrpcMessageHeader header;
583 169 : NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
584 169 : size_t expected_bytes;
585 169 : ssize_t retval;
586 169 : size_t i;
587 :
588 169 : NaClSrpcArgVectorInit(result_copy);
589 :
590 169 : if (results == NULL) {
591 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
592 : "RecvResponse: results should not be NULL\n");
593 0 : retval = -NACL_ABI_EINVAL;
594 0 : goto done;
595 : }
596 : /*
597 : * SrpcPeekMessage should have been called before this function, and should
598 : * have populated rpc. Make sure that rpc points to a sane header.
599 : */
600 676 : if (rpc->is_request ||
601 : rpc->template_len > 0 ||
602 : rpc->value_len > NACL_SRPC_MAX_ARGS ||
603 169 : rpc->value_len != VectorLen(results)) {
604 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
605 : "RecvResponse: rpc header invalid: is_request %"NACL_PRIu32", "
606 : "template_len %"NACL_PRIu32", value_len %"NACL_PRIu32"\n",
607 : rpc->is_request,
608 : rpc->template_len,
609 : rpc->value_len);
610 0 : retval = -NACL_ABI_EINVAL;
611 0 : goto done;
612 : }
613 :
614 : /*
615 : * Having read the header we know how many elements the results vector
616 : * contains. The next peek reads the fixed portion of the results vectors,
617 : * but cannot yet read the variable length portion, because we do not yet
618 : * know the counts of array types or strings. Because the results read
619 : * could conflict with the expected types, we need to read the fixed portion
620 : * into a copy.
621 : */
622 169 : if (!AllocateArgs(result_copy, rpc->value_len)) {
623 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
624 : "RecvResponse: AllocateArgs failed\n");
625 0 : retval = -NACL_ABI_EINVAL;
626 0 : goto done;
627 : }
628 169 : iov_len = 0;
629 169 : expected_bytes = 0;
630 169 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
631 754 : for (i = 0; i < rpc->value_len; ++i) {
632 208 : AddIovEntry(result_copy[i], kArgSize, kMaxIovLen, iov, &iov_len,
633 : &expected_bytes);
634 208 : }
635 169 : header.iov = iov;
636 169 : header.iov_length = (nacl_abi_size_t) iov_len;
637 169 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
638 169 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
639 169 : retval = NaClSrpcMessageChannelPeek(channel, &header);
640 169 : if (retval < (ssize_t) expected_bytes) {
641 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
642 : "RecvResponse: NaClSrpcMessageChannelPeek incomplete: "
643 : "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
644 : expected_bytes,
645 : retval);
646 0 : retval = ErrnoFromImcRet(retval);
647 0 : goto done;
648 : }
649 :
650 : /*
651 : * Check that the peeked results vector's types conform to the types passed
652 : * in and that any nonfixed size arguments are no larger than the counts
653 : * passed in from the caller. If the values are acceptable, we copy the
654 : * actual sizes to the caller's vector.
655 : */
656 169 : if (!CheckMatchAndCopyCounts(rpc->value_len, results, result_copy)) {
657 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
658 : "RecvResponse: CheckMatchAndCopyCounts failed\n");
659 0 : retval = -NACL_ABI_EIO;
660 0 : goto done;
661 : }
662 :
663 : /*
664 : * After peeking the fixed portion of the results vector we are ready to
665 : * read the nonfixed portion as well. So the read just adds the IOV entries
666 : * for the nonfixed portion of results.
667 : */
668 169 : iov_len = 0;
669 169 : expected_bytes = 0;
670 169 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
671 169 : AddFixed(results, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
672 169 : if (!AddNonfixedForRead(results, rpc->value_len, kMaxIovLen,
673 : 0, 1, iov, &iov_len, &expected_bytes)) {
674 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
675 : "RecvResponse: AddNonfixedForRead failed\n");
676 0 : retval = -NACL_ABI_EIO;
677 0 : goto done;
678 : }
679 169 : header.iov = iov;
680 169 : header.iov_length = (nacl_abi_size_t) iov_len;
681 169 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
682 169 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
683 169 : retval = NaClSrpcMessageChannelReceive(channel, &header);
684 169 : if (retval < (ssize_t) expected_bytes) {
685 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
686 : "RecvResponse: NaClSrpcMessageChannelReceive incomplete: "
687 : "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
688 : expected_bytes,
689 : retval);
690 0 : retval = ErrnoFromImcRet(retval);
691 0 : goto done;
692 : }
693 :
694 : /*
695 : * The read left any descriptors returned in the descs array. We need to
696 : * copy those descriptors to the results vector.
697 : */
698 169 : if (!GetHandles(results, rpc->value_len,
699 : descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
700 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
701 : "RecvResponse: GetHandles failed\n");
702 0 : retval = -NACL_ABI_EIO;
703 169 : }
704 :
705 : done:
706 169 : FreeArgs(result_copy);
707 169 : return retval;
708 : }
709 :
710 : /*
711 : * Adds IOV entries for the non-fixed portions of the arguments in vec.
712 : * This could also add handles/descriptors to the array to send.
713 : */
714 235 : static BoolValue AddNonfixedForWrite(NaClSrpcArg** vec,
715 235 : size_t vec_len,
716 235 : size_t max_iov_len,
717 235 : struct NaClImcMsgIoVec* iov,
718 235 : size_t* iov_len,
719 235 : NaClSrpcImcDescType* descs,
720 235 : size_t* desc_len,
721 235 : size_t* expected_bytes) {
722 235 : size_t i;
723 235 : size_t element_size;
724 235 : nacl_abi_size_t count;
725 235 : void* base;
726 :
727 : /* Add IOV entries for the array/string types in vec. */
728 880 : for (i = 0; i < vec_len; ++i) {
729 410 : switch (vec[i]->tag) {
730 : case NACL_SRPC_ARG_TYPE_BOOL:
731 : case NACL_SRPC_ARG_TYPE_DOUBLE:
732 : case NACL_SRPC_ARG_TYPE_INT:
733 : case NACL_SRPC_ARG_TYPE_INVALID:
734 : case NACL_SRPC_ARG_TYPE_LONG:
735 : case NACL_SRPC_ARG_TYPE_OBJECT:
736 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
737 : /* Scalar types are handled by fixed iovs alone. */
738 117 : break;
739 :
740 : case NACL_SRPC_ARG_TYPE_HANDLE:
741 : /* Handles are added into the desc array. */
742 35 : descs[*desc_len] = vec[i]->u.hval;
743 35 : ++*desc_len;
744 35 : break;
745 :
746 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
747 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
748 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
749 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
750 51 : count = vec[i]->u.count;
751 51 : base = vec[i]->arrays.oval;
752 51 : element_size = ArrayElementSize(vec[i]);
753 : /* Check that computing the number of bytes will not overflow. */
754 51 : if (SIZE_T_MAX / element_size < count) {
755 0 : return BoolFalse;
756 : }
757 51 : AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
758 : expected_bytes);
759 51 : break;
760 :
761 : case NACL_SRPC_ARG_TYPE_STRING:
762 2 : count = (nacl_abi_size_t) strlen(vec[i]->arrays.str) + 1;
763 2 : base = vec[i]->arrays.oval;
764 2 : vec[i]->u.count = count;
765 2 : AddIovEntry(base, count, max_iov_len, iov, iov_len, expected_bytes);
766 2 : break;
767 : }
768 205 : }
769 235 : return BoolTrue;
770 235 : }
771 :
772 235 : static ssize_t SrpcSendMessage(NaClSrpcRpc* rpc,
773 235 : NaClSrpcArg** inputs,
774 235 : NaClSrpcArg** results,
775 235 : struct NaClSrpcMessageChannel* channel) {
776 235 : NaClSrpcArg** values;
777 235 : struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
778 235 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
779 235 : size_t iov_len;
780 235 : NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
781 235 : size_t desc_len = 0;
782 235 : NaClSrpcMessageHeader header;
783 235 : ssize_t retval;
784 235 : size_t expected_bytes;
785 :
786 : /*
787 : * The message will be sent in three portions:
788 : * 1) the header (rpc)
789 : * 2) the fixed portions of the inputs and results arrays (inputs may be
790 : * null for responses)
791 : * 3) the nonfixed portions of the inputs or results array
792 : */
793 235 : iov_len = 0;
794 235 : expected_bytes = 0;
795 235 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
796 :
797 235 : if (rpc->is_request) {
798 : /*
799 : * For requests we pass only the fixed portion of the results vector.
800 : * This is to convey to the invoked procedure the type and size of the
801 : * allowed result values.
802 : * The values to be passed in both fixed and nonfixed are from inputs.
803 : */
804 172 : if (results == NULL) {
805 0 : rpc->template_len = 0;
806 0 : } else {
807 172 : rpc->template_len = VectorLen(results);
808 172 : AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
809 : &expected_bytes);
810 : }
811 172 : values = inputs;
812 172 : } else {
813 : /*
814 : * For responses there are no templates, and the values that will be passed
815 : * are from results.
816 : */
817 63 : values = results;
818 63 : rpc->template_len = 0;
819 : }
820 : /*
821 : * Pass the fixed and nonfixed portions.
822 : */
823 235 : if (values == NULL) {
824 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
825 : "SrpcSendMessage: values should not be NULL\n");
826 0 : return -NACL_ABI_EINVAL;
827 : }
828 235 : rpc->value_len = VectorLen(values);
829 235 : AddFixed(values, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
830 235 : if (!AddNonfixedForWrite(values, rpc->value_len,
831 : kMaxIovLen,
832 : iov, &iov_len,
833 : descs, &desc_len,
834 : &expected_bytes)) {
835 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
836 : "SrpcSendMessage: AddNonfixedForWrite failed\n");
837 0 : return -NACL_ABI_EIO;
838 : }
839 235 : header.iov = iov;
840 235 : header.iov_length = (nacl_abi_size_t) iov_len;
841 235 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
842 235 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) desc_len;
843 235 : retval = NaClSrpcMessageChannelSend(channel, &header);
844 470 : if (retval >= 0 && retval < (ssize_t) expected_bytes) {
845 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
846 : "SrpcSendMessage: NaClSrpcMessageChannelSend incomplete: "
847 : "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
848 : expected_bytes,
849 : retval);
850 0 : return -NACL_ABI_EIO;
851 : }
852 235 : return retval;
853 235 : }
854 :
855 : /* TODO(sehr): make this public when the client side uses RPC. */
856 260 : static BoolValue NaClSrpcRpcCtor(NaClSrpcRpc* rpc, NaClSrpcChannel* channel) {
857 260 : rpc->channel = channel;
858 260 : rpc->result = NACL_SRPC_RESULT_INTERNAL;
859 260 : rpc->rets = NULL;
860 260 : return BoolTrue;
861 : }
862 :
863 : /* A self-deleting closure to send responses from RPC servers. */
864 : typedef struct RpcCheckingClosure {
865 : struct NaClSrpcClosure base;
866 : NaClSrpcRpc* rpc;
867 : } RpcCheckingClosure;
868 :
869 63 : static void RpcCheckingClosureRun(NaClSrpcClosure* self) {
870 63 : RpcCheckingClosure* vself = (RpcCheckingClosure*) self;
871 63 : NaClSrpcRpc* rpc = vself->rpc;
872 63 : ssize_t retval;
873 :
874 63 : do {
875 63 : const char* rpc_name;
876 63 : const char* arg_types;
877 63 : const char* ret_types;
878 63 : int i;
879 63 : NaClSrpcServiceMethodNameAndTypes(rpc->channel->server,
880 : rpc->rpc_number,
881 : &rpc_name,
882 : &arg_types,
883 : &ret_types);
884 126 : NaClSrpcLog(1,
885 : "RpcCheckingClosureRun: response(channel=%p,"
886 : " rpc_number=%"NACL_PRIu32
887 : ", rpc_name=\"%s\", result=%d, string=\"%s\")\n",
888 : (void*) rpc->channel,
889 : rpc->rpc_number,
890 : rpc_name,
891 : rpc->result,
892 63 : NaClSrpcErrorString(rpc->result));
893 270 : for (i = 0; rpc->rets[i] != NULL; i++ ) {
894 72 : char buffer[256];
895 72 : NaClSrpcFormatArg(2, rpc->rets[i], buffer, NACL_ARRAY_SIZE(buffer));
896 72 : NaClSrpcLog(2,
897 : "RpcCheckingClosureRun: response(channel=%p, rets[%d]=%s)\n",
898 : (void*) rpc->channel,
899 : i,
900 : buffer);
901 72 : }
902 63 : } while(0);
903 : /* Send the RPC response to the caller. */
904 63 : rpc->is_request = 0;
905 63 : rpc->dispatch_loop_should_continue = 1;
906 63 : if (NACL_SRPC_RESULT_BREAK == rpc->result) {
907 0 : NaClSrpcLog(2,
908 : "RpcCheckingClosureRun: server requested break\n");
909 0 : rpc->result = NACL_SRPC_RESULT_OK;
910 0 : rpc->dispatch_loop_should_continue = 0;
911 0 : }
912 63 : retval = SrpcSendMessage(rpc, NULL, rpc->rets, rpc->channel->message_channel);
913 63 : if (retval < 0) {
914 : /* If the response write failed, drop request and continue. */
915 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
916 : "RpcCheckingClosureRun: response write failed\n");
917 0 : }
918 63 : free(self);
919 63 : }
920 :
921 260 : static BoolValue RpcCheckingClosureCtor(RpcCheckingClosure* self,
922 260 : NaClSrpcRpc* rpc) {
923 260 : self->base.Run = RpcCheckingClosureRun;
924 260 : self->rpc = rpc;
925 260 : self->rpc->dispatch_loop_should_continue = 1;
926 260 : return BoolTrue;
927 : }
928 :
929 65 : static BoolValue RequestVectorTypesConform(NaClSrpcChannel* channel,
930 65 : NaClSrpcRpc* rpc,
931 65 : NaClSrpcArg** args,
932 65 : NaClSrpcArg** rets) {
933 65 : const char* rpc_name;
934 65 : const char* arg_types;
935 65 : const char* ret_types;
936 65 : ssize_t retval;
937 65 : size_t i;
938 :
939 130 : if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
940 : rpc->template_len > NACL_SRPC_MAX_ARGS) {
941 0 : return BoolFalse;
942 : }
943 : /* Get service discovery's remembered types for args and rets */
944 65 : retval = NaClSrpcServiceMethodNameAndTypes(channel->server,
945 : rpc->rpc_number,
946 : &rpc_name,
947 : &arg_types,
948 : &ret_types);
949 65 : if (!retval) {
950 0 : return BoolFalse;
951 : }
952 : /* Check that lengths match. */
953 130 : if (rpc->value_len != strlen(arg_types) ||
954 65 : rpc->template_len != strlen(ret_types)) {
955 0 : return BoolFalse;
956 : }
957 : /* Check args for type conformance. */
958 182 : for (i = 0; i < rpc->value_len; ++i) {
959 26 : if (args[i] == NULL) {
960 0 : return BoolFalse;
961 : }
962 26 : if (args[i]->tag != (unsigned char) arg_types[i]) {
963 0 : return BoolFalse;
964 : }
965 26 : }
966 65 : if (args[rpc->value_len] != NULL) {
967 0 : return BoolFalse;
968 : }
969 : /* Check rets for type conformance. */
970 274 : for (i = 0; i < rpc->template_len; ++i) {
971 72 : if (rets[i] == NULL) {
972 0 : return BoolFalse;
973 : }
974 72 : if (rets[i]->tag != (unsigned char) ret_types[i]) {
975 0 : return BoolFalse;
976 : }
977 72 : }
978 65 : if (rets[rpc->template_len] != NULL) {
979 0 : return BoolFalse;
980 : }
981 65 : return BoolTrue;
982 65 : }
983 :
984 : /*
985 : * The receive/dispatch function returns an enum indicating how the enclosing
986 : * loop should proceed.
987 : */
988 : typedef enum {
989 : DISPATCH_CONTINUE, /* Continue receive-dispatch loop */
990 : DISPATCH_BREAK, /* Break out of loop was requested by invoked method */
991 : DISPATCH_RESPONSE, /* Instead of a request, we received a response */
992 : DISPATCH_EOF /* No more requests or responses can be received */
993 : } DispatchReturn;
994 :
995 260 : static DispatchReturn NaClSrpcReceiveAndDispatch(NaClSrpcChannel* channel,
996 260 : NaClSrpcRpc* rpc_stack_top) {
997 260 : NaClSrpcRpc rpc;
998 260 : NaClSrpcArg* args[NACL_SRPC_MAX_ARGS + 1];
999 260 : NaClSrpcArg* rets[NACL_SRPC_MAX_ARGS + 1];
1000 260 : NaClSrpcMethod method;
1001 260 : ssize_t bytes_read;
1002 260 : RpcCheckingClosure* closure = NULL;
1003 : /* DISPATCH_EOF is the closest we have to an error return. */
1004 260 : DispatchReturn dispatch_return = DISPATCH_EOF;
1005 :
1006 260 : NaClSrpcArgVectorInit(args);
1007 260 : NaClSrpcArgVectorInit(rets);
1008 :
1009 260 : closure = (RpcCheckingClosure*) malloc(sizeof *closure);
1010 260 : if (NULL == closure) {
1011 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1012 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1013 : "closure malloc failed\n",
1014 : (void*) channel);
1015 0 : dispatch_return = DISPATCH_EOF;
1016 0 : goto done;
1017 : }
1018 260 : if (!NaClSrpcRpcCtor(&rpc, channel) ||
1019 260 : !RpcCheckingClosureCtor(closure, &rpc)) {
1020 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1021 : "NaClSrpcReceiveAndDispatch(channel=%p): constructor failed\n",
1022 : (void*) channel);
1023 0 : goto done;
1024 : }
1025 253 : rpc.rets = rets;
1026 : /* Read a message from the channel. */
1027 253 : bytes_read = SrpcPeekMessage(channel->message_channel, &rpc);
1028 253 : if (bytes_read < 0) {
1029 19 : goto done;
1030 : }
1031 234 : if (rpc.is_request) {
1032 : /* This is a new request. */
1033 65 : if (NULL == channel->server) {
1034 0 : if (NULL == rpc_stack_top) {
1035 : /* There is no service to dispatch requests. Abort. */
1036 0 : dispatch_return = DISPATCH_EOF;
1037 0 : goto done;
1038 : } else {
1039 : /* Inform the pending invoke that a failure happened. */
1040 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1041 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1042 : "out of order request\n",
1043 : (void*) channel);
1044 0 : rpc_stack_top->result = NACL_SRPC_RESULT_INTERNAL;
1045 0 : dispatch_return = DISPATCH_BREAK;
1046 0 : goto done;
1047 : }
1048 : }
1049 : /* Fall through to request handling below. */
1050 65 : } else {
1051 : /* This is a response to a pending request. */
1052 169 : if (NULL == rpc_stack_top) {
1053 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1054 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1055 : "response, no pending request\n",
1056 : (void*) channel);
1057 : /* There is no pending request. Abort. */
1058 0 : dispatch_return = DISPATCH_BREAK;
1059 0 : goto done;
1060 : } else {
1061 169 : if (rpc.request_id == rpc_stack_top->request_id) {
1062 : /* Copy the serialized portion of the Rpc and process as a response. */
1063 507 : memcpy(rpc_stack_top, &rpc, kRpcSize);
1064 169 : dispatch_return = DISPATCH_RESPONSE;
1065 169 : goto done;
1066 : } else {
1067 : /* Received an out-of-order response. Abort. */
1068 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1069 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1070 : " response for wrong request\n",
1071 : (void*) channel);
1072 0 : dispatch_return = DISPATCH_BREAK;
1073 0 : goto done;
1074 : }
1075 : }
1076 : }
1077 65 : bytes_read = RecvRequest(channel->message_channel, &rpc, args, rets);
1078 65 : if (bytes_read < 0) {
1079 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1080 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1081 : "RecvRequest failed, bytes=%"NACL_PRIdS"\n",
1082 : (void*) channel,
1083 : bytes_read);
1084 0 : dispatch_return = DISPATCH_EOF;
1085 0 : }
1086 65 : if (!RequestVectorTypesConform(channel, &rpc, args, rets)) {
1087 0 : NaClSrpcLog(NACL_SRPC_LOG_WARNING,
1088 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1089 : " arg/ret type mismatch (recoverable error)\n",
1090 : (void*) channel);
1091 0 : dispatch_return = DISPATCH_CONTINUE;
1092 0 : goto done;
1093 : }
1094 : /* Then we invoke the method, which computes a return code. */
1095 65 : method = NaClSrpcServiceMethod(channel->server, rpc.rpc_number);
1096 65 : if (NULL == method) {
1097 0 : NaClSrpcLog(NACL_SRPC_LOG_WARNING,
1098 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1099 : " bad rpc_number %"NACL_PRIu32" (recoverable error)\n",
1100 : (void*) channel,
1101 : rpc.rpc_number);
1102 0 : dispatch_return = DISPATCH_CONTINUE;
1103 0 : goto done;
1104 : }
1105 65 : do {
1106 65 : const char* rpc_name;
1107 65 : const char* arg_types;
1108 65 : const char* ret_types;
1109 65 : int i;
1110 65 : NaClSrpcServiceMethodNameAndTypes(channel->server,
1111 : rpc.rpc_number,
1112 : &rpc_name,
1113 : &arg_types,
1114 : &ret_types);
1115 65 : NaClSrpcLog(1, "NaClSrpcReceiveAndDispatch:"
1116 : " request(channel=%p, rpc_number=%"NACL_PRIu32
1117 : ", rpc_name=\"%s\")\n",
1118 : (void*) channel,
1119 : rpc.rpc_number,
1120 : rpc_name);
1121 182 : for (i = 0; args[i] != NULL; i++ ) {
1122 26 : char buffer[256];
1123 26 : NaClSrpcFormatArg(2, args[i], buffer, NACL_ARRAY_SIZE(buffer));
1124 26 : NaClSrpcLog(2,
1125 : "NaClSrpcReceiveAndDispatch:"
1126 : " request(channel=%p, args[%d]=%s)\n",
1127 : (void*) channel,
1128 : i,
1129 : buffer);
1130 26 : }
1131 65 : } while(0);
1132 63 : (*method)(&rpc, args, rets, (NaClSrpcClosure*) closure);
1133 63 : FreeArgs(args);
1134 63 : FreeArgs(rets);
1135 : /* The invoked method takes ownership of the closure and deletes it. */
1136 63 : closure = NULL;
1137 : /*
1138 : * Return code to either continue or break out of the processing loop.
1139 : * When we separate closure invocation from the dispatch loop we will
1140 : * have to implement a barrier to make sure that all preceding RPCs are
1141 : * completed, and then signal the dispatcher to stop.
1142 : */
1143 63 : if (rpc.dispatch_loop_should_continue) {
1144 63 : dispatch_return = DISPATCH_CONTINUE;
1145 63 : } else {
1146 0 : dispatch_return = DISPATCH_BREAK;
1147 63 : }
1148 :
1149 : done:
1150 251 : free(closure);
1151 251 : return dispatch_return;
1152 : }
1153 :
1154 : /*
1155 : * After an RPC is sent, the current thread can block waiting for the
1156 : * response. As currently there is only one thread receiving messages,
1157 : * this thread will handle receiving and dispatching while waiting for
1158 : * its response. This allows for one thread to process calls back and
1159 : * forth between client and server, as required for the NPAPI main thread
1160 : * in Pepper.
1161 : */
1162 197 : void NaClSrpcRpcWait(NaClSrpcChannel* channel,
1163 197 : NaClSrpcRpc* rpc) {
1164 197 : DispatchReturn retval;
1165 :
1166 : /*
1167 : * Loop receiving RPCs and processing them.
1168 : * The loop stops when the receive/dispatch function returns.
1169 : */
1170 197 : do {
1171 260 : retval = NaClSrpcReceiveAndDispatch(channel, rpc);
1172 511 : } while (DISPATCH_CONTINUE == retval);
1173 : /* Process responses */
1174 188 : NaClSrpcLog(2,
1175 : "NaClSrpcRpcWait(channel=%p): loop done: %p, %d\n",
1176 : (void*) channel,
1177 : (void*) rpc,
1178 : retval);
1179 188 : if (NULL == rpc) {
1180 16 : NaClSrpcLog(2,
1181 : "NaClSrpcRpcWait(channel=%p):"
1182 : " rpc is NULL (this is not an error)\n",
1183 : (void*) channel);
1184 16 : return;
1185 : }
1186 172 : if (DISPATCH_RESPONSE == retval) {
1187 169 : ssize_t recv_ret = RecvResponse(channel->message_channel, rpc, rpc->rets);
1188 169 : if (recv_ret < 0) {
1189 0 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1190 : "NaClSrpcRpcWait(channel=%p): rpc receive failed (%"
1191 : NACL_PRIdS")\n",
1192 : (void*) channel,
1193 : recv_ret);
1194 0 : rpc->result = NACL_SRPC_RESULT_INTERNAL;
1195 0 : return;
1196 : }
1197 172 : } else if (DISPATCH_EOF == retval) {
1198 3 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1199 : "NaClSrpcRpcWait(channel=%p):"
1200 : " EOF is received instead of response. Probably, the other"
1201 : " side (usually, nacl module or browser plugin) crashed.\n",
1202 : (void*) channel);
1203 3 : rpc->result = NACL_SRPC_RESULT_INTERNAL;
1204 3 : }
1205 188 : }
1206 :
1207 172 : int NaClSrpcRequestWrite(NaClSrpcChannel* channel,
1208 172 : NaClSrpcRpc* rpc,
1209 172 : NaClSrpcArg** args,
1210 172 : NaClSrpcArg** rets) {
1211 172 : ssize_t retval;
1212 172 : rpc->is_request = 1;
1213 172 : retval = SrpcSendMessage(rpc, args, rets, channel->message_channel);
1214 172 : if (retval < 0) {
1215 : /* Requests with bad handles could fail. Report to the caller. */
1216 0 : NaClSrpcLog(1,
1217 : "NaClSrpcRequestWrite(channel=%p, retval=%"NACL_PRIu32
1218 : ") failed\n",
1219 : (void*) channel,
1220 : rpc->rpc_number);
1221 0 : return 0;
1222 : }
1223 172 : return 1;
1224 172 : }
|