Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(457)

Side by Side Diff: native_client_sdk/src/examples/demo/googledrivefs_demo/googledrivefs_demo.cc

Issue 2156503002: [NaCl SDK] Expose Google Drive to nacl_io. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698