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