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