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