source: trunk/third/perl/win32/win32sck.c @ 14545

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