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