* *.c: Pervasive software-engineering-motivated rewrite of
[bpt/guile.git] / libguile / net_db.c
CommitLineData
370312ae 1/* "net_db.c" network database support
e6393a4a 2 * Copyright (C) 1995, 1996, 1997, 1998, 1999 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
54#include <stdio.h>
55#include "_scm.h"
56#include "feature.h"
57
1bbd0b84 58#include "scm_validate.h"
370312ae
GH
59#include "net_db.h"
60
61#ifdef HAVE_STRING_H
62#include <string.h>
63#endif
64
65#include <sys/types.h>
cae76441 66#include <sys/socket.h>
370312ae
GH
67#include <netdb.h>
68#include <netinet/in.h>
69#include <arpa/inet.h>
70
e6393a4a
JB
71/* Some systems do not declare this. Some systems do declare it, as a
72 macro. */
73#ifndef h_errno
7a98cdb9 74extern int h_errno;
e6393a4a 75#endif
7a98cdb9 76
370312ae
GH
77\f
78
79#ifndef STDC_HEADERS
80int close ();
81#endif /* STDC_HEADERS */
82
83extern int inet_aton ();
84
1bbd0b84
GB
85GUILE_PROC (scm_inet_aton, "inet-aton", 1, 0, 0,
86 (SCM address),
87"")
88#define FUNC_NAME s_scm_inet_aton
370312ae
GH
89{
90 struct in_addr soka;
91
1bbd0b84 92 SCM_VALIDATE_ROSTRING(1,address);
370312ae
GH
93 if (SCM_SUBSTRP (address))
94 address = scm_makfromstr (SCM_ROCHARS (address), SCM_ROLENGTH (address), 0);
95 if (inet_aton (SCM_ROCHARS (address), &soka) == 0)
1bbd0b84 96 SCM_MISC_ERROR ("bad address", SCM_EOL);
370312ae
GH
97 return scm_ulong2num (ntohl (soka.s_addr));
98}
1bbd0b84 99#undef FUNC_NAME
370312ae
GH
100
101
1bbd0b84
GB
102GUILE_PROC (scm_inet_ntoa, "inet-ntoa", 1, 0, 0,
103 (SCM inetid),
104"")
105#define FUNC_NAME s_scm_inet_ntoa
370312ae
GH
106{
107 struct in_addr addr;
108 char *s;
109 SCM answer;
1bbd0b84 110 addr.s_addr = htonl (SCM_NUM2ULONG (1,inetid));
370312ae
GH
111 s = inet_ntoa (addr);
112 answer = scm_makfromstr (s, strlen (s), 0);
370312ae
GH
113 return answer;
114}
1bbd0b84 115#undef FUNC_NAME
370312ae 116
0e958795 117#ifdef HAVE_INET_NETOF
1bbd0b84
GB
118GUILE_PROC (scm_inet_netof, "inet-netof", 1, 0, 0,
119 (SCM address),
120"")
121#define FUNC_NAME s_scm_inet_netof
370312ae
GH
122{
123 struct in_addr addr;
1bbd0b84 124 addr.s_addr = htonl (SCM_NUM2ULONG (1,address));
370312ae
GH
125 return scm_ulong2num ((unsigned long) inet_netof (addr));
126}
1bbd0b84 127#undef FUNC_NAME
0e958795 128#endif
370312ae 129
0e958795 130#ifdef HAVE_INET_LNAOF
1bbd0b84
GB
131GUILE_PROC (scm_lnaof, "inet-lnaof", 1, 0, 0,
132 (SCM address),
133"")
134#define FUNC_NAME s_scm_lnaof
370312ae
GH
135{
136 struct in_addr addr;
1bbd0b84 137 addr.s_addr = htonl (SCM_NUM2ULONG (1,address));
370312ae
GH
138 return scm_ulong2num ((unsigned long) inet_lnaof (addr));
139}
1bbd0b84 140#undef FUNC_NAME
0e958795 141#endif
370312ae 142
0e958795 143#ifdef HAVE_INET_MAKEADDR
1bbd0b84
GB
144GUILE_PROC (scm_inet_makeaddr, "inet-makeaddr", 2, 0, 0,
145 (SCM net, SCM lna),
146"")
147#define FUNC_NAME s_scm_inet_makeaddr
370312ae
GH
148{
149 struct in_addr addr;
150 unsigned long netnum;
151 unsigned long lnanum;
152
1bbd0b84
GB
153 SCM_VALIDATE_INT_COPY(1,net,netnum);
154 SCM_VALIDATE_INT_COPY(2,lna,lnanum);
370312ae
GH
155 addr = inet_makeaddr (netnum, lnanum);
156 return scm_ulong2num (ntohl (addr.s_addr));
157}
1bbd0b84 158#undef FUNC_NAME
0e958795 159#endif
370312ae 160
5c11cc9d
GH
161SCM_SYMBOL (scm_host_not_found_key, "host-not-found");
162SCM_SYMBOL (scm_try_again_key, "try-again");
163SCM_SYMBOL (scm_no_recovery_key, "no-recovery");
164SCM_SYMBOL (scm_no_data_key, "no-data");
370312ae 165
5c11cc9d
GH
166static void scm_resolv_error (const char *subr, SCM bad_value)
167{
168 if (h_errno == NETDB_INTERNAL)
169 {
170 /* errno supposedly contains a useful value. */
171 scm_syserror (subr);
172 }
173 else
174 {
175 SCM key;
176 const char *errmsg;
177
178 switch (h_errno)
179 {
180 case HOST_NOT_FOUND:
181 key = scm_host_not_found_key;
182 errmsg = "Unknown host";
183 break;
184 case TRY_AGAIN:
185 key = scm_try_again_key;
186 errmsg = "Host name lookup failure";
187 break;
188 case NO_RECOVERY:
189 key = scm_no_recovery_key;
190 errmsg = "Unknown server error";
191 break;
192 case NO_DATA:
193 key = scm_no_data_key;
194 errmsg = "No address associated with name";
195 break;
196 default:
197 scm_misc_error (subr, "Unknown resolver error", SCM_EOL);
198 errmsg = NULL;
199 }
200
201#ifdef HAVE_HSTRERROR
202 errmsg = hstrerror (h_errno);
203#endif
204 scm_error (key, subr, errmsg, scm_cons (bad_value, SCM_EOL), SCM_EOL);
205 }
206}
207
208/* Should take an extra arg for address format (will be needed for IPv6).
209 Should use reentrant facilities if available.
370312ae
GH
210 */
211
1bbd0b84
GB
212GUILE_PROC (scm_gethost, "gethost", 0, 1, 0,
213 (SCM name),
214"")
215#define FUNC_NAME s_scm_gethost
370312ae 216{
a8741caa 217 SCM ans = scm_make_vector (SCM_MAKINUM (5), SCM_UNSPECIFIED);
370312ae
GH
218 SCM *ve = SCM_VELTS (ans);
219 SCM lst = SCM_EOL;
220 struct hostent *entry;
221 struct in_addr inad;
222 char **argv;
223 int i = 0;
370312ae
GH
224 if (SCM_UNBNDP (name))
225 {
cd34a384 226#ifdef HAVE_GETHOSTENT
370312ae 227 entry = gethostent ();
cd34a384
JB
228#else
229 entry = NULL;
230#endif
07513939
JB
231 if (! entry)
232 {
233 /* As far as I can tell, there's no good way to tell whether
234 zero means an error or end-of-file. The trick of
235 clearing errno before calling gethostent and checking it
236 afterwards doesn't cut it, because, on Linux, it seems to
237 try to contact some other server (YP?) and fails, which
238 is a benign failure. */
07513939
JB
239 return SCM_BOOL_F;
240 }
370312ae 241 }
ef12d978 242 else if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
370312ae 243 {
89958ad0 244 SCM_COERCE_SUBSTR (name);
ae2fa5bc 245 entry = gethostbyname (SCM_ROCHARS (name));
370312ae
GH
246 }
247 else
248 {
1bbd0b84 249 inad.s_addr = htonl (scm_num2ulong (name, (char *) SCM_ARG1, FUNC_NAME));
370312ae
GH
250 entry = gethostbyaddr ((char *) &inad, sizeof (inad), AF_INET);
251 }
370312ae 252 if (!entry)
1bbd0b84 253 scm_resolv_error (FUNC_NAME, name);
5c11cc9d
GH
254
255 ve[0] = scm_makfromstr (entry->h_name,
256 (scm_sizet) strlen (entry->h_name), 0);
370312ae
GH
257 ve[1] = scm_makfromstrs (-1, entry->h_aliases);
258 ve[2] = SCM_MAKINUM (entry->h_addrtype + 0L);
259 ve[3] = SCM_MAKINUM (entry->h_length + 0L);
260 if (sizeof (struct in_addr) != entry->h_length)
261 {
262 ve[4] = SCM_BOOL_F;
263 return ans;
264 }
265 for (argv = entry->h_addr_list; argv[i]; i++);
266 while (i--)
267 {
268 inad = *(struct in_addr *) argv[i];
269 lst = scm_cons (scm_ulong2num (ntohl (inad.s_addr)), lst);
270 }
271 ve[4] = lst;
272 return ans;
273}
1bbd0b84 274#undef FUNC_NAME
370312ae
GH
275
276
07513939
JB
277/* In all subsequent getMUMBLE functions, when we're called with no
278 arguments, we're supposed to traverse the tables entry by entry.
279 However, there doesn't seem to be any documented way to distinguish
280 between end-of-table and an error; in both cases the functions
281 return zero. Gotta love Unix. For the time being, we clear errno,
282 and if we get a zero and errno is set, we signal an error. This
283 doesn't seem quite right (what if errno gets set as part of healthy
284 operation?), but it seems to work okay. We'll see. */
285
0e958795 286#if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
1bbd0b84
GB
287GUILE_PROC (scm_getnet, "getnet", 0, 1, 0,
288 (SCM name),
289"")
290#define FUNC_NAME s_scm_getnet
370312ae
GH
291{
292 SCM ans;
293 SCM *ve;
294 struct netent *entry;
295
a8741caa 296 ans = scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED);
370312ae
GH
297 ve = SCM_VELTS (ans);
298 if (SCM_UNBNDP (name))
299 {
07513939 300 errno = 0;
370312ae 301 entry = getnetent ();
07513939
JB
302 if (! entry)
303 {
07513939 304 if (errno)
1bbd0b84 305 SCM_SYSERROR;
07513939
JB
306 else
307 return SCM_BOOL_F;
308 }
370312ae 309 }
ae2fa5bc 310 else if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
370312ae 311 {
89958ad0 312 SCM_COERCE_SUBSTR (name);
ae2fa5bc 313 entry = getnetbyname (SCM_ROCHARS (name));
370312ae
GH
314 }
315 else
316 {
317 unsigned long netnum;
1bbd0b84 318 netnum = scm_num2ulong (name, (char *) SCM_ARG1, FUNC_NAME);
370312ae
GH
319 entry = getnetbyaddr (netnum, AF_INET);
320 }
370312ae 321 if (!entry)
1bbd0b84 322 scm_syserror_msg (FUNC_NAME, "no such network %s",
07513939 323 scm_listify (name, SCM_UNDEFINED), errno);
370312ae
GH
324 ve[0] = scm_makfromstr (entry->n_name, (scm_sizet) strlen (entry->n_name), 0);
325 ve[1] = scm_makfromstrs (-1, entry->n_aliases);
326 ve[2] = SCM_MAKINUM (entry->n_addrtype + 0L);
327 ve[3] = scm_ulong2num (entry->n_net + 0L);
328 return ans;
329}
1bbd0b84 330#undef FUNC_NAME
0e958795 331#endif
370312ae 332
0e958795 333#ifdef HAVE_GETPROTOENT
1bbd0b84
GB
334GUILE_PROC (scm_getproto, "getproto", 0, 1, 0,
335 (SCM name),
336"")
337#define FUNC_NAME s_scm_getproto
370312ae
GH
338{
339 SCM ans;
340 SCM *ve;
341 struct protoent *entry;
342
a8741caa 343 ans = scm_make_vector (SCM_MAKINUM (3), SCM_UNSPECIFIED);
370312ae
GH
344 ve = SCM_VELTS (ans);
345 if (SCM_UNBNDP (name))
346 {
07513939 347 errno = 0;
370312ae 348 entry = getprotoent ();
07513939
JB
349 if (! entry)
350 {
07513939 351 if (errno)
1bbd0b84 352 SCM_SYSERROR;
07513939
JB
353 else
354 return SCM_BOOL_F;
355 }
370312ae 356 }
ae2fa5bc 357 else if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
370312ae 358 {
89958ad0 359 SCM_COERCE_SUBSTR (name);
ae2fa5bc 360 entry = getprotobyname (SCM_ROCHARS (name));
370312ae
GH
361 }
362 else
363 {
364 unsigned long protonum;
1bbd0b84 365 protonum = SCM_NUM2ULONG (1,name);
370312ae
GH
366 entry = getprotobynumber (protonum);
367 }
370312ae 368 if (!entry)
1bbd0b84 369 SCM_SYSERROR_MSG ("no such protocol %s",
07513939 370 scm_listify (name, SCM_UNDEFINED), errno);
370312ae
GH
371 ve[0] = scm_makfromstr (entry->p_name, (scm_sizet) strlen (entry->p_name), 0);
372 ve[1] = scm_makfromstrs (-1, entry->p_aliases);
373 ve[2] = SCM_MAKINUM (entry->p_proto + 0L);
374 return ans;
375}
1bbd0b84 376#undef FUNC_NAME
0e958795 377#endif
370312ae 378
370312ae 379static SCM
1bbd0b84 380scm_return_entry (struct servent *entry)
370312ae
GH
381{
382 SCM ans;
383 SCM *ve;
384
a8741caa 385 ans = scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED);
370312ae
GH
386 ve = SCM_VELTS (ans);
387 ve[0] = scm_makfromstr (entry->s_name, (scm_sizet) strlen (entry->s_name), 0);
388 ve[1] = scm_makfromstrs (-1, entry->s_aliases);
389 ve[2] = SCM_MAKINUM (ntohs (entry->s_port) + 0L);
390 ve[3] = scm_makfromstr (entry->s_proto, (scm_sizet) strlen (entry->s_proto), 0);
370312ae
GH
391 return ans;
392}
393
0e958795 394#ifdef HAVE_GETSERVENT
1bbd0b84
GB
395GUILE_PROC (scm_getserv, "getserv", 0, 2, 0,
396 (SCM name, SCM proto),
397"")
398#define FUNC_NAME s_scm_getserv
370312ae
GH
399{
400 struct servent *entry;
401 if (SCM_UNBNDP (name))
402 {
07513939 403 errno = 0;
370312ae 404 entry = getservent ();
07513939
JB
405 if (!entry)
406 {
407 if (errno)
1bbd0b84 408 SCM_SYSERROR;
07513939
JB
409 else
410 return SCM_BOOL_F;
411 }
370312ae
GH
412 return scm_return_entry (entry);
413 }
1bbd0b84 414 SCM_VALIDATE_ROSTRING(2,proto);
89958ad0 415 SCM_COERCE_SUBSTR (proto);
ae2fa5bc 416 if (SCM_NIMP (name) && SCM_ROSTRINGP (name))
370312ae 417 {
89958ad0 418 SCM_COERCE_SUBSTR (name);
ae2fa5bc 419 entry = getservbyname (SCM_ROCHARS (name), SCM_ROCHARS (proto));
370312ae
GH
420 }
421 else
422 {
1bbd0b84 423 SCM_VALIDATE_INT(1,name);
ae2fa5bc 424 entry = getservbyport (htons (SCM_INUM (name)), SCM_ROCHARS (proto));
370312ae
GH
425 }
426 if (!entry)
1bbd0b84
GB
427 SCM_SYSERROR_MSG("no such service %s",
428 scm_listify (name, SCM_UNDEFINED), errno);
370312ae
GH
429 return scm_return_entry (entry);
430}
1bbd0b84 431#undef FUNC_NAME
0e958795 432#endif
370312ae 433
0e958795 434#if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
1bbd0b84
GB
435GUILE_PROC (scm_sethost, "sethost", 0, 1, 0,
436 (SCM arg),
437"")
438#define FUNC_NAME s_scm_sethost
370312ae
GH
439{
440 if (SCM_UNBNDP (arg))
441 endhostent ();
442 else
443 sethostent (SCM_NFALSEP (arg));
444 return SCM_UNSPECIFIED;
445}
1bbd0b84 446#undef FUNC_NAME
0e958795 447#endif
370312ae 448
0e958795 449#if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
1bbd0b84
GB
450GUILE_PROC (scm_setnet, "setnet", 0, 1, 0,
451 (SCM arg),
452"")
453#define FUNC_NAME s_scm_setnet
370312ae
GH
454{
455 if (SCM_UNBNDP (arg))
456 endnetent ();
457 else
458 setnetent (SCM_NFALSEP (arg));
459 return SCM_UNSPECIFIED;
460}
1bbd0b84 461#undef FUNC_NAME
0e958795 462#endif
370312ae 463
0e958795 464#if defined(HAVE_SETPROTOENT) && defined(HAVE_ENDPROTOENT)
1bbd0b84
GB
465GUILE_PROC (scm_setproto, "setproto", 0, 1, 0,
466 (SCM arg),
467"")
468#define FUNC_NAME s_scm_setproto
370312ae
GH
469{
470 if (SCM_UNBNDP (arg))
471 endprotoent ();
472 else
473 setprotoent (SCM_NFALSEP (arg));
474 return SCM_UNSPECIFIED;
475}
1bbd0b84 476#undef FUNC_NAME
0e958795 477#endif
370312ae 478
0e958795 479#if defined(HAVE_SETSERVENT) && defined(HAVE_ENDSERVENT)
1bbd0b84
GB
480GUILE_PROC (scm_setserv, "setserv", 0, 1, 0,
481 (SCM arg),
482"")
483#define FUNC_NAME s_scm_setserv
370312ae
GH
484{
485 if (SCM_UNBNDP (arg))
486 endservent ();
487 else
488 setservent (SCM_NFALSEP (arg));
489 return SCM_UNSPECIFIED;
490}
1bbd0b84 491#undef FUNC_NAME
0e958795 492#endif
370312ae
GH
493
494
495void
496scm_init_net_db ()
497{
498#ifdef INADDR_ANY
499 scm_sysintern ("INADDR_ANY", scm_ulong2num (INADDR_ANY));
500#endif
501#ifdef INADDR_BROADCAST
502 scm_sysintern ("INADDR_BROADCAST", scm_ulong2num (INADDR_BROADCAST));
503#endif
504#ifdef INADDR_NONE
505 scm_sysintern ("INADDR_NONE", scm_ulong2num (INADDR_NONE));
506#endif
507#ifdef INADDR_LOOPBACK
508 scm_sysintern ("INADDR_LOOPBACK", scm_ulong2num (INADDR_LOOPBACK));
509#endif
510
511 scm_add_feature ("net-db");
512#include "net_db.x"
513}