Block remapping or unmapping code mappings
[nativeclient.git] / tools / libsrpc / rpc_universal.c
blob27bf939cf69b898b620ced52adecb797982f2465
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 testing shell (ported to RPC library)
37 #include <assert.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <ctype.h>
42 #include <sys/types.h>
43 #include <sys/time.h>
45 #if !NACL_WINDOWS
46 #include <unistd.h>
47 #endif
49 #include "nacl_srpc.h"
50 #include "nacl_srpc_internal.h"
52 int __GetRpcNum(const NaClSrpcDesc* rpc_desc, int num_rpc, char const* name) {
53 int i;
54 for (i = 0; i < num_rpc; ++i) {
55 if (!strcmp(name, rpc_desc[i].rpc_name)) {
56 return i;
59 return -1;
62 /* simple destructive tokenizer */
63 typedef struct {
64 const char* start;
65 int length;
66 } TOKEN;
69 /* expects *from to point to leading \" and returns pointer to trailing \" */
70 const char* __ScanEscapeString(char* to, const char* from) {
71 assert (*from == '\"');
72 from++;
73 while (*from) {
74 if (*from == '\"') {
75 if (to) *to = '\0';
76 return from;
77 }else if (*from != '\\') {
78 if (to) *to++ = *from;
79 from++;
80 } else {
81 char next = *from++;
82 switch(next) {
83 case '\0':
84 return 0;
85 case '\\':
86 case '\"':
87 if (to) *to++ = next;
88 break;
89 case 'n':
90 if (to) *to++ = '\n';
91 break;
92 default:
93 return 0;
97 return 0;
100 int __Tokenize(char* line, TOKEN *array, int n) {
101 int pos_start = 0;
102 int count = 0;
104 for( ; count < n; count++ ) {
105 int pos_end;
107 /* skip leading white space */
108 while (line[pos_start]) {
109 const char c = line[pos_start];
110 if (isspace(c)) {
111 pos_start++;
112 } else {
113 break;
117 if (!line[pos_start]) break;
119 /* find token end from current pos_start */
120 pos_end = pos_start;
122 while (line[pos_end]) {
123 const char c = line[pos_end];
125 if (isspace(c)) {
126 break;
127 } else if (c == '\"') {
128 const char* end = __ScanEscapeString(0, &line[pos_end]);
129 if (!end) return -1;
130 pos_end = end - &line[0];
132 pos_end++;
135 /* save the token */
136 array[count].start = &line[pos_start];
137 array[count].length = pos_end - pos_start;
139 if (line[pos_end]) {
140 line[pos_end] = '\0'; /* DESTRUCTION!!! */
141 pos_end++;
143 pos_start = pos_end;
144 /* printf("TOKEN %s\n", array[count].start); */
147 return count;
150 /* NOTE: This is leaking memory left and right */
151 int __ParseArg(NaClSrpcArg* arg, const char* token) {
152 long val;
153 int dim;
154 const char* comma;
155 int i;
157 dprintf(("TOKEN %s\n", token));
158 assert(token[1] == '(');
160 switch (token[0]) {
161 case NACL_SRPC_ARG_TYPE_INVALID:
162 arg->tag = NACL_SRPC_ARG_TYPE_INVALID;
163 break;
164 case NACL_SRPC_ARG_TYPE_BOOL:
165 val = strtol(&token[2], 0, 0);
166 arg->tag = NACL_SRPC_ARG_TYPE_BOOL;
167 arg->u.bval = val;
168 break;
169 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
170 dim = strtol(&token[2], 0, 0);
171 arg->tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
172 arg->u.caval.carr = (char*) calloc(dim, sizeof(char));
173 arg->u.caval.count = dim;
174 comma = strstr(token, ",");
175 if (comma) {
176 const char* p;
177 for (p = comma+1, i = 0; *p != ')' && i < dim; ++p, ++i)
178 arg->u.caval.carr[i] = *p;
180 break;
181 case NACL_SRPC_ARG_TYPE_DOUBLE:
182 arg->tag = NACL_SRPC_ARG_TYPE_DOUBLE;
183 arg->u.dval = strtod(&token[2], 0);
184 break;
185 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
186 dim = strtol(&token[2], 0, 0);
187 arg->tag = NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY;
188 /* LEAK */
189 arg->u.daval.darr = (double*) calloc(dim, sizeof(double));
190 assert(arg->u.daval.darr);
191 arg->u.daval.count = dim;
192 comma = token;
193 for (i = 0; i < dim; ++i) {
194 comma = strstr(comma, ",");
195 if (!comma) break;
196 ++comma;
197 arg->u.daval.darr[i] = strtod(comma, 0);
199 break;
200 case NACL_SRPC_ARG_TYPE_HANDLE:
201 /* TODO: get handle passing to work. */
202 val = strtol(&token[2], 0, 0);
203 arg->tag = NACL_SRPC_ARG_TYPE_HANDLE;
204 arg->u.hval = val;
205 break;
206 case NACL_SRPC_ARG_TYPE_INT:
207 val = strtol(&token[2], 0, 0);
208 arg->tag = NACL_SRPC_ARG_TYPE_INT;
209 arg->u.ival = val;
210 break;
211 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
212 dim = strtol(&token[2], 0, 0);
213 arg->tag = NACL_SRPC_ARG_TYPE_INT_ARRAY;
214 /* LEAK */
215 arg->u.iaval.iarr = (int*) calloc(dim, sizeof(int));
216 assert(arg->u.iaval.iarr);
217 arg->u.iaval.count = dim;
218 comma = token;
219 for (i = 0; i < dim; ++i) {
220 comma = strstr(comma, ",");
221 if (!comma) break;
222 ++comma;
223 arg->u.iaval.iarr[i] = strtol(comma, 0, 0);
225 break;
226 case NACL_SRPC_ARG_TYPE_STRING:
227 arg->tag = NACL_SRPC_ARG_TYPE_STRING;
228 /* this is a conservative estimate */
229 arg->u.sval = malloc(strlen(token));
230 if (NULL == arg->u.sval) {
231 return -1;
233 __ScanEscapeString(arg->u.sval, token + 2);
234 break;
236 * The two cases below are added to avoid warnings, they are only used
237 * in the plugin code
239 case NACL_SRPC_ARG_TYPE_OBJECT:
240 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
241 default:
242 return -1;
245 return 1;
248 int __ParseArgs(NaClSrpcArg* arg, const TOKEN* token, int n) {
249 int i;
250 for (i = 0; i < n; ++i) {
251 if (__ParseArg(&arg[i], token[i].start) < 0)
252 return -1;
254 return n;
257 void __DumpInterfaceDescription(const NaClSrpcDesc* rpc_desc, int num_rpc) {
258 int i;
259 printf("RPC %-20s %-10s %-10s\n", "Name", "Input args", "Output args");
260 for (i = 0; i < num_rpc; ++i) {
261 printf("%3d %-20s %-10s %-10s\n",
262 i, rpc_desc[i].rpc_name,
263 rpc_desc[i].in_args, rpc_desc[i].out_args);
268 void __DumpArg(const NaClSrpcArg* arg) {
269 int count;
270 int i;
272 switch(arg->tag) {
273 case NACL_SRPC_ARG_TYPE_INVALID:
274 printf("X()");
275 break;
276 case NACL_SRPC_ARG_TYPE_BOOL:
277 printf("b(%d)", arg->u.bval);
278 break;
279 case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
280 for (i = 0; i < arg->u.caval.count; i++)
281 putchar(arg->u.caval.carr[i]);
282 break;
283 case NACL_SRPC_ARG_TYPE_DOUBLE:
284 printf("d(%f)", arg->u.dval);
285 break;
286 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
287 count = arg->u.daval.count;
288 printf("D(%d", count);
289 for (i=0; i < count; ++i)
290 printf(",%f", arg->u.daval.darr[i]);
291 printf(")");
292 break;
293 case NACL_SRPC_ARG_TYPE_HANDLE:
294 printf("h(%d)", arg->u.hval);
295 break;
296 case NACL_SRPC_ARG_TYPE_INT:
297 printf("i(%d)", arg->u.ival);
298 break;
299 case NACL_SRPC_ARG_TYPE_INT_ARRAY:
300 count = arg->u.iaval.count;
301 printf("I(%d", count);
302 for (i=0; i < count; ++i)
303 printf(",%d", arg->u.iaval.iarr[i]);
304 printf(")");
305 break;
306 case NACL_SRPC_ARG_TYPE_STRING:
307 /* TODO: do proper escaping */
308 printf("s(\"%s\")", arg->u.sval);
309 break;
311 * The two cases below are added to avoid warnings, they are only used
312 * in the plugin code
314 case NACL_SRPC_ARG_TYPE_OBJECT:
315 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
316 default:
317 break;
321 void __DumpArgs(const NaClSrpcArg* arg, int n) {
322 int i;
323 for (i=0; i<n; ++i) {
324 printf(" ");
325 __DumpArg(&arg[i]);
327 printf("\n");
330 extern int __srpc_get_fd();
332 NaClSrpcError __CommandLoop() {
333 int errcode;
334 const NaClSrpcDesc* rpc_desc;
335 struct NaClSrpcHandlerDesc* handlers;
336 char* service_str;
337 uint32_t num_rpc;
338 int command_count = 0;
339 int socket_desc;
340 size_t length;
342 socket_desc = __srpc_get_fd();
344 if (socket_desc == -1) {
346 * No socket connection, use stdin/stdout.
349 /* Build the complete method table */
350 handlers = __NaClSrpcCompleteMethodTable(__kNaClSrpcHandlers, &num_rpc);
351 /* Build the service discovery string */
352 service_str = __NaClSrpcBuildSDString(handlers, num_rpc, &length);
353 /* Build the descriptor table from the string */
354 rpc_desc = __NaClSrpcBuildSrpcDesc(service_str, &num_rpc);
356 /* process commands from stdin and dispatch */
357 for (;;) {
358 char buffer[4096];
359 TOKEN tokens[64];
360 int n;
361 const char *command;
363 fprintf(stderr, "%d> ", command_count);
364 ++command_count;
366 if (!fgets(buffer, sizeof(buffer), stdin))
367 break;
369 n = __Tokenize(buffer, tokens, 64);
371 if (n < 1) {
372 if (n < 0)
373 fprintf(stderr, "bad line\n");
374 continue;
377 command = tokens[0].start;
378 if (0 == strcmp("#", command)) {
379 continue;
380 } else if (0 == strcmp("service", command)) {
381 __DumpInterfaceDescription(rpc_desc, num_rpc);
382 } else if (0 == strcmp("quit", command)) {
383 break;
384 } else if (0 == strcmp("rpc", command)) {
385 int int_out_sep;
386 int n_in;
387 NaClSrpcArg in[NACL_SRPC_MAX_ARGS];
388 NaClSrpcArg *inv[NACL_SRPC_MAX_ARGS+1];
389 int i;
390 int n_out;
391 NaClSrpcArg out[NACL_SRPC_MAX_ARGS];
392 NaClSrpcArg *outv[NACL_SRPC_MAX_ARGS+1];
393 int rpc_num;
395 if (n < 2) {
396 fprintf(stderr, "bad rpc command\n");
397 continue;
400 for (int_out_sep = 2; int_out_sep < n; ++int_out_sep) {
401 if (0 == strcmp(tokens[int_out_sep].start, "*"))
402 break;
405 if (int_out_sep == n) {
406 fprintf(stderr, "no in out arg separator for rpc command\n");
407 continue;
410 n_in = int_out_sep - 2;
411 dprintf(("parsing in args %d\n", n_in));
412 assert(n_in < NACL_SRPC_MAX_ARGS);
413 for (i = 0; i < n_in; ++i) inv[i] = &in[i];
414 inv[n_in] = 0;
416 if (__ParseArgs(in, &tokens[2], n_in) < 0) {
417 fprintf(stderr, "bad input args for rpc\n");
418 continue;
421 n_out = n - int_out_sep - 1;
422 dprintf(("parsing out args %d\n", n_out));
423 assert(n_out < NACL_SRPC_MAX_ARGS);
424 for (i = 0; i < n_out; ++i) outv[i] = &out[i];
425 outv[n_out] = 0;
427 if (__ParseArgs(out, &tokens[int_out_sep + 1], n_out) < 0) {
428 fprintf(stderr, "bad output args for rpc\n");
429 continue;
432 rpc_num = __GetRpcNum(rpc_desc, num_rpc, tokens[1].start);
433 if (rpc_num < 0) {
434 fprintf(stderr, "unknown rpc\n");
435 continue;
438 fprintf(stderr,"using rpc %s no %d\n", tokens[1].start, rpc_num);
439 errcode = __NaClSrpcMain(rpc_num, handlers, num_rpc, NULL, inv, outv);
440 if (NACL_SRPC_RESULT_OK != errcode) {
441 fprintf(stderr, "rpc call failed %d\n", errcode);
442 continue;
445 /* dump result vector */
446 printf("%s RESULTS: ", tokens[1].start);
447 __DumpArgs(outv[0], n_out);
448 } else {
449 fprintf(stderr, "unknown command\n");
450 continue;
453 } else {
454 NaClSrpcDefaultServerLoop(NULL);
456 return NACL_SRPC_RESULT_OK;