blob: 2ec655929ece1990aba4f7f092a2945901188a2b [file] [log] [blame]
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01001/* 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
6#include "handlers.h"
7
Ben Murdochbb1529c2013-08-08 10:24:53 +01008#include <arpa/inet.h>
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +01009#include <assert.h>
10#include <errno.h>
Ben Murdochbb1529c2013-08-08 10:24:53 +010011#include <netdb.h>
12#include <netinet/in.h>
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010013#include <stdio.h>
14#include <stdlib.h>
15#include <string.h>
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010016
17#include <sys/types.h>
Ben Murdochbb1529c2013-08-08 10:24:53 +010018#include <sys/socket.h>
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010019#include <sys/stat.h>
20
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010021#include "nacl_io/osdirent.h"
22
Torne (Richard Coles)b2df76e2013-05-13 16:52:09 +010023#include "nacl_io_demo.h"
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010024
25#define MAX_OPEN_FILES 10
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010026#define MAX_OPEN_DIRS 10
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010027
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +010028#if defined(WIN32)
29#define stat _stat
30#endif
31
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010032/**
33 * A mapping from int -> FILE*, so the JavaScript messages can refer to an open
34 * File. */
35static FILE* g_OpenFiles[MAX_OPEN_FILES];
36
37/**
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010038 * A mapping from int -> DIR*, so the JavaScript messages can refer to an open
39 * Directory. */
40static void* g_OpenDirs[MAX_OPEN_DIRS];
41
42/**
43 * Add |object| to |map| and return the index it was added at.
44 * @param[in] map The map to add the object to.
45 * @param[in] max_map_size The maximum map size.
46 * @param[in] object The object to add to the map.
47 * @return int The index of the added object, or -1 if there is no more space.
48 */
49static int AddToMap(void** map, int max_map_size, void* object) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010050 int i;
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010051 assert(object != NULL);
52 for (i = 0; i < max_map_size; ++i) {
53 if (map[i] == NULL) {
54 map[i] = object;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +010055 return i;
56 }
57 }
58
59 return -1;
60}
61
62/**
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010063 * Remove an object at index |i| from |map|.
64 * @param[in] map The map to remove from.
65 * @param[in] max_map_size The size of the map.
66 * @param[in] i The index to remove.
67 */
68static void RemoveFromMap(void** map, int max_map_size, int i) {
69 assert(i >= 0 && i < max_map_size);
70 map[i] = NULL;
71}
72
73/**
74 * Get the object from |map| at index |i|.
75 * @param[in] map The map to access.
76 * @param[in] max_map_size The size of the map.
77 * @param[in] i The index to access.
78 * @return the object at |map|. This will be NULL if there is no object at |i|.
79 */
80static void* GetFromMap(void** map, int max_map_size, int i) {
81 assert(i >= 0 && i < max_map_size);
82 return map[i];
83}
84
85/**
86 * Get an object given a string |s| containing the index.
87 * @param[in] map The map to access.
88 * @param[in] max_map_size The size of the map.
89 * @param[in] s The string containing the object index.
90 * @param[out] index The index of the object as an int.
91 * @return The object, or NULL if the index is invalid.
92 */
93static void* GetFromIndexString(void** map,
94 int max_map_size,
95 const char* s,
96 int* index) {
97 char* endptr;
98 int result = strtol(s, &endptr, 10);
99 if (endptr != s + strlen(s)) {
100 /* Garbage at the end of the number...? */
101 return NULL;
102 }
103
104 if (index)
105 *index = result;
106
107 return GetFromMap(map, max_map_size, result);
108}
109
110/**
111 * Add the file to the g_OpenFiles map.
112 * @param[in] file The file to add to g_OpenFiles.
113 * @return int The index of the FILE in g_OpenFiles, or -1 if there are too many
114 * open files. */
115static int AddFileToMap(FILE* file) {
116 return AddToMap((void**)g_OpenFiles, MAX_OPEN_FILES, file);
117}
118
119/**
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100120 * Remove the file from the g_OpenFiles map.
121 * @param[in] i The index of the file handle to remove. */
122static void RemoveFileFromMap(int i) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100123 RemoveFromMap((void**)g_OpenFiles, MAX_OPEN_FILES, i);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100124}
125
126/**
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100127 * Get a file, given a string containing the index.
128 * @param[in] s The string containing the file index.
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100129 * @param[out] file_index The index of this file.
130 * @return The FILE* for this file, or NULL if the index is invalid.
131 */
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100132static FILE* GetFileFromIndexString(const char* s, int* file_index) {
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100133 return (FILE*)GetFromIndexString(
134 (void**)g_OpenFiles, MAX_OPEN_FILES, s, file_index);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100135}
136
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100137/* Win32 doesn't support DIR/opendir/readdir/closedir. */
138#if !defined(WIN32)
139/**
140 * Add the dir to the g_OpenDirs map.
141 * @param[in] dir The dir to add to g_OpenDirs.
142 * @return int The index of the DIR in g_OpenDirs, or -1 if there are too many
143 * open dirs. */
144static int AddDirToMap(DIR* dir) {
145 return AddToMap((void**)g_OpenDirs, MAX_OPEN_DIRS, dir);
146}
147
148/**
149 * Remove the dir from the g_OpenDirs map.
150 * @param[in] i The index of the dir handle to remove. */
151static void RemoveDirFromMap(int i) {
152 RemoveFromMap((void**)g_OpenDirs, MAX_OPEN_DIRS, i);
153}
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100154
155/**
156 * Get a dir, given a string containing the index.
157 * @param[in] s The string containing the dir index.
158 * @param[out] dir_index The index of this dir.
159 * @return The DIR* for this dir, or NULL if the index is invalid.
160 */
161static DIR* GetDirFromIndexString(const char* s, int* dir_index) {
162 return (DIR*)GetFromIndexString(
163 (void**)g_OpenDirs, MAX_OPEN_DIRS, s, dir_index);
164}
165#endif
166
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100167/**
168 * Handle a call to fopen() made by JavaScript.
169 *
170 * fopen expects 2 parameters:
171 * 0: the path of the file to open
172 * 1: the mode string
173 * on success, fopen returns a result in |output| separated by \1:
174 * 0: "fopen"
175 * 1: the filename opened
176 * 2: the file index
177 * on failure, fopen returns an error string in |output|.
178 *
179 * @param[in] num_params The number of params in |params|.
180 * @param[in] params An array of strings, parameters to this function.
181 * @param[out] output A string to write informational function output to.
182 * @return An errorcode; 0 means success, anything else is a failure. */
183int HandleFopen(int num_params, char** params, char** output) {
184 FILE* file;
185 int file_index;
186 const char* filename;
187 const char* mode;
188
189 if (num_params != 2) {
190 *output = PrintfToNewString("Error: fopen takes 2 parameters.");
191 return 1;
192 }
193
194 filename = params[0];
195 mode = params[1];
196
197 file = fopen(filename, mode);
198 if (!file) {
199 *output = PrintfToNewString("Error: fopen returned a NULL FILE*.");
200 return 2;
201 }
202
203 file_index = AddFileToMap(file);
204 if (file_index == -1) {
205 *output = PrintfToNewString(
206 "Error: Example only allows %d open file handles.", MAX_OPEN_FILES);
207 return 3;
208 }
209
210 *output = PrintfToNewString("fopen\1%s\1%d", filename, file_index);
211 return 0;
212}
213
214/**
215 * Handle a call to fwrite() made by JavaScript.
216 *
217 * fwrite expects 2 parameters:
218 * 0: The index of the file (which is mapped to a FILE*)
219 * 1: A string to write to the file
220 * on success, fwrite returns a result in |output| separated by \1:
221 * 0: "fwrite"
222 * 1: the file index
223 * 2: the number of bytes written
224 * on failure, fwrite returns an error string in |output|.
225 *
226 * @param[in] num_params The number of params in |params|.
227 * @param[in] params An array of strings, parameters to this function.
228 * @param[out] output A string to write informational function output to.
229 * @return An errorcode; 0 means success, anything else is a failure. */
230int HandleFwrite(int num_params, char** params, char** output) {
231 FILE* file;
232 const char* file_index_string;
233 const char* data;
234 size_t data_len;
235 size_t bytes_written;
236
237 if (num_params != 2) {
238 *output = PrintfToNewString("Error: fwrite takes 2 parameters.");
239 return 1;
240 }
241
242 file_index_string = params[0];
243 file = GetFileFromIndexString(file_index_string, NULL);
244 data = params[1];
245 data_len = strlen(data);
246
247 if (!file) {
248 *output =
249 PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
250 return 2;
251 }
252
253 bytes_written = fwrite(data, 1, data_len, file);
254
255 if (ferror(file)) {
256 *output = PrintfToNewString(
257 "Error: Wrote %d bytes, but ferror() returns true.", bytes_written);
258 return 3;
259 }
260
261 *output =
262 PrintfToNewString("fwrite\1%s\1%d", file_index_string, bytes_written);
263 return 0;
264}
265
266/**
267 * Handle a call to fread() made by JavaScript.
268 *
269 * fread expects 2 parameters:
270 * 0: The index of the file (which is mapped to a FILE*)
271 * 1: The number of bytes to read from the file.
272 * on success, fread returns a result in |output| separated by \1:
273 * 0: "fread"
274 * 1: the file index
275 * 2: the data read from the file
276 * on failure, fread returns an error string in |output|.
277 *
278 * @param[in] num_params The number of params in |params|.
279 * @param[in] params An array of strings, parameters to this function.
280 * @param[out] output A string to write informational function output to.
281 * @return An errorcode; 0 means success, anything else is a failure. */
282int HandleFread(int num_params, char** params, char** output) {
283 FILE* file;
284 const char* file_index_string;
285 char* buffer;
286 size_t data_len;
287 size_t bytes_read;
288
289 if (num_params != 2) {
290 *output = PrintfToNewString("Error: fread takes 2 parameters.");
291 return 1;
292 }
293
294 file_index_string = params[0];
295 file = GetFileFromIndexString(file_index_string, NULL);
296 data_len = strtol(params[1], NULL, 10);
297
298 if (!file) {
299 *output =
300 PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
301 return 2;
302 }
303
304 buffer = (char*)malloc(data_len + 1);
305 bytes_read = fread(buffer, 1, data_len, file);
306 buffer[bytes_read] = 0;
307
308 if (ferror(file)) {
309 *output = PrintfToNewString(
310 "Error: Read %d bytes, but ferror() returns true.", bytes_read);
311 return 3;
312 }
313
314 *output = PrintfToNewString("fread\1%s\1%s", file_index_string, buffer);
315 free(buffer);
316 return 0;
317}
318
319/**
320 * Handle a call to fseek() made by JavaScript.
321 *
322 * fseek expects 3 parameters:
323 * 0: The index of the file (which is mapped to a FILE*)
324 * 1: The offset to seek to
325 * 2: An integer representing the whence parameter of standard fseek.
326 * whence = 0: seek from the beginning of the file
327 * whence = 1: seek from the current file position
328 * whence = 2: seek from the end of the file
329 * on success, fseek returns a result in |output| separated by \1:
330 * 0: "fseek"
331 * 1: the file index
332 * 2: The new file position
333 * on failure, fseek returns an error string in |output|.
334 *
335 * @param[in] num_params The number of params in |params|.
336 * @param[in] params An array of strings, parameters to this function.
337 * @param[out] output A string to write informational function output to.
338 * @return An errorcode; 0 means success, anything else is a failure. */
339int HandleFseek(int num_params, char** params, char** output) {
340 FILE* file;
341 const char* file_index_string;
342 long offset;
343 int whence;
344 int result;
345
346 if (num_params != 3) {
347 *output = PrintfToNewString("Error: fseek takes 3 parameters.");
348 return 1;
349 }
350
351 file_index_string = params[0];
352 file = GetFileFromIndexString(file_index_string, NULL);
353 offset = strtol(params[1], NULL, 10);
354 whence = strtol(params[2], NULL, 10);
355
356 if (!file) {
357 *output =
358 PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
359 return 2;
360 }
361
362 result = fseek(file, offset, whence);
363 if (result) {
364 *output = PrintfToNewString("Error: fseek returned error %d.", result);
365 return 3;
366 }
367
368 offset = ftell(file);
369 if (offset < 0) {
370 *output = PrintfToNewString(
371 "Error: fseek succeeded, but ftell returned error %d.", offset);
372 return 4;
373 }
374
375 *output = PrintfToNewString("fseek\1%s\1%d", file_index_string, offset);
376 return 0;
377}
378
379/**
380 * Handle a call to fclose() made by JavaScript.
381 *
382 * fclose expects 1 parameter:
383 * 0: The index of the file (which is mapped to a FILE*)
384 * on success, fclose returns a result in |output| separated by \1:
385 * 0: "fclose"
386 * 1: the file index
387 * on failure, fclose returns an error string in |output|.
388 *
389 * @param[in] num_params The number of params in |params|.
390 * @param[in] params An array of strings, parameters to this function.
391 * @param[out] output A string to write informational function output to.
392 * @return An errorcode; 0 means success, anything else is a failure. */
393int HandleFclose(int num_params, char** params, char** output) {
394 FILE* file;
395 int file_index;
396 const char* file_index_string;
397 int result;
398
399 if (num_params != 1) {
400 *output = PrintfToNewString("Error: fclose takes 1 parameters.");
401 return 1;
402 }
403
404 file_index_string = params[0];
405 file = GetFileFromIndexString(file_index_string, &file_index);
406 if (!file) {
407 *output =
408 PrintfToNewString("Error: Unknown file handle %s.", file_index_string);
409 return 2;
410 }
411
412 result = fclose(file);
413 if (result) {
414 *output = PrintfToNewString("Error: fclose returned error %d.", result);
415 return 3;
416 }
417
418 RemoveFileFromMap(file_index);
419
420 *output = PrintfToNewString("fclose\1%s", file_index_string);
421 return 0;
422}
423
424/**
425 * Handle a call to stat() made by JavaScript.
426 *
427 * stat expects 1 parameter:
428 * 0: The name of the file
429 * on success, stat returns a result in |output| separated by \1:
430 * 0: "stat"
431 * 1: the file name
432 * 2: the size of the file
433 * on failure, stat returns an error string in |output|.
434 *
435 * @param[in] num_params The number of params in |params|.
436 * @param[in] params An array of strings, parameters to this function.
437 * @param[out] output A string to write informational function output to.
438 * @return An errorcode; 0 means success, anything else is a failure. */
439int HandleStat(int num_params, char** params, char** output) {
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100440 const char* filename;
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100441 int result;
442 struct stat buf;
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100443
444 if (num_params != 1) {
445 *output = PrintfToNewString("Error: stat takes 1 parameter.");
446 return 1;
447 }
448
449 filename = params[0];
450
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100451 memset(&buf, 0, sizeof(buf));
Torne (Richard Coles)a93a17c2013-05-15 11:34:50 +0100452 result = stat(filename, &buf);
Torne (Richard Coles)c2e0dbd2013-05-09 18:35:53 +0100453 if (result == -1) {
454 *output = PrintfToNewString("Error: stat returned error %d.", errno);
455 return 2;
456 }
457
458 *output = PrintfToNewString("stat\1%s\1%d", filename, buf.st_size);
459 return 0;
460}
Ben Murdoch7dbb3d52013-07-17 14:55:54 +0100461
462/**
463 * Handle a call to opendir() made by JavaScript.
464 *
465 * opendir expects 1 parameter:
466 * 0: The name of the directory
467 * on success, opendir returns a result in |output| separated by \1:
468 * 0: "opendir"
469 * 1: the directory name
470 * 2: the index of the directory
471 * on failure, opendir returns an error string in |output|.
472 *
473 * @param[in] num_params The number of params in |params|.
474 * @param[in] params An array of strings, parameters to this function.
475 * @param[out] output A string to write informational function output to.
476 * @return An errorcode; 0 means success, anything else is a failure. */
477int HandleOpendir(int num_params, char** params, char** output) {
478#if defined(WIN32)
479 *output = PrintfToNewString("Error: Win32 does not support opendir.");
480 return 1;
481#else
482 DIR* dir;
483 int dir_index;
484 const char* dirname;
485
486 if (num_params != 1) {
487 *output = PrintfToNewString("Error: opendir takes 1 parameter.");
488 return 1;
489 }
490
491 dirname = params[0];
492
493 dir = opendir(dirname);
494 if (!dir) {
495 *output = PrintfToNewString("Error: opendir returned a NULL DIR*.");
496 return 2;
497 }
498
499 dir_index = AddDirToMap(dir);
500 if (dir_index == -1) {
501 *output = PrintfToNewString(
502 "Error: Example only allows %d open dir handles.", MAX_OPEN_DIRS);
503 return 3;
504 }
505
506 *output = PrintfToNewString("opendir\1%s\1%d", dirname, dir_index);
507 return 0;
508#endif
509}
510
511/**
512 * Handle a call to readdir() made by JavaScript.
513 *
514 * readdir expects 1 parameter:
515 * 0: The index of the directory (which is mapped to a DIR*)
516 * on success, opendir returns a result in |output| separated by \1:
517 * 0: "readdir"
518 * 1: the inode number of the entry
519 * 2: the name of the entry
520 * on failure, readdir returns an error string in |output|.
521 *
522 * @param[in] num_params The number of params in |params|.
523 * @param[in] params An array of strings, parameters to this function.
524 * @param[out] output A string to write informational function output to.
525 * @return An errorcode; 0 means success, anything else is a failure. */
526int HandleReaddir(int num_params, char** params, char** output) {
527#if defined(WIN32)
528 *output = PrintfToNewString("Error: Win32 does not support readdir.");
529 return 1;
530#else
531 DIR* dir;
532 const char* dir_index_string;
533 struct dirent* entry;
534
535 if (num_params != 1) {
536 *output = PrintfToNewString("Error: readdir takes 1 parameter.");
537 return 1;
538 }
539
540 dir_index_string = params[0];
541 dir = GetDirFromIndexString(dir_index_string, NULL);
542
543 if (!dir) {
544 *output = PrintfToNewString("Error: Unknown dir handle %s.",
545 dir_index_string);
546 return 2;
547 }
548
549 entry = readdir(dir);
550 if (entry != NULL) {
551 *output = PrintfToNewString("readdir\1%s\1%d\1%s", dir_index_string,
552 entry->d_ino, entry->d_name);
553 } else {
554 *output = PrintfToNewString("readdir\1%s\1\1", dir_index_string);
555 }
556
557 return 0;
558#endif
559}
560
561/**
562 * Handle a call to closedir() made by JavaScript.
563 *
564 * closedir expects 1 parameter:
565 * 0: The index of the directory (which is mapped to a DIR*)
566 * on success, closedir returns a result in |output| separated by \1:
567 * 0: "closedir"
568 * 1: the name of the directory
569 * on failure, closedir returns an error string in |output|.
570 *
571 * @param[in] num_params The number of params in |params|.
572 * @param[in] params An array of strings, parameters to this function.
573 * @param[out] output A string to write informational function output to.
574 * @return An errorcode; 0 means success, anything else is a failure. */
575int HandleClosedir(int num_params, char** params, char** output) {
576#if defined(WIN32)
577 *output = PrintfToNewString("Error: Win32 does not support closedir.");
578 return 1;
579#else
580 DIR* dir;
581 int dir_index;
582 const char* dir_index_string;
583 int result;
584
585 if (num_params != 1) {
586 *output = PrintfToNewString("Error: closedir takes 1 parameters.");
587 return 1;
588 }
589
590 dir_index_string = params[0];
591 dir = GetDirFromIndexString(dir_index_string, &dir_index);
592 if (!dir) {
593 *output = PrintfToNewString("Error: Unknown dir handle %s.",
594 dir_index_string);
595 return 2;
596 }
597
598 result = closedir(dir);
599 if (result) {
600 *output = PrintfToNewString("Error: closedir returned error %d.", result);
601 return 3;
602 }
603
604 RemoveDirFromMap(dir_index);
605
606 *output = PrintfToNewString("closedir\1%s", dir_index_string);
607 return 0;
608#endif
609}
610
611/**
612 * Handle a call to mkdir() made by JavaScript.
613 *
614 * mkdir expects 1 parameter:
615 * 0: The name of the directory
616 * 1: The mode to use for the new directory, in octal.
617 * on success, mkdir returns a result in |output| separated by \1:
618 * 0: "mkdir"
619 * 1: the name of the directory
620 * on failure, mkdir returns an error string in |output|.
621 *
622 * @param[in] num_params The number of params in |params|.
623 * @param[in] params An array of strings, parameters to this function.
624 * @param[out] output A string to write informational function output to.
625 * @return An errorcode; 0 means success, anything else is a failure. */
626int HandleMkdir(int num_params, char** params, char** output) {
627 const char* dirname;
628 int result;
629 int mode;
630
631 if (num_params != 2) {
632 *output = PrintfToNewString("Error: mkdir takes 2 parameters.");
633 return 1;
634 }
635
636 dirname = params[0];
637 mode = strtol(params[1], NULL, 8);
638
639 result = mkdir(dirname, mode);
640 if (result != 0) {
641 *output = PrintfToNewString("Error: mkdir returned error: %d", errno);
642 return 2;
643 }
644
645 *output = PrintfToNewString("mkdir\1%s", dirname);
646 return 0;
647}
Ben Murdochbb1529c2013-08-08 10:24:53 +0100648
649/**
650 * Handle a call to gethostbyname() made by JavaScript.
651 *
652 * gethostbyname expects 1 parameter:
653 * 0: The name of the host to look up.
654 * on success, gethostbyname returns a result in |output| separated by \1:
655 * 0: "gethostbyname"
656 * 1: Host name
657 * 2: Address type (either "AF_INET" or "AF_INET6")
658 * 3. The first address.
659 * 4+ The second, third, etc. addresses.
660 * on failure, gethostbyname returns an error string in |output|.
661 *
662 * @param[in] num_params The number of params in |params|.
663 * @param[in] params An array of strings, parameters to this function.
664 * @param[out] output A string to write informational function output to.
665 * @return An errorcode; 0 means success, anything else is a failure. */
666int HandleGethostbyname(int num_params, char** params, char** output) {
667 struct hostent* info;
668 struct in_addr **addr_list;
669 const char* addr_type;
670 const char* name;
671 char inet6_addr_str[INET6_ADDRSTRLEN];
672 int non_variable_len, output_len;
673 int current_pos;
674 int i;
675
676 if (num_params != 1) {
677 *output = PrintfToNewString("Error: gethostbyname takes 1 parameter.");
678 return 1;
679 }
680
681 name = params[0];
682
683 info = gethostbyname(name);
684 if (!info) {
685 *output = PrintfToNewString("Error: gethostbyname failed, error is \"%s\"",
686 hstrerror(h_errno));
687 return 2;
688 }
689
690 addr_type = info->h_addrtype == AF_INET ? "AF_INET" : "AF_INET6";
691
692 non_variable_len = strlen("gethostbyname") + 1
693 + strlen(info->h_name) + 1 + strlen(addr_type);
694 output_len = non_variable_len;
695
696 addr_list = (struct in_addr **)info->h_addr_list;
697 for (i = 0; addr_list[i] != NULL; i++) {
698 output_len += 1; // for the divider
699 if (info->h_addrtype == AF_INET) {
700 output_len += strlen(inet_ntoa(*addr_list[i]));
701 } else { // IPv6
702 inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
703 output_len += strlen(inet6_addr_str);
704 }
705 }
706
707 *output = (char*) calloc(output_len + 1, 1);
708 if (!*output) {
709 *output = PrintfToNewString("Error: out of memory.");
710 return 3;
711 }
712 snprintf(*output, non_variable_len + 1, "gethostbyname\1%s\1%s",
713 info->h_name, addr_type);
714
715 current_pos = non_variable_len;
716 for (i = 0; addr_list[i] != NULL; i++) {
717 if (info->h_addrtype == AF_INET) {
718 current_pos += sprintf(*output + current_pos,
719 "\1%s", inet_ntoa(*addr_list[i]));
720 } else { // IPv6
721 inet_ntop(AF_INET6, addr_list[i], inet6_addr_str, INET6_ADDRSTRLEN);
722 sprintf(*output + current_pos, "\1%s", inet6_addr_str);
723 }
724 }
725 return 0;
726}