OLD | NEW |
---|---|
1 /* Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 /* Copyright (c) 2016 The Chromium Authors. All rights reserved. |
binji
2016/07/18 23:24:02
This ends up duplicating quite a bit of code from
chanpatorikku
2016/08/07 02:41:01
Done.
Thanks.
Added the functionality to the nacl
| |
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 #include "nacl_io_demo.h" | 5 #include "googledrivefs_demo.h" |
6 | 6 |
7 #include <assert.h> | 7 #include <assert.h> |
8 #include <errno.h> | 8 #include <errno.h> |
9 #include <fcntl.h> | 9 #include <fcntl.h> |
10 #include <limits.h> | 10 #include <limits.h> |
11 #include <stdio.h> | 11 #include <stdio.h> |
12 #include <stdlib.h> | 12 #include <stdlib.h> |
13 #include <string.h> | 13 #include <string.h> |
14 #include <sys/ioctl.h> | 14 #include <sys/ioctl.h> |
15 #include <sys/mount.h> | 15 #include <sys/mount.h> |
16 #include <sys/param.h> | 16 #include <sys/param.h> |
17 #include <sys/select.h> | 17 #include <sys/select.h> |
18 #include <sys/stat.h> | 18 #include <sys/stat.h> |
19 #include <pthread.h> | 19 #include <pthread.h> |
20 #include <unistd.h> | 20 #include <unistd.h> |
21 | 21 |
22 #include "ppapi/c/pp_errors.h" | 22 #include "ppapi/c/pp_errors.h" |
23 #include "ppapi/c/pp_module.h" | 23 #include "ppapi/c/pp_module.h" |
24 #include "ppapi/c/ppb.h" | 24 #include "ppapi/c/ppb.h" |
25 #include "ppapi/c/ppb_instance.h" | 25 #include "ppapi/c/ppb_instance.h" |
26 #include "ppapi/c/ppb_messaging.h" | 26 #include "ppapi/c/ppb_messaging.h" |
27 #include "ppapi/c/ppb_var.h" | 27 #include "ppapi/c/ppb_var.h" |
28 #include "ppapi/c/ppb_var_array.h" | 28 #include "ppapi/c/ppb_var_array.h" |
29 #include "ppapi/c/ppb_var_dictionary.h" | 29 #include "ppapi/c/ppb_var_dictionary.h" |
30 #include "ppapi/c/ppp.h" | 30 #include "ppapi/c/ppp.h" |
31 #include "ppapi/c/ppp_instance.h" | 31 #include "ppapi/c/ppp_instance.h" |
32 #include "ppapi/c/ppp_messaging.h" | 32 #include "ppapi/c/ppp_messaging.h" |
33 #include "nacl_io/ioctl.h" | |
34 #include "nacl_io/nacl_io.h" | 33 #include "nacl_io/nacl_io.h" |
35 | 34 |
35 #include "ppapi/cpp/module.h" | |
36 | |
36 #include "handlers.h" | 37 #include "handlers.h" |
37 #include "queue.h" | 38 #include "queue.h" |
38 | 39 |
39 #if defined(WIN32) | 40 #if defined(WIN32) |
40 #define va_copy(d, s) ((d) = (s)) | 41 #define va_copy(d, s) ((d) = (s)) |
41 #endif | 42 #endif |
42 | 43 |
43 /** | |
44 * The location of MAX is inconsitantly between LIBCs, so instead | |
45 * we define it here for consistency. | |
46 */ | |
47 static int larger_int_of(int a, int b) { | |
48 if (a > b) | |
49 return a; | |
50 return b; | |
51 } | |
52 | |
53 typedef struct { | 44 typedef struct { |
54 const char* name; | 45 const char* name; |
55 HandleFunc function; | 46 HandleFunc function; |
56 } FuncNameMapping; | 47 } FuncNameMapping; |
57 | 48 |
58 static PP_Instance g_instance = 0; | 49 static PP_Instance g_instance = 0; |
59 static PPB_GetInterface g_get_browser_interface = NULL; | 50 static PPB_GetInterface g_get_browser_interface = NULL; |
60 static PPB_Messaging* g_ppb_messaging = NULL; | 51 static PPB_Messaging* g_ppb_messaging = NULL; |
61 PPB_Var* g_ppb_var = NULL; | 52 PPB_Var* g_ppb_var = NULL; |
62 PPB_VarArray* g_ppb_var_array = NULL; | 53 PPB_VarArray* g_ppb_var_array = NULL; |
63 PPB_VarDictionary* g_ppb_var_dictionary = NULL; | 54 PPB_VarDictionary* g_ppb_var_dictionary = NULL; |
64 | 55 |
65 static FuncNameMapping g_function_map[] = { | 56 static FuncNameMapping g_function_map[] = { |
66 {"fopen", HandleFopen}, | 57 {"fopen", HandleFopen}, |
67 {"fwrite", HandleFwrite}, | 58 {"fwrite", HandleFwrite}, |
68 {"fread", HandleFread}, | 59 {"fread", HandleFread}, |
69 {"fseek", HandleFseek}, | 60 {"fseek", HandleFseek}, |
70 {"fclose", HandleFclose}, | 61 {"fclose", HandleFclose}, |
71 {"fflush", HandleFflush}, | 62 {"fflush", HandleFflush}, |
72 {"stat", HandleStat}, | 63 {"stat", HandleStat}, |
73 {"opendir", HandleOpendir}, | 64 {"opendir", HandleOpendir}, |
74 {"readdir", HandleReaddir}, | 65 {"readdir", HandleReaddir}, |
75 {"closedir", HandleClosedir}, | 66 {"closedir", HandleClosedir}, |
76 {"mkdir", HandleMkdir}, | 67 {"mkdir", HandleMkdir}, |
77 {"rmdir", HandleRmdir}, | 68 {"rmdir", HandleRmdir}, |
78 {"chdir", HandleChdir}, | 69 {"chdir", HandleChdir}, |
79 {"getcwd", HandleGetcwd}, | 70 {"getcwd", HandleGetcwd}, |
80 {"getaddrinfo", HandleGetaddrinfo}, | |
81 {"gethostbyname", HandleGethostbyname}, | |
82 {"connect", HandleConnect}, | |
83 {"send", HandleSend}, | |
84 {"recv", HandleRecv}, | |
85 {"close", HandleClose}, | |
86 {NULL, NULL}, | 71 {NULL, NULL}, |
87 }; | 72 }; |
88 | 73 |
89 /** A handle to the thread the handles messages. */ | 74 /** A handle to the thread the handles messages. */ |
90 static pthread_t g_handle_message_thread; | 75 static pthread_t g_handle_message_thread; |
91 static pthread_t g_echo_thread; | |
92 | 76 |
93 /** | 77 /** |
94 * Create a new PP_Var from a C string. | 78 * Create a new PP_Var from a C string. |
95 * @param[in] str The string to convert. | 79 * @param[in] str The string to convert. |
96 * @return A new PP_Var with the contents of |str|. | 80 * @return A new PP_Var with the contents of |str|. |
97 */ | 81 */ |
98 struct PP_Var CStrToVar(const char* str) { | 82 struct PP_Var CStrToVar(const char* str) { |
99 return g_ppb_var->VarFromUtf8(str, strlen(str)); | 83 return g_ppb_var->VarFromUtf8(str, strlen(str)); |
100 } | 84 } |
101 | 85 |
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
285 PostMessage("Error: \"%s\" failed.", function_name); | 269 PostMessage("Error: \"%s\" failed.", function_name); |
286 } | 270 } |
287 return; | 271 return; |
288 } | 272 } |
289 | 273 |
290 /* Function returned an output dictionary. Send it to JavaScript. */ | 274 /* Function returned an output dictionary. Send it to JavaScript. */ |
291 g_ppb_messaging->PostMessage(g_instance, result_var); | 275 g_ppb_messaging->PostMessage(g_instance, result_var); |
292 g_ppb_var->Release(result_var); | 276 g_ppb_var->Release(result_var); |
293 } | 277 } |
294 | 278 |
295 | |
296 /** | |
297 * Helper function used by EchoThread which reads from a file descriptor | |
298 * and writes all the data that it reads back to the same descriptor. | |
299 */ | |
300 static void EchoInput(int fd) { | |
301 char buffer[512]; | |
302 while (1) { | |
303 int rtn = read(fd, buffer, 512); | |
304 if (rtn > 0) { | |
305 int wrote = write(fd, buffer, rtn); | |
306 if (wrote < rtn) | |
307 PostMessage("only wrote %d/%d bytes\n", wrote, rtn); | |
308 } else { | |
309 if (rtn < 0 && errno != EAGAIN) | |
310 PostMessage("read failed: %d (%s)\n", errno, strerror(errno)); | |
311 break; | |
312 } | |
313 } | |
314 } | |
315 | |
316 /** | |
317 * Worker thread that listens for input on JS pipe nodes and echos all input | |
318 * back to the same pipe. | |
319 */ | |
320 static void* EchoThread(void* user_data) { | |
321 int fd1 = open("/dev/jspipe1", O_RDWR | O_NONBLOCK); | |
322 int fd2 = open("/dev/jspipe2", O_RDWR | O_NONBLOCK); | |
323 int fd3 = open("/dev/jspipe3", O_RDWR | O_NONBLOCK); | |
324 int nfds = larger_int_of(fd1, fd2); | |
325 nfds = larger_int_of(nfds, fd3); | |
326 while (1) { | |
327 fd_set readfds; | |
328 FD_ZERO(&readfds); | |
329 FD_SET(fd1, &readfds); | |
330 FD_SET(fd2, &readfds); | |
331 FD_SET(fd3, &readfds); | |
332 int rtn = select(nfds + 1, &readfds, NULL, NULL, NULL); | |
333 if (rtn < 0 && errno != EAGAIN) { | |
334 PostMessage("select failed: %s\n", strerror(errno)); | |
335 break; | |
336 } | |
337 if (rtn > 0) { | |
338 if (FD_ISSET(fd1, &readfds)) | |
339 EchoInput(fd1); | |
340 if (FD_ISSET(fd2, &readfds)) | |
341 EchoInput(fd2); | |
342 if (FD_ISSET(fd3, &readfds)) | |
343 EchoInput(fd3); | |
344 } | |
345 | |
346 } | |
347 close(fd1); | |
348 close(fd2); | |
349 close(fd3); | |
350 return 0; | |
351 } | |
352 | |
353 /** | 279 /** |
354 * A worker thread that handles messages from JavaScript. | 280 * A worker thread that handles messages from JavaScript. |
355 * @param[in] user_data Unused. | 281 * @param[in] user_data Unused. |
356 * @return unused. | 282 * @return unused. |
357 */ | 283 */ |
358 void* HandleMessageThread(void* user_data) { | 284 void* HandleMessageThread(void* user_data) { |
359 while (1) { | 285 while (1) { |
360 struct PP_Var message = DequeueMessage(); | 286 struct PP_Var message = DequeueMessage(); |
361 HandleMessage(message); | 287 HandleMessage(message); |
362 g_ppb_var->Release(message); | 288 g_ppb_var->Release(message); |
363 } | 289 } |
364 } | 290 } |
365 | 291 |
366 static PP_Bool Instance_DidCreate(PP_Instance instance, | 292 static PP_Bool Instance_DidCreate(PP_Instance instance, |
367 uint32_t argc, | 293 uint32_t argc, |
368 const char* argn[], | 294 const char* argn[], |
369 const char* argv[]) { | 295 const char* argv[]) { |
370 g_instance = instance; | 296 for (int i = 0; i < argc; ++i) { |
371 nacl_io_init_ppapi(instance, g_get_browser_interface); | 297 if (strcmp(argn[i], "token") == 0) { |
298 char buffer[1024]; | |
299 int char_written = | |
300 sprintf(buffer, "instance=%i,token=%s", instance, argv[i]); | |
301 if (char_written < 0) { | |
302 return PP_FALSE; | |
303 } | |
372 | 304 |
373 // By default, nacl_io mounts / to pass through to the original NaCl | 305 g_instance = instance; |
374 // filesystem (which doesn't do much). Let's remount it to a memfs | 306 nacl_io_init_ppapi(instance, g_get_browser_interface); |
375 // filesystem. | |
376 umount("/"); | |
377 mount("", "/", "memfs", 0, ""); | |
378 | 307 |
379 mount("", /* source */ | 308 // By default, nacl_io mounts / to pass through to the original NaCl |
380 "/persistent", /* target */ | 309 // filesystem (which doesn't do much). Let's remount it to a googledrivefs |
381 "html5fs", /* filesystemtype */ | 310 // filesystem. |
382 0, /* mountflags */ | 311 umount("/"); |
383 "type=PERSISTENT,expected_size=1048576"); /* data */ | |
384 | 312 |
385 mount("", /* source. Use relative URL */ | 313 mount("", |
386 "/http", /* target */ | 314 "/", |
387 "httpfs", /* filesystemtype */ | 315 "googledrivefs", |
388 0, /* mountflags */ | 316 0, |
389 ""); /* data */ | 317 buffer); |
390 | 318 |
391 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL); | 319 pthread_create(&g_handle_message_thread, |
392 pthread_create(&g_echo_thread, NULL, &EchoThread, NULL); | 320 NULL, &HandleMessageThread, NULL); |
393 InitializeMessageQueue(); | 321 InitializeMessageQueue(); |
322 | |
323 return PP_TRUE; | |
324 } | |
325 } | |
394 | 326 |
395 return PP_TRUE; | 327 return PP_FALSE; |
396 } | 328 } |
397 | 329 |
398 static void Instance_DidDestroy(PP_Instance instance) { | 330 static void Instance_DidDestroy(PP_Instance instance) { |
399 } | 331 } |
400 | 332 |
401 static void Instance_DidChangeView(PP_Instance instance, | 333 static void Instance_DidChangeView(PP_Instance instance, |
402 PP_Resource view_resource) { | 334 PP_Resource view_resource) { |
403 } | 335 } |
404 | 336 |
405 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { | 337 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) { |
406 } | 338 } |
407 | 339 |
408 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, | 340 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance, |
409 PP_Resource url_loader) { | 341 PP_Resource url_loader) { |
410 /* NaCl modules do not need to handle the document load function. */ | 342 /* NaCl modules do not need to handle the document load function. */ |
411 return PP_FALSE; | 343 return PP_FALSE; |
412 } | 344 } |
413 | 345 |
414 static void Messaging_HandleMessage(PP_Instance instance, | 346 static void Messaging_HandleMessage(PP_Instance instance, |
415 struct PP_Var message) { | 347 struct PP_Var message) { |
416 /* Special case for jspipe input handling */ | |
417 if (message.type != PP_VARTYPE_DICTIONARY) { | |
418 PostMessage("Got unexpected message type: %d\n", message.type); | |
419 return; | |
420 } | |
421 | |
422 struct PP_Var pipe_var = CStrToVar("pipe"); | |
423 struct PP_Var pipe_name = g_ppb_var_dictionary->Get(message, pipe_var); | |
424 g_ppb_var->Release(pipe_var); | |
425 | |
426 /* Special case for jspipe input handling */ | |
427 if (pipe_name.type == PP_VARTYPE_STRING) { | |
428 char file_name[PATH_MAX]; | |
429 snprintf(file_name, PATH_MAX, "/dev/%s", VarToCStr(pipe_name)); | |
430 int fd = open(file_name, O_RDONLY); | |
431 g_ppb_var->Release(pipe_name); | |
432 if (fd < 0) { | |
433 PostMessage("Warning: opening %s failed.", file_name); | |
434 goto done; | |
435 } | |
436 if (ioctl(fd, NACL_IOC_HANDLEMESSAGE, &message) != 0) { | |
437 PostMessage("Error: ioctl on %s failed: %s", file_name, strerror(errno)); | |
438 } | |
439 close(fd); | |
440 goto done; | |
441 } | |
442 | |
443 g_ppb_var->AddRef(message); | 348 g_ppb_var->AddRef(message); |
444 if (!EnqueueMessage(message)) { | 349 if (!EnqueueMessage(message)) { |
445 g_ppb_var->Release(message); | 350 g_ppb_var->Release(message); |
446 PostMessage("Warning: dropped message because the queue was full."); | 351 PostMessage("Warning: dropped message because the queue was full."); |
447 } | 352 } |
353 } | |
448 | 354 |
449 done: | 355 class GoogleDriveFsDemoModule : public pp::Module { |
450 g_ppb_var->Release(pipe_name); | 356 public: |
357 pp::Instance* CreateInstance(PP_Instance instance) { return NULL; } | |
358 }; | |
359 | |
360 GoogleDriveFsDemoModule* g_googledrivefs_demo_module = NULL; | |
361 | |
362 namespace pp { | |
363 | |
364 Module* Module::Get() { | |
365 return g_googledrivefs_demo_module; | |
451 } | 366 } |
452 | 367 |
368 } // namespace pp | |
369 | |
453 #define GET_INTERFACE(var, type, name) \ | 370 #define GET_INTERFACE(var, type, name) \ |
454 var = (type*)(get_browser(name)); \ | 371 var = (type*)(get_browser(name)); \ |
455 if (!var) { \ | 372 if (!var) { \ |
456 printf("Unable to get interface " name "\n"); \ | 373 printf("Unable to get interface " name "\n"); \ |
457 return PP_ERROR_FAILED; \ | 374 return PP_ERROR_FAILED; \ |
458 } | 375 } |
459 | 376 |
460 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, | 377 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id, |
461 PPB_GetInterface get_browser) { | 378 PPB_GetInterface get_browser) { |
379 g_googledrivefs_demo_module = new GoogleDriveFsDemoModule(); | |
380 | |
462 g_get_browser_interface = get_browser; | 381 g_get_browser_interface = get_browser; |
382 | |
463 GET_INTERFACE(g_ppb_messaging, PPB_Messaging, PPB_MESSAGING_INTERFACE); | 383 GET_INTERFACE(g_ppb_messaging, PPB_Messaging, PPB_MESSAGING_INTERFACE); |
464 GET_INTERFACE(g_ppb_var, PPB_Var, PPB_VAR_INTERFACE); | 384 GET_INTERFACE(g_ppb_var, PPB_Var, PPB_VAR_INTERFACE); |
465 GET_INTERFACE(g_ppb_var_array, PPB_VarArray, PPB_VAR_ARRAY_INTERFACE); | 385 GET_INTERFACE(g_ppb_var_array, PPB_VarArray, PPB_VAR_ARRAY_INTERFACE); |
466 GET_INTERFACE( | 386 GET_INTERFACE( |
467 g_ppb_var_dictionary, PPB_VarDictionary, PPB_VAR_DICTIONARY_INTERFACE); | 387 g_ppb_var_dictionary, PPB_VarDictionary, PPB_VAR_DICTIONARY_INTERFACE); |
388 | |
389 if (!g_googledrivefs_demo_module->InternalInit(a_module_id, get_browser)) { | |
390 delete g_googledrivefs_demo_module; | |
391 return PP_ERROR_FAILED; | |
392 } | |
393 | |
468 return PP_OK; | 394 return PP_OK; |
469 } | 395 } |
470 | 396 |
471 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { | 397 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) { |
472 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { | 398 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) { |
473 static PPP_Instance instance_interface = { | 399 static PPP_Instance instance_interface = { |
474 &Instance_DidCreate, | 400 &Instance_DidCreate, |
475 &Instance_DidDestroy, | 401 &Instance_DidDestroy, |
476 &Instance_DidChangeView, | 402 &Instance_DidChangeView, |
477 &Instance_DidChangeFocus, | 403 &Instance_DidChangeFocus, |
478 &Instance_HandleDocumentLoad, | 404 &Instance_HandleDocumentLoad, |
479 }; | 405 }; |
480 return &instance_interface; | 406 return &instance_interface; |
481 } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) { | 407 } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) { |
482 static PPP_Messaging messaging_interface = { | 408 static PPP_Messaging messaging_interface = { |
483 &Messaging_HandleMessage, | 409 &Messaging_HandleMessage, |
484 }; | 410 }; |
485 return &messaging_interface; | 411 return &messaging_interface; |
486 } | 412 } |
487 return NULL; | 413 return NULL; |
488 } | 414 } |
489 | 415 |
490 PP_EXPORT void PPP_ShutdownModule() { | 416 PP_EXPORT void PPP_ShutdownModule() { |
491 } | 417 } |
OLD | NEW |