*** empty log message ***
[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
GH
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This program 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
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this software; see the file COPYING. If not, write to
82892bed
JB
16 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307 USA
370312ae
GH
18 *
19 * As a special exception, the Free Software Foundation gives permission
20 * for additional uses of the text contained in its release of GUILE.
21 *
22 * The exception is that, if you link the GUILE library with other files
23 * to produce an executable, this does not by itself cause the
24 * resulting executable to be covered by the GNU General Public License.
25 * Your use of that executable is in no way restricted on account of
26 * linking the GUILE library code into it.
27 *
28 * This exception does not however invalidate any other reasons why
29 * the executable file might be covered by the GNU General Public License.
30 *
31 * This exception applies only to the code released by the
32 * Free Software Foundation under the name GUILE. If you copy
33 * code from other Free Software Foundation releases into a copy of
34 * GUILE, as the General Public License permits, the exception does
35 * not apply to the code that you add in this way. To avoid misleading
36 * anyone as to the status of such modified files, you must delete
37 * this exception notice from them.
38 *
39 * If you write modifications of your own for GUILE, it is your choice
40 * whether to permit this exception to apply to your modifications.
82892bed 41 * If you do not wish that, delete this exception notice. */
370312ae 42
1bbd0b84
GB
43
44
370312ae
GH
45/* Written in 1994 by Aubrey Jaffer.
46 * Thanks to Hallvard.Tretteberg@si.sintef.no for inspiration and discussion.
47 * Rewritten by Gary Houston to be a closer interface to the C socket library.
48 * Split into net_db.c and socket.c.
49 */
50\f
51
83b429ed
RB
52#if HAVE_CONFIG_H
53# include <config.h>
54#endif
55
e6e2e95a
MD
56#include <errno.h>
57
a0599745
MD
58#include "libguile/_scm.h"
59#include "libguile/feature.h"
60#include "libguile/strings.h"
61#include "libguile/vectors.h"
370312ae 62
a0599745
MD
63#include "libguile/validate.h"
64#include "libguile/net_db.h"
370312ae
GH
65
66#ifdef HAVE_STRING_H
67#include <string.h>
68#endif
69
70#include <sys/types.h>
82893676 71
f87c105a 72#ifdef HAVE_WINSOCK2_H
82893676
MG
73#include <winsock2.h>
74#else
cae76441 75#include <sys/socket.h>
370312ae
GH
76#include <netdb.h>
77#include <netinet/in.h>
78#include <arpa/inet.h>
82893676 79#endif
370312ae 80
6063dc1d
SJ
81#ifdef __MINGW32__
82#include "win32-socket.h"
83#endif
84
e2c80166 85#if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__)
789ecc05
GH
86/* h_errno not found in netdb.h, maybe this will help. */
87extern int h_errno;
88#endif
89
66c73b76 90\f
370312ae 91
5c11cc9d
GH
92SCM_SYMBOL (scm_host_not_found_key, "host-not-found");
93SCM_SYMBOL (scm_try_again_key, "try-again");
94SCM_SYMBOL (scm_no_recovery_key, "no-recovery");
95SCM_SYMBOL (scm_no_data_key, "no-data");
370312ae 96
5c11cc9d
GH
97static void scm_resolv_error (const char *subr, SCM bad_value)
98{
5a5f3646 99#ifdef NETDB_INTERNAL
5c11cc9d
GH
100 if (h_errno == NETDB_INTERNAL)
101 {
102 /* errno supposedly contains a useful value. */
103 scm_syserror (subr);
104 }
105 else
5a5f3646 106#endif
5c11cc9d
GH
107 {
108 SCM key;
109 const char *errmsg;
110
111 switch (h_errno)
112 {
113 case HOST_NOT_FOUND:
114 key = scm_host_not_found_key;
115 errmsg = "Unknown host";
116 break;
117 case TRY_AGAIN:
118 key = scm_try_again_key;
119 errmsg = "Host name lookup failure";
120 break;
121 case NO_RECOVERY:
122 key = scm_no_recovery_key;
123 errmsg = "Unknown server error";
124 break;
125 case NO_DATA:
126 key = scm_no_data_key;
127 errmsg = "No address associated with name";
128 break;
129 default:
130 scm_misc_error (subr, "Unknown resolver error", SCM_EOL);
131 errmsg = NULL;
132 }
133
134#ifdef HAVE_HSTRERROR
d9b6c170 135 errmsg = (const char *) hstrerror (h_errno);
5c11cc9d
GH
136#endif
137 scm_error (key, subr, errmsg, scm_cons (bad_value, SCM_EOL), SCM_EOL);
138 }
139}
140
141/* Should take an extra arg for address format (will be needed for IPv6).
142 Should use reentrant facilities if available.
370312ae
GH
143 */
144
a1ec6916 145SCM_DEFINE (scm_gethost, "gethost", 0, 1, 0,
d46e4713 146 (SCM host),
8f85c0c6
NJ
147 "@deffnx {Scheme Procedure} gethostbyname hostname\n"
148 "@deffnx {Scheme Procedure} gethostbyaddr address\n"
b380b885
MD
149 "Look up a host by name or address, returning a host object. The\n"
150 "@code{gethost} procedure will accept either a string name or an integer\n"
151 "address; if given no arguments, it behaves like @code{gethostent} (see\n"
152 "below). If a name or address is supplied but the address can not be\n"
153 "found, an error will be thrown to one of the keys:\n"
154 "@code{host-not-found}, @code{try-again}, @code{no-recovery} or\n"
155 "@code{no-data}, corresponding to the equivalent @code{h_error} values.\n"
156 "Unusual conditions may result in errors thrown to the\n"
157 "@code{system-error} or @code{misc_error} keys.")
1bbd0b84 158#define FUNC_NAME s_scm_gethost
370312ae 159{
1d1559ce 160 SCM result = scm_c_make_vector (5, SCM_UNSPECIFIED);
370312ae
GH
161 SCM lst = SCM_EOL;
162 struct hostent *entry;
163 struct in_addr inad;
164 char **argv;
165 int i = 0;
d46e4713 166 if (SCM_UNBNDP (host))
370312ae 167 {
cd34a384 168#ifdef HAVE_GETHOSTENT
370312ae 169 entry = gethostent ();
cd34a384
JB
170#else
171 entry = NULL;
172#endif
07513939
JB
173 if (! entry)
174 {
175 /* As far as I can tell, there's no good way to tell whether
176 zero means an error or end-of-file. The trick of
177 clearing errno before calling gethostent and checking it
178 afterwards doesn't cut it, because, on Linux, it seems to
179 try to contact some other server (YP?) and fails, which
180 is a benign failure. */
07513939
JB
181 return SCM_BOOL_F;
182 }
370312ae 183 }
a6d9e5ab 184 else if (SCM_STRINGP (host))
370312ae 185 {
a6d9e5ab 186 entry = gethostbyname (SCM_STRING_CHARS (host));
370312ae
GH
187 }
188 else
189 {
e4b265d8 190 inad.s_addr = htonl (SCM_NUM2ULONG (1, host));
370312ae
GH
191 entry = gethostbyaddr ((char *) &inad, sizeof (inad), AF_INET);
192 }
370312ae 193 if (!entry)
d46e4713 194 scm_resolv_error (FUNC_NAME, host);
5c11cc9d 195
1d1559ce
HWN
196 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->h_name, strlen (entry->h_name)));
197 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->h_aliases));
198 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (entry->h_addrtype + 0L));
199 SCM_VECTOR_SET(result, 3, SCM_MAKINUM (entry->h_length + 0L));
370312ae
GH
200 if (sizeof (struct in_addr) != entry->h_length)
201 {
1d1559ce
HWN
202 SCM_VECTOR_SET(result, 4, SCM_BOOL_F);
203 return result;
370312ae
GH
204 }
205 for (argv = entry->h_addr_list; argv[i]; i++);
206 while (i--)
207 {
208 inad = *(struct in_addr *) argv[i];
209 lst = scm_cons (scm_ulong2num (ntohl (inad.s_addr)), lst);
210 }
1d1559ce
HWN
211 SCM_VECTOR_SET(result, 4, lst);
212 return result;
370312ae 213}
1bbd0b84 214#undef FUNC_NAME
370312ae
GH
215
216
07513939
JB
217/* In all subsequent getMUMBLE functions, when we're called with no
218 arguments, we're supposed to traverse the tables entry by entry.
219 However, there doesn't seem to be any documented way to distinguish
220 between end-of-table and an error; in both cases the functions
221 return zero. Gotta love Unix. For the time being, we clear errno,
222 and if we get a zero and errno is set, we signal an error. This
223 doesn't seem quite right (what if errno gets set as part of healthy
224 operation?), but it seems to work okay. We'll see. */
225
0e958795 226#if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
a1ec6916 227SCM_DEFINE (scm_getnet, "getnet", 0, 1, 0,
d46e4713 228 (SCM net),
8f85c0c6
NJ
229 "@deffnx {Scheme Procedure} getnetbyname net-name\n"
230 "@deffnx {Scheme Procedure} getnetbyaddr net-number\n"
b380b885
MD
231 "Look up a network by name or net number in the network database. The\n"
232 "@var{net-name} argument must be a string, and the @var{net-number}\n"
233 "argument must be an integer. @code{getnet} will accept either type of\n"
234 "argument, behaving like @code{getnetent} (see below) if no arguments are\n"
235 "given.")
1bbd0b84 236#define FUNC_NAME s_scm_getnet
370312ae 237{
1d1559ce 238 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
370312ae
GH
239 struct netent *entry;
240
d46e4713 241 if (SCM_UNBNDP (net))
370312ae 242 {
370312ae 243 entry = getnetent ();
07513939
JB
244 if (! entry)
245 {
1dd05fd8
MG
246 /* There's no good way to tell whether zero means an error
247 or end-of-file, so we always return #f. See `gethost'
248 for details. */
249 return SCM_BOOL_F;
07513939 250 }
370312ae 251 }
a6d9e5ab 252 else if (SCM_STRINGP (net))
370312ae 253 {
a6d9e5ab 254 entry = getnetbyname (SCM_STRING_CHARS (net));
370312ae
GH
255 }
256 else
257 {
258 unsigned long netnum;
d46e4713 259 netnum = SCM_NUM2ULONG (1, net);
370312ae
GH
260 entry = getnetbyaddr (netnum, AF_INET);
261 }
370312ae 262 if (!entry)
1afff620 263 SCM_SYSERROR_MSG ("no such network ~A", scm_list_1 (net), errno);
1d1559ce
HWN
264 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->n_name, strlen (entry->n_name)));
265 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->n_aliases));
266 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (entry->n_addrtype + 0L));
267 SCM_VECTOR_SET(result, 3, scm_ulong2num (entry->n_net + 0L));
268 return result;
370312ae 269}
1bbd0b84 270#undef FUNC_NAME
0e958795 271#endif
370312ae 272
6063dc1d 273#if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
a1ec6916 274SCM_DEFINE (scm_getproto, "getproto", 0, 1, 0,
d46e4713 275 (SCM protocol),
8f85c0c6
NJ
276 "@deffnx {Scheme Procedure} getprotobyname name\n"
277 "@deffnx {Scheme Procedure} getprotobynumber number\n"
b380b885
MD
278 "Look up a network protocol by name or by number. @code{getprotobyname}\n"
279 "takes a string argument, and @code{getprotobynumber} takes an integer\n"
280 "argument. @code{getproto} will accept either type, behaving like\n"
281 "@code{getprotoent} (see below) if no arguments are supplied.")
1bbd0b84 282#define FUNC_NAME s_scm_getproto
370312ae 283{
1d1559ce 284 SCM result = scm_c_make_vector (3, SCM_UNSPECIFIED);
370312ae 285
1d1559ce 286 struct protoent *entry;
d46e4713 287 if (SCM_UNBNDP (protocol))
370312ae 288 {
370312ae 289 entry = getprotoent ();
07513939
JB
290 if (! entry)
291 {
1dd05fd8
MG
292 /* There's no good way to tell whether zero means an error
293 or end-of-file, so we always return #f. See `gethost'
294 for details. */
295 return SCM_BOOL_F;
07513939 296 }
370312ae 297 }
a6d9e5ab 298 else if (SCM_STRINGP (protocol))
370312ae 299 {
a6d9e5ab 300 entry = getprotobyname (SCM_STRING_CHARS (protocol));
370312ae
GH
301 }
302 else
303 {
304 unsigned long protonum;
e4b265d8 305 protonum = SCM_NUM2ULONG (1, protocol);
370312ae
GH
306 entry = getprotobynumber (protonum);
307 }
370312ae 308 if (!entry)
1afff620 309 SCM_SYSERROR_MSG ("no such protocol ~A", scm_list_1 (protocol), errno);
1d1559ce
HWN
310 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->p_name, strlen (entry->p_name)));
311 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->p_aliases));
312 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (entry->p_proto + 0L));
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
1d1559ce
HWN
324 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->s_name, strlen (entry->s_name)));
325 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->s_aliases));
326 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (ntohs (entry->s_port) + 0L));
327 SCM_VECTOR_SET(result, 3, scm_mem2string (entry->s_proto, strlen (entry->s_proto)));
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;
345 if (SCM_UNBNDP (name))
346 {
370312ae 347 entry = getservent ();
07513939
JB
348 if (!entry)
349 {
1dd05fd8
MG
350 /* There's no good way to tell whether zero means an error
351 or end-of-file, so we always return #f. See `gethost'
352 for details. */
353 return SCM_BOOL_F;
07513939 354 }
370312ae
GH
355 return scm_return_entry (entry);
356 }
a6d9e5ab 357 SCM_VALIDATE_STRING (2, protocol);
a6d9e5ab 358 if (SCM_STRINGP (name))
370312ae 359 {
a6d9e5ab 360 entry = getservbyname (SCM_STRING_CHARS (name), SCM_STRING_CHARS (protocol));
370312ae
GH
361 }
362 else
363 {
34d19ef6 364 SCM_VALIDATE_INUM (1, name);
a6d9e5ab 365 entry = getservbyport (htons (SCM_INUM (name)), SCM_STRING_CHARS (protocol));
370312ae
GH
366 }
367 if (!entry)
1afff620 368 SCM_SYSERROR_MSG("no such service ~A", scm_list_1 (name), errno);
370312ae
GH
369 return scm_return_entry (entry);
370}
1bbd0b84 371#undef FUNC_NAME
0e958795 372#endif
370312ae 373
0e958795 374#if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
a1ec6916 375SCM_DEFINE (scm_sethost, "sethost", 0, 1, 0,
d46e4713 376 (SCM stayopen),
b380b885
MD
377 "If @var{stayopen} is omitted, this is equivalent to @code{endhostent}.\n"
378 "Otherwise it is equivalent to @code{sethostent stayopen}.")
1bbd0b84 379#define FUNC_NAME s_scm_sethost
370312ae 380{
d46e4713 381 if (SCM_UNBNDP (stayopen))
370312ae
GH
382 endhostent ();
383 else
36284627 384 sethostent (!SCM_FALSEP (stayopen));
370312ae
GH
385 return SCM_UNSPECIFIED;
386}
1bbd0b84 387#undef FUNC_NAME
0e958795 388#endif
370312ae 389
0e958795 390#if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
a1ec6916 391SCM_DEFINE (scm_setnet, "setnet", 0, 1, 0,
d46e4713 392 (SCM stayopen),
b380b885
MD
393 "If @var{stayopen} is omitted, this is equivalent to @code{endnetent}.\n"
394 "Otherwise it is equivalent to @code{setnetent stayopen}.")
1bbd0b84 395#define FUNC_NAME s_scm_setnet
370312ae 396{
d46e4713 397 if (SCM_UNBNDP (stayopen))
370312ae
GH
398 endnetent ();
399 else
36284627 400 setnetent (!SCM_FALSEP (stayopen));
370312ae
GH
401 return SCM_UNSPECIFIED;
402}
1bbd0b84 403#undef FUNC_NAME
0e958795 404#endif
370312ae 405
6063dc1d 406#if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__)
a1ec6916 407SCM_DEFINE (scm_setproto, "setproto", 0, 1, 0,
d46e4713 408 (SCM stayopen),
b380b885
MD
409 "If @var{stayopen} is omitted, this is equivalent to @code{endprotoent}.\n"
410 "Otherwise it is equivalent to @code{setprotoent stayopen}.")
1bbd0b84 411#define FUNC_NAME s_scm_setproto
370312ae 412{
d46e4713 413 if (SCM_UNBNDP (stayopen))
370312ae
GH
414 endprotoent ();
415 else
36284627 416 setprotoent (!SCM_FALSEP (stayopen));
370312ae
GH
417 return SCM_UNSPECIFIED;
418}
1bbd0b84 419#undef FUNC_NAME
0e958795 420#endif
370312ae 421
6063dc1d 422#if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__)
a1ec6916 423SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0,
d46e4713 424 (SCM stayopen),
b380b885
MD
425 "If @var{stayopen} is omitted, this is equivalent to @code{endservent}.\n"
426 "Otherwise it is equivalent to @code{setservent stayopen}.")
1bbd0b84 427#define FUNC_NAME s_scm_setserv
370312ae 428{
d46e4713 429 if (SCM_UNBNDP (stayopen))
370312ae
GH
430 endservent ();
431 else
36284627 432 setservent (!SCM_FALSEP (stayopen));
370312ae
GH
433 return SCM_UNSPECIFIED;
434}
1bbd0b84 435#undef FUNC_NAME
0e958795 436#endif
370312ae
GH
437
438
439void
440scm_init_net_db ()
441{
370312ae 442 scm_add_feature ("net-db");
a0599745 443#include "libguile/net_db.x"
370312ae 444}
89e00824
ML
445
446/*
447 Local Variables:
448 c-file-style: "gnu"
449 End:
450*/