* mkstemp.c: #include <config.h> if HAVE_CONFIG_H. #include
[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 67
f87c105a 68#ifdef HAVE_WINSOCK2_H
82893676
MG
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{
1d1559ce 156 SCM result = scm_c_make_vector (5, SCM_UNSPECIFIED);
370312ae
GH
157 SCM lst = SCM_EOL;
158 struct hostent *entry;
159 struct in_addr inad;
160 char **argv;
161 int i = 0;
d46e4713 162 if (SCM_UNBNDP (host))
370312ae 163 {
cd34a384 164#ifdef HAVE_GETHOSTENT
370312ae 165 entry = gethostent ();
cd34a384
JB
166#else
167 entry = NULL;
168#endif
07513939
JB
169 if (! entry)
170 {
171 /* As far as I can tell, there's no good way to tell whether
172 zero means an error or end-of-file. The trick of
173 clearing errno before calling gethostent and checking it
174 afterwards doesn't cut it, because, on Linux, it seems to
175 try to contact some other server (YP?) and fails, which
176 is a benign failure. */
07513939
JB
177 return SCM_BOOL_F;
178 }
370312ae 179 }
a6d9e5ab 180 else if (SCM_STRINGP (host))
370312ae 181 {
a6d9e5ab 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
1d1559ce
HWN
192 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->h_name, strlen (entry->h_name)));
193 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->h_aliases));
194 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (entry->h_addrtype + 0L));
195 SCM_VECTOR_SET(result, 3, SCM_MAKINUM (entry->h_length + 0L));
370312ae
GH
196 if (sizeof (struct in_addr) != entry->h_length)
197 {
1d1559ce
HWN
198 SCM_VECTOR_SET(result, 4, SCM_BOOL_F);
199 return result;
370312ae
GH
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 }
1d1559ce
HWN
207 SCM_VECTOR_SET(result, 4, lst);
208 return result;
370312ae 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),
8f85c0c6
NJ
225 "@deffnx {Scheme Procedure} getnetbyname net-name\n"
226 "@deffnx {Scheme Procedure} getnetbyaddr net-number\n"
b380b885
MD
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 233{
1d1559ce 234 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
370312ae
GH
235 struct netent *entry;
236
d46e4713 237 if (SCM_UNBNDP (net))
370312ae 238 {
370312ae 239 entry = getnetent ();
07513939
JB
240 if (! entry)
241 {
1dd05fd8
MG
242 /* There's no good way to tell whether zero means an error
243 or end-of-file, so we always return #f. See `gethost'
244 for details. */
245 return SCM_BOOL_F;
07513939 246 }
370312ae 247 }
a6d9e5ab 248 else if (SCM_STRINGP (net))
370312ae 249 {
a6d9e5ab 250 entry = getnetbyname (SCM_STRING_CHARS (net));
370312ae
GH
251 }
252 else
253 {
254 unsigned long netnum;
d46e4713 255 netnum = SCM_NUM2ULONG (1, net);
370312ae
GH
256 entry = getnetbyaddr (netnum, AF_INET);
257 }
370312ae 258 if (!entry)
1afff620 259 SCM_SYSERROR_MSG ("no such network ~A", scm_list_1 (net), errno);
1d1559ce
HWN
260 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->n_name, strlen (entry->n_name)));
261 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->n_aliases));
262 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (entry->n_addrtype + 0L));
263 SCM_VECTOR_SET(result, 3, scm_ulong2num (entry->n_net + 0L));
264 return result;
370312ae 265}
1bbd0b84 266#undef FUNC_NAME
0e958795 267#endif
370312ae 268
6063dc1d 269#if defined (HAVE_GETPROTOENT) || defined (__MINGW32__)
a1ec6916 270SCM_DEFINE (scm_getproto, "getproto", 0, 1, 0,
d46e4713 271 (SCM protocol),
8f85c0c6
NJ
272 "@deffnx {Scheme Procedure} getprotobyname name\n"
273 "@deffnx {Scheme Procedure} getprotobynumber number\n"
b380b885
MD
274 "Look up a network protocol by name or by number. @code{getprotobyname}\n"
275 "takes a string argument, and @code{getprotobynumber} takes an integer\n"
276 "argument. @code{getproto} will accept either type, behaving like\n"
277 "@code{getprotoent} (see below) if no arguments are supplied.")
1bbd0b84 278#define FUNC_NAME s_scm_getproto
370312ae 279{
1d1559ce 280 SCM result = scm_c_make_vector (3, SCM_UNSPECIFIED);
370312ae 281
1d1559ce 282 struct protoent *entry;
d46e4713 283 if (SCM_UNBNDP (protocol))
370312ae 284 {
370312ae 285 entry = getprotoent ();
07513939
JB
286 if (! entry)
287 {
1dd05fd8
MG
288 /* There's no good way to tell whether zero means an error
289 or end-of-file, so we always return #f. See `gethost'
290 for details. */
291 return SCM_BOOL_F;
07513939 292 }
370312ae 293 }
a6d9e5ab 294 else if (SCM_STRINGP (protocol))
370312ae 295 {
a6d9e5ab 296 entry = getprotobyname (SCM_STRING_CHARS (protocol));
370312ae
GH
297 }
298 else
299 {
300 unsigned long protonum;
e4b265d8 301 protonum = SCM_NUM2ULONG (1, protocol);
370312ae
GH
302 entry = getprotobynumber (protonum);
303 }
370312ae 304 if (!entry)
1afff620 305 SCM_SYSERROR_MSG ("no such protocol ~A", scm_list_1 (protocol), errno);
1d1559ce
HWN
306 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->p_name, strlen (entry->p_name)));
307 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->p_aliases));
308 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (entry->p_proto + 0L));
309 return result;
370312ae 310}
1bbd0b84 311#undef FUNC_NAME
0e958795 312#endif
370312ae 313
6063dc1d 314#if defined (HAVE_GETSERVENT) || defined (__MINGW32__)
370312ae 315static SCM
1bbd0b84 316scm_return_entry (struct servent *entry)
370312ae 317{
1d1559ce 318 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
370312ae 319
1d1559ce
HWN
320 SCM_VECTOR_SET(result, 0, scm_mem2string (entry->s_name, strlen (entry->s_name)));
321 SCM_VECTOR_SET(result, 1, scm_makfromstrs (-1, entry->s_aliases));
322 SCM_VECTOR_SET(result, 2, SCM_MAKINUM (ntohs (entry->s_port) + 0L));
323 SCM_VECTOR_SET(result, 3, scm_mem2string (entry->s_proto, strlen (entry->s_proto)));
324 return result;
370312ae
GH
325}
326
a1ec6916 327SCM_DEFINE (scm_getserv, "getserv", 0, 2, 0,
d46e4713 328 (SCM name, SCM protocol),
8f85c0c6
NJ
329 "@deffnx {Scheme Procedure} getservbyname name protocol\n"
330 "@deffnx {Scheme Procedure} getservbyport port protocol\n"
b380b885
MD
331 "Look up a network service by name or by service number, and return a\n"
332 "network service object. The @var{protocol} argument specifies the name\n"
333 "of the desired protocol; if the protocol found in the network service\n"
334 "database does not match this name, a system error is signalled.\n\n"
335 "The @code{getserv} procedure will take either a service name or number\n"
336 "as its first argument; if given no arguments, it behaves like\n"
337 "@code{getservent} (see below).")
1bbd0b84 338#define FUNC_NAME s_scm_getserv
370312ae
GH
339{
340 struct servent *entry;
341 if (SCM_UNBNDP (name))
342 {
370312ae 343 entry = getservent ();
07513939
JB
344 if (!entry)
345 {
1dd05fd8
MG
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'
348 for details. */
349 return SCM_BOOL_F;
07513939 350 }
370312ae
GH
351 return scm_return_entry (entry);
352 }
a6d9e5ab 353 SCM_VALIDATE_STRING (2, protocol);
a6d9e5ab 354 if (SCM_STRINGP (name))
370312ae 355 {
a6d9e5ab 356 entry = getservbyname (SCM_STRING_CHARS (name), SCM_STRING_CHARS (protocol));
370312ae
GH
357 }
358 else
359 {
34d19ef6 360 SCM_VALIDATE_INUM (1, name);
a6d9e5ab 361 entry = getservbyport (htons (SCM_INUM (name)), SCM_STRING_CHARS (protocol));
370312ae
GH
362 }
363 if (!entry)
1afff620 364 SCM_SYSERROR_MSG("no such service ~A", scm_list_1 (name), errno);
370312ae
GH
365 return scm_return_entry (entry);
366}
1bbd0b84 367#undef FUNC_NAME
0e958795 368#endif
370312ae 369
0e958795 370#if defined(HAVE_SETHOSTENT) && defined(HAVE_ENDHOSTENT)
a1ec6916 371SCM_DEFINE (scm_sethost, "sethost", 0, 1, 0,
d46e4713 372 (SCM stayopen),
b380b885
MD
373 "If @var{stayopen} is omitted, this is equivalent to @code{endhostent}.\n"
374 "Otherwise it is equivalent to @code{sethostent stayopen}.")
1bbd0b84 375#define FUNC_NAME s_scm_sethost
370312ae 376{
d46e4713 377 if (SCM_UNBNDP (stayopen))
370312ae
GH
378 endhostent ();
379 else
36284627 380 sethostent (!SCM_FALSEP (stayopen));
370312ae
GH
381 return SCM_UNSPECIFIED;
382}
1bbd0b84 383#undef FUNC_NAME
0e958795 384#endif
370312ae 385
0e958795 386#if defined(HAVE_SETNETENT) && defined(HAVE_ENDNETENT)
a1ec6916 387SCM_DEFINE (scm_setnet, "setnet", 0, 1, 0,
d46e4713 388 (SCM stayopen),
b380b885
MD
389 "If @var{stayopen} is omitted, this is equivalent to @code{endnetent}.\n"
390 "Otherwise it is equivalent to @code{setnetent stayopen}.")
1bbd0b84 391#define FUNC_NAME s_scm_setnet
370312ae 392{
d46e4713 393 if (SCM_UNBNDP (stayopen))
370312ae
GH
394 endnetent ();
395 else
36284627 396 setnetent (!SCM_FALSEP (stayopen));
370312ae
GH
397 return SCM_UNSPECIFIED;
398}
1bbd0b84 399#undef FUNC_NAME
0e958795 400#endif
370312ae 401
6063dc1d 402#if defined (HAVE_SETPROTOENT) && defined (HAVE_ENDPROTOENT) || defined (__MINGW32__)
a1ec6916 403SCM_DEFINE (scm_setproto, "setproto", 0, 1, 0,
d46e4713 404 (SCM stayopen),
b380b885
MD
405 "If @var{stayopen} is omitted, this is equivalent to @code{endprotoent}.\n"
406 "Otherwise it is equivalent to @code{setprotoent stayopen}.")
1bbd0b84 407#define FUNC_NAME s_scm_setproto
370312ae 408{
d46e4713 409 if (SCM_UNBNDP (stayopen))
370312ae
GH
410 endprotoent ();
411 else
36284627 412 setprotoent (!SCM_FALSEP (stayopen));
370312ae
GH
413 return SCM_UNSPECIFIED;
414}
1bbd0b84 415#undef FUNC_NAME
0e958795 416#endif
370312ae 417
6063dc1d 418#if defined (HAVE_SETSERVENT) && defined (HAVE_ENDSERVENT) || defined (__MINGW32__)
a1ec6916 419SCM_DEFINE (scm_setserv, "setserv", 0, 1, 0,
d46e4713 420 (SCM stayopen),
b380b885
MD
421 "If @var{stayopen} is omitted, this is equivalent to @code{endservent}.\n"
422 "Otherwise it is equivalent to @code{setservent stayopen}.")
1bbd0b84 423#define FUNC_NAME s_scm_setserv
370312ae 424{
d46e4713 425 if (SCM_UNBNDP (stayopen))
370312ae
GH
426 endservent ();
427 else
36284627 428 setservent (!SCM_FALSEP (stayopen));
370312ae
GH
429 return SCM_UNSPECIFIED;
430}
1bbd0b84 431#undef FUNC_NAME
0e958795 432#endif
370312ae
GH
433
434
435void
436scm_init_net_db ()
437{
370312ae 438 scm_add_feature ("net-db");
a0599745 439#include "libguile/net_db.x"
370312ae 440}
89e00824
ML
441
442/*
443 Local Variables:
444 c-file-style: "gnu"
445 End:
446*/