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