Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / native_client_sdk / src / examples / demo / nacl_io_demo / handlers.c
blobe11351178098bb8c925fca1a9f99421bfc6f66d2
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"
23 #include "nacl_io/osinttypes.h"
25 #include "nacl_io_demo.h"
27 #define MAX_OPEN_FILES 10
28 #define MAX_OPEN_DIRS 10
29 #define MAX_PARAMS 4
31 #if defined(WIN32)
32 #define stat _stat
33 #endif
35 /**
36 * A mapping from int -> FILE*, so the JavaScript messages can refer to an open
37 * File.
39 static FILE* g_OpenFiles[MAX_OPEN_FILES];
41 /**
42 * A mapping from int -> DIR*, so the JavaScript messages can refer to an open
43 * Directory.
45 static void* g_OpenDirs[MAX_OPEN_DIRS];
47 /**
48 * A collection of the most recently allocated parameter strings. This makes
49 * the Handle* functions below easier to write because they don't have to
50 * manually deallocate the strings they're using.
52 static char* g_ParamStrings[MAX_PARAMS];
54 /**
55 * Add |object| to |map| and return the index it was added at.
56 * @param[in] map The map to add the object to.
57 * @param[in] max_map_size The maximum map size.
58 * @param[in] object The object to add to the map.
59 * @return int The index of the added object, or -1 if there is no more space.
61 static int AddToMap(void** map, int max_map_size, void* object) {
62 int i;
63 assert(object != NULL);
64 for (i = 0; i < max_map_size; ++i) {
65 if (map[i] == NULL) {
66 map[i] = object;
67 return i;
71 return -1;
74 /**
75 * Remove an object at index |i| from |map|.
76 * @param[in] map The map to remove from.
77 * @param[in] max_map_size The size of the map.
78 * @param[in] i The index to remove.
80 static void RemoveFromMap(void** map, int max_map_size, int i) {
81 assert(i >= 0 && i < max_map_size);
82 map[i] = NULL;
85 /**
86 * Add the file to the g_OpenFiles map.
87 * @param[in] file The file to add to g_OpenFiles.
88 * @return int The index of the FILE in g_OpenFiles, or -1 if there are too many
89 * open files.
91 static int AddFileToMap(FILE* file) {
92 return AddToMap((void**)g_OpenFiles, MAX_OPEN_FILES, file);
95 /**
96 * Remove the file from the g_OpenFiles map.
97 * @param[in] i The index of the file handle to remove.
99 static void RemoveFileFromMap(int i) {
100 RemoveFromMap((void**)g_OpenFiles, MAX_OPEN_FILES, i);
103 /* Win32 doesn't support DIR/opendir/readdir/closedir. */
104 #if !defined(WIN32)
106 * Add the dir to the g_OpenDirs map.
107 * @param[in] dir The dir to add to g_OpenDirs.
108 * @return int The index of the DIR in g_OpenDirs, or -1 if there are too many
109 * open dirs.
111 static int AddDirToMap(DIR* dir) {
112 return AddToMap((void**)g_OpenDirs, MAX_OPEN_DIRS, dir);
116 * Remove the dir from the g_OpenDirs map.
117 * @param[in] i The index of the dir handle to remove.
119 static void RemoveDirFromMap(int i) {
120 RemoveFromMap((void**)g_OpenDirs, MAX_OPEN_DIRS, i);
122 #endif
125 * Get the number of parameters.
126 * @param[in] params The parameter array.
127 * @return uint32_t The number of parameters in the array.
129 static uint32_t GetNumParams(struct PP_Var params) {
130 return g_ppb_var_array->GetLength(params);
134 * Get a parameter at |index| as a string.
135 * @param[in] params The parameter array.
136 * @param[in] index The index in |params| to get.
137 * @param[out] out_string The output string.
138 * @param[out] out_string_len The length of the output string.
139 * @param[out] out_error An error message, if this operation failed.
140 * @return int 0 if successful, otherwise 1.
142 static int GetParamString(struct PP_Var params,
143 uint32_t index,
144 char** out_string,
145 uint32_t* out_string_len,
146 const char** out_error) {
147 if (index >= MAX_PARAMS) {
148 *out_error = PrintfToNewString("Param index %u >= MAX_PARAMS (%d)",
149 index, MAX_PARAMS);
150 return 1;
153 struct PP_Var value = g_ppb_var_array->Get(params, index);
154 if (value.type != PP_VARTYPE_STRING) {
155 *out_error =
156 PrintfToNewString("Expected param at index %d to be a string", index);
157 return 1;
160 uint32_t length;
161 const char* var_str = g_ppb_var->VarToUtf8(value, &length);
163 char* string = (char*)malloc(length + 1);
164 memcpy(string, var_str, length);
165 string[length] = 0;
167 /* Put the allocated string in g_ParamStrings. This keeps us from leaking
168 * each parameter string, without having to do manual cleanup in every
169 * Handle* function below.
171 free(g_ParamStrings[index]);
172 g_ParamStrings[index] = string;
175 *out_string = string;
176 *out_string_len = length;
177 return 0;
181 * Get a parameter at |index| as a FILE*.
182 * @param[in] params The parameter array.
183 * @param[in] index The index in |params| to get.
184 * @param[out] out_file The output FILE*.
185 * @param[out] out_file_index The index of the output FILE* in g_OpenFiles.
186 * @param[out] out_error An error message, if this operation failed.
187 * @return int 0 if successful, otherwise 1.
189 static int GetParamFile(struct PP_Var params,
190 uint32_t index,
191 FILE** out_file,
192 int32_t* out_file_index,
193 const char** out_error) {
194 struct PP_Var value = g_ppb_var_array->Get(params, index);
195 if (value.type != PP_VARTYPE_INT32) {
196 *out_error =
197 PrintfToNewString("Expected param at index %d to be an int32", index);
198 return 1;
201 int32_t file_index = value.value.as_int;
202 if (file_index < 0 || file_index >= MAX_OPEN_FILES) {
203 *out_error = PrintfToNewString("File index %d is out range", file_index);
204 return 1;
207 if (g_OpenFiles[file_index] == NULL) {
208 *out_error = PrintfToNewString("File index %d is not open", file_index);
209 return 1;
212 *out_file = g_OpenFiles[file_index];
213 *out_file_index = file_index;
214 return 0;
218 * Get a parameter at |index| as a DIR*.
219 * @param[in] params The parameter array.
220 * @param[in] index The index in |params| to get.
221 * @param[out] out_file The output DIR*.
222 * @param[out] out_file_index The index of the output DIR* in g_OpenDirs.
223 * @param[out] out_error An error message, if this operation failed.
224 * @return int 0 if successful, otherwise 1.
226 static int GetParamDir(struct PP_Var params,
227 uint32_t index,
228 DIR** out_dir,
229 int32_t* out_dir_index,
230 const char** out_error) {
231 struct PP_Var value = g_ppb_var_array->Get(params, index);
232 if (value.type != PP_VARTYPE_INT32) {
233 *out_error =
234 PrintfToNewString("Expected param at index %d to be an int32", index);
235 return 1;
238 int32_t dir_index = value.value.as_int;
239 if (dir_index < 0 || dir_index >= MAX_OPEN_DIRS) {
240 *out_error = PrintfToNewString("Dir at index %d is out range", dir_index);
241 return 1;
244 if (g_OpenDirs[dir_index] == NULL) {
245 *out_error = PrintfToNewString("Dir index %d is not open", dir_index);
246 return 1;
249 *out_dir = g_OpenDirs[dir_index];
250 *out_dir_index = dir_index;
251 return 0;
255 * Get a parameter at |index| as an int.
256 * @param[in] params The parameter array.
257 * @param[in] index The index in |params| to get.
258 * @param[out] out_file The output int32_t.
259 * @param[out] out_error An error message, if this operation failed.
260 * @return int 0 if successful, otherwise 1.
262 static int GetParamInt(struct PP_Var params,
263 uint32_t index,
264 int32_t* out_int,
265 const char** out_error) {
266 struct PP_Var value = g_ppb_var_array->Get(params, index);
267 if (value.type != PP_VARTYPE_INT32) {
268 *out_error =
269 PrintfToNewString("Expected param at index %d to be an int32", index);
270 return 1;
273 *out_int = value.value.as_int;
274 return 0;
278 * Create a response PP_Var to send back to JavaScript.
279 * @param[out] response_var The response PP_Var.
280 * @param[in] cmd The name of the function that is being executed.
281 * @param[out] out_error An error message, if this call failed.
283 static void CreateResponse(struct PP_Var* response_var,
284 const char* cmd,
285 const char** out_error) {
286 PP_Bool result;
288 struct PP_Var dict_var = g_ppb_var_dictionary->Create();
289 struct PP_Var cmd_key = CStrToVar("cmd");
290 struct PP_Var cmd_value = CStrToVar(cmd);
292 result = g_ppb_var_dictionary->Set(dict_var, cmd_key, cmd_value);
293 g_ppb_var->Release(cmd_key);
294 g_ppb_var->Release(cmd_value);
296 if (!result) {
297 g_ppb_var->Release(dict_var);
298 *out_error =
299 PrintfToNewString("Unable to set \"cmd\" key in result dictionary");
300 return;
303 struct PP_Var args_key = CStrToVar("args");
304 struct PP_Var args_value = g_ppb_var_array->Create();
305 result = g_ppb_var_dictionary->Set(dict_var, args_key, args_value);
306 g_ppb_var->Release(args_key);
307 g_ppb_var->Release(args_value);
309 if (!result) {
310 g_ppb_var->Release(dict_var);
311 *out_error =
312 PrintfToNewString("Unable to set \"args\" key in result dictionary");
313 return;
316 *response_var = dict_var;
320 * Append a PP_Var to the response dictionary.
321 * @param[in,out] response_var The response PP_var.
322 * @param[in] value The value to add to the response args.
323 * @param[out] out_error An error message, if this call failed.
325 static void AppendResponseVar(struct PP_Var* response_var,
326 struct PP_Var value,
327 const char** out_error) {
328 struct PP_Var args_value = GetDictVar(*response_var, "args");
329 uint32_t args_length = g_ppb_var_array->GetLength(args_value);
330 PP_Bool result = g_ppb_var_array->Set(args_value, args_length, value);
331 if (!result) {
332 // Release the dictionary that was there before.
333 g_ppb_var->Release(*response_var);
335 // Return an error message instead.
336 *response_var = PP_MakeUndefined();
337 *out_error = PrintfToNewString("Unable to append value to result");
338 return;
343 * Append an int to the response dictionary.
344 * @param[in,out] response_var The response PP_var.
345 * @param[in] value The value to add to the response args.
346 * @param[out] out_error An error message, if this call failed.
348 static void AppendResponseInt(struct PP_Var* response_var,
349 int32_t value,
350 const char** out_error) {
351 AppendResponseVar(response_var, PP_MakeInt32(value), out_error);
355 * Append a string to the response dictionary.
356 * @param[in,out] response_var The response PP_var.
357 * @param[in] value The value to add to the response args.
358 * @param[out] out_error An error message, if this call failed.
360 static void AppendResponseString(struct PP_Var* response_var,
361 const char* value,
362 const char** out_error) {
363 struct PP_Var value_var = CStrToVar(value);
364 AppendResponseVar(response_var, value_var, out_error);
365 g_ppb_var->Release(value_var);
368 #define CHECK_PARAM_COUNT(name, expected) \
369 if (GetNumParams(params) != expected) { \
370 *out_error = PrintfToNewString(#name " takes " #expected " parameters." \
371 " Got %d", GetNumParams(params)); \
372 return 1; \
375 #define PARAM_STRING(index, var) \
376 char* var; \
377 uint32_t var##_len; \
378 if (GetParamString(params, index, &var, &var##_len, out_error)) { \
379 return 1; \
382 #define PARAM_FILE(index, var) \
383 FILE* var; \
384 int32_t var##_index; \
385 if (GetParamFile(params, index, &var, &var##_index, out_error)) { \
386 return 1; \
389 #define PARAM_DIR(index, var) \
390 DIR* var; \
391 int32_t var##_index; \
392 if (GetParamDir(params, index, &var, &var##_index, out_error)) { \
393 return 1; \
396 #define PARAM_INT(index, var) \
397 int32_t var; \
398 if (GetParamInt(params, index, &var, out_error)) { \
399 return 1; \
402 #define CREATE_RESPONSE(name) CreateResponse(output, #name, out_error)
403 #define RESPONSE_STRING(var) AppendResponseString(output, var, out_error)
404 #define RESPONSE_INT(var) AppendResponseInt(output, var, out_error)
407 * Handle a call to fopen() made by JavaScript.
409 * fopen expects 2 parameters:
410 * 0: the path of the file to open
411 * 1: the mode string
412 * on success, fopen returns a result in |output|:
413 * 0: "fopen"
414 * 1: the filename opened
415 * 2: the file index
416 * on failure, fopen returns an error string in |out_error|.
418 int HandleFopen(struct PP_Var params,
419 struct PP_Var* output,
420 const char** out_error) {
421 CHECK_PARAM_COUNT(fopen, 2);
422 PARAM_STRING(0, filename);
423 PARAM_STRING(1, mode);
425 FILE* file = fopen(filename, mode);
427 if (!file) {
428 *out_error = PrintfToNewString("fopen returned a NULL FILE*");
429 return 1;
432 int file_index = AddFileToMap(file);
433 if (file_index == -1) {
434 *out_error = PrintfToNewString("Example only allows %d open file handles",
435 MAX_OPEN_FILES);
436 return 1;
439 CREATE_RESPONSE(fopen);
440 RESPONSE_STRING(filename);
441 RESPONSE_INT(file_index);
442 return 0;
446 * Handle a call to fwrite() made by JavaScript.
448 * fwrite expects 2 parameters:
449 * 0: The index of the file (which is mapped to a FILE*)
450 * 1: A string to write to the file
451 * on success, fwrite returns a result in |output|:
452 * 0: "fwrite"
453 * 1: the file index
454 * 2: the number of bytes written
455 * on failure, fwrite returns an error string in |out_error|.
457 int HandleFwrite(struct PP_Var params,
458 struct PP_Var* output,
459 const char** out_error) {
460 CHECK_PARAM_COUNT(fwrite, 2);
461 PARAM_FILE(0, file);
462 PARAM_STRING(1, data);
464 size_t bytes_written = fwrite(data, 1, data_len, file);
465 if (ferror(file)) {
466 *out_error = PrintfToNewString(
467 "Wrote %" PRIuS " bytes, but ferror() returns true", bytes_written);
468 return 1;
471 CREATE_RESPONSE(fwrite);
472 RESPONSE_INT(file_index);
473 RESPONSE_INT(bytes_written);
474 return 0;
478 * Handle a call to fread() made by JavaScript.
480 * fread expects 2 parameters:
481 * 0: The index of the file (which is mapped to a FILE*)
482 * 1: The number of bytes to read from the file.
483 * on success, fread returns a result in |output|:
484 * 0: "fread"
485 * 1: the file index
486 * 2: the data read from the file
487 * on failure, fread returns an error string in |out_error|.
489 int HandleFread(struct PP_Var params,
490 struct PP_Var* output,
491 const char** out_error) {
492 CHECK_PARAM_COUNT(fread, 2);
493 PARAM_FILE(0, file);
494 PARAM_INT(1, data_len);
496 char* buffer = (char*)malloc(data_len + 1);
497 size_t bytes_read = fread(buffer, 1, data_len, file);
498 buffer[bytes_read] = 0;
500 if (ferror(file)) {
501 *out_error = PrintfToNewString(
502 "Read %" PRIuS " bytes, but ferror() returns true", bytes_read);
503 free(buffer);
504 return 1;
507 CREATE_RESPONSE(fread);
508 RESPONSE_INT(file_index);
509 RESPONSE_STRING(buffer);
510 free(buffer);
511 return 0;
515 * Handle a call to fseek() made by JavaScript.
517 * fseek expects 3 parameters:
518 * 0: The index of the file (which is mapped to a FILE*)
519 * 1: The offset to seek to
520 * 2: An integer representing the whence parameter of standard fseek.
521 * whence = 0: seek from the beginning of the file
522 * whence = 1: seek from the current file position
523 * whence = 2: seek from the end of the file
524 * on success, fseek returns a result in |output|:
525 * 0: "fseek"
526 * 1: the file index
527 * 2: The new file position
528 * on failure, fseek returns an error string in |out_error|.
530 int HandleFseek(struct PP_Var params,
531 struct PP_Var* output,
532 const char** out_error) {
533 CHECK_PARAM_COUNT(fseek, 3);
534 PARAM_FILE(0, file);
535 PARAM_INT(1, offset);
536 PARAM_INT(2, whence);
538 int result = fseek(file, offset, whence);
539 if (result) {
540 *out_error = PrintfToNewString("fseek returned error %d", result);
541 return 1;
544 offset = ftell(file);
545 if (offset < 0) {
546 *out_error = PrintfToNewString(
547 "fseek succeeded, but ftell returned error %d", offset);
548 return 1;
551 CREATE_RESPONSE(fseek);
552 RESPONSE_INT(file_index);
553 RESPONSE_INT(offset);
554 return 0;
558 * Handle a call to fflush() made by JavaScript.
560 * fflush expects 1 parameters:
561 * 0: The index of the file (which is mapped to a FILE*)
562 * on success, fflush returns a result in |output|:
563 * 0: "fflush"
564 * 1: the file index
565 * on failure, fflush returns an error string in |out_error|.
567 int HandleFflush(struct PP_Var params,
568 struct PP_Var* output,
569 const char** out_error) {
570 CHECK_PARAM_COUNT(fflush, 1);
571 PARAM_FILE(0, file);
573 fflush(file);
575 CREATE_RESPONSE(fflush);
576 RESPONSE_INT(file_index);
577 return 0;
581 * Handle a call to fclose() made by JavaScript.
583 * fclose expects 1 parameter:
584 * 0: The index of the file (which is mapped to a FILE*)
585 * on success, fclose returns a result in |output|:
586 * 0: "fclose"
587 * 1: the file index
588 * on failure, fclose returns an error string in |out_error|.
590 int HandleFclose(struct PP_Var params,
591 struct PP_Var* output,
592 const char** out_error) {
593 CHECK_PARAM_COUNT(fclose, 1);
594 PARAM_FILE(0, file);
596 int result = fclose(file);
597 if (result) {
598 *out_error = PrintfToNewString("fclose returned error %d", result);
599 return 1;
602 RemoveFileFromMap(file_index);
604 CREATE_RESPONSE(fclose);
605 RESPONSE_INT(file_index);
606 return 0;
610 * Handle a call to stat() made by JavaScript.
612 * stat expects 1 parameter:
613 * 0: The name of the file
614 * on success, stat returns a result in |output|:
615 * 0: "stat"
616 * 1: the file name
617 * 2: the size of the file
618 * on failure, stat returns an error string in |out_error|.
620 int HandleStat(struct PP_Var params,
621 struct PP_Var* output,
622 const char** out_error) {
623 CHECK_PARAM_COUNT(stat, 1);
624 PARAM_STRING(0, filename);
626 struct stat buf;
627 memset(&buf, 0, sizeof(buf));
628 int result = stat(filename, &buf);
630 if (result == -1) {
631 *out_error = PrintfToNewString("stat returned error %d", errno);
632 return 1;
635 CREATE_RESPONSE(stat);
636 RESPONSE_STRING(filename);
637 RESPONSE_INT(buf.st_size);
638 return 0;
642 * Handle a call to opendir() made by JavaScript.
644 * opendir expects 1 parameter:
645 * 0: The name of the directory
646 * on success, opendir returns a result in |output|:
647 * 0: "opendir"
648 * 1: the directory name
649 * 2: the index of the directory
650 * on failure, opendir returns an error string in |out_error|.
652 int HandleOpendir(struct PP_Var params,
653 struct PP_Var* output,
654 const char** out_error) {
655 #if defined(WIN32)
656 *out_error = PrintfToNewString("Win32 does not support opendir");
657 return 1;
658 #else
659 CHECK_PARAM_COUNT(opendir, 1);
660 PARAM_STRING(0, dirname);
662 DIR* dir = opendir(dirname);
664 if (!dir) {
665 *out_error = PrintfToNewString("opendir returned a NULL DIR*");
666 return 1;
669 int dir_index = AddDirToMap(dir);
670 if (dir_index == -1) {
671 *out_error = PrintfToNewString("Example only allows %d open dir handles",
672 MAX_OPEN_DIRS);
673 return 1;
676 CREATE_RESPONSE(opendir);
677 RESPONSE_STRING(dirname);
678 RESPONSE_INT(dir_index);
679 return 0;
680 #endif
684 * Handle a call to readdir() made by JavaScript.
686 * readdir expects 1 parameter:
687 * 0: The index of the directory (which is mapped to a DIR*)
688 * on success, opendir returns a result in |output|:
689 * 0: "readdir"
690 * 1: the inode number of the entry
691 * 2: the name of the entry
692 * if there are no more entries, |output| contains:
693 * 0: "readdir"
694 * on failure, readdir returns an error string in |out_error|.
696 int HandleReaddir(struct PP_Var params,
697 struct PP_Var* output,
698 const char** out_error) {
699 #if defined(WIN32)
700 *out_error = PrintfToNewString("Win32 does not support readdir");
701 return 1;
702 #else
703 CHECK_PARAM_COUNT(readdir, 1);
704 PARAM_DIR(0, dir);
706 struct dirent* entry = readdir(dir);
708 CREATE_RESPONSE(readdir);
709 RESPONSE_INT(dir_index);
710 if (entry != NULL) {
711 RESPONSE_INT(entry->d_ino);
712 RESPONSE_STRING(entry->d_name);
714 return 0;
715 #endif
719 * Handle a call to closedir() made by JavaScript.
721 * closedir expects 1 parameter:
722 * 0: The index of the directory (which is mapped to a DIR*)
723 * on success, closedir returns a result in |output|:
724 * 0: "closedir"
725 * 1: the name of the directory
726 * on failure, closedir returns an error string in |out_error|.
728 int HandleClosedir(struct PP_Var params,
729 struct PP_Var* output,
730 const char** out_error) {
731 #if defined(WIN32)
732 *out_error = PrintfToNewString("Win32 does not support closedir");
733 return 1;
734 #else
735 CHECK_PARAM_COUNT(closedir, 1);
736 PARAM_DIR(0, dir);
738 int result = closedir(dir);
739 if (result) {
740 *out_error = PrintfToNewString("closedir returned error %d", result);
741 return 1;
744 RemoveDirFromMap(dir_index);
746 CREATE_RESPONSE(closedir);
747 RESPONSE_INT(dir_index);
748 return 0;
749 #endif
753 * Handle a call to mkdir() made by JavaScript.
755 * mkdir expects 1 parameter:
756 * 0: The name of the directory
757 * 1: The mode to use for the new directory, in octal.
758 * on success, mkdir returns a result in |output|:
759 * 0: "mkdir"
760 * 1: the name of the directory
761 * on failure, mkdir returns an error string in |out_error|.
763 int HandleMkdir(struct PP_Var params,
764 struct PP_Var* output,
765 const char** out_error) {
766 CHECK_PARAM_COUNT(mkdir, 2);
767 PARAM_STRING(0, dirname);
768 PARAM_INT(1, mode);
770 int result = mkdir(dirname, mode);
772 if (result != 0) {
773 *out_error = PrintfToNewString("mkdir returned error: %d", errno);
774 return 1;
777 CREATE_RESPONSE(mkdir);
778 RESPONSE_STRING(dirname);
779 return 0;
783 * Handle a call to rmdir() made by JavaScript.
785 * rmdir expects 1 parameter:
786 * 0: The name of the directory to remove
787 * on success, rmdir returns a result in |output|:
788 * 0: "rmdir"
789 * 1: the name of the directory
790 * on failure, rmdir returns an error string in |out_error|.
792 int HandleRmdir(struct PP_Var params,
793 struct PP_Var* output,
794 const char** out_error) {
795 CHECK_PARAM_COUNT(rmdir, 1);
796 PARAM_STRING(0, dirname);
798 int result = rmdir(dirname);
800 if (result != 0) {
801 *out_error = PrintfToNewString("rmdir returned error: %d", errno);
802 return 1;
805 CREATE_RESPONSE(rmdir);
806 RESPONSE_STRING(dirname);
807 return 0;
811 * Handle a call to chdir() made by JavaScript.
813 * chdir expects 1 parameter:
814 * 0: The name of the directory
815 * on success, chdir returns a result in |output|:
816 * 0: "chdir"
817 * 1: the name of the directory
818 * on failure, chdir returns an error string in |out_error|.
820 int HandleChdir(struct PP_Var params,
821 struct PP_Var* output,
822 const char** out_error) {
823 CHECK_PARAM_COUNT(chdir, 1);
824 PARAM_STRING(0, dirname);
826 int result = chdir(dirname);
828 if (result != 0) {
829 *out_error = PrintfToNewString("chdir returned error: %d", errno);
830 return 1;
833 CREATE_RESPONSE(chdir);
834 RESPONSE_STRING(dirname);
835 return 0;
839 * Handle a call to getcwd() made by JavaScript.
841 * getcwd expects 0 parameters.
842 * on success, getcwd returns a result in |output|:
843 * 0: "getcwd"
844 * 1: the current working directory
845 * on failure, getcwd returns an error string in |out_error|.
847 int HandleGetcwd(struct PP_Var params,
848 struct PP_Var* output,
849 const char** out_error) {
850 CHECK_PARAM_COUNT(getcwd, 0);
852 char cwd[PATH_MAX];
853 char* result = getcwd(cwd, PATH_MAX);
854 if (result == NULL) {
855 *out_error = PrintfToNewString("getcwd returned error: %d", errno);
856 return 1;
859 CREATE_RESPONSE(getcwd);
860 RESPONSE_STRING(cwd);
861 return 0;
865 * Handle a call to getaddrinfo() made by JavaScript.
867 * getaddrinfo expects 1 parameter:
868 * 0: The name of the host to look up.
869 * on success, getaddrinfo returns a result in |output|:
870 * 0: "getaddrinfo"
871 * 1: The canonical name
872 * 2*n+2: Host name
873 * 2*n+3: Address type (either "AF_INET" or "AF_INET6")
874 * on failure, getaddrinfo returns an error string in |out_error|.
876 int HandleGetaddrinfo(struct PP_Var params,
877 struct PP_Var* output,
878 const char** out_error) {
879 CHECK_PARAM_COUNT(getaddrinfo, 2);
880 PARAM_STRING(0, name);
881 PARAM_STRING(1, family);
883 struct addrinfo hints;
884 memset(&hints, 0, sizeof(hints));
885 hints.ai_flags = AI_CANONNAME;
886 if (!strcmp(family, "AF_INET"))
887 hints.ai_family = AF_INET;
888 else if (!strcmp(family, "AF_INET6"))
889 hints.ai_family = AF_INET6;
890 else if (!strcmp(family, "AF_UNSPEC"))
891 hints.ai_family = AF_UNSPEC;
892 else {
893 *out_error = PrintfToNewString("getaddrinfo uknown family: %s", family);
894 return 1;
897 struct addrinfo* ai;
898 int rtn = getaddrinfo(name, NULL, &hints, &ai);
899 if (rtn != 0) {
900 *out_error = PrintfToNewString("getaddrinfo failed, error is \"%s\"",
901 gai_strerror(rtn));
902 return 2;
905 CREATE_RESPONSE(getaddrinfo);
906 RESPONSE_STRING(ai->ai_canonname);
907 struct addrinfo* current = ai;
908 while (current) {
909 char addr_str[INET6_ADDRSTRLEN];
910 if (ai->ai_family == AF_INET6) {
911 struct sockaddr_in6* in6 = (struct sockaddr_in6*)current->ai_addr;
912 inet_ntop(
913 ai->ai_family, &in6->sin6_addr.s6_addr, addr_str, sizeof(addr_str));
914 } else if (ai->ai_family == AF_INET) {
915 struct sockaddr_in* in = (struct sockaddr_in*)current->ai_addr;
916 inet_ntop(ai->ai_family, &in->sin_addr, addr_str, sizeof(addr_str));
919 RESPONSE_STRING(addr_str);
920 RESPONSE_STRING(ai->ai_family == AF_INET ? "AF_INET" : "AF_INET6");
922 current = current->ai_next;
925 freeaddrinfo(ai);
926 return 0;
930 * Handle a call to gethostbyname() made by JavaScript.
932 * gethostbyname expects 1 parameter:
933 * 0: The name of the host to look up.
934 * on success, gethostbyname returns a result in |output|:
935 * 0: "gethostbyname"
936 * 1: Host name
937 * 2: Address type (either "AF_INET" or "AF_INET6")
938 * 3: The first address.
939 * 4+ The second, third, etc. addresses.
940 * on failure, gethostbyname returns an error string in |out_error|.
942 int HandleGethostbyname(struct PP_Var params,
943 struct PP_Var* output,
944 const char** out_error) {
945 CHECK_PARAM_COUNT(gethostbyname, 1);
946 PARAM_STRING(0, name);
948 struct hostent* info = gethostbyname(name);
949 if (!info) {
950 *out_error = PrintfToNewString("gethostbyname failed, error is \"%s\"",
951 hstrerror(h_errno));
952 return 1;
955 CREATE_RESPONSE(gethostbyname);
956 RESPONSE_STRING(info->h_name);
957 RESPONSE_STRING(info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6");
959 struct in_addr** addr_list = (struct in_addr**)info->h_addr_list;
960 int i;
961 for (i = 0; addr_list[i] != NULL; i++) {
962 if (info->h_addrtype == AF_INET) {
963 RESPONSE_STRING(inet_ntoa(*addr_list[i]));
964 } else { // IPv6
965 char addr_str[INET6_ADDRSTRLEN];
966 inet_ntop(AF_INET6, addr_list[i], addr_str, sizeof(addr_str));
967 RESPONSE_STRING(addr_str);
970 return 0;
974 * Handle a call to connect() made by JavaScript.
976 * connect expects 2 parameters:
977 * 0: The hostname to connect to.
978 * 1: The port number to connect to.
979 * on success, connect returns a result in |output|:
980 * 0: "connect"
981 * 1: The socket file descriptor.
982 * on failure, connect returns an error string in |out_error|.
984 int HandleConnect(struct PP_Var params,
985 struct PP_Var* output,
986 const char** out_error) {
987 CHECK_PARAM_COUNT(connect, 2);
988 PARAM_STRING(0, hostname);
989 PARAM_INT(1, port);
991 // Lookup host
992 struct hostent* hostent = gethostbyname(hostname);
993 if (hostent == NULL) {
994 *out_error = PrintfToNewString("gethostbyname() returned error: %d", errno);
995 return 1;
998 struct sockaddr_in addr;
999 socklen_t addrlen = sizeof(addr);
1000 addr.sin_family = AF_INET;
1001 addr.sin_port = htons(port);
1002 memcpy(&addr.sin_addr.s_addr, hostent->h_addr_list[0], hostent->h_length);
1004 int sock = socket(AF_INET, SOCK_STREAM, 0);
1005 if (sock < 0) {
1006 *out_error = PrintfToNewString("socket() failed: %s", strerror(errno));
1007 return 1;
1010 int result = connect(sock, (struct sockaddr*)&addr, addrlen);
1011 if (result != 0) {
1012 *out_error = PrintfToNewString("connect() failed: %s", strerror(errno));
1013 close(sock);
1014 return 1;
1017 CREATE_RESPONSE(connect);
1018 RESPONSE_INT(sock);
1019 return 0;
1023 * Handle a call to send() made by JavaScript.
1025 * send expects 2 parameters:
1026 * 0: The socket file descriptor to send using.
1027 * 1: The NULL terminated string to send.
1028 * on success, send returns a result in |output|:
1029 * 0: "send"
1030 * 1: The number of bytes sent.
1031 * on failure, send returns an error string in |out_error|.
1033 int HandleSend(struct PP_Var params,
1034 struct PP_Var* output,
1035 const char** out_error) {
1036 CHECK_PARAM_COUNT(send, 2);
1037 PARAM_INT(0, sock);
1038 PARAM_STRING(1, buffer);
1040 int result = send(sock, buffer, strlen(buffer), 0);
1041 if (result <= 0) {
1042 *out_error = PrintfToNewString("send failed: %s", strerror(errno));
1043 return 1;
1046 CREATE_RESPONSE(send);
1047 RESPONSE_INT(result);
1048 return 0;
1052 * Handle a call to recv() made by JavaScript.
1054 * recv expects 2 parameters:
1055 * 0: The socket file descriptor to recv from.
1056 * 1: The size of the buffer to pass to recv.
1057 * on success, send returns a result in |output|:
1058 * 0: "recv"
1059 * 1: The number of bytes received.
1060 * 2: The data received.
1061 * on failure, recv returns an error string in |out_error|.
1063 int HandleRecv(struct PP_Var params,
1064 struct PP_Var* output,
1065 const char** out_error) {
1066 CHECK_PARAM_COUNT(recv, 2);
1067 PARAM_INT(0, sock);
1068 PARAM_INT(1, buffersize);
1070 if (buffersize < 0 || buffersize > 65 * 1024) {
1071 *out_error =
1072 PrintfToNewString("recv buffersize must be between 0 and 65k.");
1073 return 1;
1076 char* buffer = alloca(buffersize);
1077 memset(buffer, 0, buffersize);
1078 int result = recv(sock, buffer, buffersize, 0);
1079 if (result <= 0) {
1080 *out_error = PrintfToNewString("recv failed: %s", strerror(errno));
1081 return 1;
1084 CREATE_RESPONSE(recv);
1085 RESPONSE_INT(result);
1086 RESPONSE_STRING(buffer);
1087 return 0;
1091 * Handle a call to close() made by JavaScript.
1093 * close expects 1 parameters:
1094 * 0: The socket file descriptor to close.
1095 * on success, close returns a result in |output|:
1096 * 0: "close"
1097 * 1: The socket file descriptor closed.
1098 * on failure, close returns an error string in |out_error|.
1100 int HandleClose(struct PP_Var params,
1101 struct PP_Var* output,
1102 const char** out_error) {
1103 CHECK_PARAM_COUNT(close, 1);
1104 PARAM_INT(0, sock);
1106 int result = close(sock);
1107 if (result != 0) {
1108 *out_error = PrintfToNewString("close returned error: %d", errno);
1109 return 1;
1112 CREATE_RESPONSE(close);
1113 RESPONSE_INT(sock);
1114 return 0;