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 2 : static ssize_t ErrnoFromImcRet(ssize_t imc_ret) {
102 2 : if (0 > imc_ret) {
103 2 : return imc_ret;
104 : } else {
105 0 : return -NACL_ABI_EIO;
106 : }
107 2 : }
108 :
109 : static void AddIovEntry(void* base,
110 : size_t length,
111 : size_t max_iov_len,
112 : struct NaClImcMsgIoVec* iov,
113 : size_t* iov_len,
114 2 : size_t* total_bytes) {
115 2 : if (length == 0) {
116 0 : return;
117 : }
118 2 : if (*iov_len >= max_iov_len) {
119 0 : return;
120 : }
121 2 : iov[*iov_len].base = base;
122 2 : iov[*iov_len].length = length;
123 2 : ++*iov_len;
124 2 : *total_bytes += length;
125 2 : }
126 :
127 2 : static nacl_abi_size_t VectorLen(NaClSrpcArg** vec) {
128 2 : nacl_abi_size_t len = 0;
129 2 : for (len = 0; len <= NACL_SRPC_MAX_ARGS; ++len) {
130 2 : if (vec[len] == NULL) {
131 2 : return len;
132 : }
133 2 : }
134 0 : return NACL_SRPC_MAX_ARGS;
135 2 : }
136 :
137 2 : static size_t ArrayElementSize(NaClSrpcArg* arg) {
138 2 : 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 1 : return 0;
149 :
150 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
151 2 : return sizeof *arg->arrays.carr;
152 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
153 0 : return sizeof *arg->arrays.darr;
154 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
155 0 : return sizeof *arg->arrays.iarr;
156 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
157 0 : return sizeof *arg->arrays.larr;
158 : case NACL_SRPC_ARG_TYPE_STRING:
159 0 : return sizeof *arg->arrays.str;
160 : }
161 : /* UNREACHED */
162 0 : return 0;
163 2 : }
164 :
165 : static void ClearTemplateStringLengths(NaClSrpcArg** vec,
166 2 : size_t vec_len) {
167 : size_t i;
168 2 : for (i = 0; i < vec_len; ++i) {
169 2 : if (vec[i]->tag == NACL_SRPC_ARG_TYPE_STRING) {
170 0 : vec[i]->u.count = 0;
171 : }
172 2 : }
173 2 : }
174 :
175 : /*
176 : * Adds the IOV entries for the fixed portion of the arguments in vec.
177 : */
178 : static void AddFixed(NaClSrpcArg** vec,
179 : size_t vec_len,
180 : size_t max_iov_len,
181 : struct NaClImcMsgIoVec* iov,
182 : size_t* iov_len,
183 2 : size_t* expected_bytes) {
184 : size_t i;
185 2 : for (i = 0; i < vec_len; ++i) {
186 2 : AddIovEntry(vec[i], kArgSize, max_iov_len, iov, iov_len, expected_bytes);
187 2 : }
188 2 : }
189 :
190 : /*
191 : * Copies the handles/descriptors from descs into the appropriately typed
192 : * elements of vec.
193 : */
194 : static BoolValue GetHandles(NaClSrpcArg** vec,
195 : size_t vec_len,
196 : NaClSrpcImcDescType* descs,
197 2 : size_t desc_len) {
198 : size_t i;
199 2 : size_t handle_index = 0;
200 2 : for (i = 0; i < vec_len; ++i) {
201 2 : if (vec[i]->tag != NACL_SRPC_ARG_TYPE_HANDLE) {
202 2 : continue;
203 : }
204 0 : if (handle_index >= desc_len) {
205 0 : return BoolFalse;
206 : }
207 0 : vec[i]->u.hval = descs[handle_index];
208 0 : ++handle_index;
209 0 : }
210 2 : return BoolTrue;
211 2 : }
212 :
213 : /*
214 : * Reads the header of the message to determine whether to call RecvRequest or
215 : * RecvResponse.
216 : */
217 : static ssize_t SrpcPeekMessage(struct NaClSrpcMessageChannel* channel,
218 2 : NaClSrpcRpc* rpc) {
219 : struct NaClImcMsgIoVec iov[1];
220 2 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
221 : size_t iov_len;
222 : NaClSrpcMessageHeader header;
223 : size_t expected_bytes;
224 : ssize_t retval;
225 :
226 2 : iov_len = 0;
227 2 : expected_bytes = 0;
228 2 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
229 2 : header.iov = iov;
230 2 : header.iov_length = NACL_ARRAY_SIZE(iov);
231 2 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
232 2 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
233 2 : retval = NaClSrpcMessageChannelPeek(channel, &header);
234 : /*
235 : * Check that the peek read the RPC and that the argument lengths are sane.
236 : */
237 2 : if (retval < (ssize_t) expected_bytes) {
238 2 : retval = ErrnoFromImcRet(retval);
239 : }
240 2 : else if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
241 2 : rpc->template_len > NACL_SRPC_MAX_ARGS) {
242 0 : retval = -NACL_ABI_EIO;
243 : }
244 2 : return retval;
245 2 : }
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 : static BoolValue AddNonfixedForRead(NaClSrpcArg** vec,
258 : size_t vec_len,
259 : size_t max_iov_len,
260 : BoolValue alloc_value,
261 : BoolValue read_value,
262 : struct NaClImcMsgIoVec* iov,
263 : size_t* iov_len,
264 2 : size_t* expected_bytes) {
265 : size_t i;
266 :
267 : /* Initialize the array pointers to allow cleanup if errors happen. */
268 2 : if (alloc_value) {
269 2 : for (i = 0; i < vec_len; ++i) {
270 2 : vec[i]->arrays.oval = NULL;
271 2 : }
272 : }
273 :
274 2 : for (i = 0; i < vec_len; ++i) {
275 2 : size_t count = vec[i]->u.count;
276 2 : void* base = 0;
277 2 : size_t element_size = ArrayElementSize(vec[i]);
278 :
279 2 : if (element_size == 0) {
280 : /* Skip fixed size arguments. */
281 1 : continue;
282 : }
283 2 : if (SIZE_T_MAX / element_size < count) {
284 0 : return BoolFalse;
285 : }
286 2 : base = vec[i]->arrays.oval;
287 2 : if (alloc_value) {
288 2 : base = malloc(element_size * count);
289 2 : if (base == 0) {
290 0 : return BoolFalse;
291 : }
292 2 : vec[i]->arrays.oval = base;
293 : }
294 2 : if (read_value) {
295 : AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
296 2 : expected_bytes);
297 : }
298 2 : }
299 2 : return BoolTrue;
300 2 : }
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 2 : static void NaClSrpcArgVectorInit(NaClSrpcArg** arg_pointers) {
308 2 : arg_pointers[0] = NULL;
309 2 : }
310 :
311 2 : static BoolValue AllocateArgs(NaClSrpcArg** arg_pointers, size_t length) {
312 : NaClSrpcArg* arg_array;
313 : nacl_abi_size_t i;
314 :
315 : /* Initialize the array pointers to allow cleanup if errors happen. */
316 2 : for (i = 0; i < length + 1; ++i) {
317 2 : arg_pointers[i] = NULL;
318 2 : }
319 2 : if (length == 0) {
320 2 : return BoolTrue;
321 : }
322 :
323 2 : if (SIZE_T_MAX / sizeof **arg_pointers < length) {
324 0 : return BoolFalse;
325 : }
326 2 : arg_array = (NaClSrpcArg*) malloc(length * sizeof **arg_pointers);
327 2 : if (arg_array == NULL) {
328 0 : return BoolFalse;
329 : }
330 : /* Initialize the individual args. */
331 2 : for (i = 0; i < length; ++i) {
332 2 : NaClSrpcArgCtor(&arg_array[i]);
333 2 : }
334 : /* Set each array pointer to point to the respective arg. */
335 2 : for (i = 0; i < length; ++i) {
336 2 : arg_pointers[i] = &arg_array[i];
337 2 : }
338 2 : return BoolTrue;
339 2 : }
340 :
341 2 : static void FreeArgs(NaClSrpcArg** vec) {
342 : nacl_abi_size_t i;
343 : NaClSrpcArg* args;
344 :
345 2 : if (vec == NULL) {
346 2 : return;
347 : }
348 2 : args = vec[0];
349 :
350 2 : for (i = 0; i <= NACL_SRPC_MAX_ARGS; ++i) {
351 2 : if (vec[i] == NULL) {
352 2 : break;
353 : }
354 2 : 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 : 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 2 : free(vec[i]->arrays.oval);
371 : break;
372 : }
373 2 : vec[i] = NULL;
374 2 : }
375 2 : free(args);
376 2 : }
377 :
378 : static ssize_t RecvRequest(struct NaClSrpcMessageChannel* channel,
379 : NaClSrpcRpc* rpc,
380 : NaClSrpcArg** inputs,
381 2 : NaClSrpcArg** results) {
382 : struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
383 2 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
384 : size_t iov_len;
385 : NaClSrpcMessageHeader header;
386 : NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
387 : size_t expected_bytes;
388 : ssize_t retval;
389 :
390 2 : NaClSrpcArgVectorInit(results);
391 2 : 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 : if (!rpc->is_request ||
398 : rpc->template_len > NACL_SRPC_MAX_ARGS ||
399 2 : rpc->value_len > NACL_SRPC_MAX_ARGS) {
400 : 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 0 : 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 : if (!AllocateArgs(results, rpc->template_len) ||
415 2 : !AllocateArgs(inputs, rpc->value_len)) {
416 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
417 0 : "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 2 : iov_len = 0;
429 2 : expected_bytes = 0;
430 2 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
431 : AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
432 2 : &expected_bytes);
433 2 : AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
434 2 : header.iov = iov;
435 2 : header.iov_length = (nacl_abi_size_t) iov_len;
436 2 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
437 2 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
438 2 : retval = NaClSrpcMessageChannelPeek(channel, &header);
439 2 : if (retval < (ssize_t) expected_bytes) {
440 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
441 : "RecvRequest:"
442 : "NaClSrpcMessageChannelPeek incomplete: expected %"
443 : NACL_PRIuS", got %"NACL_PRIdS"\n",
444 : expected_bytes,
445 0 : 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 2 : iov_len = 0;
456 2 : expected_bytes = 0;
457 2 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
458 2 : ClearTemplateStringLengths(results, rpc->template_len);
459 : AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
460 2 : &expected_bytes);
461 2 : AddFixed(inputs, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
462 : if (!AddNonfixedForRead(results, rpc->template_len, kMaxIovLen,
463 2 : 1, 0, iov, &iov_len, &expected_bytes)) {
464 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
465 0 : "RecvRequest: AllocateArgs failed for results\n");
466 0 : retval = -NACL_ABI_EIO;
467 0 : goto done;
468 : }
469 : if (!AddNonfixedForRead(inputs, rpc->value_len, kMaxIovLen,
470 2 : 1, 1, iov, &iov_len, &expected_bytes)) {
471 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
472 0 : "RecvRequest: AllocateArgs failed for inputs\n");
473 0 : retval = -NACL_ABI_EIO;
474 0 : goto done;
475 : }
476 2 : header.iov = iov;
477 2 : header.iov_length = (nacl_abi_size_t) iov_len;
478 2 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
479 2 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
480 2 : retval = NaClSrpcMessageChannelReceive(channel, &header);
481 2 : if (retval < (ssize_t) expected_bytes) {
482 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
483 : "RecvRequest:"
484 : " NaClSrpcMessageChannelReceive incomplete: expected %"
485 : NACL_PRIuS", got %"NACL_PRIdS"\n",
486 : expected_bytes,
487 0 : 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 : if (!GetHandles(inputs, rpc->value_len,
497 2 : descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
498 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
499 0 : "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 2 : inputs = NULL;
508 2 : results = NULL;
509 :
510 : done:
511 2 : FreeArgs(inputs);
512 2 : FreeArgs(results);
513 2 : return retval;
514 2 : }
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 : static BoolValue CheckMatchAndCopyCounts(size_t vec_len,
524 : NaClSrpcArg** expected,
525 2 : NaClSrpcArg** peeked) {
526 : size_t i;
527 :
528 2 : for (i = 0; i < vec_len; ++i) {
529 2 : if (expected[i]->tag != peeked[i]->tag) {
530 0 : return BoolFalse;
531 : }
532 2 : 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 : 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 0 : void *buffer = malloc(peeked[i]->u.count);
552 0 : if (buffer == NULL) {
553 0 : return BoolFalse;
554 : }
555 0 : free(expected[i]->arrays.oval);
556 0 : expected[i]->arrays.oval = buffer;
557 0 : expected[i]->u.count = peeked[i]->u.count;
558 : }
559 0 : 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 2 : if (peeked[i]->u.count > expected[i]->u.count) {
566 0 : return BoolFalse;
567 : }
568 2 : expected[i]->u.count = peeked[i]->u.count;
569 : break;
570 : }
571 2 : }
572 2 : return BoolTrue;
573 2 : }
574 :
575 : static ssize_t RecvResponse(struct NaClSrpcMessageChannel* channel,
576 : NaClSrpcRpc* rpc,
577 2 : NaClSrpcArg** results) {
578 : NaClSrpcArg* result_copy[NACL_SRPC_MAX_ARGS + 1];
579 : struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
580 2 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
581 2 : size_t iov_len = 0;
582 : NaClSrpcMessageHeader header;
583 : NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
584 : size_t expected_bytes;
585 : ssize_t retval;
586 : size_t i;
587 :
588 2 : NaClSrpcArgVectorInit(result_copy);
589 :
590 2 : if (results == NULL) {
591 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
592 0 : "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 : if (rpc->is_request ||
601 : rpc->template_len > 0 ||
602 : rpc->value_len > NACL_SRPC_MAX_ARGS ||
603 2 : rpc->value_len != VectorLen(results)) {
604 : 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 0 : 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 2 : if (!AllocateArgs(result_copy, rpc->value_len)) {
623 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
624 0 : "RecvResponse: AllocateArgs failed\n");
625 0 : retval = -NACL_ABI_EINVAL;
626 0 : goto done;
627 : }
628 2 : iov_len = 0;
629 2 : expected_bytes = 0;
630 2 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
631 2 : for (i = 0; i < rpc->value_len; ++i) {
632 : AddIovEntry(result_copy[i], kArgSize, kMaxIovLen, iov, &iov_len,
633 2 : &expected_bytes);
634 2 : }
635 2 : header.iov = iov;
636 2 : header.iov_length = (nacl_abi_size_t) iov_len;
637 2 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = NULL;
638 2 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = 0;
639 2 : retval = NaClSrpcMessageChannelPeek(channel, &header);
640 2 : if (retval < (ssize_t) expected_bytes) {
641 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
642 : "RecvResponse: NaClSrpcMessageChannelPeek incomplete: "
643 : "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
644 : expected_bytes,
645 0 : 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 2 : if (!CheckMatchAndCopyCounts(rpc->value_len, results, result_copy)) {
657 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
658 0 : "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 2 : iov_len = 0;
669 2 : expected_bytes = 0;
670 2 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
671 2 : AddFixed(results, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
672 : if (!AddNonfixedForRead(results, rpc->value_len, kMaxIovLen,
673 2 : 0, 1, iov, &iov_len, &expected_bytes)) {
674 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
675 0 : "RecvResponse: AddNonfixedForRead failed\n");
676 0 : retval = -NACL_ABI_EIO;
677 0 : goto done;
678 : }
679 2 : header.iov = iov;
680 2 : header.iov_length = (nacl_abi_size_t) iov_len;
681 2 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
682 2 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = NACL_ARRAY_SIZE(descs);
683 2 : retval = NaClSrpcMessageChannelReceive(channel, &header);
684 2 : if (retval < (ssize_t) expected_bytes) {
685 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
686 : "RecvResponse: NaClSrpcMessageChannelReceive incomplete: "
687 : "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
688 : expected_bytes,
689 0 : 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 : if (!GetHandles(results, rpc->value_len,
699 2 : descs, header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH)) {
700 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
701 0 : "RecvResponse: GetHandles failed\n");
702 0 : retval = -NACL_ABI_EIO;
703 : }
704 :
705 : done:
706 2 : FreeArgs(result_copy);
707 2 : return retval;
708 2 : }
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 : static BoolValue AddNonfixedForWrite(NaClSrpcArg** vec,
715 : size_t vec_len,
716 : size_t max_iov_len,
717 : struct NaClImcMsgIoVec* iov,
718 : size_t* iov_len,
719 : NaClSrpcImcDescType* descs,
720 : size_t* desc_len,
721 2 : size_t* expected_bytes) {
722 : size_t i;
723 : size_t element_size;
724 : nacl_abi_size_t count;
725 : void* base;
726 :
727 : /* Add IOV entries for the array/string types in vec. */
728 2 : for (i = 0; i < vec_len; ++i) {
729 2 : 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 : break;
739 :
740 : case NACL_SRPC_ARG_TYPE_HANDLE:
741 : /* Handles are added into the desc array. */
742 0 : descs[*desc_len] = vec[i]->u.hval;
743 0 : ++*desc_len;
744 0 : 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 2 : count = vec[i]->u.count;
751 2 : base = vec[i]->arrays.oval;
752 2 : element_size = ArrayElementSize(vec[i]);
753 : /* Check that computing the number of bytes will not overflow. */
754 2 : if (SIZE_T_MAX / element_size < count) {
755 0 : return BoolFalse;
756 : }
757 : AddIovEntry(base, element_size * count, max_iov_len, iov, iov_len,
758 2 : expected_bytes);
759 2 : break;
760 :
761 : case NACL_SRPC_ARG_TYPE_STRING:
762 0 : count = (nacl_abi_size_t) strlen(vec[i]->arrays.str) + 1;
763 0 : base = vec[i]->arrays.oval;
764 0 : vec[i]->u.count = count;
765 0 : AddIovEntry(base, count, max_iov_len, iov, iov_len, expected_bytes);
766 : break;
767 : }
768 2 : }
769 2 : return BoolTrue;
770 2 : }
771 :
772 : static ssize_t SrpcSendMessage(NaClSrpcRpc* rpc,
773 : NaClSrpcArg** inputs,
774 : NaClSrpcArg** results,
775 2 : struct NaClSrpcMessageChannel* channel) {
776 : NaClSrpcArg** values;
777 : struct NaClImcMsgIoVec iov[IOV_ENTRY_MAX];
778 2 : const size_t kMaxIovLen = NACL_ARRAY_SIZE(iov);
779 : size_t iov_len;
780 : NaClSrpcImcDescType descs[NACL_SRPC_MAX_ARGS];
781 2 : size_t desc_len = 0;
782 : NaClSrpcMessageHeader header;
783 : ssize_t retval;
784 : 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 2 : iov_len = 0;
794 2 : expected_bytes = 0;
795 2 : AddIovEntry(rpc, kRpcSize, kMaxIovLen, iov, &iov_len, &expected_bytes);
796 :
797 2 : 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 2 : if (results == NULL) {
805 0 : rpc->template_len = 0;
806 0 : } else {
807 2 : rpc->template_len = VectorLen(results);
808 : AddFixed(results, rpc->template_len, kMaxIovLen, iov, &iov_len,
809 2 : &expected_bytes);
810 : }
811 2 : values = inputs;
812 2 : } else {
813 : /*
814 : * For responses there are no templates, and the values that will be passed
815 : * are from results.
816 : */
817 2 : values = results;
818 2 : rpc->template_len = 0;
819 : }
820 : /*
821 : * Pass the fixed and nonfixed portions.
822 : */
823 2 : if (values == NULL) {
824 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
825 0 : "SrpcSendMessage: values should not be NULL\n");
826 0 : return -NACL_ABI_EINVAL;
827 : }
828 2 : rpc->value_len = VectorLen(values);
829 2 : AddFixed(values, rpc->value_len, kMaxIovLen, iov, &iov_len, &expected_bytes);
830 : if (!AddNonfixedForWrite(values, rpc->value_len,
831 : kMaxIovLen,
832 : iov, &iov_len,
833 : descs, &desc_len,
834 2 : &expected_bytes)) {
835 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
836 0 : "SrpcSendMessage: AddNonfixedForWrite failed\n");
837 0 : return -NACL_ABI_EIO;
838 : }
839 2 : header.iov = iov;
840 2 : header.iov_length = (nacl_abi_size_t) iov_len;
841 2 : header.NACL_SRPC_MESSAGE_HEADER_DESCV = descs;
842 2 : header.NACL_SRPC_MESSAGE_HEADER_DESC_LENGTH = (nacl_abi_size_t) desc_len;
843 2 : retval = NaClSrpcMessageChannelSend(channel, &header);
844 2 : if (retval >= 0 && retval < (ssize_t) expected_bytes) {
845 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
846 : "SrpcSendMessage: NaClSrpcMessageChannelSend incomplete: "
847 : "expected %"NACL_PRIuS", got %"NACL_PRIdS"\n",
848 : expected_bytes,
849 0 : retval);
850 0 : return -NACL_ABI_EIO;
851 : }
852 2 : return retval;
853 2 : }
854 :
855 : /* TODO(sehr): make this public when the client side uses RPC. */
856 2 : static BoolValue NaClSrpcRpcCtor(NaClSrpcRpc* rpc, NaClSrpcChannel* channel) {
857 2 : rpc->channel = channel;
858 2 : rpc->result = NACL_SRPC_RESULT_INTERNAL;
859 2 : rpc->rets = NULL;
860 2 : return BoolTrue;
861 2 : }
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 2 : static void RpcCheckingClosureRun(NaClSrpcClosure* self) {
870 2 : RpcCheckingClosure* vself = (RpcCheckingClosure*) self;
871 2 : NaClSrpcRpc* rpc = vself->rpc;
872 : ssize_t retval;
873 :
874 : do {
875 : const char* rpc_name;
876 : const char* arg_types;
877 : const char* ret_types;
878 : int i;
879 : NaClSrpcServiceMethodNameAndTypes(rpc->channel->server,
880 : rpc->rpc_number,
881 : &rpc_name,
882 : &arg_types,
883 2 : &ret_types);
884 : 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 2 : NaClSrpcErrorString(rpc->result));
893 2 : for (i = 0; rpc->rets[i] != NULL; i++ ) {
894 : char buffer[256];
895 2 : NaClSrpcFormatArg(2, rpc->rets[i], buffer, NACL_ARRAY_SIZE(buffer));
896 : NaClSrpcLog(2,
897 : "RpcCheckingClosureRun: response(channel=%p, rets[%d]=%s)\n",
898 : (void*) rpc->channel,
899 : i,
900 2 : buffer);
901 2 : }
902 2 : } while(0);
903 : /* Send the RPC response to the caller. */
904 2 : rpc->is_request = 0;
905 2 : rpc->dispatch_loop_should_continue = 1;
906 2 : if (NACL_SRPC_RESULT_BREAK == rpc->result) {
907 : NaClSrpcLog(2,
908 0 : "RpcCheckingClosureRun: server requested break\n");
909 0 : rpc->result = NACL_SRPC_RESULT_OK;
910 0 : rpc->dispatch_loop_should_continue = 0;
911 : }
912 2 : retval = SrpcSendMessage(rpc, NULL, rpc->rets, rpc->channel->message_channel);
913 2 : if (retval < 0) {
914 : /* If the response write failed, drop request and continue. */
915 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
916 0 : "RpcCheckingClosureRun: response write failed\n");
917 : }
918 2 : free(self);
919 2 : }
920 :
921 : static BoolValue RpcCheckingClosureCtor(RpcCheckingClosure* self,
922 2 : NaClSrpcRpc* rpc) {
923 2 : self->base.Run = RpcCheckingClosureRun;
924 2 : self->rpc = rpc;
925 2 : self->rpc->dispatch_loop_should_continue = 1;
926 2 : return BoolTrue;
927 2 : }
928 :
929 : static BoolValue RequestVectorTypesConform(NaClSrpcChannel* channel,
930 : NaClSrpcRpc* rpc,
931 : NaClSrpcArg** args,
932 2 : NaClSrpcArg** rets) {
933 : const char* rpc_name;
934 : const char* arg_types;
935 : const char* ret_types;
936 : ssize_t retval;
937 : size_t i;
938 :
939 : if (rpc->value_len > NACL_SRPC_MAX_ARGS ||
940 2 : rpc->template_len > NACL_SRPC_MAX_ARGS) {
941 0 : return BoolFalse;
942 : }
943 : /* Get service discovery's remembered types for args and rets */
944 : retval = NaClSrpcServiceMethodNameAndTypes(channel->server,
945 : rpc->rpc_number,
946 : &rpc_name,
947 : &arg_types,
948 2 : &ret_types);
949 2 : if (!retval) {
950 0 : return BoolFalse;
951 : }
952 : /* Check that lengths match. */
953 : if (rpc->value_len != strlen(arg_types) ||
954 2 : rpc->template_len != strlen(ret_types)) {
955 0 : return BoolFalse;
956 : }
957 : /* Check args for type conformance. */
958 2 : for (i = 0; i < rpc->value_len; ++i) {
959 1 : if (args[i] == NULL) {
960 0 : return BoolFalse;
961 : }
962 1 : if (args[i]->tag != (unsigned char) arg_types[i]) {
963 0 : return BoolFalse;
964 : }
965 1 : }
966 2 : if (args[rpc->value_len] != NULL) {
967 0 : return BoolFalse;
968 : }
969 : /* Check rets for type conformance. */
970 2 : for (i = 0; i < rpc->template_len; ++i) {
971 2 : if (rets[i] == NULL) {
972 0 : return BoolFalse;
973 : }
974 2 : if (rets[i]->tag != (unsigned char) ret_types[i]) {
975 0 : return BoolFalse;
976 : }
977 2 : }
978 2 : if (rets[rpc->template_len] != NULL) {
979 0 : return BoolFalse;
980 : }
981 2 : return BoolTrue;
982 2 : }
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 : static DispatchReturn NaClSrpcReceiveAndDispatch(NaClSrpcChannel* channel,
996 2 : NaClSrpcRpc* rpc_stack_top) {
997 : NaClSrpcRpc rpc;
998 : NaClSrpcArg* args[NACL_SRPC_MAX_ARGS + 1];
999 : NaClSrpcArg* rets[NACL_SRPC_MAX_ARGS + 1];
1000 : NaClSrpcMethod method;
1001 : ssize_t bytes_read;
1002 2 : RpcCheckingClosure* closure = NULL;
1003 : /* DISPATCH_EOF is the closest we have to an error return. */
1004 2 : DispatchReturn dispatch_return = DISPATCH_EOF;
1005 :
1006 2 : NaClSrpcArgVectorInit(args);
1007 2 : NaClSrpcArgVectorInit(rets);
1008 :
1009 2 : closure = (RpcCheckingClosure*) malloc(sizeof *closure);
1010 2 : if (NULL == closure) {
1011 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1012 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1013 : "closure malloc failed\n",
1014 0 : (void*) channel);
1015 0 : dispatch_return = DISPATCH_EOF;
1016 0 : goto done;
1017 : }
1018 : if (!NaClSrpcRpcCtor(&rpc, channel) ||
1019 2 : !RpcCheckingClosureCtor(closure, &rpc)) {
1020 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1021 : "NaClSrpcReceiveAndDispatch(channel=%p): constructor failed\n",
1022 0 : (void*) channel);
1023 0 : goto done;
1024 : }
1025 2 : rpc.rets = rets;
1026 : /* Read a message from the channel. */
1027 2 : bytes_read = SrpcPeekMessage(channel->message_channel, &rpc);
1028 2 : if (bytes_read < 0) {
1029 2 : goto done;
1030 : }
1031 2 : if (rpc.is_request) {
1032 : /* This is a new request. */
1033 2 : 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 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1041 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1042 : "out of order request\n",
1043 0 : (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 2 : } else {
1051 : /* This is a response to a pending request. */
1052 2 : if (NULL == rpc_stack_top) {
1053 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1054 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1055 : "response, no pending request\n",
1056 0 : (void*) channel);
1057 : /* There is no pending request. Abort. */
1058 0 : dispatch_return = DISPATCH_BREAK;
1059 0 : goto done;
1060 : } else {
1061 2 : if (rpc.request_id == rpc_stack_top->request_id) {
1062 : /* Copy the serialized portion of the Rpc and process as a response. */
1063 2 : memcpy(rpc_stack_top, &rpc, kRpcSize);
1064 2 : dispatch_return = DISPATCH_RESPONSE;
1065 2 : goto done;
1066 : } else {
1067 : /* Received an out-of-order response. Abort. */
1068 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1069 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1070 : " response for wrong request\n",
1071 0 : (void*) channel);
1072 0 : dispatch_return = DISPATCH_BREAK;
1073 0 : goto done;
1074 : }
1075 : }
1076 : }
1077 2 : bytes_read = RecvRequest(channel->message_channel, &rpc, args, rets);
1078 2 : if (bytes_read < 0) {
1079 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1080 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1081 : "RecvRequest failed, bytes=%"NACL_PRIdS"\n",
1082 : (void*) channel,
1083 0 : bytes_read);
1084 0 : dispatch_return = DISPATCH_EOF;
1085 : }
1086 2 : if (!RequestVectorTypesConform(channel, &rpc, args, rets)) {
1087 : NaClSrpcLog(NACL_SRPC_LOG_WARNING,
1088 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1089 : " arg/ret type mismatch (recoverable error)\n",
1090 0 : (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 2 : method = NaClSrpcServiceMethod(channel->server, rpc.rpc_number);
1096 2 : if (NULL == method) {
1097 : NaClSrpcLog(NACL_SRPC_LOG_WARNING,
1098 : "NaClSrpcReceiveAndDispatch(channel=%p):"
1099 : " bad rpc_number %"NACL_PRIu32" (recoverable error)\n",
1100 : (void*) channel,
1101 0 : rpc.rpc_number);
1102 0 : dispatch_return = DISPATCH_CONTINUE;
1103 0 : goto done;
1104 : }
1105 : do {
1106 : const char* rpc_name;
1107 : const char* arg_types;
1108 : const char* ret_types;
1109 : int i;
1110 : NaClSrpcServiceMethodNameAndTypes(channel->server,
1111 : rpc.rpc_number,
1112 : &rpc_name,
1113 : &arg_types,
1114 2 : &ret_types);
1115 : NaClSrpcLog(1, "NaClSrpcReceiveAndDispatch:"
1116 : " request(channel=%p, rpc_number=%"NACL_PRIu32
1117 : ", rpc_name=\"%s\")\n",
1118 : (void*) channel,
1119 : rpc.rpc_number,
1120 2 : rpc_name);
1121 2 : for (i = 0; args[i] != NULL; i++ ) {
1122 : char buffer[256];
1123 1 : NaClSrpcFormatArg(2, args[i], buffer, NACL_ARRAY_SIZE(buffer));
1124 : NaClSrpcLog(2,
1125 : "NaClSrpcReceiveAndDispatch:"
1126 : " request(channel=%p, args[%d]=%s)\n",
1127 : (void*) channel,
1128 : i,
1129 1 : buffer);
1130 1 : }
1131 2 : } while(0);
1132 2 : (*method)(&rpc, args, rets, (NaClSrpcClosure*) closure);
1133 2 : FreeArgs(args);
1134 2 : FreeArgs(rets);
1135 : /* The invoked method takes ownership of the closure and deletes it. */
1136 2 : 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 2 : if (rpc.dispatch_loop_should_continue) {
1144 2 : dispatch_return = DISPATCH_CONTINUE;
1145 2 : } else {
1146 0 : dispatch_return = DISPATCH_BREAK;
1147 : }
1148 :
1149 : done:
1150 2 : free(closure);
1151 2 : return dispatch_return;
1152 2 : }
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 : void NaClSrpcRpcWait(NaClSrpcChannel* channel,
1163 2 : NaClSrpcRpc* rpc) {
1164 : DispatchReturn retval;
1165 :
1166 : /*
1167 : * Loop receiving RPCs and processing them.
1168 : * The loop stops when the receive/dispatch function returns.
1169 : */
1170 : do {
1171 2 : retval = NaClSrpcReceiveAndDispatch(channel, rpc);
1172 2 : } while (DISPATCH_CONTINUE == retval);
1173 : /* Process responses */
1174 : NaClSrpcLog(2,
1175 : "NaClSrpcRpcWait(channel=%p): loop done: %p, %d\n",
1176 : (void*) channel,
1177 : (void*) rpc,
1178 2 : retval);
1179 2 : if (NULL == rpc) {
1180 : NaClSrpcLog(2,
1181 : "NaClSrpcRpcWait(channel=%p):"
1182 : " rpc is NULL (this is not an error)\n",
1183 2 : (void*) channel);
1184 2 : return;
1185 : }
1186 2 : if (DISPATCH_RESPONSE == retval) {
1187 2 : ssize_t recv_ret = RecvResponse(channel->message_channel, rpc, rpc->rets);
1188 2 : if (recv_ret < 0) {
1189 : NaClSrpcLog(NACL_SRPC_LOG_ERROR,
1190 : "NaClSrpcRpcWait(channel=%p): rpc receive failed (%"
1191 : NACL_PRIdS")\n",
1192 : (void*) channel,
1193 0 : recv_ret);
1194 0 : rpc->result = NACL_SRPC_RESULT_INTERNAL;
1195 0 : return;
1196 2 : }
1197 0 : } else if (DISPATCH_EOF == retval) {
1198 : 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 0 : (void*) channel);
1203 0 : rpc->result = NACL_SRPC_RESULT_INTERNAL;
1204 : }
1205 2 : }
1206 :
1207 : int NaClSrpcRequestWrite(NaClSrpcChannel* channel,
1208 : NaClSrpcRpc* rpc,
1209 : NaClSrpcArg** args,
1210 2 : NaClSrpcArg** rets) {
1211 : ssize_t retval;
1212 2 : rpc->is_request = 1;
1213 2 : retval = SrpcSendMessage(rpc, args, rets, channel->message_channel);
1214 2 : if (retval < 0) {
1215 : /* Requests with bad handles could fail. Report to the caller. */
1216 : NaClSrpcLog(1,
1217 : "NaClSrpcRequestWrite(channel=%p, retval=%"NACL_PRIu32
1218 : ") failed\n",
1219 : (void*) channel,
1220 0 : rpc->rpc_number);
1221 0 : return 0;
1222 : }
1223 2 : return 1;
1224 2 : }
|