OLD | NEW |
| (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 #include "handlers.h" | |
6 | |
7 #include <arpa/inet.h> | |
8 #include <assert.h> | |
9 #include <errno.h> | |
10 #include <limits.h> | |
11 #include <netdb.h> | |
12 #include <netinet/in.h> | |
13 #include <stdio.h> | |
14 #include <stdlib.h> | |
15 #include <string.h> | |
16 #include <unistd.h> | |
17 | |
18 #include <sys/types.h> | |
19 #include <sys/socket.h> | |
20 #include <sys/stat.h> | |
21 | |
22 #include "nacl_io/osdirent.h" | |
23 | |
24 #include "nacl_io_demo.h" | |
25 | |
26 #define MAX_OPEN_FILES 10 | |
27 #define MAX_OPEN_DIRS 10 | |
28 #define MAX_PARAMS 4 | |
29 | |
30 #if defined(WIN32) | |
31 #define stat _stat | |
32 #endif | |
33 | |
34 /** | |
35 * A mapping from int -> FILE*, so the JavaScript messages can refer to an open | |
36 * File. | |
37 */ | |
38 static FILE* g_OpenFiles[MAX_OPEN_FILES]; | |
39 | |
40 /** | |
41 * A mapping from int -> DIR*, so the JavaScript messages can refer to an open | |
42 * Directory. | |
43 */ | |
44 static void* g_OpenDirs[MAX_OPEN_DIRS]; | |
45 | |
46 /** | |
47 * A collection of the most recently allocated parameter strings. This makes | |
48 * the Handle* functions below easier to write because they don't have to | |
49 * manually deallocate the strings they're using. | |
50 */ | |
51 static char* g_ParamStrings[MAX_PARAMS]; | |
52 | |
53 /** | |
54 * Add |object| to |map| and return the index it was added at. | |
55 * @param[in] map The map to add the object to. | |
56 * @param[in] max_map_size The maximum map size. | |
57 * @param[in] object The object to add to the map. | |
58 * @return int The index of the added object, or -1 if there is no more space. | |
59 */ | |
60 static int AddToMap(void** map, int max_map_size, void* object) { | |
61 int i; | |
62 assert(object != NULL); | |
63 for (i = 0; i < max_map_size; ++i) { | |
64 if (map[i] == NULL) { | |
65 map[i] = object; | |
66 return i; | |
67 } | |
68 } | |
69 | |
70 return -1; | |
71 } | |
72 | |
73 /** | |
74 * Remove an object at index |i| from |map|. | |
75 * @param[in] map The map to remove from. | |
76 * @param[in] max_map_size The size of the map. | |
77 * @param[in] i The index to remove. | |
78 */ | |
79 static void RemoveFromMap(void** map, int max_map_size, int i) { | |
80 assert(i >= 0 && i < max_map_size); | |
81 map[i] = NULL; | |
82 } | |
83 | |
84 /** | |
85 * Add the file to the g_OpenFiles map. | |
86 * @param[in] file The file to add to g_OpenFiles. | |
87 * @return int The index of the FILE in g_OpenFiles, or -1 if there are too many | |
88 * open files. | |
89 */ | |
90 static int AddFileToMap(FILE* file) { | |
91 return AddToMap((void**)g_OpenFiles, MAX_OPEN_FILES, file); | |
92 } | |
93 | |
94 /** | |
95 * Remove the file from the g_OpenFiles map. | |
96 * @param[in] i The index of the file handle to remove. | |
97 */ | |
98 static void RemoveFileFromMap(int i) { | |
99 RemoveFromMap((void**)g_OpenFiles, MAX_OPEN_FILES, i); | |
100 } | |
101 | |
102 /* Win32 doesn't support DIR/opendir/readdir/closedir. */ | |
103 #if !defined(WIN32) | |
104 /** | |
105 * Add the dir to the g_OpenDirs map. | |
106 * @param[in] dir The dir to add to g_OpenDirs. | |
107 * @return int The index of the DIR in g_OpenDirs, or -1 if there are too many | |
108 * open dirs. | |
109 */ | |
110 static int AddDirToMap(DIR* dir) { | |
111 return AddToMap((void**)g_OpenDirs, MAX_OPEN_DIRS, dir); | |
112 } | |
113 | |
114 /** | |
115 * Remove the dir from the g_OpenDirs map. | |
116 * @param[in] i The index of the dir handle to remove. | |
117 */ | |
118 static void RemoveDirFromMap(int i) { | |
119 RemoveFromMap((void**)g_OpenDirs, MAX_OPEN_DIRS, i); | |
120 } | |
121 #endif | |
122 | |
123 /** | |
124 * Get the number of parameters. | |
125 * @param[in] params The parameter array. | |
126 * @return uint32_t The number of parameters in the array. | |
127 */ | |
128 static uint32_t GetNumParams(struct PP_Var params) { | |
129 return g_ppb_var_array->GetLength(params); | |
130 } | |
131 | |
132 /** | |
133 * Get a parameter at |index| as a string. | |
134 * @param[in] params The parameter array. | |
135 * @param[in] index The index in |params| to get. | |
136 * @param[out] out_string The output string. | |
137 * @param[out] out_string_len The length of the output string. | |
138 * @param[out] out_error An error message, if this operation failed. | |
139 * @return int 0 if successful, otherwise 1. | |
140 */ | |
141 static int GetParamString(struct PP_Var params, | |
142 uint32_t index, | |
143 char** out_string, | |
144 uint32_t* out_string_len, | |
145 const char** out_error) { | |
146 if (index >= MAX_PARAMS) { | |
147 *out_error = PrintfToNewString("Param index %u >= MAX_PARAMS (%d)", | |
148 index, MAX_PARAMS); | |
149 return 1; | |
150 } | |
151 | |
152 struct PP_Var value = g_ppb_var_array->Get(params, index); | |
153 if (value.type != PP_VARTYPE_STRING) { | |
154 *out_error = | |
155 PrintfToNewString("Expected param at index %d to be a string", index); | |
156 return 1; | |
157 } | |
158 | |
159 uint32_t length; | |
160 const char* var_str = g_ppb_var->VarToUtf8(value, &length); | |
161 | |
162 char* string = (char*)malloc(length + 1); | |
163 memcpy(string, var_str, length); | |
164 string[length] = 0; | |
165 | |
166 /* Put the allocated string in g_ParamStrings. This keeps us from leaking | |
167 * each parameter string, without having to do manual cleanup in every | |
168 * Handle* function below. | |
169 */ | |
170 free(g_ParamStrings[index]); | |
171 g_ParamStrings[index] = string; | |
172 | |
173 | |
174 *out_string = string; | |
175 *out_string_len = length; | |
176 return 0; | |
177 } | |
178 | |
179 /** | |
180 * Get a parameter at |index| as a FILE*. | |
181 * @param[in] params The parameter array. | |
182 * @param[in] index The index in |params| to get. | |
183 * @param[out] out_file The output FILE*. | |
184 * @param[out] out_file_index The index of the output FILE* in g_OpenFiles. | |
185 * @param[out] out_error An error message, if this operation failed. | |
186 * @return int 0 if successful, otherwise 1. | |
187 */ | |
188 static int GetParamFile(struct PP_Var params, | |
189 uint32_t index, | |
190 FILE** out_file, | |
191 int32_t* out_file_index, | |
192 const char** out_error) { | |
193 struct PP_Var value = g_ppb_var_array->Get(params, index); | |
194 if (value.type != PP_VARTYPE_INT32) { | |
195 *out_error = | |
196 PrintfToNewString("Expected param at index %d to be an int32", index); | |
197 return 1; | |
198 } | |
199 | |
200 int32_t file_index = value.value.as_int; | |
201 if (file_index < 0 || file_index >= MAX_OPEN_FILES) { | |
202 *out_error = PrintfToNewString("File index %d is out range", file_index); | |
203 return 1; | |
204 } | |
205 | |
206 if (g_OpenFiles[file_index] == NULL) { | |
207 *out_error = PrintfToNewString("File index %d is not open", file_index); | |
208 return 1; | |
209 } | |
210 | |
211 *out_file = g_OpenFiles[file_index]; | |
212 *out_file_index = file_index; | |
213 return 0; | |
214 } | |
215 | |
216 /** | |
217 * Get a parameter at |index| as a DIR*. | |
218 * @param[in] params The parameter array. | |
219 * @param[in] index The index in |params| to get. | |
220 * @param[out] out_file The output DIR*. | |
221 * @param[out] out_file_index The index of the output DIR* in g_OpenDirs. | |
222 * @param[out] out_error An error message, if this operation failed. | |
223 * @return int 0 if successful, otherwise 1. | |
224 */ | |
225 static int GetParamDir(struct PP_Var params, | |
226 uint32_t index, | |
227 DIR** out_dir, | |
228 int32_t* out_dir_index, | |
229 const char** out_error) { | |
230 struct PP_Var value = g_ppb_var_array->Get(params, index); | |
231 if (value.type != PP_VARTYPE_INT32) { | |
232 *out_error = | |
233 PrintfToNewString("Expected param at index %d to be an int32", index); | |
234 return 1; | |
235 } | |
236 | |
237 int32_t dir_index = value.value.as_int; | |
238 if (dir_index < 0 || dir_index >= MAX_OPEN_DIRS) { | |
239 *out_error = PrintfToNewString("Dir at index %d is out range", dir_index); | |
240 return 1; | |
241 } | |
242 | |
243 if (g_OpenDirs[dir_index] == NULL) { | |
244 *out_error = PrintfToNewString("Dir index %d is not open", dir_index); | |
245 return 1; | |
246 } | |
247 | |
248 *out_dir = g_OpenDirs[dir_index]; | |
249 *out_dir_index = dir_index; | |
250 return 0; | |
251 } | |
252 | |
253 /** | |
254 * Get a parameter at |index| as an int. | |
255 * @param[in] params The parameter array. | |
256 * @param[in] index The index in |params| to get. | |
257 * @param[out] out_file The output int32_t. | |
258 * @param[out] out_error An error message, if this operation failed. | |
259 * @return int 0 if successful, otherwise 1. | |
260 */ | |
261 static int GetParamInt(struct PP_Var params, | |
262 uint32_t index, | |
263 int32_t* out_int, | |
264 const char** out_error) { | |
265 struct PP_Var value = g_ppb_var_array->Get(params, index); | |
266 if (value.type != PP_VARTYPE_INT32) { | |
267 *out_error = | |
268 PrintfToNewString("Expected param at index %d to be an int32", index); | |
269 return 1; | |
270 } | |
271 | |
272 *out_int = value.value.as_int; | |
273 return 0; | |
274 } | |
275 | |
276 /** | |
277 * Create a response PP_Var to send back to JavaScript. | |
278 * @param[out] response_var The response PP_Var. | |
279 * @param[in] cmd The name of the function that is being executed. | |
280 * @param[out] out_error An error message, if this call failed. | |
281 */ | |
282 static void CreateResponse(struct PP_Var* response_var, | |
283 const char* cmd, | |
284 const char** out_error) { | |
285 PP_Bool result; | |
286 | |
287 struct PP_Var dict_var = g_ppb_var_dictionary->Create(); | |
288 struct PP_Var cmd_key = CStrToVar("cmd"); | |
289 struct PP_Var cmd_value = CStrToVar(cmd); | |
290 | |
291 result = g_ppb_var_dictionary->Set(dict_var, cmd_key, cmd_value); | |
292 g_ppb_var->Release(cmd_key); | |
293 g_ppb_var->Release(cmd_value); | |
294 | |
295 if (!result) { | |
296 g_ppb_var->Release(dict_var); | |
297 *out_error = | |
298 PrintfToNewString("Unable to set \"cmd\" key in result dictionary"); | |
299 return; | |
300 } | |
301 | |
302 struct PP_Var args_key = CStrToVar("args"); | |
303 struct PP_Var args_value = g_ppb_var_array->Create(); | |
304 result = g_ppb_var_dictionary->Set(dict_var, args_key, args_value); | |
305 g_ppb_var->Release(args_key); | |
306 g_ppb_var->Release(args_value); | |
307 | |
308 if (!result) { | |
309 g_ppb_var->Release(dict_var); | |
310 *out_error = | |
311 PrintfToNewString("Unable to set \"args\" key in result dictionary"); | |
312 return; | |
313 } | |
314 | |
315 *response_var = dict_var; | |
316 } | |
317 | |
318 /** | |
319 * Append a PP_Var to the response dictionary. | |
320 * @param[in,out] response_var The response PP_var. | |
321 * @param[in] value The value to add to the response args. | |
322 * @param[out] out_error An error message, if this call failed. | |
323 */ | |
324 static void AppendResponseVar(struct PP_Var* response_var, | |
325 struct PP_Var value, | |
326 const char** out_error) { | |
327 struct PP_Var args_value = GetDictVar(*response_var, "args"); | |
328 uint32_t args_length = g_ppb_var_array->GetLength(args_value); | |
329 PP_Bool result = g_ppb_var_array->Set(args_value, args_length, value); | |
330 if (!result) { | |
331 // Release the dictionary that was there before. | |
332 g_ppb_var->Release(*response_var); | |
333 | |
334 // Return an error message instead. | |
335 *response_var = PP_MakeUndefined(); | |
336 *out_error = PrintfToNewString("Unable to append value to result"); | |
337 return; | |
338 } | |
339 } | |
340 | |
341 /** | |
342 * Append an int to the response dictionary. | |
343 * @param[in,out] response_var The response PP_var. | |
344 * @param[in] value The value to add to the response args. | |
345 * @param[out] out_error An error message, if this call failed. | |
346 */ | |
347 static void AppendResponseInt(struct PP_Var* response_var, | |
348 int32_t value, | |
349 const char** out_error) { | |
350 AppendResponseVar(response_var, PP_MakeInt32(value), out_error); | |
351 } | |
352 | |
353 /** | |
354 * Append a string to the response dictionary. | |
355 * @param[in,out] response_var The response PP_var. | |
356 * @param[in] value The value to add to the response args. | |
357 * @param[out] out_error An error message, if this call failed. | |
358 */ | |
359 static void AppendResponseString(struct PP_Var* response_var, | |
360 const char* value, | |
361 const char** out_error) { | |
362 struct PP_Var value_var = CStrToVar(value); | |
363 AppendResponseVar(response_var, value_var, out_error); | |
364 g_ppb_var->Release(value_var); | |
365 } | |
366 | |
367 #define CHECK_PARAM_COUNT(name, expected) \ | |
368 if (GetNumParams(params) != expected) { \ | |
369 *out_error = PrintfToNewString(#name " takes " #expected " parameters." \ | |
370 " Got %d", GetNumParams(params)); \ | |
371 return 1; \ | |
372 } | |
373 | |
374 #define PARAM_STRING(index, var) \ | |
375 char* var; \ | |
376 uint32_t var##_len; \ | |
377 if (GetParamString(params, index, &var, &var##_len, out_error)) { \ | |
378 return 1; \ | |
379 } | |
380 | |
381 #define PARAM_FILE(index, var) \ | |
382 FILE* var; \ | |
383 int32_t var##_index; \ | |
384 if (GetParamFile(params, index, &var, &var##_index, out_error)) { \ | |
385 return 1; \ | |
386 } | |
387 | |
388 #define PARAM_DIR(index, var) \ | |
389 DIR* var; \ | |
390 int32_t var##_index; \ | |
391 if (GetParamDir(params, index, &var, &var##_index, out_error)) { \ | |
392 return 1; \ | |
393 } | |
394 | |
395 #define PARAM_INT(index, var) \ | |
396 int32_t var; \ | |
397 if (GetParamInt(params, index, &var, out_error)) { \ | |
398 return 1; \ | |
399 } | |
400 | |
401 #define CREATE_RESPONSE(name) CreateResponse(output, #name, out_error) | |
402 #define RESPONSE_STRING(var) AppendResponseString(output, var, out_error) | |
403 #define RESPONSE_INT(var) AppendResponseInt(output, var, out_error) | |
404 | |
405 /** | |
406 * Handle a call to fopen() made by JavaScript. | |
407 * | |
408 * fopen expects 2 parameters: | |
409 * 0: the path of the file to open | |
410 * 1: the mode string | |
411 * on success, fopen returns a result in |output|: | |
412 * 0: "fopen" | |
413 * 1: the filename opened | |
414 * 2: the file index | |
415 * on failure, fopen returns an error string in |out_error|. | |
416 */ | |
417 int HandleFopen(struct PP_Var params, | |
418 struct PP_Var* output, | |
419 const char** out_error) { | |
420 CHECK_PARAM_COUNT(fopen, 2); | |
421 PARAM_STRING(0, filename); | |
422 PARAM_STRING(1, mode); | |
423 | |
424 FILE* file = fopen(filename, mode); | |
425 | |
426 if (!file) { | |
427 *out_error = PrintfToNewString("fopen returned a NULL FILE*"); | |
428 return 1; | |
429 } | |
430 | |
431 int file_index = AddFileToMap(file); | |
432 if (file_index == -1) { | |
433 *out_error = PrintfToNewString("Example only allows %d open file handles", | |
434 MAX_OPEN_FILES); | |
435 return 1; | |
436 } | |
437 | |
438 CREATE_RESPONSE(fopen); | |
439 RESPONSE_STRING(filename); | |
440 RESPONSE_INT(file_index); | |
441 return 0; | |
442 } | |
443 | |
444 /** | |
445 * Handle a call to fwrite() made by JavaScript. | |
446 * | |
447 * fwrite expects 2 parameters: | |
448 * 0: The index of the file (which is mapped to a FILE*) | |
449 * 1: A string to write to the file | |
450 * on success, fwrite returns a result in |output|: | |
451 * 0: "fwrite" | |
452 * 1: the file index | |
453 * 2: the number of bytes written | |
454 * on failure, fwrite returns an error string in |out_error|. | |
455 */ | |
456 int HandleFwrite(struct PP_Var params, | |
457 struct PP_Var* output, | |
458 const char** out_error) { | |
459 CHECK_PARAM_COUNT(fwrite, 2); | |
460 PARAM_FILE(0, file); | |
461 PARAM_STRING(1, data); | |
462 | |
463 size_t bytes_written = fwrite(data, 1, data_len, file); | |
464 if (ferror(file)) { | |
465 *out_error = PrintfToNewString("Wrote %d bytes, but ferror() returns true", | |
466 bytes_written); | |
467 return 1; | |
468 } | |
469 | |
470 CREATE_RESPONSE(fwrite); | |
471 RESPONSE_INT(file_index); | |
472 RESPONSE_INT(bytes_written); | |
473 return 0; | |
474 } | |
475 | |
476 /** | |
477 * Handle a call to fread() made by JavaScript. | |
478 * | |
479 * fread expects 2 parameters: | |
480 * 0: The index of the file (which is mapped to a FILE*) | |
481 * 1: The number of bytes to read from the file. | |
482 * on success, fread returns a result in |output|: | |
483 * 0: "fread" | |
484 * 1: the file index | |
485 * 2: the data read from the file | |
486 * on failure, fread returns an error string in |out_error|. | |
487 */ | |
488 int HandleFread(struct PP_Var params, | |
489 struct PP_Var* output, | |
490 const char** out_error) { | |
491 CHECK_PARAM_COUNT(fread, 2); | |
492 PARAM_FILE(0, file); | |
493 PARAM_INT(1, data_len); | |
494 | |
495 char* buffer = (char*)malloc(data_len + 1); | |
496 size_t bytes_read = fread(buffer, 1, data_len, file); | |
497 buffer[bytes_read] = 0; | |
498 | |
499 if (ferror(file)) { | |
500 *out_error = PrintfToNewString("Read %d bytes, but ferror() returns true", | |
501 bytes_read); | |
502 free(buffer); | |
503 return 1; | |
504 } | |
505 | |
506 CREATE_RESPONSE(fread); | |
507 RESPONSE_INT(file_index); | |
508 RESPONSE_STRING(buffer); | |
509 free(buffer); | |
510 return 0; | |
511 } | |
512 | |
513 /** | |
514 * Handle a call to fseek() made by JavaScript. | |
515 * | |
516 * fseek expects 3 parameters: | |
517 * 0: The index of the file (which is mapped to a FILE*) | |
518 * 1: The offset to seek to | |
519 * 2: An integer representing the whence parameter of standard fseek. | |
520 * whence = 0: seek from the beginning of the file | |
521 * whence = 1: seek from the current file position | |
522 * whence = 2: seek from the end of the file | |
523 * on success, fseek returns a result in |output|: | |
524 * 0: "fseek" | |
525 * 1: the file index | |
526 * 2: The new file position | |
527 * on failure, fseek returns an error string in |out_error|. | |
528 */ | |
529 int HandleFseek(struct PP_Var params, | |
530 struct PP_Var* output, | |
531 const char** out_error) { | |
532 CHECK_PARAM_COUNT(fseek, 3); | |
533 PARAM_FILE(0, file); | |
534 PARAM_INT(1, offset); | |
535 PARAM_INT(2, whence); | |
536 | |
537 int result = fseek(file, offset, whence); | |
538 if (result) { | |
539 *out_error = PrintfToNewString("fseek returned error %d", result); | |
540 return 1; | |
541 } | |
542 | |
543 offset = ftell(file); | |
544 if (offset < 0) { | |
545 *out_error = PrintfToNewString( | |
546 "fseek succeeded, but ftell returned error %d", offset); | |
547 return 1; | |
548 } | |
549 | |
550 CREATE_RESPONSE(fseek); | |
551 RESPONSE_INT(file_index); | |
552 RESPONSE_INT(offset); | |
553 return 0; | |
554 } | |
555 | |
556 /** | |
557 * Handle a call to fflush() made by JavaScript. | |
558 * | |
559 * fflush expects 1 parameters: | |
560 * 0: The index of the file (which is mapped to a FILE*) | |
561 * on success, fflush returns a result in |output|: | |
562 * 0: "fflush" | |
563 * 1: the file index | |
564 * on failure, fflush returns an error string in |out_error|. | |
565 */ | |
566 int HandleFflush(struct PP_Var params, | |
567 struct PP_Var* output, | |
568 const char** out_error) { | |
569 CHECK_PARAM_COUNT(fflush, 1); | |
570 PARAM_FILE(0, file); | |
571 | |
572 fflush(file); | |
573 | |
574 CREATE_RESPONSE(fflush); | |
575 RESPONSE_INT(file_index); | |
576 return 0; | |
577 } | |
578 | |
579 /** | |
580 * Handle a call to fclose() made by JavaScript. | |
581 * | |
582 * fclose expects 1 parameter: | |
583 * 0: The index of the file (which is mapped to a FILE*) | |
584 * on success, fclose returns a result in |output|: | |
585 * 0: "fclose" | |
586 * 1: the file index | |
587 * on failure, fclose returns an error string in |out_error|. | |
588 */ | |
589 int HandleFclose(struct PP_Var params, | |
590 struct PP_Var* output, | |
591 const char** out_error) { | |
592 CHECK_PARAM_COUNT(fclose, 1); | |
593 PARAM_FILE(0, file); | |
594 | |
595 int result = fclose(file); | |
596 if (result) { | |
597 *out_error = PrintfToNewString("fclose returned error %d", result); | |
598 return 1; | |
599 } | |
600 | |
601 RemoveFileFromMap(file_index); | |
602 | |
603 CREATE_RESPONSE(fclose); | |
604 RESPONSE_INT(file_index); | |
605 return 0; | |
606 } | |
607 | |
608 /** | |
609 * Handle a call to stat() made by JavaScript. | |
610 * | |
611 * stat expects 1 parameter: | |
612 * 0: The name of the file | |
613 * on success, stat returns a result in |output|: | |
614 * 0: "stat" | |
615 * 1: the file name | |
616 * 2: the size of the file | |
617 * on failure, stat returns an error string in |out_error|. | |
618 */ | |
619 int HandleStat(struct PP_Var params, | |
620 struct PP_Var* output, | |
621 const char** out_error) { | |
622 CHECK_PARAM_COUNT(stat, 1); | |
623 PARAM_STRING(0, filename); | |
624 | |
625 struct stat buf; | |
626 memset(&buf, 0, sizeof(buf)); | |
627 int result = stat(filename, &buf); | |
628 | |
629 if (result == -1) { | |
630 *out_error = PrintfToNewString("stat returned error %d", errno); | |
631 return 1; | |
632 } | |
633 | |
634 CREATE_RESPONSE(stat); | |
635 RESPONSE_STRING(filename); | |
636 RESPONSE_INT(buf.st_size); | |
637 return 0; | |
638 } | |
639 | |
640 /** | |
641 * Handle a call to opendir() made by JavaScript. | |
642 * | |
643 * opendir expects 1 parameter: | |
644 * 0: The name of the directory | |
645 * on success, opendir returns a result in |output|: | |
646 * 0: "opendir" | |
647 * 1: the directory name | |
648 * 2: the index of the directory | |
649 * on failure, opendir returns an error string in |out_error|. | |
650 */ | |
651 int HandleOpendir(struct PP_Var params, | |
652 struct PP_Var* output, | |
653 const char** out_error) { | |
654 #if defined(WIN32) | |
655 *out_error = PrintfToNewString("Win32 does not support opendir"); | |
656 return 1; | |
657 #else | |
658 CHECK_PARAM_COUNT(opendir, 1); | |
659 PARAM_STRING(0, dirname); | |
660 | |
661 DIR* dir = opendir(dirname); | |
662 | |
663 if (!dir) { | |
664 *out_error = PrintfToNewString("opendir returned a NULL DIR*"); | |
665 return 1; | |
666 } | |
667 | |
668 int dir_index = AddDirToMap(dir); | |
669 if (dir_index == -1) { | |
670 *out_error = PrintfToNewString("Example only allows %d open dir handles", | |
671 MAX_OPEN_DIRS); | |
672 return 1; | |
673 } | |
674 | |
675 CREATE_RESPONSE(opendir); | |
676 RESPONSE_STRING(dirname); | |
677 RESPONSE_INT(dir_index); | |
678 return 0; | |
679 #endif | |
680 } | |
681 | |
682 /** | |
683 * Handle a call to readdir() made by JavaScript. | |
684 * | |
685 * readdir expects 1 parameter: | |
686 * 0: The index of the directory (which is mapped to a DIR*) | |
687 * on success, opendir returns a result in |output|: | |
688 * 0: "readdir" | |
689 * 1: the inode number of the entry | |
690 * 2: the name of the entry | |
691 * if there are no more entries, |output| contains: | |
692 * 0: "readdir" | |
693 * on failure, readdir returns an error string in |out_error|. | |
694 */ | |
695 int HandleReaddir(struct PP_Var params, | |
696 struct PP_Var* output, | |
697 const char** out_error) { | |
698 #if defined(WIN32) | |
699 *out_error = PrintfToNewString("Win32 does not support readdir"); | |
700 return 1; | |
701 #else | |
702 CHECK_PARAM_COUNT(readdir, 1); | |
703 PARAM_DIR(0, dir); | |
704 | |
705 struct dirent* entry = readdir(dir); | |
706 | |
707 CREATE_RESPONSE(readdir); | |
708 RESPONSE_INT(dir_index); | |
709 if (entry != NULL) { | |
710 RESPONSE_INT(entry->d_ino); | |
711 RESPONSE_STRING(entry->d_name); | |
712 } | |
713 return 0; | |
714 #endif | |
715 } | |
716 | |
717 /** | |
718 * Handle a call to closedir() made by JavaScript. | |
719 * | |
720 * closedir expects 1 parameter: | |
721 * 0: The index of the directory (which is mapped to a DIR*) | |
722 * on success, closedir returns a result in |output|: | |
723 * 0: "closedir" | |
724 * 1: the name of the directory | |
725 * on failure, closedir returns an error string in |out_error|. | |
726 */ | |
727 int HandleClosedir(struct PP_Var params, | |
728 struct PP_Var* output, | |
729 const char** out_error) { | |
730 #if defined(WIN32) | |
731 *out_error = PrintfToNewString("Win32 does not support closedir"); | |
732 return 1; | |
733 #else | |
734 CHECK_PARAM_COUNT(closedir, 1); | |
735 PARAM_DIR(0, dir); | |
736 | |
737 int result = closedir(dir); | |
738 if (result) { | |
739 *out_error = PrintfToNewString("closedir returned error %d", result); | |
740 return 1; | |
741 } | |
742 | |
743 RemoveDirFromMap(dir_index); | |
744 | |
745 CREATE_RESPONSE(closedir); | |
746 RESPONSE_INT(dir_index); | |
747 return 0; | |
748 #endif | |
749 } | |
750 | |
751 /** | |
752 * Handle a call to mkdir() made by JavaScript. | |
753 * | |
754 * mkdir expects 1 parameter: | |
755 * 0: The name of the directory | |
756 * 1: The mode to use for the new directory, in octal. | |
757 * on success, mkdir returns a result in |output|: | |
758 * 0: "mkdir" | |
759 * 1: the name of the directory | |
760 * on failure, mkdir returns an error string in |out_error|. | |
761 */ | |
762 int HandleMkdir(struct PP_Var params, | |
763 struct PP_Var* output, | |
764 const char** out_error) { | |
765 CHECK_PARAM_COUNT(mkdir, 2); | |
766 PARAM_STRING(0, dirname); | |
767 PARAM_INT(1, mode); | |
768 | |
769 int result = mkdir(dirname, mode); | |
770 | |
771 if (result != 0) { | |
772 *out_error = PrintfToNewString("mkdir returned error: %d", errno); | |
773 return 1; | |
774 } | |
775 | |
776 CREATE_RESPONSE(mkdir); | |
777 RESPONSE_STRING(dirname); | |
778 return 0; | |
779 } | |
780 | |
781 /** | |
782 * Handle a call to rmdir() made by JavaScript. | |
783 * | |
784 * rmdir expects 1 parameter: | |
785 * 0: The name of the directory to remove | |
786 * on success, rmdir returns a result in |output|: | |
787 * 0: "rmdir" | |
788 * 1: the name of the directory | |
789 * on failure, rmdir returns an error string in |out_error|. | |
790 */ | |
791 int HandleRmdir(struct PP_Var params, | |
792 struct PP_Var* output, | |
793 const char** out_error) { | |
794 CHECK_PARAM_COUNT(rmdir, 1); | |
795 PARAM_STRING(0, dirname); | |
796 | |
797 int result = rmdir(dirname); | |
798 | |
799 if (result != 0) { | |
800 *out_error = PrintfToNewString("rmdir returned error: %d", errno); | |
801 return 1; | |
802 } | |
803 | |
804 CREATE_RESPONSE(rmdir); | |
805 RESPONSE_STRING(dirname); | |
806 return 0; | |
807 } | |
808 | |
809 /** | |
810 * Handle a call to chdir() made by JavaScript. | |
811 * | |
812 * chdir expects 1 parameter: | |
813 * 0: The name of the directory | |
814 * on success, chdir returns a result in |output|: | |
815 * 0: "chdir" | |
816 * 1: the name of the directory | |
817 * on failure, chdir returns an error string in |out_error|. | |
818 */ | |
819 int HandleChdir(struct PP_Var params, | |
820 struct PP_Var* output, | |
821 const char** out_error) { | |
822 CHECK_PARAM_COUNT(chdir, 1); | |
823 PARAM_STRING(0, dirname); | |
824 | |
825 int result = chdir(dirname); | |
826 | |
827 if (result != 0) { | |
828 *out_error = PrintfToNewString("chdir returned error: %d", errno); | |
829 return 1; | |
830 } | |
831 | |
832 CREATE_RESPONSE(chdir); | |
833 RESPONSE_STRING(dirname); | |
834 return 0; | |
835 } | |
836 | |
837 /** | |
838 * Handle a call to getcwd() made by JavaScript. | |
839 * | |
840 * getcwd expects 0 parameters. | |
841 * on success, getcwd returns a result in |output|: | |
842 * 0: "getcwd" | |
843 * 1: the current working directory | |
844 * on failure, getcwd returns an error string in |out_error|. | |
845 */ | |
846 int HandleGetcwd(struct PP_Var params, | |
847 struct PP_Var* output, | |
848 const char** out_error) { | |
849 CHECK_PARAM_COUNT(getcwd, 0); | |
850 | |
851 char cwd[PATH_MAX]; | |
852 char* result = getcwd(cwd, PATH_MAX); | |
853 if (result == NULL) { | |
854 *out_error = PrintfToNewString("getcwd returned error: %d", errno); | |
855 return 1; | |
856 } | |
857 | |
858 CREATE_RESPONSE(getcwd); | |
859 RESPONSE_STRING(cwd); | |
860 return 0; | |
861 } | |
862 | |
863 /** | |
864 * Handle a call to getaddrinfo() made by JavaScript. | |
865 * | |
866 * getaddrinfo expects 1 parameter: | |
867 * 0: The name of the host to look up. | |
868 * on success, getaddrinfo returns a result in |output|: | |
869 * 0: "getaddrinfo" | |
870 * 1: The canonical name | |
871 * 2*n+2: Host name | |
872 * 2*n+3: Address type (either "AF_INET" or "AF_INET6") | |
873 * on failure, getaddrinfo returns an error string in |out_error|. | |
874 */ | |
875 int HandleGetaddrinfo(struct PP_Var params, | |
876 struct PP_Var* output, | |
877 const char** out_error) { | |
878 CHECK_PARAM_COUNT(getaddrinfo, 2); | |
879 PARAM_STRING(0, name); | |
880 PARAM_STRING(1, family); | |
881 | |
882 struct addrinfo hints; | |
883 memset(&hints, 0, sizeof(hints)); | |
884 hints.ai_flags = AI_CANONNAME; | |
885 if (!strcmp(family, "AF_INET")) | |
886 hints.ai_family = AF_INET; | |
887 else if (!strcmp(family, "AF_INET6")) | |
888 hints.ai_family = AF_INET6; | |
889 else if (!strcmp(family, "AF_UNSPEC")) | |
890 hints.ai_family = AF_UNSPEC; | |
891 else { | |
892 *out_error = PrintfToNewString("getaddrinfo uknown family: %s", family); | |
893 return 1; | |
894 } | |
895 | |
896 struct addrinfo* ai; | |
897 int rtn = getaddrinfo(name, NULL, &hints, &ai); | |
898 if (rtn != 0) { | |
899 *out_error = PrintfToNewString("getaddrinfo failed, error is \"%s\"", | |
900 gai_strerror(rtn)); | |
901 return 2; | |
902 } | |
903 | |
904 CREATE_RESPONSE(getaddrinfo); | |
905 RESPONSE_STRING(ai->ai_canonname); | |
906 struct addrinfo* current = ai; | |
907 while (current) { | |
908 char addr_str[INET6_ADDRSTRLEN]; | |
909 if (ai->ai_family == AF_INET6) { | |
910 struct sockaddr_in6* in6 = (struct sockaddr_in6*)current->ai_addr; | |
911 inet_ntop( | |
912 ai->ai_family, &in6->sin6_addr.s6_addr, addr_str, sizeof(addr_str)); | |
913 } else if (ai->ai_family == AF_INET) { | |
914 struct sockaddr_in* in = (struct sockaddr_in*)current->ai_addr; | |
915 inet_ntop(ai->ai_family, &in->sin_addr, addr_str, sizeof(addr_str)); | |
916 } | |
917 | |
918 RESPONSE_STRING(addr_str); | |
919 RESPONSE_STRING(ai->ai_family == AF_INET ? "AF_INET" : "AF_INET6"); | |
920 | |
921 current = current->ai_next; | |
922 } | |
923 | |
924 freeaddrinfo(ai); | |
925 return 0; | |
926 } | |
927 | |
928 /** | |
929 * Handle a call to gethostbyname() made by JavaScript. | |
930 * | |
931 * gethostbyname expects 1 parameter: | |
932 * 0: The name of the host to look up. | |
933 * on success, gethostbyname returns a result in |output|: | |
934 * 0: "gethostbyname" | |
935 * 1: Host name | |
936 * 2: Address type (either "AF_INET" or "AF_INET6") | |
937 * 3: The first address. | |
938 * 4+ The second, third, etc. addresses. | |
939 * on failure, gethostbyname returns an error string in |out_error|. | |
940 */ | |
941 int HandleGethostbyname(struct PP_Var params, | |
942 struct PP_Var* output, | |
943 const char** out_error) { | |
944 CHECK_PARAM_COUNT(gethostbyname, 1); | |
945 PARAM_STRING(0, name); | |
946 | |
947 struct hostent* info = gethostbyname(name); | |
948 if (!info) { | |
949 *out_error = PrintfToNewString("gethostbyname failed, error is \"%s\"", | |
950 hstrerror(h_errno)); | |
951 return 1; | |
952 } | |
953 | |
954 CREATE_RESPONSE(gethostbyname); | |
955 RESPONSE_STRING(info->h_name); | |
956 RESPONSE_STRING(info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6"); | |
957 | |
958 struct in_addr** addr_list = (struct in_addr**)info->h_addr_list; | |
959 int i; | |
960 for (i = 0; addr_list[i] != NULL; i++) { | |
961 if (info->h_addrtype == AF_INET) { | |
962 RESPONSE_STRING(inet_ntoa(*addr_list[i])); | |
963 } else { // IPv6 | |
964 char addr_str[INET6_ADDRSTRLEN]; | |
965 inet_ntop(AF_INET6, addr_list[i], addr_str, sizeof(addr_str)); | |
966 RESPONSE_STRING(addr_str); | |
967 } | |
968 } | |
969 return 0; | |
970 } | |
971 | |
972 /** | |
973 * Handle a call to connect() made by JavaScript. | |
974 * | |
975 * connect expects 2 parameters: | |
976 * 0: The hostname to connect to. | |
977 * 1: The port number to connect to. | |
978 * on success, connect returns a result in |output|: | |
979 * 0: "connect" | |
980 * 1: The socket file descriptor. | |
981 * on failure, connect returns an error string in |out_error|. | |
982 */ | |
983 int HandleConnect(struct PP_Var params, | |
984 struct PP_Var* output, | |
985 const char** out_error) { | |
986 CHECK_PARAM_COUNT(connect, 2); | |
987 PARAM_STRING(0, hostname); | |
988 PARAM_INT(1, port); | |
989 | |
990 // Lookup host | |
991 struct hostent* hostent = gethostbyname(hostname); | |
992 if (hostent == NULL) { | |
993 *out_error = PrintfToNewString("gethostbyname() returned error: %d", errno); | |
994 return 1; | |
995 } | |
996 | |
997 struct sockaddr_in addr; | |
998 socklen_t addrlen = sizeof(addr); | |
999 addr.sin_family = AF_INET; | |
1000 addr.sin_port = htons(port); | |
1001 memcpy(&addr.sin_addr.s_addr, hostent->h_addr_list[0], hostent->h_length); | |
1002 | |
1003 int sock = socket(AF_INET, SOCK_STREAM, 0); | |
1004 if (sock < 0) { | |
1005 *out_error = PrintfToNewString("socket() failed: %s", strerror(errno)); | |
1006 return 1; | |
1007 } | |
1008 | |
1009 int result = connect(sock, (struct sockaddr*)&addr, addrlen); | |
1010 if (result != 0) { | |
1011 *out_error = PrintfToNewString("connect() failed: %s", strerror(errno)); | |
1012 close(sock); | |
1013 return 1; | |
1014 } | |
1015 | |
1016 CREATE_RESPONSE(connect); | |
1017 RESPONSE_INT(sock); | |
1018 return 0; | |
1019 } | |
1020 | |
1021 /** | |
1022 * Handle a call to send() made by JavaScript. | |
1023 * | |
1024 * send expects 2 parameters: | |
1025 * 0: The socket file descriptor to send using. | |
1026 * 1: The NULL terminated string to send. | |
1027 * on success, send returns a result in |output|: | |
1028 * 0: "send" | |
1029 * 1: The number of bytes sent. | |
1030 * on failure, send returns an error string in |out_error|. | |
1031 */ | |
1032 int HandleSend(struct PP_Var params, | |
1033 struct PP_Var* output, | |
1034 const char** out_error) { | |
1035 CHECK_PARAM_COUNT(send, 2); | |
1036 PARAM_INT(0, sock); | |
1037 PARAM_STRING(1, buffer); | |
1038 | |
1039 int result = send(sock, buffer, strlen(buffer), 0); | |
1040 if (result <= 0) { | |
1041 *out_error = PrintfToNewString("send failed: %s", strerror(errno)); | |
1042 return 1; | |
1043 } | |
1044 | |
1045 CREATE_RESPONSE(send); | |
1046 RESPONSE_INT(result); | |
1047 return 0; | |
1048 } | |
1049 | |
1050 /** | |
1051 * Handle a call to recv() made by JavaScript. | |
1052 * | |
1053 * recv expects 2 parameters: | |
1054 * 0: The socket file descriptor to recv from. | |
1055 * 1: The size of the buffer to pass to recv. | |
1056 * on success, send returns a result in |output|: | |
1057 * 0: "recv" | |
1058 * 1: The number of bytes received. | |
1059 * 2: The data received. | |
1060 * on failure, recv returns an error string in |out_error|. | |
1061 */ | |
1062 int HandleRecv(struct PP_Var params, | |
1063 struct PP_Var* output, | |
1064 const char** out_error) { | |
1065 CHECK_PARAM_COUNT(recv, 2); | |
1066 PARAM_INT(0, sock); | |
1067 PARAM_INT(1, buffersize); | |
1068 | |
1069 if (buffersize < 0 || buffersize > 65 * 1024) { | |
1070 *out_error = | |
1071 PrintfToNewString("recv buffersize must be between 0 and 65k."); | |
1072 return 1; | |
1073 } | |
1074 | |
1075 char* buffer = alloca(buffersize); | |
1076 memset(buffer, 0, buffersize); | |
1077 int result = recv(sock, buffer, buffersize, 0); | |
1078 if (result <= 0) { | |
1079 *out_error = PrintfToNewString("recv failed: %s", strerror(errno)); | |
1080 return 1; | |
1081 } | |
1082 | |
1083 CREATE_RESPONSE(recv); | |
1084 RESPONSE_INT(result); | |
1085 RESPONSE_STRING(buffer); | |
1086 return 0; | |
1087 } | |
1088 | |
1089 /** | |
1090 * Handle a call to close() made by JavaScript. | |
1091 * | |
1092 * close expects 1 parameters: | |
1093 * 0: The socket file descriptor to close. | |
1094 * on success, close returns a result in |output|: | |
1095 * 0: "close" | |
1096 * 1: The socket file descriptor closed. | |
1097 * on failure, close returns an error string in |out_error|. | |
1098 */ | |
1099 int HandleClose(struct PP_Var params, | |
1100 struct PP_Var* output, | |
1101 const char** out_error) { | |
1102 CHECK_PARAM_COUNT(close, 1); | |
1103 PARAM_INT(0, sock); | |
1104 | |
1105 int result = close(sock); | |
1106 if (result != 0) { | |
1107 *out_error = PrintfToNewString("close returned error: %d", errno); | |
1108 return 1; | |
1109 } | |
1110 | |
1111 CREATE_RESPONSE(close); | |
1112 RESPONSE_INT(sock); | |
1113 return 0; | |
1114 } | |
OLD | NEW |