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