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