Merge branch 'upstream'
[nativeclient.git] / tools / libsrpc / rpc_serialize.c
blob192a79caf58a419b6ca26fcea4a5e6784edd690a
1 /*
2 * Copyright 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * NaCl simple RPC over IMC mechanism.
37 #include "nacl_srpc.h"
38 #include "nacl_srpc_internal.h"
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <errno.h>
43 #include <sys/types.h>
46 * Message formats:
47 * SRPC communicates using two main message types, requests and responses.
48 * Both are encoded with variable sizes, according to the table.
50 * Request
51 * protocol - 4 bytes
52 * rpc method index - 4 bytes
53 * #args - 4 bytes
54 * #args * (arg value) - varying size
55 * #rets - 4 bytes
56 * #rets * (arg template) - varying size
58 * Response
59 * protocol - 4 bytes
60 * return code - 4 bytes
61 * #rets - 4 bytes
62 * #rets * (arg value) - varying size
64 * Sub-messages:
66 * arg value:
67 * type - 1 byte
68 * union
69 * bool - 1 byte
70 * int - 4 bytes
71 * double - 8 bytes
72 * string
73 * length - 4 bytes
74 * value - (length) * 1 bytes ('\0' is not sent)
75 * char array
76 * length - 4 bytes
77 * value - (length) * 1 bytes
78 * int array
79 * length - 4 bytes
80 * value - (length) * 4 bytes
81 * double array
82 * length - 4 bytes
83 * value - (length) * 8 bytes
84 * descriptor handle
85 * (work in progress)
87 * arg template:
88 * type - 1 byte
89 * union
90 * bool - 0 bytes
91 * int - 0 bytes
92 * double - 0 bytes
93 * string - 0 bytes
94 * char array
95 * length - 4 bytes
96 * int array
97 * length - 4 bytes
98 * double array
99 * length - 4 bytes
100 * descriptor handle
101 * (work in progress)
106 * Support for timing the SRPC infrastructure.
108 static NaClSrpcError GetTimes(NaClSrpcChannel* channel,
109 NaClSrpcArg** in_args,
110 NaClSrpcArg** out_args);
111 static NaClSrpcError SetTimingEnabled(NaClSrpcChannel* channel,
112 NaClSrpcArg** in_args,
113 NaClSrpcArg** out_args);
117 * The high level APIs provided for external use.
119 NaClSrpcError NaClSrpcReceiveAndDispatch(NaClSrpcChannel* channel) {
120 NaClSrpcArg* args[NACL_SRPC_MAX_ARGS+1];
121 NaClSrpcArg* rets[NACL_SRPC_MAX_ARGS+1];
122 const char* in_types;
123 const char* out_types;
124 uint32_t rpc_number;
125 NaClSrpcError retval;
126 NaClSrpcError app_error;
127 int client_protocol;
128 int return_break = 0;
129 double this_start_usec = 0.0;
130 double this_method_usec;
133 * If we are timing, get the start time.
135 if (channel->timing_enabled) {
136 this_start_usec = __NaClSrpcGetUsec();
140 * First we receive the parameters for the method
142 dprintf(("SERVER: receiving RPC request\n"));
143 retval = __NaClSrpcImcRead(&client_protocol,
144 sizeof(client_protocol),
146 channel);
147 if (retval != 1) {
148 dprintf(("SERVER: RPC protocol version read failed: %d\n", retval));
149 return NACL_SRPC_RESULT_INTERNAL;
151 if (client_protocol != kSrpcProtocolVersion) {
152 dprintf(("SERVER: client protocol %x does not match server %x\n",
153 client_protocol, kSrpcProtocolVersion));
154 return NACL_SRPC_RESULT_PROTOCOL_MISMATCH;
156 dprintf(("SERVER: protocol versions matched\n"));
157 retval = __NaClSrpcImcRead(&rpc_number, sizeof(rpc_number), 1, channel);
158 if (retval != 1) {
159 dprintf(("SERVER: RPC rpc_number read error: %d %d\n", retval, errno));
160 perror("fread");
161 return NACL_SRPC_RESULT_INTERNAL;
163 dprintf(("SERVER: rpc number %u\n", (unsigned) rpc_number));
164 if (rpc_number == NACL_SRPC_SHUTDOWN_METHOD) {
165 in_types = "";
166 out_types = "";
167 } else if (rpc_number == NACL_SRPC_GET_TIMES_METHOD) {
168 in_types = "";
169 out_types = "dddd";
170 } else if (rpc_number == NACL_SRPC_TOGGLE_CHANNEL_TIMING_METHOD) {
171 in_types = "";
172 out_types = "i";
173 } else if (rpc_number >= channel->rpc_count) {
174 dprintf(("SERVER: RPC bad rpc number: %u not in [0, %u)\n",
175 (unsigned) rpc_number, (unsigned) channel->rpc_count));
176 return NACL_SRPC_RESULT_BAD_RPC_NUMBER;
177 } else {
178 in_types = channel->rpc_descr[rpc_number].in_args;
179 out_types = channel->rpc_descr[rpc_number].out_args;
181 if ((retval = __NaClSrpcArgsGet(channel, 1, 1, args, in_types))
182 != NACL_SRPC_RESULT_OK) {
183 dprintf(("SERVER: argument vector receive failed: %d\n", retval));
184 return retval;
186 dprintf(("SERVER: argument vector received\n"));
187 if ((retval = __NaClSrpcArgsGet(channel, 1, 0, rets, out_types))
188 != NACL_SRPC_RESULT_OK) {
189 dprintf(("SERVER: return descriptor receive failed: %d, %s\n", retval,
190 NaClSrpcErrorString(retval)));
191 return retval;
193 dprintf(("SERVER: received RPC request\n"));
196 * Then we invoke the method, which computes a return code.
198 dprintf(("SERVER: invoking RPC %u\n", (unsigned) rpc_number));
199 if (NACL_SRPC_SHUTDOWN_METHOD == rpc_number) {
200 app_error = NACL_SRPC_RESULT_SHUTDOWN;
201 } else if (NACL_SRPC_GET_TIMES_METHOD == rpc_number) {
202 app_error = GetTimes(channel, args, rets);
203 } else if (NACL_SRPC_TOGGLE_CHANNEL_TIMING_METHOD == rpc_number) {
204 app_error = SetTimingEnabled(channel, args, rets);
205 } else {
206 dprintf(("SERVER: handler %p\n", channel->rpc_descr[rpc_number].handler));
207 app_error = (channel->rpc_descr[rpc_number].handler)(channel, args, rets);
208 if (NACL_SRPC_RESULT_BREAK == app_error) {
209 return_break = 1;
210 app_error = NACL_SRPC_RESULT_OK;
213 dprintf(("SERVER: performed RPC\n"));
216 * Then we return the response
218 dprintf(("SERVER: sending response\n"));
219 __NaClSrpcImcWrite(&kSrpcProtocolVersion,
220 sizeof(kSrpcProtocolVersion),
222 channel);
223 dprintf(("SERVER: sent protocol version\n"));
224 __NaClSrpcImcWrite(&app_error, sizeof(app_error), 1, channel);
225 dprintf(("SERVER: RPC returned code %d\n", app_error));
226 if ((retval = __NaClSrpcArgsPut(channel, 1, rets)) != NACL_SRPC_RESULT_OK) {
227 dprintf(("SERVER: return value(s) send failed: %d\n", retval));
228 return retval;
230 dprintf(("SERVER: return value(s) sent\n"));
231 __NaClSrpcImcFlush(channel);
232 dprintf(("SERVER: sent response\n"));
235 * Then we free any memory that might have been allocated for array-typed
236 * arguments or returns.
238 __NaClSrpcArgsFree(args);
239 __NaClSrpcArgsFree(rets);
240 dprintf(("SERVER: freed memory\n"));
243 * If we are timing, collect the current time, compute the delta from
244 * the start, and update the cumulative counter.
246 if (channel->timing_enabled) {
247 this_method_usec = __NaClSrpcGetUsec();
248 channel->receive_usec += this_method_usec;
251 if (NACL_SRPC_SHUTDOWN_METHOD == rpc_number ||
252 NACL_SRPC_RESULT_SHUTDOWN == app_error) {
253 return NACL_SRPC_RESULT_SHUTDOWN;
254 } else if (return_break) {
255 return NACL_SRPC_RESULT_BREAK;
256 } else {
257 return NACL_SRPC_RESULT_OK;
261 void __NaClSrpcArgsFree(NaClSrpcArg* argvec[]) {
262 NaClSrpcArg** argvecp;
264 for (argvecp = argvec; *argvecp != NULL; ++argvecp) {
265 switch ((*argvecp)->tag) {
266 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
267 free((*argvecp)->u.caval.carr);
268 break;
269 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
270 free((*argvecp)->u.daval.darr);
271 break;
272 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
273 free((*argvecp)->u.iaval.iarr);
274 break;
275 case NACL_SRPC_ARG_TYPE_INVALID:
276 case NACL_SRPC_ARG_TYPE_BOOL:
277 case NACL_SRPC_ARG_TYPE_DOUBLE:
278 case NACL_SRPC_ARG_TYPE_HANDLE:
279 case NACL_SRPC_ARG_TYPE_INT:
280 break;
281 case NACL_SRPC_ARG_TYPE_STRING:
282 free((*argvecp)->u.sval);
283 break;
285 * The two cases below are added to avoid warnings, they are only used
286 * in the plugin code
288 case NACL_SRPC_ARG_TYPE_OBJECT:
289 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
290 default:
291 break;
294 free(argvec[0]);
297 char* NaClSrpcErrorString(NaClSrpcError error_code) {
298 switch (error_code) {
299 case NACL_SRPC_RESULT_OK:
300 return "No error";
301 case NACL_SRPC_RESULT_BREAK:
302 return "Break out of server RPC loop";
303 case NACL_SRPC_RESULT_SHUTDOWN:
304 return "Connection shut down by other end";
305 case NACL_SRPC_RESULT_INTERNAL:
306 return "Internal error in rpc method";
307 case NACL_SRPC_RESULT_BAD_SERVICE_DISCOVERY:
308 return "Service discovery failed";
309 case NACL_SRPC_RESULT_BAD_RPC_NUMBER:
310 return "No method for the given rpc number";
311 case NACL_SRPC_RESULT_BAD_ARG_TYPE:
312 return "Bad argument type received";
313 case NACL_SRPC_RESULT_TOO_MANY_ARGS:
314 return "Too many arguments (more than NACL_SRPC_MAX_ARGS or declared)";
315 case NACL_SRPC_RESULT_TOO_FEW_ARGS:
316 return "Too few arguments (fewer than declared)";
317 case NACL_SRPC_RESULT_IN_ARG_TYPE_MISMATCH:
318 return "Input argument type mismatch";
319 case NACL_SRPC_RESULT_OUT_ARG_TYPE_MISMATCH:
320 return "Output argument type mismatch";
321 case NACL_SRPC_RESULT_NO_MEMORY:
322 return "Out of memory";
323 case NACL_SRPC_RESULT_APP_ERROR:
324 return "Rpc application returned an error";
325 case NACL_SRPC_RESULT_STRING_OUTPUT:
326 return "Strings may not be used as output arguments";
327 case NACL_SRPC_RESULT_EOF_ON_STREAM:
328 return "End of file encountered";
329 case NACL_SRPC_RESULT_PROTOCOL_MISMATCH:
330 return "Client and server have different protocol versions";
332 return "Unrecognized NaClSrpcError value";
336 * Static function definitions.
338 NaClSrpcError __NaClSrpcArgsGet(NaClSrpcChannel* channel,
339 int allocate_args,
340 int read_values,
341 NaClSrpcArg* argvec[],
342 const char* arg_types) {
343 uint32_t dim;
344 int length;
345 NaClSrpcArg *args;
346 int retval = NACL_SRPC_RESULT_OK;
347 int i = 0; /* must be initialized here to get proper error handling. */
349 retval = __NaClSrpcImcRead(&length, sizeof(length), 1, channel);
350 if (retval != 1) {
351 return NACL_SRPC_RESULT_INTERNAL;
353 if (length >= NACL_SRPC_MAX_ARGS) {
355 * It is an error if the argument length exceeds the length of the
356 * vector passed in.
358 return NACL_SRPC_RESULT_TOO_MANY_ARGS;
361 dprintf(("GET: length %d\n", length));
363 if (allocate_args && length > 0) {
364 int i;
366 args = (NaClSrpcArg*) malloc(length * sizeof(NaClSrpcArg));
367 if (args == NULL) {
368 retval = NACL_SRPC_RESULT_NO_MEMORY;
369 goto error;
371 memset((void*) args, 0, length * sizeof(NaClSrpcArg));
374 * Initialize the arg type tags with those specified in the declaration.
376 for (i = 0; i < length; ++i) {
377 if (arg_types[i] == ':' || arg_types[i] == '\0') {
378 return NACL_SRPC_RESULT_TOO_MANY_ARGS;
380 args[i].tag = arg_types[i];
382 if (arg_types[length] == ':' && arg_types[length] == '\0') {
383 return NACL_SRPC_RESULT_TOO_FEW_ARGS;
385 } else {
386 args = argvec[0];
389 for (; i < length; ++i) {
390 char read_type;
392 retval = __NaClSrpcImcRead(&read_type, sizeof(char), 1, channel);
393 if (retval != 1) {
394 retval = NACL_SRPC_RESULT_INTERNAL;
395 goto error;
397 if (args[i].tag != read_type) {
398 dprintf(("arg[%d]: tag %d, expected %d\n", i, read_type, args[i].tag));
399 retval = NACL_SRPC_RESULT_BAD_ARG_TYPE;
400 goto error;
403 argvec[i] = args + i;
405 switch (args[i].tag) {
406 case NACL_SRPC_ARG_TYPE_INVALID:
407 retval = NACL_SRPC_RESULT_BAD_ARG_TYPE;
408 goto error;
409 case NACL_SRPC_ARG_TYPE_BOOL:
410 if (read_values) {
411 retval = __NaClSrpcImcRead(&args[i].u.bval, sizeof(char), 1, channel);
412 if (retval != 1) {
413 retval = NACL_SRPC_RESULT_INTERNAL;
414 goto error;
417 dprintf(("value %d\n", args[i].u.bval));
418 break;
419 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
420 retval = __NaClSrpcImcRead(&dim, sizeof(dim), 1, channel);
421 if (retval != 1) {
422 retval = NACL_SRPC_RESULT_INTERNAL;
423 goto error;
425 dprintf(("dim %u\n", (unsigned) dim));
426 if (allocate_args) {
427 args[i].u.caval.carr = (char*) malloc(dim * sizeof(char));
428 if (args[i].u.caval.carr == NULL) {
429 retval = NACL_SRPC_RESULT_NO_MEMORY;
430 goto error;
432 args[i].u.caval.count = dim;
433 } else {
434 if (args[i].u.caval.count < dim) {
435 return NACL_SRPC_RESULT_TOO_MANY_ARGS;
438 if (read_values) {
439 retval = __NaClSrpcImcRead(args[i].u.caval.carr, 1, dim, channel);
440 if (retval != dim) {
441 return NACL_SRPC_RESULT_INTERNAL;
444 break;
445 case NACL_SRPC_ARG_TYPE_DOUBLE:
446 if (read_values) {
447 retval = __NaClSrpcImcRead(&args[i].u.dval, sizeof(double), 1, channel);
448 if (retval != 1) {
449 return NACL_SRPC_RESULT_INTERNAL;
452 dprintf(("value %f\n", args[i].u.dval));
453 break;
454 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
455 retval = __NaClSrpcImcRead(&dim, sizeof(dim), 1, channel);
456 if (retval != 1) {
457 retval = NACL_SRPC_RESULT_INTERNAL;
458 goto error;
460 dprintf(("dim %u\n", (unsigned) dim));
461 if (allocate_args) {
462 args[i].u.daval.darr = (double*) malloc(dim * sizeof(double));
463 if (args[i].u.daval.darr == NULL) {
464 retval = NACL_SRPC_RESULT_NO_MEMORY;
465 goto error;
467 args[i].u.daval.count = dim;
468 } else {
469 if (args[i].u.daval.count < dim) {
470 return NACL_SRPC_RESULT_TOO_MANY_ARGS;
473 if (read_values) {
474 retval = __NaClSrpcImcRead(args[i].u.daval.darr,
475 sizeof(double),
476 dim,
477 channel);
478 if (retval != dim) {
479 return NACL_SRPC_RESULT_INTERNAL;
482 break;
483 case NACL_SRPC_ARG_TYPE_HANDLE:
484 if (read_values) {
485 args[i].u.hval = __NaClSrpcImcReadDesc(channel);
487 break;
488 case NACL_SRPC_ARG_TYPE_INT:
489 if (read_values) {
490 retval = __NaClSrpcImcRead(&args[i].u.ival, sizeof(int), 1, channel);
491 if (retval != 1) {
492 return NACL_SRPC_RESULT_INTERNAL;
495 dprintf(("value %d\n", args[i].u.ival));
496 break;
497 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
498 retval = __NaClSrpcImcRead(&dim, sizeof(dim), 1, channel);
499 if (retval != 1) {
500 retval = NACL_SRPC_RESULT_INTERNAL;
501 goto error;
503 dprintf(("dim %u\n", (unsigned) dim));
504 if (allocate_args) {
505 args[i].u.iaval.iarr = (int*) malloc(dim * sizeof(int));
506 if (args[i].u.iaval.iarr == NULL) {
507 retval = NACL_SRPC_RESULT_NO_MEMORY;
508 goto error;
510 args[i].u.iaval.count = dim;
511 } else {
512 if (args[i].u.iaval.count < dim) {
513 return NACL_SRPC_RESULT_TOO_MANY_ARGS;
516 if (read_values) {
517 retval = __NaClSrpcImcRead(args[i].u.iaval.iarr,
518 sizeof(int),
519 dim,
520 channel);
521 if (retval != dim) {
522 return NACL_SRPC_RESULT_INTERNAL;
525 break;
526 case NACL_SRPC_ARG_TYPE_STRING:
527 if (read_values) {
528 retval = __NaClSrpcImcRead(&dim, sizeof(dim), 1, channel);
529 if (retval != 1) {
530 retval = NACL_SRPC_RESULT_INTERNAL;
531 goto error;
533 args[i].u.sval = (char*) malloc(dim + 1);
534 if (args[i].u.sval == NULL) {
535 retval = NACL_SRPC_RESULT_NO_MEMORY;
536 goto error;
538 retval = __NaClSrpcImcRead(args[i].u.sval, sizeof(char), dim, channel);
539 if (retval != dim) {
540 retval = NACL_SRPC_RESULT_INTERNAL;
541 goto error;
543 args[i].u.sval[dim] = '\0';
545 break;
547 * The two cases below are added to avoid warnings, they are only used
548 * in the plugin code
550 case NACL_SRPC_ARG_TYPE_OBJECT:
551 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
552 default:
553 retval = NACL_SRPC_RESULT_BAD_ARG_TYPE;
554 goto error;
557 argvec[length] = NULL;
558 return NACL_SRPC_RESULT_OK;
559 error:
560 if (args != NULL) {
561 __NaClSrpcArgsFree(argvec);
563 return retval;
566 NaClSrpcError __NaClSrpcArgsPut(NaClSrpcChannel* channel,
567 int write_values,
568 NaClSrpcArg* argvec[]) {
569 int i;
570 int length;
571 size_t slen;
572 NaClSrpcArg* arg;
574 for (length = 0; argvec[length] != NULL; ++length);
575 if (length >= NACL_SRPC_MAX_ARGS) {
577 * It is an error if the argument length exceeds the length of the
578 * vector passed in.
580 return NACL_SRPC_RESULT_TOO_MANY_ARGS;
582 __NaClSrpcImcWrite(&length, sizeof(length), 1, channel);
583 dprintf(("PUT: length %d\n", length));
585 for (i = 0; i < length; ++i) {
586 arg = argvec[i];
587 __NaClSrpcImcWrite(&arg->tag, sizeof(char), 1, channel);
589 dprintf(("PUT: arg[%d]: tag %d, ", i, arg->tag));
591 switch (arg->tag) {
592 case NACL_SRPC_ARG_TYPE_INVALID:
593 break;
594 case NACL_SRPC_ARG_TYPE_BOOL:
595 dprintf(("value %d\n", arg->u.bval));
596 if (write_values) {
597 __NaClSrpcImcWrite(&arg->u.bval, sizeof(char), 1, channel);
599 break;
600 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
601 dprintf(("dim %u\n", (unsigned) arg->u.caval.count));
602 __NaClSrpcImcWrite(&arg->u.caval.count, sizeof(uint32_t), 1, channel);
603 dprintf(("PUT: sent length, carr = %p\n", arg->u.caval.carr));
604 if (write_values) {
605 __NaClSrpcImcWrite(arg->u.caval.carr, 1, arg->u.caval.count, channel);
607 break;
608 case NACL_SRPC_ARG_TYPE_DOUBLE:
609 dprintf(("value %f\n", arg->u.dval));
610 if (write_values) {
611 __NaClSrpcImcWrite(&arg->u.dval, sizeof(double), 1, channel);
613 break;
614 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
615 dprintf(("dim %u\n", (unsigned) arg->u.daval.count));
616 __NaClSrpcImcWrite(&arg->u.daval.count, sizeof(uint32_t), 1, channel);
617 dprintf(("PUT: sent length, darr = %p\n", arg->u.daval.darr));
618 if (write_values) {
619 __NaClSrpcImcWrite(arg->u.daval.darr,
620 sizeof(double),
621 arg->u.daval.count,
622 channel);
624 break;
625 case NACL_SRPC_ARG_TYPE_HANDLE:
626 dprintf(("value %d\n", (int) arg->u.hval));
627 if (write_values) {
628 __NaClSrpcImcWriteDesc(channel, arg->u.hval);
630 break;
631 case NACL_SRPC_ARG_TYPE_INT:
632 dprintf(("value %d\n", arg->u.ival));
633 if (write_values) {
634 __NaClSrpcImcWrite(&arg->u.ival, sizeof(int), 1, channel);
636 break;
637 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
638 dprintf(("dim %u\n", (unsigned) arg->u.iaval.count));
639 __NaClSrpcImcWrite(&arg->u.iaval.count, sizeof(uint32_t), 1, channel);
640 dprintf(("PUT: sent length, iarr = %p\n", arg->u.iaval.iarr));
641 if (write_values) {
642 __NaClSrpcImcWrite(arg->u.iaval.iarr,
643 sizeof(int),
644 arg->u.iaval.count,
645 channel);
647 break;
648 case NACL_SRPC_ARG_TYPE_STRING:
649 if (write_values) {
650 slen = strlen(arg->u.sval);
651 dprintf(("strlen %u\n", (unsigned) slen));
652 __NaClSrpcImcWrite(&slen, sizeof(slen), 1, channel);
653 __NaClSrpcImcWrite(arg->u.sval, 1, strlen(arg->u.sval), channel);
655 break;
657 * The two cases below are added to avoid warnings, they are only used
658 * in the plugin code
660 case NACL_SRPC_ARG_TYPE_OBJECT:
661 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
662 default:
663 break;
665 dprintf(("PUT: sent value\n"));
667 return NACL_SRPC_RESULT_OK;
670 static NaClSrpcError GetTimes(NaClSrpcChannel* channel,
671 NaClSrpcArg** in_args,
672 NaClSrpcArg** out_args)
674 NaClSrpcGetTimes(channel,
675 &out_args[0]->u.dval,
676 &out_args[1]->u.dval,
677 &out_args[2]->u.dval,
678 &out_args[3]->u.dval);
679 return NACL_SRPC_RESULT_OK;
682 static NaClSrpcError SetTimingEnabled(NaClSrpcChannel* channel,
683 NaClSrpcArg** in_args,
684 NaClSrpcArg** out_args)
686 NaClSrpcToggleChannelTiming(channel, in_args[0]->u.ival);
687 return NACL_SRPC_RESULT_OK;
690 void NaClSrpcToggleChannelTiming(NaClSrpcChannel* channel, int enable_timing) {
691 channel->timing_enabled = enable_timing;
694 void NaClSrpcGetTimes(NaClSrpcChannel* channel,
695 double* send_time,
696 double* receive_time,
697 double* imc_read_time,
698 double* imc_write_time) {
699 *send_time = channel->send_usec;
700 *receive_time = channel->receive_usec;
701 *imc_read_time = channel->imc_read_usec;
702 *imc_write_time = channel->imc_write_usec;