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