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> | |
9 #include <stdio.h> | 11 #include <stdio.h> |
10 #include <stdlib.h> | 12 #include <stdlib.h> |
11 #include <string.h> | 13 #include <string.h> |
14 #include <sys/ioctl.h> | |
12 #include <sys/mount.h> | 15 #include <sys/mount.h> |
16 #include <sys/param.h> | |
17 #include <sys/select.h> | |
18 #include <sys/stat.h> | |
13 #include <pthread.h> | 19 #include <pthread.h> |
20 #include <unistd.h> | |
14 | 21 |
15 #include "ppapi/c/pp_errors.h" | 22 #include "ppapi/c/pp_errors.h" |
16 #include "ppapi/c/pp_module.h" | 23 #include "ppapi/c/pp_module.h" |
17 #include "ppapi/c/ppb.h" | 24 #include "ppapi/c/ppb.h" |
18 #include "ppapi/c/ppb_instance.h" | 25 #include "ppapi/c/ppb_instance.h" |
19 #include "ppapi/c/ppb_messaging.h" | 26 #include "ppapi/c/ppb_messaging.h" |
20 #include "ppapi/c/ppb_var.h" | 27 #include "ppapi/c/ppb_var.h" |
21 #include "ppapi/c/ppb_var_array.h" | 28 #include "ppapi/c/ppb_var_array.h" |
22 #include "ppapi/c/ppb_var_dictionary.h" | 29 #include "ppapi/c/ppb_var_dictionary.h" |
23 #include "ppapi/c/ppp.h" | 30 #include "ppapi/c/ppp.h" |
24 #include "ppapi/c/ppp_instance.h" | 31 #include "ppapi/c/ppp_instance.h" |
25 #include "ppapi/c/ppp_messaging.h" | 32 #include "ppapi/c/ppp_messaging.h" |
33 #include "nacl_io/ioctl.h" | |
26 #include "nacl_io/nacl_io.h" | 34 #include "nacl_io/nacl_io.h" |
27 | 35 |
28 #include "handlers.h" | 36 #include "handlers.h" |
29 #include "queue.h" | 37 #include "queue.h" |
30 | 38 |
31 #if defined(WIN32) | 39 #if defined(WIN32) |
32 #define va_copy(d, s) ((d) = (s)) | 40 #define va_copy(d, s) ((d) = (s)) |
33 #endif | 41 #endif |
34 | 42 |
35 typedef struct { | 43 typedef struct { |
36 const char* name; | 44 const char* name; |
37 HandleFunc function; | 45 HandleFunc function; |
38 } FuncNameMapping; | 46 } FuncNameMapping; |
39 | 47 |
40 PP_Instance g_instance = 0; | 48 static PP_Instance g_instance = 0; |
41 PPB_GetInterface g_get_browser_interface = NULL; | 49 static PPB_GetInterface g_get_browser_interface = NULL; |
42 PPB_Messaging* g_ppb_messaging = NULL; | 50 static PPB_Messaging* g_ppb_messaging = NULL; |
43 PPB_Var* g_ppb_var = NULL; | 51 PPB_Var* g_ppb_var = NULL; |
44 PPB_VarArray* g_ppb_var_array = NULL; | 52 PPB_VarArray* g_ppb_var_array = NULL; |
45 PPB_VarDictionary* g_ppb_var_dictionary = NULL; | 53 PPB_VarDictionary* g_ppb_var_dictionary = NULL; |
46 | 54 |
47 static FuncNameMapping g_function_map[] = { | 55 static FuncNameMapping g_function_map[] = { |
48 {"fopen", HandleFopen}, | 56 {"fopen", HandleFopen}, |
49 {"fwrite", HandleFwrite}, | 57 {"fwrite", HandleFwrite}, |
50 {"fread", HandleFread}, | 58 {"fread", HandleFread}, |
51 {"fseek", HandleFseek}, | 59 {"fseek", HandleFseek}, |
52 {"fclose", HandleFclose}, | 60 {"fclose", HandleFclose}, |
(...skipping 10 matching lines...) Expand all Loading... | |
63 {"gethostbyname", HandleGethostbyname}, | 71 {"gethostbyname", HandleGethostbyname}, |
64 {"connect", HandleConnect}, | 72 {"connect", HandleConnect}, |
65 {"send", HandleSend}, | 73 {"send", HandleSend}, |
66 {"recv", HandleRecv}, | 74 {"recv", HandleRecv}, |
67 {"close", HandleClose}, | 75 {"close", HandleClose}, |
68 {NULL, NULL}, | 76 {NULL, NULL}, |
69 }; | 77 }; |
70 | 78 |
71 /** A handle to the thread the handles messages. */ | 79 /** A handle to the thread the handles messages. */ |
72 static pthread_t g_handle_message_thread; | 80 static pthread_t g_handle_message_thread; |
81 static pthread_t g_echo_thread; | |
73 | 82 |
74 /** | 83 /** |
75 * Create a new PP_Var from a C string. | 84 * Create a new PP_Var from a C string. |
76 * @param[in] str The string to convert. | 85 * @param[in] str The string to convert. |
77 * @return A new PP_Var with the contents of |str|. | 86 * @return A new PP_Var with the contents of |str|. |
78 */ | 87 */ |
79 struct PP_Var CStrToVar(const char* str) { | 88 struct PP_Var CStrToVar(const char* str) { |
80 return g_ppb_var->VarFromUtf8(str, strlen(str)); | 89 return g_ppb_var->VarFromUtf8(str, strlen(str)); |
81 } | 90 } |
82 | 91 |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
132 string = VprintfToNewString(format, args); | 141 string = VprintfToNewString(format, args); |
133 va_end(args); | 142 va_end(args); |
134 | 143 |
135 var = g_ppb_var->VarFromUtf8(string, strlen(string)); | 144 var = g_ppb_var->VarFromUtf8(string, strlen(string)); |
136 free(string); | 145 free(string); |
137 | 146 |
138 return var; | 147 return var; |
139 } | 148 } |
140 | 149 |
141 /** | 150 /** |
142 * Convert a PP_Var to a C string, given a buffer. | 151 * Convert a PP_Var to a C string. |
143 * @param[in] var The PP_Var to convert. | 152 * @param[in] var The PP_Var to convert. |
144 * @param[out] buffer The buffer to write to. | 153 * @return A newly allocated, NULL-terminated string. |
145 * @param[in] length The length of |buffer|. | |
146 * @return The number of characters written. | |
147 */ | 154 */ |
148 const char* VarToCStr(struct PP_Var var) { | 155 static const char* VarToCStr(struct PP_Var var) { |
149 uint32_t length; | 156 uint32_t length; |
150 const char* str = g_ppb_var->VarToUtf8(var, &length); | 157 const char* str = g_ppb_var->VarToUtf8(var, &length); |
151 if (str == NULL) { | 158 if (str == NULL) { |
152 return NULL; | 159 return NULL; |
153 } | 160 } |
154 | 161 |
155 /* str is NOT NULL-terminated. Copy using memcpy. */ | 162 /* str is NOT NULL-terminated. Copy using memcpy. */ |
156 char* new_str = (char*)malloc(length + 1); | 163 char* new_str = (char*)malloc(length + 1); |
157 memcpy(new_str, str, length); | 164 memcpy(new_str, str, length); |
158 new_str[length] = 0; | 165 new_str[length] = 0; |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
272 /* Post the error to JavaScript, so the user can see it. */ | 279 /* Post the error to JavaScript, so the user can see it. */ |
273 PostMessageVar(var); | 280 PostMessageVar(var); |
274 return; | 281 return; |
275 } | 282 } |
276 | 283 |
277 /* Function returned an output dictionary. Send it to JavaScript. */ | 284 /* Function returned an output dictionary. Send it to JavaScript. */ |
278 PostMessageVar(result_var); | 285 PostMessageVar(result_var); |
279 g_ppb_var->Release(result_var); | 286 g_ppb_var->Release(result_var); |
280 } | 287 } |
281 | 288 |
289 | |
290 /** | |
291 * Helper function used by EchoThread which reads from a file descriptor | |
292 * and writes all the data that it reads back to the same descriptor. | |
293 */ | |
294 static void EchoInput(int fd) { | |
295 char buffer[512]; | |
296 while (1) { | |
297 int rtn = read(fd, buffer, 512); | |
298 if (rtn > 0) { | |
299 int wrote = write(fd, buffer, rtn); | |
300 if (wrote < rtn) | |
301 fprintf(stderr, "only wrote %d/%d bytes\n", wrote, rtn); | |
binji
2014/05/01 20:22:31
might be nice to send these errors to JavaScript,
Sam Clegg
2014/05/01 22:16:55
Done.
| |
302 } else { | |
303 if (rtn < 0 && errno != EAGAIN) | |
304 fprintf(stderr, "read failed: %d (%s)\n", errno, strerror(errno)); | |
305 break; | |
306 } | |
307 } | |
308 } | |
309 | |
310 /** | |
311 * Worker thread that listens for input on JS pipe nodes and echos all input | |
312 * back to the same pipe. | |
313 */ | |
314 static void* EchoThread(void* user_data) { | |
315 int fd1 = open("/dev/jspipe1", O_RDWR | O_NONBLOCK); | |
316 int fd2 = open("/dev/jspipe2", O_RDWR | O_NONBLOCK); | |
317 int fd3 = open("/dev/jspipe3", O_RDWR | O_NONBLOCK); | |
318 int nfds = MAX(fd1, fd2); | |
319 nfds = MAX(nfds, fd3); | |
320 while (1) { | |
321 fd_set readfds; | |
322 FD_ZERO(&readfds); | |
323 FD_SET(fd1, &readfds); | |
324 FD_SET(fd2, &readfds); | |
325 FD_SET(fd3, &readfds); | |
326 int rtn = select(nfds + 1, &readfds, NULL, NULL, NULL); | |
327 if (rtn < 0 && errno != EAGAIN) { | |
328 fprintf(stderr, "select failed: %s\n", strerror(errno)); | |
329 break; | |
330 } | |
331 if (rtn > 0) { | |
332 if (FD_ISSET(fd1, &readfds)) | |
333 EchoInput(fd1); | |
334 if (FD_ISSET(fd2, &readfds)) | |
335 EchoInput(fd2); | |
336 if (FD_ISSET(fd3, &readfds)) | |
337 EchoInput(fd3); | |
338 } | |
339 | |
340 } | |
341 close(fd1); | |
342 close(fd2); | |
343 close(fd3); | |
344 return 0; | |
345 } | |
346 | |
282 /** | 347 /** |
283 * A worker thread that handles messages from JavaScript. | 348 * A worker thread that handles messages from JavaScript. |
284 * @param[in] user_data Unused. | 349 * @param[in] user_data Unused. |
285 * @return unused. | 350 * @return unused. |
286 */ | 351 */ |
287 void* HandleMessageThread(void* user_data) { | 352 void* HandleMessageThread(void* user_data) { |
288 while (1) { | 353 while (1) { |
289 struct PP_Var message = DequeueMessage(); | 354 struct PP_Var message = DequeueMessage(); |
290 HandleMessage(message); | 355 HandleMessage(message); |
291 g_ppb_var->Release(message); | 356 g_ppb_var->Release(message); |
(...skipping 19 matching lines...) Expand all Loading... | |
311 0, /* mountflags */ | 376 0, /* mountflags */ |
312 "type=PERSISTENT,expected_size=1048576"); /* data */ | 377 "type=PERSISTENT,expected_size=1048576"); /* data */ |
313 | 378 |
314 mount("", /* source. Use relative URL */ | 379 mount("", /* source. Use relative URL */ |
315 "/http", /* target */ | 380 "/http", /* target */ |
316 "httpfs", /* filesystemtype */ | 381 "httpfs", /* filesystemtype */ |
317 0, /* mountflags */ | 382 0, /* mountflags */ |
318 ""); /* data */ | 383 ""); /* data */ |
319 | 384 |
320 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); | 385 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); |
386 pthread_create(&g_echo_thread, NULL, &EchoThread, NULL); | |
321 InitializeMessageQueue(); | 387 InitializeMessageQueue(); |
322 | 388 |
323 return PP_TRUE; | 389 return PP_TRUE; |
324 } | 390 } |
325 | 391 |
326 static void Instance_DidDestroy(PP_Instance instance) { | 392 static void Instance_DidDestroy(PP_Instance instance) { |
327 } | 393 } |
328 | 394 |
329 static void Instance_DidChangeView(PP_Instance instance, | 395 static void Instance_DidChangeView(PP_Instance instance, |
330 PP_Resource view_resource) { | 396 PP_Resource view_resource) { |
331 } | 397 } |
332 | 398 |
333 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { | 399 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { |
334 } | 400 } |
335 | 401 |
336 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, | 402 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, |
337 PP_Resource url_loader) { | 403 PP_Resource url_loader) { |
338 /* NaCl modules do not need to handle the document load function. */ | 404 /* NaCl modules do not need to handle the document load function. */ |
339 return PP_FALSE; | 405 return PP_FALSE; |
340 } | 406 } |
341 | 407 |
342 static void Messaging_HandleMessage(PP_Instance instance, | 408 static void Messaging_HandleMessage(PP_Instance instance, |
343 struct PP_Var message) { | 409 struct PP_Var message) { |
410 /* Special case for jspipe input handling */ | |
411 if (message.type == PP_VARTYPE_DICTIONARY) { | |
binji
2014/05/01 20:22:31
this won't work anymore because all messages are d
Sam Clegg
2014/05/01 22:16:55
Done.
| |
412 struct PP_Var keys = g_ppb_var_dictionary->GetKeys(message); | |
413 struct PP_Var key = g_ppb_var_array->Get(keys, 0); | |
414 const char* key_string = VarToCStr(key); | |
415 char pipe_name[64]; | |
416 | |
417 sprintf(pipe_name, "/dev/%s", key_string); | |
binji
2014/05/01 20:22:31
snprintf
| |
418 int fd = open(pipe_name, O_RDONLY); | |
419 if (fd < 0) { | |
420 struct PP_Var var = PrintfToVar("Warning: opening %s failed.", | |
421 pipe_name); | |
422 g_ppb_messaging->PostMessage(g_instance, var); | |
binji
2014/05/01 20:22:31
Use PostMessageVar to cleanup the newly created st
Sam Clegg
2014/05/01 22:16:55
Done.
| |
423 return; | |
binji
2014/05/01 20:22:31
release PP_Vars on failure
Sam Clegg
2014/05/01 22:16:55
Done.
| |
424 } | |
425 struct PP_Var payload = g_ppb_var_dictionary->Get(message, key); | |
426 if (ioctl(fd, NACL_IOC_HANDLEMESSAGE, (char*)&payload) != 0) { | |
427 struct PP_Var var = PrintfToVar("Error: ioctl on %s failed: %s", | |
428 pipe_name, strerror(errno)); | |
429 g_ppb_messaging->PostMessage(g_instance, var); | |
430 } | |
431 g_ppb_var->Release(keys); | |
432 g_ppb_var->Release(key); | |
433 g_ppb_var->Release(payload); | |
434 close(fd); | |
435 return; | |
436 } | |
437 | |
344 g_ppb_var->AddRef(message); | 438 g_ppb_var->AddRef(message); |
345 if (!EnqueueMessage(message)) { | 439 if (!EnqueueMessage(message)) { |
346 g_ppb_var->Release(message); | 440 g_ppb_var->Release(message); |
347 PostMessageVar( | 441 PostMessageVar( |
348 PrintfToVar("Warning: dropped message because the queue was full.")); | 442 PrintfToVar("Warning: dropped message because the queue was full.")); |
349 } | 443 } |
350 } | 444 } |
351 | 445 |
352 #define GET_INTERFACE(var, type, name) \ | 446 #define GET_INTERFACE(var, type, name) \ |
353 var = (type*)(get_browser(name)); \ | 447 var = (type*)(get_browser(name)); \ |
(...skipping 27 matching lines...) Expand all Loading... | |
381 static PPP_Messaging messaging_interface = { | 475 static PPP_Messaging messaging_interface = { |
382 &Messaging_HandleMessage, | 476 &Messaging_HandleMessage, |
383 }; | 477 }; |
384 return &messaging_interface; | 478 return &messaging_interface; |
385 } | 479 } |
386 return NULL; | 480 return NULL; |
387 } | 481 } |
388 | 482 |
389 PP_EXPORT void PPP_ShutdownModule() { | 483 PP_EXPORT void PPP_ShutdownModule() { |
390 } | 484 } |
OLD | NEW |