1 /* "net_db.c" network database support
2 * Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006 Free Software Foundation, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library 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 GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /* Written in 1994 by Aubrey Jaffer.
22 * Thanks to Hallvard.Tretteberg@si.sintef.no for inspiration and discussion.
23 * Rewritten by Gary Houston to be a closer interface to the C socket library.
24 * Split into net_db.c and socket.c.
34 #include "libguile/_scm.h"
35 #include "libguile/feature.h"
36 #include "libguile/strings.h"
37 #include "libguile/vectors.h"
38 #include "libguile/dynwind.h"
40 #include "libguile/validate.h"
41 #include "libguile/net_db.h"
47 #include <sys/types.h>
49 #ifdef HAVE_WINSOCK2_H
52 #include <sys/socket.h>
54 #include <netinet/in.h>
55 #include <arpa/inet.h>
59 #include "win32-socket.h"
62 #if !defined (HAVE_H_ERRNO) && !defined (__MINGW32__) && !defined (__CYGWIN__)
63 /* h_errno not found in netdb.h, maybe this will help. */
69 SCM_SYMBOL (scm_host_not_found_key
, "host-not-found");
70 SCM_SYMBOL (scm_try_again_key
, "try-again");
71 SCM_SYMBOL (scm_no_recovery_key
, "no-recovery");
72 SCM_SYMBOL (scm_no_data_key
, "no-data");
74 static void scm_resolv_error (const char *subr
, SCM bad_value
)
77 if (h_errno
== NETDB_INTERNAL
)
79 /* errno supposedly contains a useful value. */
91 key
= scm_host_not_found_key
;
92 errmsg
= "Unknown host";
95 key
= scm_try_again_key
;
96 errmsg
= "Host name lookup failure";
99 key
= scm_no_recovery_key
;
100 errmsg
= "Unknown server error";
103 key
= scm_no_data_key
;
104 errmsg
= "No address associated with name";
107 scm_misc_error (subr
, "Unknown resolver error", SCM_EOL
);
111 #ifdef HAVE_HSTRERROR
112 errmsg
= (const char *) hstrerror (h_errno
);
114 scm_error (key
, subr
, errmsg
, SCM_BOOL_F
, SCM_EOL
);
118 /* Should take an extra arg for address format (will be needed for IPv6).
119 Should use reentrant facilities if available.
122 SCM_DEFINE (scm_gethost
, "gethost", 0, 1, 0,
124 "@deffnx {Scheme Procedure} gethostbyname hostname\n"
125 "@deffnx {Scheme Procedure} gethostbyaddr address\n"
126 "Look up a host by name or address, returning a host object. The\n"
127 "@code{gethost} procedure will accept either a string name or an integer\n"
128 "address; if given no arguments, it behaves like @code{gethostent} (see\n"
129 "below). If a name or address is supplied but the address can not be\n"
130 "found, an error will be thrown to one of the keys:\n"
131 "@code{host-not-found}, @code{try-again}, @code{no-recovery} or\n"
132 "@code{no-data}, corresponding to the equivalent @code{h_error} values.\n"
133 "Unusual conditions may result in errors thrown to the\n"
134 "@code{system-error} or @code{misc_error} keys.")
135 #define FUNC_NAME s_scm_gethost
137 SCM result
= scm_c_make_vector (5, SCM_UNSPECIFIED
);
139 struct hostent
*entry
;
144 if (SCM_UNBNDP (host
))
146 #ifdef HAVE_GETHOSTENT
147 entry
= gethostent ();
153 /* As far as I can tell, there's no good way to tell whether
154 zero means an error or end-of-file. The trick of
155 clearing errno before calling gethostent and checking it
156 afterwards doesn't cut it, because, on Linux, it seems to
157 try to contact some other server (YP?) and fails, which
158 is a benign failure. */
162 else if (scm_is_string (host
))
164 char *str
= scm_to_locale_string (host
);
165 entry
= gethostbyname (str
);
170 inad
.s_addr
= htonl (scm_to_ulong (host
));
171 entry
= gethostbyaddr ((char *) &inad
, sizeof (inad
), AF_INET
);
175 scm_resolv_error (FUNC_NAME
, host
);
177 SCM_SIMPLE_VECTOR_SET(result
, 0, scm_from_locale_string (entry
->h_name
));
178 SCM_SIMPLE_VECTOR_SET(result
, 1, scm_makfromstrs (-1, entry
->h_aliases
));
179 SCM_SIMPLE_VECTOR_SET(result
, 2, scm_from_int (entry
->h_addrtype
));
180 SCM_SIMPLE_VECTOR_SET(result
, 3, scm_from_int (entry
->h_length
));
181 if (sizeof (struct in_addr
) != entry
->h_length
)
183 SCM_SIMPLE_VECTOR_SET(result
, 4, SCM_BOOL_F
);
186 for (argv
= entry
->h_addr_list
; argv
[i
]; i
++);
189 inad
= *(struct in_addr
*) argv
[i
];
190 lst
= scm_cons (scm_from_ulong (ntohl (inad
.s_addr
)), lst
);
192 SCM_SIMPLE_VECTOR_SET(result
, 4, lst
);
198 /* In all subsequent getMUMBLE functions, when we're called with no
199 arguments, we're supposed to traverse the tables entry by entry.
200 However, there doesn't seem to be any documented way to distinguish
201 between end-of-table and an error; in both cases the functions
202 return zero. Gotta love Unix. For the time being, we clear errno,
203 and if we get a zero and errno is set, we signal an error. This
204 doesn't seem quite right (what if errno gets set as part of healthy
205 operation?), but it seems to work okay. We'll see. */
207 #if defined(HAVE_GETNETENT) && defined(HAVE_GETNETBYNAME) && defined(HAVE_GETNETBYADDR)
208 SCM_DEFINE (scm_getnet
, "getnet", 0, 1, 0,
210 "@deffnx {Scheme Procedure} getnetbyname net-name\n"
211 "@deffnx {Scheme Procedure} getnetbyaddr net-number\n"
212 "Look up a network by name or net number in the network database. The\n"
213 "@var{net-name} argument must be a string, and the @var{net-number}\n"
214 "argument must be an integer. @code{getnet} will accept either type of\n"
215 "argument, behaving like @code{getnetent} (see below) if no arguments are\n"
217 #define FUNC_NAME s_scm_getnet
219 SCM result
= scm_c_make_vector (4, SCM_UNSPECIFIED
);
220 struct netent
*entry
;
223 if (SCM_UNBNDP (net
))
225 entry
= getnetent ();
228 /* There's no good way to tell whether zero means an error
229 or end-of-file, so we always return #f. See `gethost'
234 else if (scm_is_string (net
))
236 char *str
= scm_to_locale_string (net
);
237 entry
= getnetbyname (str
);
243 unsigned long netnum
= scm_to_ulong (net
);
244 entry
= getnetbyaddr (netnum
, AF_INET
);
249 SCM_SYSERROR_MSG ("no such network ~A", scm_list_1 (net
), eno
);
251 SCM_SIMPLE_VECTOR_SET(result
, 0, scm_from_locale_string (entry
->n_name
));
252 SCM_SIMPLE_VECTOR_SET(result
, 1, scm_makfromstrs (-1, entry
->n_aliases
));
253 SCM_SIMPLE_VECTOR_SET(result
, 2, scm_from_int (entry
->n_addrtype
));
254 SCM_SIMPLE_VECTOR_SET(result
, 3, scm_from_ulong (entry
->n_net
));
260 #if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
261 SCM_DEFINE (scm_getproto
, "getproto", 0, 1, 0,
263 "@deffnx {Scheme Procedure} getprotobyname name\n"
264 "@deffnx {Scheme Procedure} getprotobynumber number\n"
265 "Look up a network protocol by name or by number. @code{getprotobyname}\n"
266 "takes a string argument, and @code{getprotobynumber} takes an integer\n"
267 "argument. @code{getproto} will accept either type, behaving like\n"
268 "@code{getprotoent} (see below) if no arguments are supplied.")
269 #define FUNC_NAME s_scm_getproto
271 SCM result
= scm_c_make_vector (3, SCM_UNSPECIFIED
);
272 struct protoent
*entry
;
275 if (SCM_UNBNDP (protocol
))
277 entry
= getprotoent ();
280 /* There's no good way to tell whether zero means an error
281 or end-of-file, so we always return #f. See `gethost'
286 else if (scm_is_string (protocol
))
288 char *str
= scm_to_locale_string (protocol
);
289 entry
= getprotobyname (str
);
295 unsigned long protonum
= scm_to_ulong (protocol
);
296 entry
= getprotobynumber (protonum
);
301 SCM_SYSERROR_MSG ("no such protocol ~A", scm_list_1 (protocol
), eno
);
303 SCM_SIMPLE_VECTOR_SET(result
, 0, scm_from_locale_string (entry
->p_name
));
304 SCM_SIMPLE_VECTOR_SET(result
, 1, scm_makfromstrs (-1, entry
->p_aliases
));
305 SCM_SIMPLE_VECTOR_SET(result
, 2, scm_from_int (entry
->p_proto
));
311 #if defined (HAVE_GETSERVENT) || defined (__MINGW32__)
313 scm_return_entry (struct servent
*entry
)
315 SCM result
= scm_c_make_vector (4, SCM_UNSPECIFIED
);
317 SCM_SIMPLE_VECTOR_SET(result
, 0, scm_from_locale_string (entry
->s_name
));
318 SCM_SIMPLE_VECTOR_SET(result
, 1, scm_makfromstrs (-1, entry
->s_aliases
));
319 SCM_SIMPLE_VECTOR_SET(result
, 2, scm_from_uint16 (ntohs (entry
->s_port
)));
320 SCM_SIMPLE_VECTOR_SET(result
, 3, scm_from_locale_string (entry
->s_proto
));
324 SCM_DEFINE (scm_getserv
, "getserv", 0, 2, 0,
325 (SCM name
, SCM protocol
),
326 "@deffnx {Scheme Procedure} getservbyname name protocol\n"
327 "@deffnx {Scheme Procedure} getservbyport port protocol\n"
328 "Look up a network service by name or by service number, and return a\n"
329 "network service object. The @var{protocol} argument specifies the name\n"
330 "of the desired protocol; if the protocol found in the network service\n"
331 "database does not match this name, a system error is signalled.\n\n"
332 "The @code{getserv} procedure will take either a service name or number\n"
333 "as its first argument; if given no arguments, it behaves like\n"
334 "@code{getservent} (see below).")
335 #define FUNC_NAME s_scm_getserv
337 struct servent
*entry
;
341 if (SCM_UNBNDP (name
))
343 entry
= getservent ();
346 /* There's no good way to tell whether zero means an error
347 or end-of-file, so we always return #f. See `gethost'
351 return scm_return_entry (entry
);
354 scm_dynwind_begin (0);
356 protoname
= scm_to_locale_string (protocol
);
357 scm_dynwind_free (protoname
);
359 if (scm_is_string (name
))
361 char *str
= scm_to_locale_string (name
);
362 entry
= getservbyname (str
, protoname
);
368 entry
= getservbyport (htons (scm_to_int (name
)), protoname
);
373 SCM_SYSERROR_MSG("no such service ~A", scm_list_1 (name
), eno
);
376 return scm_return_entry (entry
);
381 #if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
382 SCM_DEFINE (scm_sethost
, "sethost", 0, 1, 0,
384 "If @var{stayopen} is omitted, this is equivalent to @code{endhostent}.\n"
385 "Otherwise it is equivalent to @code{sethostent stayopen}.")
386 #define FUNC_NAME s_scm_sethost
388 if (SCM_UNBNDP (stayopen
))
391 sethostent (scm_is_true (stayopen
));
392 return SCM_UNSPECIFIED
;
397 #if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
398 SCM_DEFINE (scm_setnet
, "setnet", 0, 1, 0,
400 "If @var{stayopen} is omitted, this is equivalent to @code{endnetent}.\n"
401 "Otherwise it is equivalent to @code{setnetent stayopen}.")
402 #define FUNC_NAME s_scm_setnet
404 if (SCM_UNBNDP (stayopen
))
407 setnetent (scm_is_true (stayopen
));
408 return SCM_UNSPECIFIED
;
413 #if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__)
414 SCM_DEFINE (scm_setproto
, "setproto", 0, 1, 0,
416 "If @var{stayopen} is omitted, this is equivalent to @code{endprotoent}.\n"
417 "Otherwise it is equivalent to @code{setprotoent stayopen}.")
418 #define FUNC_NAME s_scm_setproto
420 if (SCM_UNBNDP (stayopen
))
423 setprotoent (scm_is_true (stayopen
));
424 return SCM_UNSPECIFIED
;
429 #if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__)
430 SCM_DEFINE (scm_setserv
, "setserv", 0, 1, 0,
432 "If @var{stayopen} is omitted, this is equivalent to @code{endservent}.\n"
433 "Otherwise it is equivalent to @code{setservent stayopen}.")
434 #define FUNC_NAME s_scm_setserv
436 if (SCM_UNBNDP (stayopen
))
439 setservent (scm_is_true (stayopen
));
440 return SCM_UNSPECIFIED
;
449 scm_add_feature ("net-db");
450 #include "libguile/net_db.x"