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