diff options
author | Ludovic Courtès <ludo@gnu.org> | 2010-02-14 20:56:31 +0100 |
---|---|---|
committer | Ludovic Courtès <ludo@gnu.org> | 2010-02-14 20:56:47 +0100 |
commit | 55ae00ea73e5698d64c31118717c15e6dd9cafe7 (patch) | |
tree | 514b45f0da93acaeb3c66b5e75328c479fb6bbc6 | |
parent | 61cd9dc907b8a09990b14e9aeac7e20fe77cecc6 (diff) |
Add `getaddrinfo' and related procedures.
* libguile/net_db.c (sym_getaddrinfo_error, sym_ai_passive,
sym_ai_canonname, sym_ai_numerichost, sym_ai_numericserv,
sym_ai_v4mapped, sym_ai_all, sym_ai_addrconfig, sym_eai_badflags,
sym_eai_noname, sym_eai_again, sym_eai_fail, sym_eai_family,
sym_eai_socktype, sym_eai_service, sym_eai_memory, sym_eai_system,
sym_eai_overflow, sym_eai_nodata, sym_eai_addrfamily,
sym_eai_inprogress, sym_eai_canceled, sym_eai_notcanceled,
sym_eai_alldone, sym_eai_intr, sym_eai_idn_encode): New variables.
(scm_from_addrinfo, scm_getaddrinfo, scm_gai_strerror): New functions.
* libguile/net_db.h (scm_getaddrinfo, scm_gai_strerror): New functions.
* module/ice-9/networking.scm (addrinfo:flags, addrinfo:fam,
addrinfo:socktype, addrinfo:protocol, addrinfo:addr,
addrinfo:canonname): New procedures.
* test-suite/tests/net-db.test: New file.
* test-suite/Makefile.am (SCM_TESTS): Add `tests/net-db.test'.
* doc/ref/posix.texi (Network Databases)[getaddrinfo]: New subsection.
[The Host Database]: Suggest using `getaddrinfo'.
-rw-r--r-- | doc/ref/posix.texi | 164 | ||||
-rw-r--r-- | libguile/net_db.c | 292 | ||||
-rw-r--r-- | libguile/net_db.h | 4 | ||||
-rw-r--r-- | module/ice-9/networking.scm | 9 | ||||
-rw-r--r-- | test-suite/Makefile.am | 1 | ||||
-rw-r--r-- | test-suite/tests/net-db.test | 74 |
6 files changed, 539 insertions, 5 deletions
diff --git a/doc/ref/posix.texi b/doc/ref/posix.texi index 6ff7109fd..85df34f71 100644 --- a/doc/ref/posix.texi +++ b/doc/ref/posix.texi @@ -1,6 +1,6 @@ @c -*-texinfo-*- @c This is part of the GNU Guile Reference Manual. -@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009 +@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2006, 2007, 2008, 2009, 2010 @c Free Software Foundation, Inc. @c See the file guile.texi for copying conditions. @@ -2336,6 +2336,164 @@ This section describes procedures which query various network databases. Care should be taken when using the database routines since they are not reentrant. +@subsubheading @code{getaddrinfo} + +@cindex @code{addrinfo} object type +@cindex host name lookup +@cindex service name lookup + +The @code{getaddrinfo} procedure maps host and service names to socket addresses +and associated information in a protocol-independent way. + +@deffn {Scheme Procedure} getaddrinfo name service [hint_flags [hint_family [hint_socktype [hint_protocol]]]] +@deffnx {C Function} scm_getaddrinfo (name, service, hint_flags, hint_family, hint_socktype, hint_protocol) +Return a list of @code{addrinfo} structures containing +a socket address and associated information for host @var{name} +and/or @var{service} to be used in creating a socket with +which to address the specified service. + +@example +(let* ((ai (car (getaddrinfo "www.gnu.org" "http"))) + (s (socket (addrinfo:fam ai) (addrinfo:socktype ai) + (addrinfo:protocol ai)))) + (connect s (addrinfo:addr ai)) + s) +@end example + +When @var{service} is omitted or is @code{#f}, return +network-level addresses for @var{name}. When @var{name} +is @code{#f} @var{service} must be provided and service +locations local to the caller are returned. + +Additional hints can be provided. When specified, +@var{hint_flags} should be a bitwise-or of zero or more +constants among the following: + +@table @code +@item AI_PASSIVE +Socket address is intended for @code{bind}. + +@item AI_CANONNAME +Request for canonical host name, available via +@code{addrinfo:canonname}. This makes sense mainly when +DNS lookups are involved. + +@item AI_NUMERICHOST +Specifies that @var{name} is a numeric host address string +(e.g., @code{"127.0.0.1"}), meaning that name resolution +will not be used. + +@item AI_NUMERICSERV +Likewise, specifies that @var{service} is a numeric port +string (e.g., @code{"80"}). + +@item AI_ADDRCONFIG +Return only addresses configured on the local system It is +highly recommended to provide this flag when the returned +socket addresses are to be used to make connections; +otherwise, some of the returned addresses could be unreachable +or use a protocol that is not supported. + +@item AI_V4MAPPED +When looking up IPv6 addresses, return mapped IPv4 addresses if +there is no IPv6 address available at all. + +@item AI_ALL +If this flag is set along with @code{AI_V4MAPPED} when looking up IPv6 +addresses, return all IPv6 addresses as well as all IPv4 addresses, the latter +mapped to IPv6 format. +@end table + +When given, @var{hint_family} should specify the requested +address family, e.g., @code{AF_INET6}. Similarly, +@var{hint_socktype} should specify the requested socket type +(e.g., @code{SOCK_DGRAM}), and @var{hint_protocol} should +specify the requested protocol (its value is interpretered +as in calls to @code{socket}). + +On error, an exception with key @code{getaddrinfo-error} is +thrown, with an error code (an integer) as its argument: + +@example +(catch 'getaddrinfo-error + (lambda () + (getaddrinfo "www.gnu.org" "gopher")) + (lambda (key errcode) + (cond ((= errcode EAI_SERVICE) + (display "doesn't know about Gopher!\n")) + ((= errcode EAI_NONAME) + (display "www.gnu.org not found\\n")) + (else + (format #t "something wrong: ~a\n" + (gai-strerror errcode)))))) +@end example + +Error codes are: + +@table @code +@item EAI_AGAIN +The name or service could not be resolved at this time. Future +attempts may succeed. + +@item EAI_BADFLAGS +@var{hint_flags} contains an invalid value. + +@item EAI_FAIL +A non-recoverable error occurred when attempting to +resolve the name. + +@item EAI_FAMILY +@var{hint_family} was not recognized. + +@item EAI_NONAME +Either @var{name} does not resolve for the supplied parameters, +or neither @var{name} nor @var{service} were supplied. + +@item EAI_SERVICE +@var{service} was not recognized for the specified socket type. + +@item EAI_SOCKTYPE +@var{hint_socktype} was not recognized. + +@item EAI_SYSTEM +A system error occurred; the error code can be found in +@code{errno}. +@end table + +Users are encouraged to read the +@url{http://www.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html, +"POSIX specification} for more details. +@end deffn + +The following procedures take an @code{addrinfo} object as returned by +@code{getaddrinfo}: + +@deffn {Scheme Procedure} addrinfo:flags ai +Return flags for @var{ai} as a bitwise or of @code{AI_} values (see above). +@end deffn + +@deffn {Scheme Procedure} addrinfo:fam ai +Return the address family of @var{ai} (a @code{AF_} value). +@end deffn + +@deffn {Scheme Procedure} addrinfo:socktype ai +Return the socket type for @var{ai} (a @code{SOCK_} value). +@end deffn + +@deffn {Scheme Procedure} addrinfo:protocol ai +Return the protocol of @var{ai}. +@end deffn + +@deffn {Scheme Procedure} addrinfo:addr ai +Return the socket address associated with @var{ai} as a @code{sockaddr} +object (@pxref{Network Socket Address}). +@end deffn + +@deffn {Scheme Procedure} addrinfo:canonname ai +Return a string for the canonical name associated with @var{ai} if +the @code{AI_CANONNAME} flag was supplied. +@end deffn + @subsubheading The Host Database @cindex @file{/etc/hosts} @cindex network database @@ -2366,7 +2524,9 @@ The list of network addresses associated with @var{host}. For Conversion}). @end deffn -The following procedures are used to search the host database: +The following procedures can be used to search the host database. However, +@code{getaddrinfo} should be preferred over them since it's more generic and +thread-safe. @deffn {Scheme Procedure} gethost [host] @deffnx {Scheme Procedure} gethostbyname hostname diff --git a/libguile/net_db.c b/libguile/net_db.c index 4307091f7..ca6dafb28 100644 --- a/libguile/net_db.c +++ b/libguile/net_db.c @@ -30,6 +30,7 @@ # include <config.h> #endif +#include <verify.h> #include <errno.h> #include "libguile/_scm.h" @@ -40,6 +41,7 @@ #include "libguile/validate.h" #include "libguile/net_db.h" +#include "libguile/socket.h" #ifdef HAVE_STRING_H #include <string.h> @@ -449,8 +451,296 @@ SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0, #undef FUNC_NAME #endif + +/* Protocol-independent name resolution with getaddrinfo(3) & co. */ + +SCM_SYMBOL (sym_getaddrinfo_error, "getaddrinfo-error"); + +/* Make sure the `AI_*' flags can be stored as INUMs. */ +verify (SCM_I_INUM (SCM_I_MAKINUM (AI_ALL)) == AI_ALL); + +/* Valid values for the `ai_flags' to `struct addrinfo'. */ +SCM_VARIABLE_INIT (sym_ai_passive, "AI_PASSIVE", + SCM_I_MAKINUM (AI_PASSIVE)); +SCM_VARIABLE_INIT (sym_ai_canonname, "AI_CANONNAME", + SCM_I_MAKINUM (AI_CANONNAME)); +SCM_VARIABLE_INIT (sym_ai_numerichost, "AI_NUMERICHOST", + SCM_I_MAKINUM (AI_NUMERICHOST)); +SCM_VARIABLE_INIT (sym_ai_numericserv, "AI_NUMERICSERV", + SCM_I_MAKINUM (AI_NUMERICSERV)); +SCM_VARIABLE_INIT (sym_ai_v4mapped, "AI_V4MAPPED", + SCM_I_MAKINUM (AI_V4MAPPED)); +SCM_VARIABLE_INIT (sym_ai_all, "AI_ALL", + SCM_I_MAKINUM (AI_ALL)); +SCM_VARIABLE_INIT (sym_ai_addrconfig, "AI_ADDRCONFIG", + SCM_I_MAKINUM (AI_ADDRCONFIG)); + +/* Return a Scheme vector whose elements correspond to the fields of C_AI, + ignoring the `ai_next' field. This function is not exported because the + definition of `struct addrinfo' is provided by Gnulib. */ +static SCM +scm_from_addrinfo (const struct addrinfo *c_ai) +{ + SCM ai; + + /* Note: The indices here must be kept synchronized with those used by the + `addrinfo:' procedures in `networking.scm'. */ + + ai = scm_c_make_vector (6, SCM_UNDEFINED); + SCM_SIMPLE_VECTOR_SET (ai, 0, scm_from_int (c_ai->ai_flags)); + SCM_SIMPLE_VECTOR_SET (ai, 1, scm_from_int (c_ai->ai_family)); + SCM_SIMPLE_VECTOR_SET (ai, 2, scm_from_int (c_ai->ai_socktype)); + SCM_SIMPLE_VECTOR_SET (ai, 3, scm_from_int (c_ai->ai_protocol)); + SCM_SIMPLE_VECTOR_SET (ai, 4, + scm_from_sockaddr (c_ai->ai_addr, c_ai->ai_addrlen)); + SCM_SIMPLE_VECTOR_SET (ai, 5, scm_from_locale_string (c_ai->ai_canonname)); + + return ai; +} + +SCM_DEFINE (scm_getaddrinfo, "getaddrinfo", 1, 5, 0, + (SCM name, SCM service, SCM hint_flags, SCM hint_family, + SCM hint_socktype, SCM hint_protocol), + "Return a list of @code{addrinfo} structures containing " + "a socket address and associated information for host @var{name} " + "and/or @var{service} to be used in creating a socket with " + "which to address the specified service.\n\n" + "@example\n" + "(let* ((ai (car (getaddrinfo \"www.gnu.org\" \"http\")))\n" + " (s (socket (addrinfo:fam ai) (addrinfo:socktype ai)\n" + " (addrinfo:protocol ai))))\n" + " (connect s (addrinfo:addr ai))\n" + " s)\n" + "@end example\n\n" + "When @var{service} is omitted or is @code{#f}, return " + "network-level addresses for @var{name}. When @var{name} " + "is @code{#f} @var{service} must be provided and service " + "locations local to the caller are returned.\n" + "\n" + "Additional hints can be provided. When specified, " + "@var{hint_flags} should be a bitwise-or of zero or more " + "constants among the following:\n\n" + "@table @code\n" + "@item AI_PASSIVE\n" + "Socket address is intended for @code{bind}.\n\n" + "@item AI_CANONNAME\n" + "Request for canonical host name, available via " + "@code{addrinfo:canonname}. This makes sense mainly when " + "DNS lookups are involved.\n\n" + "@item AI_NUMERICHOST\n" + "Specifies that @var{name} is a numeric host address string " + "(e.g., @code{\"127.0.0.1\"}), meaning that name resolution " + "will not be used.\n\n" + "@item AI_NUMERICSERV\n" + "Likewise, specifies that @var{service} is a numeric port " + "string (e.g., @code{\"80\"}).\n\n" + "@item AI_ADDRCONFIG\n" + "Return only addresses configured on the local system. It is " + "highly recommended to provide this flag when the returned " + "socket addresses are to be used to make connections; " + "otherwise, some of the returned addresses could be unreachable " + "or use a protocol that is not supported.\n\n" + "@item AI_V4MAPPED\n" + "When looking up IPv6 addresses, return mapped " + "IPv4 addresses if there is no IPv6 address available at all.\n\n" + "@item AI_ALL\n" + "If this flag is set along with @code{AI_V4MAPPED} when looking " + "up IPv6 addresses, return all IPv6 addresses " + "as well as all IPv4 addresses, the latter mapped to IPv6 " + "format.\n" + "@end table\n\n" + "When given, @var{hint_family} should specify the requested " + "address family, e.g., @code{AF_INET6}. Similarly, " + "@var{hint_socktype} should specify the requested socket type " + "(e.g., @code{SOCK_DGRAM}), and @var{hint_protocol} should " + "specify the requested protocol (its value is interpretered " + "as in calls to @code{socket}).\n" + "\n" + "On error, an exception with key @code{getaddrinfo-error} is " + "thrown, with an error code (an integer) as its argument:\n\n" + "@example\n" + "(catch 'getaddrinfo-error\n" + " (lambda ()\n" + " (getaddrinfo \"www.gnu.org\" \"gopher\"))\n" + " (lambda (key errcode)\n" + " (cond ((= errcode EAI_SERVICE)\n" + " (display \"doesn't know about Gopher!\\n\"))\n" + " ((= errcode EAI_NONAME)\n" + " (display \"www.gnu.org not found\\n\"))\n" + " (else\n" + " (format #t \"something wrong: ~a\\n\"\n" + " (gai-strerror errcode))))))\n" + "@end example\n" + "\n" + "Error codes are:\n\n" + "@table @code\n" + "@item EAI_AGAIN\n" + "The name or service could not be resolved at this time. Future " + "attempts may succeed.\n\n" + "@item EAI_BADFLAGS\n" + "@var{hint_flags} contains an invalid value.\n\n" + "@item EAI_FAIL\n" + "A non-recoverable error occurred when attempting to " + "resolve the name.\n\n" + "@item EAI_FAMILY\n" + "@var{hint_family} was not recognized.\n\n" + "@item EAI_NONAME\n" + "Either @var{name} does not resolve for the supplied parameters, " + "or neither @var{name} nor @var{service} were supplied.\n\n" + "@item EAI_SERVICE\n" + "@var{service} was not recognized for the specified socket type.\n\n" + "@item EAI_SOCKTYPE\n" + "@var{hint_socktype} was not recognized.\n\n" + "@item EAI_SYSTEM\n" + "A system error occurred; the error code can be found in " + "@code{errno}.\n" + "@end table\n" + "\n" + "Users are encouraged to read the " + "@url{http://www.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html," + "POSIX specification} for more details.\n") +#define FUNC_NAME s_scm_getaddrinfo +{ + int err; + char *c_name, *c_service; + struct addrinfo c_hints, *c_result; + SCM result = SCM_EOL; + + if (scm_is_true (name)) + SCM_VALIDATE_STRING (SCM_ARG1, name); + + if (!SCM_UNBNDP (service) && scm_is_true (service)) + SCM_VALIDATE_STRING (SCM_ARG2, service); + + scm_dynwind_begin (0); + + if (scm_is_string (name)) + { + c_name = scm_to_locale_string (name); + scm_dynwind_free (c_name); + } + else + c_name = NULL; + + if (scm_is_string (service)) + { + c_service = scm_to_locale_string (service); + scm_dynwind_free (c_service); + } + else + c_service = NULL; + + memset (&c_hints, 0, sizeof (c_hints)); + if (!SCM_UNBNDP (hint_flags)) + { + c_hints.ai_flags = scm_to_int (hint_flags); + if (!SCM_UNBNDP (hint_family)) + { + c_hints.ai_family = scm_to_int (hint_family); + if (!SCM_UNBNDP (hint_socktype)) + { + c_hints.ai_socktype = scm_to_int (hint_socktype); + if (!SCM_UNBNDP (hint_family)) + c_hints.ai_family = scm_to_int (hint_family); + } + } + } -void + err = getaddrinfo (c_name, c_service, &c_hints, &c_result); + if (err == 0) + { + SCM *prev_addr; + struct addrinfo *a; + + for (prev_addr = &result, a = c_result; + a != NULL; + a = a->ai_next, prev_addr = SCM_CDRLOC (*prev_addr)) + *prev_addr = scm_list_1 (scm_from_addrinfo (a)); + + freeaddrinfo (c_result); + } + else + scm_throw (sym_getaddrinfo_error, scm_list_1 (scm_from_int (err))); + + scm_dynwind_end (); + + return result; +} +#undef FUNC_NAME + +/* Make sure the `EAI_*' flags can be stored as INUMs. */ +verify (SCM_I_INUM (SCM_I_MAKINUM (EAI_BADFLAGS)) == EAI_BADFLAGS); + +/* Error codes returned by `getaddrinfo'. */ +SCM_VARIABLE_INIT (sym_eai_badflags, "EAI_BADFLAGS", + SCM_I_MAKINUM (EAI_BADFLAGS)); +SCM_VARIABLE_INIT (sym_eai_noname, "EAI_NONAME", + SCM_I_MAKINUM (EAI_NONAME)); +SCM_VARIABLE_INIT (sym_eai_again, "EAI_AGAIN", + SCM_I_MAKINUM (EAI_AGAIN)); +SCM_VARIABLE_INIT (sym_eai_fail, "EAI_FAIL", + SCM_I_MAKINUM (EAI_FAIL)); +SCM_VARIABLE_INIT (sym_eai_family, "EAI_FAMILY", + SCM_I_MAKINUM (EAI_FAMILY)); +SCM_VARIABLE_INIT (sym_eai_socktype, "EAI_SOCKTYPE", + SCM_I_MAKINUM (EAI_SOCKTYPE)); +SCM_VARIABLE_INIT (sym_eai_service, "EAI_SERVICE", + SCM_I_MAKINUM (EAI_SERVICE)); +SCM_VARIABLE_INIT (sym_eai_memory, "EAI_MEMORY", + SCM_I_MAKINUM (EAI_MEMORY)); +SCM_VARIABLE_INIT (sym_eai_system, "EAI_SYSTEM", + SCM_I_MAKINUM (EAI_SYSTEM)); +SCM_VARIABLE_INIT (sym_eai_overflow, "EAI_OVERFLOW", + SCM_I_MAKINUM (EAI_OVERFLOW)); + +/* The following values are GNU extensions. */ +#ifdef EAI_NODATA +SCM_VARIABLE_INIT (sym_eai_nodata, "EAI_NODATA", + SCM_I_MAKINUM (EAI_NODATA)); +#endif +#ifdef EAI_ADDRFAMILY +SCM_VARIABLE_INIT (sym_eai_addrfamily, "EAI_ADDRFAMILY", + SCM_I_MAKINUM (EAI_ADDRFAMILY)); +#endif +#ifdef EAI_INPROGRESS +SCM_VARIABLE_INIT (sym_eai_inprogress, "EAI_INPROGRESS", + SCM_I_MAKINUM (EAI_INPROGRESS)); +#endif +#ifdef EAI_CANCELED +SCM_VARIABLE_INIT (sym_eai_canceled, "EAI_CANCELED", + SCM_I_MAKINUM (EAI_CANCELED)); +#endif +#ifdef EAI_NOTCANCELED +SCM_VARIABLE_INIT (sym_eai_notcanceled, "EAI_NOTCANCELED", + SCM_I_MAKINUM (EAI_NOTCANCELED)); +#endif +#ifdef EAI_ALLDONE +SCM_VARIABLE_INIT (sym_eai_alldone, "EAI_ALLDONE", + SCM_I_MAKINUM (EAI_ALLDONE)); +#endif +#ifdef EAI_INTR +SCM_VARIABLE_INIT (sym_eai_intr, "EAI_INTR", + SCM_I_MAKINUM (EAI_INTR)); +#endif +#ifdef EAI_IDN_ENCODE +SCM_VARIABLE_INIT (sym_eai_idn_encode, "EAI_IDN_ENCODE", + SCM_I_MAKINUM (EAI_IDN_ENCODE)); +#endif + +SCM_DEFINE (scm_gai_strerror, "gai-strerror", 1, 0, 0, + (SCM error), + "Return a string describing @var{error}, an integer error code " + "returned by @code{getaddrinfo}.") +#define FUNC_NAME s_scm_gai_strerror +{ + return scm_from_locale_string (gai_strerror (scm_to_int (error))); +} +#undef FUNC_NAME + +/* TODO: Add a getnameinfo(3) wrapper. */ + + +void scm_init_net_db () { scm_add_feature ("net-db"); diff --git a/libguile/net_db.h b/libguile/net_db.h index 4b6327f27..68b2a8b0c 100644 --- a/libguile/net_db.h +++ b/libguile/net_db.h @@ -3,7 +3,7 @@ #ifndef SCM_NET_DB_H #define SCM_NET_DB_H -/* Copyright (C) 1995,2000,2001, 2006, 2008 Free Software Foundation, Inc. +/* Copyright (C) 1995,2000,2001, 2006, 2008, 2010 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -35,6 +35,8 @@ SCM_API SCM scm_sethost (SCM arg); SCM_API SCM scm_setnet (SCM arg); SCM_API SCM scm_setproto (SCM arg); SCM_API SCM scm_setserv (SCM arg); +SCM_API SCM scm_getaddrinfo (SCM, SCM, SCM, SCM, SCM, SCM); +SCM_API SCM scm_gai_strerror (SCM); SCM_INTERNAL void scm_init_net_db (void); #endif /* SCM_NET_DB_H */ diff --git a/module/ice-9/networking.scm b/module/ice-9/networking.scm index 7e84f0969..f9ff39436 100644 --- a/module/ice-9/networking.scm +++ b/module/ice-9/networking.scm @@ -1,6 +1,6 @@ ;;; installed-scm-file -;;;; Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. +;;;; Copyright (C) 1999, 2005, 2006, 2010 Free Software Foundation, Inc. ;;;; ;;;; This library is free software; you can redistribute it and/or ;;;; modify it under the terms of the GNU Lesser General Public @@ -85,3 +85,10 @@ (define (sockaddr:port obj) (vector-ref obj 2)) (define (sockaddr:flowinfo obj) (vector-ref obj 3)) (define (sockaddr:scopeid obj) (vector-ref obj 4)) + +(define (addrinfo:flags obj) (vector-ref obj 0)) +(define (addrinfo:fam obj) (vector-ref obj 1)) +(define (addrinfo:socktype obj) (vector-ref obj 2)) +(define (addrinfo:protocol obj) (vector-ref obj 3)) +(define (addrinfo:addr obj) (vector-ref obj 4)) +(define (addrinfo:canonname obj) (vector-ref obj 5)) diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am index c65f4d353..027a77359 100644 --- a/test-suite/Makefile.am +++ b/test-suite/Makefile.am @@ -55,6 +55,7 @@ SCM_TESTS = tests/alist.test \ tests/load.test \ tests/modules.test \ tests/multilingual.nottest \ + tests/net-db.test \ tests/numbers.test \ tests/optargs.test \ tests/options.test \ diff --git a/test-suite/tests/net-db.test b/test-suite/tests/net-db.test new file mode 100644 index 000000000..e1f7c083e --- /dev/null +++ b/test-suite/tests/net-db.test @@ -0,0 +1,74 @@ +;;;; net-db.test --- Test suite for `net-db' -*- mode: scheme; coding: utf-8; -*- +;;;; Ludovic Courtès <ludo@gnu.org> +;;;; +;;;; Copyright (C) 2010 Free Software Foundation, Inc. +;;;; +;;;; This library is free software; you can redistribute it and/or +;;;; modify it under the terms of the GNU Lesser General Public +;;;; License as published by the Free Software Foundation; either +;;;; version 3 of the License, or (at your option) any later version. +;;;; +;;;; This library is distributed in the hope that it will be useful, +;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +;;;; Lesser General Public License for more details. +;;;; +;;;; You should have received a copy of the GNU Lesser General Public +;;;; License along with this library; if not, write to the Free Software +;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +(define-module (test-suite test-net-db) + #:use-module (srfi srfi-1) + #:use-module (test-suite lib)) + +(if (provided? 'net-db) + (with-test-prefix "getaddrinfo" + + (pass-if "127.0.0.1, any service" + (let ((ai (getaddrinfo "127.0.0.1" #f AI_NUMERICHOST))) + (and (> (length ai) 0) + (fold (lambda (sa ok?) + (and ok? + (= (sockaddr:addr sa) INADDR_LOOPBACK))) + #t + (map addrinfo:addr ai))))) + + (pass-if "127.0.0.1:80" + (let ((ai (getaddrinfo "127.0.0.1" "80" + (logior AI_NUMERICHOST AI_NUMERICSERV)))) + (and (> (length ai) 0) + (fold (lambda (sa ok?) + (and ok? + (= (sockaddr:addr sa) INADDR_LOOPBACK) + (= (sockaddr:port sa) 80))) + #t + (map addrinfo:addr ai))))) + + (pass-if "port 80" + (let ((ai (getaddrinfo #f "80" (logior AI_ADDRCONFIG AI_NUMERICSERV)))) + (and (> (length ai) 0) + (fold (lambda (ai ok?) + (let ((sa (addrinfo:addr ai))) + (and ok? + (> (logand (addrinfo:flags ai) AI_ADDRCONFIG) 0) + (= (sockaddr:port sa) 80)))) + #t + ai)))) + + (pass-if "no name" + (catch 'getaddrinfo-error + (lambda () + (getaddrinfo "does-not-exist") + #f) + (lambda (key errcode) + (and (= errcode EAI_NONAME) + (string? (gai-strerror errcode)))))) + + (pass-if "wrong service name" + (catch 'getaddrinfo-error + (lambda () + (getaddrinfo "127.0.0.1" "does-not-exist" AI_NUMERICHOST) + #f) + (lambda (key errcode) + (and (= errcode EAI_SERVICE) + (string? (gai-strerror errcode)))))))) |