Add missing win32_closesocket() and export it (extension writers' complaint).
[p5sagit/p5-mst-13.2.git] / win32 / win32sck.c
1 /* win32sck.c
2  *
3  * (c) 1995 Microsoft Corporation. All rights reserved. 
4  *              Developed by hip communications inc., http://info.hip.com/info/
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  */
10
11 #include <windows.h>
12 #define WIN32_LEAN_AND_MEAN
13 #include "EXTERN.h"
14 #include "perl.h"
15 #include <sys/socket.h>
16 #include <fcntl.h>
17 #include <sys/stat.h>
18 #include <assert.h>
19
20 #undef htonl
21 #undef htons
22 #undef ntohl
23 #undef ntohs
24 #undef inet_addr
25 #undef inet_ntoa
26 #undef socket
27 #undef bind
28 #undef listen
29 #undef accept
30 #undef connect
31 #undef send
32 #undef sendto
33 #undef recv
34 #undef recvfrom
35 #undef shutdown
36 #undef closesocket
37 #undef ioctlsocket
38 #undef setsockopt
39 #undef getsockopt
40 #undef getpeername
41 #undef getsockname
42 #undef gethostname
43 #undef gethostbyname
44 #undef gethostbyaddr
45 #undef getprotobyname
46 #undef getprotobynumber
47 #undef getservbyname
48 #undef getservbyport
49 #undef select
50 #undef endhostent
51 #undef endnetent
52 #undef endprotoent
53 #undef endservent
54 #undef getnetent
55 #undef getnetbyname
56 #undef getnetbyaddr
57 #undef getprotoent
58 #undef getservent
59 #undef sethostent
60 #undef setnetent
61 #undef setprotoent
62 #undef setservent
63
64 /* thanks to Beverly Brown      (beverly@datacube.com) */
65 #ifdef USE_SOCKETS_AS_HANDLES
66 #       define OPEN_SOCKET(x)   _open_osfhandle(x,O_RDWR|O_BINARY)
67 #       define TO_SOCKET(x)     _get_osfhandle(x)
68 #else
69 #       define OPEN_SOCKET(x)   (x)
70 #       define TO_SOCKET(x)     (x)
71 #endif  /* USE_SOCKETS_AS_HANDLES */
72
73 #define StartSockets() \
74     STMT_START {                                        \
75         if (!wsock_started)                             \
76             start_sockets();                            \
77     } STMT_END
78
79 #define EndSockets() \
80     STMT_START {                                        \
81         if (wsock_started)                              \
82             WSACleanup();                               \
83     } STMT_END
84
85 #define SOCKET_TEST(x, y) \
86     STMT_START {                                        \
87         StartSockets();                                 \
88         if((x) == (y))                                  \
89             errno = WSAGetLastError();                  \
90     } STMT_END
91
92 #define SOCKET_TEST_ERROR(x) SOCKET_TEST(x, SOCKET_ERROR)
93
94 static struct servent* win32_savecopyservent(struct servent*d,
95                                              struct servent*s,
96                                              const char *proto);
97
98 __declspec(thread) struct servent myservent;
99 static int wsock_started = 0;
100
101 void
102 start_sockets(void) 
103 {
104     unsigned short version;
105     WSADATA retdata;
106     int ret;
107     int iSockOpt = SO_SYNCHRONOUS_NONALERT;
108
109     /*
110      * initalize the winsock interface and insure that it is
111      * cleaned up at exit.
112      */
113     version = 0x101;
114     if(ret = WSAStartup(version, &retdata))
115         croak("Unable to locate winsock library!\n");
116     if(retdata.wVersion != version)
117         croak("Could not find version 1.1 of winsock dll\n");
118
119     /* atexit((void (*)(void)) EndSockets); */
120
121 #ifdef USE_SOCKETS_AS_HANDLES
122     /*
123      * Enable the use of sockets as filehandles
124      */
125     setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE,
126                 (char *)&iSockOpt, sizeof(iSockOpt));
127 #endif  /* USE_SOCKETS_AS_HANDLES */
128     wsock_started = 1;
129 }
130
131
132 #ifndef USE_SOCKETS_AS_HANDLES
133 FILE *
134 myfdopen(int fd, char *mode)
135 {
136     FILE *fp;
137     char sockbuf[256];
138     int optlen = sizeof(sockbuf);
139     int retval;
140
141     if (!wsock_started)
142         return(fdopen(fd, mode));
143
144     retval = getsockopt((SOCKET)fd, SOL_SOCKET, SO_TYPE, sockbuf, &optlen);
145     if(retval == SOCKET_ERROR && WSAGetLastError() == WSAENOTSOCK) {
146         return(fdopen(fd, mode));
147     }
148
149     /*
150      * If we get here, then fd is actually a socket.
151      */
152     Newz(1310, fp, 1, FILE);
153     if(fp == NULL) {
154         errno = ENOMEM;
155         return NULL;
156     }
157
158     fp->_file = fd;
159     if(*mode == 'r')
160         fp->_flag = _IOREAD;
161     else
162         fp->_flag = _IOWRT;
163    
164     return fp;
165 }
166 #endif  /* USE_SOCKETS_AS_HANDLES */
167
168
169 u_long
170 win32_htonl(u_long hostlong)
171 {
172     StartSockets();
173     return htonl(hostlong);
174 }
175
176 u_short
177 win32_htons(u_short hostshort)
178 {
179     StartSockets();
180     return htons(hostshort);
181 }
182
183 u_long
184 win32_ntohl(u_long netlong)
185 {
186     StartSockets();
187     return ntohl(netlong);
188 }
189
190 u_short
191 win32_ntohs(u_short netshort)
192 {
193     StartSockets();
194     return ntohs(netshort);
195 }
196
197
198
199 SOCKET
200 win32_accept(SOCKET s, struct sockaddr *addr, int *addrlen)
201 {
202     SOCKET r;
203
204     SOCKET_TEST((r = accept(TO_SOCKET(s), addr, addrlen)), INVALID_SOCKET);
205     return OPEN_SOCKET(r);
206 }
207
208 int
209 win32_bind(SOCKET s, const struct sockaddr *addr, int addrlen)
210 {
211     int r;
212
213     SOCKET_TEST_ERROR(r = bind(TO_SOCKET(s), addr, addrlen));
214     return r;
215 }
216
217 int
218 win32_connect(SOCKET s, const struct sockaddr *addr, int addrlen)
219 {
220     int r;
221
222     SOCKET_TEST_ERROR(r = connect(TO_SOCKET(s), addr, addrlen));
223     return r;
224 }
225
226
227 int
228 win32_getpeername(SOCKET s, struct sockaddr *addr, int *addrlen)
229 {
230     int r;
231
232     SOCKET_TEST_ERROR(r = getpeername(TO_SOCKET(s), addr, addrlen));
233     return r;
234 }
235
236 int
237 win32_getsockname(SOCKET s, struct sockaddr *addr, int *addrlen)
238 {
239     int r;
240
241     SOCKET_TEST_ERROR(r = getsockname(TO_SOCKET(s), addr, addrlen));
242     return r;
243 }
244
245 int
246 win32_getsockopt(SOCKET s, int level, int optname, char *optval, int *optlen)
247 {
248     int r;
249
250     SOCKET_TEST_ERROR(r = getsockopt(TO_SOCKET(s), level, optname, optval, optlen));
251     return r;
252 }
253
254 int
255 win32_ioctlsocket(SOCKET s, long cmd, u_long *argp)
256 {
257     int r;
258
259     SOCKET_TEST_ERROR(r = ioctlsocket(TO_SOCKET(s), cmd, argp));
260     return r;
261 }
262
263 int
264 win32_listen(SOCKET s, int backlog)
265 {
266     int r;
267
268     SOCKET_TEST_ERROR(r = listen(TO_SOCKET(s), backlog));
269     return r;
270 }
271
272 int
273 win32_recv(SOCKET s, char *buf, int len, int flags)
274 {
275     int r;
276
277     SOCKET_TEST_ERROR(r = recv(TO_SOCKET(s), buf, len, flags));
278     return r;
279 }
280
281 int
282 win32_recvfrom(SOCKET s, char *buf, int len, int flags, struct sockaddr *from, int *fromlen)
283 {
284     int r;
285
286     SOCKET_TEST_ERROR(r = recvfrom(TO_SOCKET(s), buf, len, flags, from, fromlen));
287     return r;
288 }
289
290 /* select contributed by Vincent R. Slyngstad (vrs@ibeam.intel.com) */
291 int
292 win32_select(int nfds, int* rd, int* wr, int* ex, const struct timeval* timeout)
293 {
294     long r;
295     int dummy = 0;
296     int i, fd, bit, offset;
297     FD_SET nrd, nwr, nex,*prd,*pwr,*pex;
298
299     if (!rd)
300         rd = &dummy, prd = NULL;
301     else
302         prd = &nrd;
303     if (!wr)
304         wr = &dummy, pwr = NULL;
305     else
306         pwr = &nwr;
307     if (!ex)
308         ex = &dummy, pex = NULL;
309     else
310         pex = &nex;
311
312     FD_ZERO(&nrd);
313     FD_ZERO(&nwr);
314     FD_ZERO(&nex);
315     for (i = 0; i < nfds; i++) {
316         fd = TO_SOCKET(i);
317         bit = 1L<<(i % (sizeof(int)*8));
318         offset = i / (sizeof(int)*8);
319         if (rd[offset] & bit)
320             FD_SET(fd, &nrd);
321         if (wr[offset] & bit)
322             FD_SET(fd, &nwr);
323         if (ex[offset] & bit)
324             FD_SET(fd, &nex);
325     }
326
327     SOCKET_TEST_ERROR(r = select(nfds, prd, pwr, pex, timeout));
328
329     for (i = 0; i < nfds; i++) {
330         fd = TO_SOCKET(i);
331         bit = 1L<<(i % (sizeof(int)*8));
332         offset = i / (sizeof(int)*8);
333         if (rd[offset] & bit) {
334             if (!__WSAFDIsSet(fd, &nrd))
335                 rd[offset] &= ~bit;
336         }
337         if (wr[offset] & bit) {
338             if (!__WSAFDIsSet(fd, &nwr))
339                 wr[offset] &= ~bit;
340         }
341         if (ex[offset] & bit) {
342             if (!__WSAFDIsSet(fd, &nex))
343                 ex[offset] &= ~bit;
344         }
345     }
346     return r;
347 }
348
349 int
350 win32_send(SOCKET s, const char *buf, int len, int flags)
351 {
352     int r;
353
354     SOCKET_TEST_ERROR(r = send(TO_SOCKET(s), buf, len, flags));
355     return r;
356 }
357
358 int
359 win32_sendto(SOCKET s, const char *buf, int len, int flags,
360              const struct sockaddr *to, int tolen)
361 {
362     int r;
363
364     SOCKET_TEST_ERROR(r = sendto(TO_SOCKET(s), buf, len, flags, to, tolen));
365     return r;
366 }
367
368 int
369 win32_setsockopt(SOCKET s, int level, int optname, const char *optval, int optlen)
370 {
371     int r;
372
373     SOCKET_TEST_ERROR(r = setsockopt(TO_SOCKET(s), level, optname, optval, optlen));
374     return r;
375 }
376     
377 int
378 win32_shutdown(SOCKET s, int how)
379 {
380     int r;
381
382     SOCKET_TEST_ERROR(r = shutdown(TO_SOCKET(s), how));
383     return r;
384 }
385
386 int
387 win32_closesocket(SOCKET s)
388 {
389     int r;
390
391     SOCKET_TEST_ERROR(r = closesocket(TO_SOCKET(s)));
392     return r;
393 }
394
395 SOCKET
396 win32_socket(int af, int type, int protocol)
397 {
398     SOCKET s;
399
400 #ifndef USE_SOCKETS_AS_HANDLES
401     SOCKET_TEST(s = socket(af, type, protocol), INVALID_SOCKET);
402 #else
403     StartSockets();
404     if((s = socket(af, type, protocol)) == INVALID_SOCKET)
405         errno = WSAGetLastError();
406     else
407         s = OPEN_SOCKET(s);
408 #endif  /* USE_SOCKETS_AS_HANDLES */
409
410     return s;
411 }
412
413 #undef fclose
414 int
415 my_fclose (FILE *pf)
416 {
417     int osf, retval;
418     if (!wsock_started)         /* No WinSock? */
419         return(fclose(pf));     /* Then not a socket. */
420     osf = TO_SOCKET(fileno(pf));/* Get it now before it's gone! */
421     retval = fclose(pf);        /* Must fclose() before closesocket() */
422     if (osf != -1
423         && closesocket(osf) == SOCKET_ERROR
424         && WSAGetLastError() != WSAENOTSOCK)
425     {
426         return EOF;
427     }
428     return retval;
429 }
430
431 struct hostent *
432 win32_gethostbyaddr(const char *addr, int len, int type)
433 {
434     struct hostent *r;
435
436     SOCKET_TEST(r = gethostbyaddr(addr, len, type), NULL);
437     return r;
438 }
439
440 struct hostent *
441 win32_gethostbyname(const char *name)
442 {
443     struct hostent *r;
444
445     SOCKET_TEST(r = gethostbyname(name), NULL);
446     return r;
447 }
448
449 int
450 win32_gethostname(char *name, int len)
451 {
452     int r;
453
454     SOCKET_TEST_ERROR(r = gethostname(name, len));
455     return r;
456 }
457
458 struct protoent *
459 win32_getprotobyname(const char *name)
460 {
461     struct protoent *r;
462
463     SOCKET_TEST(r = getprotobyname(name), NULL);
464     return r;
465 }
466
467 struct protoent *
468 win32_getprotobynumber(int num)
469 {
470     struct protoent *r;
471
472     SOCKET_TEST(r = getprotobynumber(num), NULL);
473     return r;
474 }
475
476 struct servent *
477 win32_getservbyname(const char *name, const char *proto)
478 {
479     struct servent *r;
480    
481     SOCKET_TEST(r = getservbyname(name, proto), NULL);
482     if (r) {
483         r = win32_savecopyservent(&myservent, r, proto);
484     }
485     return r;
486 }
487
488 struct servent *
489 win32_getservbyport(int port, const char *proto)
490 {
491     struct servent *r;
492
493     SOCKET_TEST(r = getservbyport(port, proto), NULL);
494     if (r) {
495         r = win32_savecopyservent(&myservent, r, proto);
496     }
497     return r;
498 }
499
500 char FAR *
501 win32_inet_ntoa(struct in_addr in)
502 {
503     StartSockets();
504     return inet_ntoa(in);
505 }
506
507 unsigned long
508 win32_inet_addr(const char FAR *cp)
509 {
510     StartSockets();
511     return inet_addr(cp);
512 }
513
514 /*
515  * Networking stubs
516  */
517
518 void
519 win32_endhostent() 
520 {
521     croak("endhostent not implemented!\n");
522 }
523
524 void
525 win32_endnetent()
526 {
527     croak("endnetent not implemented!\n");
528 }
529
530 void
531 win32_endprotoent()
532 {
533     croak("endprotoent not implemented!\n");
534 }
535
536 void
537 win32_endservent()
538 {
539     croak("endservent not implemented!\n");
540 }
541
542
543 struct netent *
544 win32_getnetent(void) 
545 {
546     croak("getnetent not implemented!\n");
547     return (struct netent *) NULL;
548 }
549
550 struct netent *
551 win32_getnetbyname(char *name) 
552 {
553     croak("getnetbyname not implemented!\n");
554     return (struct netent *)NULL;
555 }
556
557 struct netent *
558 win32_getnetbyaddr(long net, int type) 
559 {
560     croak("getnetbyaddr not implemented!\n");
561     return (struct netent *)NULL;
562 }
563
564 struct protoent *
565 win32_getprotoent(void) 
566 {
567     croak("getprotoent not implemented!\n");
568     return (struct protoent *) NULL;
569 }
570
571 struct servent *
572 win32_getservent(void) 
573 {
574     croak("getservent not implemented!\n");
575     return (struct servent *) NULL;
576 }
577
578 void
579 win32_sethostent(int stayopen)
580 {
581     croak("sethostent not implemented!\n");
582 }
583
584
585 void
586 win32_setnetent(int stayopen)
587 {
588     croak("setnetent not implemented!\n");
589 }
590
591
592 void
593 win32_setprotoent(int stayopen)
594 {
595     croak("setprotoent not implemented!\n");
596 }
597
598
599 void
600 win32_setservent(int stayopen)
601 {
602     croak("setservent not implemented!\n");
603 }
604
605 #define WIN32IO_IS_STDIO
606 #include <io.h>
607
608 #ifdef __cplusplus
609 extern "C" {
610 #endif
611 #include "win32iop.h"
612 #ifdef __cplusplus
613 }
614 #endif
615
616 static struct servent*
617 win32_savecopyservent(struct servent*d, struct servent*s, const char *proto)
618 {
619     d->s_name = s->s_name;
620     d->s_aliases = s->s_aliases;
621     d->s_port = s->s_port;
622 #ifndef __BORLANDC__    /* Buggy on Win95 and WinNT-with-Borland-WSOCK */
623     if (!IsWin95() && s->s_proto && strlen(s->s_proto))
624         d->s_proto = s->s_proto;
625     else
626 #endif
627         if (proto && strlen(proto))
628         d->s_proto = (char *)proto;
629     else
630         d->s_proto = "tcp";
631    
632     return d;
633 }
634
635