Commit | Line | Data |
---|---|---|
326b05e3 | 1 | /* win32sck.c |
68dc0745 | 2 | * |
3 | * (c) 1995 Microsoft Corporation. All rights reserved. | |
0d130a44 | 4 | * Developed by hip communications inc. |
68dc0745 | 5 | * Portions (c) 1993 Intergraph Corporation. All rights reserved. |
6 | * | |
7 | * You may distribute under the terms of either the GNU General Public | |
8 | * License or the Artistic License, as specified in the README file. | |
9 | */ | |
0a753a76 | 10 | |
390b85e7 | 11 | #define WIN32IO_IS_STDIO |
55d25626 | 12 | #define WIN32SCK_IS_STDSCK |
0a753a76 | 13 | #define WIN32_LEAN_AND_MEAN |
8fada4f6 | 14 | #define PERLIO_NOT_STDIO 0 |
a835ef8a NIS |
15 | #ifdef __GNUC__ |
16 | #define Win32_Winsock | |
17 | #endif | |
390b85e7 | 18 | #include <windows.h> |
036c1c1e SH |
19 | #include <ws2spi.h> |
20 | ||
0a753a76 | 21 | #include "EXTERN.h" |
22 | #include "perl.h" | |
c69f6586 | 23 | |
58a50f62 | 24 | #include "Win32iop.h" |
0a753a76 | 25 | #include <sys/socket.h> |
26 | #include <fcntl.h> | |
27 | #include <sys/stat.h> | |
28 | #include <assert.h> | |
390b85e7 | 29 | #include <io.h> |
0a753a76 | 30 | |
68dc0745 | 31 | /* thanks to Beverly Brown (beverly@datacube.com) */ |
72e6b643 SH |
32 | #define OPEN_SOCKET(x) win32_open_osfhandle(x,O_RDWR|O_BINARY) |
33 | #define TO_SOCKET(x) _get_osfhandle(x) | |
0a753a76 | 34 | |
326b05e3 GS |
35 | #define StartSockets() \ |
36 | STMT_START { \ | |
37 | if (!wsock_started) \ | |
38 | start_sockets(); \ | |
39 | } STMT_END | |
40 | ||
326b05e3 GS |
41 | #define SOCKET_TEST(x, y) \ |
42 | STMT_START { \ | |
43 | StartSockets(); \ | |
44 | if((x) == (y)) \ | |
b0ba2190 | 45 | errno = get_last_socket_error(); \ |
326b05e3 GS |
46 | } STMT_END |
47 | ||
48 | #define SOCKET_TEST_ERROR(x) SOCKET_TEST(x, SOCKET_ERROR) | |
49 | ||
c9beaf97 | 50 | static int get_last_socket_error(void); |
137443ea | 51 | static struct servent* win32_savecopyservent(struct servent*d, |
52 | struct servent*s, | |
53 | const char *proto); | |
0a753a76 | 54 | |
326b05e3 | 55 | static int wsock_started = 0; |
68dc0745 | 56 | |
b47a847f DD |
57 | #ifdef WIN32_DYN_IOINFO_SIZE |
58 | EXTERN_C Size_t w32_ioinfo_size; | |
59 | #endif | |
60 | ||
b73db59c GS |
61 | EXTERN_C void |
62 | EndSockets(void) | |
63 | { | |
64 | if (wsock_started) | |
65 | WSACleanup(); | |
66 | } | |
67 | ||
d31f3d60 SH |
68 | /* Translate WSAExxx values to corresponding Exxx values where possible. Not all |
69 | * WSAExxx constants have corresponding Exxx constants in <errno.h> (even in | |
70 | * VC++ 2010 and above, which have expanded <errno.h> with more values), but | |
71 | * most missing constants are provided by win32/include/sys/errno2.h. The few | |
72 | * that are not are returned unchanged. | |
73 | * | |
c9beaf97 SH |
74 | * The list of possible WSAExxx values used here comes from the MSDN page |
75 | * titled "Windows Sockets Error Codes". | |
d31f3d60 | 76 | * |
c9beaf97 SH |
77 | * (Note: Only the WSAExxx values are handled here; other WSAxxx values are |
78 | * returned unchanged. The return value normally ends up in errno/$! and at | |
79 | * the Perl code level may be tested against the Exxx constants exported by | |
80 | * the Errno and POSIX modules, which have never handled the other WSAxxx | |
81 | * values themselves, apparently without any ill effect so far.) | |
82 | */ | |
83 | int | |
84 | convert_wsa_error_to_errno(int wsaerr) | |
85 | { | |
86 | switch (wsaerr) { | |
b0ba2190 SH |
87 | case WSAEINTR: |
88 | return EINTR; | |
89 | case WSAEBADF: | |
90 | return EBADF; | |
91 | case WSAEACCES: | |
92 | return EACCES; | |
93 | case WSAEFAULT: | |
94 | return EFAULT; | |
95 | case WSAEINVAL: | |
96 | return EINVAL; | |
97 | case WSAEMFILE: | |
98 | return EMFILE; | |
99 | case WSAEWOULDBLOCK: | |
100 | return EWOULDBLOCK; | |
101 | case WSAEINPROGRESS: | |
102 | return EINPROGRESS; | |
103 | case WSAEALREADY: | |
104 | return EALREADY; | |
105 | case WSAENOTSOCK: | |
106 | return ENOTSOCK; | |
107 | case WSAEDESTADDRREQ: | |
108 | return EDESTADDRREQ; | |
109 | case WSAEMSGSIZE: | |
110 | return EMSGSIZE; | |
111 | case WSAEPROTOTYPE: | |
112 | return EPROTOTYPE; | |
113 | case WSAENOPROTOOPT: | |
114 | return ENOPROTOOPT; | |
115 | case WSAEPROTONOSUPPORT: | |
116 | return EPROTONOSUPPORT; | |
117 | case WSAESOCKTNOSUPPORT: | |
118 | return ESOCKTNOSUPPORT; | |
119 | case WSAEOPNOTSUPP: | |
120 | return EOPNOTSUPP; | |
121 | case WSAEPFNOSUPPORT: | |
122 | return EPFNOSUPPORT; | |
123 | case WSAEAFNOSUPPORT: | |
124 | return EAFNOSUPPORT; | |
125 | case WSAEADDRINUSE: | |
126 | return EADDRINUSE; | |
127 | case WSAEADDRNOTAVAIL: | |
128 | return EADDRNOTAVAIL; | |
129 | case WSAENETDOWN: | |
130 | return ENETDOWN; | |
131 | case WSAENETUNREACH: | |
132 | return ENETUNREACH; | |
133 | case WSAENETRESET: | |
134 | return ENETRESET; | |
135 | case WSAECONNABORTED: | |
136 | return ECONNABORTED; | |
137 | case WSAECONNRESET: | |
138 | return ECONNRESET; | |
139 | case WSAENOBUFS: | |
140 | return ENOBUFS; | |
141 | case WSAEISCONN: | |
142 | return EISCONN; | |
143 | case WSAENOTCONN: | |
144 | return ENOTCONN; | |
145 | case WSAESHUTDOWN: | |
146 | return ESHUTDOWN; | |
147 | case WSAETOOMANYREFS: | |
148 | return ETOOMANYREFS; | |
149 | case WSAETIMEDOUT: | |
150 | return ETIMEDOUT; | |
151 | case WSAECONNREFUSED: | |
152 | return ECONNREFUSED; | |
153 | case WSAELOOP: | |
154 | return ELOOP; | |
155 | case WSAENAMETOOLONG: | |
156 | return ENAMETOOLONG; | |
157 | case WSAEHOSTDOWN: | |
d31f3d60 | 158 | return WSAEHOSTDOWN; /* EHOSTDOWN is not defined */ |
b0ba2190 SH |
159 | case WSAEHOSTUNREACH: |
160 | return EHOSTUNREACH; | |
161 | case WSAENOTEMPTY: | |
162 | return ENOTEMPTY; | |
163 | case WSAEPROCLIM: | |
164 | return EPROCLIM; | |
165 | case WSAEUSERS: | |
166 | return EUSERS; | |
167 | case WSAEDQUOT: | |
168 | return EDQUOT; | |
169 | case WSAESTALE: | |
170 | return ESTALE; | |
171 | case WSAEREMOTE: | |
172 | return EREMOTE; | |
173 | case WSAEDISCON: | |
d31f3d60 | 174 | return WSAEDISCON; /* EDISCON is not defined */ |
b0ba2190 | 175 | case WSAENOMORE: |
d31f3d60 | 176 | return WSAENOMORE; /* ENOMORE is not defined */ |
4eaf3102 SH |
177 | #ifdef WSAECANCELLED |
178 | case WSAECANCELLED: /* New in WinSock2 */ | |
cd6a3131 | 179 | return ECANCELED; |
4eaf3102 | 180 | #endif |
b0ba2190 | 181 | case WSAEINVALIDPROCTABLE: |
d31f3d60 | 182 | return WSAEINVALIDPROCTABLE; /* EINVALIDPROCTABLE is not defined */ |
b0ba2190 | 183 | case WSAEINVALIDPROVIDER: |
d31f3d60 | 184 | return WSAEINVALIDPROVIDER; /* EINVALIDPROVIDER is not defined */ |
b0ba2190 | 185 | case WSAEPROVIDERFAILEDINIT: |
d31f3d60 | 186 | return WSAEPROVIDERFAILEDINIT; /* EPROVIDERFAILEDINIT is not defined */ |
b0ba2190 | 187 | case WSAEREFUSED: |
d31f3d60 | 188 | return WSAEREFUSED; /* EREFUSED is not defined */ |
b0ba2190 SH |
189 | } |
190 | ||
c9beaf97 | 191 | return wsaerr; |
b0ba2190 SH |
192 | } |
193 | ||
e85fa3eb | 194 | #ifdef ERRNO_HAS_POSIX_SUPPLEMENT |
cd6a3131 SH |
195 | /* Translate Exxx values in the POSIX supplement range defined in VC++ 2010 and |
196 | * above (EADDRINUSE <= err <= EWOULDBLOCK) to corresponding WSAExxx values. Not | |
4eaf3102 | 197 | * all such Exxx constants have corresponding WSAExxx constants in <winsock*.h>; |
cd6a3131 | 198 | * we just use ERROR_INVALID_FUNCTION for those that are missing but do not |
e85fa3eb SH |
199 | * really expect to encounter them anyway in the context in which this function |
200 | * is called. | |
4f79e9b1 SH |
201 | * Some versions of MinGW/gcc-4.8 and above also define most, but not all, of |
202 | * these extra Exxx values. The missing ones are all cases for which there is no | |
203 | * corresponding WSAExxx constant anyway, so we simply omit the cases for them | |
204 | * here. | |
cd6a3131 SH |
205 | * Other Exxx values (err < sys_nerr) are returned unchanged. |
206 | */ | |
207 | int | |
208 | convert_errno_to_wsa_error(int err) | |
209 | { | |
210 | switch (err) { | |
211 | case EADDRINUSE: | |
212 | return WSAEADDRINUSE; | |
213 | case EADDRNOTAVAIL: | |
214 | return WSAEADDRNOTAVAIL; | |
215 | case EAFNOSUPPORT: | |
216 | return WSAEAFNOSUPPORT; | |
217 | case EALREADY: | |
218 | return WSAEALREADY; | |
4f79e9b1 SH |
219 | #ifdef EBADMSG |
220 | case EBADMSG: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 221 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 222 | #endif |
cd6a3131 | 223 | case ECANCELED: |
4eaf3102 SH |
224 | #ifdef WSAECANCELLED |
225 | return WSAECANCELLED; /* New in WinSock2 */ | |
226 | #else | |
227 | return ERROR_INVALID_FUNCTION; | |
228 | #endif | |
cd6a3131 SH |
229 | case ECONNABORTED: |
230 | return WSAECONNABORTED; | |
231 | case ECONNREFUSED: | |
232 | return WSAECONNREFUSED; | |
233 | case ECONNRESET: | |
234 | return WSAECONNRESET; | |
235 | case EDESTADDRREQ: | |
236 | return WSAEDESTADDRREQ; | |
237 | case EHOSTUNREACH: | |
238 | return WSAEHOSTUNREACH; | |
4f79e9b1 SH |
239 | #ifdef EIDRM |
240 | case EIDRM: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 241 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 242 | #endif |
cd6a3131 SH |
243 | case EINPROGRESS: |
244 | return WSAEINPROGRESS; | |
245 | case EISCONN: | |
246 | return WSAEISCONN; | |
247 | case ELOOP: | |
248 | return WSAELOOP; | |
249 | case EMSGSIZE: | |
250 | return WSAEMSGSIZE; | |
251 | case ENETDOWN: | |
252 | return WSAENETDOWN; | |
253 | case ENETRESET: | |
254 | return WSAENETRESET; | |
255 | case ENETUNREACH: | |
256 | return WSAENETUNREACH; | |
257 | case ENOBUFS: | |
258 | return WSAENOBUFS; | |
4f79e9b1 SH |
259 | #ifdef ENODATA |
260 | case ENODATA: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 261 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 SH |
262 | #endif |
263 | #ifdef ENOLINK | |
264 | case ENOLINK: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 265 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 SH |
266 | #endif |
267 | #ifdef ENOMSG | |
268 | case ENOMSG: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 269 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 270 | #endif |
cd6a3131 SH |
271 | case ENOPROTOOPT: |
272 | return WSAENOPROTOOPT; | |
4f79e9b1 SH |
273 | #ifdef ENOSR |
274 | case ENOSR: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 275 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 SH |
276 | #endif |
277 | #ifdef ENOSTR | |
278 | case ENOSTR: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 279 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 280 | #endif |
cd6a3131 SH |
281 | case ENOTCONN: |
282 | return WSAENOTCONN; | |
4f79e9b1 SH |
283 | #ifdef ENOTRECOVERABLE |
284 | case ENOTRECOVERABLE: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 285 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 286 | #endif |
cd6a3131 SH |
287 | case ENOTSOCK: |
288 | return WSAENOTSOCK; | |
289 | case ENOTSUP: | |
290 | return ERROR_INVALID_FUNCTION; | |
291 | case EOPNOTSUPP: | |
292 | return WSAEOPNOTSUPP; | |
4f79e9b1 SH |
293 | #ifdef EOTHER |
294 | case EOTHER: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 295 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 296 | #endif |
cd6a3131 SH |
297 | case EOVERFLOW: |
298 | return ERROR_INVALID_FUNCTION; | |
299 | case EOWNERDEAD: | |
300 | return ERROR_INVALID_FUNCTION; | |
301 | case EPROTO: | |
302 | return ERROR_INVALID_FUNCTION; | |
303 | case EPROTONOSUPPORT: | |
304 | return WSAEPROTONOSUPPORT; | |
305 | case EPROTOTYPE: | |
306 | return WSAEPROTOTYPE; | |
4f79e9b1 SH |
307 | #ifdef ETIME |
308 | case ETIME: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 309 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 310 | #endif |
cd6a3131 SH |
311 | case ETIMEDOUT: |
312 | return WSAETIMEDOUT; | |
4f79e9b1 SH |
313 | #ifdef ETXTBSY |
314 | case ETXTBSY: /* Not defined in gcc-4.8.0 */ | |
cd6a3131 | 315 | return ERROR_INVALID_FUNCTION; |
4f79e9b1 | 316 | #endif |
cd6a3131 SH |
317 | case EWOULDBLOCK: |
318 | return WSAEWOULDBLOCK; | |
319 | } | |
320 | ||
321 | return err; | |
322 | } | |
e85fa3eb | 323 | #endif /* ERRNO_HAS_POSIX_SUPPLEMENT */ |
cd6a3131 SH |
324 | |
325 | static int | |
326 | get_last_socket_error(void) | |
327 | { | |
328 | return convert_wsa_error_to_errno(WSAGetLastError()); | |
329 | } | |
330 | ||
68dc0745 | 331 | void |
326b05e3 | 332 | start_sockets(void) |
68dc0745 | 333 | { |
334 | unsigned short version; | |
335 | WSADATA retdata; | |
336 | int ret; | |
68dc0745 | 337 | |
68dc0745 | 338 | /* |
339 | * initalize the winsock interface and insure that it is | |
340 | * cleaned up at exit. | |
341 | */ | |
036c1c1e | 342 | version = 0x2; |
326b05e3 | 343 | if(ret = WSAStartup(version, &retdata)) |
4f63d024 | 344 | Perl_croak_nocontext("Unable to locate winsock library!\n"); |
68dc0745 | 345 | if(retdata.wVersion != version) |
036c1c1e | 346 | Perl_croak_nocontext("Could not find version 2.0 of winsock dll\n"); |
68dc0745 | 347 | |
348 | /* atexit((void (*)(void)) EndSockets); */ | |
401ef382 SN |
349 | wsock_started = 1; |
350 | } | |
0a753a76 | 351 | |
36bb5e1d NC |
352 | /* in no sockets Win32 builds, these use the inline functions defined in |
353 | * perl.h | |
19253ae6 | 354 | */ |
68dc0745 | 355 | u_long |
356 | win32_htonl(u_long hostlong) | |
0a753a76 | 357 | { |
36bb5e1d | 358 | #ifndef WIN32_NO_SOCKETS |
326b05e3 | 359 | StartSockets(); |
19253ae6 | 360 | #endif |
326b05e3 | 361 | return htonl(hostlong); |
0a753a76 | 362 | } |
363 | ||
68dc0745 | 364 | u_short |
365 | win32_htons(u_short hostshort) | |
0a753a76 | 366 | { |
36bb5e1d | 367 | #ifndef WIN32_NO_SOCKETS |
326b05e3 | 368 | StartSockets(); |
19253ae6 | 369 | #endif |
326b05e3 | 370 | return htons(hostshort); |
0a753a76 | 371 | } |
372 | ||
68dc0745 | 373 | u_long |
374 | win32_ntohl(u_long netlong) | |
0a753a76 | 375 | { |
36bb5e1d | 376 | #ifndef WIN32_NO_SOCKETS |
326b05e3 | 377 | StartSockets(); |
19253ae6 | 378 | #endif |
326b05e3 | 379 | return ntohl(netlong); |
0a753a76 | 380 | } |
381 | ||
68dc0745 | 382 | u_short |
383 | win32_ntohs(u_short netshort) | |
0a753a76 | 384 | { |
36bb5e1d | 385 | #ifndef WIN32_NO_SOCKETS |
326b05e3 | 386 | StartSockets(); |
19253ae6 | 387 | #endif |
326b05e3 | 388 | return ntohs(netshort); |
0a753a76 | 389 | } |
390 | ||
391 | ||
0a753a76 | 392 | |
68dc0745 | 393 | SOCKET |
394 | win32_accept(SOCKET s, struct sockaddr *addr, int *addrlen) | |
0a753a76 | 395 | { |
68dc0745 | 396 | SOCKET r; |
0a753a76 | 397 | |
326b05e3 | 398 | SOCKET_TEST((r = accept(TO_SOCKET(s), addr, addrlen)), INVALID_SOCKET); |
68dc0745 | 399 | return OPEN_SOCKET(r); |
0a753a76 | 400 | } |
401 | ||
68dc0745 | 402 | int |
403 | win32_bind(SOCKET s, const struct sockaddr *addr, int addrlen) | |
0a753a76 | 404 | { |
68dc0745 | 405 | int r; |
0a753a76 | 406 | |
326b05e3 | 407 | SOCKET_TEST_ERROR(r = bind(TO_SOCKET(s), addr, addrlen)); |
68dc0745 | 408 | return r; |
0a753a76 | 409 | } |
410 | ||
68dc0745 | 411 | int |
412 | win32_connect(SOCKET s, const struct sockaddr *addr, int addrlen) | |
0a753a76 | 413 | { |
68dc0745 | 414 | int r; |
0a753a76 | 415 | |
326b05e3 | 416 | SOCKET_TEST_ERROR(r = connect(TO_SOCKET(s), addr, addrlen)); |
68dc0745 | 417 | return r; |
0a753a76 | 418 | } |
419 | ||
420 | ||
68dc0745 | 421 | int |
422 | win32_getpeername(SOCKET s, struct sockaddr *addr, int *addrlen) | |
0a753a76 | 423 | { |
68dc0745 | 424 | int r; |
0a753a76 | 425 | |
326b05e3 | 426 | SOCKET_TEST_ERROR(r = getpeername(TO_SOCKET(s), addr, addrlen)); |
68dc0745 | 427 | return r; |
0a753a76 | 428 | } |
429 | ||
68dc0745 | 430 | int |
431 | win32_getsockname(SOCKET s, struct sockaddr *addr, int *addrlen) | |
0a753a76 | 432 | { |
68dc0745 | 433 | int r; |
0a753a76 | 434 | |
326b05e3 | 435 | SOCKET_TEST_ERROR(r = getsockname(TO_SOCKET(s), addr, addrlen)); |
68dc0745 | 436 | return r; |
0a753a76 | 437 | } |
438 | ||
68dc0745 | 439 | int |
440 | win32_getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen) | |
0a753a76 | 441 | { |
68dc0745 | 442 | int r; |
0a753a76 | 443 | |
326b05e3 | 444 | SOCKET_TEST_ERROR(r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen)); |
68dc0745 | 445 | return r; |
0a753a76 | 446 | } |
447 | ||
2d7a9237 | 448 | int |
68dc0745 | 449 | win32_ioctlsocket(SOCKET s, long cmd, u_long *argp) |
0a753a76 | 450 | { |
68dc0745 | 451 | int r; |
0a753a76 | 452 | |
326b05e3 | 453 | SOCKET_TEST_ERROR(r = ioctlsocket(TO_SOCKET(s), cmd, argp)); |
68dc0745 | 454 | return r; |
0a753a76 | 455 | } |
456 | ||
68dc0745 | 457 | int |
458 | win32_listen(SOCKET s, int backlog) | |
0a753a76 | 459 | { |
68dc0745 | 460 | int r; |
0a753a76 | 461 | |
326b05e3 | 462 | SOCKET_TEST_ERROR(r = listen(TO_SOCKET(s), backlog)); |
68dc0745 | 463 | return r; |
0a753a76 | 464 | } |
465 | ||
68dc0745 | 466 | int |
467 | win32_recv(SOCKET s, char *buf, int len, int flags) | |
0a753a76 | 468 | { |
68dc0745 | 469 | int r; |
0a753a76 | 470 | |
326b05e3 | 471 | SOCKET_TEST_ERROR(r = recv(TO_SOCKET(s), buf, len, flags)); |
68dc0745 | 472 | return r; |
0a753a76 | 473 | } |
474 | ||
68dc0745 | 475 | int |
476 | win32_recvfrom(SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen) | |
0a753a76 | 477 | { |
68dc0745 | 478 | int r; |
e4449fe1 | 479 | int frombufsize = *fromlen; |
0a753a76 | 480 | |
326b05e3 | 481 | SOCKET_TEST_ERROR(r = recvfrom(TO_SOCKET(s), buf, len, flags, from, fromlen)); |
e4449fe1 GS |
482 | /* Winsock's recvfrom() only returns a valid 'from' when the socket |
483 | * is connectionless. Perl expects a valid 'from' for all types | |
484 | * of sockets, so go the extra mile. | |
485 | */ | |
486 | if (r != SOCKET_ERROR && frombufsize == *fromlen) | |
487 | (void)win32_getpeername(s, from, fromlen); | |
68dc0745 | 488 | return r; |
0a753a76 | 489 | } |
490 | ||
68dc0745 | 491 | /* select contributed by Vincent R. Slyngstad (vrs@ibeam.intel.com) */ |
492 | int | |
55d25626 | 493 | win32_select(int nfds, Perl_fd_set* rd, Perl_fd_set* wr, Perl_fd_set* ex, const struct timeval* timeout) |
0a753a76 | 494 | { |
55d25626 | 495 | int r; |
3ead22cb | 496 | int i, fd, save_errno = errno; |
8dc00b2f | 497 | FD_SET nrd, nwr, nex; |
e4d771f5 | 498 | bool just_sleep = TRUE; |
0a753a76 | 499 | |
f2bb5751 | 500 | StartSockets(); |
0a753a76 | 501 | |
68dc0745 | 502 | FD_ZERO(&nrd); |
503 | FD_ZERO(&nwr); | |
504 | FD_ZERO(&nex); | |
505 | for (i = 0; i < nfds; i++) { | |
f7bbabd3 JD |
506 | if (rd && PERL_FD_ISSET(i,rd)) { |
507 | fd = TO_SOCKET(i); | |
47660177 | 508 | FD_SET((unsigned)fd, &nrd); |
e4d771f5 | 509 | just_sleep = FALSE; |
f7bbabd3 JD |
510 | } |
511 | if (wr && PERL_FD_ISSET(i,wr)) { | |
512 | fd = TO_SOCKET(i); | |
47660177 | 513 | FD_SET((unsigned)fd, &nwr); |
e4d771f5 | 514 | just_sleep = FALSE; |
f7bbabd3 JD |
515 | } |
516 | if (ex && PERL_FD_ISSET(i,ex)) { | |
517 | fd = TO_SOCKET(i); | |
47660177 | 518 | FD_SET((unsigned)fd, &nex); |
e4d771f5 | 519 | just_sleep = FALSE; |
f7bbabd3 | 520 | } |
68dc0745 | 521 | } |
522 | ||
e4d771f5 JD |
523 | /* winsock seems incapable of dealing with all three fd_sets being empty, |
524 | * so do the (millisecond) sleep as a special case | |
525 | */ | |
526 | if (just_sleep) { | |
527 | if (timeout) | |
528 | Sleep(timeout->tv_sec * 1000 + | |
529 | timeout->tv_usec / 1000); /* do the best we can */ | |
530 | else | |
531 | Sleep(UINT_MAX); | |
532 | return 0; | |
533 | } | |
534 | ||
1c878075 | 535 | errno = save_errno; |
6fc8e913 | 536 | SOCKET_TEST_ERROR(r = select(nfds, &nrd, &nwr, &nex, (PTIMEVAL)timeout)); |
1c878075 | 537 | save_errno = errno; |
0a753a76 | 538 | |
68dc0745 | 539 | for (i = 0; i < nfds; i++) { |
f7bbabd3 JD |
540 | if (rd && PERL_FD_ISSET(i,rd)) { |
541 | fd = TO_SOCKET(i); | |
542 | if (!FD_ISSET(fd, &nrd)) | |
543 | PERL_FD_CLR(i,rd); | |
544 | } | |
545 | if (wr && PERL_FD_ISSET(i,wr)) { | |
546 | fd = TO_SOCKET(i); | |
547 | if (!FD_ISSET(fd, &nwr)) | |
548 | PERL_FD_CLR(i,wr); | |
549 | } | |
550 | if (ex && PERL_FD_ISSET(i,ex)) { | |
551 | fd = TO_SOCKET(i); | |
552 | if (!FD_ISSET(fd, &nex)) | |
553 | PERL_FD_CLR(i,ex); | |
554 | } | |
68dc0745 | 555 | } |
1c878075 | 556 | errno = save_errno; |
68dc0745 | 557 | return r; |
0a753a76 | 558 | } |
559 | ||
68dc0745 | 560 | int |
561 | win32_send(SOCKET s, const char *buf, int len, int flags) | |
0a753a76 | 562 | { |
68dc0745 | 563 | int r; |
0a753a76 | 564 | |
326b05e3 | 565 | SOCKET_TEST_ERROR(r = send(TO_SOCKET(s), buf, len, flags)); |
68dc0745 | 566 | return r; |
0a753a76 | 567 | } |
568 | ||
68dc0745 | 569 | int |
570 | win32_sendto(SOCKET s, const char *buf, int len, int flags, | |
571 | const struct sockaddr *to, int tolen) | |
0a753a76 | 572 | { |
68dc0745 | 573 | int r; |
0a753a76 | 574 | |
326b05e3 | 575 | SOCKET_TEST_ERROR(r = sendto(TO_SOCKET(s), buf, len, flags, to, tolen)); |
68dc0745 | 576 | return r; |
0a753a76 | 577 | } |
578 | ||
68dc0745 | 579 | int |
580 | win32_setsockopt(SOCKET s, int level, int optname, const char *optval, int optlen) | |
0a753a76 | 581 | { |
68dc0745 | 582 | int r; |
0a753a76 | 583 | |
326b05e3 | 584 | SOCKET_TEST_ERROR(r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen)); |
68dc0745 | 585 | return r; |
0a753a76 | 586 | } |
587 | ||
68dc0745 | 588 | int |
589 | win32_shutdown(SOCKET s, int how) | |
0a753a76 | 590 | { |
68dc0745 | 591 | int r; |
0a753a76 | 592 | |
326b05e3 | 593 | SOCKET_TEST_ERROR(r = shutdown(TO_SOCKET(s), how)); |
68dc0745 | 594 | return r; |
0a753a76 | 595 | } |
596 | ||
3a25acb4 GS |
597 | int |
598 | win32_closesocket(SOCKET s) | |
599 | { | |
600 | int r; | |
601 | ||
602 | SOCKET_TEST_ERROR(r = closesocket(TO_SOCKET(s))); | |
603 | return r; | |
604 | } | |
605 | ||
036c1c1e SH |
606 | void |
607 | convert_proto_info_w2a(WSAPROTOCOL_INFOW *in, WSAPROTOCOL_INFOA *out) | |
608 | { | |
609 | Copy(in, out, 1, WSAPROTOCOL_INFOA); | |
610 | wcstombs(out->szProtocol, in->szProtocol, sizeof(out->szProtocol)); | |
611 | } | |
612 | ||
613 | SOCKET | |
614 | open_ifs_socket(int af, int type, int protocol) | |
615 | { | |
1c972609 SH |
616 | dTHX; |
617 | char *s; | |
036c1c1e SH |
618 | unsigned long proto_buffers_len = 0; |
619 | int error_code; | |
620 | SOCKET out = INVALID_SOCKET; | |
621 | ||
1c972609 SH |
622 | if ((s = PerlEnv_getenv("PERL_ALLOW_NON_IFS_LSP")) && atoi(s)) |
623 | return WSASocket(af, type, protocol, NULL, 0, 0); | |
624 | ||
036c1c1e SH |
625 | if (WSCEnumProtocols(NULL, NULL, &proto_buffers_len, &error_code) == SOCKET_ERROR |
626 | && error_code == WSAENOBUFS) | |
627 | { | |
628 | WSAPROTOCOL_INFOW *proto_buffers; | |
629 | int protocols_available = 0; | |
630 | ||
a02a5408 | 631 | Newx(proto_buffers, proto_buffers_len / sizeof(WSAPROTOCOL_INFOW), |
036c1c1e SH |
632 | WSAPROTOCOL_INFOW); |
633 | ||
634 | if ((protocols_available = WSCEnumProtocols(NULL, proto_buffers, | |
635 | &proto_buffers_len, &error_code)) != SOCKET_ERROR) | |
636 | { | |
637 | int i; | |
638 | for (i = 0; i < protocols_available; i++) | |
639 | { | |
640 | WSAPROTOCOL_INFOA proto_info; | |
641 | ||
642 | if ((af != AF_UNSPEC && af != proto_buffers[i].iAddressFamily) | |
643 | || (type != proto_buffers[i].iSocketType) | |
f9169742 SH |
644 | || (protocol != 0 && proto_buffers[i].iProtocol != 0 && |
645 | protocol != proto_buffers[i].iProtocol)) | |
036c1c1e SH |
646 | continue; |
647 | ||
648 | if ((proto_buffers[i].dwServiceFlags1 & XP1_IFS_HANDLES) == 0) | |
649 | continue; | |
650 | ||
651 | convert_proto_info_w2a(&(proto_buffers[i]), &proto_info); | |
652 | ||
653 | out = WSASocket(af, type, protocol, &proto_info, 0, 0); | |
654 | break; | |
655 | } | |
656 | } | |
657 | ||
658 | Safefree(proto_buffers); | |
659 | } | |
660 | ||
661 | return out; | |
662 | } | |
663 | ||
68dc0745 | 664 | SOCKET |
665 | win32_socket(int af, int type, int protocol) | |
0a753a76 | 666 | { |
68dc0745 | 667 | SOCKET s; |
0a753a76 | 668 | |
3a25acb4 | 669 | StartSockets(); |
036c1c1e | 670 | |
72e6b643 | 671 | if((s = open_ifs_socket(af, type, protocol)) == INVALID_SOCKET) |
b0ba2190 | 672 | errno = get_last_socket_error(); |
68dc0745 | 673 | else |
674 | s = OPEN_SOCKET(s); | |
0a753a76 | 675 | |
68dc0745 | 676 | return s; |
0a753a76 | 677 | } |
678 | ||
00b02797 JH |
679 | /* |
680 | * close RTL fd while respecting sockets | |
681 | * added as temporary measure until PerlIO has real | |
682 | * Win32 native layer | |
683 | * -- BKS, 11-11-2000 | |
684 | */ | |
685 | ||
686 | int my_close(int fd) | |
687 | { | |
688 | int osf; | |
689 | if (!wsock_started) /* No WinSock? */ | |
690 | return(close(fd)); /* Then not a socket. */ | |
691 | osf = TO_SOCKET(fd);/* Get it now before it's gone! */ | |
692 | if (osf != -1) { | |
693 | int err; | |
694 | err = closesocket(osf); | |
695 | if (err == 0) { | |
b47a847f DD |
696 | assert(_osfhnd(fd) == osf); /* catch a bad ioinfo struct def */ |
697 | /* don't close freed handle */ | |
698 | _set_osfhnd(fd, INVALID_HANDLE_VALUE); | |
699 | return close(fd); | |
00b02797 JH |
700 | } |
701 | else if (err == SOCKET_ERROR) { | |
b0ba2190 SH |
702 | err = get_last_socket_error(); |
703 | if (err != ENOTSOCK) { | |
00b02797 JH |
704 | (void)close(fd); |
705 | errno = err; | |
706 | return EOF; | |
707 | } | |
708 | } | |
709 | } | |
710 | return close(fd); | |
711 | } | |
712 | ||
fb73857a | 713 | #undef fclose |
714 | int | |
715 | my_fclose (FILE *pf) | |
716 | { | |
4e945249 | 717 | int osf; |
326b05e3 GS |
718 | if (!wsock_started) /* No WinSock? */ |
719 | return(fclose(pf)); /* Then not a socket. */ | |
00b02797 | 720 | osf = TO_SOCKET(win32_fileno(pf));/* Get it now before it's gone! */ |
d3d49e29 GS |
721 | if (osf != -1) { |
722 | int err; | |
723 | win32_fflush(pf); | |
724 | err = closesocket(osf); | |
725 | if (err == 0) { | |
b47a847f DD |
726 | assert(_osfhnd(win32_fileno(pf)) == osf); /* catch a bad ioinfo struct def */ |
727 | /* don't close freed handle */ | |
728 | _set_osfhnd(win32_fileno(pf), INVALID_HANDLE_VALUE); | |
729 | return fclose(pf); | |
d3d49e29 GS |
730 | } |
731 | else if (err == SOCKET_ERROR) { | |
b0ba2190 SH |
732 | err = get_last_socket_error(); |
733 | if (err != ENOTSOCK) { | |
d3d49e29 GS |
734 | (void)fclose(pf); |
735 | errno = err; | |
736 | return EOF; | |
737 | } | |
738 | } | |
326b05e3 | 739 | } |
d3d49e29 | 740 | return fclose(pf); |
fb73857a | 741 | } |
742 | ||
68dc0745 | 743 | struct hostent * |
744 | win32_gethostbyaddr(const char *addr, int len, int type) | |
0a753a76 | 745 | { |
68dc0745 | 746 | struct hostent *r; |
0a753a76 | 747 | |
326b05e3 | 748 | SOCKET_TEST(r = gethostbyaddr(addr, len, type), NULL); |
68dc0745 | 749 | return r; |
0a753a76 | 750 | } |
751 | ||
68dc0745 | 752 | struct hostent * |
753 | win32_gethostbyname(const char *name) | |
0a753a76 | 754 | { |
68dc0745 | 755 | struct hostent *r; |
0a753a76 | 756 | |
326b05e3 | 757 | SOCKET_TEST(r = gethostbyname(name), NULL); |
68dc0745 | 758 | return r; |
0a753a76 | 759 | } |
760 | ||
68dc0745 | 761 | int |
762 | win32_gethostname(char *name, int len) | |
0a753a76 | 763 | { |
68dc0745 | 764 | int r; |
0a753a76 | 765 | |
326b05e3 | 766 | SOCKET_TEST_ERROR(r = gethostname(name, len)); |
68dc0745 | 767 | return r; |
0a753a76 | 768 | } |
769 | ||
68dc0745 | 770 | struct protoent * |
771 | win32_getprotobyname(const char *name) | |
0a753a76 | 772 | { |
68dc0745 | 773 | struct protoent *r; |
0a753a76 | 774 | |
326b05e3 | 775 | SOCKET_TEST(r = getprotobyname(name), NULL); |
68dc0745 | 776 | return r; |
0a753a76 | 777 | } |
778 | ||
68dc0745 | 779 | struct protoent * |
780 | win32_getprotobynumber(int num) | |
0a753a76 | 781 | { |
68dc0745 | 782 | struct protoent *r; |
0a753a76 | 783 | |
326b05e3 | 784 | SOCKET_TEST(r = getprotobynumber(num), NULL); |
68dc0745 | 785 | return r; |
0a753a76 | 786 | } |
787 | ||
68dc0745 | 788 | struct servent * |
789 | win32_getservbyname(const char *name, const char *proto) | |
0a753a76 | 790 | { |
04a2c3d9 | 791 | dTHXa(NULL); |
68dc0745 | 792 | struct servent *r; |
c53bd28a | 793 | |
326b05e3 | 794 | SOCKET_TEST(r = getservbyname(name, proto), NULL); |
68dc0745 | 795 | if (r) { |
04a2c3d9 | 796 | aTHXa(PERL_GET_THX); |
3352bfcb | 797 | r = win32_savecopyservent(&w32_servent, r, proto); |
68dc0745 | 798 | } |
799 | return r; | |
0a753a76 | 800 | } |
801 | ||
68dc0745 | 802 | struct servent * |
803 | win32_getservbyport(int port, const char *proto) | |
0a753a76 | 804 | { |
04a2c3d9 | 805 | dTHXa(NULL); |
68dc0745 | 806 | struct servent *r; |
0a753a76 | 807 | |
326b05e3 | 808 | SOCKET_TEST(r = getservbyport(port, proto), NULL); |
68dc0745 | 809 | if (r) { |
04a2c3d9 | 810 | aTHXa(PERL_GET_THX); |
3352bfcb | 811 | r = win32_savecopyservent(&w32_servent, r, proto); |
68dc0745 | 812 | } |
813 | return r; | |
0a753a76 | 814 | } |
815 | ||
f998180f GS |
816 | int |
817 | win32_ioctl(int i, unsigned int u, char *data) | |
818 | { | |
69a143a6 | 819 | u_long u_long_arg; |
f998180f | 820 | int retval; |
69a143a6 | 821 | |
f998180f | 822 | if (!wsock_started) { |
4f63d024 | 823 | Perl_croak_nocontext("ioctl implemented only on sockets"); |
f998180f GS |
824 | /* NOTREACHED */ |
825 | } | |
826 | ||
69a143a6 YO |
827 | /* mauke says using memcpy avoids alignment issues */ |
828 | memcpy(&u_long_arg, data, sizeof u_long_arg); | |
829 | retval = ioctlsocket(TO_SOCKET(i), (long)u, &u_long_arg); | |
830 | memcpy(data, &u_long_arg, sizeof u_long_arg); | |
831 | ||
f998180f | 832 | if (retval == SOCKET_ERROR) { |
b0ba2190 SH |
833 | int err = get_last_socket_error(); |
834 | if (err == ENOTSOCK) { | |
4f63d024 | 835 | Perl_croak_nocontext("ioctl implemented only on sockets"); |
f998180f GS |
836 | /* NOTREACHED */ |
837 | } | |
b0ba2190 | 838 | errno = err; |
f998180f GS |
839 | } |
840 | return retval; | |
841 | } | |
842 | ||
68dc0745 | 843 | char FAR * |
844 | win32_inet_ntoa(struct in_addr in) | |
0a753a76 | 845 | { |
326b05e3 GS |
846 | StartSockets(); |
847 | return inet_ntoa(in); | |
0a753a76 | 848 | } |
849 | ||
68dc0745 | 850 | unsigned long |
851 | win32_inet_addr(const char FAR *cp) | |
0a753a76 | 852 | { |
326b05e3 GS |
853 | StartSockets(); |
854 | return inet_addr(cp); | |
0a753a76 | 855 | } |
68dc0745 | 856 | |
857 | /* | |
858 | * Networking stubs | |
859 | */ | |
0a753a76 | 860 | |
68dc0745 | 861 | void |
862 | win32_endhostent() | |
0a753a76 | 863 | { |
073dd035 | 864 | win32_croak_not_implemented("endhostent"); |
0a753a76 | 865 | } |
866 | ||
68dc0745 | 867 | void |
868 | win32_endnetent() | |
0a753a76 | 869 | { |
073dd035 | 870 | win32_croak_not_implemented("endnetent"); |
0a753a76 | 871 | } |
872 | ||
68dc0745 | 873 | void |
874 | win32_endprotoent() | |
0a753a76 | 875 | { |
073dd035 | 876 | win32_croak_not_implemented("endprotoent"); |
0a753a76 | 877 | } |
878 | ||
68dc0745 | 879 | void |
880 | win32_endservent() | |
0a753a76 | 881 | { |
073dd035 | 882 | win32_croak_not_implemented("endservent"); |
0a753a76 | 883 | } |
884 | ||
885 | ||
68dc0745 | 886 | struct netent * |
887 | win32_getnetent(void) | |
0a753a76 | 888 | { |
073dd035 | 889 | win32_croak_not_implemented("getnetent"); |
68dc0745 | 890 | return (struct netent *) NULL; |
0a753a76 | 891 | } |
892 | ||
68dc0745 | 893 | struct netent * |
894 | win32_getnetbyname(char *name) | |
0a753a76 | 895 | { |
073dd035 | 896 | win32_croak_not_implemented("getnetbyname"); |
68dc0745 | 897 | return (struct netent *)NULL; |
0a753a76 | 898 | } |
899 | ||
68dc0745 | 900 | struct netent * |
901 | win32_getnetbyaddr(long net, int type) | |
0a753a76 | 902 | { |
073dd035 | 903 | win32_croak_not_implemented("getnetbyaddr"); |
68dc0745 | 904 | return (struct netent *)NULL; |
0a753a76 | 905 | } |
906 | ||
68dc0745 | 907 | struct protoent * |
908 | win32_getprotoent(void) | |
0a753a76 | 909 | { |
073dd035 | 910 | win32_croak_not_implemented("getprotoent"); |
68dc0745 | 911 | return (struct protoent *) NULL; |
0a753a76 | 912 | } |
913 | ||
68dc0745 | 914 | struct servent * |
915 | win32_getservent(void) | |
0a753a76 | 916 | { |
073dd035 | 917 | win32_croak_not_implemented("getservent"); |
68dc0745 | 918 | return (struct servent *) NULL; |
0a753a76 | 919 | } |
920 | ||
68dc0745 | 921 | void |
922 | win32_sethostent(int stayopen) | |
0a753a76 | 923 | { |
073dd035 | 924 | win32_croak_not_implemented("sethostent"); |
0a753a76 | 925 | } |
926 | ||
927 | ||
68dc0745 | 928 | void |
929 | win32_setnetent(int stayopen) | |
0a753a76 | 930 | { |
073dd035 | 931 | win32_croak_not_implemented("setnetent"); |
0a753a76 | 932 | } |
933 | ||
934 | ||
68dc0745 | 935 | void |
936 | win32_setprotoent(int stayopen) | |
0a753a76 | 937 | { |
073dd035 | 938 | win32_croak_not_implemented("setprotoent"); |
0a753a76 | 939 | } |
940 | ||
941 | ||
68dc0745 | 942 | void |
943 | win32_setservent(int stayopen) | |
0a753a76 | 944 | { |
073dd035 | 945 | win32_croak_not_implemented("setservent"); |
0a753a76 | 946 | } |
947 | ||
137443ea | 948 | static struct servent* |
949 | win32_savecopyservent(struct servent*d, struct servent*s, const char *proto) | |
950 | { | |
951 | d->s_name = s->s_name; | |
952 | d->s_aliases = s->s_aliases; | |
953 | d->s_port = s->s_port; | |
8cbe99e5 | 954 | if (s->s_proto && strlen(s->s_proto)) |
137443ea | 955 | d->s_proto = s->s_proto; |
0af56dfe | 956 | else |
c69f6586 | 957 | if (proto && strlen(proto)) |
137443ea | 958 | d->s_proto = (char *)proto; |
959 | else | |
960 | d->s_proto = "tcp"; | |
961 | ||
962 | return d; | |
963 | } | |
964 | ||
0a753a76 | 965 |