*** empty log message ***
[bpt/guile.git] / libguile / win32-socket.c
CommitLineData
b4e15479
SJ
1/* Copyright (C) 2001 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42
43\f
44
72bcac39
RB
45#if HAVE_CONFIG_H
46# include <config.h>
47#endif
48
b4e15479
SJ
49#include "libguile/__scm.h"
50#include "libguile/modules.h"
51#include "libguile/numbers.h"
52
6063dc1d
SJ
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56#include <ctype.h>
b4e15479 57#include <errno.h>
6063dc1d
SJ
58#include <limits.h>
59
60#ifndef PATH_MAX
61#define PATH_MAX 255
62#endif
b4e15479
SJ
63
64#include "win32-socket.h"
65
66/* Winsock API error description structure. The error description is
67 necessary because there is no error list available. */
68typedef struct
69{
70 int error; /* Error code. */
71 char *str; /* Error description. */
72 int replace; /* Possible error code replacement. */
73 char *replace_str; /* Replacement symbol. */
74 char *correct_str; /* Original symbol. */
75}
76socket_error_t;
77
6063dc1d
SJ
78#define FILE_ETC_SERVICES "services"
79#define ENVIRON_ETC_SERVICES "SERVICES"
80#define FILE_ETC_NETWORKS "networks"
81#define ENVIRON_ETC_NETWORKS "NETWORKS"
82#define FILE_ETC_PROTOCOLS "protocol"
83#define ENVIRON_ETC_PROTOCOLS "PROTOCOLS"
84#define MAX_NAMLEN 256
85#define MAX_ALIASES 4
86
87/* Internal structure for a thread's M$-Windows servent interface. */
88typedef struct
89{
90 FILE *fd; /* Current file. */
91 char file[PATH_MAX]; /* File name. */
92 struct servent ent; /* Return value. */
93 char name[MAX_NAMLEN]; /* Service name. */
94 char proto[MAX_NAMLEN]; /* Protocol name. */
95 char alias[MAX_ALIASES][MAX_NAMLEN]; /* All aliases. */
96 char *aliases[MAX_ALIASES]; /* Alias pointers. */
97 int port; /* Network port. */
98}
99scm_i_servent_t;
100
101static scm_i_servent_t scm_i_servent;
102
103/* Internal structure for a thread's M$-Windows protoent interface. */
104typedef struct
105{
106 FILE *fd; /* Current file. */
107 char file[PATH_MAX]; /* File name. */
108 struct protoent ent; /* Return value. */
109 char name[MAX_NAMLEN]; /* Protocol name. */
110 char alias[MAX_ALIASES][MAX_NAMLEN]; /* All aliases. */
111 char *aliases[MAX_ALIASES]; /* Alias pointers. */
112 int proto; /* Protocol number. */
113}
114scm_i_protoent_t;
115
116static scm_i_protoent_t scm_i_protoent;
117
b4e15479
SJ
118/* Define replacement symbols for most of the WSA* error codes. */
119#ifndef EWOULDBLOCK
120# define EWOULDBLOCK WSAEWOULDBLOCK
121#endif
122#ifndef EINPROGRESS
123# define EINPROGRESS WSAEINPROGRESS
124#endif
125#ifndef EALREADY
126# define EALREADY WSAEALREADY
127#endif
128#ifndef EDESTADDRREQ
129# define EDESTADDRREQ WSAEDESTADDRREQ
130#endif
131#ifndef EMSGSIZE
132# define EMSGSIZE WSAEMSGSIZE
133#endif
134#ifndef EPROTOTYPE
135# define EPROTOTYPE WSAEPROTOTYPE
136#endif
137#ifndef ENOTSOCK
138# define ENOTSOCK WSAENOTSOCK
139#endif
140#ifndef ENOPROTOOPT
141# define ENOPROTOOPT WSAENOPROTOOPT
142#endif
143#ifndef EPROTONOSUPPORT
144# define EPROTONOSUPPORT WSAEPROTONOSUPPORT
145#endif
146#ifndef ESOCKTNOSUPPORT
147# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
148#endif
149#ifndef EOPNOTSUPP
150# define EOPNOTSUPP WSAEOPNOTSUPP
151#endif
152#ifndef EPFNOSUPPORT
153# define EPFNOSUPPORT WSAEPFNOSUPPORT
154#endif
155#ifndef EAFNOSUPPORT
156# define EAFNOSUPPORT WSAEAFNOSUPPORT
157#endif
158#ifndef EADDRINUSE
159# define EADDRINUSE WSAEADDRINUSE
160#endif
161#ifndef EADDRNOTAVAIL
162# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
163#endif
164#ifndef ENETDOWN
165# define ENETDOWN WSAENETDOWN
166#endif
167#ifndef ENETUNREACH
168# define ENETUNREACH WSAENETUNREACH
169#endif
170#ifndef ENETRESET
171# define ENETRESET WSAENETRESET
172#endif
173#ifndef ECONNABORTED
174# define ECONNABORTED WSAECONNABORTED
175#endif
176#ifndef ECONNRESET
177# define ECONNRESET WSAECONNRESET
178#endif
179#ifndef ENOBUFS
180# define ENOBUFS WSAENOBUFS
181#endif
182#ifndef EISCONN
183# define EISCONN WSAEISCONN
184#endif
185#ifndef ENOTCONN
186# define ENOTCONN WSAENOTCONN
187#endif
188#ifndef ESHUTDOWN
189# define ESHUTDOWN WSAESHUTDOWN
190#endif
191#ifndef ETOOMANYREFS
192# define ETOOMANYREFS WSAETOOMANYREFS
193#endif
194#ifndef ETIMEDOUT
195# define ETIMEDOUT WSAETIMEDOUT
196#endif
197#ifndef ECONNREFUSED
198# define ECONNREFUSED WSAECONNREFUSED
199#endif
200#ifndef ELOOP
201# define ELOOP WSAELOOP
202#endif
203#ifndef EHOSTDOWN
204# define EHOSTDOWN WSAEHOSTDOWN
205#endif
206#ifndef EHOSTUNREACH
207# define EHOSTUNREACH WSAEHOSTUNREACH
208#endif
209#ifndef EPROCLIM
210# define EPROCLIM WSAEPROCLIM
211#endif
212#ifndef EUSERS
213# define EUSERS WSAEUSERS
214#endif
215#ifndef EDQUOT
216# define EDQUOT WSAEDQUOT
217#endif
218#ifndef ESTALE
219# define ESTALE WSAESTALE
220#endif
221#ifndef EREMOTE
222# define EREMOTE WSAEREMOTE
223#endif
224
225/* List of error structures. */
226static socket_error_t socket_errno [] = {
227 /* 000 */ { 0, NULL, 0, NULL, NULL },
228 /* 001 */ { 0, NULL, 0, NULL, NULL },
229 /* 002 */ { 0, NULL, 0, NULL, NULL },
230 /* 003 */ { 0, NULL, 0, NULL, NULL },
231 /* 004 */ { WSAEINTR, "Interrupted function call", EINTR, NULL, "WSAEINTR" },
232 /* 005 */ { 0, NULL, 0, NULL, NULL },
233 /* 006 */ { 0, NULL, 0, NULL, NULL },
234 /* 007 */ { 0, NULL, 0, NULL, NULL },
235 /* 008 */ { 0, NULL, 0, NULL, NULL },
236 /* 009 */ { WSAEBADF, "Bad file number", EBADF, NULL, "WSAEBADF" },
237 /* 010 */ { 0, NULL, 0, NULL, NULL },
238 /* 011 */ { 0, NULL, 0, NULL, NULL },
239 /* 012 */ { 0, NULL, 0, NULL, NULL },
240 /* 013 */ { WSAEACCES, "Permission denied", EACCES, NULL, "WSAEACCES" },
241 /* 014 */ { WSAEFAULT, "Bad address", EFAULT, NULL, "WSAEFAULT" },
242 /* 015 */ { 0, NULL, 0, NULL, NULL },
243 /* 016 */ { 0, NULL, 0, NULL, NULL },
244 /* 017 */ { 0, NULL, 0, NULL, NULL },
245 /* 018 */ { 0, NULL, 0, NULL, NULL },
246 /* 019 */ { 0, NULL, 0, NULL, NULL },
247 /* 020 */ { 0, NULL, 0, NULL, NULL },
248 /* 021 */ { 0, NULL, 0, NULL, NULL },
249 /* 022 */ { WSAEINVAL, "Invalid argument", EINVAL, NULL, "WSAEINVAL" },
250 /* 023 */ { 0, NULL, 0, NULL, NULL },
251 /* 024 */ { WSAEMFILE, "Too many open files", EMFILE, NULL, "WSAEMFILE" },
252 /* 025 */ { 0, NULL, 0, NULL, NULL },
253 /* 026 */ { 0, NULL, 0, NULL, NULL },
254 /* 027 */ { 0, NULL, 0, NULL, NULL },
255 /* 028 */ { 0, NULL, 0, NULL, NULL },
256 /* 029 */ { 0, NULL, 0, NULL, NULL },
257 /* 030 */ { 0, NULL, 0, NULL, NULL },
258 /* 031 */ { 0, NULL, 0, NULL, NULL },
259 /* 032 */ { 0, NULL, 0, NULL, NULL },
260 /* 033 */ { 0, NULL, 0, NULL, NULL },
261 /* 034 */ { 0, NULL, 0, NULL, NULL },
262 /* 035 */ { WSAEWOULDBLOCK, "Resource temporarily unavailable",
263 EWOULDBLOCK, "EWOULDBLOCK", "WSAEWOULDBLOCK" },
264 /* 036 */ { WSAEINPROGRESS, "Operation now in progress",
265 EINPROGRESS, "EINPROGRESS", "WSAEINPROGRESS" },
266 /* 037 */ { WSAEALREADY, "Operation already in progress",
267 EALREADY, "EALREADY", "WSAEALREADY" },
268 /* 038 */ { WSAENOTSOCK, "Socket operation on non-socket",
269 ENOTSOCK, "ENOTSOCK", "WSAENOTSOCK"},
270 /* 039 */ { WSAEDESTADDRREQ, "Destination address required",
271 EDESTADDRREQ, "EDESTADDRREQ", "WSAEDESTADDRREQ" },
272 /* 040 */ { WSAEMSGSIZE, "Message too long",
273 EMSGSIZE, "EMSGSIZE", "WSAEMSGSIZE" },
274 /* 041 */ { WSAEPROTOTYPE, "Protocol wrong type for socket",
275 EPROTOTYPE, "EPROTOTYPE", "WSAEPROTOTYPE" },
276 /* 042 */ { WSAENOPROTOOPT, "Bad protocol option",
277 ENOPROTOOPT, "ENOPROTOOPT", "WSAENOPROTOOPT" },
278 /* 043 */ { WSAEPROTONOSUPPORT, "Protocol not supported",
279 EPROTONOSUPPORT, "EPROTONOSUPPORT", "WSAEPROTONOSUPPORT" },
280 /* 044 */ { WSAESOCKTNOSUPPORT, "Socket type not supported",
281 ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "WSAESOCKTNOSUPPORT" },
282 /* 045 */ { WSAEOPNOTSUPP, "Operation not supported",
283 EOPNOTSUPP, "EOPNOTSUPP", "WSAEOPNOTSUPP" },
284 /* 046 */ { WSAEPFNOSUPPORT, "Protocol family not supported",
285 EPFNOSUPPORT, "EPFNOSUPPORT", "WSAEPFNOSUPPORT" },
286 /* 047 */ { WSAEAFNOSUPPORT,
287 "Address family not supported by protocol family",
288 EAFNOSUPPORT, "EAFNOSUPPORT", "WSAEAFNOSUPPORT" },
289 /* 048 */ { WSAEADDRINUSE, "Address already in use",
290 EADDRINUSE, "EADDRINUSE", "WSAEADDRINUSE" },
291 /* 049 */ { WSAEADDRNOTAVAIL, "Cannot assign requested address",
292 EADDRNOTAVAIL, "EADDRNOTAVAIL", "WSAEADDRNOTAVAIL" },
293 /* 050 */ { WSAENETDOWN, "Network is down",
294 ENETDOWN, "ENETDOWN", "WSAENETDOWN" },
295 /* 051 */ { WSAENETUNREACH, "Network is unreachable",
296 ENETUNREACH, "ENETUNREACH", "WSAENETUNREACH" },
297 /* 052 */ { WSAENETRESET, "Network dropped connection on reset",
298 ENETRESET, "ENETRESET", "WSAENETRESET" },
299 /* 053 */ { WSAECONNABORTED, "Software caused connection abort",
300 ECONNABORTED, "ECONNABORTED", "WSAECONNABORTED" },
301 /* 054 */ { WSAECONNRESET, "Connection reset by peer",
302 ECONNRESET, "ECONNRESET", "WSAECONNRESET" },
303 /* 055 */ { WSAENOBUFS, "No buffer space available",
304 ENOBUFS, "ENOBUFS", "WSAENOBUFS" },
305 /* 056 */ { WSAEISCONN, "Socket is already connected",
306 EISCONN, "EISCONN", "WSAEISCONN" },
307 /* 057 */ { WSAENOTCONN, "Socket is not connected",
308 ENOTCONN, "ENOTCONN", "WSAENOTCONN" },
309 /* 058 */ { WSAESHUTDOWN, "Cannot send after socket shutdown",
310 ESHUTDOWN, "ESHUTDOWN", "WSAESHUTDOWN" },
311 /* 059 */ { WSAETOOMANYREFS, "Too many references; can't splice",
312 ETOOMANYREFS, "ETOOMANYREFS", "WSAETOOMANYREFS" },
313 /* 060 */ { WSAETIMEDOUT, "Connection timed out",
314 ETIMEDOUT, "ETIMEDOUT", "WSAETIMEDOUT" },
315 /* 061 */ { WSAECONNREFUSED, "Connection refused",
316 ECONNREFUSED, "ECONNREFUSED", "WSAECONNREFUSED" },
317 /* 062 */ { WSAELOOP, "Too many levels of symbolic links",
318 ELOOP, "ELOOP", "WSAELOOP" },
319 /* 063 */ { WSAENAMETOOLONG, "File name too long",
320 ENAMETOOLONG, NULL, "WSAENAMETOOLONG" },
321 /* 064 */ { WSAEHOSTDOWN, "Host is down",
322 EHOSTDOWN, "EHOSTDOWN", "WSAEHOSTDOWN" },
323 /* 065 */ { WSAEHOSTUNREACH, "No route to host",
324 EHOSTUNREACH, "EHOSTUNREACH", "WSAEHOSTUNREACH" },
325 /* 066 */ { WSAENOTEMPTY, "Directory not empty",
326 ENOTEMPTY, NULL, "WSAENOTEMPTY" },
327 /* 067 */ { WSAEPROCLIM, "Too many processes",
328 EPROCLIM, "EPROCLIM", "WSAEPROCLIM" },
329 /* 068 */ { WSAEUSERS, "Too many users",
330 EUSERS, "EUSERS", "WSAEUSERS" },
331 /* 069 */ { WSAEDQUOT, "Disc quota exceeded",
332 EDQUOT, "EDQUOT", "WSAEDQUOT" },
333 /* 070 */ { WSAESTALE, "Stale NFS file handle",
334 ESTALE, "ESTALE", "WSAESTALE" },
335 /* 071 */ { WSAEREMOTE, "Too many levels of remote in path",
336 EREMOTE, "EREMOTE", "WSAEREMOTE" },
337 /* 072 */ { 0, NULL, 0, NULL, NULL },
338 /* 073 */ { 0, NULL, 0, NULL, NULL },
339 /* 074 */ { 0, NULL, 0, NULL, NULL },
340 /* 075 */ { 0, NULL, 0, NULL, NULL },
341 /* 076 */ { 0, NULL, 0, NULL, NULL },
342 /* 077 */ { 0, NULL, 0, NULL, NULL },
343 /* 078 */ { 0, NULL, 0, NULL, NULL },
344 /* 079 */ { 0, NULL, 0, NULL, NULL },
345 /* 080 */ { 0, NULL, 0, NULL, NULL },
346 /* 081 */ { 0, NULL, 0, NULL, NULL },
347 /* 082 */ { 0, NULL, 0, NULL, NULL },
348 /* 083 */ { 0, NULL, 0, NULL, NULL },
349 /* 084 */ { 0, NULL, 0, NULL, NULL },
350 /* 085 */ { 0, NULL, 0, NULL, NULL },
351 /* 086 */ { 0, NULL, 0, NULL, NULL },
352 /* 087 */ { 0, NULL, 0, NULL, NULL },
353 /* 088 */ { 0, NULL, 0, NULL, NULL },
354 /* 089 */ { 0, NULL, 0, NULL, NULL },
355 /* 090 */ { 0, NULL, 0, NULL, NULL },
356 /* 091 */ { WSASYSNOTREADY, "Network subsystem is unavailable",
357 0, NULL, "WSASYSNOTREADY" },
358 /* 092 */ { WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range",
359 0, NULL, "WSAVERNOTSUPPORTED" },
360 /* 093 */ { WSANOTINITIALISED, "Successful WSAStartup not yet performed",
361 0, NULL, "WSANOTINITIALISED" },
362 /* 094 */ { 0, NULL, 0, NULL, NULL },
363 /* 095 */ { 0, NULL, 0, NULL, NULL },
364 /* 096 */ { 0, NULL, 0, NULL, NULL },
365 /* 097 */ { 0, NULL, 0, NULL, NULL },
366 /* 098 */ { 0, NULL, 0, NULL, NULL },
367 /* 099 */ { 0, NULL, 0, NULL, NULL },
368 /* 100 */ { 0, NULL, 0, NULL, NULL },
369 /* 101 */ { WSAEDISCON, "Graceful shutdown in progress",
370 0, NULL, "WSAEDISCON" },
371 /* 102 */ { WSAENOMORE, "No more services",
372 0, NULL, "WSAENOMORE" },
373 /* 103 */ { WSAECANCELLED, "Service lookup cancelled",
374 0, NULL, "WSAECANCELLED" },
375 /* 104 */ { WSAEINVALIDPROCTABLE, "Invalid procedure call table",
376 0, NULL, "WSAEINVALIDPROCTABLE" },
377 /* 105 */ { WSAEINVALIDPROVIDER, "Invalid service provider",
378 0, NULL, "WSAEINVALIDPROVIDER" },
379 /* 106 */ { WSAEPROVIDERFAILEDINIT, "Service provider failure",
380 0, NULL, "WSAEPROVIDERFAILEDINIT" },
381 /* 107 */ { WSASYSCALLFAILURE, "System call failed",
382 0, NULL, "WSASYSCALLFAILURE" },
383 /* 108 */ { WSASERVICE_NOT_FOUND, "No such service",
384 0, NULL, "WSASERVICE_NOT_FOUND" },
385 /* 109 */ { WSATYPE_NOT_FOUND, "Class not found",
386 0, NULL, "WSATYPE_NOT_FOUND" },
387 /* 110 */ { WSA_E_NO_MORE, "No more services",
388 0, NULL, "WSA_E_NO_MORE" },
389 /* 111 */ { WSA_E_CANCELLED, "Service lookup cancelled",
390 0, NULL, "WSA_E_CANCELLED" },
391 /* 112 */ { WSAEREFUSED, "Database query refused",
392 0, NULL, "WSAEREFUSED" },
393 /* end */ { -1, NULL, -1, NULL, NULL }
394};
395
396/* Extended list of error structures. */
397static socket_error_t socket_h_errno [] = {
398 /* 000 */ { 0, NULL, 0, NULL, NULL },
399 /* 001 */ { WSAHOST_NOT_FOUND, "Host not found",
400 HOST_NOT_FOUND, "HOST_NOT_FOUND", "WSAHOST_NOT_FOUND" },
401 /* 002 */ { WSATRY_AGAIN, "Non-authoritative host not found",
402 TRY_AGAIN, "TRY_AGAIN", "WSATRY_AGAIN" },
403 /* 003 */ { WSANO_RECOVERY, "This is a non-recoverable error",
404 NO_RECOVERY, "NO_RECOVERY", "WSANO_RECOVERY" },
405 /* 004 */ { WSANO_DATA, "Valid name, no data record of requested type",
406 NO_DATA, "NO_DATA", "WSANO_DATA" },
407 /* 005 */ { WSANO_ADDRESS, "No address, look for MX record",
408 NO_ADDRESS, "NO_ADDRESS", "WSANO_ADDRESS" },
409 /* end */ { -1, NULL, -1, NULL, NULL }
410};
411
412/* Returns the result of @code{WSAGetLastError()}. */
413int
414scm_i_socket_errno (void)
415{
416 return WSAGetLastError ();
417}
418
419/* Returns a valid error message for Winsock-API error codes obtained via
420 @code{WSAGetLastError()} or NULL otherwise. */
421char *
422scm_i_socket_strerror (int error)
423{
424 if (error >= WSABASEERR && error <= (WSABASEERR + 112))
425 return socket_errno[error - WSABASEERR].str;
426 else if (error >= (WSABASEERR + 1000) && error <= (WSABASEERR + 1005))
427 return socket_h_errno[error - (WSABASEERR + 1000)].str;
428 return NULL;
429}
430
6063dc1d
SJ
431/* Constructs a valid filename for the given file @var{file} in the M$-Windows
432 directory. This is usually the default location for the network files. */
433char *
434scm_i_socket_filename (char *file)
435{
436 static char dir[PATH_MAX];
437 int len = PATH_MAX;
438
439 len = GetWindowsDirectory (dir, len);
440 if (dir[len - 1] != '\\')
441 strcat (dir, "\\");
442 strcat (dir, file);
443 return dir;
444}
445
446/* Removes comments and white spaces at end of line and returns a pointer
447 to the end of the line. */
448static char *
449scm_i_socket_uncomment (char *line)
450{
451 char *end;
452
453 if ((end = strchr (line, '#')) != NULL)
454 *end-- = '\0';
455 else
456 {
457 end = line + strlen (line) - 1;
458 while (end > line && (*end == '\r' || *end == '\n'))
459 *end-- = '\0';
460 }
461 while (end > line && isspace (*end))
462 *end-- = '\0';
463
464 return end;
465}
466
467/* The getservent() function reads the next line from the file `/etc/services'
468 and returns a structure servent containing the broken out fields from the
469 line. The `/etc/services' file is opened if necessary. */
470struct servent *
471getservent (void)
472{
473 char line[MAX_NAMLEN], *end, *p;
474 int done = 0, i, n, a;
475 struct servent *e = NULL;
476
477 /* Ensure a open file. */
478 if (scm_i_servent.fd == NULL || feof (scm_i_servent.fd))
479 {
480 setservent (1);
481 if (scm_i_servent.fd == NULL)
482 return NULL;
483 }
484
485 while (!done)
486 {
487 /* Get new line. */
488 if (fgets (line, MAX_NAMLEN, scm_i_servent.fd) != NULL)
489 {
490 end = scm_i_socket_uncomment (line);
491
492 /* Scan the line. */
493 if ((i = sscanf (line, "%s %d/%s%n",
494 scm_i_servent.name,
495 &scm_i_servent.port,
496 scm_i_servent.proto, &n)) != 3)
497 continue;
498
499 /* Scan the remaining aliases. */
500 p = line + n;
501 for (a = 0; a < MAX_ALIASES && p < end && i != -1 && n > 1;
502 a++, p += n)
503 i = sscanf (p, "%s%n", scm_i_servent.alias[a], &n);
504
505 /* Prepare the return value. */
506 e = &scm_i_servent.ent;
507 e->s_name = scm_i_servent.name;
508 e->s_port = htons (scm_i_servent.port);
509 e->s_proto = scm_i_servent.proto;
510 e->s_aliases = scm_i_servent.aliases;
511 scm_i_servent.aliases[a] = NULL;
512 while (a--)
513 scm_i_servent.aliases[a] = scm_i_servent.alias[a];
514 done = 1;
515 }
516 else
517 break;
518 }
519 return done ? e : NULL;
520}
521
522/* The setservent() function opens and rewinds the `/etc/services' file.
523 This file can be set from outside with an environment variable specifying
524 the file name. */
525void
526setservent (int stayopen)
527{
528 char *file = NULL;
529
530 endservent ();
531 if ((file = getenv (ENVIRON_ETC_SERVICES)) != NULL)
532 strcpy (scm_i_servent.file, file);
533 else if ((file = scm_i_socket_filename (FILE_ETC_SERVICES)) != NULL)
534 strcpy (scm_i_servent.file, file);
535 scm_i_servent.fd = fopen (scm_i_servent.file, "rt");
536}
537
538/* The endservent() function closes the `/etc/services' file. */
539void
540endservent (void)
541{
542 if (scm_i_servent.fd != NULL)
543 {
544 fclose (scm_i_servent.fd);
545 scm_i_servent.fd = NULL;
546 }
547}
548
549/* The getprotoent() function reads the next line from the file
550 `/etc/protocols' and returns a structure protoent containing the broken
551 out fields from the line. The `/etc/protocols' file is opened if
552 necessary. */
553struct protoent *
554getprotoent (void)
555{
556 char line[MAX_NAMLEN], *end, *p;
557 int done = 0, i, n, a;
558 struct protoent *e = NULL;
559
560 /* Ensure a open file. */
561 if (scm_i_protoent.fd == NULL || feof (scm_i_protoent.fd))
562 {
563 setprotoent (1);
564 if (scm_i_protoent.fd == NULL)
565 return NULL;
566 }
567
568 while (!done)
569 {
570 /* Get new line. */
571 if (fgets (line, MAX_NAMLEN, scm_i_protoent.fd) != NULL)
572 {
573 end = scm_i_socket_uncomment (line);
574
575 /* Scan the line. */
576 if ((i = sscanf (line, "%s %d%n",
577 scm_i_protoent.name,
578 &scm_i_protoent.proto, &n)) != 2)
579 continue;
580
581 /* Scan the remaining aliases. */
582 p = line + n;
583 for (a = 0; a < MAX_ALIASES && p < end && i != -1 && n > 1;
584 a++, p += n)
585 i = sscanf (p, "%s%n", scm_i_protoent.alias[a], &n);
586
587 /* Prepare the return value. */
588 e = &scm_i_protoent.ent;
589 e->p_name = scm_i_protoent.name;
590 e->p_proto = scm_i_protoent.proto;
591 e->p_aliases = scm_i_protoent.aliases;
592 scm_i_protoent.aliases[a] = NULL;
593 while (a--)
594 scm_i_protoent.aliases[a] = scm_i_protoent.alias[a];
595 done = 1;
596 }
597 else
598 break;
599 }
600 return done ? e : NULL;
601}
602
603/* The setprotoent() function opens and rewinds the `/etc/protocols' file.
604 As in setservent() the user can modify the location of the file using
605 an environment variable. */
606void
607setprotoent (int stayopen)
608{
609 char *file = NULL;
610
611 endprotoent ();
612 if ((file = getenv (ENVIRON_ETC_PROTOCOLS)) != NULL)
613 strcpy (scm_i_protoent.file, file);
614 else if ((file = scm_i_socket_filename (FILE_ETC_PROTOCOLS)) != NULL)
615 strcpy (scm_i_protoent.file, file);
616 scm_i_protoent.fd = fopen (scm_i_protoent.file, "rt");
617}
618
619/* The endprotoent() function closes `/etc/protocols'. */
620void
621endprotoent (void)
622{
623 if (scm_i_protoent.fd != NULL)
624 {
625 fclose (scm_i_protoent.fd);
626 scm_i_protoent.fd = NULL;
627 }
628}
629
b4e15479
SJ
630/* Define both the original and replacement error symbol is possible. Thus
631 the user is able to check symbolic errors after unsuccessful networking
632 function calls. */
633static void
634scm_socket_symbols_Win32 (socket_error_t * e)
635{
636 while (e->error != -1)
637 {
638 if (e->error)
639 {
640 if (e->correct_str)
641 scm_c_define (e->correct_str, SCM_MAKINUM (e->error));
642 if (e->replace && e->replace_str)
643 scm_c_define (e->replace_str, SCM_MAKINUM (e->replace));
644 }
645 e++;
646 }
647}
648
649/* Initialize Winsock API under M$-Windows. */
650void
651scm_i_init_socket_Win32 (void)
652{
653 scm_socket_symbols_Win32 (socket_errno);
654 scm_socket_symbols_Win32 (socket_h_errno);
655}