1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-04-30 03:40:34 +02:00

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'.
This commit is contained in:
Ludovic Courtès 2010-02-14 20:56:31 +01:00
parent 61cd9dc907
commit 55ae00ea73
6 changed files with 539 additions and 5 deletions

View file

@ -1,6 +1,6 @@
@c -*-texinfo-*- @c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual. @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 Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions. @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 Care should be taken when using the database routines since they are not
reentrant. 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 @subsubheading The Host Database
@cindex @file{/etc/hosts} @cindex @file{/etc/hosts}
@cindex network database @cindex network database
@ -2366,7 +2524,9 @@ The list of network addresses associated with @var{host}. For
Conversion}). Conversion}).
@end deffn @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] @deffn {Scheme Procedure} gethost [host]
@deffnx {Scheme Procedure} gethostbyname hostname @deffnx {Scheme Procedure} gethostbyname hostname

View file

@ -30,6 +30,7 @@
# include <config.h> # include <config.h>
#endif #endif
#include <verify.h>
#include <errno.h> #include <errno.h>
#include "libguile/_scm.h" #include "libguile/_scm.h"
@ -40,6 +41,7 @@
#include "libguile/validate.h" #include "libguile/validate.h"
#include "libguile/net_db.h" #include "libguile/net_db.h"
#include "libguile/socket.h"
#ifdef HAVE_STRING_H #ifdef HAVE_STRING_H
#include <string.h> #include <string.h>
@ -449,8 +451,296 @@ SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0,
#undef FUNC_NAME #undef FUNC_NAME
#endif #endif
/* Protocol-independent name resolution with getaddrinfo(3) & co. */
void 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);
}
}
}
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_init_net_db ()
{ {
scm_add_feature ("net-db"); scm_add_feature ("net-db");

View file

@ -3,7 +3,7 @@
#ifndef SCM_NET_DB_H #ifndef SCM_NET_DB_H
#define 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 * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * 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_setnet (SCM arg);
SCM_API SCM scm_setproto (SCM arg); SCM_API SCM scm_setproto (SCM arg);
SCM_API SCM scm_setserv (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); SCM_INTERNAL void scm_init_net_db (void);
#endif /* SCM_NET_DB_H */ #endif /* SCM_NET_DB_H */

View file

@ -1,6 +1,6 @@
;;; installed-scm-file ;;; 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 ;;;; This library is free software; you can redistribute it and/or
;;;; modify it under the terms of the GNU Lesser General Public ;;;; 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:port obj) (vector-ref obj 2))
(define (sockaddr:flowinfo obj) (vector-ref obj 3)) (define (sockaddr:flowinfo obj) (vector-ref obj 3))
(define (sockaddr:scopeid obj) (vector-ref obj 4)) (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))

View file

@ -55,6 +55,7 @@ SCM_TESTS = tests/alist.test \
tests/load.test \ tests/load.test \
tests/modules.test \ tests/modules.test \
tests/multilingual.nottest \ tests/multilingual.nottest \
tests/net-db.test \
tests/numbers.test \ tests/numbers.test \
tests/optargs.test \ tests/optargs.test \
tests/options.test \ tests/options.test \

View file

@ -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))))))))