The FSF has a new address.
[bpt/guile.git] / libguile / net_db.c
CommitLineData
370312ae 1/* "net_db.c" network database support
e4b265d8 2 * Copyright (C) 1995,1996,1997,1998,1999,2000,2001 Free Software Foundation, Inc.
370312ae 3 *
73be1d9e
MV
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
370312ae 8 *
73be1d9e
MV
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
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
92205699 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 17 */
370312ae 18
1bbd0b84
GB
19
20
370312ae
GH
21/* Written in 1994 by Aubrey Jaffer.
22 * Thanks to Hallvard.Tretteberg@si.sintef.no for inspiration and discussion.
23 * Rewritten by Gary Houston to be a closer interface to the C socket library.
24 * Split into net_db.c and socket.c.
25 */
26\f
27
83b429ed
RB
28#if HAVE_CONFIG_H
29# include <config.h>
30#endif
31
e6e2e95a
MD
32#include <errno.h>
33
a0599745
MD
34#include "libguile/_scm.h"
35#include "libguile/feature.h"
36#include "libguile/strings.h"
37#include "libguile/vectors.h"
7f9994d9 38#include "libguile/dynwind.h"
370312ae 39
a0599745
MD
40#include "libguile/validate.h"
41#include "libguile/net_db.h"
370312ae
GH
42
43#ifdef HAVE_STRING_H
44#include <string.h>
45#endif
46
47#include <sys/types.h>
82893676 48
f87c105a 49#ifdef HAVE_WINSOCK2_H
82893676
MG
50#include <winsock2.h>
51#else
cae76441 52#include <sys/socket.h>
370312ae
GH
53#include <netdb.h>
54#include <netinet/in.h>
55#include <arpa/inet.h>
82893676 56#endif
370312ae 57
6063dc1d
SJ
58#ifdef __MINGW32__
59#include "win32-socket.h"
60#endif
61
e2c80166 62#if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__)
789ecc05
GH
63/* h_errno not found in netdb.h, maybe this will help. */
64extern int h_errno;
65#endif
66
66c73b76 67\f
370312ae 68
5c11cc9d
GH
69SCM_SYMBOL (scm_host_not_found_key, "host-not-found");
70SCM_SYMBOL (scm_try_again_key, "try-again");
71SCM_SYMBOL (scm_no_recovery_key, "no-recovery");
72SCM_SYMBOL (scm_no_data_key, "no-data");
370312ae 73
5c11cc9d
GH
74static void scm_resolv_error (const char *subr, SCM bad_value)
75{
5a5f3646 76#ifdef NETDB_INTERNAL
5c11cc9d
GH
77 if (h_errno == NETDB_INTERNAL)
78 {
79 /* errno supposedly contains a useful value. */
80 scm_syserror (subr);
81 }
82 else
5a5f3646 83#endif
5c11cc9d
GH
84 {
85 SCM key;
86 const char *errmsg;
87
88 switch (h_errno)
89 {
90 case HOST_NOT_FOUND:
91 key = scm_host_not_found_key;
92 errmsg = "Unknown host";
93 break;
94 case TRY_AGAIN:
95 key = scm_try_again_key;
96 errmsg = "Host name lookup failure";
97 break;
98 case NO_RECOVERY:
99 key = scm_no_recovery_key;
100 errmsg = "Unknown server error";
101 break;
102 case NO_DATA:
103 key = scm_no_data_key;
104 errmsg = "No address associated with name";
105 break;
106 default:
107 scm_misc_error (subr, "Unknown resolver error", SCM_EOL);
108 errmsg = NULL;
109 }
110
111#ifdef HAVE_HSTRERROR
d9b6c170 112 errmsg = (const char *) hstrerror (h_errno);
5c11cc9d 113#endif
63ce14e7 114 scm_error (key, subr, errmsg, SCM_BOOL_F, SCM_EOL);
5c11cc9d
GH
115 }
116}
117
118/* Should take an extra arg for address format (will be needed for IPv6).
119 Should use reentrant facilities if available.
370312ae
GH
120 */
121
a1ec6916 122SCM_DEFINE (scm_gethost, "gethost", 0, 1, 0,
d46e4713 123 (SCM host),
8f85c0c6
NJ
124 "@deffnx {Scheme Procedure} gethostbyname hostname\n"
125 "@deffnx {Scheme Procedure} gethostbyaddr address\n"
b380b885
MD
126 "Look up a host by name or address, returning a host object. The\n"
127 "@code{gethost} procedure will accept either a string name or an integer\n"
128 "address; if given no arguments, it behaves like @code{gethostent} (see\n"
129 "below). If a name or address is supplied but the address can not be\n"
130 "found, an error will be thrown to one of the keys:\n"
131 "@code{host-not-found}, @code{try-again}, @code{no-recovery} or\n"
132 "@code{no-data}, corresponding to the equivalent @code{h_error} values.\n"
133 "Unusual conditions may result in errors thrown to the\n"
134 "@code{system-error} or @code{misc_error} keys.")
1bbd0b84 135#define FUNC_NAME s_scm_gethost
370312ae 136{
1d1559ce 137 SCM result = scm_c_make_vector (5, SCM_UNSPECIFIED);
370312ae
GH
138 SCM lst = SCM_EOL;
139 struct hostent *entry;
140 struct in_addr inad;
141 char **argv;
142 int i = 0;
7f9994d9 143
d46e4713 144 if (SCM_UNBNDP (host))
370312ae 145 {
cd34a384 146#ifdef HAVE_GETHOSTENT
370312ae 147 entry = gethostent ();
cd34a384
JB
148#else
149 entry = NULL;
150#endif
07513939
JB
151 if (! entry)
152 {
153 /* As far as I can tell, there's no good way to tell whether
154 zero means an error or end-of-file. The trick of
155 clearing errno before calling gethostent and checking it
156 afterwards doesn't cut it, because, on Linux, it seems to
157 try to contact some other server (YP?) and fails, which
158 is a benign failure. */
07513939
JB
159 return SCM_BOOL_F;
160 }
370312ae 161 }
7f9994d9 162 else if (scm_is_string (host))
370312ae 163 {
7f9994d9
MV
164 char *str = scm_to_locale_string (host);
165 entry = gethostbyname (str);
166 free (str);
370312ae
GH
167 }
168 else
169 {
7f9994d9 170 inad.s_addr = htonl (scm_to_ulong (host));
370312ae
GH
171 entry = gethostbyaddr ((char *) &inad, sizeof (inad), AF_INET);
172 }
7f9994d9 173
370312ae 174 if (!entry)
d46e4713 175 scm_resolv_error (FUNC_NAME, host);
5c11cc9d 176
4057a3e0
MV
177 SCM_SIMPLE_VECTOR_SET(result, 0, scm_from_locale_string (entry->h_name));
178 SCM_SIMPLE_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->h_aliases));
179 SCM_SIMPLE_VECTOR_SET(result, 2, scm_from_int (entry->h_addrtype));
180 SCM_SIMPLE_VECTOR_SET(result, 3, scm_from_int (entry->h_length));
370312ae
GH
181 if (sizeof (struct in_addr) != entry->h_length)
182 {
4057a3e0 183 SCM_SIMPLE_VECTOR_SET(result, 4, SCM_BOOL_F);
1d1559ce 184 return result;
370312ae
GH
185 }
186 for (argv = entry->h_addr_list; argv[i]; i++);
187 while (i--)
188 {
189 inad = *(struct in_addr *) argv[i];
b9bd8526 190 lst = scm_cons (scm_from_ulong (ntohl (inad.s_addr)), lst);
370312ae 191 }
4057a3e0 192 SCM_SIMPLE_VECTOR_SET(result, 4, lst);
1d1559ce 193 return result;
370312ae 194}
1bbd0b84 195#undef FUNC_NAME
370312ae
GH
196
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
6063dc1d 260#if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
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
6063dc1d 311#if defined (HAVE_GETSERVENT) || defined (__MINGW32__)
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
MV
353
354 scm_frame_begin (0);
355
356 protoname = scm_to_locale_string (protocol);
357 scm_frame_free (protoname);
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
375 scm_frame_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
6063dc1d 413#if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__)
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
6063dc1d 429#if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__)
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
GH
444
445
446void
447scm_init_net_db ()
448{
370312ae 449 scm_add_feature ("net-db");
a0599745 450#include "libguile/net_db.x"
370312ae 451}
89e00824
ML
452
453/*
454 Local Variables:
455 c-file-style: "gnu"
456 End:
457*/