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 */
38static 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 */
44static 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 */
51static 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 */
60static 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 */
79static 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 */
90static 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 */
98static 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 */
110static 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 */
118static 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 */
128static 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 */
141static 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 */
188static 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 */
225static 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 */
261static 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 */
282static 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 */
324static 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 */
347static 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 */
359static 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 */
417int 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 */
456int 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 */
488int 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 */
529int 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 */
566int 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 */
589int 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 */
619int 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 */
651int 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 */
695int 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 */
727int 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 */
762int 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 */
791int 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 */
819int 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 */
846int 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 */
875int 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 */
941int 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 */
983int 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 */
1032int 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 */
1062int 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 */
1099int 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}
1115