2001-11-07 Stefan Jahn <stefan@lkcc.org>
[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
45#include "libguile/__scm.h"
46#include "libguile/modules.h"
47#include "libguile/numbers.h"
48
49#include <errno.h>
50
51#include "win32-socket.h"
52
53/* Winsock API error description structure. The error description is
54 necessary because there is no error list available. */
55typedef struct
56{
57 int error; /* Error code. */
58 char *str; /* Error description. */
59 int replace; /* Possible error code replacement. */
60 char *replace_str; /* Replacement symbol. */
61 char *correct_str; /* Original symbol. */
62}
63socket_error_t;
64
65/* Define replacement symbols for most of the WSA* error codes. */
66#ifndef EWOULDBLOCK
67# define EWOULDBLOCK WSAEWOULDBLOCK
68#endif
69#ifndef EINPROGRESS
70# define EINPROGRESS WSAEINPROGRESS
71#endif
72#ifndef EALREADY
73# define EALREADY WSAEALREADY
74#endif
75#ifndef EDESTADDRREQ
76# define EDESTADDRREQ WSAEDESTADDRREQ
77#endif
78#ifndef EMSGSIZE
79# define EMSGSIZE WSAEMSGSIZE
80#endif
81#ifndef EPROTOTYPE
82# define EPROTOTYPE WSAEPROTOTYPE
83#endif
84#ifndef ENOTSOCK
85# define ENOTSOCK WSAENOTSOCK
86#endif
87#ifndef ENOPROTOOPT
88# define ENOPROTOOPT WSAENOPROTOOPT
89#endif
90#ifndef EPROTONOSUPPORT
91# define EPROTONOSUPPORT WSAEPROTONOSUPPORT
92#endif
93#ifndef ESOCKTNOSUPPORT
94# define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
95#endif
96#ifndef EOPNOTSUPP
97# define EOPNOTSUPP WSAEOPNOTSUPP
98#endif
99#ifndef EPFNOSUPPORT
100# define EPFNOSUPPORT WSAEPFNOSUPPORT
101#endif
102#ifndef EAFNOSUPPORT
103# define EAFNOSUPPORT WSAEAFNOSUPPORT
104#endif
105#ifndef EADDRINUSE
106# define EADDRINUSE WSAEADDRINUSE
107#endif
108#ifndef EADDRNOTAVAIL
109# define EADDRNOTAVAIL WSAEADDRNOTAVAIL
110#endif
111#ifndef ENETDOWN
112# define ENETDOWN WSAENETDOWN
113#endif
114#ifndef ENETUNREACH
115# define ENETUNREACH WSAENETUNREACH
116#endif
117#ifndef ENETRESET
118# define ENETRESET WSAENETRESET
119#endif
120#ifndef ECONNABORTED
121# define ECONNABORTED WSAECONNABORTED
122#endif
123#ifndef ECONNRESET
124# define ECONNRESET WSAECONNRESET
125#endif
126#ifndef ENOBUFS
127# define ENOBUFS WSAENOBUFS
128#endif
129#ifndef EISCONN
130# define EISCONN WSAEISCONN
131#endif
132#ifndef ENOTCONN
133# define ENOTCONN WSAENOTCONN
134#endif
135#ifndef ESHUTDOWN
136# define ESHUTDOWN WSAESHUTDOWN
137#endif
138#ifndef ETOOMANYREFS
139# define ETOOMANYREFS WSAETOOMANYREFS
140#endif
141#ifndef ETIMEDOUT
142# define ETIMEDOUT WSAETIMEDOUT
143#endif
144#ifndef ECONNREFUSED
145# define ECONNREFUSED WSAECONNREFUSED
146#endif
147#ifndef ELOOP
148# define ELOOP WSAELOOP
149#endif
150#ifndef EHOSTDOWN
151# define EHOSTDOWN WSAEHOSTDOWN
152#endif
153#ifndef EHOSTUNREACH
154# define EHOSTUNREACH WSAEHOSTUNREACH
155#endif
156#ifndef EPROCLIM
157# define EPROCLIM WSAEPROCLIM
158#endif
159#ifndef EUSERS
160# define EUSERS WSAEUSERS
161#endif
162#ifndef EDQUOT
163# define EDQUOT WSAEDQUOT
164#endif
165#ifndef ESTALE
166# define ESTALE WSAESTALE
167#endif
168#ifndef EREMOTE
169# define EREMOTE WSAEREMOTE
170#endif
171
172/* List of error structures. */
173static socket_error_t socket_errno [] = {
174 /* 000 */ { 0, NULL, 0, NULL, NULL },
175 /* 001 */ { 0, NULL, 0, NULL, NULL },
176 /* 002 */ { 0, NULL, 0, NULL, NULL },
177 /* 003 */ { 0, NULL, 0, NULL, NULL },
178 /* 004 */ { WSAEINTR, "Interrupted function call", EINTR, NULL, "WSAEINTR" },
179 /* 005 */ { 0, NULL, 0, NULL, NULL },
180 /* 006 */ { 0, NULL, 0, NULL, NULL },
181 /* 007 */ { 0, NULL, 0, NULL, NULL },
182 /* 008 */ { 0, NULL, 0, NULL, NULL },
183 /* 009 */ { WSAEBADF, "Bad file number", EBADF, NULL, "WSAEBADF" },
184 /* 010 */ { 0, NULL, 0, NULL, NULL },
185 /* 011 */ { 0, NULL, 0, NULL, NULL },
186 /* 012 */ { 0, NULL, 0, NULL, NULL },
187 /* 013 */ { WSAEACCES, "Permission denied", EACCES, NULL, "WSAEACCES" },
188 /* 014 */ { WSAEFAULT, "Bad address", EFAULT, NULL, "WSAEFAULT" },
189 /* 015 */ { 0, NULL, 0, NULL, NULL },
190 /* 016 */ { 0, NULL, 0, NULL, NULL },
191 /* 017 */ { 0, NULL, 0, NULL, NULL },
192 /* 018 */ { 0, NULL, 0, NULL, NULL },
193 /* 019 */ { 0, NULL, 0, NULL, NULL },
194 /* 020 */ { 0, NULL, 0, NULL, NULL },
195 /* 021 */ { 0, NULL, 0, NULL, NULL },
196 /* 022 */ { WSAEINVAL, "Invalid argument", EINVAL, NULL, "WSAEINVAL" },
197 /* 023 */ { 0, NULL, 0, NULL, NULL },
198 /* 024 */ { WSAEMFILE, "Too many open files", EMFILE, NULL, "WSAEMFILE" },
199 /* 025 */ { 0, NULL, 0, NULL, NULL },
200 /* 026 */ { 0, NULL, 0, NULL, NULL },
201 /* 027 */ { 0, NULL, 0, NULL, NULL },
202 /* 028 */ { 0, NULL, 0, NULL, NULL },
203 /* 029 */ { 0, NULL, 0, NULL, NULL },
204 /* 030 */ { 0, NULL, 0, NULL, NULL },
205 /* 031 */ { 0, NULL, 0, NULL, NULL },
206 /* 032 */ { 0, NULL, 0, NULL, NULL },
207 /* 033 */ { 0, NULL, 0, NULL, NULL },
208 /* 034 */ { 0, NULL, 0, NULL, NULL },
209 /* 035 */ { WSAEWOULDBLOCK, "Resource temporarily unavailable",
210 EWOULDBLOCK, "EWOULDBLOCK", "WSAEWOULDBLOCK" },
211 /* 036 */ { WSAEINPROGRESS, "Operation now in progress",
212 EINPROGRESS, "EINPROGRESS", "WSAEINPROGRESS" },
213 /* 037 */ { WSAEALREADY, "Operation already in progress",
214 EALREADY, "EALREADY", "WSAEALREADY" },
215 /* 038 */ { WSAENOTSOCK, "Socket operation on non-socket",
216 ENOTSOCK, "ENOTSOCK", "WSAENOTSOCK"},
217 /* 039 */ { WSAEDESTADDRREQ, "Destination address required",
218 EDESTADDRREQ, "EDESTADDRREQ", "WSAEDESTADDRREQ" },
219 /* 040 */ { WSAEMSGSIZE, "Message too long",
220 EMSGSIZE, "EMSGSIZE", "WSAEMSGSIZE" },
221 /* 041 */ { WSAEPROTOTYPE, "Protocol wrong type for socket",
222 EPROTOTYPE, "EPROTOTYPE", "WSAEPROTOTYPE" },
223 /* 042 */ { WSAENOPROTOOPT, "Bad protocol option",
224 ENOPROTOOPT, "ENOPROTOOPT", "WSAENOPROTOOPT" },
225 /* 043 */ { WSAEPROTONOSUPPORT, "Protocol not supported",
226 EPROTONOSUPPORT, "EPROTONOSUPPORT", "WSAEPROTONOSUPPORT" },
227 /* 044 */ { WSAESOCKTNOSUPPORT, "Socket type not supported",
228 ESOCKTNOSUPPORT, "ESOCKTNOSUPPORT", "WSAESOCKTNOSUPPORT" },
229 /* 045 */ { WSAEOPNOTSUPP, "Operation not supported",
230 EOPNOTSUPP, "EOPNOTSUPP", "WSAEOPNOTSUPP" },
231 /* 046 */ { WSAEPFNOSUPPORT, "Protocol family not supported",
232 EPFNOSUPPORT, "EPFNOSUPPORT", "WSAEPFNOSUPPORT" },
233 /* 047 */ { WSAEAFNOSUPPORT,
234 "Address family not supported by protocol family",
235 EAFNOSUPPORT, "EAFNOSUPPORT", "WSAEAFNOSUPPORT" },
236 /* 048 */ { WSAEADDRINUSE, "Address already in use",
237 EADDRINUSE, "EADDRINUSE", "WSAEADDRINUSE" },
238 /* 049 */ { WSAEADDRNOTAVAIL, "Cannot assign requested address",
239 EADDRNOTAVAIL, "EADDRNOTAVAIL", "WSAEADDRNOTAVAIL" },
240 /* 050 */ { WSAENETDOWN, "Network is down",
241 ENETDOWN, "ENETDOWN", "WSAENETDOWN" },
242 /* 051 */ { WSAENETUNREACH, "Network is unreachable",
243 ENETUNREACH, "ENETUNREACH", "WSAENETUNREACH" },
244 /* 052 */ { WSAENETRESET, "Network dropped connection on reset",
245 ENETRESET, "ENETRESET", "WSAENETRESET" },
246 /* 053 */ { WSAECONNABORTED, "Software caused connection abort",
247 ECONNABORTED, "ECONNABORTED", "WSAECONNABORTED" },
248 /* 054 */ { WSAECONNRESET, "Connection reset by peer",
249 ECONNRESET, "ECONNRESET", "WSAECONNRESET" },
250 /* 055 */ { WSAENOBUFS, "No buffer space available",
251 ENOBUFS, "ENOBUFS", "WSAENOBUFS" },
252 /* 056 */ { WSAEISCONN, "Socket is already connected",
253 EISCONN, "EISCONN", "WSAEISCONN" },
254 /* 057 */ { WSAENOTCONN, "Socket is not connected",
255 ENOTCONN, "ENOTCONN", "WSAENOTCONN" },
256 /* 058 */ { WSAESHUTDOWN, "Cannot send after socket shutdown",
257 ESHUTDOWN, "ESHUTDOWN", "WSAESHUTDOWN" },
258 /* 059 */ { WSAETOOMANYREFS, "Too many references; can't splice",
259 ETOOMANYREFS, "ETOOMANYREFS", "WSAETOOMANYREFS" },
260 /* 060 */ { WSAETIMEDOUT, "Connection timed out",
261 ETIMEDOUT, "ETIMEDOUT", "WSAETIMEDOUT" },
262 /* 061 */ { WSAECONNREFUSED, "Connection refused",
263 ECONNREFUSED, "ECONNREFUSED", "WSAECONNREFUSED" },
264 /* 062 */ { WSAELOOP, "Too many levels of symbolic links",
265 ELOOP, "ELOOP", "WSAELOOP" },
266 /* 063 */ { WSAENAMETOOLONG, "File name too long",
267 ENAMETOOLONG, NULL, "WSAENAMETOOLONG" },
268 /* 064 */ { WSAEHOSTDOWN, "Host is down",
269 EHOSTDOWN, "EHOSTDOWN", "WSAEHOSTDOWN" },
270 /* 065 */ { WSAEHOSTUNREACH, "No route to host",
271 EHOSTUNREACH, "EHOSTUNREACH", "WSAEHOSTUNREACH" },
272 /* 066 */ { WSAENOTEMPTY, "Directory not empty",
273 ENOTEMPTY, NULL, "WSAENOTEMPTY" },
274 /* 067 */ { WSAEPROCLIM, "Too many processes",
275 EPROCLIM, "EPROCLIM", "WSAEPROCLIM" },
276 /* 068 */ { WSAEUSERS, "Too many users",
277 EUSERS, "EUSERS", "WSAEUSERS" },
278 /* 069 */ { WSAEDQUOT, "Disc quota exceeded",
279 EDQUOT, "EDQUOT", "WSAEDQUOT" },
280 /* 070 */ { WSAESTALE, "Stale NFS file handle",
281 ESTALE, "ESTALE", "WSAESTALE" },
282 /* 071 */ { WSAEREMOTE, "Too many levels of remote in path",
283 EREMOTE, "EREMOTE", "WSAEREMOTE" },
284 /* 072 */ { 0, NULL, 0, NULL, NULL },
285 /* 073 */ { 0, NULL, 0, NULL, NULL },
286 /* 074 */ { 0, NULL, 0, NULL, NULL },
287 /* 075 */ { 0, NULL, 0, NULL, NULL },
288 /* 076 */ { 0, NULL, 0, NULL, NULL },
289 /* 077 */ { 0, NULL, 0, NULL, NULL },
290 /* 078 */ { 0, NULL, 0, NULL, NULL },
291 /* 079 */ { 0, NULL, 0, NULL, NULL },
292 /* 080 */ { 0, NULL, 0, NULL, NULL },
293 /* 081 */ { 0, NULL, 0, NULL, NULL },
294 /* 082 */ { 0, NULL, 0, NULL, NULL },
295 /* 083 */ { 0, NULL, 0, NULL, NULL },
296 /* 084 */ { 0, NULL, 0, NULL, NULL },
297 /* 085 */ { 0, NULL, 0, NULL, NULL },
298 /* 086 */ { 0, NULL, 0, NULL, NULL },
299 /* 087 */ { 0, NULL, 0, NULL, NULL },
300 /* 088 */ { 0, NULL, 0, NULL, NULL },
301 /* 089 */ { 0, NULL, 0, NULL, NULL },
302 /* 090 */ { 0, NULL, 0, NULL, NULL },
303 /* 091 */ { WSASYSNOTREADY, "Network subsystem is unavailable",
304 0, NULL, "WSASYSNOTREADY" },
305 /* 092 */ { WSAVERNOTSUPPORTED, "WINSOCK.DLL version out of range",
306 0, NULL, "WSAVERNOTSUPPORTED" },
307 /* 093 */ { WSANOTINITIALISED, "Successful WSAStartup not yet performed",
308 0, NULL, "WSANOTINITIALISED" },
309 /* 094 */ { 0, NULL, 0, NULL, NULL },
310 /* 095 */ { 0, NULL, 0, NULL, NULL },
311 /* 096 */ { 0, NULL, 0, NULL, NULL },
312 /* 097 */ { 0, NULL, 0, NULL, NULL },
313 /* 098 */ { 0, NULL, 0, NULL, NULL },
314 /* 099 */ { 0, NULL, 0, NULL, NULL },
315 /* 100 */ { 0, NULL, 0, NULL, NULL },
316 /* 101 */ { WSAEDISCON, "Graceful shutdown in progress",
317 0, NULL, "WSAEDISCON" },
318 /* 102 */ { WSAENOMORE, "No more services",
319 0, NULL, "WSAENOMORE" },
320 /* 103 */ { WSAECANCELLED, "Service lookup cancelled",
321 0, NULL, "WSAECANCELLED" },
322 /* 104 */ { WSAEINVALIDPROCTABLE, "Invalid procedure call table",
323 0, NULL, "WSAEINVALIDPROCTABLE" },
324 /* 105 */ { WSAEINVALIDPROVIDER, "Invalid service provider",
325 0, NULL, "WSAEINVALIDPROVIDER" },
326 /* 106 */ { WSAEPROVIDERFAILEDINIT, "Service provider failure",
327 0, NULL, "WSAEPROVIDERFAILEDINIT" },
328 /* 107 */ { WSASYSCALLFAILURE, "System call failed",
329 0, NULL, "WSASYSCALLFAILURE" },
330 /* 108 */ { WSASERVICE_NOT_FOUND, "No such service",
331 0, NULL, "WSASERVICE_NOT_FOUND" },
332 /* 109 */ { WSATYPE_NOT_FOUND, "Class not found",
333 0, NULL, "WSATYPE_NOT_FOUND" },
334 /* 110 */ { WSA_E_NO_MORE, "No more services",
335 0, NULL, "WSA_E_NO_MORE" },
336 /* 111 */ { WSA_E_CANCELLED, "Service lookup cancelled",
337 0, NULL, "WSA_E_CANCELLED" },
338 /* 112 */ { WSAEREFUSED, "Database query refused",
339 0, NULL, "WSAEREFUSED" },
340 /* end */ { -1, NULL, -1, NULL, NULL }
341};
342
343/* Extended list of error structures. */
344static socket_error_t socket_h_errno [] = {
345 /* 000 */ { 0, NULL, 0, NULL, NULL },
346 /* 001 */ { WSAHOST_NOT_FOUND, "Host not found",
347 HOST_NOT_FOUND, "HOST_NOT_FOUND", "WSAHOST_NOT_FOUND" },
348 /* 002 */ { WSATRY_AGAIN, "Non-authoritative host not found",
349 TRY_AGAIN, "TRY_AGAIN", "WSATRY_AGAIN" },
350 /* 003 */ { WSANO_RECOVERY, "This is a non-recoverable error",
351 NO_RECOVERY, "NO_RECOVERY", "WSANO_RECOVERY" },
352 /* 004 */ { WSANO_DATA, "Valid name, no data record of requested type",
353 NO_DATA, "NO_DATA", "WSANO_DATA" },
354 /* 005 */ { WSANO_ADDRESS, "No address, look for MX record",
355 NO_ADDRESS, "NO_ADDRESS", "WSANO_ADDRESS" },
356 /* end */ { -1, NULL, -1, NULL, NULL }
357};
358
359/* Returns the result of @code{WSAGetLastError()}. */
360int
361scm_i_socket_errno (void)
362{
363 return WSAGetLastError ();
364}
365
366/* Returns a valid error message for Winsock-API error codes obtained via
367 @code{WSAGetLastError()} or NULL otherwise. */
368char *
369scm_i_socket_strerror (int error)
370{
371 if (error >= WSABASEERR && error <= (WSABASEERR + 112))
372 return socket_errno[error - WSABASEERR].str;
373 else if (error >= (WSABASEERR + 1000) && error <= (WSABASEERR + 1005))
374 return socket_h_errno[error - (WSABASEERR + 1000)].str;
375 return NULL;
376}
377
378/* Define both the original and replacement error symbol is possible. Thus
379 the user is able to check symbolic errors after unsuccessful networking
380 function calls. */
381static void
382scm_socket_symbols_Win32 (socket_error_t * e)
383{
384 while (e->error != -1)
385 {
386 if (e->error)
387 {
388 if (e->correct_str)
389 scm_c_define (e->correct_str, SCM_MAKINUM (e->error));
390 if (e->replace && e->replace_str)
391 scm_c_define (e->replace_str, SCM_MAKINUM (e->replace));
392 }
393 e++;
394 }
395}
396
397/* Initialize Winsock API under M$-Windows. */
398void
399scm_i_init_socket_Win32 (void)
400{
401 scm_socket_symbols_Win32 (socket_errno);
402 scm_socket_symbols_Win32 (socket_h_errno);
403}