2 * Copyright 2008, Google Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
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
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)
42 #include <sys/types.h>
49 #include "nacl_srpc.h"
50 #include "nacl_srpc_internal.h"
52 int __GetRpcNum(const NaClSrpcDesc
* rpc_desc
, int num_rpc
, char const* name
) {
54 for (i
= 0; i
< num_rpc
; ++i
) {
55 if (!strcmp(name
, rpc_desc
[i
].rpc_name
)) {
62 /* simple destructive tokenizer */
69 /* expects *from to point to leading \" and returns pointer to trailing \" */
70 const char* __ScanEscapeString(char* to
, const char* from
) {
71 assert (*from
== '\"');
77 }else if (*from
!= '\\') {
78 if (to
) *to
++ = *from
;
100 int __Tokenize(char* line
, TOKEN
*array
, int n
) {
104 for( ; count
< n
; count
++ ) {
107 /* skip leading white space */
108 while (line
[pos_start
]) {
109 const char c
= line
[pos_start
];
117 if (!line
[pos_start
]) break;
119 /* find token end from current pos_start */
122 while (line
[pos_end
]) {
123 const char c
= line
[pos_end
];
127 } else if (c
== '\"') {
128 const char* end
= __ScanEscapeString(0, &line
[pos_end
]);
130 pos_end
= end
- &line
[0];
136 array
[count
].start
= &line
[pos_start
];
137 array
[count
].length
= pos_end
- pos_start
;
140 line
[pos_end
] = '\0'; /* DESTRUCTION!!! */
144 /* printf("TOKEN %s\n", array[count].start); */
150 /* NOTE: This is leaking memory left and right */
151 int __ParseArg(NaClSrpcArg
* arg
, const char* token
) {
157 dprintf(("TOKEN %s\n", token
));
158 assert(token
[1] == '(');
161 case NACL_SRPC_ARG_TYPE_INVALID
:
162 arg
->tag
= NACL_SRPC_ARG_TYPE_INVALID
;
164 case NACL_SRPC_ARG_TYPE_BOOL
:
165 val
= strtol(&token
[2], 0, 0);
166 arg
->tag
= NACL_SRPC_ARG_TYPE_BOOL
;
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
, ",");
177 for (p
= comma
+1, i
= 0; *p
!= ')' && i
< dim
; ++p
, ++i
)
178 arg
->u
.caval
.carr
[i
] = *p
;
181 case NACL_SRPC_ARG_TYPE_DOUBLE
:
182 arg
->tag
= NACL_SRPC_ARG_TYPE_DOUBLE
;
183 arg
->u
.dval
= strtod(&token
[2], 0);
185 case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY
:
186 dim
= strtol(&token
[2], 0, 0);
187 arg
->tag
= NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY
;
189 arg
->u
.daval
.darr
= (double*) calloc(dim
, sizeof(double));
190 assert(arg
->u
.daval
.darr
);
191 arg
->u
.daval
.count
= dim
;
193 for (i
= 0; i
< dim
; ++i
) {
194 comma
= strstr(comma
, ",");
197 arg
->u
.daval
.darr
[i
] = strtod(comma
, 0);
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
;
206 case NACL_SRPC_ARG_TYPE_INT
:
207 val
= strtol(&token
[2], 0, 0);
208 arg
->tag
= NACL_SRPC_ARG_TYPE_INT
;
211 case NACL_SRPC_ARG_TYPE_INT_ARRAY
:
212 dim
= strtol(&token
[2], 0, 0);
213 arg
->tag
= NACL_SRPC_ARG_TYPE_INT_ARRAY
;
215 arg
->u
.iaval
.iarr
= (int*) calloc(dim
, sizeof(int));
216 assert(arg
->u
.iaval
.iarr
);
217 arg
->u
.iaval
.count
= dim
;
219 for (i
= 0; i
< dim
; ++i
) {
220 comma
= strstr(comma
, ",");
223 arg
->u
.iaval
.iarr
[i
] = strtol(comma
, 0, 0);
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
) {
233 __ScanEscapeString(arg
->u
.sval
, token
+ 2);
236 * The two cases below are added to avoid warnings, they are only used
239 case NACL_SRPC_ARG_TYPE_OBJECT
:
240 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY
:
248 int __ParseArgs(NaClSrpcArg
* arg
, const TOKEN
* token
, int n
) {
250 for (i
= 0; i
< n
; ++i
) {
251 if (__ParseArg(&arg
[i
], token
[i
].start
) < 0)
257 void __DumpInterfaceDescription(const NaClSrpcDesc
* rpc_desc
, int num_rpc
) {
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
) {
273 case NACL_SRPC_ARG_TYPE_INVALID
:
276 case NACL_SRPC_ARG_TYPE_BOOL
:
277 printf("b(%d)", arg
->u
.bval
);
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
]);
283 case NACL_SRPC_ARG_TYPE_DOUBLE
:
284 printf("d(%f)", arg
->u
.dval
);
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
]);
293 case NACL_SRPC_ARG_TYPE_HANDLE
:
294 printf("h(%d)", arg
->u
.hval
);
296 case NACL_SRPC_ARG_TYPE_INT
:
297 printf("i(%d)", arg
->u
.ival
);
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
]);
306 case NACL_SRPC_ARG_TYPE_STRING
:
307 /* TODO: do proper escaping */
308 printf("s(\"%s\")", arg
->u
.sval
);
311 * The two cases below are added to avoid warnings, they are only used
314 case NACL_SRPC_ARG_TYPE_OBJECT
:
315 case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY
:
321 void __DumpArgs(const NaClSrpcArg
* arg
, int n
) {
323 for (i
=0; i
<n
; ++i
) {
330 extern int __srpc_get_fd();
332 NaClSrpcError
__CommandLoop() {
334 const NaClSrpcDesc
* rpc_desc
;
335 struct NaClSrpcHandlerDesc
* handlers
;
338 int command_count
= 0;
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 */
363 fprintf(stderr
, "%d> ", command_count
);
366 if (!fgets(buffer
, sizeof(buffer
), stdin
))
369 n
= __Tokenize(buffer
, tokens
, 64);
373 fprintf(stderr
, "bad line\n");
377 command
= tokens
[0].start
;
378 if (0 == strcmp("#", command
)) {
380 } else if (0 == strcmp("service", command
)) {
381 __DumpInterfaceDescription(rpc_desc
, num_rpc
);
382 } else if (0 == strcmp("quit", command
)) {
384 } else if (0 == strcmp("rpc", command
)) {
387 NaClSrpcArg in
[NACL_SRPC_MAX_ARGS
];
388 NaClSrpcArg
*inv
[NACL_SRPC_MAX_ARGS
+1];
391 NaClSrpcArg out
[NACL_SRPC_MAX_ARGS
];
392 NaClSrpcArg
*outv
[NACL_SRPC_MAX_ARGS
+1];
396 fprintf(stderr
, "bad rpc command\n");
400 for (int_out_sep
= 2; int_out_sep
< n
; ++int_out_sep
) {
401 if (0 == strcmp(tokens
[int_out_sep
].start
, "*"))
405 if (int_out_sep
== n
) {
406 fprintf(stderr
, "no in out arg separator for rpc command\n");
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
];
416 if (__ParseArgs(in
, &tokens
[2], n_in
) < 0) {
417 fprintf(stderr
, "bad input args for rpc\n");
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
];
427 if (__ParseArgs(out
, &tokens
[int_out_sep
+ 1], n_out
) < 0) {
428 fprintf(stderr
, "bad output args for rpc\n");
432 rpc_num
= __GetRpcNum(rpc_desc
, num_rpc
, tokens
[1].start
);
434 fprintf(stderr
, "unknown rpc\n");
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
);
445 /* dump result vector */
446 printf("%s RESULTS: ", tokens
[1].start
);
447 __DumpArgs(outv
[0], n_out
);
449 fprintf(stderr
, "unknown command\n");
454 NaClSrpcDefaultServerLoop(NULL
);
456 return NACL_SRPC_RESULT_OK
;