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 : * SRPC utility functions.
9 : */
10 :
11 : #include <ctype.h>
12 : #include <stdarg.h>
13 : #include <stdlib.h>
14 : #include <string.h>
15 :
16 : #include "native_client/src/include/nacl_assert.h"
17 : #include "native_client/src/include/portability.h"
18 : #include "native_client/src/include/portability_io.h"
19 : #include "native_client/src/include/portability_process.h"
20 :
21 : #include "native_client/src/shared/platform/nacl_exit.h"
22 : #include "native_client/src/shared/platform/nacl_sync_checked.h"
23 : #include "native_client/src/shared/platform/nacl_threads.h"
24 : #include "native_client/src/shared/platform/nacl_timestamp.h"
25 : #include "native_client/src/shared/srpc/nacl_srpc.h"
26 : #include "native_client/src/shared/srpc/nacl_srpc_internal.h"
27 :
28 : static struct NaClMutex log_mu;
29 :
30 : static int verbosity;
31 :
32 3 : static void setVerbosityFromEnv(void) {
33 3 : const char* env_verbosity = getenv("NACL_SRPC_DEBUG");
34 3 : verbosity = 0;
35 3 : if (NULL != env_verbosity) {
36 0 : int v = strtol(env_verbosity, (char**) 0, 0);
37 0 : if (v >= 0) {
38 0 : verbosity = v;
39 : }
40 : }
41 3 : }
42 :
43 3 : int NaClSrpcLogInit(void) {
44 3 : NaClXMutexCtor(&log_mu);
45 3 : setVerbosityFromEnv();
46 3 : return 1;
47 3 : }
48 :
49 3 : void NaClSrpcLogFini(void) {
50 3 : NaClMutexDtor(&log_mu);
51 3 : }
52 :
53 3 : void NaClSrpcLog(int detail_level, const char* fmt, ...) {
54 : /*
55 : * It would be better to use the NaClLog infrastructure to do this, but
56 : * it requires some more enhancement to be ready.
57 : * http://code.google.com/p/nativeclient/issues/detail?id=1802
58 : * TODO(bsy,sehr): convert this when NaClLog is ready for SRPC levels, etc.
59 : */
60 3 : if (detail_level <= verbosity) {
61 : char timestamp[128];
62 0 : int pid = GETPID();
63 : va_list ap;
64 0 : unsigned tid = NaClThreadId();
65 : const char* ts;
66 : #ifdef __native_client__
67 : const char* host_or_nacl = "NACL";
68 : #else
69 0 : const char* host_or_nacl = "HOST";
70 : #endif
71 0 : va_start(ap, fmt);
72 0 : NaClXMutexLock(&log_mu);
73 0 : ts = NaClTimeStampString(timestamp, sizeof timestamp);
74 : fprintf(stderr,
75 : "[SRPC:%s:%d,%"NACL_PRIu32":%s] ",
76 : host_or_nacl,
77 : pid,
78 : tid,
79 0 : ts);
80 0 : vfprintf(stderr, fmt, ap);
81 0 : NaClXMutexUnlock(&log_mu);
82 0 : va_end(ap);
83 : }
84 3 : if (detail_level == NACL_SRPC_LOG_FATAL) {
85 0 : NaClAbort();
86 : }
87 3 : }
88 :
89 : /*
90 : * This makes a best-effort escape sequence to feed sel_universal's parser
91 : * in src/trusted/sel_universal/parsing.cc.
92 : */
93 0 : static int shouldPrintAsEscaped(int cval) {
94 0 : switch (cval) {
95 : case '\0':
96 0 : return '0';
97 : case '\\':
98 0 : return '\\';
99 : case '\"':
100 0 : return '\"';
101 : case '\'':
102 0 : return '\'';
103 : case '\a':
104 0 : return 'a';
105 : case '\b':
106 0 : return 'b';
107 : case '\f':
108 0 : return 'f';
109 : case '\n':
110 0 : return 'n';
111 : case '\r':
112 0 : return 'r';
113 : case '\t':
114 0 : return 't';
115 : case '\v':
116 0 : return 'v';
117 : default:
118 0 : return -1;
119 : }
120 0 : }
121 :
122 0 : static void formatChar(int cval, char** buf, size_t* bytes_remaining) {
123 : int escaped_char;
124 0 : if (isprint(cval)) {
125 : static const size_t kBytesRequiredForChar = 1;
126 0 : if (*bytes_remaining >= kBytesRequiredForChar) {
127 0 : **buf = cval;
128 0 : *buf += kBytesRequiredForChar;
129 0 : *bytes_remaining -= kBytesRequiredForChar;
130 : }
131 0 : return;
132 : }
133 0 : escaped_char = shouldPrintAsEscaped(cval);
134 0 : if (escaped_char != -1) {
135 : static const size_t kBytesRequiredForEscapedChar = 2;
136 0 : if (*bytes_remaining >= kBytesRequiredForEscapedChar) {
137 0 : (*buf)[0] = '\\';
138 0 : (*buf)[1] = escaped_char;
139 0 : *buf += kBytesRequiredForEscapedChar;
140 0 : *bytes_remaining -= kBytesRequiredForEscapedChar;
141 : }
142 0 : } else {
143 : /* SNPRINTF needs space to write the NUL, but reports only the non-NUL
144 : * byte count written. */
145 : static const size_t kBytesRequiredForHex = 4 + 1;
146 0 : if (*bytes_remaining >= kBytesRequiredForHex) {
147 : size_t written_bytes =
148 0 : SNPRINTF(*buf, kBytesRequiredForHex, "\\x%02x", (unsigned char) cval);
149 0 : *buf += written_bytes;
150 0 : *bytes_remaining -= written_bytes;
151 : }
152 : }
153 0 : }
154 :
155 : static void formatString(const char* str,
156 : char** buf,
157 0 : size_t* bytes_remaining) {
158 0 : while (*str != 0) {
159 0 : formatChar((unsigned char) *str, buf, bytes_remaining);
160 0 : ++str;
161 0 : }
162 0 : }
163 :
164 0 : static void formatDouble(double dval, char** buf, size_t* bytes_remaining) {
165 : char tmp[32];
166 0 : SNPRINTF(tmp, sizeof(tmp), "%f", dval);
167 0 : formatString(tmp, buf, bytes_remaining);
168 0 : }
169 :
170 0 : static void formatCount(uint32_t count, char** buf, size_t* bytes_remaining) {
171 : char tmp[32];
172 0 : SNPRINTF(tmp, sizeof(tmp), "%"NACL_PRIu32, count);
173 0 : formatString(tmp, buf, bytes_remaining);
174 0 : }
175 :
176 0 : static void formatInt(int32_t ival, char** buf, size_t* bytes_remaining) {
177 : char tmp[32];
178 0 : SNPRINTF(tmp, sizeof(tmp), "%"NACL_PRId32, ival);
179 0 : formatString(tmp, buf, bytes_remaining);
180 0 : }
181 :
182 0 : static void formatLong(int64_t lval, char** buf, size_t* bytes_remaining) {
183 : char tmp[32];
184 0 : SNPRINTF(tmp, sizeof(tmp), "%"NACL_PRId64, lval);
185 0 : formatString(tmp, buf, bytes_remaining);
186 0 : }
187 :
188 0 : static void formatPointer(void* pval, char** buf, size_t* bytes_remaining) {
189 : char tmp[32];
190 0 : SNPRINTF(tmp, sizeof(tmp), "%p", pval);
191 0 : formatString(tmp, buf, bytes_remaining);
192 0 : }
193 :
194 : void NaClSrpcFormatArg(int detail_level,
195 : const NaClSrpcArg* arg,
196 : char* buffer,
197 2 : size_t buffer_size) {
198 : uint32_t i;
199 :
200 2 : if (detail_level > verbosity) {
201 2 : return;
202 : }
203 : /* Reserve space for trailing zero. */
204 0 : if (buffer_size == 0) {
205 0 : return;
206 : }
207 0 : buffer_size--;
208 0 : formatChar(arg->tag, &buffer, &buffer_size);
209 0 : formatString("(", &buffer, &buffer_size);
210 0 : switch (arg->tag) {
211 : case NACL_SRPC_ARG_TYPE_INVALID:
212 : break;
213 : case NACL_SRPC_ARG_TYPE_BOOL:
214 0 : formatInt(arg->u.bval, &buffer, &buffer_size);
215 0 : break;
216 : case NACL_SRPC_ARG_TYPE_CHAR_ARRAY:
217 0 : formatCount(arg->u.count, &buffer, &buffer_size);
218 0 : if (arg->arrays.carr == NULL) {
219 0 : formatString(",(nil)", &buffer, &buffer_size);
220 0 : } else {
221 0 : formatString(",", &buffer, &buffer_size);
222 0 : for (i = 0; i < arg->u.count; ++i)
223 0 : formatChar(arg->arrays.carr[i], &buffer, &buffer_size);
224 : }
225 0 : break;
226 : case NACL_SRPC_ARG_TYPE_DOUBLE:
227 0 : formatDouble(arg->u.dval, &buffer, &buffer_size);
228 0 : break;
229 : case NACL_SRPC_ARG_TYPE_DOUBLE_ARRAY:
230 0 : formatCount(arg->u.count, &buffer, &buffer_size);
231 0 : if (arg->arrays.darr == NULL) {
232 0 : formatString(",(nil)", &buffer, &buffer_size);
233 0 : } else {
234 0 : for (i = 0; i < arg->u.count; ++i) {
235 0 : formatString(",", &buffer, &buffer_size);
236 0 : formatDouble(arg->arrays.darr[i], &buffer, &buffer_size);
237 0 : }
238 : }
239 0 : break;
240 : case NACL_SRPC_ARG_TYPE_HANDLE:
241 0 : formatPointer((void*) arg->u.hval, &buffer, &buffer_size);
242 0 : break;
243 : case NACL_SRPC_ARG_TYPE_INT:
244 0 : formatInt(arg->u.ival, &buffer, &buffer_size);
245 0 : break;
246 : case NACL_SRPC_ARG_TYPE_INT_ARRAY:
247 0 : formatCount(arg->u.count, &buffer, &buffer_size);
248 0 : if (arg->arrays.iarr == NULL) {
249 0 : formatString(",(nil)", &buffer, &buffer_size);
250 0 : } else {
251 0 : for (i = 0; i < arg->u.count; ++i) {
252 0 : formatString(",", &buffer, &buffer_size);
253 0 : formatInt(arg->arrays.iarr[i], &buffer, &buffer_size);
254 0 : }
255 : }
256 0 : break;
257 : case NACL_SRPC_ARG_TYPE_LONG:
258 0 : formatString("l(", &buffer, &buffer_size);
259 0 : formatLong(arg->u.lval, &buffer, &buffer_size);
260 0 : break;
261 : case NACL_SRPC_ARG_TYPE_LONG_ARRAY:
262 0 : formatCount(arg->u.count, &buffer, &buffer_size);
263 0 : if (arg->arrays.larr == NULL) {
264 0 : formatString(",(nil)", &buffer, &buffer_size);
265 0 : } else {
266 0 : for (i = 0; i < arg->u.count; ++i) {
267 0 : formatString(",", &buffer, &buffer_size);
268 0 : formatLong(arg->arrays.larr[i], &buffer, &buffer_size);
269 0 : }
270 : }
271 0 : break;
272 : case NACL_SRPC_ARG_TYPE_STRING:
273 0 : if (arg->arrays.str == NULL) {
274 0 : formatString("(nil)", &buffer, &buffer_size);
275 0 : } else {
276 0 : formatString("\"", &buffer, &buffer_size);
277 0 : formatString(arg->arrays.str, &buffer, &buffer_size);
278 0 : formatString("\"", &buffer, &buffer_size);
279 : }
280 0 : break;
281 : /*
282 : * The cases below are added to avoid warnings, they are only used
283 : * in the plugin code
284 : */
285 : case NACL_SRPC_ARG_TYPE_OBJECT:
286 : /* this is a pointer that NaCl module can do nothing with */
287 0 : formatPointer(arg->arrays.oval, &buffer, &buffer_size);
288 : break;
289 : case NACL_SRPC_ARG_TYPE_VARIANT_ARRAY:
290 : break;
291 : default:
292 : break;
293 : }
294 0 : formatString(")", &buffer, &buffer_size);
295 0 : *buffer = '\0';
296 2 : }
297 :
298 :
299 : /*
300 : * Get the printable form of an error code.
301 : */
302 2 : const char* NaClSrpcErrorString(NaClSrpcError error_code) {
303 2 : switch (error_code) {
304 : case NACL_SRPC_RESULT_OK:
305 2 : return "No error";
306 : case NACL_SRPC_RESULT_BREAK:
307 0 : return "Break out of server RPC loop";
308 : case NACL_SRPC_RESULT_MESSAGE_TRUNCATED:
309 0 : return "Received message was shorter than expected";
310 : case NACL_SRPC_RESULT_NO_MEMORY:
311 0 : return "Out of memory";
312 : case NACL_SRPC_RESULT_PROTOCOL_MISMATCH:
313 0 : return "Client and server have different protocol versions";
314 : case NACL_SRPC_RESULT_BAD_RPC_NUMBER:
315 0 : return "No method for the given rpc number";
316 : case NACL_SRPC_RESULT_BAD_ARG_TYPE:
317 0 : return "Bad argument type received";
318 : case NACL_SRPC_RESULT_TOO_MANY_ARGS:
319 0 : return "Too many arguments (more than NACL_SRPC_MAX_ARGS or declared)";
320 : case NACL_SRPC_RESULT_TOO_FEW_ARGS:
321 0 : return "Too few arguments (fewer than declared)";
322 : case NACL_SRPC_RESULT_IN_ARG_TYPE_MISMATCH:
323 0 : return "Input argument type mismatch";
324 : case NACL_SRPC_RESULT_OUT_ARG_TYPE_MISMATCH:
325 0 : return "Output argument type mismatch";
326 : case NACL_SRPC_RESULT_INTERNAL:
327 0 : return "Internal error in rpc method";
328 : case NACL_SRPC_RESULT_APP_ERROR:
329 0 : return "Rpc application returned an error";
330 : default:
331 : break;
332 : }
333 0 : return "Unrecognized NaClSrpcError value";
334 2 : }
|