Update Gnulib to v0.0-6827-g39c3009; use the `dirfd' module.
[bpt/guile.git] / libguile / net_db.c
CommitLineData
370312ae 1/* "net_db.c" network database support
66d86131 2 * Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006, 2009, 2010, 2011 Free Software Foundation, Inc.
370312ae 3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
5 * modify it under the terms of the GNU Lesser General Public License
6 * as published by the Free Software Foundation; either version 3 of
7 * the License, or (at your option) any later version.
370312ae 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
370312ae 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
370312ae 19
1bbd0b84
GB
20
21
370312ae
GH
22/* Written in 1994 by Aubrey Jaffer.
23 * Thanks to Hallvard.Tretteberg@si.sintef.no for inspiration and discussion.
24 * Rewritten by Gary Houston to be a closer interface to the C socket library.
25 * Split into net_db.c and socket.c.
26 */
27\f
28
dbb605f5 29#ifdef HAVE_CONFIG_H
83b429ed
RB
30# include <config.h>
31#endif
32
55ae00ea 33#include <verify.h>
e6e2e95a
MD
34#include <errno.h>
35
a0599745
MD
36#include "libguile/_scm.h"
37#include "libguile/feature.h"
38#include "libguile/strings.h"
39#include "libguile/vectors.h"
7f9994d9 40#include "libguile/dynwind.h"
370312ae 41
a0599745
MD
42#include "libguile/validate.h"
43#include "libguile/net_db.h"
55ae00ea 44#include "libguile/socket.h"
370312ae
GH
45
46#ifdef HAVE_STRING_H
47#include <string.h>
48#endif
49
50#include <sys/types.h>
82893676 51
f87c105a 52#ifdef HAVE_WINSOCK2_H
82893676
MG
53#include <winsock2.h>
54#else
cae76441 55#include <sys/socket.h>
370312ae
GH
56#include <netdb.h>
57#include <netinet/in.h>
58#include <arpa/inet.h>
82893676 59#endif
370312ae 60
6063dc1d
SJ
61#ifdef __MINGW32__
62#include "win32-socket.h"
63#endif
64
e2c80166 65#if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__)
789ecc05
GH
66/* h_errno not found in netdb.h, maybe this will help. */
67extern int h_errno;
68#endif
69
ca329120
LC
70#if defined HAVE_HSTRERROR && !HAVE_DECL_HSTRERROR \
71 && !defined __MINGW32__ && !defined __CYGWIN__
72/* Some OSes, such as Tru64 5.1b, lack a declaration for hstrerror(3). */
73extern const char *hstrerror (int);
74#endif
75
66c73b76 76\f
370312ae 77
5c11cc9d
GH
78SCM_SYMBOL (scm_host_not_found_key, "host-not-found");
79SCM_SYMBOL (scm_try_again_key, "try-again");
80SCM_SYMBOL (scm_no_recovery_key, "no-recovery");
81SCM_SYMBOL (scm_no_data_key, "no-data");
370312ae 82
5c11cc9d
GH
83static void scm_resolv_error (const char *subr, SCM bad_value)
84{
5a5f3646 85#ifdef NETDB_INTERNAL
5c11cc9d
GH
86 if (h_errno == NETDB_INTERNAL)
87 {
88 /* errno supposedly contains a useful value. */
89 scm_syserror (subr);
90 }
91 else
5a5f3646 92#endif
5c11cc9d
GH
93 {
94 SCM key;
95 const char *errmsg;
96
97 switch (h_errno)
98 {
99 case HOST_NOT_FOUND:
100 key = scm_host_not_found_key;
101 errmsg = "Unknown host";
102 break;
103 case TRY_AGAIN:
104 key = scm_try_again_key;
105 errmsg = "Host name lookup failure";
106 break;
107 case NO_RECOVERY:
108 key = scm_no_recovery_key;
109 errmsg = "Unknown server error";
110 break;
111 case NO_DATA:
112 key = scm_no_data_key;
113 errmsg = "No address associated with name";
114 break;
115 default:
116 scm_misc_error (subr, "Unknown resolver error", SCM_EOL);
117 errmsg = NULL;
118 }
119
120#ifdef HAVE_HSTRERROR
d9b6c170 121 errmsg = (const char *) hstrerror (h_errno);
5c11cc9d 122#endif
63ce14e7 123 scm_error (key, subr, errmsg, SCM_BOOL_F, SCM_EOL);
5c11cc9d
GH
124 }
125}
126
127/* Should take an extra arg for address format (will be needed for IPv6).
128 Should use reentrant facilities if available.
370312ae
GH
129 */
130
a1ec6916 131SCM_DEFINE (scm_gethost, "gethost", 0, 1, 0,
d46e4713 132 (SCM host),
8f85c0c6
NJ
133 "@deffnx {Scheme Procedure} gethostbyname hostname\n"
134 "@deffnx {Scheme Procedure} gethostbyaddr address\n"
b380b885
MD
135 "Look up a host by name or address, returning a host object. The\n"
136 "@code{gethost} procedure will accept either a string name or an integer\n"
137 "address; if given no arguments, it behaves like @code{gethostent} (see\n"
138 "below). If a name or address is supplied but the address can not be\n"
139 "found, an error will be thrown to one of the keys:\n"
140 "@code{host-not-found}, @code{try-again}, @code{no-recovery} or\n"
141 "@code{no-data}, corresponding to the equivalent @code{h_error} values.\n"
142 "Unusual conditions may result in errors thrown to the\n"
143 "@code{system-error} or @code{misc_error} keys.")
1bbd0b84 144#define FUNC_NAME s_scm_gethost
370312ae 145{
1d1559ce 146 SCM result = scm_c_make_vector (5, SCM_UNSPECIFIED);
370312ae
GH
147 SCM lst = SCM_EOL;
148 struct hostent *entry;
149 struct in_addr inad;
150 char **argv;
151 int i = 0;
7f9994d9 152
d46e4713 153 if (SCM_UNBNDP (host))
370312ae 154 {
cd34a384 155#ifdef HAVE_GETHOSTENT
370312ae 156 entry = gethostent ();
cd34a384
JB
157#else
158 entry = NULL;
159#endif
07513939
JB
160 if (! entry)
161 {
162 /* As far as I can tell, there's no good way to tell whether
163 zero means an error or end-of-file. The trick of
164 clearing errno before calling gethostent and checking it
165 afterwards doesn't cut it, because, on Linux, it seems to
166 try to contact some other server (YP?) and fails, which
167 is a benign failure. */
07513939
JB
168 return SCM_BOOL_F;
169 }
370312ae 170 }
7f9994d9 171 else if (scm_is_string (host))
370312ae 172 {
7f9994d9
MV
173 char *str = scm_to_locale_string (host);
174 entry = gethostbyname (str);
175 free (str);
370312ae
GH
176 }
177 else
178 {
7f9994d9 179 inad.s_addr = htonl (scm_to_ulong (host));
370312ae
GH
180 entry = gethostbyaddr ((char *) &inad, sizeof (inad), AF_INET);
181 }
7f9994d9 182
370312ae 183 if (!entry)
d46e4713 184 scm_resolv_error (FUNC_NAME, host);
5c11cc9d 185
4057a3e0
MV
186 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->h_name));
187 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->h_aliases));
188 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_int (entry->h_addrtype));
189 SCM_SIMPLE_VECTOR_SET(result, 3, scm_from_int (entry->h_length));
370312ae
GH
190 if (sizeof (struct in_addr) != entry->h_length)
191 {
4057a3e0 192 SCM_SIMPLE_VECTOR_SET(result, 4, SCM_BOOL_F);
1d1559ce 193 return result;
370312ae
GH
194 }
195 for (argv = entry->h_addr_list; argv[i]; i++);
196 while (i--)
197 {
198 inad = *(struct in_addr *) argv[i];
b9bd8526 199 lst = scm_cons (scm_from_ulong (ntohl (inad.s_addr)), lst);
370312ae 200 }
4057a3e0 201 SCM_SIMPLE_VECTOR_SET(result, 4, lst);
1d1559ce 202 return result;
370312ae 203}
1bbd0b84 204#undef FUNC_NAME
370312ae
GH
205
206
07513939
JB
207/* In all subsequent getMUMBLE functions, when we're called with no
208 arguments, we're supposed to traverse the tables entry by entry.
209 However, there doesn't seem to be any documented way to distinguish
210 between end-of-table and an error; in both cases the functions
211 return zero. Gotta love Unix. For the time being, we clear errno,
212 and if we get a zero and errno is set, we signal an error. This
213 doesn't seem quite right (what if errno gets set as part of healthy
214 operation?), but it seems to work okay. We'll see. */
215
0e958795 216#if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
a1ec6916 217SCM_DEFINE (scm_getnet, "getnet", 0, 1, 0,
d46e4713 218 (SCM net),
8f85c0c6
NJ
219 "@deffnx {Scheme Procedure} getnetbyname net-name\n"
220 "@deffnx {Scheme Procedure} getnetbyaddr net-number\n"
b380b885
MD
221 "Look up a network by name or net number in the network database. The\n"
222 "@var{net-name} argument must be a string, and the @var{net-number}\n"
223 "argument must be an integer. @code{getnet} will accept either type of\n"
224 "argument, behaving like @code{getnetent} (see below) if no arguments are\n"
225 "given.")
1bbd0b84 226#define FUNC_NAME s_scm_getnet
370312ae 227{
7f9994d9 228 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
370312ae 229 struct netent *entry;
7f9994d9 230 int eno;
370312ae 231
d46e4713 232 if (SCM_UNBNDP (net))
370312ae 233 {
370312ae 234 entry = getnetent ();
07513939
JB
235 if (! entry)
236 {
1dd05fd8
MG
237 /* There's no good way to tell whether zero means an error
238 or end-of-file, so we always return #f. See `gethost'
239 for details. */
240 return SCM_BOOL_F;
07513939 241 }
370312ae 242 }
7f9994d9 243 else if (scm_is_string (net))
370312ae 244 {
7f9994d9
MV
245 char *str = scm_to_locale_string (net);
246 entry = getnetbyname (str);
247 eno = errno;
248 free (str);
370312ae
GH
249 }
250 else
251 {
7f9994d9 252 unsigned long netnum = scm_to_ulong (net);
370312ae 253 entry = getnetbyaddr (netnum, AF_INET);
7f9994d9 254 eno = errno;
370312ae 255 }
7f9994d9 256
370312ae 257 if (!entry)
7f9994d9
MV
258 SCM_SYSERROR_MSG ("no such network ~A", scm_list_1 (net), eno);
259
4057a3e0
MV
260 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->n_name));
261 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->n_aliases));
262 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_int (entry->n_addrtype));
263 SCM_SIMPLE_VECTOR_SET(result, 3, scm_from_ulong (entry->n_net));
1d1559ce 264 return result;
370312ae 265}
1bbd0b84 266#undef FUNC_NAME
0e958795 267#endif
370312ae 268
6063dc1d 269#if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
a1ec6916 270SCM_DEFINE (scm_getproto, "getproto", 0, 1, 0,
d46e4713 271 (SCM protocol),
8f85c0c6
NJ
272 "@deffnx {Scheme Procedure} getprotobyname name\n"
273 "@deffnx {Scheme Procedure} getprotobynumber number\n"
b380b885
MD
274 "Look up a network protocol by name or by number. @code{getprotobyname}\n"
275 "takes a string argument, and @code{getprotobynumber} takes an integer\n"
276 "argument. @code{getproto} will accept either type, behaving like\n"
277 "@code{getprotoent} (see below) if no arguments are supplied.")
1bbd0b84 278#define FUNC_NAME s_scm_getproto
370312ae 279{
7f9994d9 280 SCM result = scm_c_make_vector (3, SCM_UNSPECIFIED);
1d1559ce 281 struct protoent *entry;
7f9994d9
MV
282 int eno;
283
d46e4713 284 if (SCM_UNBNDP (protocol))
370312ae 285 {
370312ae 286 entry = getprotoent ();
07513939
JB
287 if (! entry)
288 {
1dd05fd8
MG
289 /* There's no good way to tell whether zero means an error
290 or end-of-file, so we always return #f. See `gethost'
291 for details. */
292 return SCM_BOOL_F;
07513939 293 }
370312ae 294 }
7f9994d9 295 else if (scm_is_string (protocol))
370312ae 296 {
7f9994d9
MV
297 char *str = scm_to_locale_string (protocol);
298 entry = getprotobyname (str);
299 eno = errno;
300 free (str);
370312ae
GH
301 }
302 else
303 {
7f9994d9 304 unsigned long protonum = scm_to_ulong (protocol);
370312ae 305 entry = getprotobynumber (protonum);
7f9994d9 306 eno = errno;
370312ae 307 }
7f9994d9 308
370312ae 309 if (!entry)
7f9994d9
MV
310 SCM_SYSERROR_MSG ("no such protocol ~A", scm_list_1 (protocol), eno);
311
4057a3e0
MV
312 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->p_name));
313 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->p_aliases));
314 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_int (entry->p_proto));
1d1559ce 315 return result;
370312ae 316}
1bbd0b84 317#undef FUNC_NAME
0e958795 318#endif
370312ae 319
6063dc1d 320#if defined (HAVE_GETSERVENT) || defined (__MINGW32__)
370312ae 321static SCM
1bbd0b84 322scm_return_entry (struct servent *entry)
370312ae 323{
1d1559ce 324 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
370312ae 325
4057a3e0
MV
326 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->s_name));
327 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->s_aliases));
328 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_uint16 (ntohs (entry->s_port)));
329 SCM_SIMPLE_VECTOR_SET(result, 3, scm_from_locale_string (entry->s_proto));
1d1559ce 330 return result;
370312ae
GH
331}
332
a1ec6916 333SCM_DEFINE (scm_getserv, "getserv", 0, 2, 0,
d46e4713 334 (SCM name, SCM protocol),
8f85c0c6
NJ
335 "@deffnx {Scheme Procedure} getservbyname name protocol\n"
336 "@deffnx {Scheme Procedure} getservbyport port protocol\n"
b380b885
MD
337 "Look up a network service by name or by service number, and return a\n"
338 "network service object. The @var{protocol} argument specifies the name\n"
339 "of the desired protocol; if the protocol found in the network service\n"
340 "database does not match this name, a system error is signalled.\n\n"
341 "The @code{getserv} procedure will take either a service name or number\n"
342 "as its first argument; if given no arguments, it behaves like\n"
343 "@code{getservent} (see below).")
1bbd0b84 344#define FUNC_NAME s_scm_getserv
370312ae
GH
345{
346 struct servent *entry;
7f9994d9
MV
347 char *protoname;
348 int eno;
349
370312ae
GH
350 if (SCM_UNBNDP (name))
351 {
370312ae 352 entry = getservent ();
07513939
JB
353 if (!entry)
354 {
1dd05fd8
MG
355 /* There's no good way to tell whether zero means an error
356 or end-of-file, so we always return #f. See `gethost'
357 for details. */
358 return SCM_BOOL_F;
07513939 359 }
370312ae
GH
360 return scm_return_entry (entry);
361 }
7f9994d9 362
661ae7ab 363 scm_dynwind_begin (0);
7f9994d9
MV
364
365 protoname = scm_to_locale_string (protocol);
661ae7ab 366 scm_dynwind_free (protoname);
7f9994d9
MV
367
368 if (scm_is_string (name))
370312ae 369 {
7f9994d9
MV
370 char *str = scm_to_locale_string (name);
371 entry = getservbyname (str, protoname);
372 eno = errno;
373 free (str);
370312ae
GH
374 }
375 else
376 {
7f9994d9
MV
377 entry = getservbyport (htons (scm_to_int (name)), protoname);
378 eno = errno;
370312ae 379 }
7f9994d9 380
370312ae 381 if (!entry)
7f9994d9
MV
382 SCM_SYSERROR_MSG("no such service ~A", scm_list_1 (name), eno);
383
661ae7ab 384 scm_dynwind_end ();
370312ae
GH
385 return scm_return_entry (entry);
386}
1bbd0b84 387#undef FUNC_NAME
0e958795 388#endif
370312ae 389
0e958795 390#if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
a1ec6916 391SCM_DEFINE (scm_sethost, "sethost", 0, 1, 0,
d46e4713 392 (SCM stayopen),
b380b885
MD
393 "If @var{stayopen} is omitted, this is equivalent to @code{endhostent}.\n"
394 "Otherwise it is equivalent to @code{sethostent stayopen}.")
1bbd0b84 395#define FUNC_NAME s_scm_sethost
370312ae 396{
d46e4713 397 if (SCM_UNBNDP (stayopen))
370312ae
GH
398 endhostent ();
399 else
7888309b 400 sethostent (scm_is_true (stayopen));
370312ae
GH
401 return SCM_UNSPECIFIED;
402}
1bbd0b84 403#undef FUNC_NAME
0e958795 404#endif
370312ae 405
0e958795 406#if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
a1ec6916 407SCM_DEFINE (scm_setnet, "setnet", 0, 1, 0,
d46e4713 408 (SCM stayopen),
b380b885
MD
409 "If @var{stayopen} is omitted, this is equivalent to @code{endnetent}.\n"
410 "Otherwise it is equivalent to @code{setnetent stayopen}.")
1bbd0b84 411#define FUNC_NAME s_scm_setnet
370312ae 412{
d46e4713 413 if (SCM_UNBNDP (stayopen))
370312ae
GH
414 endnetent ();
415 else
7888309b 416 setnetent (scm_is_true (stayopen));
370312ae
GH
417 return SCM_UNSPECIFIED;
418}
1bbd0b84 419#undef FUNC_NAME
0e958795 420#endif
370312ae 421
6063dc1d 422#if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__)
a1ec6916 423SCM_DEFINE (scm_setproto, "setproto", 0, 1, 0,
d46e4713 424 (SCM stayopen),
b380b885
MD
425 "If @var{stayopen} is omitted, this is equivalent to @code{endprotoent}.\n"
426 "Otherwise it is equivalent to @code{setprotoent stayopen}.")
1bbd0b84 427#define FUNC_NAME s_scm_setproto
370312ae 428{
d46e4713 429 if (SCM_UNBNDP (stayopen))
370312ae
GH
430 endprotoent ();
431 else
7888309b 432 setprotoent (scm_is_true (stayopen));
370312ae
GH
433 return SCM_UNSPECIFIED;
434}
1bbd0b84 435#undef FUNC_NAME
0e958795 436#endif
370312ae 437
6063dc1d 438#if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__)
a1ec6916 439SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0,
d46e4713 440 (SCM stayopen),
b380b885
MD
441 "If @var{stayopen} is omitted, this is equivalent to @code{endservent}.\n"
442 "Otherwise it is equivalent to @code{setservent stayopen}.")
1bbd0b84 443#define FUNC_NAME s_scm_setserv
370312ae 444{
d46e4713 445 if (SCM_UNBNDP (stayopen))
370312ae
GH
446 endservent ();
447 else
7888309b 448 setservent (scm_is_true (stayopen));
370312ae
GH
449 return SCM_UNSPECIFIED;
450}
1bbd0b84 451#undef FUNC_NAME
0e958795 452#endif
370312ae 453
55ae00ea
LC
454\f
455/* Protocol-independent name resolution with getaddrinfo(3) & co. */
456
457SCM_SYMBOL (sym_getaddrinfo_error, "getaddrinfo-error");
458
459/* Make sure the `AI_*' flags can be stored as INUMs. */
6ef43766 460verify (AI_ALL < SCM_MOST_POSITIVE_FIXNUM);
55ae00ea
LC
461
462/* Valid values for the `ai_flags' to `struct addrinfo'. */
463SCM_VARIABLE_INIT (sym_ai_passive, "AI_PASSIVE",
464 SCM_I_MAKINUM (AI_PASSIVE));
465SCM_VARIABLE_INIT (sym_ai_canonname, "AI_CANONNAME",
466 SCM_I_MAKINUM (AI_CANONNAME));
467SCM_VARIABLE_INIT (sym_ai_numerichost, "AI_NUMERICHOST",
468 SCM_I_MAKINUM (AI_NUMERICHOST));
469SCM_VARIABLE_INIT (sym_ai_numericserv, "AI_NUMERICSERV",
470 SCM_I_MAKINUM (AI_NUMERICSERV));
471SCM_VARIABLE_INIT (sym_ai_v4mapped, "AI_V4MAPPED",
472 SCM_I_MAKINUM (AI_V4MAPPED));
473SCM_VARIABLE_INIT (sym_ai_all, "AI_ALL",
474 SCM_I_MAKINUM (AI_ALL));
475SCM_VARIABLE_INIT (sym_ai_addrconfig, "AI_ADDRCONFIG",
476 SCM_I_MAKINUM (AI_ADDRCONFIG));
477
478/* Return a Scheme vector whose elements correspond to the fields of C_AI,
479 ignoring the `ai_next' field. This function is not exported because the
480 definition of `struct addrinfo' is provided by Gnulib. */
481static SCM
482scm_from_addrinfo (const struct addrinfo *c_ai)
483{
484 SCM ai;
485
486 /* Note: The indices here must be kept synchronized with those used by the
487 `addrinfo:' procedures in `networking.scm'. */
488
489 ai = scm_c_make_vector (6, SCM_UNDEFINED);
490 SCM_SIMPLE_VECTOR_SET (ai, 0, scm_from_int (c_ai->ai_flags));
491 SCM_SIMPLE_VECTOR_SET (ai, 1, scm_from_int (c_ai->ai_family));
492 SCM_SIMPLE_VECTOR_SET (ai, 2, scm_from_int (c_ai->ai_socktype));
493 SCM_SIMPLE_VECTOR_SET (ai, 3, scm_from_int (c_ai->ai_protocol));
494 SCM_SIMPLE_VECTOR_SET (ai, 4,
495 scm_from_sockaddr (c_ai->ai_addr, c_ai->ai_addrlen));
3474222a
LC
496 SCM_SIMPLE_VECTOR_SET (ai, 5,
497 c_ai->ai_canonname != NULL
498 ? scm_from_locale_string (c_ai->ai_canonname)
499 : SCM_BOOL_F);
55ae00ea
LC
500
501 return ai;
502}
503
504SCM_DEFINE (scm_getaddrinfo, "getaddrinfo", 1, 5, 0,
505 (SCM name, SCM service, SCM hint_flags, SCM hint_family,
506 SCM hint_socktype, SCM hint_protocol),
507 "Return a list of @code{addrinfo} structures containing "
508 "a socket address and associated information for host @var{name} "
509 "and/or @var{service} to be used in creating a socket with "
510 "which to address the specified service.\n\n"
511 "@example\n"
512 "(let* ((ai (car (getaddrinfo \"www.gnu.org\" \"http\")))\n"
513 " (s (socket (addrinfo:fam ai) (addrinfo:socktype ai)\n"
514 " (addrinfo:protocol ai))))\n"
515 " (connect s (addrinfo:addr ai))\n"
516 " s)\n"
517 "@end example\n\n"
518 "When @var{service} is omitted or is @code{#f}, return "
519 "network-level addresses for @var{name}. When @var{name} "
520 "is @code{#f} @var{service} must be provided and service "
521 "locations local to the caller are returned.\n"
522 "\n"
523 "Additional hints can be provided. When specified, "
524 "@var{hint_flags} should be a bitwise-or of zero or more "
525 "constants among the following:\n\n"
526 "@table @code\n"
527 "@item AI_PASSIVE\n"
528 "Socket address is intended for @code{bind}.\n\n"
529 "@item AI_CANONNAME\n"
530 "Request for canonical host name, available via "
531 "@code{addrinfo:canonname}. This makes sense mainly when "
532 "DNS lookups are involved.\n\n"
533 "@item AI_NUMERICHOST\n"
534 "Specifies that @var{name} is a numeric host address string "
535 "(e.g., @code{\"127.0.0.1\"}), meaning that name resolution "
536 "will not be used.\n\n"
537 "@item AI_NUMERICSERV\n"
538 "Likewise, specifies that @var{service} is a numeric port "
539 "string (e.g., @code{\"80\"}).\n\n"
540 "@item AI_ADDRCONFIG\n"
541 "Return only addresses configured on the local system. It is "
542 "highly recommended to provide this flag when the returned "
543 "socket addresses are to be used to make connections; "
544 "otherwise, some of the returned addresses could be unreachable "
545 "or use a protocol that is not supported.\n\n"
546 "@item AI_V4MAPPED\n"
547 "When looking up IPv6 addresses, return mapped "
548 "IPv4 addresses if there is no IPv6 address available at all.\n\n"
549 "@item AI_ALL\n"
550 "If this flag is set along with @code{AI_V4MAPPED} when looking "
551 "up IPv6 addresses, return all IPv6 addresses "
552 "as well as all IPv4 addresses, the latter mapped to IPv6 "
553 "format.\n"
554 "@end table\n\n"
555 "When given, @var{hint_family} should specify the requested "
556 "address family, e.g., @code{AF_INET6}. Similarly, "
557 "@var{hint_socktype} should specify the requested socket type "
558 "(e.g., @code{SOCK_DGRAM}), and @var{hint_protocol} should "
559 "specify the requested protocol (its value is interpretered "
560 "as in calls to @code{socket}).\n"
561 "\n"
562 "On error, an exception with key @code{getaddrinfo-error} is "
563 "thrown, with an error code (an integer) as its argument:\n\n"
564 "@example\n"
565 "(catch 'getaddrinfo-error\n"
566 " (lambda ()\n"
567 " (getaddrinfo \"www.gnu.org\" \"gopher\"))\n"
568 " (lambda (key errcode)\n"
569 " (cond ((= errcode EAI_SERVICE)\n"
570 " (display \"doesn't know about Gopher!\\n\"))\n"
571 " ((= errcode EAI_NONAME)\n"
572 " (display \"www.gnu.org not found\\n\"))\n"
573 " (else\n"
574 " (format #t \"something wrong: ~a\\n\"\n"
575 " (gai-strerror errcode))))))\n"
576 "@end example\n"
577 "\n"
578 "Error codes are:\n\n"
579 "@table @code\n"
580 "@item EAI_AGAIN\n"
581 "The name or service could not be resolved at this time. Future "
582 "attempts may succeed.\n\n"
583 "@item EAI_BADFLAGS\n"
584 "@var{hint_flags} contains an invalid value.\n\n"
585 "@item EAI_FAIL\n"
586 "A non-recoverable error occurred when attempting to "
587 "resolve the name.\n\n"
588 "@item EAI_FAMILY\n"
589 "@var{hint_family} was not recognized.\n\n"
590 "@item EAI_NONAME\n"
591 "Either @var{name} does not resolve for the supplied parameters, "
592 "or neither @var{name} nor @var{service} were supplied.\n\n"
66d86131
LC
593 "@item EAI_NODATA\n"
594 "This non-POSIX error code can be returned on GNU systems when a\n"
595 "request was actually made but returned no data, meaning\n"
596 "that no address is associated with @var{name}. Error handling\n"
597 "code should be prepared to handle it when it is defined.\n\n"
55ae00ea
LC
598 "@item EAI_SERVICE\n"
599 "@var{service} was not recognized for the specified socket type.\n\n"
600 "@item EAI_SOCKTYPE\n"
601 "@var{hint_socktype} was not recognized.\n\n"
602 "@item EAI_SYSTEM\n"
603 "A system error occurred; the error code can be found in "
604 "@code{errno}.\n"
605 "@end table\n"
606 "\n"
607 "Users are encouraged to read the "
608 "@url{http://www.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html,"
609 "POSIX specification} for more details.\n")
610#define FUNC_NAME s_scm_getaddrinfo
611{
612 int err;
613 char *c_name, *c_service;
614 struct addrinfo c_hints, *c_result;
615 SCM result = SCM_EOL;
616
617 if (scm_is_true (name))
618 SCM_VALIDATE_STRING (SCM_ARG1, name);
619
620 if (!SCM_UNBNDP (service) && scm_is_true (service))
621 SCM_VALIDATE_STRING (SCM_ARG2, service);
622
623 scm_dynwind_begin (0);
624
625 if (scm_is_string (name))
626 {
627 c_name = scm_to_locale_string (name);
628 scm_dynwind_free (c_name);
629 }
630 else
631 c_name = NULL;
632
633 if (scm_is_string (service))
634 {
635 c_service = scm_to_locale_string (service);
636 scm_dynwind_free (c_service);
637 }
638 else
639 c_service = NULL;
640
641 memset (&c_hints, 0, sizeof (c_hints));
642 if (!SCM_UNBNDP (hint_flags))
643 {
644 c_hints.ai_flags = scm_to_int (hint_flags);
645 if (!SCM_UNBNDP (hint_family))
646 {
647 c_hints.ai_family = scm_to_int (hint_family);
648 if (!SCM_UNBNDP (hint_socktype))
649 {
650 c_hints.ai_socktype = scm_to_int (hint_socktype);
651 if (!SCM_UNBNDP (hint_family))
652 c_hints.ai_family = scm_to_int (hint_family);
653 }
654 }
655 }
370312ae 656
55ae00ea
LC
657 err = getaddrinfo (c_name, c_service, &c_hints, &c_result);
658 if (err == 0)
659 {
660 SCM *prev_addr;
661 struct addrinfo *a;
662
663 for (prev_addr = &result, a = c_result;
664 a != NULL;
665 a = a->ai_next, prev_addr = SCM_CDRLOC (*prev_addr))
666 *prev_addr = scm_list_1 (scm_from_addrinfo (a));
667
668 freeaddrinfo (c_result);
669 }
670 else
671 scm_throw (sym_getaddrinfo_error, scm_list_1 (scm_from_int (err)));
672
673 scm_dynwind_end ();
674
675 return result;
676}
677#undef FUNC_NAME
678
679/* Make sure the `EAI_*' flags can be stored as INUMs. */
6ef43766 680verify (EAI_BADFLAGS < SCM_MOST_POSITIVE_FIXNUM);
55ae00ea
LC
681
682/* Error codes returned by `getaddrinfo'. */
683SCM_VARIABLE_INIT (sym_eai_badflags, "EAI_BADFLAGS",
684 SCM_I_MAKINUM (EAI_BADFLAGS));
685SCM_VARIABLE_INIT (sym_eai_noname, "EAI_NONAME",
686 SCM_I_MAKINUM (EAI_NONAME));
687SCM_VARIABLE_INIT (sym_eai_again, "EAI_AGAIN",
688 SCM_I_MAKINUM (EAI_AGAIN));
689SCM_VARIABLE_INIT (sym_eai_fail, "EAI_FAIL",
690 SCM_I_MAKINUM (EAI_FAIL));
691SCM_VARIABLE_INIT (sym_eai_family, "EAI_FAMILY",
692 SCM_I_MAKINUM (EAI_FAMILY));
693SCM_VARIABLE_INIT (sym_eai_socktype, "EAI_SOCKTYPE",
694 SCM_I_MAKINUM (EAI_SOCKTYPE));
695SCM_VARIABLE_INIT (sym_eai_service, "EAI_SERVICE",
696 SCM_I_MAKINUM (EAI_SERVICE));
697SCM_VARIABLE_INIT (sym_eai_memory, "EAI_MEMORY",
698 SCM_I_MAKINUM (EAI_MEMORY));
699SCM_VARIABLE_INIT (sym_eai_system, "EAI_SYSTEM",
700 SCM_I_MAKINUM (EAI_SYSTEM));
701SCM_VARIABLE_INIT (sym_eai_overflow, "EAI_OVERFLOW",
702 SCM_I_MAKINUM (EAI_OVERFLOW));
703
704/* The following values are GNU extensions. */
705#ifdef EAI_NODATA
706SCM_VARIABLE_INIT (sym_eai_nodata, "EAI_NODATA",
707 SCM_I_MAKINUM (EAI_NODATA));
708#endif
709#ifdef EAI_ADDRFAMILY
710SCM_VARIABLE_INIT (sym_eai_addrfamily, "EAI_ADDRFAMILY",
711 SCM_I_MAKINUM (EAI_ADDRFAMILY));
712#endif
713#ifdef EAI_INPROGRESS
714SCM_VARIABLE_INIT (sym_eai_inprogress, "EAI_INPROGRESS",
715 SCM_I_MAKINUM (EAI_INPROGRESS));
716#endif
717#ifdef EAI_CANCELED
718SCM_VARIABLE_INIT (sym_eai_canceled, "EAI_CANCELED",
719 SCM_I_MAKINUM (EAI_CANCELED));
720#endif
721#ifdef EAI_NOTCANCELED
722SCM_VARIABLE_INIT (sym_eai_notcanceled, "EAI_NOTCANCELED",
723 SCM_I_MAKINUM (EAI_NOTCANCELED));
724#endif
725#ifdef EAI_ALLDONE
726SCM_VARIABLE_INIT (sym_eai_alldone, "EAI_ALLDONE",
727 SCM_I_MAKINUM (EAI_ALLDONE));
728#endif
729#ifdef EAI_INTR
730SCM_VARIABLE_INIT (sym_eai_intr, "EAI_INTR",
731 SCM_I_MAKINUM (EAI_INTR));
732#endif
733#ifdef EAI_IDN_ENCODE
734SCM_VARIABLE_INIT (sym_eai_idn_encode, "EAI_IDN_ENCODE",
735 SCM_I_MAKINUM (EAI_IDN_ENCODE));
736#endif
737
738SCM_DEFINE (scm_gai_strerror, "gai-strerror", 1, 0, 0,
739 (SCM error),
740 "Return a string describing @var{error}, an integer error code "
741 "returned by @code{getaddrinfo}.")
742#define FUNC_NAME s_scm_gai_strerror
743{
744 return scm_from_locale_string (gai_strerror (scm_to_int (error)));
745}
746#undef FUNC_NAME
747
748/* TODO: Add a getnameinfo(3) wrapper. */
749
750\f
751void
370312ae
GH
752scm_init_net_db ()
753{
370312ae 754 scm_add_feature ("net-db");
a0599745 755#include "libguile/net_db.x"
370312ae 756}
89e00824
ML
757
758/*
759 Local Variables:
760 c-file-style: "gnu"
761 End:
762*/