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