[SyncFS] Build indexes from FileTracker entries on disk.
[chromium-blink-merge.git] / native_client_sdk / src / examples / demo / nacl_io_demo / handlers.c
blob4fef3507fffc15bb015da3dc120d5bc4200bdbba
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. */
5 #include "handlers.h"
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>
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/stat.h>
22 #include "nacl_io/osdirent.h"
24 #include "nacl_io_demo.h"
26 #define MAX_OPEN_FILES 10
27 #define MAX_OPEN_DIRS 10
28 #define MAX_PARAMS 4
30 #if defined(WIN32)
31 #define stat _stat
32 #endif
34 /**
35 * A mapping from int -> FILE*, so the JavaScript messages can refer to an open
36 * File.
38 static FILE* g_OpenFiles[MAX_OPEN_FILES];
40 /**
41 * A mapping from int -> DIR*, so the JavaScript messages can refer to an open
42 * Directory.
44 static void* g_OpenDirs[MAX_OPEN_DIRS];
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.
51 static char* g_ParamStrings[MAX_PARAMS];
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.
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;
70 return -1;
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.
79 static void RemoveFromMap(void** map, int max_map_size, int i) {
80 assert(i >= 0 && i < max_map_size);
81 map[i] = NULL;
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.
90 static int AddFileToMap(FILE* file) {
91 return AddToMap((void**)g_OpenFiles, MAX_OPEN_FILES, file);
94 /**
95 * Remove the file from the g_OpenFiles map.
96 * @param[in] i The index of the file handle to remove.
98 static void RemoveFileFromMap(int i) {
99 RemoveFromMap((void**)g_OpenFiles, MAX_OPEN_FILES, i);
102 /* Win32 doesn't support DIR/opendir/readdir/closedir. */
103 #if !defined(WIN32)
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.
110 static int AddDirToMap(DIR* dir) {
111 return AddToMap((void**)g_OpenDirs, MAX_OPEN_DIRS, dir);
115 * Remove the dir from the g_OpenDirs map.
116 * @param[in] i The index of the dir handle to remove.
118 static void RemoveDirFromMap(int i) {
119 RemoveFromMap((void**)g_OpenDirs, MAX_OPEN_DIRS, i);
121 #endif
124 * Get the number of parameters.
125 * @param[in] params The parameter array.
126 * @return uint32_t The number of parameters in the array.
128 static uint32_t GetNumParams(struct PP_Var params) {
129 return g_ppb_var_array->GetLength(params);
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.
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;
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;
159 uint32_t length;
160 const char* var_str = g_ppb_var->VarToUtf8(value, &length);
162 char* string = (char*)malloc(length + 1);
163 memcpy(string, var_str, length);
164 string[length] = 0;
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.
170 free(g_ParamStrings[index]);
171 g_ParamStrings[index] = string;
174 *out_string = string;
175 *out_string_len = length;
176 return 0;
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.
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;
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;
206 if (g_OpenFiles[file_index] == NULL) {
207 *out_error = PrintfToNewString("File index %d is not open", file_index);
208 return 1;
211 *out_file = g_OpenFiles[file_index];
212 *out_file_index = file_index;
213 return 0;
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.
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;
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;
243 if (g_OpenDirs[dir_index] == NULL) {
244 *out_error = PrintfToNewString("Dir index %d is not open", dir_index);
245 return 1;
248 *out_dir = g_OpenDirs[dir_index];
249 *out_dir_index = dir_index;
250 return 0;
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.
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;
272 *out_int = value.value.as_int;
273 return 0;
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.
282 static void CreateResponse(struct PP_Var* response_var,
283 const char* cmd,
284 const char** out_error) {
285 PP_Bool result;
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);
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);
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;
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);
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;
315 *response_var = dict_var;
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.
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);
334 // Return an error message instead.
335 *response_var = PP_MakeUndefined();
336 *out_error = PrintfToNewString("Unable to append value to result");
337 return;
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.
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);
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.
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);
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; \
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; \
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; \
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; \
395 #define PARAM_INT(index, var) \
396 int32_t var; \
397 if (GetParamInt(params, index, &var, out_error)) { \
398 return 1; \
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)
406 * Handle a call to fopen() made by JavaScript.
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|.
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);
424 FILE* file = fopen(filename, mode);
426 if (!file) {
427 *out_error = PrintfToNewString("fopen returned a NULL FILE*");
428 return 1;
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;
438 CREATE_RESPONSE(fopen);
439 RESPONSE_STRING(filename);
440 RESPONSE_INT(file_index);
441 return 0;
445 * Handle a call to fwrite() made by JavaScript.
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|.
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);
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;
470 CREATE_RESPONSE(fwrite);
471 RESPONSE_INT(file_index);
472 RESPONSE_INT(bytes_written);
473 return 0;
477 * Handle a call to fread() made by JavaScript.
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|.
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);
495 char* buffer = (char*)malloc(data_len + 1);
496 size_t bytes_read = fread(buffer, 1, data_len, file);
497 buffer[bytes_read] = 0;
499 if (ferror(file)) {
500 *out_error = PrintfToNewString("Read %d bytes, but ferror() returns true",
501 bytes_read);
502 free(buffer);
503 return 1;
506 CREATE_RESPONSE(fread);
507 RESPONSE_INT(file_index);
508 RESPONSE_STRING(buffer);
509 free(buffer);
510 return 0;
514 * Handle a call to fseek() made by JavaScript.
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|.
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);
537 int result = fseek(file, offset, whence);
538 if (result) {
539 *out_error = PrintfToNewString("fseek returned error %d", result);
540 return 1;
543 offset = ftell(file);
544 if (offset < 0) {
545 *out_error = PrintfToNewString(
546 "fseek succeeded, but ftell returned error %d", offset);
547 return 1;
550 CREATE_RESPONSE(fseek);
551 RESPONSE_INT(file_index);
552 RESPONSE_INT(offset);
553 return 0;
557 * Handle a call to fflush() made by JavaScript.
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|.
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);
572 fflush(file);
574 CREATE_RESPONSE(fflush);
575 RESPONSE_INT(file_index);
576 return 0;
580 * Handle a call to fclose() made by JavaScript.
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|.
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);
595 int result = fclose(file);
596 if (result) {
597 *out_error = PrintfToNewString("fclose returned error %d", result);
598 return 1;
601 RemoveFileFromMap(file_index);
603 CREATE_RESPONSE(fclose);
604 RESPONSE_INT(file_index);
605 return 0;
609 * Handle a call to stat() made by JavaScript.
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|.
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);
625 struct stat buf;
626 memset(&buf, 0, sizeof(buf));
627 int result = stat(filename, &buf);
629 if (result == -1) {
630 *out_error = PrintfToNewString("stat returned error %d", errno);
631 return 1;
634 CREATE_RESPONSE(stat);
635 RESPONSE_STRING(filename);
636 RESPONSE_INT(buf.st_size);
637 return 0;
641 * Handle a call to opendir() made by JavaScript.
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|.
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);
661 DIR* dir = opendir(dirname);
663 if (!dir) {
664 *out_error = PrintfToNewString("opendir returned a NULL DIR*");
665 return 1;
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;
675 CREATE_RESPONSE(opendir);
676 RESPONSE_STRING(dirname);
677 RESPONSE_INT(dir_index);
678 return 0;
679 #endif
683 * Handle a call to readdir() made by JavaScript.
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|.
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);
705 struct dirent* entry = readdir(dir);
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);
713 return 0;
714 #endif
718 * Handle a call to closedir() made by JavaScript.
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|.
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);
737 int result = closedir(dir);
738 if (result) {
739 *out_error = PrintfToNewString("closedir returned error %d", result);
740 return 1;
743 RemoveDirFromMap(dir_index);
745 CREATE_RESPONSE(closedir);
746 RESPONSE_INT(dir_index);
747 return 0;
748 #endif
752 * Handle a call to mkdir() made by JavaScript.
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|.
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);
769 int result = mkdir(dirname, mode);
771 if (result != 0) {
772 *out_error = PrintfToNewString("mkdir returned error: %d", errno);
773 return 1;
776 CREATE_RESPONSE(mkdir);
777 RESPONSE_STRING(dirname);
778 return 0;
782 * Handle a call to rmdir() made by JavaScript.
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|.
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);
797 int result = rmdir(dirname);
799 if (result != 0) {
800 *out_error = PrintfToNewString("rmdir returned error: %d", errno);
801 return 1;
804 CREATE_RESPONSE(rmdir);
805 RESPONSE_STRING(dirname);
806 return 0;
810 * Handle a call to chdir() made by JavaScript.
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|.
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);
825 int result = chdir(dirname);
827 if (result != 0) {
828 *out_error = PrintfToNewString("chdir returned error: %d", errno);
829 return 1;
832 CREATE_RESPONSE(chdir);
833 RESPONSE_STRING(dirname);
834 return 0;
838 * Handle a call to getcwd() made by JavaScript.
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|.
846 int HandleGetcwd(struct PP_Var params,
847 struct PP_Var* output,
848 const char** out_error) {
849 CHECK_PARAM_COUNT(getcwd, 0);
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;
858 CREATE_RESPONSE(getcwd);
859 RESPONSE_STRING(cwd);
860 return 0;
864 * Handle a call to getaddrinfo() made by JavaScript.
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|.
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);
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;
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;
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));
918 RESPONSE_STRING(addr_str);
919 RESPONSE_STRING(ai->ai_family == AF_INET ? "AF_INET" : "AF_INET6");
921 current = current->ai_next;
924 freeaddrinfo(ai);
925 return 0;
929 * Handle a call to gethostbyname() made by JavaScript.
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|.
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);
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;
954 CREATE_RESPONSE(gethostbyname);
955 RESPONSE_STRING(info->h_name);
956 RESPONSE_STRING(info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6");
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);
969 return 0;
973 * Handle a call to connect() made by JavaScript.
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|.
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);
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;
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);
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;
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;
1016 CREATE_RESPONSE(connect);
1017 RESPONSE_INT(sock);
1018 return 0;
1022 * Handle a call to send() made by JavaScript.
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|.
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);
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;
1045 CREATE_RESPONSE(send);
1046 RESPONSE_INT(result);
1047 return 0;
1051 * Handle a call to recv() made by JavaScript.
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|.
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);
1069 if (buffersize < 0 || buffersize > 65 * 1024) {
1070 *out_error =
1071 PrintfToNewString("recv buffersize must be between 0 and 65k.");
1072 return 1;
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;
1083 CREATE_RESPONSE(recv);
1084 RESPONSE_INT(result);
1085 RESPONSE_STRING(buffer);
1086 return 0;
1090 * Handle a call to close() made by JavaScript.
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|.
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);
1105 int result = close(sock);
1106 if (result != 0) {
1107 *out_error = PrintfToNewString("close returned error: %d", errno);
1108 return 1;
1111 CREATE_RESPONSE(close);
1112 RESPONSE_INT(sock);
1113 return 0;