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. */
12 #include <netinet/in.h>
18 #include <sys/types.h>
19 #include <sys/socket.h>
22 #include "nacl_io/osdirent.h"
24 #include "nacl_io_demo.h"
26 #define MAX_OPEN_FILES 10
27 #define MAX_OPEN_DIRS 10
34 * A mapping from int -> FILE*, so the JavaScript messages can refer to an open
37 static FILE* g_OpenFiles[MAX_OPEN_FILES];
40 * A mapping from int -> DIR*, so the JavaScript messages can refer to an open
43 static void* g_OpenDirs[MAX_OPEN_DIRS];
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.
52 static int AddToMap(void** map, int max_map_size, void* object) {
54 assert(object != NULL);
55 for (i = 0; i < max_map_size; ++i) {
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.
71 static void RemoveFromMap(void** map, int max_map_size, int i) {
72 assert(i >= 0 && i < max_map_size);
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|.
83 static void* GetFromMap(void** map, int max_map_size, int i) {
84 assert(i >= 0 && i < max_map_size);
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.
96 static void* GetFromIndexString(void** map,
101 int result = strtol(s, &endptr, 10);
102 if (endptr != s + strlen(s)) {
103 /* Garbage at the end of the number...? */
110 return GetFromMap(map, max_map_size, result);
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
119 static int AddFileToMap(FILE* file) {
120 return AddToMap((void**)g_OpenFiles, MAX_OPEN_FILES, file);
124 * Remove the file from the g_OpenFiles map.
125 * @param[in] i The index of the file handle to remove.
127 static void RemoveFileFromMap(int i) {
128 RemoveFromMap((void**)g_OpenFiles, MAX_OPEN_FILES, i);
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.
137 static FILE* GetFileFromIndexString(const char* s, int* file_index) {
138 return (FILE*)GetFromIndexString(
139 (void**)g_OpenFiles, MAX_OPEN_FILES, s, file_index);
142 /* Win32 doesn't support DIR/opendir/readdir/closedir. */
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
150 static int AddDirToMap(DIR* dir) {
151 return AddToMap((void**)g_OpenDirs, MAX_OPEN_DIRS, dir);
155 * Remove the dir from the g_OpenDirs map.
156 * @param[in] i The index of the dir handle to remove.
158 static void RemoveDirFromMap(int i) {
159 RemoveFromMap((void**)g_OpenDirs, MAX_OPEN_DIRS, i);
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.
168 static DIR* GetDirFromIndexString(const char* s, int* dir_index) {
169 return (DIR*)GetFromIndexString(
170 (void**)g_OpenDirs, MAX_OPEN_DIRS, s, dir_index);
175 * Handle a call to fopen() made by JavaScript.
177 * fopen expects 2 parameters:
178 * 0: the path of the file to open
180 * on success, fopen returns a result in |output| separated by \1:
182 * 1: the filename opened
184 * on failure, fopen returns an error string in |output|.
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.
191 int HandleFopen(int num_params, char** params, char** output) {
194 const char* filename;
197 if (num_params != 2) {
198 *output = PrintfToNewString("fopen takes 2 parameters.");
202 filename = params[0];
205 file = fopen(filename, mode);
207 *output = PrintfToNewString("fopen returned a NULL FILE*.");
211 file_index = AddFileToMap(file);
212 if (file_index == -1) {
213 *output = PrintfToNewString(
214 "Example only allows %d open file handles.", MAX_OPEN_FILES);
218 *output = PrintfToNewString("fopen\1%s\1%d", filename, file_index);
223 * Handle a call to fwrite() made by JavaScript.
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:
231 * 2: the number of bytes written
232 * on failure, fwrite returns an error string in |output|.
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.
239 int HandleFwrite(int num_params, char** params, char** output) {
241 const char* file_index_string;
244 size_t bytes_written;
246 if (num_params != 2) {
247 *output = PrintfToNewString("fwrite takes 2 parameters.");
251 file_index_string = params[0];
252 file = GetFileFromIndexString(file_index_string, NULL);
254 data_len = strlen(data);
258 PrintfToNewString("Unknown file handle %s.", file_index_string);
262 bytes_written = fwrite(data, 1, data_len, file);
265 *output = PrintfToNewString(
266 "Wrote %d bytes, but ferror() returns true.", bytes_written);
271 PrintfToNewString("fwrite\1%s\1%d", file_index_string, bytes_written);
276 * Handle a call to fread() made by JavaScript.
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:
284 * 2: the data read from the file
285 * on failure, fread returns an error string in |output|.
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.
292 int HandleFread(int num_params, char** params, char** output) {
294 const char* file_index_string;
299 if (num_params != 2) {
300 *output = PrintfToNewString("fread takes 2 parameters.");
304 file_index_string = params[0];
305 file = GetFileFromIndexString(file_index_string, NULL);
306 data_len = strtol(params[1], NULL, 10);
310 PrintfToNewString("Unknown file handle %s.", file_index_string);
314 buffer = (char*)malloc(data_len + 1);
315 bytes_read = fread(buffer, 1, data_len, file);
316 buffer[bytes_read] = 0;
319 *output = PrintfToNewString(
320 "Read %d bytes, but ferror() returns true.", bytes_read);
324 *output = PrintfToNewString("fread\1%s\1%s", file_index_string, buffer);
330 * Handle a call to fseek() made by JavaScript.
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:
342 * 2: The new file position
343 * on failure, fseek returns an error string in |output|.
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.
350 int HandleFseek(int num_params, char** params, char** output) {
352 const char* file_index_string;
357 if (num_params != 3) {
358 *output = PrintfToNewString("fseek takes 3 parameters.");
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);
369 PrintfToNewString("Unknown file handle %s.", file_index_string);
373 result = fseek(file, offset, whence);
375 *output = PrintfToNewString("fseek returned error %d.", result);
379 offset = ftell(file);
381 *output = PrintfToNewString(
382 "fseek succeeded, but ftell returned error %d.", offset);
386 *output = PrintfToNewString("fseek\1%s\1%d", file_index_string, offset);
391 * Handle a call to fclose() made by JavaScript.
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:
398 * on failure, fclose returns an error string in |output|.
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.
405 int HandleFclose(int num_params, char** params, char** output) {
408 const char* file_index_string;
411 if (num_params != 1) {
412 *output = PrintfToNewString("fclose takes 1 parameters.");
416 file_index_string = params[0];
417 file = GetFileFromIndexString(file_index_string, &file_index);
420 PrintfToNewString("Unknown file handle %s.", file_index_string);
424 result = fclose(file);
426 *output = PrintfToNewString("fclose returned error %d.", result);
430 RemoveFileFromMap(file_index);
432 *output = PrintfToNewString("fclose\1%s", file_index_string);
437 * Handle a call to stat() made by JavaScript.
439 * stat expects 1 parameter:
440 * 0: The name of the file
441 * on success, stat returns a result in |output| separated by \1:
444 * 2: the size of the file
445 * on failure, stat returns an error string in |output|.
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.
452 int HandleStat(int num_params, char** params, char** output) {
453 const char* filename;
457 if (num_params != 1) {
458 *output = PrintfToNewString("stat takes 1 parameter.");
462 filename = params[0];
464 memset(&buf, 0, sizeof(buf));
465 result = stat(filename, &buf);
467 *output = PrintfToNewString("stat returned error %d.", errno);
471 *output = PrintfToNewString("stat\1%s\1%d", filename, buf.st_size);
476 * Handle a call to opendir() made by JavaScript.
478 * opendir expects 1 parameter:
479 * 0: The name of the directory
480 * on success, opendir returns a result in |output| separated by \1:
482 * 1: the directory name
483 * 2: the index of the directory
484 * on failure, opendir returns an error string in |output|.
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.
491 int HandleOpendir(int num_params, char** params, char** output) {
493 *output = PrintfToNewString("Win32 does not support opendir.");
500 if (num_params != 1) {
501 *output = PrintfToNewString("opendir takes 1 parameter.");
507 dir = opendir(dirname);
509 *output = PrintfToNewString("opendir returned a NULL DIR*.");
513 dir_index = AddDirToMap(dir);
514 if (dir_index == -1) {
515 *output = PrintfToNewString(
516 "Example only allows %d open dir handles.", MAX_OPEN_DIRS);
520 *output = PrintfToNewString("opendir\1%s\1%d", dirname, dir_index);
526 * Handle a call to readdir() made by JavaScript.
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:
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|.
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.
541 int HandleReaddir(int num_params, char** params, char** output) {
543 *output = PrintfToNewString("Win32 does not support readdir.");
547 const char* dir_index_string;
548 struct dirent* entry;
550 if (num_params != 1) {
551 *output = PrintfToNewString("readdir takes 1 parameter.");
555 dir_index_string = params[0];
556 dir = GetDirFromIndexString(dir_index_string, NULL);
559 *output = PrintfToNewString("Unknown dir handle %s.", dir_index_string);
563 entry = readdir(dir);
565 *output = PrintfToNewString("readdir\1%s\1%d\1%s", dir_index_string,
566 entry->d_ino, entry->d_name);
568 *output = PrintfToNewString("readdir\1%s\1\1", dir_index_string);
576 * Handle a call to closedir() made by JavaScript.
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:
582 * 1: the name of the directory
583 * on failure, closedir returns an error string in |output|.
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.
590 int HandleClosedir(int num_params, char** params, char** output) {
592 *output = PrintfToNewString("Win32 does not support closedir.");
597 const char* dir_index_string;
600 if (num_params != 1) {
601 *output = PrintfToNewString("closedir takes 1 parameters.");
605 dir_index_string = params[0];
606 dir = GetDirFromIndexString(dir_index_string, &dir_index);
608 *output = PrintfToNewString("Unknown dir handle %s.",
613 result = closedir(dir);
615 *output = PrintfToNewString("closedir returned error %d.", result);
619 RemoveDirFromMap(dir_index);
621 *output = PrintfToNewString("closedir\1%s", dir_index_string);
627 * Handle a call to mkdir() made by JavaScript.
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:
634 * 1: the name of the directory
635 * on failure, mkdir returns an error string in |output|.
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.
642 int HandleMkdir(int num_params, char** params, char** output) {
647 if (num_params != 2) {
648 *output = PrintfToNewString("mkdir takes 2 parameters.");
653 mode = strtol(params[1], NULL, 8);
655 result = mkdir(dirname, mode);
657 *output = PrintfToNewString("mkdir returned error: %d", errno);
661 *output = PrintfToNewString("mkdir\1%s", dirname);
666 * Handle a call to rmdir() made by JavaScript.
668 * rmdir expects 1 parameter:
669 * 0: The name of the directory to remove
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.
676 int HandleRmdir(int num_params, char** params, char** output) {
677 if (num_params != 1) {
678 *output = PrintfToNewString("rmdir takes 1 parameter.");
682 const char* dirname = params[0];
683 int result = rmdir(dirname);
685 *output = PrintfToNewString("rmdir returned error: %d", errno);
689 *output = PrintfToNewString("rmdir\1%s", dirname);
694 * Handle a call to chdir() made by JavaScript.
696 * chdir expects 1 parameter:
697 * 0: The name of the directory
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.
704 int HandleChdir(int num_params, char** params, char** output) {
705 if (num_params != 1) {
706 *output = PrintfToNewString("chdir takes 1 parameter.");
710 const char* dirname = params[0];
711 int result = chdir(dirname);
713 *output = PrintfToNewString("chdir returned error: %d", errno);
717 *output = PrintfToNewString("chdir\1%s", dirname);
722 * Handle a call to getcwd() made by JavaScript.
724 * getcwd expects 0 parameters.
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.
731 int HandleGetcwd(int num_params, char** params, char** output) {
732 if (num_params != 0) {
733 *output = PrintfToNewString("getcwd takes 0 parameters.");
738 char* result = getcwd(cwd, PATH_MAX);
739 if (result == NULL) {
740 *output = PrintfToNewString("getcwd returned error: %d", errno);
744 *output = PrintfToNewString("getcwd\1%s", cwd);
749 * Handle a call to gethostbyname() made by JavaScript.
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:
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|.
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.
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;
771 char inet6_addr_str[INET6_ADDRSTRLEN];
772 int non_variable_len, output_len;
776 if (num_params != 1) {
777 *output = PrintfToNewString("gethostbyname takes 1 parameter.");
783 info = gethostbyname(name);
785 *output = PrintfToNewString("gethostbyname failed, error is \"%s\"",
790 addr_type = info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6";
792 non_variable_len = strlen("gethostbyname") + 1
793 + strlen(info->h_name) + 1 + strlen(addr_type);
794 output_len = non_variable_len;
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]));
802 inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
803 output_len += strlen(inet6_addr_str);
807 *output = (char*) calloc(output_len + 1, 1);
809 *output = PrintfToNewString("out of memory.");
812 snprintf(*output, non_variable_len + 1, "gethostbyname\1%s\1%s",
813 info->h_name, addr_type);
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]));
821 inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
822 sprintf(*output + current_pos, "\1%s", inet6_addr_str);
829 * Handle a call to connect() made by JavaScript.
831 * This call expects 2 parameters:
832 * 0: The hostname to connect to.
833 * 1: The port number to connect to.
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.
840 int HandleConnect(int num_params, char** params, char** output) {
841 if (num_params != 2) {
842 *output = PrintfToNewString("connect takes 2 parameters.");
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);
852 struct hostent* hostent = gethostbyname(hostname);
853 if (hostent == NULL) {
854 *output = PrintfToNewString("gethostbyname() returned error: %d", errno);
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);
862 int sock = socket(AF_INET, SOCK_STREAM, 0);
864 *output = PrintfToNewString("socket() failed: %s", strerror(errno));
868 int result = connect(sock, (struct sockaddr*)&addr, addrlen);
870 *output = PrintfToNewString("connect() failed: %s", strerror(errno));
875 *output = PrintfToNewString("connect\1%d", sock);
880 * Handle a call to send() made by JavaScript.
882 * This call expects 2 parameters:
883 * 0: The socket file descriptor to send using.
884 * 1: The NULL terminated string to send.
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.
891 int HandleSend(int num_params, char** params, char** output) {
892 if (num_params != 2) {
893 *output = PrintfToNewString("send takes 2 parameters.");
897 int sock = strtol(params[0], NULL, 10);
898 const char* buffer = params[1];
899 int result = send(sock, buffer, strlen(buffer), 0);
901 *output = PrintfToNewString("send failed: %s", strerror(errno));
905 *output = PrintfToNewString("send\1%d", result);
910 * Handle a call to recv() made by JavaScript.
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.
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.
921 int HandleRecv(int num_params, char** params, char** output) {
922 if (num_params != 2) {
923 *output = PrintfToNewString("recv takes 2 parameters.");
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.");
934 char* buffer = alloca(buffersize);
935 memset(buffer, 0, buffersize);
936 int result = recv(sock, buffer, buffersize, 0);
938 *output = PrintfToNewString("recv failed: %s", strerror(errno));
942 *output = PrintfToNewString("recv\1%d\1%s", result, buffer);
947 * Handle a call to close() made by JavaScript.
949 * This call expects 1 parameters:
950 * 0: The socket file descriptor to close.
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.
957 int HandleClose(int num_params, char** params, char** output) {
958 if (num_params != 1) {
959 *output = PrintfToNewString("close takes 1 parameters.");
963 int sock = strtol(params[0], NULL, 10);
964 int result = close(sock);
966 *output = PrintfToNewString("close returned error: %d", errno);
970 *output = PrintfToNewString("close\1%d", sock);