- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / examples / demo / nacl_io / handlers.c
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
29 #if defined(WIN32)
30 #define stat _stat
31 #endif
32
33 /**
34  * A mapping from int -> FILE*, so the JavaScript messages can refer to an open
35  * File.
36  */
37 static FILE* g_OpenFiles[MAX_OPEN_FILES];
38
39 /**
40  * A mapping from int -> DIR*, so the JavaScript messages can refer to an open
41  * Directory.
42  */
43 static void* g_OpenDirs[MAX_OPEN_DIRS];
44
45 /**
46  * Add |object| to |map| and return the index it was added at.
47  * @param[in] map The map to add the object to.
48  * @param[in] max_map_size The maximum map size.
49  * @param[in] object The object to add to the map.
50  * @return int The index of the added object, or -1 if there is no more space.
51  */
52 static int AddToMap(void** map, int max_map_size, void* object) {
53   int i;
54   assert(object != NULL);
55   for (i = 0; i < max_map_size; ++i) {
56     if (map[i] == NULL) {
57       map[i] = object;
58       return i;
59     }
60   }
61
62   return -1;
63 }
64
65 /**
66  * Remove an object at index |i| from |map|.
67  * @param[in] map The map to remove from.
68  * @param[in] max_map_size The size of the map.
69  * @param[in] i The index to remove.
70  */
71 static void RemoveFromMap(void** map, int max_map_size, int i) {
72   assert(i >= 0 && i < max_map_size);
73   map[i] = NULL;
74 }
75
76 /**
77  * Get the object from |map| at index |i|.
78  * @param[in] map The map to access.
79  * @param[in] max_map_size The size of the map.
80  * @param[in] i The index to access.
81  * @return the object at |map|. This will be NULL if there is no object at |i|.
82  */
83 static void* GetFromMap(void** map, int max_map_size, int i) {
84   assert(i >= 0 && i < max_map_size);
85   return map[i];
86 }
87
88 /**
89  * Get an object given a string |s| containing the index.
90  * @param[in] map The map to access.
91  * @param[in] max_map_size The size of the map.
92  * @param[in] s The string containing the object index.
93  * @param[out] index The index of the object as an int.
94  * @return The object, or NULL if the index is invalid.
95  */
96 static void* GetFromIndexString(void** map,
97                                 int max_map_size,
98                                 const char* s,
99                                 int* index) {
100   char* endptr;
101   int result = strtol(s, &endptr, 10);
102   if (endptr != s + strlen(s)) {
103     /* Garbage at the end of the number...? */
104     return NULL;
105   }
106
107   if (index)
108     *index = result;
109
110   return GetFromMap(map, max_map_size, result);
111 }
112
113 /**
114  * Add the file to the g_OpenFiles map.
115  * @param[in] file The file to add to g_OpenFiles.
116  * @return int The index of the FILE in g_OpenFiles, or -1 if there are too many
117  *             open files.
118  */
119 static int AddFileToMap(FILE* file) {
120   return AddToMap((void**)g_OpenFiles, MAX_OPEN_FILES, file);
121 }
122
123 /**
124  * Remove the file from the g_OpenFiles map.
125  * @param[in] i The index of the file handle to remove.
126  */
127 static void RemoveFileFromMap(int i) {
128   RemoveFromMap((void**)g_OpenFiles, MAX_OPEN_FILES, i);
129 }
130
131 /**
132  * Get a file, given a string containing the index.
133  * @param[in] s The string containing the file index.
134  * @param[out] file_index The index of this file.
135  * @return The FILE* for this file, or NULL if the index is invalid.
136  */
137 static FILE* GetFileFromIndexString(const char* s, int* file_index) {
138   return (FILE*)GetFromIndexString(
139       (void**)g_OpenFiles, MAX_OPEN_FILES, s, file_index);
140 }
141
142 /* Win32 doesn't support DIR/opendir/readdir/closedir. */
143 #if !defined(WIN32)
144 /**
145  * Add the dir to the g_OpenDirs map.
146  * @param[in] dir The dir to add to g_OpenDirs.
147  * @return int The index of the DIR in g_OpenDirs, or -1 if there are too many
148  *             open dirs.
149  */
150 static int AddDirToMap(DIR* dir) {
151   return AddToMap((void**)g_OpenDirs, MAX_OPEN_DIRS, dir);
152 }
153
154 /**
155  * Remove the dir from the g_OpenDirs map.
156  * @param[in] i The index of the dir handle to remove.
157  */
158 static void RemoveDirFromMap(int i) {
159   RemoveFromMap((void**)g_OpenDirs, MAX_OPEN_DIRS, i);
160 }
161
162 /**
163  * Get a dir, given a string containing the index.
164  * @param[in] s The string containing the dir index.
165  * @param[out] dir_index The index of this dir.
166  * @return The DIR* for this dir, or NULL if the index is invalid.
167  */
168 static DIR* GetDirFromIndexString(const char* s, int* dir_index) {
169   return (DIR*)GetFromIndexString(
170       (void**)g_OpenDirs, MAX_OPEN_DIRS, s, dir_index);
171 }
172 #endif
173
174 /**
175  * Handle a call to fopen() made by JavaScript.
176  *
177  * fopen expects 2 parameters:
178  *   0: the path of the file to open
179  *   1: the mode string
180  * on success, fopen returns a result in |output| separated by \1:
181  *   0: "fopen"
182  *   1: the filename opened
183  *   2: the file index
184  * on failure, fopen returns an error string in |output|.
185  *
186  * @param[in] num_params The number of params in |params|.
187  * @param[in] params An array of strings, parameters to this function.
188  * @param[out] output A string to write informational function output to.
189  * @return An errorcode; 0 means success, anything else is a failure.
190  */
191 int HandleFopen(int num_params, char** params, char** output) {
192   FILE* file;
193   int file_index;
194   const char* filename;
195   const char* mode;
196
197   if (num_params != 2) {
198     *output = PrintfToNewString("fopen takes 2 parameters.");
199     return 1;
200   }
201
202   filename = params[0];
203   mode = params[1];
204
205   file = fopen(filename, mode);
206   if (!file) {
207     *output = PrintfToNewString("fopen returned a NULL FILE*.");
208     return 2;
209   }
210
211   file_index = AddFileToMap(file);
212   if (file_index == -1) {
213     *output = PrintfToNewString(
214         "Example only allows %d open file handles.", MAX_OPEN_FILES);
215     return 3;
216   }
217
218   *output = PrintfToNewString("fopen\1%s\1%d", filename, file_index);
219   return 0;
220 }
221
222 /**
223  * Handle a call to fwrite() made by JavaScript.
224  *
225  * fwrite expects 2 parameters:
226  *   0: The index of the file (which is mapped to a FILE*)
227  *   1: A string to write to the file
228  * on success, fwrite returns a result in |output| separated by \1:
229  *   0: "fwrite"
230  *   1: the file index
231  *   2: the number of bytes written
232  * on failure, fwrite returns an error string in |output|.
233  *
234  * @param[in] num_params The number of params in |params|.
235  * @param[in] params An array of strings, parameters to this function.
236  * @param[out] output A string to write informational function output to.
237  * @return An errorcode; 0 means success, anything else is a failure.
238  */
239 int HandleFwrite(int num_params, char** params, char** output) {
240   FILE* file;
241   const char* file_index_string;
242   const char* data;
243   size_t data_len;
244   size_t bytes_written;
245
246   if (num_params != 2) {
247     *output = PrintfToNewString("fwrite takes 2 parameters.");
248     return 1;
249   }
250
251   file_index_string = params[0];
252   file = GetFileFromIndexString(file_index_string, NULL);
253   data = params[1];
254   data_len = strlen(data);
255
256   if (!file) {
257     *output =
258         PrintfToNewString("Unknown file handle %s.", file_index_string);
259     return 2;
260   }
261
262   bytes_written = fwrite(data, 1, data_len, file);
263
264   if (ferror(file)) {
265     *output = PrintfToNewString(
266         "Wrote %d bytes, but ferror() returns true.", bytes_written);
267     return 3;
268   }
269
270   *output =
271       PrintfToNewString("fwrite\1%s\1%d", file_index_string, bytes_written);
272   return 0;
273 }
274
275 /**
276  * Handle a call to fread() made by JavaScript.
277  *
278  * fread expects 2 parameters:
279  *   0: The index of the file (which is mapped to a FILE*)
280  *   1: The number of bytes to read from the file.
281  * on success, fread returns a result in |output| separated by \1:
282  *   0: "fread"
283  *   1: the file index
284  *   2: the data read from the file
285  * on failure, fread returns an error string in |output|.
286  *
287  * @param[in] num_params The number of params in |params|.
288  * @param[in] params An array of strings, parameters to this function.
289  * @param[out] output A string to write informational function output to.
290  * @return An errorcode; 0 means success, anything else is a failure.
291  */
292 int HandleFread(int num_params, char** params, char** output) {
293   FILE* file;
294   const char* file_index_string;
295   char* buffer;
296   size_t data_len;
297   size_t bytes_read;
298
299   if (num_params != 2) {
300     *output = PrintfToNewString("fread takes 2 parameters.");
301     return 1;
302   }
303
304   file_index_string = params[0];
305   file = GetFileFromIndexString(file_index_string, NULL);
306   data_len = strtol(params[1], NULL, 10);
307
308   if (!file) {
309     *output =
310         PrintfToNewString("Unknown file handle %s.", file_index_string);
311     return 2;
312   }
313
314   buffer = (char*)malloc(data_len + 1);
315   bytes_read = fread(buffer, 1, data_len, file);
316   buffer[bytes_read] = 0;
317
318   if (ferror(file)) {
319     *output = PrintfToNewString(
320         "Read %d bytes, but ferror() returns true.", bytes_read);
321     return 3;
322   }
323
324   *output = PrintfToNewString("fread\1%s\1%s", file_index_string, buffer);
325   free(buffer);
326   return 0;
327 }
328
329 /**
330  * Handle a call to fseek() made by JavaScript.
331  *
332  * fseek expects 3 parameters:
333  *   0: The index of the file (which is mapped to a FILE*)
334  *   1: The offset to seek to
335  *   2: An integer representing the whence parameter of standard fseek.
336  *      whence = 0: seek from the beginning of the file
337  *      whence = 1: seek from the current file position
338  *      whence = 2: seek from the end of the file
339  * on success, fseek returns a result in |output| separated by \1:
340  *   0: "fseek"
341  *   1: the file index
342  *   2: The new file position
343  * on failure, fseek returns an error string in |output|.
344  *
345  * @param[in] num_params The number of params in |params|.
346  * @param[in] params An array of strings, parameters to this function.
347  * @param[out] output A string to write informational function output to.
348  * @return An errorcode; 0 means success, anything else is a failure.
349  */
350 int HandleFseek(int num_params, char** params, char** output) {
351   FILE* file;
352   const char* file_index_string;
353   long offset;
354   int whence;
355   int result;
356
357   if (num_params != 3) {
358     *output = PrintfToNewString("fseek takes 3 parameters.");
359     return 1;
360   }
361
362   file_index_string = params[0];
363   file = GetFileFromIndexString(file_index_string, NULL);
364   offset = strtol(params[1], NULL, 10);
365   whence = strtol(params[2], NULL, 10);
366
367   if (!file) {
368     *output =
369         PrintfToNewString("Unknown file handle %s.", file_index_string);
370     return 2;
371   }
372
373   result = fseek(file, offset, whence);
374   if (result) {
375     *output = PrintfToNewString("fseek returned error %d.", result);
376     return 3;
377   }
378
379   offset = ftell(file);
380   if (offset < 0) {
381     *output = PrintfToNewString(
382         "fseek succeeded, but ftell returned error %d.", offset);
383     return 4;
384   }
385
386   *output = PrintfToNewString("fseek\1%s\1%d", file_index_string, offset);
387   return 0;
388 }
389
390 /**
391  * Handle a call to fclose() made by JavaScript.
392  *
393  * fclose expects 1 parameter:
394  *   0: The index of the file (which is mapped to a FILE*)
395  * on success, fclose returns a result in |output| separated by \1:
396  *   0: "fclose"
397  *   1: the file index
398  * on failure, fclose returns an error string in |output|.
399  *
400  * @param[in] num_params The number of params in |params|.
401  * @param[in] params An array of strings, parameters to this function.
402  * @param[out] output A string to write informational function output to.
403  * @return An errorcode; 0 means success, anything else is a failure.
404  */
405 int HandleFclose(int num_params, char** params, char** output) {
406   FILE* file;
407   int file_index;
408   const char* file_index_string;
409   int result;
410
411   if (num_params != 1) {
412     *output = PrintfToNewString("fclose takes 1 parameters.");
413     return 1;
414   }
415
416   file_index_string = params[0];
417   file = GetFileFromIndexString(file_index_string, &file_index);
418   if (!file) {
419     *output =
420         PrintfToNewString("Unknown file handle %s.", file_index_string);
421     return 2;
422   }
423
424   result = fclose(file);
425   if (result) {
426     *output = PrintfToNewString("fclose returned error %d.", result);
427     return 3;
428   }
429
430   RemoveFileFromMap(file_index);
431
432   *output = PrintfToNewString("fclose\1%s", file_index_string);
433   return 0;
434 }
435
436 /**
437  * Handle a call to stat() made by JavaScript.
438  *
439  * stat expects 1 parameter:
440  *   0: The name of the file
441  * on success, stat returns a result in |output| separated by \1:
442  *   0: "stat"
443  *   1: the file name
444  *   2: the size of the file
445  * on failure, stat returns an error string in |output|.
446  *
447  * @param[in] num_params The number of params in |params|.
448  * @param[in] params An array of strings, parameters to this function.
449  * @param[out] output A string to write informational function output to.
450  * @return An errorcode; 0 means success, anything else is a failure.
451  */
452 int HandleStat(int num_params, char** params, char** output) {
453   const char* filename;
454   int result;
455   struct stat buf;
456
457   if (num_params != 1) {
458     *output = PrintfToNewString("stat takes 1 parameter.");
459     return 1;
460   }
461
462   filename = params[0];
463
464   memset(&buf, 0, sizeof(buf));
465   result = stat(filename, &buf);
466   if (result == -1) {
467     *output = PrintfToNewString("stat returned error %d.", errno);
468     return 2;
469   }
470
471   *output = PrintfToNewString("stat\1%s\1%d", filename, buf.st_size);
472   return 0;
473 }
474
475 /**
476  * Handle a call to opendir() made by JavaScript.
477  *
478  * opendir expects 1 parameter:
479  *   0: The name of the directory
480  * on success, opendir returns a result in |output| separated by \1:
481  *   0: "opendir"
482  *   1: the directory name
483  *   2: the index of the directory
484  * on failure, opendir returns an error string in |output|.
485  *
486  * @param[in] num_params The number of params in |params|.
487  * @param[in] params An array of strings, parameters to this function.
488  * @param[out] output A string to write informational function output to.
489  * @return An errorcode; 0 means success, anything else is a failure.
490  */
491 int HandleOpendir(int num_params, char** params, char** output) {
492 #if defined(WIN32)
493   *output = PrintfToNewString("Win32 does not support opendir.");
494   return 1;
495 #else
496   DIR* dir;
497   int dir_index;
498   const char* dirname;
499
500   if (num_params != 1) {
501     *output = PrintfToNewString("opendir takes 1 parameter.");
502     return 1;
503   }
504
505   dirname = params[0];
506
507   dir = opendir(dirname);
508   if (!dir) {
509     *output = PrintfToNewString("opendir returned a NULL DIR*.");
510     return 2;
511   }
512
513   dir_index = AddDirToMap(dir);
514   if (dir_index == -1) {
515     *output = PrintfToNewString(
516         "Example only allows %d open dir handles.", MAX_OPEN_DIRS);
517     return 3;
518   }
519
520   *output = PrintfToNewString("opendir\1%s\1%d", dirname, dir_index);
521   return 0;
522 #endif
523 }
524
525 /**
526  * Handle a call to readdir() made by JavaScript.
527  *
528  * readdir expects 1 parameter:
529  *   0: The index of the directory (which is mapped to a DIR*)
530  * on success, opendir returns a result in |output| separated by \1:
531  *   0: "readdir"
532  *   1: the inode number of the entry
533  *   2: the name of the entry
534  * on failure, readdir returns an error string in |output|.
535  *
536  * @param[in] num_params The number of params in |params|.
537  * @param[in] params An array of strings, parameters to this function.
538  * @param[out] output A string to write informational function output to.
539  * @return An errorcode; 0 means success, anything else is a failure.
540  */
541 int HandleReaddir(int num_params, char** params, char** output) {
542 #if defined(WIN32)
543   *output = PrintfToNewString("Win32 does not support readdir.");
544   return 1;
545 #else
546   DIR* dir;
547   const char* dir_index_string;
548   struct dirent* entry;
549
550   if (num_params != 1) {
551     *output = PrintfToNewString("readdir takes 1 parameter.");
552     return 1;
553   }
554
555   dir_index_string = params[0];
556   dir = GetDirFromIndexString(dir_index_string, NULL);
557
558   if (!dir) {
559     *output = PrintfToNewString("Unknown dir handle %s.", dir_index_string);
560     return 2;
561   }
562
563   entry = readdir(dir);
564   if (entry != NULL) {
565     *output = PrintfToNewString("readdir\1%s\1%d\1%s", dir_index_string,
566                                 entry->d_ino, entry->d_name);
567   } else {
568     *output = PrintfToNewString("readdir\1%s\1\1", dir_index_string);
569   }
570
571   return 0;
572 #endif
573 }
574
575 /**
576  * Handle a call to closedir() made by JavaScript.
577  *
578  * closedir expects 1 parameter:
579  *   0: The index of the directory (which is mapped to a DIR*)
580  * on success, closedir returns a result in |output| separated by \1:
581  *   0: "closedir"
582  *   1: the name of the directory
583  * on failure, closedir returns an error string in |output|.
584  *
585  * @param[in] num_params The number of params in |params|.
586  * @param[in] params An array of strings, parameters to this function.
587  * @param[out] output A string to write informational function output to.
588  * @return An errorcode; 0 means success, anything else is a failure.
589  */
590 int HandleClosedir(int num_params, char** params, char** output) {
591 #if defined(WIN32)
592   *output = PrintfToNewString("Win32 does not support closedir.");
593   return 1;
594 #else
595   DIR* dir;
596   int dir_index;
597   const char* dir_index_string;
598   int result;
599
600   if (num_params != 1) {
601     *output = PrintfToNewString("closedir takes 1 parameters.");
602     return 1;
603   }
604
605   dir_index_string = params[0];
606   dir = GetDirFromIndexString(dir_index_string, &dir_index);
607   if (!dir) {
608     *output = PrintfToNewString("Unknown dir handle %s.",
609                                 dir_index_string);
610     return 2;
611   }
612
613   result = closedir(dir);
614   if (result) {
615     *output = PrintfToNewString("closedir returned error %d.", result);
616     return 3;
617   }
618
619   RemoveDirFromMap(dir_index);
620
621   *output = PrintfToNewString("closedir\1%s", dir_index_string);
622   return 0;
623 #endif
624 }
625
626 /**
627  * Handle a call to mkdir() made by JavaScript.
628  *
629  * mkdir expects 1 parameter:
630  *   0: The name of the directory
631  *   1: The mode to use for the new directory, in octal.
632  * on success, mkdir returns a result in |output| separated by \1:
633  *   0: "mkdir"
634  *   1: the name of the directory
635  * on failure, mkdir returns an error string in |output|.
636  *
637  * @param[in] num_params The number of params in |params|.
638  * @param[in] params An array of strings, parameters to this function.
639  * @param[out] output A string to write informational function output to.
640  * @return An errorcode; 0 means success, anything else is a failure.
641  */
642 int HandleMkdir(int num_params, char** params, char** output) {
643   const char* dirname;
644   int result;
645   int mode;
646
647   if (num_params != 2) {
648     *output = PrintfToNewString("mkdir takes 2 parameters.");
649     return 1;
650   }
651
652   dirname = params[0];
653   mode = strtol(params[1], NULL, 8);
654
655   result = mkdir(dirname, mode);
656   if (result != 0) {
657     *output = PrintfToNewString("mkdir returned error: %d", errno);
658     return 2;
659   }
660
661   *output = PrintfToNewString("mkdir\1%s", dirname);
662   return 0;
663 }
664
665 /**
666  * Handle a call to rmdir() made by JavaScript.
667  *
668  * rmdir expects 1 parameter:
669  *   0: The name of the directory to remove
670  *
671  * @param[in] num_params The number of params in |params|.
672  * @param[in] params An array of strings, parameters to this function.
673  * @param[out] output A string to write informational function output to.
674  * @return An errorcode; 0 means success, anything else is a failure.
675  */
676 int HandleRmdir(int num_params, char** params, char** output) {
677   if (num_params != 1) {
678     *output = PrintfToNewString("rmdir takes 1 parameter.");
679     return 1;
680   }
681
682   const char* dirname = params[0];
683   int result = rmdir(dirname);
684   if (result != 0) {
685     *output = PrintfToNewString("rmdir returned error: %d", errno);
686     return 2;
687   }
688
689   *output = PrintfToNewString("rmdir\1%s", dirname);
690   return 0;
691 }
692
693 /**
694  * Handle a call to chdir() made by JavaScript.
695  *
696  * chdir expects 1 parameter:
697  *   0: The name of the directory
698  *
699  * @param[in] num_params The number of params in |params|.
700  * @param[in] params An array of strings, parameters to this function.
701  * @param[out] output A string to write informational function output to.
702  * @return An errorcode; 0 means success, anything else is a failure.
703  */
704 int HandleChdir(int num_params, char** params, char** output) {
705   if (num_params != 1) {
706     *output = PrintfToNewString("chdir takes 1 parameter.");
707     return 1;
708   }
709
710   const char* dirname = params[0];
711   int result = chdir(dirname);
712   if (result != 0) {
713     *output = PrintfToNewString("chdir returned error: %d", errno);
714     return 2;
715   }
716
717   *output = PrintfToNewString("chdir\1%s", dirname);
718   return 0;
719 }
720
721 /**
722  * Handle a call to getcwd() made by JavaScript.
723  *
724  * getcwd expects 0 parameters.
725  *
726  * @param[in] num_params The number of params in |params|.
727  * @param[in] params An array of strings, parameters to this function.
728  * @param[out] output A string to write informational function output to.
729  * @return An errorcode; 0 means success, anything else is a failure.
730  */
731 int HandleGetcwd(int num_params, char** params, char** output) {
732   if (num_params != 0) {
733     *output = PrintfToNewString("getcwd takes 0 parameters.");
734     return 1;
735   }
736
737   char cwd[PATH_MAX];
738   char* result = getcwd(cwd, PATH_MAX);
739   if (result == NULL) {
740     *output = PrintfToNewString("getcwd returned error: %d", errno);
741     return 1;
742   }
743
744   *output = PrintfToNewString("getcwd\1%s", cwd);
745   return 0;
746 }
747
748 /**
749  * Handle a call to gethostbyname() made by JavaScript.
750  *
751  * gethostbyname expects 1 parameter:
752  *   0: The name of the host to look up.
753  * on success, gethostbyname returns a result in |output| separated by \1:
754  *   0: "gethostbyname"
755  *   1: Host name
756  *   2: Address type (either "AF_INET" or "AF_INET6")
757  *   3. The first address.
758  *   4+ The second, third, etc. addresses.
759  * on failure, gethostbyname returns an error string in |output|.
760  *
761  * @param[in] num_params The number of params in |params|.
762  * @param[in] params An array of strings, parameters to this function.
763  * @param[out] output A string to write informational function output to.
764  * @return An errorcode; 0 means success, anything else is a failure.
765  */
766 int HandleGethostbyname(int num_params, char** params, char** output) {
767   struct hostent* info;
768   struct in_addr **addr_list;
769   const char* addr_type;
770   const char* name;
771   char inet6_addr_str[INET6_ADDRSTRLEN];
772   int non_variable_len, output_len;
773   int current_pos;
774   int i;
775
776   if (num_params != 1) {
777     *output = PrintfToNewString("gethostbyname takes 1 parameter.");
778     return 1;
779   }
780
781   name = params[0];
782
783   info = gethostbyname(name);
784   if (!info) {
785     *output = PrintfToNewString("gethostbyname failed, error is \"%s\"",
786                                 hstrerror(h_errno));
787     return 2;
788   }
789
790   addr_type = info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6";
791
792   non_variable_len = strlen("gethostbyname") + 1
793     + strlen(info->h_name) + 1 + strlen(addr_type);
794   output_len = non_variable_len;
795
796   addr_list = (struct in_addr **)info->h_addr_list;
797   for (i = 0; addr_list[i] != NULL; i++) {
798     output_len += 1; // for the divider
799     if (info->h_addrtype == AF_INET) {
800       output_len += strlen(inet_ntoa(*addr_list[i]));
801     } else { // IPv6
802       inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
803       output_len += strlen(inet6_addr_str);
804     }
805   }
806
807   *output = (char*) calloc(output_len + 1, 1);
808   if (!*output) {
809     *output = PrintfToNewString("out of memory.");
810     return 3;
811   }
812   snprintf(*output, non_variable_len + 1, "gethostbyname\1%s\1%s",
813            info->h_name, addr_type);
814
815   current_pos = non_variable_len;
816   for (i = 0; addr_list[i] != NULL; i++) {
817     if (info->h_addrtype == AF_INET) {
818       current_pos += sprintf(*output + current_pos,
819                              "\1%s", inet_ntoa(*addr_list[i]));
820     } else { // IPv6
821       inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
822       sprintf(*output + current_pos, "\1%s", inet6_addr_str);
823     }
824   }
825   return 0;
826 }
827
828 /**
829  * Handle a call to connect() made by JavaScript.
830  *
831  * This call expects 2 parameters:
832  *   0: The hostname to connect to.
833  *   1: The port number to connect to.
834  *
835  * @param[in] num_params The number of params in |params|.
836  * @param[in] params An array of strings, parameters to this function.
837  * @param[out] output A string to write informational function output to.
838  * @return An errorcode; 0 means success, anything else is a failure.
839  */
840 int HandleConnect(int num_params, char** params, char** output) {
841   if (num_params != 2) {
842     *output = PrintfToNewString("connect takes 2 parameters.");
843     return 1;
844   }
845
846   struct sockaddr_in addr;
847   socklen_t addrlen = sizeof(addr);
848   const char* hostname = params[0];
849   int port = strtol(params[1], NULL, 10);
850
851   // Lookup host
852   struct hostent* hostent = gethostbyname(hostname);
853   if (hostent == NULL) {
854     *output = PrintfToNewString("gethostbyname() returned error: %d", errno);
855     return 1;
856   }
857
858   addr.sin_family = AF_INET;
859   addr.sin_port = htons(port);
860   memcpy(&addr.sin_addr.s_addr, hostent->h_addr_list[0], hostent->h_length);
861
862   int sock = socket(AF_INET, SOCK_STREAM, 0);
863   if (sock < 0) {
864     *output = PrintfToNewString("socket() failed: %s", strerror(errno));
865     return 1;
866   }
867
868   int result = connect(sock, (struct sockaddr*)&addr, addrlen);
869   if (result != 0) {
870     *output = PrintfToNewString("connect() failed: %s", strerror(errno));
871     close(sock);
872     return 1;
873   }
874
875   *output = PrintfToNewString("connect\1%d", sock);
876   return 0;
877 }
878
879 /**
880  * Handle a call to send() made by JavaScript.
881  *
882  * This call expects 2 parameters:
883  *   0: The socket file descriptor to send using.
884  *   1: The NULL terminated string to send.
885  *
886  * @param[in] num_params The number of params in |params|.
887  * @param[in] params An array of strings, parameters to this function.
888  * @param[out] output A string to write informational function output to.
889  * @return An errorcode; 0 means success, anything else is a failure.
890  */
891 int HandleSend(int num_params, char** params, char** output) {
892   if (num_params != 2) {
893     *output = PrintfToNewString("send takes 2 parameters.");
894     return 1;
895   }
896
897   int sock = strtol(params[0], NULL, 10);
898   const char* buffer = params[1];
899   int result = send(sock, buffer, strlen(buffer), 0);
900   if (result <= 0) {
901     *output = PrintfToNewString("send failed: %s", strerror(errno));
902     return 1;
903   }
904
905   *output = PrintfToNewString("send\1%d", result);
906   return 0;
907 }
908
909 /**
910  * Handle a call to recv() made by JavaScript.
911  *
912  * This call expects 2 parameters:
913  *   0: The socket file descriptor to recv from.
914  *   1: The size of the buffer to pass to recv.
915  *
916  * @param[in] num_params The number of params in |params|.
917  * @param[in] params An array of strings, parameters to this function.
918  * @param[out] output A string to write informational function output to.
919  * @return An errorcode; 0 means success, anything else is a failure.
920  */
921 int HandleRecv(int num_params, char** params, char** output) {
922   if (num_params != 2) {
923     *output = PrintfToNewString("recv takes 2 parameters.");
924     return 1;
925   }
926
927   int sock = strtol(params[0], NULL, 10);
928   int buffersize = strtol(params[1], NULL, 10);
929   if (buffersize < 0 || buffersize > 65 * 1024) {
930     *output = PrintfToNewString("recv buffersize must be between 0 and 65k.");
931     return 1;
932   }
933
934   char* buffer = alloca(buffersize);
935   memset(buffer, 0, buffersize);
936   int result = recv(sock, buffer, buffersize, 0);
937   if (result <= 0) {
938     *output = PrintfToNewString("recv failed: %s", strerror(errno));
939     return 2;
940   }
941
942   *output = PrintfToNewString("recv\1%d\1%s", result, buffer);
943   return 0;
944 }
945
946 /**
947  * Handle a call to close() made by JavaScript.
948  *
949  * This call expects 1 parameters:
950  *   0: The socket file descriptor to close.
951  *
952  * @param[in] num_params The number of params in |params|.
953  * @param[in] params An array of strings, parameters to this function.
954  * @param[out] output A string to write informational function output to.
955  * @return An errorcode; 0 means success, anything else is a failure.
956  */
957 int HandleClose(int num_params, char** params, char** output) {
958   if (num_params != 1) {
959     *output = PrintfToNewString("close takes 1 parameters.");
960     return 1;
961   }
962
963   int sock = strtol(params[0], NULL, 10);
964   int result = close(sock);
965   if (result != 0) {
966     *output = PrintfToNewString("close returned error: %d", errno);
967     return 2;
968   }
969
970   *output = PrintfToNewString("close\1%d", sock);
971   return 0;
972 }