1/* 2 Title: Network functions. 3 4 Copyright (c) 2000-7, 2016, 2018, 2019 David C. J. Matthews 5 6 This library is free software; you can redistribute it and/or 7 modify it under the terms of the GNU Lesser General Public 8 License version 2.1 as published by the Free Software Foundation. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19*/ 20#ifdef HAVE_CONFIG_H 21#include "config.h" 22#elif defined(_WIN32) 23#include "winconfig.h" 24#else 25#error "No configuration file" 26#endif 27 28#ifdef HAVE_STDIO_H 29#include <stdio.h> 30#endif 31 32#ifdef HAVE_STDLIB_H 33#include <stdlib.h> 34#endif 35 36#ifdef HAVE_ERRNO_H 37#include <errno.h> 38#endif 39 40#ifdef HAVE_ASSERT_H 41#include <assert.h> 42#define ASSERT(x) assert(x) 43#else 44#define ASSERT(x) 0 45#endif 46 47#ifdef HAVE_STRING_H 48#include <string.h> 49#endif 50 51#ifdef HAVE_UNISTD_H 52#include <unistd.h> 53#endif 54 55#ifdef HAVE_SYS_PARAM_H 56#include <sys/param.h> 57#endif 58 59#ifdef HAVE_SYS_TIME_H 60#include <sys/time.h> 61#endif 62 63#ifdef HAVE_NETDB_H 64#include <netdb.h> 65#endif 66 67#ifdef HAVE_SYS_SOCKET_H 68#include <sys/socket.h> 69#endif 70 71#ifdef HAVE_NETINET_IN_H 72#include <netinet/in.h> 73#endif 74 75#ifdef HAVE_NETINET_TCP_H 76#include <netinet/tcp.h> 77#endif 78 79#ifdef HAVE_UNISTD_H 80#include <unistd.h> 81#endif 82 83#ifdef HAVE_SYS_IOCTL_H 84#include <sys/ioctl.h> 85#endif 86 87#ifdef HAVE_SYS_UN_H 88#include <sys/un.h> 89#endif 90 91#ifdef HAVE_SYS_FILIO_H 92#include <sys/filio.h> 93#endif 94 95#ifdef HAVE_SYS_SOCKIO_H 96#include <sys/sockio.h> 97#endif 98 99#ifdef HAVE_SYS_SELECT_H 100#include <sys/select.h> 101#endif 102 103#ifdef HAVE_ARPA_INET_H 104#include <arpa/inet.h> 105#endif 106 107#ifdef HAVE_LIMITS_H 108#include <limits.h> 109#endif 110 111#ifndef HAVE_SOCKLEN_T 112typedef int socklen_t; 113#endif 114 115 116#if (defined(_WIN32)) 117#include <winsock2.h> 118#include <ws2tcpip.h> // For getaddrinfo 119#else 120typedef int SOCKET; 121#endif 122 123#ifdef HAVE_WINDOWS_H 124#include <windows.h> 125#endif 126 127#include <new> 128 129#include "globals.h" 130#include "gc.h" 131#include "arb.h" 132#include "run_time.h" 133#include "mpoly.h" 134#include "processes.h" 135#include "network.h" 136#include "io_internal.h" 137#include "sys.h" 138#include "polystring.h" 139#include "save_vec.h" 140#include "rts_module.h" 141#include "machine_dep.h" 142#include "errors.h" 143#include "rtsentry.h" 144#include "timing.h" 145 146extern "C" { 147 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetAddrList(FirstArgument threadId); 148 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetSockTypeList(FirstArgument threadId); 149 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkCreateSocket(FirstArgument threadId, PolyWord af, PolyWord st, PolyWord prot); 150 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSetOption(FirstArgument threadId, PolyWord code, PolyWord sock, PolyWord opt); 151 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetOption(FirstArgument threadId, PolyWord code, PolyWord arg); 152 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSetLinger(FirstArgument threadId, PolyWord sock, PolyWord linger); 153 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetLinger(FirstArgument threadId, PolyWord arg); 154 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetPeerName(FirstArgument threadId, PolyWord arg); 155 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetSockName(FirstArgument threadId, PolyWord arg); 156 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkBytesAvailable(FirstArgument threadId, PolyWord arg); 157 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetAtMark(FirstArgument threadId, PolyWord arg); 158 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkBind(FirstArgument threadId, PolyWord sock, PolyWord addr); 159 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkListen(FirstArgument threadId, PolyWord sock, PolyWord back); 160 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkShutdown(FirstArgument threadId, PolyWord skt, PolyWord smode); 161 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkCreateSocketPair(FirstArgument threadId, PolyWord af, PolyWord st, PolyWord prot); 162 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkUnixPathToSockAddr(FirstArgument threadId, PolyWord arg); 163 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkUnixSockAddrToPath(FirstArgument threadId, PolyWord arg); 164 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetServByName(FirstArgument threadId, PolyWord servName); 165 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetServByNameAndProtocol(FirstArgument threadId, PolyWord servName, PolyWord protName); 166 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetServByPort(FirstArgument threadId, PolyWord portNo); 167 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetServByPortAndProtocol(FirstArgument threadId, PolyWord portNo, PolyWord protName); 168 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetProtByName(FirstArgument threadId, PolyWord protocolName); 169 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetProtByNo(FirstArgument threadId, PolyWord protoNo); 170 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetHostName(FirstArgument threadId); 171 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetAddrInfo(FirstArgument threadId, PolyWord hostName, PolyWord addrFamily); 172 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetNameInfo(FirstArgument threadId, PolyWord sockAddr); 173 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkCloseSocket(FirstArgument threadId, PolyWord arg); 174 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSelect(FirstArgument threadId, PolyWord fdVecTriple, PolyWord maxMillisecs); 175 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetSocketError(FirstArgument threadId, PolyWord skt); 176 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkConnect(FirstArgument threadId, PolyWord skt, PolyWord addr); 177 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkAccept(FirstArgument threadId, PolyWord skt); 178 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSend(FirstArgument threadId, PolyWord args); 179 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSendTo(FirstArgument threadId, PolyWord args); 180 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReceive(FirstArgument threadId, PolyWord args); 181 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReceiveFrom(FirstArgument threadId, PolyWord args); 182 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetFamilyFromAddress(PolyWord sockAddress); 183 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetAddressAndPortFromIP4(FirstArgument threadId, PolyWord sockAddress); 184 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkCreateIP4Address(FirstArgument threadId, PolyWord ip4Address, PolyWord portNumber); 185 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReturnIP4AddressAny(FirstArgument threadId); 186 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetAddressAndPortFromIP6(FirstArgument threadId, PolyWord sockAddress); 187 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkCreateIP6Address(FirstArgument threadId, PolyWord ip6Address, PolyWord portNumber); 188 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReturnIP6AddressAny(FirstArgument threadId); 189 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkIP6AddressToString(FirstArgument threadId, PolyWord ip6Address); 190 POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkStringToIP6Address(FirstArgument threadId, PolyWord stringRep); 191} 192 193#define SAVE(x) taskData->saveVec.push(x) 194#define ALLOC(n) alloc_and_save(taskData, n) 195#define SIZEOF(x) (sizeof(x)/sizeof(PolyWord)) 196 197#if (defined(_WIN32)) 198static int winsock_init = 0; /* Check that it has been initialised. */ 199 200#else 201#define INVALID_SOCKET (-1) 202#define SOCKET_ERROR (-1) 203#endif 204 205#ifndef HAVE_SOCKLEN_T 206typedef int socklen_t; // This must be int for Windows at least 207#endif 208 209#ifndef SHUT_RD 210#define SHUT_RD 0 211#endif 212 213#ifndef SHUT_WR 214#define SHUT_WR 1 215#endif 216 217#ifndef SHUT_RDWR 218#define SHUT_RDWR 2 219#endif 220 221/* Address families. Although this table is in ascending 222 numerical order of address family nothing depends on that. 223 The only requirement is that "INET" => AF_INET must always 224 be present and "UNIX" => AF_UNIX must be present on Unix. 225 Other entries are entirely optional and are for amusement 226 only. */ 227struct af_tab_struct { 228 const char *af_name; 229 int af_num; 230} af_table[] = 231{ 232#ifdef AF_UNIX 233 { "UNIX", AF_UNIX }, /* This is nearly always there. */ 234#endif 235#ifdef AF_LOCAL 236 { "LOCAL", AF_LOCAL }, 237#endif 238 { "INET", AF_INET }, /* This one should always be there. */ 239#ifdef AF_IMPLINK 240 { "IMPLINK", AF_IMPLINK }, 241#endif 242#ifdef AF_PUP 243 { "PUP", AF_PUP }, 244#endif 245#ifdef AF_CHAOS 246 { "CHAOS", AF_CHAOS }, 247#endif 248#ifdef AF_IPX 249 { "IPX", AF_IPX }, 250#endif 251#ifdef AF_NS 252 { "NS", AF_NS }, 253#endif 254#ifdef AF_ISO 255 { "ISO", AF_ISO }, 256#endif 257#ifdef AF_OSI 258 { "OSI", AF_OSI }, 259#endif 260#ifdef AF_ECMA 261 { "ECMA", AF_ECMA }, 262#endif 263#ifdef AF_DATAKIT 264 { "DATAKIT", AF_DATAKIT }, 265#endif 266#ifdef AF_CCITT 267 { "CCITT", AF_CCITT }, 268#endif 269#ifdef AF_SNA 270 { "SNA", AF_SNA }, 271#endif 272#ifdef AF_DECnet 273 { "DECnet", AF_DECnet }, 274#endif 275#ifdef AF_DLI 276 { "DLI", AF_DLI }, 277#endif 278#ifdef AF_LAT 279 { "LAT", AF_LAT }, 280#endif 281#ifdef AF_HYLINK 282 { "HYLINK", AF_HYLINK }, 283#endif 284#ifdef AF_APPLETALK 285 { "APPLETALK", AF_APPLETALK }, 286#endif 287#ifdef AF_NETBIOS 288 { "NETBIOS", AF_NETBIOS }, 289#endif 290#ifdef AF_ROUTE 291 { "ROUTE", AF_ROUTE }, 292#endif 293#ifdef AF_VOICEVIEW 294 { "VOICEVIEW", AF_VOICEVIEW }, 295#endif 296#ifdef AF_FIREFOX 297 { "FIREFOX", AF_FIREFOX }, 298#endif 299#ifdef AF_BAN 300 { "BAN", AF_BAN }, 301#endif 302#ifdef AF_LINK 303 { "LINK", AF_LINK }, 304#endif 305#ifdef AF_COIP 306 { "COIP", AF_COIP }, 307#endif 308#ifdef AF_CNT 309 { "CNT", AF_CNT }, 310#endif 311#ifdef AF_SIP 312 { "SIP", AF_SIP }, 313#endif 314#ifdef AF_ISDN 315 { "ISDN", AF_ISDN }, 316#endif 317#ifdef AF_E164 318 { "E164", AF_E164 }, 319#endif 320#ifdef AF_INET6 321 { "INET6", AF_INET6 }, // This one should always be there. 322#endif 323#ifdef AF_NATM 324 { "NATM", AF_NATM }, 325#endif 326#ifdef AF_ATM 327 { "ATM", AF_ATM }, 328#endif 329#ifdef AF_NETGRAPH 330 { "NETGRAPH", AF_NETGRAPH }, 331#endif 332#ifdef AF_CLUSTER 333 { "CLUSTER", AF_CLUSTER }, 334#endif 335#ifdef AF_12844 336 { "12844", AF_12844 }, 337#endif 338#ifdef AF_IRDA 339 { "IRDA", AF_IRDA }, 340#endif 341#ifdef AF_NETDES 342 { "NETDES", AF_NETDES }, 343#endif 344#ifdef AF_TCNPROCESS 345 { "TCNPROCESS", AF_TCNPROCESS }, 346#endif 347#ifdef AF_TCNMESSAGE 348 { "TCNMESSAGE", AF_TCNMESSAGE }, 349#endif 350#ifdef AF_ICLFXBM 351 { "ICLFXBM", AF_ICLFXBM }, 352#endif 353#ifdef AF_BTH 354 { "BTH", AF_BTH }, 355#endif 356#ifdef AF_HYPERV 357 { "HYPERV", AF_HYPERV }, 358#endif 359#ifdef AF_FILE 360 { "FILE", AF_FILE }, 361#endif 362#ifdef AF_AX25 363 { "AX25", AF_AX25 }, 364#endif 365#ifdef AF_NETROM 366 { "NETROM", AF_NETROM }, 367#endif 368#ifdef AF_BRIDGE 369 { "BRIDGE", AF_BRIDGE }, 370#endif 371#ifdef AF_ATMPVC 372 { "ATMPVC", AF_ATMPVC }, 373#endif 374#ifdef AF_X25 375 { "X25", AF_X25 }, 376#endif 377#ifdef AF_ROSE 378 { "ROSE", AF_ROSE }, 379#endif 380#ifdef AF_NETBEUI 381 { "NETBEUI", AF_NETBEUI }, 382#endif 383#ifdef AF_SECURITY 384 { "SECURITY", AF_SECURITY }, 385#endif 386#ifdef AF_KEY 387 { "KEY", AF_KEY }, 388#endif 389#ifdef AF_NETLINK 390 { "NETLINK", AF_NETLINK }, 391#endif 392#ifdef AF_PACKET 393 { "PACKET", AF_PACKET }, 394#endif 395#ifdef AF_ASH 396 { "ASH", AF_ASH }, 397#endif 398#ifdef AF_ECONET 399 { "ECONET", AF_ECONET }, 400#endif 401#ifdef AF_ATMSVC 402 { "ATMSVC", AF_ATMSVC }, 403#endif 404#ifdef AF_RDS 405 { "RDS", AF_RDS }, 406#endif 407#ifdef AF_PPPOX 408 { "PPPOX", AF_PPPOX }, 409#endif 410#ifdef AF_WANPIPE 411 { "WANPIPE", AF_WANPIPE }, 412#endif 413#ifdef AF_LLC 414 { "LLC", AF_LLC }, 415#endif 416#ifdef AF_IB 417 { "IB", AF_IB }, 418#endif 419#ifdef AF_MPLS 420 { "MPLS", AF_MPLS }, 421#endif 422#ifdef AF_CAN 423 { "CAN", AF_CAN }, 424#endif 425#ifdef AF_TIPC 426 { "TIPC", AF_TIPC }, 427#endif 428#ifdef AF_BLUETOOTH 429 { "BLUETOOTH", AF_BLUETOOTH }, 430#endif 431#ifdef AF_IUCV 432 { "IUCV", AF_IUCV }, 433#endif 434#ifdef AF_RXRPC 435 { "RXRPC", AF_RXRPC }, 436#endif 437#ifdef AF_PHONET 438 { "PHONET", AF_PHONET }, 439#endif 440#ifdef AF_IEEE802154 441 { "IEEE802154", AF_IEEE802154 }, 442#endif 443#ifdef AF_CAIF 444 { "CAIF", AF_CAIF }, 445#endif 446#ifdef AF_ALG 447 { "ALG", AF_ALG }, 448#endif 449#ifdef AF_NFC 450 { "NFC", AF_NFC }, 451#endif 452#ifdef AF_VSOCK 453 { "VSOCK", AF_VSOCK }, 454#endif 455#ifdef AF_KCM 456 { "KCM", AF_KCM }, 457#endif 458}; 459 460/* Socket types. Only STREAM and DGRAM are required. */ 461struct sk_tab_struct { 462 const char *sk_name; 463 int sk_num; 464} sk_table[] = 465{ 466 { "STREAM", SOCK_STREAM }, 467 { "DGRAM", SOCK_DGRAM }, 468 { "RAW", SOCK_RAW }, 469 { "RDM", SOCK_RDM }, 470 { "SEQPACKET", SOCK_SEQPACKET }, 471#ifdef SOCK_DCCP 472 { "DCCP", SOCK_DCCP }, 473#endif 474}; 475 476static Handle makeProtoEntry(TaskData *taskData, struct protoent *proto); 477static Handle mkAftab(TaskData *taskData, void*, char *p); 478static Handle mkSktab(TaskData *taskData, void*, char *p); 479static Handle setSocketOption(TaskData *taskData, Handle sockHandle, Handle optHandle, int level, int opt); 480static Handle getSocketOption(TaskData *taskData, Handle args, int level, int opt); 481 482#if (defined(_WIN32)) 483#define GETERROR (WSAGetLastError()) 484#define TOOMANYFILES WSAEMFILE 485#define NOMEMORY WSA_NOT_ENOUGH_MEMORY 486#define STREAMCLOSED WSA_INVALID_HANDLE 487#define WOULDBLOCK WSAEWOULDBLOCK 488#define INPROGRESS WSAEINPROGRESS 489#define CALLINTERRUPTED WSAEINTR 490#undef EBADF 491#undef EMFILE 492#undef EAGAIN 493#undef EINTR 494#undef EWOULDBLOCK 495#undef ENOMEM 496#else 497#define GETERROR (errno) 498#define TOOMANYFILES EMFILE 499#define NOMEMORY ENOMEM 500#define STREAMCLOSED EBADF 501#define ERRORNUMBER errno 502#define FILEDOESNOTEXIST ENOENT 503#define WOULDBLOCK EWOULDBLOCK 504#define INPROGRESS EINPROGRESS 505#define CALLINTERRUPTED EINTR 506#endif 507 508 509// Wait until "select" returns. In Windows this is used only for networking. 510class WaitSelect: public Waiter 511{ 512public: 513 WaitSelect(unsigned maxMillisecs=(unsigned)-1); 514 virtual void Wait(unsigned maxMillisecs); 515 void SetRead(SOCKET fd) { FD_SET(fd, &readSet); } 516 void SetWrite(SOCKET fd) { FD_SET(fd, &writeSet); } 517 void SetExcept(SOCKET fd) { FD_SET(fd, &exceptSet); } 518 bool IsSetRead(SOCKET fd) { return FD_ISSET(fd, &readSet) != 0; } 519 bool IsSetWrite(SOCKET fd) { return FD_ISSET(fd, &writeSet) != 0; } 520 bool IsSetExcept(SOCKET fd) { return FD_ISSET(fd, &exceptSet) != 0; } 521 // Save the result of the select call and any associated error 522 int SelectResult(void) { return selectResult; } 523 int SelectError(void) { return errorResult; } 524private: 525 fd_set readSet, writeSet, exceptSet; 526 int selectResult; 527 int errorResult; 528 unsigned maxTime; 529}; 530 531WaitSelect::WaitSelect(unsigned maxMillisecs) 532{ 533 FD_ZERO(&readSet); 534 FD_ZERO(&writeSet); 535 FD_ZERO(&exceptSet); 536 selectResult = 0; 537 errorResult = 0; 538 maxTime = maxMillisecs; 539} 540 541void WaitSelect::Wait(unsigned maxMillisecs) 542{ 543 if (maxTime < maxMillisecs) maxMillisecs = maxTime; 544 struct timeval toWait = { 0, 0 }; 545 toWait.tv_sec = maxMillisecs / 1000; 546 toWait.tv_usec = (maxMillisecs % 1000) * 1000; 547 selectResult = select(FD_SETSIZE, &readSet, &writeSet, &exceptSet, &toWait); 548 if (selectResult < 0) errorResult = GETERROR; 549} 550 551#if (defined(_WIN32)) 552class WinSocket : public WinStreamBase 553{ 554public: 555 WinSocket(SOCKET skt) : socket(skt) {} 556 557 virtual SOCKET getSocket() { 558 return socket; 559 } 560 561 virtual int pollTest() { 562 // We can poll for any of these. 563 return POLL_BIT_IN | POLL_BIT_OUT | POLL_BIT_PRI; 564 } 565 566 virtual int poll(TaskData *taskData, int test); 567 568public: 569 SOCKET socket; 570}; 571 572// Poll without blocking. 573int WinSocket::poll(TaskData *taskData, int bits) 574{ 575 int result = 0; 576 if (bits & POLL_BIT_PRI) 577 { 578 u_long atMark = 0; 579 if (ioctlsocket(socket, SIOCATMARK, &atMark) != 0) 580 raise_syscall(taskData, "ioctlsocket failed", GETERROR); 581 if (atMark) { result |= POLL_BIT_PRI; } 582 } 583 if (bits & (POLL_BIT_IN | POLL_BIT_OUT)) 584 { 585 FD_SET readFds, writeFds; 586 TIMEVAL poll = { 0, 0 }; 587 FD_ZERO(&readFds); FD_ZERO(&writeFds); 588 if (bits & POLL_BIT_IN) FD_SET(socket, &readFds); 589 if (bits & POLL_BIT_OUT) FD_SET(socket, &writeFds); 590 int selRes = select(FD_SETSIZE, &readFds, &writeFds, NULL, &poll); 591 if (selRes < 0) 592 raise_syscall(taskData, "select failed", GETERROR); 593 else if (selRes > 0) 594 { 595 // N.B. select only tells us about out-of-band data if SO_OOBINLINE is FALSE. */ 596 if (FD_ISSET(socket, &readFds)) result |= POLL_BIT_IN; 597 if (FD_ISSET(socket, &writeFds)) result |= POLL_BIT_OUT; 598 } 599 } 600 return result; 601} 602 603static SOCKET getStreamSocket(TaskData *taskData, PolyWord strm) 604{ 605 WinSocket *winskt = *(WinSocket**)(strm.AsObjPtr()); 606 if (winskt == 0) 607 raise_syscall(taskData, "Stream is closed", STREAMCLOSED); 608 return winskt->getSocket(); 609} 610 611static Handle wrapStreamSocket(TaskData *taskData, SOCKET skt) 612{ 613 try { 614 WinSocket *winskt = new WinSocket(skt); 615 return MakeVolatileWord(taskData, winskt); 616 } 617 catch (std::bad_alloc&) { 618 raise_syscall(taskData, "Insufficient memory", NOMEMORY); 619 } 620} 621 622#else 623 624static SOCKET getStreamSocket(TaskData *taskData, PolyWord strm) 625{ 626 return getStreamFileDescriptor(taskData, strm); 627} 628 629static Handle wrapStreamSocket(TaskData *taskData, SOCKET skt) 630{ 631 return wrapFileDescriptor(taskData, skt); 632} 633#endif 634 635static Handle makeProtoEntry(TaskData *taskData, struct protoent *proto) 636{ 637 int i; 638 char **p; 639 Handle aliases, name, protocol, result; 640 641 /* Canonical name. */ 642 name = SAVE(C_string_to_Poly(taskData, proto->p_name)); 643 644 /* Aliases. */ 645 for (i=0, p = proto->p_aliases; *p != NULL; p++, i++); 646 aliases = convert_string_list(taskData, i, proto->p_aliases); 647 648 /* Protocol number. */ 649 protocol = Make_fixed_precision(taskData, proto->p_proto); 650 651 /* Make the result structure. */ 652 result = ALLOC(3); 653 DEREFHANDLE(result)->Set(0, name->Word()); 654 DEREFHANDLE(result)->Set(1, aliases->Word()); 655 DEREFHANDLE(result)->Set(2, protocol->Word()); 656 return result; 657} 658 659static Handle makeServEntry(TaskData *taskData, struct servent *serv) 660{ 661 int i; 662 char **p; 663 Handle aliases, name, protocol, result, port; 664 665 /* Canonical name. */ 666 name = SAVE(C_string_to_Poly(taskData, serv->s_name)); 667 668 /* Aliases. */ 669 for (i=0, p = serv->s_aliases; *p != NULL; p++, i++); 670 aliases = convert_string_list(taskData, i, serv->s_aliases); 671 672 /* Port number. */ 673 port = Make_fixed_precision(taskData, ntohs(serv->s_port)); 674 675 /* Protocol name. */ 676 protocol = SAVE(C_string_to_Poly(taskData, serv->s_proto)); 677 678 /* Make the result structure. */ 679 result = ALLOC(4); 680 DEREFHANDLE(result)->Set(0, name->Word()); 681 DEREFHANDLE(result)->Set(1, aliases->Word()); 682 DEREFHANDLE(result)->Set(2, port->Word()); 683 DEREFHANDLE(result)->Set(3, protocol->Word()); 684 return result; 685} 686 687static Handle mkAftab(TaskData *taskData, void *arg, char *p) 688{ 689 struct af_tab_struct *af = (struct af_tab_struct *)p; 690 Handle result, name, num; 691 /* Construct a pair of the string and the number. */ 692 name = SAVE(C_string_to_Poly(taskData, af->af_name)); 693 num = Make_fixed_precision(taskData, af->af_num); 694 result = ALLOC(2); 695 DEREFHANDLE(result)->Set(0, name->Word()); 696 DEREFHANDLE(result)->Set(1, num->Word()); 697 return result; 698} 699 700static Handle mkSktab(TaskData *taskData, void *arg, char *p) 701{ 702 struct sk_tab_struct *sk = (struct sk_tab_struct *)p; 703 Handle result, name, num; 704 /* Construct a pair of the string and the number. */ 705 name = SAVE(C_string_to_Poly(taskData, sk->sk_name)); 706 num = Make_fixed_precision(taskData, sk->sk_num); 707 result = ALLOC(2); 708 DEREFHANDLE(result)->Set(0, name->Word()); 709 DEREFHANDLE(result)->Set(1, num->Word()); 710 return result; 711} 712 713/* This sets an option and can also be used to set an integer. */ 714static Handle setSocketOption(TaskData *taskData, Handle sockHandle, Handle optHandle, int level, int opt) 715{ 716 SOCKET sock = getStreamSocket(taskData, sockHandle->Word()); 717 int onOff = get_C_int(taskData, optHandle->Word()); 718 if (setsockopt(sock, level, opt, 719 (char*)&onOff, sizeof(int)) != 0) 720 raise_syscall(taskData, "setsockopt failed", GETERROR); 721 return Make_fixed_precision(taskData, 0); 722} 723 724// Get a socket option as an integer. 725static Handle getSocketOption(TaskData *taskData, Handle args, int level, int opt) 726{ 727 SOCKET sock = getStreamSocket(taskData, args->Word()); 728 int optVal = 0; 729 socklen_t size = sizeof(int); 730 if (getsockopt(sock, level, opt, (char*)&optVal, &size) != 0) 731 raise_syscall(taskData, "getsockopt failed", GETERROR); 732 return Make_fixed_precision(taskData, optVal); 733} 734 735// Get and clear the error state for the socket. Returns a SysWord.word value. 736POLYUNSIGNED PolyNetworkGetSocketError(FirstArgument threadId, PolyWord skt) 737{ 738 TaskData *taskData = TaskData::FindTaskForId(threadId); 739 ASSERT(taskData != 0); 740 taskData->PreRTSCall(); 741 Handle reset = taskData->saveVec.mark(); 742 Handle result = 0; 743 744 try { 745 SOCKET sock = getStreamSocket(taskData, skt); 746 int intVal = 0; 747 socklen_t size = sizeof(int); 748 if (getsockopt(sock, SOL_SOCKET, SO_ERROR, (char*)&intVal, &size) != 0) 749 raise_syscall(taskData, "getsockopt failed", GETERROR); 750 result = Make_sysword(taskData, intVal); 751 } 752 catch (...) {} // If an ML exception is raised 753 754 taskData->saveVec.reset(reset); 755 taskData->PostRTSCall(); 756 if (result == 0) return TAGGED(0).AsUnsigned(); 757 else return result->Word().AsUnsigned(); 758} 759 760// Helper function for selectCall. Creates the result vector of active sockets. 761static bool testBit(int offset, SOCKET fd, WaitSelect *pSelect) 762{ 763 switch (offset) 764 { 765 case 0: return pSelect->IsSetRead(fd); 766 case 1: return pSelect->IsSetWrite(fd); 767 case 2: return pSelect->IsSetExcept(fd); 768 default: return false; 769 } 770} 771 772static Handle getSelectResult(TaskData *taskData, Handle args, int offset, WaitSelect *pSelect) 773{ 774 /* Construct the result vectors. */ 775 PolyObject *inVec = DEREFHANDLE(args)->Get(offset).AsObjPtr(); 776 POLYUNSIGNED nVec = inVec->Length(); 777 int nRes = 0; 778 POLYUNSIGNED i; 779 for (i = 0; i < nVec; i++) { 780 SOCKET sock = getStreamSocket(taskData, inVec->Get(i)); 781 if (testBit(offset, sock, pSelect)) nRes++; 782 } 783 if (nRes == 0) 784 return ALLOC(0); /* None - return empty vector. */ 785 else { 786 Handle result = ALLOC(nRes); 787 inVec = DEREFHANDLE(args)->Get(offset).AsObjPtr(); /* It could have moved as a result of a gc. */ 788 nRes = 0; 789 for (i = 0; i < nVec; i++) { 790 SOCKET sock = getStreamSocket(taskData, inVec->Get(i)); 791 if (testBit(offset, sock, pSelect)) 792 DEREFWORDHANDLE(result)->Set(nRes++, inVec->Get(i)); 793 } 794 return result; 795 } 796} 797 798/* Wrapper for "select" call. The arguments are arrays of socket ids. These arrays are 799 updated so that "active" sockets are left unchanged and inactive sockets are set to 800 minus one. */ 801POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSelect(FirstArgument threadId, PolyWord fdVecTriple, PolyWord maxMillisecs) 802{ 803 TaskData *taskData = TaskData::FindTaskForId(threadId); 804 ASSERT(taskData != 0); 805 taskData->PreRTSCall(); 806 Handle reset = taskData->saveVec.mark(); 807 Handle result = 0; 808 POLYUNSIGNED maxMilliseconds = maxMillisecs.UnTaggedUnsigned(); 809 Handle fdVecTripleHandle = taskData->saveVec.push(fdVecTriple); 810 /* Set up the bitmaps for the select call from the arrays. */ 811 812 try { 813 WaitSelect waitSelect((unsigned int)maxMilliseconds); 814 PolyObject *readVec = fdVecTripleHandle->WordP()->Get(0).AsObjPtr(); 815 PolyObject *writeVec = fdVecTripleHandle->WordP()->Get(1).AsObjPtr(); 816 PolyObject *excVec = fdVecTripleHandle->WordP()->Get(2).AsObjPtr(); 817 for (POLYUNSIGNED i = 0; i < readVec->Length(); i++) 818 waitSelect.SetRead(getStreamSocket(taskData, readVec->Get(i))); 819 for (POLYUNSIGNED i = 0; i < writeVec->Length(); i++) 820 waitSelect.SetWrite(getStreamSocket(taskData, writeVec->Get(i))); 821 for (POLYUNSIGNED i = 0; i < excVec->Length(); i++) 822 waitSelect.SetExcept(getStreamSocket(taskData, excVec->Get(i))); 823 824 // Do the select. This may return immediately if the maximum time-out is short. 825 processes->ThreadPauseForIO(taskData, &waitSelect); 826 if (waitSelect.SelectResult() < 0) 827 raise_syscall(taskData, "select failed", waitSelect.SelectError()); 828 829 // Construct the result vectors. 830 Handle rdResult = getSelectResult(taskData, fdVecTripleHandle, 0, &waitSelect); 831 Handle wrResult = getSelectResult(taskData, fdVecTripleHandle, 1, &waitSelect); 832 Handle exResult = getSelectResult(taskData, fdVecTripleHandle, 2, &waitSelect); 833 result = ALLOC(3); 834 DEREFHANDLE(result)->Set(0, rdResult->Word()); 835 DEREFHANDLE(result)->Set(1, wrResult->Word()); 836 DEREFHANDLE(result)->Set(2, exResult->Word()); 837 } 838 catch (...) {} // If an ML exception is raised 839 840 taskData->saveVec.reset(reset); 841 taskData->PostRTSCall(); 842 if (result == 0) return TAGGED(0).AsUnsigned(); 843 else return result->Word().AsUnsigned(); 844 845} 846 847POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkConnect(FirstArgument threadId, PolyWord skt, PolyWord addr) 848{ 849 TaskData *taskData = TaskData::FindTaskForId(threadId); 850 ASSERT(taskData != 0); 851 taskData->PreRTSCall(); 852 Handle reset = taskData->saveVec.mark(); 853 try { 854 SOCKET sock = getStreamSocket(taskData, skt); 855 PolyStringObject * psAddr = (PolyStringObject *)(addr.AsObjPtr()); 856 struct sockaddr *psock = (struct sockaddr *)&psAddr->chars; 857 // Begin the connection. The socket is always non-blocking so this will return immediately. 858 if (connect(sock, psock, (int)psAddr->length) != 0) 859 raise_syscall(taskData, "connect failed", GETERROR); 860 } 861 catch (...) {} // If an ML exception is raised 862 863 taskData->saveVec.reset(reset); 864 taskData->PostRTSCall(); 865 return TAGGED(0).AsUnsigned(); // Always returns unit 866} 867 868POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkAccept(FirstArgument threadId, PolyWord skt) 869{ 870 TaskData *taskData = TaskData::FindTaskForId(threadId); 871 ASSERT(taskData != 0); 872 taskData->PreRTSCall(); 873 Handle reset = taskData->saveVec.mark(); 874 Handle result = 0; 875 876 try { 877 SOCKET sock = getStreamSocket(taskData, skt); 878 struct sockaddr_storage resultAddr; 879 socklen_t addrLen = sizeof(resultAddr); 880 SOCKET resultSkt = accept(sock, (struct sockaddr*)&resultAddr, &addrLen); 881 if (resultSkt == INVALID_SOCKET) 882 raise_syscall(taskData, "accept failed", GETERROR); 883 if (addrLen > sizeof(resultAddr)) addrLen = sizeof(resultAddr); 884 Handle addrHandle = taskData->saveVec.push(C_string_to_Poly(taskData, (char*)&resultAddr, addrLen)); 885 // Return a pair of the new socket and the address. 886 Handle resSkt = wrapStreamSocket(taskData, resultSkt); 887 result = alloc_and_save(taskData, 2); 888 result->WordP()->Set(0, resSkt->Word()); 889 result->WordP()->Set(1, addrHandle->Word()); 890 } 891 catch (...) {} // If an ML exception is raised 892 893 taskData->saveVec.reset(reset); 894 taskData->PostRTSCall(); 895 if (result == 0) return TAGGED(0).AsUnsigned(); 896 else return result->Word().AsUnsigned(); 897} 898 899POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSend(FirstArgument threadId, PolyWord argsAsWord) 900{ 901 TaskData *taskData = TaskData::FindTaskForId(threadId); 902 ASSERT(taskData != 0); 903 taskData->PreRTSCall(); 904 Handle reset = taskData->saveVec.mark(); 905 Handle args = taskData->saveVec.push(argsAsWord); 906#if(defined(_WIN32) && ! defined(_CYGWIN)) 907 int sent = 0; 908#else 909 ssize_t sent = 0; 910#endif 911 912 try { 913 SOCKET sock = getStreamSocket(taskData, DEREFHANDLE(args)->Get(0)); 914 PolyWord pBase = DEREFHANDLE(args)->Get(1); 915 POLYUNSIGNED offset = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(2)); 916#if(defined(_WIN32) && ! defined(_CYGWIN)) 917 int length = get_C_int(taskData, DEREFHANDLE(args)->Get(3)); 918#else 919 ssize_t length = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(3)); 920#endif 921 unsigned int dontRoute = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(4)); 922 unsigned int outOfBand = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(5)); 923 int flags = 0; 924 if (dontRoute != 0) flags |= MSG_DONTROUTE; 925 if (outOfBand != 0) flags |= MSG_OOB; 926 char *base = (char*)pBase.AsObjPtr()->AsBytePtr(); 927 sent = send(sock, base + offset, length, flags); 928 if (sent == SOCKET_ERROR) 929 raise_syscall(taskData, "send failed", GETERROR); 930 } 931 catch (...) {} // If an ML exception is raised 932 933 taskData->saveVec.reset(reset); 934 taskData->PostRTSCall(); 935 return TAGGED(sent).AsUnsigned(); 936} 937 938POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkSendTo(FirstArgument threadId, PolyWord argsAsWord) 939{ 940 TaskData *taskData = TaskData::FindTaskForId(threadId); 941 ASSERT(taskData != 0); 942 taskData->PreRTSCall(); 943 Handle reset = taskData->saveVec.mark(); 944 Handle args = taskData->saveVec.push(argsAsWord); 945#if(defined(_WIN32) && ! defined(_CYGWIN)) 946 int sent = 0; 947#else 948 ssize_t sent = 0; 949#endif 950 951 try { 952 SOCKET sock = getStreamSocket(taskData, DEREFHANDLE(args)->Get(0)); 953 PolyStringObject * psAddr = (PolyStringObject *)args->WordP()->Get(1).AsObjPtr(); 954 PolyWord pBase = DEREFHANDLE(args)->Get(2); 955 956 POLYUNSIGNED offset = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(3)); 957#if(defined(_WIN32) && ! defined(_CYGWIN)) 958 int length = get_C_int(taskData, DEREFHANDLE(args)->Get(4)); 959#else 960 size_t length = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(4)); 961#endif 962 unsigned int dontRoute = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(5)); 963 unsigned int outOfBand = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(6)); 964 int flags = 0; 965 if (dontRoute != 0) flags |= MSG_DONTROUTE; 966 if (outOfBand != 0) flags |= MSG_OOB; 967 char *base = (char*)pBase.AsObjPtr()->AsBytePtr(); 968 sent = sendto(sock, base + offset, length, flags, 969 (struct sockaddr *)psAddr->chars, (int)psAddr->length); 970 if (sent == SOCKET_ERROR) 971 raise_syscall(taskData, "sendto failed", GETERROR); 972 } 973 catch (...) {} // If an ML exception is raised 974 975 taskData->saveVec.reset(reset); 976 taskData->PostRTSCall(); 977 return TAGGED(sent).AsUnsigned(); 978} 979 980POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReceive(FirstArgument threadId, PolyWord argsAsWord) 981{ 982 TaskData *taskData = TaskData::FindTaskForId(threadId); 983 ASSERT(taskData != 0); 984 taskData->PreRTSCall(); 985 Handle reset = taskData->saveVec.mark(); 986 Handle args = taskData->saveVec.push(argsAsWord); 987#if(defined(_WIN32) && ! defined(_CYGWIN)) 988 int recvd = 0; 989#else 990 ssize_t recvd = 0; 991#endif 992 993 try { 994 SOCKET sock = getStreamSocket(taskData, DEREFHANDLE(args)->Get(0)); 995 char *base = (char*)DEREFHANDLE(args)->Get(1).AsObjPtr()->AsBytePtr(); 996 POLYUNSIGNED offset = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(2)); 997#if(defined(_WIN32) && ! defined(_CYGWIN)) 998 int length = get_C_int(taskData, DEREFHANDLE(args)->Get(3)); 999#else 1000 size_t length = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(3)); 1001#endif 1002 unsigned int peek = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(4)); 1003 unsigned int outOfBand = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(5)); 1004 int flags = 0; 1005 if (peek != 0) flags |= MSG_PEEK; 1006 if (outOfBand != 0) flags |= MSG_OOB; 1007 1008 recvd = recv(sock, base + offset, length, flags); 1009 if (recvd == SOCKET_ERROR) 1010 raise_syscall(taskData, "recv failed", GETERROR); 1011 } 1012 catch (...) {} // If an ML exception is raised 1013 1014 taskData->saveVec.reset(reset); 1015 taskData->PostRTSCall(); 1016 return TAGGED(recvd).AsUnsigned(); 1017} 1018 1019POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReceiveFrom(FirstArgument threadId, PolyWord argsAsWord) 1020{ 1021 TaskData *taskData = TaskData::FindTaskForId(threadId); 1022 ASSERT(taskData != 0); 1023 taskData->PreRTSCall(); 1024 Handle reset = taskData->saveVec.mark(); 1025 Handle args = taskData->saveVec.push(argsAsWord); 1026 Handle result = 0; 1027 1028 try { 1029 SOCKET sock = getStreamSocket(taskData, DEREFHANDLE(args)->Get(0)); 1030 char *base = (char*)DEREFHANDLE(args)->Get(1).AsObjPtr()->AsBytePtr(); 1031 POLYUNSIGNED offset = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(2)); 1032#if(defined(_WIN32) && ! defined(_CYGWIN)) 1033 int length = get_C_int(taskData, DEREFHANDLE(args)->Get(3)); 1034#else 1035 size_t length = getPolyUnsigned(taskData, DEREFHANDLE(args)->Get(3)); 1036#endif 1037 unsigned int peek = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(4)); 1038 unsigned int outOfBand = get_C_unsigned(taskData, DEREFHANDLE(args)->Get(5)); 1039 int flags = 0; 1040 struct sockaddr_storage resultAddr; 1041 socklen_t addrLen = sizeof(resultAddr); 1042 1043 if (peek != 0) flags |= MSG_PEEK; 1044 if (outOfBand != 0) flags |= MSG_OOB; 1045 1046#if(defined(_WIN32) && ! defined(_CYGWIN)) 1047 int recvd; 1048#else 1049 ssize_t recvd; 1050#endif 1051 recvd = recvfrom(sock, base + offset, length, flags, (struct sockaddr*)&resultAddr, &addrLen); 1052 if (recvd == SOCKET_ERROR) 1053 raise_syscall(taskData, "recvfrom failed", GETERROR); 1054 1055 if (recvd > (int)length) recvd = length; 1056 Handle lengthHandle = Make_fixed_precision(taskData, recvd); 1057 if (addrLen > sizeof(resultAddr)) addrLen = sizeof(resultAddr); 1058 Handle addrHandle = SAVE(C_string_to_Poly(taskData, (char*)&resultAddr, addrLen)); 1059 result = ALLOC(2); 1060 DEREFHANDLE(result)->Set(0, lengthHandle->Word()); 1061 DEREFHANDLE(result)->Set(1, addrHandle->Word()); 1062 } 1063 catch (...) {} // If an ML exception is raised 1064 1065 taskData->saveVec.reset(reset); 1066 taskData->PostRTSCall(); 1067 if (result == 0) return TAGGED(0).AsUnsigned(); 1068 else return result->Word().AsUnsigned(); 1069} 1070 1071/* Return a list of known address families. */ 1072POLYUNSIGNED PolyNetworkGetAddrList(FirstArgument threadId) 1073{ 1074 TaskData* taskData = TaskData::FindTaskForId(threadId); 1075 ASSERT(taskData != 0); 1076 taskData->PreRTSCall(); 1077 Handle reset = taskData->saveVec.mark(); 1078 Handle result = 0; 1079 1080 try { 1081 result = makeList(taskData, sizeof(af_table) / sizeof(af_table[0]), 1082 (char*)af_table, sizeof(af_table[0]), 0, mkAftab); 1083 } 1084 catch (...) {} // If an ML exception is raised 1085 1086 taskData->saveVec.reset(reset); 1087 taskData->PostRTSCall(); 1088 if (result == 0) return TAGGED(0).AsUnsigned(); 1089 else return result->Word().AsUnsigned(); 1090} 1091 1092/* Return a list of known socket types. */ 1093POLYUNSIGNED PolyNetworkGetSockTypeList(FirstArgument threadId) 1094{ 1095 TaskData* taskData = TaskData::FindTaskForId(threadId); 1096 ASSERT(taskData != 0); 1097 taskData->PreRTSCall(); 1098 Handle reset = taskData->saveVec.mark(); 1099 Handle result = 0; 1100 1101 try { 1102 result = makeList(taskData, sizeof(sk_table) / sizeof(sk_table[0]), 1103 (char*)sk_table, sizeof(sk_table[0]), 1104 0, mkSktab); 1105 } 1106 catch (...) {} // If an ML exception is raised 1107 1108 taskData->saveVec.reset(reset); 1109 taskData->PostRTSCall(); 1110 if (result == 0) return TAGGED(0).AsUnsigned(); 1111 else return result->Word().AsUnsigned(); 1112} 1113 1114// Create a socket */ 1115POLYUNSIGNED PolyNetworkCreateSocket(FirstArgument threadId, PolyWord family, PolyWord st, PolyWord prot) 1116{ 1117 TaskData* taskData = TaskData::FindTaskForId(threadId); 1118 ASSERT(taskData != 0); 1119 taskData->PreRTSCall(); 1120 Handle reset = taskData->saveVec.mark(); 1121 Handle result = 0; 1122 int af = (int)family.UnTagged(); 1123 int type = (int)st.UnTagged(); 1124 int proto = (int)prot.UnTagged(); 1125 1126 try { 1127 SOCKET skt = 0; 1128 do { 1129 skt = socket(af, type, proto); 1130 } while (skt == INVALID_SOCKET && GETERROR == CALLINTERRUPTED); 1131 1132 if (skt == INVALID_SOCKET) 1133 raise_syscall(taskData, "socket failed", GETERROR); 1134 1135 /* Set the socket to non-blocking mode. */ 1136#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1137 unsigned long onOff = 1; 1138 if (ioctlsocket(skt, FIONBIO, &onOff) != 0) 1139#else 1140 int onOff = 1; 1141 if (ioctl(skt, FIONBIO, &onOff) < 0) 1142#endif 1143 { 1144#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1145 closesocket(skt); 1146#else 1147 close(skt); 1148#endif 1149 raise_syscall(taskData, "ioctl failed", GETERROR); 1150 } 1151 result = wrapStreamSocket(taskData, skt); 1152 } 1153 catch (...) {} // If an ML exception is raised 1154 1155 taskData->saveVec.reset(reset); 1156 taskData->PostRTSCall(); 1157 if (result == 0) return TAGGED(0).AsUnsigned(); 1158 else return result->Word().AsUnsigned(); 1159} 1160 1161POLYUNSIGNED PolyNetworkSetOption(FirstArgument threadId, PolyWord code, PolyWord sock, PolyWord opt) 1162{ 1163 TaskData* taskData = TaskData::FindTaskForId(threadId); 1164 ASSERT(taskData != 0); 1165 taskData->PreRTSCall(); 1166 Handle reset = taskData->saveVec.mark(); 1167 Handle pushedSock = taskData->saveVec.push(sock); 1168 Handle pushedOpt = taskData->saveVec.push(opt); 1169 1170 try { 1171 switch (UNTAGGED(code)) 1172 { 1173 case 15: /* Set TCP No-delay option. */ 1174 setSocketOption(taskData, pushedSock, pushedOpt, IPPROTO_TCP, TCP_NODELAY); 1175 break; 1176 1177 case 17: /* Set Debug option. */ 1178 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_DEBUG); 1179 break; 1180 1181 case 19: /* Set REUSEADDR option. */ 1182 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_REUSEADDR); 1183 break; 1184 1185 case 21: /* Set KEEPALIVE option. */ 1186 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_KEEPALIVE); 1187 break; 1188 1189 case 23: /* Set DONTROUTE option. */ 1190 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_DONTROUTE); 1191 break; 1192 1193 case 25: /* Set BROADCAST option. */ 1194 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_BROADCAST); 1195 break; 1196 1197 case 27: /* Set OOBINLINE option. */ 1198 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_OOBINLINE); 1199 break; 1200 1201 case 29: /* Set SNDBUF size. */ 1202 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_SNDBUF); 1203 break; 1204 1205 case 31: /* Set RCVBUF size. */ 1206 setSocketOption(taskData, pushedSock, pushedOpt, SOL_SOCKET, SO_RCVBUF); 1207 break; 1208 } 1209 } 1210 catch (KillException&) { 1211 processes->ThreadExit(taskData); // May test for kill 1212 } 1213 catch (...) {} // If an ML exception is raised 1214 1215 taskData->saveVec.reset(reset); 1216 taskData->PostRTSCall(); 1217 return TAGGED(0).AsUnsigned(); 1218} 1219 1220POLYUNSIGNED PolyNetworkGetOption(FirstArgument threadId, PolyWord code, PolyWord arg) 1221{ 1222 TaskData* taskData = TaskData::FindTaskForId(threadId); 1223 ASSERT(taskData != 0); 1224 taskData->PreRTSCall(); 1225 Handle reset = taskData->saveVec.mark(); 1226 Handle pushedArg = taskData->saveVec.push(arg); 1227 Handle result = 0; 1228 1229 try { 1230 switch (UNTAGGED(code)) 1231 { 1232 case 16: /* Get TCP No-delay option. */ 1233 result = getSocketOption(taskData, pushedArg, IPPROTO_TCP, TCP_NODELAY); 1234 break; 1235 1236 case 18: /* Get Debug option. */ 1237 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_DEBUG); 1238 break; 1239 1240 case 20: /* Get REUSEADDR option. */ 1241 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_REUSEADDR); 1242 break; 1243 1244 case 22: /* Get KEEPALIVE option. */ 1245 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_KEEPALIVE); 1246 break; 1247 1248 case 24: /* Get DONTROUTE option. */ 1249 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_DONTROUTE); 1250 break; 1251 1252 case 26: /* Get BROADCAST option. */ 1253 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_BROADCAST); 1254 break; 1255 1256 case 28: /* Get OOBINLINE option. */ 1257 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_OOBINLINE); 1258 break; 1259 1260 case 30: /* Get SNDBUF size. */ 1261 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_SNDBUF); 1262 break; 1263 1264 case 32: /* Get RCVBUF size. */ 1265 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_RCVBUF); 1266 break; 1267 1268 case 33: /* Get socket type e.g. SOCK_STREAM. */ 1269 result = getSocketOption(taskData, pushedArg, SOL_SOCKET, SO_TYPE); 1270 break; 1271 } 1272 } 1273 catch (KillException&) { 1274 processes->ThreadExit(taskData); // May test for kill 1275 } 1276 catch (...) {} // If an ML exception is raised 1277 1278 taskData->saveVec.reset(reset); 1279 taskData->PostRTSCall(); 1280 if (result == 0) return TAGGED(0).AsUnsigned(); 1281 else return result->Word().AsUnsigned(); 1282} 1283 1284/* Set Linger time. */ 1285POLYUNSIGNED PolyNetworkSetLinger(FirstArgument threadId, PolyWord sock, PolyWord lingerTime) 1286{ 1287 TaskData* taskData = TaskData::FindTaskForId(threadId); 1288 ASSERT(taskData != 0); 1289 taskData->PreRTSCall(); 1290 Handle reset = taskData->saveVec.mark(); 1291 1292 try { 1293 SOCKET skt = getStreamSocket(taskData, sock); 1294 int lTime = get_C_int(taskData, lingerTime); 1295 struct linger linger; 1296 /* We pass in a negative value to turn the option off, 1297 zero or positive to turn it on. */ 1298 if (lTime < 0) 1299 { 1300 linger.l_onoff = 0; 1301 linger.l_linger = 0; 1302 } 1303 else 1304 { 1305 linger.l_onoff = 1; 1306 linger.l_linger = lTime; 1307 } 1308 if (setsockopt(skt, SOL_SOCKET, SO_LINGER, 1309 (char*)& linger, sizeof(linger)) != 0) 1310 raise_syscall(taskData, "setsockopt failed", GETERROR); 1311 } 1312 catch (...) {} // If an ML exception is raised 1313 1314 taskData->saveVec.reset(reset); 1315 taskData->PostRTSCall(); 1316 return TAGGED(0).AsUnsigned(); 1317} 1318 1319/* Get Linger time. */ 1320POLYUNSIGNED PolyNetworkGetLinger(FirstArgument threadId, PolyWord sock) 1321{ 1322 TaskData* taskData = TaskData::FindTaskForId(threadId); 1323 ASSERT(taskData != 0); 1324 taskData->PreRTSCall(); 1325 Handle reset = taskData->saveVec.mark(); 1326 Handle result = 0; 1327 1328 try { 1329 SOCKET skt = getStreamSocket(taskData, sock); 1330 socklen_t size = sizeof(linger); 1331 int lTime = 0; 1332 struct linger linger; 1333 if (getsockopt(skt, SOL_SOCKET, SO_LINGER, (char*)& linger, &size) != 0) 1334 raise_syscall(taskData, "getsockopt failed", GETERROR); 1335 /* If the option is off return a negative. */ 1336 if (linger.l_onoff == 0) lTime = -1; 1337 else lTime = linger.l_linger; 1338 result = Make_arbitrary_precision(taskData, lTime); // Returns LargeInt.int 1339 } 1340 catch (...) {} // If an ML exception is raised 1341 1342 taskData->saveVec.reset(reset); 1343 taskData->PostRTSCall(); 1344 if (result == 0) return TAGGED(0).AsUnsigned(); 1345 else return result->Word().AsUnsigned(); 1346} 1347 1348/* Get peer name. */ 1349POLYUNSIGNED PolyNetworkGetPeerName(FirstArgument threadId, PolyWord sock) 1350{ 1351 TaskData* taskData = TaskData::FindTaskForId(threadId); 1352 ASSERT(taskData != 0); 1353 taskData->PreRTSCall(); 1354 Handle reset = taskData->saveVec.mark(); 1355 Handle result = 0; 1356 1357 try { 1358 SOCKET skt = getStreamSocket(taskData, sock); 1359 struct sockaddr_storage sockA; 1360 socklen_t size = sizeof(sockA); 1361 if (getpeername(skt, (struct sockaddr*) & sockA, &size) != 0) 1362 raise_syscall(taskData, "getpeername failed", GETERROR); 1363 if (size > sizeof(sockA)) size = sizeof(sockA); 1364 /* Addresses are treated as strings. */ 1365 result = (SAVE(C_string_to_Poly(taskData, (char*)& sockA, size))); 1366 } 1367 catch (...) {} // If an ML exception is raised 1368 1369 taskData->saveVec.reset(reset); 1370 taskData->PostRTSCall(); 1371 if (result == 0) return TAGGED(0).AsUnsigned(); 1372 else return result->Word().AsUnsigned(); 1373} 1374 1375/* Get socket name. */ 1376POLYUNSIGNED PolyNetworkGetSockName(FirstArgument threadId, PolyWord sock) 1377{ 1378 TaskData* taskData = TaskData::FindTaskForId(threadId); 1379 ASSERT(taskData != 0); 1380 taskData->PreRTSCall(); 1381 Handle reset = taskData->saveVec.mark(); 1382 Handle result = 0; 1383 1384 try { 1385 SOCKET skt = getStreamSocket(taskData, sock); 1386 struct sockaddr_storage sockA; 1387 socklen_t size = sizeof(sockA); 1388 if (getsockname(skt, (struct sockaddr*) & sockA, &size) != 0) 1389 raise_syscall(taskData, "getsockname failed", GETERROR); 1390 if (size > sizeof(sockA)) size = sizeof(sockA); 1391 result = (SAVE(C_string_to_Poly(taskData, (char*)& sockA, size))); 1392 } 1393 catch (...) {} // If an ML exception is raised 1394 1395 taskData->saveVec.reset(reset); 1396 taskData->PostRTSCall(); 1397 if (result == 0) return TAGGED(0).AsUnsigned(); 1398 else return result->Word().AsUnsigned(); 1399} 1400 1401/* Find number of bytes available. */ 1402POLYUNSIGNED PolyNetworkBytesAvailable(FirstArgument threadId, PolyWord sock) 1403{ 1404 TaskData* taskData = TaskData::FindTaskForId(threadId); 1405 ASSERT(taskData != 0); 1406 taskData->PreRTSCall(); 1407 Handle reset = taskData->saveVec.mark(); 1408 Handle result = 0; 1409 1410 try { 1411 SOCKET skt = getStreamSocket(taskData, sock); 1412#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1413 unsigned long readable; 1414 if (ioctlsocket(skt, FIONREAD, &readable) != 0) 1415 raise_syscall(taskData, "ioctlsocket failed", GETERROR); 1416#else 1417 int readable; 1418 if (ioctl(skt, FIONREAD, &readable) < 0) 1419 raise_syscall(taskData, "ioctl failed", GETERROR); 1420#endif 1421 result = Make_fixed_precision(taskData, readable); 1422 } 1423 catch (...) {} // If an ML exception is raised 1424 1425 taskData->saveVec.reset(reset); 1426 taskData->PostRTSCall(); 1427 if (result == 0) return TAGGED(0).AsUnsigned(); 1428 else return result->Word().AsUnsigned(); 1429} 1430 1431/* Find out if we are at the mark. */ 1432POLYUNSIGNED PolyNetworkGetAtMark(FirstArgument threadId, PolyWord sock) 1433{ 1434 TaskData* taskData = TaskData::FindTaskForId(threadId); 1435 ASSERT(taskData != 0); 1436 taskData->PreRTSCall(); 1437 Handle reset = taskData->saveVec.mark(); 1438 Handle result = 0; 1439 1440 try { 1441 SOCKET skt = getStreamSocket(taskData, sock); 1442#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1443 unsigned long atMark; 1444 if (ioctlsocket(skt, SIOCATMARK, &atMark) != 0) 1445 raise_syscall(taskData, "ioctlsocket failed", GETERROR); 1446#else 1447 int atMark; 1448 if (ioctl(skt, SIOCATMARK, &atMark) < 0) 1449 raise_syscall(taskData, "ioctl failed", GETERROR); 1450#endif 1451 result = Make_fixed_precision(taskData, atMark == 0 ? 0 : 1); 1452 } 1453 catch (...) {} // If an ML exception is raised 1454 1455 taskData->saveVec.reset(reset); 1456 taskData->PostRTSCall(); 1457 if (result == 0) return TAGGED(0).AsUnsigned(); 1458 else return result->Word().AsUnsigned(); 1459} 1460 1461/* Bind an address to a socket. */ 1462POLYUNSIGNED PolyNetworkBind(FirstArgument threadId, PolyWord sock, PolyWord addr) 1463{ 1464 TaskData* taskData = TaskData::FindTaskForId(threadId); 1465 ASSERT(taskData != 0); 1466 taskData->PreRTSCall(); 1467 Handle reset = taskData->saveVec.mark(); 1468 1469 try { 1470 SOCKET skt = getStreamSocket(taskData, sock); 1471 PolyStringObject* psAddr = (PolyStringObject*)addr.AsObjPtr(); 1472 struct sockaddr* psock = (struct sockaddr*) & psAddr->chars; 1473 if (bind(skt, psock, (int)psAddr->length) != 0) 1474 raise_syscall(taskData, "bind failed", GETERROR); 1475 } 1476 catch (...) {} // If an ML exception is raised 1477 1478 taskData->saveVec.reset(reset); 1479 taskData->PostRTSCall(); 1480 return TAGGED(0).AsUnsigned(); 1481} 1482 1483/* Put socket into listening mode. */ 1484POLYUNSIGNED PolyNetworkListen(FirstArgument threadId, PolyWord skt, PolyWord back) 1485{ 1486 TaskData* taskData = TaskData::FindTaskForId(threadId); 1487 ASSERT(taskData != 0); 1488 taskData->PreRTSCall(); 1489 Handle reset = taskData->saveVec.mark(); 1490 1491 try { 1492 SOCKET sock = getStreamSocket(taskData, skt); 1493 int backlog = get_C_int(taskData, back); 1494 if (listen(sock, backlog) != 0) 1495 raise_syscall(taskData, "listen failed", GETERROR); 1496 } 1497 catch (...) {} // If an ML exception is raised 1498 1499 taskData->saveVec.reset(reset); 1500 taskData->PostRTSCall(); 1501 return TAGGED(0).AsUnsigned(); 1502} 1503 1504/* Shutdown the socket. */ 1505POLYUNSIGNED PolyNetworkShutdown(FirstArgument threadId, PolyWord skt, PolyWord smode) 1506{ 1507 TaskData* taskData = TaskData::FindTaskForId(threadId); 1508 ASSERT(taskData != 0); 1509 taskData->PreRTSCall(); 1510 Handle reset = taskData->saveVec.mark(); 1511 1512 try { 1513 SOCKET sock = getStreamSocket(taskData, skt); 1514 int mode = 0; 1515 switch (get_C_ulong(taskData, smode)) 1516 { 1517 case 1: mode = SHUT_RD; break; 1518 case 2: mode = SHUT_WR; break; 1519 case 3: mode = SHUT_RDWR; 1520 } 1521 if (shutdown(sock, mode) != 0) 1522 raise_syscall(taskData, "shutdown failed", GETERROR); 1523 } 1524 catch (...) {} // If an ML exception is raised 1525 1526 taskData->saveVec.reset(reset); 1527 taskData->PostRTSCall(); 1528 return TAGGED(0).AsUnsigned(); 1529} 1530 1531/* Create a socket pair. */ 1532POLYUNSIGNED PolyNetworkCreateSocketPair(FirstArgument threadId, PolyWord family, PolyWord st, PolyWord prot) 1533{ 1534 TaskData* taskData = TaskData::FindTaskForId(threadId); 1535 ASSERT(taskData != 0); 1536 taskData->PreRTSCall(); 1537 Handle reset = taskData->saveVec.mark(); 1538 Handle result = 0; 1539 1540 try { 1541#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1542 /* Not implemented. */ 1543 raise_syscall(taskData, "socketpair not implemented", WSAEAFNOSUPPORT); 1544#else 1545 int af = family.UnTagged(); 1546 int type = st.UnTagged(); 1547 int proto = prot.UnTagged(); 1548 SOCKET skt[2]; 1549 int skPRes = 0; 1550 1551 do { 1552 skPRes = socketpair(af, type, proto, skt); 1553 } while (skPRes != 0 && GETERROR == CALLINTERRUPTED); 1554 1555 int onOff = 1; 1556 /* Set the sockets to non-blocking mode. */ 1557 if (ioctl(skt[0], FIONBIO, &onOff) < 0 || 1558 ioctl(skt[1], FIONBIO, &onOff) < 0) 1559 { 1560 close(skt[0]); 1561 close(skt[1]); 1562 raise_syscall(taskData, "ioctl failed", GETERROR); 1563 } 1564 Handle str_token1 = wrapStreamSocket(taskData, skt[0]); 1565 Handle str_token2 = wrapStreamSocket(taskData, skt[1]); 1566 /* Return the two streams as a pair. */ 1567 result = ALLOC(2); 1568 DEREFHANDLE(result)->Set(0, DEREFWORD(str_token1)); 1569 DEREFHANDLE(result)->Set(1, DEREFWORD(str_token2)); 1570#endif 1571 } 1572 catch (KillException&) { 1573 processes->ThreadExit(taskData); // May test for kill 1574 } 1575 catch (...) {} // If an ML exception is raised 1576 1577 taskData->saveVec.reset(reset); 1578 taskData->PostRTSCall(); 1579 if (result == 0) return TAGGED(0).AsUnsigned(); 1580 else return result->Word().AsUnsigned(); 1581} 1582 1583/* Create a Unix socket address from a string. */ 1584POLYUNSIGNED PolyNetworkUnixPathToSockAddr(FirstArgument threadId, PolyWord arg) 1585{ 1586 TaskData* taskData = TaskData::FindTaskForId(threadId); 1587 ASSERT(taskData != 0); 1588 taskData->PreRTSCall(); 1589 Handle reset = taskData->saveVec.mark(); 1590 Handle result = 0; 1591 1592 try { 1593#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1594 /* Not implemented. */ 1595 raise_syscall(taskData, "Unix addresses not implemented", WSAEAFNOSUPPORT); 1596#else 1597 struct sockaddr_un addr; 1598 memset(&addr, 0, sizeof(addr)); 1599 addr.sun_family = AF_UNIX; 1600#ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN 1601 addr.sun_len = sizeof(addr); // Used in FreeBSD only. 1602#endif 1603 POLYUNSIGNED length = Poly_string_to_C(arg, addr.sun_path, sizeof(addr.sun_path)); 1604 if (length > (int)sizeof(addr.sun_path)) 1605 raise_syscall(taskData, "Address too long", ENAMETOOLONG); 1606 result = SAVE(C_string_to_Poly(taskData, (char*)& addr, sizeof(addr))); 1607#endif 1608 } 1609 catch (...) {} // If an ML exception is raised 1610 1611 taskData->saveVec.reset(reset); 1612 taskData->PostRTSCall(); 1613 if (result == 0) return TAGGED(0).AsUnsigned(); 1614 else return result->Word().AsUnsigned(); 1615} 1616 1617/* Get the file name from a Unix socket address. */ 1618POLYUNSIGNED PolyNetworkUnixSockAddrToPath(FirstArgument threadId, PolyWord arg) 1619{ 1620 TaskData* taskData = TaskData::FindTaskForId(threadId); 1621 ASSERT(taskData != 0); 1622 taskData->PreRTSCall(); 1623 Handle reset = taskData->saveVec.mark(); 1624 Handle result = 0; 1625 1626 try { 1627#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1628 /* Not implemented. */ 1629 raise_syscall(taskData, "Unix addresses not implemented", WSAEAFNOSUPPORT); 1630#else 1631 PolyStringObject* psAddr = (PolyStringObject*)arg.AsObjPtr(); 1632 struct sockaddr_un* psock = (struct sockaddr_un*) & psAddr->chars; 1633 result = SAVE(C_string_to_Poly(taskData, psock->sun_path)); 1634#endif 1635 } 1636 catch (...) {} // If an ML exception is raised 1637 1638 taskData->saveVec.reset(reset); 1639 taskData->PostRTSCall(); 1640 if (result == 0) return TAGGED(0).AsUnsigned(); 1641 else return result->Word().AsUnsigned(); 1642} 1643 1644POLYUNSIGNED PolyNetworkGetServByName(FirstArgument threadId, PolyWord serviceName) 1645{ 1646 TaskData *taskData = TaskData::FindTaskForId(threadId); 1647 ASSERT(taskData != 0); 1648 taskData->PreRTSCall(); 1649 Handle reset = taskData->saveVec.mark(); 1650 1651 /* Get service given service name only. */ 1652 TempCString servName(Poly_string_to_C_alloc(serviceName)); 1653 struct servent *serv = getservbyname (servName, NULL); 1654 // If this fails the ML function returns NONE 1655 Handle result = serv == NULL ? 0 : makeServEntry(taskData, serv); 1656 1657 taskData->saveVec.reset(reset); 1658 taskData->PostRTSCall(); 1659 if (result == 0) return TAGGED(0).AsUnsigned(); 1660 else return result->Word().AsUnsigned(); 1661} 1662 1663POLYUNSIGNED PolyNetworkGetServByNameAndProtocol(FirstArgument threadId, PolyWord serviceName, PolyWord protName) 1664{ 1665 TaskData *taskData = TaskData::FindTaskForId(threadId); 1666 ASSERT(taskData != 0); 1667 taskData->PreRTSCall(); 1668 Handle reset = taskData->saveVec.mark(); 1669 1670 /* Get service given service name and protocol name. */ 1671 TempCString servName(Poly_string_to_C_alloc(serviceName)); 1672 TempCString protoName(Poly_string_to_C_alloc(protName)); 1673 struct servent *serv = getservbyname (servName, protoName); 1674 Handle result = serv == NULL ? 0 : makeServEntry(taskData, serv); 1675 1676 taskData->saveVec.reset(reset); 1677 taskData->PostRTSCall(); 1678 if (result == 0) return TAGGED(0).AsUnsigned(); 1679 else return result->Word().AsUnsigned(); 1680} 1681 1682POLYUNSIGNED PolyNetworkGetServByPort(FirstArgument threadId, PolyWord portNo) 1683{ 1684 TaskData *taskData = TaskData::FindTaskForId(threadId); 1685 ASSERT(taskData != 0); 1686 taskData->PreRTSCall(); 1687 Handle reset = taskData->saveVec.mark(); 1688 1689 /* Get service given port number only. */ 1690 long port = htons(get_C_ushort(taskData, portNo)); 1691 struct servent *serv = getservbyport(port, NULL); 1692 Handle result = serv == NULL ? 0 : makeServEntry(taskData, serv); 1693 1694 taskData->saveVec.reset(reset); 1695 taskData->PostRTSCall(); 1696 if (result == 0) return TAGGED(0).AsUnsigned(); 1697 else return result->Word().AsUnsigned(); 1698} 1699 1700POLYUNSIGNED PolyNetworkGetServByPortAndProtocol(FirstArgument threadId, PolyWord portNo, PolyWord protName) 1701{ 1702 TaskData *taskData = TaskData::FindTaskForId(threadId); 1703 ASSERT(taskData != 0); 1704 taskData->PreRTSCall(); 1705 Handle reset = taskData->saveVec.mark(); 1706 1707 /* Get service given port number and protocol name. */ 1708 long port = htons(get_C_ushort(taskData, portNo)); 1709 TempCString protoName(Poly_string_to_C_alloc(protName)); 1710 struct servent *serv = getservbyport (port, protoName); 1711 Handle result = serv == NULL ? 0 : makeServEntry(taskData, serv); 1712 1713 taskData->saveVec.reset(reset); 1714 taskData->PostRTSCall(); 1715 if (result == 0) return TAGGED(0).AsUnsigned(); 1716 else return result->Word().AsUnsigned(); 1717} 1718 1719POLYUNSIGNED PolyNetworkGetProtByName(FirstArgument threadId, PolyWord protocolName) 1720{ 1721 TaskData *taskData = TaskData::FindTaskForId(threadId); 1722 ASSERT(taskData != 0); 1723 taskData->PreRTSCall(); 1724 Handle reset = taskData->saveVec.mark(); 1725 1726 /* Look up protocol entry. */ 1727 TempCString protoName(Poly_string_to_C_alloc(protocolName)); 1728 struct protoent *proto = getprotobyname(protoName); 1729 // If this fails the ML function returns NONE 1730 Handle result = proto == NULL ? 0 : makeProtoEntry(taskData, proto); 1731 1732 taskData->saveVec.reset(reset); 1733 taskData->PostRTSCall(); 1734 if (result == 0) return TAGGED(0).AsUnsigned(); 1735 else return result->Word().AsUnsigned(); 1736} 1737 1738POLYUNSIGNED PolyNetworkGetProtByNo(FirstArgument threadId, PolyWord protoNo) 1739{ 1740 TaskData *taskData = TaskData::FindTaskForId(threadId); 1741 ASSERT(taskData != 0); 1742 taskData->PreRTSCall(); 1743 Handle reset = taskData->saveVec.mark(); 1744 1745 /* Look up protocol entry. */ 1746 int pNum = get_C_int(taskData, protoNo); 1747 struct protoent *proto = getprotobynumber(pNum); 1748 Handle result = proto == NULL ? 0 : makeProtoEntry(taskData, proto); 1749 1750 taskData->saveVec.reset(reset); 1751 taskData->PostRTSCall(); 1752 if (result == 0) return TAGGED(0).AsUnsigned(); 1753 else return result->Word().AsUnsigned(); 1754} 1755 1756POLYUNSIGNED PolyNetworkGetHostName(FirstArgument threadId) 1757{ 1758 TaskData *taskData = TaskData::FindTaskForId(threadId); 1759 ASSERT(taskData != 0); 1760 taskData->PreRTSCall(); 1761 Handle reset = taskData->saveVec.mark(); 1762 Handle result = 0; 1763 1764 try { /* Get the current host name. */ 1765 // Since the maximum length of a FQDN is 256 bytes it should fit in the buffer. 1766#ifdef HOST_NAME_MAX 1767 char hostName[HOST_NAME_MAX+1]; 1768#else 1769 char hostName[1024]; 1770#endif 1771 int err = gethostname(hostName, sizeof(hostName)); 1772 if (err != 0) 1773 raise_syscall(taskData, "gethostname failed", GETERROR); 1774 // Add a null at the end just in case. See gethostname man page. 1775 hostName[sizeof(hostName) - 1] = 0; 1776 1777 result = SAVE(C_string_to_Poly(taskData, hostName)); 1778 } 1779 catch (...) { } // If an ML exception is raised 1780 1781 taskData->saveVec.reset(reset); 1782 taskData->PostRTSCall(); 1783 if (result == 0) return TAGGED(0).AsUnsigned(); 1784 else return result->Word().AsUnsigned(); 1785} 1786 1787POLYUNSIGNED PolyNetworkGetNameInfo(FirstArgument threadId, PolyWord sockAddr) 1788{ 1789 TaskData *taskData = TaskData::FindTaskForId(threadId); 1790 ASSERT(taskData != 0); 1791 taskData->PreRTSCall(); 1792 Handle reset = taskData->saveVec.mark(); 1793 Handle result = 0; 1794 1795 try { 1796 PolyStringObject* psAddr = (PolyStringObject*)sockAddr.AsObjPtr(); 1797 struct sockaddr* psock = (struct sockaddr*) & psAddr->chars; 1798 // Since the maximum length of a FQDN is 256 bytes it should fit in the buffer. 1799 char hostName[1024]; 1800 int gniRes = getnameinfo(psock, (socklen_t)psAddr->length, hostName, sizeof(hostName), NULL, 0, 0); 1801 if (gniRes != 0) 1802 { 1803#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1804 raise_syscall(taskData, "getnameinfo failed", GETERROR); 1805#else 1806 if (gniRes == EAI_SYSTEM) 1807 raise_syscall(taskData, "getnameinfo failed", GETERROR); 1808 else raise_syscall(taskData, gai_strerror(gniRes), 0); 1809#endif 1810 } 1811 result = SAVE(C_string_to_Poly(taskData, hostName)); 1812 } 1813 catch (...) {} // If an ML exception is raised 1814 1815 taskData->saveVec.reset(reset); 1816 taskData->PostRTSCall(); 1817 if (result == 0) return TAGGED(0).AsUnsigned(); 1818 else return result->Word().AsUnsigned(); 1819} 1820 1821// Copy addrInfo data into ML memory. We copy this although most of it 1822// is currently unused. 1823static Handle extractAddrInfo(TaskData *taskData, struct addrinfo *ainfo) 1824{ 1825 if (ainfo == 0) 1826 return taskData->saveVec.push(ListNull); 1827 1828 Handle reset = taskData->saveVec.mark(); 1829 Handle tail = extractAddrInfo(taskData, ainfo->ai_next); 1830 Handle name = 0; 1831 // Only the first entry may have a canonical name. 1832 if (ainfo->ai_canonname == 0) 1833 name = taskData->saveVec.push(C_string_to_Poly(taskData, "")); 1834 else name = taskData->saveVec.push(C_string_to_Poly(taskData, ainfo->ai_canonname)); 1835 1836 Handle address = taskData->saveVec.push(C_string_to_Poly(taskData, (char*)ainfo->ai_addr, ainfo->ai_addrlen)); 1837 1838 Handle value = alloc_and_save(taskData, 6); 1839 value->WordP()->Set(0, TAGGED(ainfo->ai_flags)); 1840 value->WordP()->Set(1, TAGGED(ainfo->ai_family)); 1841 value->WordP()->Set(2, TAGGED(ainfo->ai_socktype)); 1842 value->WordP()->Set(3, TAGGED(ainfo->ai_protocol)); 1843 value->WordP()->Set(4, address->Word()); 1844 value->WordP()->Set(5, name->Word()); 1845 1846 ML_Cons_Cell *next = (ML_Cons_Cell*)alloc(taskData, SIZEOF(ML_Cons_Cell)); 1847 next->h = value->Word(); 1848 next->t = tail->Word(); 1849 1850 taskData->saveVec.reset(reset); 1851 return taskData->saveVec.push(next); 1852} 1853 1854POLYUNSIGNED PolyNetworkGetAddrInfo(FirstArgument threadId, PolyWord hName, PolyWord addrFamily) 1855{ 1856 TaskData *taskData = TaskData::FindTaskForId(threadId); 1857 ASSERT(taskData != 0); 1858 taskData->PreRTSCall(); 1859 Handle reset = taskData->saveVec.mark(); 1860 Handle result = 0; 1861 struct addrinfo *resAddr = 0; 1862 1863 try { 1864 TempCString hostName(Poly_string_to_C_alloc(hName)); 1865 struct addrinfo hints; 1866 memset(&hints, 0, sizeof(hints)); 1867 hints.ai_family = (int)UNTAGGED(addrFamily); // AF_INET or AF_INET6 or, possibly, AF_UNSPEC. 1868 hints.ai_flags = AI_CANONNAME; 1869 1870 int gaiRes = getaddrinfo(hostName, 0, &hints, &resAddr); 1871 if (gaiRes != 0) 1872 { 1873#if (defined(_WIN32) && ! defined(__CYGWIN__)) 1874 raise_syscall(taskData, "getaddrinfo failed", GETERROR); 1875#else 1876 if (gaiRes == EAI_SYSTEM) 1877 raise_syscall(taskData, "getnameinfo failed", GETERROR); 1878 else raise_syscall(taskData, gai_strerror(gaiRes), 0); 1879#endif 1880 } 1881 1882 result = extractAddrInfo(taskData, resAddr); 1883 } 1884 catch (...) { } // Could raise an exception if we run out of heap space 1885 1886 if (resAddr) freeaddrinfo(resAddr); 1887 1888 taskData->saveVec.reset(reset); 1889 taskData->PostRTSCall(); 1890 if (result == 0) return TAGGED(0).AsUnsigned(); 1891 else return result->Word().AsUnsigned(); 1892} 1893 1894POLYUNSIGNED PolyNetworkCloseSocket(FirstArgument threadId, PolyWord strm) 1895{ 1896 TaskData *taskData = TaskData::FindTaskForId(threadId); 1897 ASSERT(taskData != 0); 1898 taskData->PreRTSCall(); 1899 Handle reset = taskData->saveVec.mark(); 1900 Handle result = 0; 1901 Handle pushedStream = taskData->saveVec.push(strm); 1902 1903 try { 1904 // This is defined to raise an exception if the socket has already been closed 1905#if (defined(_WIN32)) 1906 WinSocket *winskt = *(WinSocket**)(pushedStream->WordP()); 1907 if (winskt != 0) 1908 { 1909 if (closesocket(winskt->getSocket()) != 0) 1910 raise_syscall(taskData, "Error during close", GETERROR); 1911 } 1912 else raise_syscall(taskData, "Socket is closed", WSAEBADF); 1913 *(WinSocket **)(pushedStream->WordP()) = 0; // Mark as closed 1914#else 1915 int descr = getStreamFileDescriptorWithoutCheck(pushedStream->Word()); 1916 if (descr >= 0) 1917 { 1918 if (close(descr) != 0) 1919 raise_syscall(taskData, "Error during close", GETERROR); 1920 } 1921 else raise_syscall(taskData, "Socket is closed", EBADF); 1922 *(int*)(pushedStream->WordP()) = 0; // Mark as closed 1923#endif 1924 result = Make_fixed_precision(taskData, 0); 1925 } 1926 catch (...) {} // If an ML exception is raised 1927 1928 taskData->saveVec.reset(reset); 1929 taskData->PostRTSCall(); 1930 if (result == 0) return TAGGED(0).AsUnsigned(); 1931 else return result->Word().AsUnsigned(); 1932} 1933 1934// Return the family 1935POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetFamilyFromAddress(PolyWord sockAddress) 1936{ 1937 PolyStringObject* psAddr = (PolyStringObject*)sockAddress.AsObjPtr(); 1938 struct sockaddr* psock = (struct sockaddr*) & psAddr->chars; 1939 return TAGGED(psock->sa_family).AsUnsigned(); 1940} 1941 1942// Return internet address and port from an internet socket address. 1943// Assumes that we've already checked the address family. 1944POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetAddressAndPortFromIP4(FirstArgument threadId, PolyWord sockAddress) 1945{ 1946 TaskData* taskData = TaskData::FindTaskForId(threadId); 1947 ASSERT(taskData != 0); 1948 taskData->PreRTSCall(); 1949 Handle reset = taskData->saveVec.mark(); 1950 Handle result = 0; 1951 1952 try { 1953 PolyStringObject* psAddr = (PolyStringObject*)sockAddress.AsObjPtr(); 1954 struct sockaddr_in* psock = (struct sockaddr_in*) & psAddr->chars; 1955 Handle ipAddr = Make_arbitrary_precision(taskData, ntohl(psock->sin_addr.s_addr)); // IPv4 addr is LargeInt.int 1956 result = alloc_and_save(taskData, 2); 1957 result->WordP()->Set(0, ipAddr->Word()); 1958 result->WordP()->Set(1, TAGGED(ntohs(psock->sin_port))); 1959 } 1960 catch (...) {} // If an ML exception is raised 1961 1962 taskData->saveVec.reset(reset); 1963 taskData->PostRTSCall(); 1964 if (result == 0) return TAGGED(0).AsUnsigned(); 1965 else return result->Word().AsUnsigned(); 1966} 1967 1968// Create a socket address from a port number and internet address. 1969POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkCreateIP4Address(FirstArgument threadId, PolyWord ip4Address, PolyWord portNumber) 1970{ 1971 TaskData* taskData = TaskData::FindTaskForId(threadId); 1972 ASSERT(taskData != 0); 1973 taskData->PreRTSCall(); 1974 Handle reset = taskData->saveVec.mark(); 1975 Handle result = 0; 1976 1977 try { 1978 struct sockaddr_in sockaddr; 1979 memset(&sockaddr, 0, sizeof(sockaddr)); 1980 sockaddr.sin_family = AF_INET; 1981 sockaddr.sin_port = htons(get_C_ushort(taskData, portNumber)); 1982 sockaddr.sin_addr.s_addr = htonl(get_C_unsigned(taskData, ip4Address)); 1983 result = SAVE(C_string_to_Poly(taskData, (char*)&sockaddr, sizeof(sockaddr))); 1984 } 1985 catch (...) {} // If an ML exception is raised 1986 1987 taskData->saveVec.reset(reset); 1988 taskData->PostRTSCall(); 1989 if (result == 0) return TAGGED(0).AsUnsigned(); 1990 else return result->Word().AsUnsigned(); 1991} 1992 1993// Return the value of INADDR_ANY. 1994POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReturnIP4AddressAny(FirstArgument threadId) 1995{ 1996 TaskData* taskData = TaskData::FindTaskForId(threadId); 1997 ASSERT(taskData != 0); 1998 taskData->PreRTSCall(); 1999 Handle reset = taskData->saveVec.mark(); 2000 Handle result = 0; 2001 2002 try { 2003 result = Make_arbitrary_precision(taskData, INADDR_ANY); // IPv4 addr is LargeInt.int 2004 } 2005 catch (...) {} // If an ML exception is raised 2006 2007 taskData->saveVec.reset(reset); 2008 taskData->PostRTSCall(); 2009 if (result == 0) return TAGGED(0).AsUnsigned(); 2010 else return result->Word().AsUnsigned(); 2011} 2012 2013POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkGetAddressAndPortFromIP6(FirstArgument threadId, PolyWord sockAddress) 2014{ 2015 TaskData* taskData = TaskData::FindTaskForId(threadId); 2016 ASSERT(taskData != 0); 2017 taskData->PreRTSCall(); 2018 Handle reset = taskData->saveVec.mark(); 2019 Handle result = 0; 2020 2021 try { 2022 PolyStringObject* psAddr = (PolyStringObject*)sockAddress.AsObjPtr(); 2023 if (psAddr->length != sizeof(struct sockaddr_in6)) 2024 raise_fail(taskData, "Invalid length"); 2025 struct sockaddr_in6* psock = (struct sockaddr_in6*) & psAddr->chars; 2026 Handle ipAddr = SAVE(C_string_to_Poly(taskData, (const char*)&psock->sin6_addr, sizeof(struct in6_addr))); 2027 result = alloc_and_save(taskData, 2); 2028 result->WordP()->Set(0, ipAddr->Word()); 2029 result->WordP()->Set(1, TAGGED(ntohs(psock->sin6_port))); 2030 2031 } 2032 catch (...) {} // If an ML exception is raised 2033 2034 taskData->saveVec.reset(reset); 2035 taskData->PostRTSCall(); 2036 if (result == 0) return TAGGED(0).AsUnsigned(); 2037 else return result->Word().AsUnsigned(); 2038} 2039 2040POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkCreateIP6Address(FirstArgument threadId, PolyWord ip6Address, PolyWord portNumber) 2041{ 2042 TaskData* taskData = TaskData::FindTaskForId(threadId); 2043 ASSERT(taskData != 0); 2044 taskData->PreRTSCall(); 2045 Handle reset = taskData->saveVec.mark(); 2046 Handle result = 0; 2047 2048 try { 2049 struct sockaddr_in6 addr; 2050 memset(&addr, 0, sizeof(addr)); 2051 result = SAVE(C_string_to_Poly(taskData, (const char*)&addr, sizeof(struct in6_addr))); 2052 addr.sin6_family = AF_INET6; 2053 addr.sin6_port = htons(get_C_ushort(taskData, portNumber)); 2054 PolyStringObject* addrAsString = (PolyStringObject*)ip6Address.AsObjPtr(); 2055 if (addrAsString->length != sizeof(addr.sin6_addr)) 2056 raise_fail(taskData, "Invalid address length"); 2057 memcpy(&addr.sin6_addr, addrAsString->chars, sizeof(addr.sin6_addr)); 2058 result = SAVE(C_string_to_Poly(taskData, (char*)&addr, sizeof(addr))); 2059 } 2060 catch (...) {} // If an ML exception is raised 2061 2062 taskData->saveVec.reset(reset); 2063 taskData->PostRTSCall(); 2064 if (result == 0) return TAGGED(0).AsUnsigned(); 2065 else return result->Word().AsUnsigned(); 2066} 2067 2068POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkReturnIP6AddressAny(FirstArgument threadId) 2069{ 2070 TaskData* taskData = TaskData::FindTaskForId(threadId); 2071 ASSERT(taskData != 0); 2072 taskData->PreRTSCall(); 2073 Handle reset = taskData->saveVec.mark(); 2074 Handle result = 0; 2075 2076 try { 2077 result = SAVE(C_string_to_Poly(taskData, (const char*)&in6addr_any, sizeof(struct in6_addr))); 2078 } 2079 catch (...) {} // If an ML exception is raised 2080 2081 taskData->saveVec.reset(reset); 2082 taskData->PostRTSCall(); 2083 if (result == 0) return TAGGED(0).AsUnsigned(); 2084 else return result->Word().AsUnsigned(); 2085} 2086 2087// Convert an IPV6 address to string. This could be done in ML but the rules 2088// for converting zeros to double-colon are complicated. 2089POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkIP6AddressToString(FirstArgument threadId, PolyWord ip6Address) 2090{ 2091 TaskData* taskData = TaskData::FindTaskForId(threadId); 2092 ASSERT(taskData != 0); 2093 taskData->PreRTSCall(); 2094 Handle reset = taskData->saveVec.mark(); 2095 Handle result = 0; 2096 2097 try { 2098 char buffer[80]; // 40 should actually be enough: 32 hex bytes, 7 colons and a null. 2099 PolyStringObject* addrAsString = (PolyStringObject*)ip6Address.AsObjPtr(); 2100 if (addrAsString->length != sizeof(struct in6_addr)) 2101 raise_fail(taskData, "Invalid address length"); 2102 if (inet_ntop(AF_INET6, addrAsString->chars, buffer, sizeof(buffer)) == 0) 2103 raise_syscall(taskData, "inet_ntop", GETERROR); 2104 result = SAVE(C_string_to_Poly(taskData, buffer)); 2105 } 2106 catch (...) {} // If an ML exception is raised 2107 2108 taskData->saveVec.reset(reset); 2109 taskData->PostRTSCall(); 2110 if (result == 0) return TAGGED(0).AsUnsigned(); 2111 else return result->Word().AsUnsigned(); 2112} 2113 2114// Convert a string to an IPv6 address. The parsing has to be done in ML. 2115POLYEXTERNALSYMBOL POLYUNSIGNED PolyNetworkStringToIP6Address(FirstArgument threadId, PolyWord stringRep) 2116{ 2117 TaskData* taskData = TaskData::FindTaskForId(threadId); 2118 ASSERT(taskData != 0); 2119 taskData->PreRTSCall(); 2120 Handle reset = taskData->saveVec.mark(); 2121 Handle result = 0; 2122 2123 try { 2124 struct in6_addr address; 2125 TempCString stringAddr(Poly_string_to_C_alloc(stringRep)); 2126 if (inet_pton(AF_INET6, stringAddr, &address) != 1) 2127 raise_fail(taskData, "Invalid IPv6 address"); 2128 result = taskData->saveVec.push(C_string_to_Poly(taskData, (const char *)&address, sizeof(struct in6_addr))); 2129 } 2130 catch (...) {} // If an ML exception is raised 2131 2132 taskData->saveVec.reset(reset); 2133 taskData->PostRTSCall(); 2134 if (result == 0) return TAGGED(0).AsUnsigned(); 2135 else return result->Word().AsUnsigned(); 2136} 2137 2138struct _entrypts networkingEPT[] = 2139{ 2140 { "PolyNetworkGetAddrList", (polyRTSFunction)&PolyNetworkGetAddrList}, 2141 { "PolyNetworkGetSockTypeList", (polyRTSFunction)&PolyNetworkGetSockTypeList}, 2142 { "PolyNetworkCreateSocket", (polyRTSFunction)&PolyNetworkCreateSocket}, 2143 { "PolyNetworkSetOption", (polyRTSFunction)&PolyNetworkSetOption}, 2144 { "PolyNetworkGetOption", (polyRTSFunction)&PolyNetworkGetOption}, 2145 { "PolyNetworkSetLinger", (polyRTSFunction)&PolyNetworkSetLinger}, 2146 { "PolyNetworkGetLinger", (polyRTSFunction)&PolyNetworkGetLinger}, 2147 { "PolyNetworkGetPeerName", (polyRTSFunction)&PolyNetworkGetPeerName}, 2148 { "PolyNetworkGetSockName", (polyRTSFunction)&PolyNetworkGetSockName}, 2149 { "PolyNetworkBytesAvailable", (polyRTSFunction)&PolyNetworkBytesAvailable}, 2150 { "PolyNetworkGetAtMark", (polyRTSFunction)&PolyNetworkGetAtMark}, 2151 { "PolyNetworkBind", (polyRTSFunction)&PolyNetworkBind}, 2152 { "PolyNetworkListen", (polyRTSFunction)&PolyNetworkListen}, 2153 { "PolyNetworkShutdown", (polyRTSFunction)&PolyNetworkShutdown}, 2154 { "PolyNetworkCreateSocketPair", (polyRTSFunction)&PolyNetworkCreateSocketPair}, 2155 { "PolyNetworkUnixPathToSockAddr", (polyRTSFunction)&PolyNetworkUnixPathToSockAddr}, 2156 { "PolyNetworkUnixSockAddrToPath", (polyRTSFunction)&PolyNetworkUnixSockAddrToPath}, 2157 { "PolyNetworkGetServByName", (polyRTSFunction)&PolyNetworkGetServByName}, 2158 { "PolyNetworkGetServByNameAndProtocol", (polyRTSFunction)&PolyNetworkGetServByNameAndProtocol}, 2159 { "PolyNetworkGetServByPort", (polyRTSFunction)&PolyNetworkGetServByPort}, 2160 { "PolyNetworkGetServByPortAndProtocol", (polyRTSFunction)&PolyNetworkGetServByPortAndProtocol}, 2161 { "PolyNetworkGetProtByName", (polyRTSFunction)&PolyNetworkGetProtByName}, 2162 { "PolyNetworkGetProtByNo", (polyRTSFunction)&PolyNetworkGetProtByNo}, 2163 { "PolyNetworkGetHostName", (polyRTSFunction)&PolyNetworkGetHostName}, 2164 { "PolyNetworkGetNameInfo", (polyRTSFunction)&PolyNetworkGetNameInfo}, 2165 { "PolyNetworkCloseSocket", (polyRTSFunction)&PolyNetworkCloseSocket }, 2166 { "PolyNetworkSelect", (polyRTSFunction)&PolyNetworkSelect }, 2167 { "PolyNetworkGetSocketError", (polyRTSFunction)&PolyNetworkGetSocketError }, 2168 { "PolyNetworkConnect", (polyRTSFunction)&PolyNetworkConnect }, 2169 { "PolyNetworkAccept", (polyRTSFunction)&PolyNetworkAccept }, 2170 { "PolyNetworkSend", (polyRTSFunction)&PolyNetworkSend }, 2171 { "PolyNetworkSendTo", (polyRTSFunction)&PolyNetworkSendTo }, 2172 { "PolyNetworkReceive", (polyRTSFunction)&PolyNetworkReceive }, 2173 { "PolyNetworkReceiveFrom", (polyRTSFunction)&PolyNetworkReceiveFrom }, 2174 { "PolyNetworkGetAddrInfo", (polyRTSFunction)&PolyNetworkGetAddrInfo }, 2175 { "PolyNetworkGetFamilyFromAddress", (polyRTSFunction)&PolyNetworkGetFamilyFromAddress }, 2176 { "PolyNetworkGetAddressAndPortFromIP4", (polyRTSFunction)&PolyNetworkGetAddressAndPortFromIP4 }, 2177 { "PolyNetworkCreateIP4Address", (polyRTSFunction)&PolyNetworkCreateIP4Address }, 2178 { "PolyNetworkReturnIP4AddressAny", (polyRTSFunction)&PolyNetworkReturnIP4AddressAny }, 2179 { "PolyNetworkGetAddressAndPortFromIP6", (polyRTSFunction)&PolyNetworkGetAddressAndPortFromIP6 }, 2180 { "PolyNetworkCreateIP6Address", (polyRTSFunction)&PolyNetworkCreateIP6Address }, 2181 { "PolyNetworkReturnIP6AddressAny", (polyRTSFunction)&PolyNetworkReturnIP4AddressAny }, 2182 { "PolyNetworkIP6AddressToString", (polyRTSFunction)&PolyNetworkIP6AddressToString }, 2183 { "PolyNetworkStringToIP6Address", (polyRTSFunction)&PolyNetworkStringToIP6Address }, 2184 2185 { NULL, NULL} // End of list. 2186}; 2187 2188class Networking: public RtsModule 2189{ 2190public: 2191 virtual void Init(void); 2192 virtual void Stop(void); 2193}; 2194 2195// Declare this. It will be automatically added to the table. 2196static Networking networkingModule; 2197 2198void Networking::Init(void) 2199{ 2200#if (defined(_WIN32)) 2201#define WINSOCK_MAJOR_VERSION 2 2202#define WINSOCK_MINOR_VERSION 2 2203 WSADATA wsaData; 2204 WORD wVersion = MAKEWORD(WINSOCK_MINOR_VERSION, WINSOCK_MAJOR_VERSION); 2205 /* Initialise the system and check that the version it supplied 2206 is the one we requested. */ 2207 if(WSAStartup(wVersion, &wsaData) == 0) 2208 { 2209 if (wsaData.wVersion == wVersion) 2210 winsock_init = 1; 2211 else WSACleanup(); 2212 } 2213#endif 2214} 2215 2216void Networking::Stop(void) 2217{ 2218#if (defined(_WIN32)) 2219 if (winsock_init) WSACleanup(); 2220 winsock_init = 0; 2221#endif 2222} 2223