Chromium Code Reviews| 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 |