2002-07-20 Han-Wen <hanwen@cs.uu.nl>
[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
e6e2e95a
MD
52#include <errno.h>
53
a0599745
MD
54#include "libguile/_scm.h"
55#include "libguile/feature.h"
56#include "libguile/strings.h"
57#include "libguile/vectors.h"
370312ae 58
a0599745
MD
59#include "libguile/validate.h"
60#include "libguile/net_db.h"
370312ae
GH
61
62#ifdef HAVE_STRING_H
63#include <string.h>
64#endif
65
66#include <sys/types.h>
82893676 67
f87c105a 68#ifdef HAVE_WINSOCK2_H
82893676
MG
69#include <winsock2.h>
70#else
cae76441 71#include <sys/socket.h>
370312ae
GH
72#include <netdb.h>
73#include <netinet/in.h>
74#include <arpa/inet.h>
82893676 75#endif
370312ae 76
6063dc1d
SJ
77#ifdef __MINGW32__
78#include "win32-socket.h"
79#endif
80
e2c80166 81#if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__)
789ecc05
GH
82/* h_errno not found in netdb.h, maybe this will help. */
83extern int h_errno;
84#endif
85
66c73b76 86\f
370312ae 87
5c11cc9d
GH
88SCM_SYMBOL (scm_host_not_found_key, "host-not-found");
89SCM_SYMBOL (scm_try_again_key, "try-again");
90SCM_SYMBOL (scm_no_recovery_key, "no-recovery");
91SCM_SYMBOL (scm_no_data_key, "no-data");
370312ae 92
5c11cc9d
GH
93static void scm_resolv_error (const char *subr, SCM bad_value)
94{
5a5f3646 95#ifdef NETDB_INTERNAL
5c11cc9d
GH
96 if (h_errno == NETDB_INTERNAL)
97 {
98 /* errno supposedly contains a useful value. */
99 scm_syserror (subr);
100 }
101 else
5a5f3646 102#endif
5c11cc9d
GH
103 {
104 SCM key;
105 const char *errmsg;
106
107 switch (h_errno)
108 {
109 case HOST_NOT_FOUND:
110 key = scm_host_not_found_key;
111 errmsg = "Unknown host";
112 break;
113 case TRY_AGAIN:
114 key = scm_try_again_key;
115 errmsg = "Host name lookup failure";
116 break;
117 case NO_RECOVERY:
118 key = scm_no_recovery_key;
119 errmsg = "Unknown server error";
120 break;
121 case NO_DATA:
122 key = scm_no_data_key;
123 errmsg = "No address associated with name";
124 break;
125 default:
126 scm_misc_error (subr, "Unknown resolver error", SCM_EOL);
127 errmsg = NULL;
128 }
129
130#ifdef HAVE_HSTRERROR
d9b6c170 131 errmsg = (const char *) hstrerror (h_errno);
5c11cc9d
GH
132#endif
133 scm_error (key, subr, errmsg, scm_cons (bad_value, SCM_EOL), SCM_EOL);
134 }
135}
136
137/* Should take an extra arg for address format (will be needed for IPv6).
138 Should use reentrant facilities if available.
370312ae
GH
139 */
140
a1ec6916 141SCM_DEFINE (scm_gethost, "gethost", 0, 1, 0,
d46e4713 142 (SCM host),
8f85c0c6
NJ
143 "@deffnx {Scheme Procedure} gethostbyname hostname\n"
144 "@deffnx {Scheme Procedure} gethostbyaddr address\n"
b380b885
MD
145 "Look up a host by name or address, returning a host object. The\n"
146 "@code{gethost} procedure will accept either a string name or an integer\n"
147 "address; if given no arguments, it behaves like @code{gethostent} (see\n"
148 "below). If a name or address is supplied but the address can not be\n"
149 "found, an error will be thrown to one of the keys:\n"
150 "@code{host-not-found}, @code{try-again}, @code{no-recovery} or\n"
151 "@code{no-data}, corresponding to the equivalent @code{h_error} values.\n"
152 "Unusual conditions may result in errors thrown to the\n"
153 "@code{system-error} or @code{misc_error} keys.")
1bbd0b84 154#define FUNC_NAME s_scm_gethost
370312ae 155{
00ffa0e7 156 SCM ans = scm_c_make_vector (5, SCM_UNSPECIFIED);
34d19ef6 157 SCM *ve = SCM_WRITABLE_VELTS (ans);
370312ae
GH
158 SCM lst = SCM_EOL;
159 struct hostent *entry;
160 struct in_addr inad;
161 char **argv;
162 int i = 0;
d46e4713 163 if (SCM_UNBNDP (host))
370312ae 164 {
cd34a384 165#ifdef HAVE_GETHOSTENT
370312ae 166 entry = gethostent ();
cd34a384
JB
167#else
168 entry = NULL;
169#endif
07513939
JB
170 if (! entry)
171 {
172 /* As far as I can tell, there's no good way to tell whether
173 zero means an error or end-of-file. The trick of
174 clearing errno before calling gethostent and checking it
175 afterwards doesn't cut it, because, on Linux, it seems to
176 try to contact some other server (YP?) and fails, which
177 is a benign failure. */
07513939
JB
178 return SCM_BOOL_F;
179 }
370312ae 180 }
a6d9e5ab 181 else if (SCM_STRINGP (host))
370312ae 182 {
a6d9e5ab 183 entry = gethostbyname (SCM_STRING_CHARS (host));
370312ae
GH
184 }
185 else
186 {
e4b265d8 187 inad.s_addr = htonl (SCM_NUM2ULONG (1, host));
370312ae
GH
188 entry = gethostbyaddr ((char *) &inad, sizeof (inad), AF_INET);
189 }
370312ae 190 if (!entry)
d46e4713 191 scm_resolv_error (FUNC_NAME, host);
5c11cc9d 192
34d19ef6
HWN
193 SCM_VECTOR_SET(ans, 0, scm_mem2string (entry->h_name, strlen (entry->h_name)));
194 SCM_VECTOR_SET(ans, 1, scm_makfromstrs (-1, entry->h_aliases));
195 SCM_VECTOR_SET(ans, 2, SCM_MAKINUM (entry->h_addrtype + 0L));
196 SCM_VECTOR_SET(ans, 3, SCM_MAKINUM (entry->h_length + 0L));
370312ae
GH
197 if (sizeof (struct in_addr) != entry->h_length)
198 {
34d19ef6 199 SCM_VECTOR_SET(ans, 4, SCM_BOOL_F);
370312ae
GH
200 return ans;
201 }
202 for (argv = entry->h_addr_list; argv[i]; i++);
203 while (i--)
204 {
205 inad = *(struct in_addr *) argv[i];
206 lst = scm_cons (scm_ulong2num (ntohl (inad.s_addr)), lst);
207 }
34d19ef6 208 SCM_VECTOR_SET(ans, 4, lst);
370312ae
GH
209 return ans;
210}
1bbd0b84 211#undef FUNC_NAME
370312ae
GH
212
213
07513939
JB
214/* In all subsequent getMUMBLE functions, when we're called with no
215 arguments, we're supposed to traverse the tables entry by entry.
216 However, there doesn't seem to be any documented way to distinguish
217 between end-of-table and an error; in both cases the functions
218 return zero. Gotta love Unix. For the time being, we clear errno,
219 and if we get a zero and errno is set, we signal an error. This
220 doesn't seem quite right (what if errno gets set as part of healthy
221 operation?), but it seems to work okay. We'll see. */
222
0e958795 223#if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
a1ec6916 224SCM_DEFINE (scm_getnet, "getnet", 0, 1, 0,
d46e4713 225 (SCM net),
8f85c0c6
NJ
226 "@deffnx {Scheme Procedure} getnetbyname net-name\n"
227 "@deffnx {Scheme Procedure} getnetbyaddr net-number\n"
b380b885
MD
228 "Look up a network by name or net number in the network database. The\n"
229 "@var{net-name} argument must be a string, and the @var{net-number}\n"
230 "argument must be an integer. @code{getnet} will accept either type of\n"
231 "argument, behaving like @code{getnetent} (see below) if no arguments are\n"
232 "given.")
1bbd0b84 233#define FUNC_NAME s_scm_getnet
370312ae
GH
234{
235 SCM ans;
236 SCM *ve;
237 struct netent *entry;
238
00ffa0e7 239 ans = scm_c_make_vector (4, SCM_UNSPECIFIED);
34d19ef6
HWN
240 ve = SCM_WRITABLE_VELTS (ans);
241
d46e4713 242 if (SCM_UNBNDP (net))
370312ae 243 {
370312ae 244 entry = getnetent ();
07513939
JB
245 if (! entry)
246 {
1dd05fd8
MG
247 /* There's no good way to tell whether zero means an error
248 or end-of-file, so we always return #f. See `gethost'
249 for details. */
250 return SCM_BOOL_F;
07513939 251 }
370312ae 252 }
a6d9e5ab 253 else if (SCM_STRINGP (net))
370312ae 254 {
a6d9e5ab 255 entry = getnetbyname (SCM_STRING_CHARS (net));
370312ae
GH
256 }
257 else
258 {
259 unsigned long netnum;
d46e4713 260 netnum = SCM_NUM2ULONG (1, net);
370312ae
GH
261 entry = getnetbyaddr (netnum, AF_INET);
262 }
370312ae 263 if (!entry)
1afff620 264 SCM_SYSERROR_MSG ("no such network ~A", scm_list_1 (net), errno);
34d19ef6
HWN
265 SCM_VECTOR_SET(ans, 0, scm_mem2string (entry->n_name, strlen (entry->n_name)));
266 SCM_VECTOR_SET(ans, 1, scm_makfromstrs (-1, entry->n_aliases));
267 SCM_VECTOR_SET(ans, 2, SCM_MAKINUM (entry->n_addrtype + 0L));
268 SCM_VECTOR_SET(ans, 3, scm_ulong2num (entry->n_net + 0L));
370312ae
GH
269 return ans;
270}
1bbd0b84 271#undef FUNC_NAME
0e958795 272#endif
370312ae 273
6063dc1d 274#if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
a1ec6916 275SCM_DEFINE (scm_getproto, "getproto", 0, 1, 0,
d46e4713 276 (SCM protocol),
8f85c0c6
NJ
277 "@deffnx {Scheme Procedure} getprotobyname name\n"
278 "@deffnx {Scheme Procedure} getprotobynumber number\n"
b380b885
MD
279 "Look up a network protocol by name or by number. @code{getprotobyname}\n"
280 "takes a string argument, and @code{getprotobynumber} takes an integer\n"
281 "argument. @code{getproto} will accept either type, behaving like\n"
282 "@code{getprotoent} (see below) if no arguments are supplied.")
1bbd0b84 283#define FUNC_NAME s_scm_getproto
370312ae
GH
284{
285 SCM ans;
286 SCM *ve;
287 struct protoent *entry;
288
00ffa0e7 289 ans = scm_c_make_vector (3, SCM_UNSPECIFIED);
34d19ef6 290 ve = SCM_WRITABLE_VELTS (ans);
d46e4713 291 if (SCM_UNBNDP (protocol))
370312ae 292 {
370312ae 293 entry = getprotoent ();
07513939
JB
294 if (! entry)
295 {
1dd05fd8
MG
296 /* There's no good way to tell whether zero means an error
297 or end-of-file, so we always return #f. See `gethost'
298 for details. */
299 return SCM_BOOL_F;
07513939 300 }
370312ae 301 }
a6d9e5ab 302 else if (SCM_STRINGP (protocol))
370312ae 303 {
a6d9e5ab 304 entry = getprotobyname (SCM_STRING_CHARS (protocol));
370312ae
GH
305 }
306 else
307 {
308 unsigned long protonum;
e4b265d8 309 protonum = SCM_NUM2ULONG (1, protocol);
370312ae
GH
310 entry = getprotobynumber (protonum);
311 }
370312ae 312 if (!entry)
1afff620 313 SCM_SYSERROR_MSG ("no such protocol ~A", scm_list_1 (protocol), errno);
34d19ef6
HWN
314 SCM_VECTOR_SET(ans, 0, scm_mem2string (entry->p_name, strlen (entry->p_name)));
315 SCM_VECTOR_SET(ans, 1, scm_makfromstrs (-1, entry->p_aliases));
316 SCM_VECTOR_SET(ans, 2, SCM_MAKINUM (entry->p_proto + 0L));
370312ae
GH
317 return ans;
318}
1bbd0b84 319#undef FUNC_NAME
0e958795 320#endif
370312ae 321
6063dc1d 322#if defined (HAVE_GETSERVENT) || defined (__MINGW32__)
370312ae 323static SCM
1bbd0b84 324scm_return_entry (struct servent *entry)
370312ae
GH
325{
326 SCM ans;
327 SCM *ve;
328
00ffa0e7 329 ans = scm_c_make_vector (4, SCM_UNSPECIFIED);
34d19ef6
HWN
330 ve = SCM_WRITABLE_VELTS (ans);
331 SCM_VECTOR_SET(ans, 0, scm_mem2string (entry->s_name, strlen (entry->s_name)));
332 SCM_VECTOR_SET(ans, 1, scm_makfromstrs (-1, entry->s_aliases));
333 SCM_VECTOR_SET(ans, 2, SCM_MAKINUM (ntohs (entry->s_port) + 0L));
334 SCM_VECTOR_SET(ans, 3, scm_mem2string (entry->s_proto, strlen (entry->s_proto)));
370312ae
GH
335 return ans;
336}
337
a1ec6916 338SCM_DEFINE (scm_getserv, "getserv", 0, 2, 0,
d46e4713 339 (SCM name, SCM protocol),
8f85c0c6
NJ
340 "@deffnx {Scheme Procedure} getservbyname name protocol\n"
341 "@deffnx {Scheme Procedure} getservbyport port protocol\n"
b380b885
MD
342 "Look up a network service by name or by service number, and return a\n"
343 "network service object. The @var{protocol} argument specifies the name\n"
344 "of the desired protocol; if the protocol found in the network service\n"
345 "database does not match this name, a system error is signalled.\n\n"
346 "The @code{getserv} procedure will take either a service name or number\n"
347 "as its first argument; if given no arguments, it behaves like\n"
348 "@code{getservent} (see below).")
1bbd0b84 349#define FUNC_NAME s_scm_getserv
370312ae
GH
350{
351 struct servent *entry;
352 if (SCM_UNBNDP (name))
353 {
370312ae 354 entry = getservent ();
07513939
JB
355 if (!entry)
356 {
1dd05fd8
MG
357 /* There's no good way to tell whether zero means an error
358 or end-of-file, so we always return #f. See `gethost'
359 for details. */
360 return SCM_BOOL_F;
07513939 361 }
370312ae
GH
362 return scm_return_entry (entry);
363 }
a6d9e5ab 364 SCM_VALIDATE_STRING (2, protocol);
a6d9e5ab 365 if (SCM_STRINGP (name))
370312ae 366 {
a6d9e5ab 367 entry = getservbyname (SCM_STRING_CHARS (name), SCM_STRING_CHARS (protocol));
370312ae
GH
368 }
369 else
370 {
34d19ef6 371 SCM_VALIDATE_INUM (1, name);
a6d9e5ab 372 entry = getservbyport (htons (SCM_INUM (name)), SCM_STRING_CHARS (protocol));
370312ae
GH
373 }
374 if (!entry)
1afff620 375 SCM_SYSERROR_MSG("no such service ~A", scm_list_1 (name), errno);
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
36284627 391 sethostent (!SCM_FALSEP (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
36284627 407 setnetent (!SCM_FALSEP (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
36284627 423 setprotoent (!SCM_FALSEP (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
36284627 439 setservent (!SCM_FALSEP (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*/