mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-04-30 11:50:28 +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:
parent
61cd9dc907
commit
55ae00ea73
6 changed files with 539 additions and 5 deletions
|
@ -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
|
||||||
|
|
|
@ -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,7 +451,295 @@ SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0,
|
||||||
#undef FUNC_NAME
|
#undef FUNC_NAME
|
||||||
#endif
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
void
|
||||||
scm_init_net_db ()
|
scm_init_net_db ()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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 \
|
||||||
|
|
74
test-suite/tests/net-db.test
Normal file
74
test-suite/tests/net-db.test
Normal 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))))))))
|
Loading…
Add table
Add a link
Reference in a new issue