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

Side by Side Diff: native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.c

Issue 306973002: [NaCl SDK] rename nacl_io demo. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 6 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 * found in the LICENSE file.
4 */
5
6 #include "nacl_io_demo.h"
7
8 #include <assert.h>
9 #include <errno.h>
10 #include <fcntl.h>
11 #include <limits.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/mount.h>
17 #include <sys/param.h>
18 #include <sys/select.h>
19 #include <sys/stat.h>
20 #include <pthread.h>
21 #include <unistd.h>
22
23 #include "ppapi/c/pp_errors.h"
24 #include "ppapi/c/pp_module.h"
25 #include "ppapi/c/ppb.h"
26 #include "ppapi/c/ppb_instance.h"
27 #include "ppapi/c/ppb_messaging.h"
28 #include "ppapi/c/ppb_var.h"
29 #include "ppapi/c/ppb_var_array.h"
30 #include "ppapi/c/ppb_var_dictionary.h"
31 #include "ppapi/c/ppp.h"
32 #include "ppapi/c/ppp_instance.h"
33 #include "ppapi/c/ppp_messaging.h"
34 #include "nacl_io/ioctl.h"
35 #include "nacl_io/nacl_io.h"
36
37 #include "handlers.h"
38 #include "queue.h"
39
40 #if defined(WIN32)
41 #define va_copy(d, s) ((d) = (s))
42 #endif
43
44 typedef struct {
45 const char* name;
46 HandleFunc function;
47 } FuncNameMapping;
48
49 static PP_Instance g_instance = 0;
50 static PPB_GetInterface g_get_browser_interface = NULL;
51 static PPB_Messaging* g_ppb_messaging = NULL;
52 PPB_Var* g_ppb_var = NULL;
53 PPB_VarArray* g_ppb_var_array = NULL;
54 PPB_VarDictionary* g_ppb_var_dictionary = NULL;
55
56 static FuncNameMapping g_function_map[] = {
57 {"fopen", HandleFopen},
58 {"fwrite", HandleFwrite},
59 {"fread", HandleFread},
60 {"fseek", HandleFseek},
61 {"fclose", HandleFclose},
62 {"fflush", HandleFflush},
63 {"stat", HandleStat},
64 {"opendir", HandleOpendir},
65 {"readdir", HandleReaddir},
66 {"closedir", HandleClosedir},
67 {"mkdir", HandleMkdir},
68 {"rmdir", HandleRmdir},
69 {"chdir", HandleChdir},
70 {"getcwd", HandleGetcwd},
71 {"getaddrinfo", HandleGetaddrinfo},
72 {"gethostbyname", HandleGethostbyname},
73 {"connect", HandleConnect},
74 {"send", HandleSend},
75 {"recv", HandleRecv},
76 {"close", HandleClose},
77 {NULL, NULL},
78 };
79
80 /** A handle to the thread the handles messages. */
81 static pthread_t g_handle_message_thread;
82 static pthread_t g_echo_thread;
83
84 /**
85 * Create a new PP_Var from a C string.
86 * @param[in] str The string to convert.
87 * @return A new PP_Var with the contents of |str|.
88 */
89 struct PP_Var CStrToVar(const char* str) {
90 return g_ppb_var->VarFromUtf8(str, strlen(str));
91 }
92
93 /**
94 * Printf to a newly allocated C string.
95 * @param[in] format A printf format string.
96 * @param[in] args The printf arguments.
97 * @return The newly constructed string. Caller takes ownership. */
98 char* VprintfToNewString(const char* format, va_list args) {
99 va_list args_copy;
100 int length;
101 char* buffer;
102 int result;
103
104 va_copy(args_copy, args);
105 length = vsnprintf(NULL, 0, format, args);
106 buffer = (char*)malloc(length + 1); /* +1 for NULL-terminator. */
107 result = vsnprintf(&buffer[0], length + 1, format, args_copy);
108 if (result != length) {
109 assert(0);
110 return NULL;
111 }
112 return buffer;
113 }
114
115 /**
116 * Printf to a newly allocated C string.
117 * @param[in] format A print format string.
118 * @param[in] ... The printf arguments.
119 * @return The newly constructed string. Caller takes ownership.
120 */
121 char* PrintfToNewString(const char* format, ...) {
122 va_list args;
123 char* result;
124 va_start(args, format);
125 result = VprintfToNewString(format, args);
126 va_end(args);
127 return result;
128 }
129
130 /**
131 * Vprintf to a new PP_Var.
132 * @param[in] format A print format string.
133 * @param[in] va_list The printf arguments.
134 * @return A new PP_Var.
135 */
136 static struct PP_Var VprintfToVar(const char* format, va_list args) {
137 struct PP_Var var;
138 char* string = VprintfToNewString(format, args);
139 var = g_ppb_var->VarFromUtf8(string, strlen(string));
140 free(string);
141 return var;
142 }
143
144 /**
145 * Convert a PP_Var to a C string.
146 * @param[in] var The PP_Var to convert.
147 * @return A newly allocated, NULL-terminated string.
148 */
149 static const char* VarToCStr(struct PP_Var var) {
150 uint32_t length;
151 const char* str = g_ppb_var->VarToUtf8(var, &length);
152 if (str == NULL) {
153 return NULL;
154 }
155
156 /* str is NOT NULL-terminated. Copy using memcpy. */
157 char* new_str = (char*)malloc(length + 1);
158 memcpy(new_str, str, length);
159 new_str[length] = 0;
160 return new_str;
161 }
162
163 /**
164 * Get a value from a Dictionary, given a string key.
165 * @param[in] dict The dictionary to look in.
166 * @param[in] key The key to look up.
167 * @return PP_Var The value at |key| in the |dict|. If the key doesn't exist,
168 * return a PP_Var with the undefined value.
169 */
170 struct PP_Var GetDictVar(struct PP_Var dict, const char* key) {
171 struct PP_Var key_var = CStrToVar(key);
172 struct PP_Var value = g_ppb_var_dictionary->Get(dict, key_var);
173 g_ppb_var->Release(key_var);
174 return value;
175 }
176
177 /**
178 * Post a message to JavaScript.
179 * @param[in] format A printf format string.
180 * @param[in] ... The printf arguments.
181 */
182 static void PostMessage(const char* format, ...) {
183 struct PP_Var var;
184 va_list args;
185
186 va_start(args, format);
187 var = VprintfToVar(format, args);
188 va_end(args);
189
190 g_ppb_messaging->PostMessage(g_instance, var);
191 g_ppb_var->Release(var);
192 }
193
194 /**
195 * Given a message from JavaScript, parse it for functions and parameters.
196 *
197 * The format of the message is:
198 * {
199 * "cmd": <function name>,
200 * "args": [<arg0>, <arg1>, ...]
201 * }
202 *
203 * @param[in] message The message to parse.
204 * @param[out] out_function The function name.
205 * @param[out] out_params A PP_Var array.
206 * @return 0 if successful, otherwise 1.
207 */
208 static int ParseMessage(struct PP_Var message,
209 const char** out_function,
210 struct PP_Var* out_params) {
211 if (message.type != PP_VARTYPE_DICTIONARY) {
212 return 1;
213 }
214
215 struct PP_Var cmd_value = GetDictVar(message, "cmd");
216 *out_function = VarToCStr(cmd_value);
217 g_ppb_var->Release(cmd_value);
218 if (cmd_value.type != PP_VARTYPE_STRING) {
219 return 1;
220 }
221
222 *out_params = GetDictVar(message, "args");
223 if (out_params->type != PP_VARTYPE_ARRAY) {
224 return 1;
225 }
226
227 return 0;
228 }
229
230 /**
231 * Given a function name, look up its handler function.
232 * @param[in] function_name The function name to look up.
233 * @return The handler function mapped to |function_name|.
234 */
235 static HandleFunc GetFunctionByName(const char* function_name) {
236 FuncNameMapping* map_iter = g_function_map;
237 for (; map_iter->name; ++map_iter) {
238 if (strcmp(map_iter->name, function_name) == 0) {
239 return map_iter->function;
240 }
241 }
242
243 return NULL;
244 }
245
246 /**
247 * Handle as message from JavaScript on the worker thread.
248 *
249 * @param[in] message The message to parse and handle.
250 */
251 static void HandleMessage(struct PP_Var message) {
252 const char* function_name;
253 struct PP_Var params;
254 if (ParseMessage(message, &function_name, &params)) {
255 PostMessage("Error: Unable to parse message");
256 return;
257 }
258
259 HandleFunc function = GetFunctionByName(function_name);
260 if (!function) {
261 /* Function name wasn't found. Error. */
262 PostMessage("Error: Unknown function \"%s\"", function_name);
263 return;
264 }
265
266 /* Function name was found, call it. */
267 struct PP_Var result_var;
268 const char* error;
269 int result = (*function)(params, &result_var, &error);
270 if (result != 0) {
271 /* Error. */
272 if (error != NULL) {
273 PostMessage("Error: \"%s\" failed: %s.", function_name, error);
274 free((void*)error);
275 } else {
276 PostMessage("Error: \"%s\" failed.", function_name);
277 }
278 return;
279 }
280
281 /* Function returned an output dictionary. Send it to JavaScript. */
282 g_ppb_messaging->PostMessage(g_instance, result_var);
283 g_ppb_var->Release(result_var);
284 }
285
286
287 /**
288 * Helper function used by EchoThread which reads from a file descriptor
289 * and writes all the data that it reads back to the same descriptor.
290 */
291 static void EchoInput(int fd) {
292 char buffer[512];
293 while (1) {
294 int rtn = read(fd, buffer, 512);
295 if (rtn > 0) {
296 int wrote = write(fd, buffer, rtn);
297 if (wrote < rtn)
298 PostMessage("only wrote %d/%d bytes\n", wrote, rtn);
299 } else {
300 if (rtn < 0 && errno != EAGAIN)
301 PostMessage("read failed: %d (%s)\n", errno, strerror(errno));
302 break;
303 }
304 }
305 }
306
307 /**
308 * Worker thread that listens for input on JS pipe nodes and echos all input
309 * back to the same pipe.
310 */
311 static void* EchoThread(void* user_data) {
312 int fd1 = open("/dev/jspipe1", O_RDWR | O_NONBLOCK);
313 int fd2 = open("/dev/jspipe2", O_RDWR | O_NONBLOCK);
314 int fd3 = open("/dev/jspipe3", O_RDWR | O_NONBLOCK);
315 int nfds = MAX(fd1, fd2);
316 nfds = MAX(nfds, fd3);
317 while (1) {
318 fd_set readfds;
319 FD_ZERO(&readfds);
320 FD_SET(fd1, &readfds);
321 FD_SET(fd2, &readfds);
322 FD_SET(fd3, &readfds);
323 int rtn = select(nfds + 1, &readfds, NULL, NULL, NULL);
324 if (rtn < 0 && errno != EAGAIN) {
325 PostMessage("select failed: %s\n", strerror(errno));
326 break;
327 }
328 if (rtn > 0) {
329 if (FD_ISSET(fd1, &readfds))
330 EchoInput(fd1);
331 if (FD_ISSET(fd2, &readfds))
332 EchoInput(fd2);
333 if (FD_ISSET(fd3, &readfds))
334 EchoInput(fd3);
335 }
336
337 }
338 close(fd1);
339 close(fd2);
340 close(fd3);
341 return 0;
342 }
343
344 /**
345 * A worker thread that handles messages from JavaScript.
346 * @param[in] user_data Unused.
347 * @return unused.
348 */
349 void* HandleMessageThread(void* user_data) {
350 while (1) {
351 struct PP_Var message = DequeueMessage();
352 HandleMessage(message);
353 g_ppb_var->Release(message);
354 }
355 }
356
357 static PP_Bool Instance_DidCreate(PP_Instance instance,
358 uint32_t argc,
359 const char* argn[],
360 const char* argv[]) {
361 g_instance = instance;
362 nacl_io_init_ppapi(instance, g_get_browser_interface);
363
364 // By default, nacl_io mounts / to pass through to the original NaCl
365 // filesystem (which doesn't do much). Let's remount it to a memfs
366 // filesystem.
367 umount("/");
368 mount("", "/", "memfs", 0, "");
369
370 mount("", /* source */
371 "/persistent", /* target */
372 "html5fs", /* filesystemtype */
373 0, /* mountflags */
374 "type=PERSISTENT,expected_size=1048576"); /* data */
375
376 mount("", /* source. Use relative URL */
377 "/http", /* target */
378 "httpfs", /* filesystemtype */
379 0, /* mountflags */
380 ""); /* data */
381
382 pthread_create(&g_handle_message_thread, NULL, &HandleMessageThread, NULL);
383 pthread_create(&g_echo_thread, NULL, &EchoThread, NULL);
384 InitializeMessageQueue();
385
386 return PP_TRUE;
387 }
388
389 static void Instance_DidDestroy(PP_Instance instance) {
390 }
391
392 static void Instance_DidChangeView(PP_Instance instance,
393 PP_Resource view_resource) {
394 }
395
396 static void Instance_DidChangeFocus(PP_Instance instance, PP_Bool has_focus) {
397 }
398
399 static PP_Bool Instance_HandleDocumentLoad(PP_Instance instance,
400 PP_Resource url_loader) {
401 /* NaCl modules do not need to handle the document load function. */
402 return PP_FALSE;
403 }
404
405 static void Messaging_HandleMessage(PP_Instance instance,
406 struct PP_Var message) {
407 /* Special case for jspipe input handling */
408 if (message.type != PP_VARTYPE_DICTIONARY) {
409 PostMessage("Got unexpected message type: %d\n", message.type);
410 return;
411 }
412
413 struct PP_Var pipe_var = CStrToVar("pipe");
414 struct PP_Var pipe_name = g_ppb_var_dictionary->Get(message, pipe_var);
415 g_ppb_var->Release(pipe_var);
416
417 /* Special case for jspipe input handling */
418 if (pipe_name.type == PP_VARTYPE_STRING) {
419 char file_name[PATH_MAX];
420 snprintf(file_name, PATH_MAX, "/dev/%s", VarToCStr(pipe_name));
421 int fd = open(file_name, O_RDONLY);
422 g_ppb_var->Release(pipe_name);
423 if (fd < 0) {
424 PostMessage("Warning: opening %s failed.", file_name);
425 goto done;
426 }
427 if (ioctl(fd, NACL_IOC_HANDLEMESSAGE, &message) != 0) {
428 PostMessage("Error: ioctl on %s failed: %s", file_name, strerror(errno));
429 }
430 close(fd);
431 goto done;
432 }
433
434 g_ppb_var->AddRef(message);
435 if (!EnqueueMessage(message)) {
436 g_ppb_var->Release(message);
437 PostMessage("Warning: dropped message because the queue was full.");
438 }
439
440 done:
441 g_ppb_var->Release(pipe_name);
442 }
443
444 #define GET_INTERFACE(var, type, name) \
445 var = (type*)(get_browser(name)); \
446 if (!var) { \
447 printf("Unable to get interface " name "\n"); \
448 return PP_ERROR_FAILED; \
449 }
450
451 PP_EXPORT int32_t PPP_InitializeModule(PP_Module a_module_id,
452 PPB_GetInterface get_browser) {
453 g_get_browser_interface = get_browser;
454 GET_INTERFACE(g_ppb_messaging, PPB_Messaging, PPB_MESSAGING_INTERFACE);
455 GET_INTERFACE(g_ppb_var, PPB_Var, PPB_VAR_INTERFACE);
456 GET_INTERFACE(g_ppb_var_array, PPB_VarArray, PPB_VAR_ARRAY_INTERFACE);
457 GET_INTERFACE(
458 g_ppb_var_dictionary, PPB_VarDictionary, PPB_VAR_DICTIONARY_INTERFACE);
459 return PP_OK;
460 }
461
462 PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
463 if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0) {
464 static PPP_Instance instance_interface = {
465 &Instance_DidCreate,
466 &Instance_DidDestroy,
467 &Instance_DidChangeView,
468 &Instance_DidChangeFocus,
469 &Instance_HandleDocumentLoad,
470 };
471 return &instance_interface;
472 } else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0) {
473 static PPP_Messaging messaging_interface = {
474 &Messaging_HandleMessage,
475 };
476 return &messaging_interface;
477 }
478 return NULL;
479 }
480
481 PP_EXPORT void PPP_ShutdownModule() {
482 }
OLDNEW
« no previous file with comments | « native_client_sdk/src/examples/demo/nacl_io/nacl_io_demo.h ('k') | native_client_sdk/src/examples/demo/nacl_io/queue.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698