1 /* "net_db.c" network database support
2 * Copyright (C) 1995, 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
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)
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.
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
16 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307 USA
19 * As a special exception, the Free Software Foundation gives permission
20 * for additional uses of the text contained in its release of GUILE.
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.
28 * This exception does not however invalidate any other reasons why
29 * the executable file might be covered by the GNU General Public License.
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.
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.
41 * If you do not wish that, delete this exception notice. */
43 /* Written in 1994 by Aubrey Jaffer.
44 * Thanks to Hallvard.Tretteberg@si.sintef.no for inspiration and discussion.
45 * Rewritten by Gary Houston to be a closer interface to the C socket library.
46 * Split into net_db.c and socket.c.
60 #include <sys/types.h>
61 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
66 /* Some systems do not declare this. Some systems do declare it, as a
76 #endif /* STDC_HEADERS */
78 extern int inet_aton ();
80 SCM_PROC (s_inet_aton
, "inet-aton", 1, 0, 0, scm_inet_aton
);
83 scm_inet_aton (address
)
88 SCM_ASSERT (SCM_NIMP (address
) && SCM_ROSTRINGP (address
), address
, SCM_ARG1
, s_inet_aton
);
89 if (SCM_SUBSTRP (address
))
90 address
= scm_makfromstr (SCM_ROCHARS (address
), SCM_ROLENGTH (address
), 0);
91 if (inet_aton (SCM_ROCHARS (address
), &soka
) == 0)
92 scm_misc_error (s_inet_aton
, "bad address", SCM_EOL
);
93 return scm_ulong2num (ntohl (soka
.s_addr
));
97 SCM_PROC (s_inet_ntoa
, "inet-ntoa", 1, 0, 0, scm_inet_ntoa
);
100 scm_inet_ntoa (inetid
)
106 addr
.s_addr
= htonl (scm_num2ulong (inetid
, (char *) SCM_ARG1
, s_inet_ntoa
));
107 s
= inet_ntoa (addr
);
108 answer
= scm_makfromstr (s
, strlen (s
), 0);
112 #ifdef HAVE_INET_NETOF
113 SCM_PROC (s_inet_netof
, "inet-netof", 1, 0, 0, scm_inet_netof
);
116 scm_inet_netof (address
)
120 addr
.s_addr
= htonl (scm_num2ulong (address
, (char *) SCM_ARG1
, s_inet_netof
));
121 return scm_ulong2num ((unsigned long) inet_netof (addr
));
125 #ifdef HAVE_INET_LNAOF
126 SCM_PROC (s_lnaof
, "inet-lnaof", 1, 0, 0, scm_lnaof
);
133 addr
.s_addr
= htonl (scm_num2ulong (address
, (char *) SCM_ARG1
, s_lnaof
));
134 return scm_ulong2num ((unsigned long) inet_lnaof (addr
));
138 #ifdef HAVE_INET_MAKEADDR
139 SCM_PROC (s_inet_makeaddr
, "inet-makeaddr", 2, 0, 0, scm_inet_makeaddr
);
142 scm_inet_makeaddr (net
, lna
)
147 unsigned long netnum
;
148 unsigned long lnanum
;
150 netnum
= scm_num2ulong (net
, (char *) SCM_ARG1
, s_inet_makeaddr
);
151 lnanum
= scm_num2ulong (lna
, (char *) SCM_ARG2
, s_inet_makeaddr
);
152 addr
= inet_makeaddr (netnum
, lnanum
);
153 return scm_ulong2num (ntohl (addr
.s_addr
));
157 SCM_SYMBOL (scm_host_not_found_key
, "host-not-found");
158 SCM_SYMBOL (scm_try_again_key
, "try-again");
159 SCM_SYMBOL (scm_no_recovery_key
, "no-recovery");
160 SCM_SYMBOL (scm_no_data_key
, "no-data");
162 static void scm_resolv_error (const char *subr
, SCM bad_value
)
164 if (h_errno
== NETDB_INTERNAL
)
166 /* errno supposedly contains a useful value. */
177 key
= scm_host_not_found_key
;
178 errmsg
= "Unknown host";
181 key
= scm_try_again_key
;
182 errmsg
= "Host name lookup failure";
185 key
= scm_no_recovery_key
;
186 errmsg
= "Unknown server error";
189 key
= scm_no_data_key
;
190 errmsg
= "No address associated with name";
193 scm_misc_error (subr
, "Unknown resolver error", SCM_EOL
);
197 #ifdef HAVE_HSTRERROR
198 errmsg
= hstrerror (h_errno
);
200 scm_error (key
, subr
, errmsg
, scm_cons (bad_value
, SCM_EOL
), SCM_EOL
);
204 /* Should take an extra arg for address format (will be needed for IPv6).
205 Should use reentrant facilities if available.
208 SCM_PROC (s_gethost
, "gethost", 0, 1, 0, scm_gethost
);
214 SCM ans
= scm_make_vector (SCM_MAKINUM (5), SCM_UNSPECIFIED
);
215 SCM
*ve
= SCM_VELTS (ans
);
217 struct hostent
*entry
;
221 if (SCM_UNBNDP (name
))
223 #ifdef HAVE_GETHOSTENT
224 entry
= gethostent ();
230 /* As far as I can tell, there's no good way to tell whether
231 zero means an error or end-of-file. The trick of
232 clearing errno before calling gethostent and checking it
233 afterwards doesn't cut it, because, on Linux, it seems to
234 try to contact some other server (YP?) and fails, which
235 is a benign failure. */
239 else if (SCM_NIMP (name
) && SCM_ROSTRINGP (name
))
241 SCM_COERCE_SUBSTR (name
);
242 entry
= gethostbyname (SCM_ROCHARS (name
));
246 inad
.s_addr
= htonl (scm_num2ulong (name
, (char *) SCM_ARG1
, s_gethost
));
247 entry
= gethostbyaddr ((char *) &inad
, sizeof (inad
), AF_INET
);
250 scm_resolv_error (s_gethost
, name
);
252 ve
[0] = scm_makfromstr (entry
->h_name
,
253 (scm_sizet
) strlen (entry
->h_name
), 0);
254 ve
[1] = scm_makfromstrs (-1, entry
->h_aliases
);
255 ve
[2] = SCM_MAKINUM (entry
->h_addrtype
+ 0L);
256 ve
[3] = SCM_MAKINUM (entry
->h_length
+ 0L);
257 if (sizeof (struct in_addr
) != entry
->h_length
)
262 for (argv
= entry
->h_addr_list
; argv
[i
]; i
++);
265 inad
= *(struct in_addr
*) argv
[i
];
266 lst
= scm_cons (scm_ulong2num (ntohl (inad
.s_addr
)), lst
);
273 /* In all subsequent getMUMBLE functions, when we're called with no
274 arguments, we're supposed to traverse the tables entry by entry.
275 However, there doesn't seem to be any documented way to distinguish
276 between end-of-table and an error; in both cases the functions
277 return zero. Gotta love Unix. For the time being, we clear errno,
278 and if we get a zero and errno is set, we signal an error. This
279 doesn't seem quite right (what if errno gets set as part of healthy
280 operation?), but it seems to work okay. We'll see. */
282 #if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
283 SCM_PROC (s_getnet
, "getnet", 0, 1, 0, scm_getnet
);
291 struct netent
*entry
;
293 ans
= scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED
);
294 ve
= SCM_VELTS (ans
);
295 if (SCM_UNBNDP (name
))
298 entry
= getnetent ();
302 scm_syserror (s_getnet
);
307 else if (SCM_NIMP (name
) && SCM_ROSTRINGP (name
))
309 SCM_COERCE_SUBSTR (name
);
310 entry
= getnetbyname (SCM_ROCHARS (name
));
314 unsigned long netnum
;
315 netnum
= scm_num2ulong (name
, (char *) SCM_ARG1
, s_getnet
);
316 entry
= getnetbyaddr (netnum
, AF_INET
);
319 scm_syserror_msg (s_getnet
, "no such network %s",
320 scm_listify (name
, SCM_UNDEFINED
), errno
);
321 ve
[0] = scm_makfromstr (entry
->n_name
, (scm_sizet
) strlen (entry
->n_name
), 0);
322 ve
[1] = scm_makfromstrs (-1, entry
->n_aliases
);
323 ve
[2] = SCM_MAKINUM (entry
->n_addrtype
+ 0L);
324 ve
[3] = scm_ulong2num (entry
->n_net
+ 0L);
329 #ifdef HAVE_GETPROTOENT
330 SCM_PROC (s_getproto
, "getproto", 0, 1, 0, scm_getproto
);
338 struct protoent
*entry
;
340 ans
= scm_make_vector (SCM_MAKINUM (3), SCM_UNSPECIFIED
);
341 ve
= SCM_VELTS (ans
);
342 if (SCM_UNBNDP (name
))
345 entry
= getprotoent ();
349 scm_syserror (s_getproto
);
354 else if (SCM_NIMP (name
) && SCM_ROSTRINGP (name
))
356 SCM_COERCE_SUBSTR (name
);
357 entry
= getprotobyname (SCM_ROCHARS (name
));
361 unsigned long protonum
;
362 protonum
= scm_num2ulong (name
, (char *) SCM_ARG1
, s_getproto
);
363 entry
= getprotobynumber (protonum
);
366 scm_syserror_msg (s_getproto
, "no such protocol %s",
367 scm_listify (name
, SCM_UNDEFINED
), errno
);
368 ve
[0] = scm_makfromstr (entry
->p_name
, (scm_sizet
) strlen (entry
->p_name
), 0);
369 ve
[1] = scm_makfromstrs (-1, entry
->p_aliases
);
370 ve
[2] = SCM_MAKINUM (entry
->p_proto
+ 0L);
375 static SCM scm_return_entry
SCM_P ((struct servent
*entry
));
378 scm_return_entry (entry
)
379 struct servent
*entry
;
384 ans
= scm_make_vector (SCM_MAKINUM (4), SCM_UNSPECIFIED
);
385 ve
= SCM_VELTS (ans
);
386 ve
[0] = scm_makfromstr (entry
->s_name
, (scm_sizet
) strlen (entry
->s_name
), 0);
387 ve
[1] = scm_makfromstrs (-1, entry
->s_aliases
);
388 ve
[2] = SCM_MAKINUM (ntohs (entry
->s_port
) + 0L);
389 ve
[3] = scm_makfromstr (entry
->s_proto
, (scm_sizet
) strlen (entry
->s_proto
), 0);
393 #ifdef HAVE_GETSERVENT
394 SCM_PROC (s_getserv
, "getserv", 0, 2, 0, scm_getserv
);
397 scm_getserv (name
, proto
)
401 struct servent
*entry
;
402 if (SCM_UNBNDP (name
))
405 entry
= getservent ();
409 scm_syserror (s_getserv
);
413 return scm_return_entry (entry
);
415 SCM_ASSERT (SCM_NIMP (proto
) && SCM_ROSTRINGP (proto
), proto
, SCM_ARG2
, s_getserv
);
416 SCM_COERCE_SUBSTR (proto
);
417 if (SCM_NIMP (name
) && SCM_ROSTRINGP (name
))
419 SCM_COERCE_SUBSTR (name
);
420 entry
= getservbyname (SCM_ROCHARS (name
), SCM_ROCHARS (proto
));
424 SCM_ASSERT (SCM_INUMP (name
), name
, SCM_ARG1
, s_getserv
);
425 entry
= getservbyport (htons (SCM_INUM (name
)), SCM_ROCHARS (proto
));
428 scm_syserror_msg (s_getserv
, "no such service %s",
429 scm_listify (name
, SCM_UNDEFINED
), errno
);
430 return scm_return_entry (entry
);
434 #if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
435 SCM_PROC (s_sethost
, "sethost", 0, 1, 0, scm_sethost
);
441 if (SCM_UNBNDP (arg
))
444 sethostent (SCM_NFALSEP (arg
));
445 return SCM_UNSPECIFIED
;
449 #if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
450 SCM_PROC (s_setnet
, "setnet", 0, 1, 0, scm_setnet
);
456 if (SCM_UNBNDP (arg
))
459 setnetent (SCM_NFALSEP (arg
));
460 return SCM_UNSPECIFIED
;
464 #if defined(HAVE_SETPROTOENT) && defined(HAVE_ENDPROTOENT)
465 SCM_PROC (s_setproto
, "setproto", 0, 1, 0, scm_setproto
);
471 if (SCM_UNBNDP (arg
))
474 setprotoent (SCM_NFALSEP (arg
));
475 return SCM_UNSPECIFIED
;
479 #if defined(HAVE_SETSERVENT) && defined(HAVE_ENDSERVENT)
480 SCM_PROC (s_setserv
, "setserv", 0, 1, 0, scm_setserv
);
486 if (SCM_UNBNDP (arg
))
489 setservent (SCM_NFALSEP (arg
));
490 return SCM_UNSPECIFIED
;
499 scm_sysintern ("INADDR_ANY", scm_ulong2num (INADDR_ANY
));
501 #ifdef INADDR_BROADCAST
502 scm_sysintern ("INADDR_BROADCAST", scm_ulong2num (INADDR_BROADCAST
));
505 scm_sysintern ("INADDR_NONE", scm_ulong2num (INADDR_NONE
));
507 #ifdef INADDR_LOOPBACK
508 scm_sysintern ("INADDR_LOOPBACK", scm_ulong2num (INADDR_LOOPBACK
));
511 scm_add_feature ("net-db");