1 /* "net_db.c" network database support
2 * Copyright (C) 1995,1996,1997,1998,1999,2000,2001 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. */
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.
58 #include "libguile/_scm.h"
59 #include "libguile/feature.h"
60 #include "libguile/strings.h"
61 #include "libguile/vectors.h"
63 #include "libguile/validate.h"
64 #include "libguile/net_db.h"
70 #include <sys/types.h>
72 #ifdef HAVE_WINSOCK2_H
75 #include <sys/socket.h>
77 #include <netinet/in.h>
78 #include <arpa/inet.h>
82 #include "win32-socket.h"
85 #if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__)
86 /* h_errno not found in netdb.h, maybe this will help. */
92 SCM_SYMBOL (scm_host_not_found_key
, "host-not-found");
93 SCM_SYMBOL (scm_try_again_key
, "try-again");
94 SCM_SYMBOL (scm_no_recovery_key
, "no-recovery");
95 SCM_SYMBOL (scm_no_data_key
, "no-data");
97 static void scm_resolv_error (const char *subr
, SCM bad_value
)
100 if (h_errno
== NETDB_INTERNAL
)
102 /* errno supposedly contains a useful value. */
114 key
= scm_host_not_found_key
;
115 errmsg
= "Unknown host";
118 key
= scm_try_again_key
;
119 errmsg
= "Host name lookup failure";
122 key
= scm_no_recovery_key
;
123 errmsg
= "Unknown server error";
126 key
= scm_no_data_key
;
127 errmsg
= "No address associated with name";
130 scm_misc_error (subr
, "Unknown resolver error", SCM_EOL
);
134 #ifdef HAVE_HSTRERROR
135 errmsg
= (const char *) hstrerror (h_errno
);
137 scm_error (key
, subr
, errmsg
, scm_cons (bad_value
, SCM_EOL
), SCM_EOL
);
141 /* Should take an extra arg for address format (will be needed for IPv6).
142 Should use reentrant facilities if available.
145 SCM_DEFINE (scm_gethost
, "gethost", 0, 1, 0,
147 "@deffnx {Scheme Procedure} gethostbyname hostname\n"
148 "@deffnx {Scheme Procedure} gethostbyaddr address\n"
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.")
158 #define FUNC_NAME s_scm_gethost
160 SCM result
= scm_c_make_vector (5, SCM_UNSPECIFIED
);
162 struct hostent
*entry
;
166 if (SCM_UNBNDP (host
))
168 #ifdef HAVE_GETHOSTENT
169 entry
= gethostent ();
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. */
184 else if (SCM_STRINGP (host
))
186 entry
= gethostbyname (SCM_STRING_CHARS (host
));
190 inad
.s_addr
= htonl (SCM_NUM2ULONG (1, host
));
191 entry
= gethostbyaddr ((char *) &inad
, sizeof (inad
), AF_INET
);
194 scm_resolv_error (FUNC_NAME
, host
);
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));
200 if (sizeof (struct in_addr
) != entry
->h_length
)
202 SCM_VECTOR_SET(result
, 4, SCM_BOOL_F
);
205 for (argv
= entry
->h_addr_list
; argv
[i
]; i
++);
208 inad
= *(struct in_addr
*) argv
[i
];
209 lst
= scm_cons (scm_ulong2num (ntohl (inad
.s_addr
)), lst
);
211 SCM_VECTOR_SET(result
, 4, lst
);
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. */
226 #if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
227 SCM_DEFINE (scm_getnet
, "getnet", 0, 1, 0,
229 "@deffnx {Scheme Procedure} getnetbyname net-name\n"
230 "@deffnx {Scheme Procedure} getnetbyaddr net-number\n"
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"
236 #define FUNC_NAME s_scm_getnet
238 SCM result
= scm_c_make_vector (4, SCM_UNSPECIFIED
);
239 struct netent
*entry
;
241 if (SCM_UNBNDP (net
))
243 entry
= getnetent ();
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'
252 else if (SCM_STRINGP (net
))
254 entry
= getnetbyname (SCM_STRING_CHARS (net
));
258 unsigned long netnum
;
259 netnum
= SCM_NUM2ULONG (1, net
);
260 entry
= getnetbyaddr (netnum
, AF_INET
);
263 SCM_SYSERROR_MSG ("no such network ~A", scm_list_1 (net
), errno
);
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));
273 #if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
274 SCM_DEFINE (scm_getproto
, "getproto", 0, 1, 0,
276 "@deffnx {Scheme Procedure} getprotobyname name\n"
277 "@deffnx {Scheme Procedure} getprotobynumber number\n"
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.")
282 #define FUNC_NAME s_scm_getproto
284 SCM result
= scm_c_make_vector (3, SCM_UNSPECIFIED
);
286 struct protoent
*entry
;
287 if (SCM_UNBNDP (protocol
))
289 entry
= getprotoent ();
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'
298 else if (SCM_STRINGP (protocol
))
300 entry
= getprotobyname (SCM_STRING_CHARS (protocol
));
304 unsigned long protonum
;
305 protonum
= SCM_NUM2ULONG (1, protocol
);
306 entry
= getprotobynumber (protonum
);
309 SCM_SYSERROR_MSG ("no such protocol ~A", scm_list_1 (protocol
), errno
);
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));
318 #if defined (HAVE_GETSERVENT) || defined (__MINGW32__)
320 scm_return_entry (struct servent
*entry
)
322 SCM result
= scm_c_make_vector (4, SCM_UNSPECIFIED
);
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
)));
331 SCM_DEFINE (scm_getserv
, "getserv", 0, 2, 0,
332 (SCM name
, SCM protocol
),
333 "@deffnx {Scheme Procedure} getservbyname name protocol\n"
334 "@deffnx {Scheme Procedure} getservbyport port protocol\n"
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).")
342 #define FUNC_NAME s_scm_getserv
344 struct servent
*entry
;
345 if (SCM_UNBNDP (name
))
347 entry
= getservent ();
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'
355 return scm_return_entry (entry
);
357 SCM_VALIDATE_STRING (2, protocol
);
358 if (SCM_STRINGP (name
))
360 entry
= getservbyname (SCM_STRING_CHARS (name
), SCM_STRING_CHARS (protocol
));
364 SCM_VALIDATE_INUM (1, name
);
365 entry
= getservbyport (htons (SCM_INUM (name
)), SCM_STRING_CHARS (protocol
));
368 SCM_SYSERROR_MSG("no such service ~A", scm_list_1 (name
), errno
);
369 return scm_return_entry (entry
);
374 #if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
375 SCM_DEFINE (scm_sethost
, "sethost", 0, 1, 0,
377 "If @var{stayopen} is omitted, this is equivalent to @code{endhostent}.\n"
378 "Otherwise it is equivalent to @code{sethostent stayopen}.")
379 #define FUNC_NAME s_scm_sethost
381 if (SCM_UNBNDP (stayopen
))
384 sethostent (!SCM_FALSEP (stayopen
));
385 return SCM_UNSPECIFIED
;
390 #if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
391 SCM_DEFINE (scm_setnet
, "setnet", 0, 1, 0,
393 "If @var{stayopen} is omitted, this is equivalent to @code{endnetent}.\n"
394 "Otherwise it is equivalent to @code{setnetent stayopen}.")
395 #define FUNC_NAME s_scm_setnet
397 if (SCM_UNBNDP (stayopen
))
400 setnetent (!SCM_FALSEP (stayopen
));
401 return SCM_UNSPECIFIED
;
406 #if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__)
407 SCM_DEFINE (scm_setproto
, "setproto", 0, 1, 0,
409 "If @var{stayopen} is omitted, this is equivalent to @code{endprotoent}.\n"
410 "Otherwise it is equivalent to @code{setprotoent stayopen}.")
411 #define FUNC_NAME s_scm_setproto
413 if (SCM_UNBNDP (stayopen
))
416 setprotoent (!SCM_FALSEP (stayopen
));
417 return SCM_UNSPECIFIED
;
422 #if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__)
423 SCM_DEFINE (scm_setserv
, "setserv", 0, 1, 0,
425 "If @var{stayopen} is omitted, this is equivalent to @code{endservent}.\n"
426 "Otherwise it is equivalent to @code{setservent stayopen}.")
427 #define FUNC_NAME s_scm_setserv
429 if (SCM_UNBNDP (stayopen
))
432 setservent (!SCM_FALSEP (stayopen
));
433 return SCM_UNSPECIFIED
;
442 scm_add_feature ("net-db");
443 #include "libguile/net_db.x"