OLD | NEW |
1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 * Use of this source code is governed by a BSD-style license that can be | 2 * Use of this source code is governed by a BSD-style license that can be |
3 * found in the LICENSE file. | 3 * found in the LICENSE file. |
4 */ | 4 */ |
5 | 5 |
6 #include "nacl_io_demo.h" | 6 #include "nacl_io_demo.h" |
7 | 7 |
8 #include <assert.h> | 8 #include <assert.h> |
| 9 #include <errno.h> |
| 10 #include <fcntl.h> |
| 11 #include <limits.h> |
9 #include <stdio.h> | 12 #include <stdio.h> |
10 #include <stdlib.h> | 13 #include <stdlib.h> |
11 #include <string.h> | 14 #include <string.h> |
| 15 #include <sys/ioctl.h> |
12 #include <sys/mount.h> | 16 #include <sys/mount.h> |
| 17 #include <sys/param.h> |
| 18 #include <sys/select.h> |
| 19 #include <sys/stat.h> |
13 #include <pthread.h> | 20 #include <pthread.h> |
| 21 #include <unistd.h> |
14 | 22 |
15 #include "ppapi/c/pp_errors.h" | 23 #include "ppapi/c/pp_errors.h" |
16 #include "ppapi/c/pp_module.h" | 24 #include "ppapi/c/pp_module.h" |
17 #include "ppapi/c/ppb.h" | 25 #include "ppapi/c/ppb.h" |
18 #include "ppapi/c/ppb_instance.h" | 26 #include "ppapi/c/ppb_instance.h" |
19 #include "ppapi/c/ppb_messaging.h" | 27 #include "ppapi/c/ppb_messaging.h" |
20 #include "ppapi/c/ppb_var.h" | 28 #include "ppapi/c/ppb_var.h" |
21 #include "ppapi/c/ppb_var_array.h" | 29 #include "ppapi/c/ppb_var_array.h" |
22 #include "ppapi/c/ppb_var_dictionary.h" | 30 #include "ppapi/c/ppb_var_dictionary.h" |
23 #include "ppapi/c/ppp.h" | 31 #include "ppapi/c/ppp.h" |
24 #include "ppapi/c/ppp_instance.h" | 32 #include "ppapi/c/ppp_instance.h" |
25 #include "ppapi/c/ppp_messaging.h" | 33 #include "ppapi/c/ppp_messaging.h" |
| 34 #include "nacl_io/ioctl.h" |
26 #include "nacl_io/nacl_io.h" | 35 #include "nacl_io/nacl_io.h" |
27 | 36 |
28 #include "handlers.h" | 37 #include "handlers.h" |
29 #include "queue.h" | 38 #include "queue.h" |
30 | 39 |
31 #if defined(WIN32) | 40 #if defined(WIN32) |
32 #define va_copy(d, s) ((d) = (s)) | 41 #define va_copy(d, s) ((d) = (s)) |
33 #endif | 42 #endif |
34 | 43 |
35 typedef struct { | 44 typedef struct { |
36 const char* name; | 45 const char* name; |
37 HandleFunc function; | 46 HandleFunc function; |
38 } FuncNameMapping; | 47 } FuncNameMapping; |
39 | 48 |
40 PP_Instance g_instance = 0; | 49 static PP_Instance g_instance = 0; |
41 PPB_GetInterface g_get_browser_interface = NULL; | 50 static PPB_GetInterface g_get_browser_interface = NULL; |
42 PPB_Messaging* g_ppb_messaging = NULL; | 51 static PPB_Messaging* g_ppb_messaging = NULL; |
43 PPB_Var* g_ppb_var = NULL; | 52 PPB_Var* g_ppb_var = NULL; |
44 PPB_VarArray* g_ppb_var_array = NULL; | 53 PPB_VarArray* g_ppb_var_array = NULL; |
45 PPB_VarDictionary* g_ppb_var_dictionary = NULL; | 54 PPB_VarDictionary* g_ppb_var_dictionary = NULL; |
46 | 55 |
47 static FuncNameMapping g_function_map[] = { | 56 static FuncNameMapping g_function_map[] = { |
48 {"fopen", HandleFopen}, | 57 {"fopen", HandleFopen}, |
49 {"fwrite", HandleFwrite}, | 58 {"fwrite", HandleFwrite}, |
50 {"fread", HandleFread}, | 59 {"fread", HandleFread}, |
51 {"fseek", HandleFseek}, | 60 {"fseek", HandleFseek}, |
52 {"fclose", HandleFclose}, | 61 {"fclose", HandleFclose}, |
(...skipping 10 matching lines...) Expand all Loading... |
63 {"gethostbyname", HandleGethostbyname}, | 72 {"gethostbyname", HandleGethostbyname}, |
64 {"connect", HandleConnect}, | 73 {"connect", HandleConnect}, |
65 {"send", HandleSend}, | 74 {"send", HandleSend}, |
66 {"recv", HandleRecv}, | 75 {"recv", HandleRecv}, |
67 {"close", HandleClose}, | 76 {"close", HandleClose}, |
68 {NULL, NULL}, | 77 {NULL, NULL}, |
69 }; | 78 }; |
70 | 79 |
71 /** A handle to the thread the handles messages. */ | 80 /** A handle to the thread the handles messages. */ |
72 static pthread_t g_handle_message_thread; | 81 static pthread_t g_handle_message_thread; |
| 82 static pthread_t g_echo_thread; |
73 | 83 |
74 /** | 84 /** |
75 * Create a new PP_Var from a C string. | 85 * Create a new PP_Var from a C string. |
76 * @param[in] str The string to convert. | 86 * @param[in] str The string to convert. |
77 * @return A new PP_Var with the contents of |str|. | 87 * @return A new PP_Var with the contents of |str|. |
78 */ | 88 */ |
79 struct PP_Var CStrToVar(const char* str) { | 89 struct PP_Var CStrToVar(const char* str) { |
80 return g_ppb_var->VarFromUtf8(str, strlen(str)); | 90 return g_ppb_var->VarFromUtf8(str, strlen(str)); |
81 } | 91 } |
82 | 92 |
(...skipping 28 matching lines...) Expand all Loading... |
111 char* PrintfToNewString(const char* format, ...) { | 121 char* PrintfToNewString(const char* format, ...) { |
112 va_list args; | 122 va_list args; |
113 char* result; | 123 char* result; |
114 va_start(args, format); | 124 va_start(args, format); |
115 result = VprintfToNewString(format, args); | 125 result = VprintfToNewString(format, args); |
116 va_end(args); | 126 va_end(args); |
117 return result; | 127 return result; |
118 } | 128 } |
119 | 129 |
120 /** | 130 /** |
121 * Printf to a new PP_Var. | 131 * Vprintf to a new PP_Var. |
122 * @param[in] format A print format string. | 132 * @param[in] format A print format string. |
123 * @param[in] ... The printf arguments. | 133 * @param[in] va_list The printf arguments. |
124 * @return A new PP_Var. | 134 * @return A new PP_Var. |
125 */ | 135 */ |
126 struct PP_Var PrintfToVar(const char* format, ...) { | 136 static struct PP_Var VprintfToVar(const char* format, va_list args) { |
127 char* string; | |
128 va_list args; | |
129 struct PP_Var var; | 137 struct PP_Var var; |
130 | 138 char* string = VprintfToNewString(format, args); |
131 va_start(args, format); | |
132 string = VprintfToNewString(format, args); | |
133 va_end(args); | |
134 | |
135 var = g_ppb_var->VarFromUtf8(string, strlen(string)); | 139 var = g_ppb_var->VarFromUtf8(string, strlen(string)); |
136 free(string); | 140 free(string); |
137 | |
138 return var; | 141 return var; |
139 } | 142 } |
140 | 143 |
141 /** | 144 /** |
142 * Convert a PP_Var to a C string, given a buffer. | 145 * Convert a PP_Var to a C string. |
143 * @param[in] var The PP_Var to convert. | 146 * @param[in] var The PP_Var to convert. |
144 * @param[out] buffer The buffer to write to. | 147 * @return A newly allocated, NULL-terminated string. |
145 * @param[in] length The length of |buffer|. | |
146 * @return The number of characters written. | |
147 */ | 148 */ |
148 const char* VarToCStr(struct PP_Var var) { | 149 static const char* VarToCStr(struct PP_Var var) { |
149 uint32_t length; | 150 uint32_t length; |
150 const char* str = g_ppb_var->VarToUtf8(var, &length); | 151 const char* str = g_ppb_var->VarToUtf8(var, &length); |
151 if (str == NULL) { | 152 if (str == NULL) { |
152 return NULL; | 153 return NULL; |
153 } | 154 } |
154 | 155 |
155 /* str is NOT NULL-terminated. Copy using memcpy. */ | 156 /* str is NOT NULL-terminated. Copy using memcpy. */ |
156 char* new_str = (char*)malloc(length + 1); | 157 char* new_str = (char*)malloc(length + 1); |
157 memcpy(new_str, str, length); | 158 memcpy(new_str, str, length); |
158 new_str[length] = 0; | 159 new_str[length] = 0; |
159 return new_str; | 160 return new_str; |
160 } | 161 } |
161 | 162 |
162 /** | 163 /** |
163 * Get a value from a Dictionary, given a string key. | 164 * Get a value from a Dictionary, given a string key. |
164 * @param[in] dict The dictionary to look in. | 165 * @param[in] dict The dictionary to look in. |
165 * @param[in] key The key to look up. | 166 * @param[in] key The key to look up. |
166 * @return PP_Var The value at |key| in the |dict|. If the key doesn't exist, | 167 * @return PP_Var The value at |key| in the |dict|. If the key doesn't exist, |
167 * return a PP_Var with the undefined value. | 168 * return a PP_Var with the undefined value. |
168 */ | 169 */ |
169 struct PP_Var GetDictVar(struct PP_Var dict, const char* key) { | 170 struct PP_Var GetDictVar(struct PP_Var dict, const char* key) { |
170 struct PP_Var key_var = CStrToVar(key); | 171 struct PP_Var key_var = CStrToVar(key); |
171 struct PP_Var value = g_ppb_var_dictionary->Get(dict, key_var); | 172 struct PP_Var value = g_ppb_var_dictionary->Get(dict, key_var); |
172 g_ppb_var->Release(key_var); | 173 g_ppb_var->Release(key_var); |
173 return value; | 174 return value; |
174 } | 175 } |
175 | 176 |
176 /** | 177 /** |
177 * Send a newly-created PP_Var to JavaScript, then release it. | 178 * Post a message to JavaScript. |
178 * @param[in] var The PP_Var to send. | 179 * @param[in] format A printf format string. |
| 180 * @param[in] ... The printf arguments. |
179 */ | 181 */ |
180 static void PostMessageVar(struct PP_Var var) { | 182 static void PostMessage(const char* format, ...) { |
| 183 struct PP_Var var; |
| 184 va_list args; |
| 185 |
| 186 va_start(args, format); |
| 187 var = VprintfToVar(format, args); |
| 188 va_end(args); |
| 189 |
181 g_ppb_messaging->PostMessage(g_instance, var); | 190 g_ppb_messaging->PostMessage(g_instance, var); |
182 g_ppb_var->Release(var); | 191 g_ppb_var->Release(var); |
183 } | 192 } |
184 | 193 |
185 /** | 194 /** |
186 * Given a message from JavaScript, parse it for functions and parameters. | 195 * Given a message from JavaScript, parse it for functions and parameters. |
187 * | 196 * |
188 * The format of the message is: | 197 * The format of the message is: |
189 * { | 198 * { |
190 * "cmd": <function name>, | 199 * "cmd": <function name>, |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 | 245 |
237 /** | 246 /** |
238 * Handle as message from JavaScript on the worker thread. | 247 * Handle as message from JavaScript on the worker thread. |
239 * | 248 * |
240 * @param[in] message The message to parse and handle. | 249 * @param[in] message The message to parse and handle. |
241 */ | 250 */ |
242 static void HandleMessage(struct PP_Var message) { | 251 static void HandleMessage(struct PP_Var message) { |
243 const char* function_name; | 252 const char* function_name; |
244 struct PP_Var params; | 253 struct PP_Var params; |
245 if (ParseMessage(message, &function_name, ¶ms)) { | 254 if (ParseMessage(message, &function_name, ¶ms)) { |
246 PostMessageVar(CStrToVar("Error: Unable to parse message")); | 255 PostMessage("Error: Unable to parse message"); |
247 return; | 256 return; |
248 } | 257 } |
249 | 258 |
250 HandleFunc function = GetFunctionByName(function_name); | 259 HandleFunc function = GetFunctionByName(function_name); |
251 if (!function) { | 260 if (!function) { |
252 /* Function name wasn't found. Error. */ | 261 /* Function name wasn't found. Error. */ |
253 PostMessageVar( | 262 PostMessage("Error: Unknown function \"%s\"", function_name); |
254 PrintfToVar("Error: Unknown function \"%s\"", function_name)); | |
255 return; | 263 return; |
256 } | 264 } |
257 | 265 |
258 /* Function name was found, call it. */ | 266 /* Function name was found, call it. */ |
259 struct PP_Var result_var; | 267 struct PP_Var result_var; |
260 const char* error; | 268 const char* error; |
261 int result = (*function)(params, &result_var, &error); | 269 int result = (*function)(params, &result_var, &error); |
262 if (result != 0) { | 270 if (result != 0) { |
263 /* Error. */ | 271 /* Error. */ |
264 struct PP_Var var; | |
265 if (error != NULL) { | 272 if (error != NULL) { |
266 var = PrintfToVar("Error: \"%s\" failed: %s.", function_name, error); | 273 PostMessage("Error: \"%s\" failed: %s.", function_name, error); |
267 free((void*)error); | 274 free((void*)error); |
268 } else { | 275 } else { |
269 var = PrintfToVar("Error: \"%s\" failed.", function_name); | 276 PostMessage("Error: \"%s\" failed.", function_name); |
270 } | 277 } |
271 | |
272 /* Post the error to JavaScript, so the user can see it. */ | |
273 PostMessageVar(var); | |
274 return; | 278 return; |
275 } | 279 } |
276 | 280 |
277 /* Function returned an output dictionary. Send it to JavaScript. */ | 281 /* Function returned an output dictionary. Send it to JavaScript. */ |
278 PostMessageVar(result_var); | 282 g_ppb_messaging->PostMessage(g_instance, result_var); |
279 g_ppb_var->Release(result_var); | 283 g_ppb_var->Release(result_var); |
280 } | 284 } |
281 | 285 |
| 286 |
| 287 /** |
| 288 * Helper function used by EchoThread which reads from a file descriptor |
| 289 * and writes all the data that it reads back to the same descriptor. |
| 290 */ |
| 291 static void EchoInput(int fd) { |
| 292 char buffer[512]; |
| 293 while (1) { |
| 294 int rtn = read(fd, buffer, 512); |
| 295 if (rtn > 0) { |
| 296 int wrote = write(fd, buffer, rtn); |
| 297 if (wrote < rtn) |
| 298 PostMessage("only wrote %d/%d bytes\n", wrote, rtn); |
| 299 } else { |
| 300 if (rtn < 0 && errno != EAGAIN) |
| 301 PostMessage("read failed: %d (%s)\n", errno, strerror(errno)); |
| 302 break; |
| 303 } |
| 304 } |
| 305 } |
| 306 |
| 307 /** |
| 308 * Worker thread that listens for input on JS pipe nodes and echos all input |
| 309 * back to the same pipe. |
| 310 */ |
| 311 static void* EchoThread(void* user_data) { |
| 312 int fd1 = open("/dev/jspipe1", O_RDWR | O_NONBLOCK); |
| 313 int fd2 = open("/dev/jspipe2", O_RDWR | O_NONBLOCK); |
| 314 int fd3 = open("/dev/jspipe3", O_RDWR | O_NONBLOCK); |
| 315 int nfds = MAX(fd1, fd2); |
| 316 nfds = MAX(nfds, fd3); |
| 317 while (1) { |
| 318 fd_set readfds; |
| 319 FD_ZERO(&readfds); |
| 320 FD_SET(fd1, &readfds); |
| 321 FD_SET(fd2, &readfds); |
| 322 FD_SET(fd3, &readfds); |
| 323 int rtn = select(nfds + 1, &readfds, NULL, NULL, NULL); |
| 324 if (rtn < 0 && errno != EAGAIN) { |
| 325 PostMessage("select failed: %s\n", strerror(errno)); |
| 326 break; |
| 327 } |
| 328 if (rtn > 0) { |
| 329 if (FD_ISSET(fd1, &readfds)) |
| 330 EchoInput(fd1); |
| 331 if (FD_ISSET(fd2, &readfds)) |
| 332 EchoInput(fd2); |
| 333 if (FD_ISSET(fd3, &readfds)) |
| 334 EchoInput(fd3); |
| 335 } |
| 336 |
| 337 } |
| 338 close(fd1); |
| 339 close(fd2); |
| 340 close(fd3); |
| 341 return 0; |
| 342 } |
| 343 |
282 /** | 344 /** |
283 * A worker thread that handles messages from JavaScript. | 345 * A worker thread that handles messages from JavaScript. |
284 * @param[in] user_data Unused. | 346 * @param[in] user_data Unused. |
285 * @return unused. | 347 * @return unused. |
286 */ | 348 */ |
287 void* HandleMessageThread(void* user_data) { | 349 void* HandleMessageThread(void* user_data) { |
288 while (1) { | 350 while (1) { |
289 struct PP_Var message = DequeueMessage(); | 351 struct PP_Var message = DequeueMessage(); |
290 HandleMessage(message); | 352 HandleMessage(message); |
291 g_ppb_var->Release(message); | 353 g_ppb_var->Release(message); |
(...skipping 19 matching lines...) Expand all Loading... |
311 0, /* mountflags */ | 373 0, /* mountflags */ |
312 "type=PERSISTENT,expected_size=1048576"); /* data */ | 374 "type=PERSISTENT,expected_size=1048576"); /* data */ |
313 | 375 |
314 mount("", /* source. Use relative URL */ | 376 mount("", /* source. Use relative URL */ |
315 "/http", /* target */ | 377 "/http", /* target */ |
316 "httpfs", /* filesystemtype */ | 378 "httpfs", /* filesystemtype */ |
317 0, /* mountflags */ | 379 0, /* mountflags */ |
318 ""); /* data */ | 380 ""); /* data */ |
319 | 381 |
320 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); | 382 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); |
| 383 pthread_create(&g_echo_thread, NULL, &EchoThread, NULL); |
321 InitializeMessageQueue(); | 384 InitializeMessageQueue(); |
322 | 385 |
323 return PP_TRUE; | 386 return PP_TRUE; |
324 } | 387 } |
325 | 388 |
326 static void Instance_DidDestroy(PP_Instance instance) { | 389 static void Instance_DidDestroy(PP_Instance instance) { |
327 } | 390 } |
328 | 391 |
329 static void Instance_DidChangeView(PP_Instance instance, | 392 static void Instance_DidChangeView(PP_Instance instance, |
330 PP_Resource view_resource) { | 393 PP_Resource view_resource) { |
331 } | 394 } |
332 | 395 |
333 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { | 396 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { |
334 } | 397 } |
335 | 398 |
336 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, | 399 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, |
337 PP_Resource url_loader) { | 400 PP_Resource url_loader) { |
338 /* NaCl modules do not need to handle the document load function. */ | 401 /* NaCl modules do not need to handle the document load function. */ |
339 return PP_FALSE; | 402 return PP_FALSE; |
340 } | 403 } |
341 | 404 |
342 static void Messaging_HandleMessage(PP_Instance instance, | 405 static void Messaging_HandleMessage(PP_Instance instance, |
343 struct PP_Var message) { | 406 struct PP_Var message) { |
| 407 /* Special case for jspipe input handling */ |
| 408 if (message.type != PP_VARTYPE_DICTIONARY) { |
| 409 PostMessage("Got unexpected message type: %d\n", message.type); |
| 410 return; |
| 411 } |
| 412 |
| 413 struct PP_Var pipe_var = CStrToVar("pipe"); |
| 414 struct PP_Var pipe_name = g_ppb_var_dictionary->Get(message, pipe_var); |
| 415 g_ppb_var->Release(pipe_var); |
| 416 |
| 417 /* Special case for jspipe input handling */ |
| 418 if (pipe_name.type == PP_VARTYPE_STRING) { |
| 419 char file_name[PATH_MAX]; |
| 420 snprintf(file_name, PATH_MAX, "/dev/%s", VarToCStr(pipe_name)); |
| 421 int fd = open(file_name, O_RDONLY); |
| 422 g_ppb_var->Release(pipe_name); |
| 423 if (fd < 0) { |
| 424 PostMessage("Warning: opening %s failed.", file_name); |
| 425 goto done; |
| 426 } |
| 427 if (ioctl(fd, NACL_IOC_HANDLEMESSAGE, &message) != 0) { |
| 428 PostMessage("Error: ioctl on %s failed: %s", file_name, strerror(errno)); |
| 429 } |
| 430 close(fd); |
| 431 goto done; |
| 432 } |
| 433 |
344 g_ppb_var->AddRef(message); | 434 g_ppb_var->AddRef(message); |
345 if (!EnqueueMessage(message)) { | 435 if (!EnqueueMessage(message)) { |
346 g_ppb_var->Release(message); | 436 g_ppb_var->Release(message); |
347 PostMessageVar( | 437 PostMessage("Warning: dropped message because the queue was full."); |
348 PrintfToVar("Warning: dropped message because the queue was full.")); | |
349 } | 438 } |
| 439 |
| 440 done: |
| 441 g_ppb_var->Release(pipe_name); |
350 } | 442 } |
351 | 443 |
352 #define GET_INTERFACE(var, type, name) \ | 444 #define GET_INTERFACE(var, type, name) \ |
353 var = (type*)(get_browser(name)); \ | 445 var = (type*)(get_browser(name)); \ |
354 if (!var) { \ | 446 if (!var) { \ |
355 printf("Unable to get interface " name "\n"); \ | 447 printf("Unable to get interface " name "\n"); \ |
356 return PP_ERROR_FAILED; \ | 448 return PP_ERROR_FAILED; \ |
357 } | 449 } |
358 | 450 |
359 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, | 451 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, |
(...skipping 21 matching lines...) Expand all Loading... |
381 static PPP_Messaging messaging_interface = { | 473 static PPP_Messaging messaging_interface = { |
382 &Messaging_HandleMessage, | 474 &Messaging_HandleMessage, |
383 }; | 475 }; |
384 return &messaging_interface; | 476 return &messaging_interface; |
385 } | 477 } |
386 return NULL; | 478 return NULL; |
387 } | 479 } |
388 | 480 |
389 PP_EXPORT void PPP_ShutdownModule() { | 481 PP_EXPORT void PPP_ShutdownModule() { |
390 } | 482 } |
OLD | NEW |