Use Gnulib's `getaddrinfo' module.
[bpt/guile.git] / libguile / net_db.c
CommitLineData
370312ae 1/* "net_db.c" network database support
ca329120 2 * Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006, 2009 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
e6e2e95a
MD
33#include <errno.h>
34
a0599745
MD
35#include "libguile/_scm.h"
36#include "libguile/feature.h"
37#include "libguile/strings.h"
38#include "libguile/vectors.h"
7f9994d9 39#include "libguile/dynwind.h"
370312ae 40
a0599745
MD
41#include "libguile/validate.h"
42#include "libguile/net_db.h"
370312ae
GH
43
44#ifdef HAVE_STRING_H
45#include <string.h>
46#endif
47
48#include <sys/types.h>
82893676 49
f87c105a 50#ifdef HAVE_WINSOCK2_H
82893676
MG
51#include <winsock2.h>
52#else
cae76441 53#include <sys/socket.h>
370312ae
GH
54#include <netdb.h>
55#include <netinet/in.h>
56#include <arpa/inet.h>
82893676 57#endif
370312ae 58
6063dc1d
SJ
59#ifdef __MINGW32__
60#include "win32-socket.h"
61#endif
62
e2c80166 63#if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__)
789ecc05
GH
64/* h_errno not found in netdb.h, maybe this will help. */
65extern int h_errno;
66#endif
67
ca329120
LC
68#if defined HAVE_HSTRERROR && !HAVE_DECL_HSTRERROR \
69 && !defined __MINGW32__ && !defined __CYGWIN__
70/* Some OSes, such as Tru64 5.1b, lack a declaration for hstrerror(3). */
71extern const char *hstrerror (int);
72#endif
73
66c73b76 74\f
370312ae 75
5c11cc9d
GH
76SCM_SYMBOL (scm_host_not_found_key, "host-not-found");
77SCM_SYMBOL (scm_try_again_key, "try-again");
78SCM_SYMBOL (scm_no_recovery_key, "no-recovery");
79SCM_SYMBOL (scm_no_data_key, "no-data");
370312ae 80
5c11cc9d
GH
81static void scm_resolv_error (const char *subr, SCM bad_value)
82{
5a5f3646 83#ifdef NETDB_INTERNAL
5c11cc9d
GH
84 if (h_errno == NETDB_INTERNAL)
85 {
86 /* errno supposedly contains a useful value. */
87 scm_syserror (subr);
88 }
89 else
5a5f3646 90#endif
5c11cc9d
GH
91 {
92 SCM key;
93 const char *errmsg;
94
95 switch (h_errno)
96 {
97 case HOST_NOT_FOUND:
98 key = scm_host_not_found_key;
99 errmsg = "Unknown host";
100 break;
101 case TRY_AGAIN:
102 key = scm_try_again_key;
103 errmsg = "Host name lookup failure";
104 break;
105 case NO_RECOVERY:
106 key = scm_no_recovery_key;
107 errmsg = "Unknown server error";
108 break;
109 case NO_DATA:
110 key = scm_no_data_key;
111 errmsg = "No address associated with name";
112 break;
113 default:
114 scm_misc_error (subr, "Unknown resolver error", SCM_EOL);
115 errmsg = NULL;
116 }
117
118#ifdef HAVE_HSTRERROR
d9b6c170 119 errmsg = (const char *) hstrerror (h_errno);
5c11cc9d 120#endif
63ce14e7 121 scm_error (key, subr, errmsg, SCM_BOOL_F, SCM_EOL);
5c11cc9d
GH
122 }
123}
124
125/* Should take an extra arg for address format (will be needed for IPv6).
126 Should use reentrant facilities if available.
370312ae
GH
127 */
128
a1ec6916 129SCM_DEFINE (scm_gethost, "gethost", 0, 1, 0,
d46e4713 130 (SCM host),
8f85c0c6
NJ
131 "@deffnx {Scheme Procedure} gethostbyname hostname\n"
132 "@deffnx {Scheme Procedure} gethostbyaddr address\n"
b380b885
MD
133 "Look up a host by name or address, returning a host object. The\n"
134 "@code{gethost} procedure will accept either a string name or an integer\n"
135 "address; if given no arguments, it behaves like @code{gethostent} (see\n"
136 "below). If a name or address is supplied but the address can not be\n"
137 "found, an error will be thrown to one of the keys:\n"
138 "@code{host-not-found}, @code{try-again}, @code{no-recovery} or\n"
139 "@code{no-data}, corresponding to the equivalent @code{h_error} values.\n"
140 "Unusual conditions may result in errors thrown to the\n"
141 "@code{system-error} or @code{misc_error} keys.")
1bbd0b84 142#define FUNC_NAME s_scm_gethost
370312ae 143{
1d1559ce 144 SCM result = scm_c_make_vector (5, SCM_UNSPECIFIED);
370312ae
GH
145 SCM lst = SCM_EOL;
146 struct hostent *entry;
147 struct in_addr inad;
148 char **argv;
149 int i = 0;
7f9994d9 150
d46e4713 151 if (SCM_UNBNDP (host))
370312ae 152 {
cd34a384 153#ifdef HAVE_GETHOSTENT
370312ae 154 entry = gethostent ();
cd34a384
JB
155#else
156 entry = NULL;
157#endif
07513939
JB
158 if (! entry)
159 {
160 /* As far as I can tell, there's no good way to tell whether
161 zero means an error or end-of-file. The trick of
162 clearing errno before calling gethostent and checking it
163 afterwards doesn't cut it, because, on Linux, it seems to
164 try to contact some other server (YP?) and fails, which
165 is a benign failure. */
07513939
JB
166 return SCM_BOOL_F;
167 }
370312ae 168 }
7f9994d9 169 else if (scm_is_string (host))
370312ae 170 {
7f9994d9
MV
171 char *str = scm_to_locale_string (host);
172 entry = gethostbyname (str);
173 free (str);
370312ae
GH
174 }
175 else
176 {
7f9994d9 177 inad.s_addr = htonl (scm_to_ulong (host));
370312ae
GH
178 entry = gethostbyaddr ((char *) &inad, sizeof (inad), AF_INET);
179 }
7f9994d9 180
370312ae 181 if (!entry)
d46e4713 182 scm_resolv_error (FUNC_NAME, host);
5c11cc9d 183
4057a3e0
MV
184 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->h_name));
185 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->h_aliases));
186 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_int (entry->h_addrtype));
187 SCM_SIMPLE_VECTOR_SET(result, 3, scm_from_int (entry->h_length));
370312ae
GH
188 if (sizeof (struct in_addr) != entry->h_length)
189 {
4057a3e0 190 SCM_SIMPLE_VECTOR_SET(result, 4, SCM_BOOL_F);
1d1559ce 191 return result;
370312ae
GH
192 }
193 for (argv = entry->h_addr_list; argv[i]; i++);
194 while (i--)
195 {
196 inad = *(struct in_addr *) argv[i];
b9bd8526 197 lst = scm_cons (scm_from_ulong (ntohl (inad.s_addr)), lst);
370312ae 198 }
4057a3e0 199 SCM_SIMPLE_VECTOR_SET(result, 4, lst);
1d1559ce 200 return result;
370312ae 201}
1bbd0b84 202#undef FUNC_NAME
370312ae
GH
203
204
07513939
JB
205/* In all subsequent getMUMBLE functions, when we're called with no
206 arguments, we're supposed to traverse the tables entry by entry.
207 However, there doesn't seem to be any documented way to distinguish
208 between end-of-table and an error; in both cases the functions
209 return zero. Gotta love Unix. For the time being, we clear errno,
210 and if we get a zero and errno is set, we signal an error. This
211 doesn't seem quite right (what if errno gets set as part of healthy
212 operation?), but it seems to work okay. We'll see. */
213
0e958795 214#if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
a1ec6916 215SCM_DEFINE (scm_getnet, "getnet", 0, 1, 0,
d46e4713 216 (SCM net),
8f85c0c6
NJ
217 "@deffnx {Scheme Procedure} getnetbyname net-name\n"
218 "@deffnx {Scheme Procedure} getnetbyaddr net-number\n"
b380b885
MD
219 "Look up a network by name or net number in the network database. The\n"
220 "@var{net-name} argument must be a string, and the @var{net-number}\n"
221 "argument must be an integer. @code{getnet} will accept either type of\n"
222 "argument, behaving like @code{getnetent} (see below) if no arguments are\n"
223 "given.")
1bbd0b84 224#define FUNC_NAME s_scm_getnet
370312ae 225{
7f9994d9 226 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
370312ae 227 struct netent *entry;
7f9994d9 228 int eno;
370312ae 229
d46e4713 230 if (SCM_UNBNDP (net))
370312ae 231 {
370312ae 232 entry = getnetent ();
07513939
JB
233 if (! entry)
234 {
1dd05fd8
MG
235 /* There's no good way to tell whether zero means an error
236 or end-of-file, so we always return #f. See `gethost'
237 for details. */
238 return SCM_BOOL_F;
07513939 239 }
370312ae 240 }
7f9994d9 241 else if (scm_is_string (net))
370312ae 242 {
7f9994d9
MV
243 char *str = scm_to_locale_string (net);
244 entry = getnetbyname (str);
245 eno = errno;
246 free (str);
370312ae
GH
247 }
248 else
249 {
7f9994d9 250 unsigned long netnum = scm_to_ulong (net);
370312ae 251 entry = getnetbyaddr (netnum, AF_INET);
7f9994d9 252 eno = errno;
370312ae 253 }
7f9994d9 254
370312ae 255 if (!entry)
7f9994d9
MV
256 SCM_SYSERROR_MSG ("no such network ~A", scm_list_1 (net), eno);
257
4057a3e0
MV
258 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->n_name));
259 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->n_aliases));
260 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_int (entry->n_addrtype));
261 SCM_SIMPLE_VECTOR_SET(result, 3, scm_from_ulong (entry->n_net));
1d1559ce 262 return result;
370312ae 263}
1bbd0b84 264#undef FUNC_NAME
0e958795 265#endif
370312ae 266
6063dc1d 267#if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
a1ec6916 268SCM_DEFINE (scm_getproto, "getproto", 0, 1, 0,
d46e4713 269 (SCM protocol),
8f85c0c6
NJ
270 "@deffnx {Scheme Procedure} getprotobyname name\n"
271 "@deffnx {Scheme Procedure} getprotobynumber number\n"
b380b885
MD
272 "Look up a network protocol by name or by number. @code{getprotobyname}\n"
273 "takes a string argument, and @code{getprotobynumber} takes an integer\n"
274 "argument. @code{getproto} will accept either type, behaving like\n"
275 "@code{getprotoent} (see below) if no arguments are supplied.")
1bbd0b84 276#define FUNC_NAME s_scm_getproto
370312ae 277{
7f9994d9 278 SCM result = scm_c_make_vector (3, SCM_UNSPECIFIED);
1d1559ce 279 struct protoent *entry;
7f9994d9
MV
280 int eno;
281
d46e4713 282 if (SCM_UNBNDP (protocol))
370312ae 283 {
370312ae 284 entry = getprotoent ();
07513939
JB
285 if (! entry)
286 {
1dd05fd8
MG
287 /* There's no good way to tell whether zero means an error
288 or end-of-file, so we always return #f. See `gethost'
289 for details. */
290 return SCM_BOOL_F;
07513939 291 }
370312ae 292 }
7f9994d9 293 else if (scm_is_string (protocol))
370312ae 294 {
7f9994d9
MV
295 char *str = scm_to_locale_string (protocol);
296 entry = getprotobyname (str);
297 eno = errno;
298 free (str);
370312ae
GH
299 }
300 else
301 {
7f9994d9 302 unsigned long protonum = scm_to_ulong (protocol);
370312ae 303 entry = getprotobynumber (protonum);
7f9994d9 304 eno = errno;
370312ae 305 }
7f9994d9 306
370312ae 307 if (!entry)
7f9994d9
MV
308 SCM_SYSERROR_MSG ("no such protocol ~A", scm_list_1 (protocol), eno);
309
4057a3e0
MV
310 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->p_name));
311 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->p_aliases));
312 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_int (entry->p_proto));
1d1559ce 313 return result;
370312ae 314}
1bbd0b84 315#undef FUNC_NAME
0e958795 316#endif
370312ae 317
6063dc1d 318#if defined (HAVE_GETSERVENT) || defined (__MINGW32__)
370312ae 319static SCM
1bbd0b84 320scm_return_entry (struct servent *entry)
370312ae 321{
1d1559ce 322 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
370312ae 323
4057a3e0
MV
324 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->s_name));
325 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->s_aliases));
326 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_uint16 (ntohs (entry->s_port)));
327 SCM_SIMPLE_VECTOR_SET(result, 3, scm_from_locale_string (entry->s_proto));
1d1559ce 328 return result;
370312ae
GH
329}
330
a1ec6916 331SCM_DEFINE (scm_getserv, "getserv", 0, 2, 0,
d46e4713 332 (SCM name, SCM protocol),
8f85c0c6
NJ
333 "@deffnx {Scheme Procedure} getservbyname name protocol\n"
334 "@deffnx {Scheme Procedure} getservbyport port protocol\n"
b380b885
MD
335 "Look up a network service by name or by service number, and return a\n"
336 "network service object. The @var{protocol} argument specifies the name\n"
337 "of the desired protocol; if the protocol found in the network service\n"
338 "database does not match this name, a system error is signalled.\n\n"
339 "The @code{getserv} procedure will take either a service name or number\n"
340 "as its first argument; if given no arguments, it behaves like\n"
341 "@code{getservent} (see below).")
1bbd0b84 342#define FUNC_NAME s_scm_getserv
370312ae
GH
343{
344 struct servent *entry;
7f9994d9
MV
345 char *protoname;
346 int eno;
347
370312ae
GH
348 if (SCM_UNBNDP (name))
349 {
370312ae 350 entry = getservent ();
07513939
JB
351 if (!entry)
352 {
1dd05fd8
MG
353 /* There's no good way to tell whether zero means an error
354 or end-of-file, so we always return #f. See `gethost'
355 for details. */
356 return SCM_BOOL_F;
07513939 357 }
370312ae
GH
358 return scm_return_entry (entry);
359 }
7f9994d9 360
661ae7ab 361 scm_dynwind_begin (0);
7f9994d9
MV
362
363 protoname = scm_to_locale_string (protocol);
661ae7ab 364 scm_dynwind_free (protoname);
7f9994d9
MV
365
366 if (scm_is_string (name))
370312ae 367 {
7f9994d9
MV
368 char *str = scm_to_locale_string (name);
369 entry = getservbyname (str, protoname);
370 eno = errno;
371 free (str);
370312ae
GH
372 }
373 else
374 {
7f9994d9
MV
375 entry = getservbyport (htons (scm_to_int (name)), protoname);
376 eno = errno;
370312ae 377 }
7f9994d9 378
370312ae 379 if (!entry)
7f9994d9
MV
380 SCM_SYSERROR_MSG("no such service ~A", scm_list_1 (name), eno);
381
661ae7ab 382 scm_dynwind_end ();
370312ae
GH
383 return scm_return_entry (entry);
384}
1bbd0b84 385#undef FUNC_NAME
0e958795 386#endif
370312ae 387
0e958795 388#if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
a1ec6916 389SCM_DEFINE (scm_sethost, "sethost", 0, 1, 0,
d46e4713 390 (SCM stayopen),
b380b885
MD
391 "If @var{stayopen} is omitted, this is equivalent to @code{endhostent}.\n"
392 "Otherwise it is equivalent to @code{sethostent stayopen}.")
1bbd0b84 393#define FUNC_NAME s_scm_sethost
370312ae 394{
d46e4713 395 if (SCM_UNBNDP (stayopen))
370312ae
GH
396 endhostent ();
397 else
7888309b 398 sethostent (scm_is_true (stayopen));
370312ae
GH
399 return SCM_UNSPECIFIED;
400}
1bbd0b84 401#undef FUNC_NAME
0e958795 402#endif
370312ae 403
0e958795 404#if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
a1ec6916 405SCM_DEFINE (scm_setnet, "setnet", 0, 1, 0,
d46e4713 406 (SCM stayopen),
b380b885
MD
407 "If @var{stayopen} is omitted, this is equivalent to @code{endnetent}.\n"
408 "Otherwise it is equivalent to @code{setnetent stayopen}.")
1bbd0b84 409#define FUNC_NAME s_scm_setnet
370312ae 410{
d46e4713 411 if (SCM_UNBNDP (stayopen))
370312ae
GH
412 endnetent ();
413 else
7888309b 414 setnetent (scm_is_true (stayopen));
370312ae
GH
415 return SCM_UNSPECIFIED;
416}
1bbd0b84 417#undef FUNC_NAME
0e958795 418#endif
370312ae 419
6063dc1d 420#if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__)
a1ec6916 421SCM_DEFINE (scm_setproto, "setproto", 0, 1, 0,
d46e4713 422 (SCM stayopen),
b380b885
MD
423 "If @var{stayopen} is omitted, this is equivalent to @code{endprotoent}.\n"
424 "Otherwise it is equivalent to @code{setprotoent stayopen}.")
1bbd0b84 425#define FUNC_NAME s_scm_setproto
370312ae 426{
d46e4713 427 if (SCM_UNBNDP (stayopen))
370312ae
GH
428 endprotoent ();
429 else
7888309b 430 setprotoent (scm_is_true (stayopen));
370312ae
GH
431 return SCM_UNSPECIFIED;
432}
1bbd0b84 433#undef FUNC_NAME
0e958795 434#endif
370312ae 435
6063dc1d 436#if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__)
a1ec6916 437SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0,
d46e4713 438 (SCM stayopen),
b380b885
MD
439 "If @var{stayopen} is omitted, this is equivalent to @code{endservent}.\n"
440 "Otherwise it is equivalent to @code{setservent stayopen}.")
1bbd0b84 441#define FUNC_NAME s_scm_setserv
370312ae 442{
d46e4713 443 if (SCM_UNBNDP (stayopen))
370312ae
GH
444 endservent ();
445 else
7888309b 446 setservent (scm_is_true (stayopen));
370312ae
GH
447 return SCM_UNSPECIFIED;
448}
1bbd0b84 449#undef FUNC_NAME
0e958795 450#endif
370312ae
GH
451
452
453void
454scm_init_net_db ()
455{
370312ae 456 scm_add_feature ("net-db");
a0599745 457#include "libguile/net_db.x"
370312ae 458}
89e00824
ML
459
460/*
461 Local Variables:
462 c-file-style: "gnu"
463 End:
464*/