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