/vm/platforms/unix/plugins/SocketPlugin/sqUnixSocket.c
C | 1420 lines | 994 code | 214 blank | 212 comment | 195 complexity | 7d4eda38e6f2a025ca10261b1d5e3eac MD5 | raw file
1/* sqUnixSocket.c -- Unix socket support 2 * 3 * Copyright (C) 1996-2006 by Ian Piumarta and other authors/contributors 4 * listed elsewhere in this file. 5 * All rights reserved. 6 * 7 * This file is part of Unix Squeak. 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to deal 11 * in the Software without restriction, including without limitation the rights 12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 * copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 * SOFTWARE. 26 */ 27 28/* Author: Ian.Piumarta@inria.fr 29 * 30 * Last edited: 2006-10-18 10:08:57 by piumarta on emilia.local 31 * 32 * Support for BSD-style "accept" primitives contributed by: 33 * Lex Spoon <lex@cc.gatech.edu> 34 * 35 * Notes: 36 * Sockets are completely asynchronous, but the resolver is still 37 * synchronous. 38 * 39 * BUGS: 40 * Now that the image has real UDP primitives, the TCP/UDP duality in 41 * many of the connection-oriented functions should be removed and 42 * cremated. 43 */ 44 45#include "sq.h" 46#include "SocketPlugin/SocketPlugin.h" 47#include "sqaio.h" 48 49#undef AIO_DEBUG 50#undef DEBUG 51 52#ifdef ACORN 53# include <time.h> 54# define __time_t 55# include <signal.h> 56# include "inetlib.h" 57# include "socklib.h" 58# include "netdb.h" 59# include "unixlib.h" 60# include "sys/ioctl.h" 61# include "sys/errno.h" 62# define h_errno errno 63# define MAXHOSTNAMELEN 256 64# define socklen_t int 65# define strncpy(dst, src, len) copyNCharsFromTo(len, src, dst) 66 67#else /* !ACORN */ 68 69# ifdef NEED_GETHOSTNAME_P 70 extern int gethostname(); 71# endif 72# ifdef HAVE_SYS_TIME_H 73# include <sys/time.h> 74# else 75# include <time.h> 76# endif 77# include <sys/param.h> 78# include <sys/socket.h> 79# include <netinet/in.h> 80# include <netinet/udp.h> 81# include <netinet/tcp.h> 82# include <arpa/inet.h> 83# include <netdb.h> 84# include <errno.h> 85# include <unistd.h> 86 87#endif /* !ACORN */ 88 89/* Solaris sometimes fails to define this in netdb.h */ 90#ifndef MAXHOSTNAMELEN 91# define MAXHOSTNAMELEN 256 92#endif 93 94 95/* debugging stuff. can probably be deleted */ 96 97#ifdef DEBUG 98# ifdef ACORN 99# define FPRINTF(s) \ 100 { \ 101 extern os_error privateErr; \ 102 extern void platReportError(os_error *e); \ 103 privateErr.errnum = (bits)0; \ 104 sprintf s; \ 105 platReportError((os_error *)&privateErr); \ 106 }; 107# else /* !ACORN */ 108 extern int aioLastTick, aioThisTick; 109# define FPRINTF(X) { aioThisTick= ioLowResMSecs(); fprintf(stderr, "%8d %8d ", aioThisTick, aioThisTick - aioLastTick); aioLastTick= aioThisTick; fprintf X; } 110# endif 111#else /* !DEBUG */ 112# define FPRINTF(X) 113#endif 114 115 116/*** Socket types ***/ 117 118#define TCPSocketType 0 119#define UDPSocketType 1 120 121 122/*** Resolver states ***/ 123 124#define ResolverUninitialised 0 125#define ResolverSuccess 1 126#define ResolverBusy 2 127#define ResolverError 3 128 129 130/*** TCP Socket states ***/ 131 132#define Invalid -1 133#define Unconnected 0 134#define WaitingForConnection 1 135#define Connected 2 136#define OtherEndClosed 3 137#define ThisEndClosed 4 138 139#define LINGER_SECS 1 140 141static int thisNetSession= 0; 142static int one= 1; 143 144static char localHostName[MAXHOSTNAMELEN]; 145static u_long localHostAddress; /* GROSS IPv4 ASSUMPTION! */ 146 147typedef struct privateSocketStruct 148{ 149 int s; /* Unix socket */ 150 int connSema; /* connection io notification semaphore */ 151 int readSema; /* read io notification semaphore */ 152 int writeSema; /* write io notification semaphore */ 153 int sockState; /* connection + data state */ 154 int sockError; /* errno after socket error */ 155 struct sockaddr_in peer; /* default send/recv address for UDP */ 156 int multiListen; /* whether to listen for multiple connections */ 157 int acceptedSock; /* a connection that has been accepted */ 158} privateSocketStruct; 159 160#define CONN_NOTIFY (1<<0) 161#define READ_NOTIFY (1<<1) 162#define WRITE_NOTIFY (1<<2) 163 164#define PING(S,EVT) \ 165{ \ 166 interpreterProxy->signalSemaphoreWithIndex((S)->EVT##Sema); \ 167 FPRINTF((stderr, "notify %d %s\n", (S)->s, #EVT)); \ 168} 169 170#define notify(SOCK,MASK) \ 171{ \ 172 if ((MASK) & CONN_NOTIFY) PING(SOCK,conn); \ 173 if ((MASK) & READ_NOTIFY) PING(SOCK,read); \ 174 if ((MASK) & WRITE_NOTIFY) PING(SOCK,write); \ 175} 176 177 178/*** Accessors for private socket members from a Squeak socket pointer ***/ 179 180#define _PSP(S) (((S)->privateSocketPtr)) 181#define PSP(S) ((privateSocketStruct *)((S)->privateSocketPtr)) 182 183#define SOCKET(S) (PSP(S)->s) 184#define SOCKETSTATE(S) (PSP(S)->sockState) 185#define SOCKETERROR(S) (PSP(S)->sockError) 186#define SOCKETPEER(S) (PSP(S)->peer) 187 188 189/*** Resolver state ***/ 190 191static char lastName[MAXHOSTNAMELEN+1]; 192static int lastAddr= 0; 193static int lastError= 0; 194static int resolverSema= 0; 195 196/*** Variables ***/ 197 198extern struct VirtualMachine *interpreterProxy; 199int setHookFn; 200 201 202static void acceptHandler(int, void *, int); 203static void connectHandler(int, void *, int); 204static void dataHandler(int, void *, int); 205static void closeHandler(int, void *, int); 206 207 208 209/* this MUST be turned on if DEBUG is turned on in aio.c */ 210 211#ifdef AIO_DEBUG 212char *socketHandlerName(aioHandler h) 213{ 214 if (h == acceptHandler) return "acceptHandler"; 215 if (h == connectHandler) return "connectHandler"; 216 if (h == dataHandler) return "dataHandler"; 217 if (h == closeHandler) return "closeHandler"; 218 return "***unknownHandler***"; 219} 220#endif 221 222 223/*** module initialisation/shutdown ***/ 224 225 226sqInt socketInit(void) 227{ 228 return 1; 229} 230 231sqInt socketShutdown(void) 232{ 233 /* shutdown the network */ 234 sqNetworkShutdown(); 235 return 1; 236} 237 238 239/*** miscellaneous sundries ***/ 240 241/* set linger on a connected stream */ 242 243static void setLinger(int fd, int flag) 244{ 245 struct linger linger= { flag, flag * LINGER_SECS }; 246 setsockopt(fd, SOL_SOCKET, SO_LINGER, (char *)&linger, sizeof(linger)); 247} 248 249/* answer the hostname for the given IP address */ 250 251static const char *addrToName(int netAddress) 252{ 253 u_long nAddr; 254 struct hostent *he; 255 256 lastError= 0; /* for the resolver */ 257 nAddr= htonl(netAddress); 258 if ((he= gethostbyaddr((char *)&nAddr, sizeof(nAddr), AF_INET))) 259 return he->h_name; 260 lastError= h_errno; /* ditto */ 261 return ""; 262} 263 264/* answer the IP address for the given hostname */ 265 266static int nameToAddr(char *hostName) 267{ 268 struct hostent *he; 269 270 lastError= 0; /* ditto */ 271 if ((he= gethostbyname(hostName))) 272 return ntohl(*(long *)(he->h_addr_list[0])); 273 lastError= h_errno; /* and one more ditto */ 274 return 0; 275} 276 277/* answer whether the given socket is valid in this net session */ 278 279static int socketValid(SocketPtr s) 280{ 281 if (s && s->privateSocketPtr && thisNetSession && (s->sessionID == thisNetSession)) 282 return true; 283 interpreterProxy->success(false); 284 return false; 285} 286 287/* answer 1 if the given socket is readable, 288 0 if read would block, or 289 -1 if the socket is no longer connected */ 290 291static int socketReadable(int s) 292{ 293 char buf[1]; 294 int n= recv(s, (void *)buf, 1, MSG_PEEK); 295 if (n > 0) return 1; 296 if ((n < 0) && (errno == EWOULDBLOCK)) return 0; 297 return -1; /* EOF */ 298} 299 300 301/* answer whether the socket can be written without blocking */ 302 303static int socketWritable(int s) 304{ 305 struct timeval tv= { 0, 0 }; 306 fd_set fds; 307 308 FD_ZERO(&fds); 309 FD_SET(s, &fds); 310 return select(s+1, 0, &fds, 0, &tv) > 0; 311} 312 313/* answer the error condition on the given socket */ 314 315static int socketError(int s) 316{ 317 int error= 0; 318 socklen_t errsz= sizeof(error); 319 /* Solaris helpfuly returns -1 if there is an error on the socket, so 320 we can't check the success of the getsockopt call itself. Ho hum. */ 321 getsockopt(s, SOL_SOCKET, SO_ERROR, (void *)&error, &errsz); 322 return error; 323} 324 325 326/*** asynchronous io handlers ***/ 327 328 329/* accept() can now be performed for the socket: call accept(), 330 and replace the server socket with the new client socket 331 leaving the client socket unhandled 332*/ 333static void acceptHandler(int fd, void *data, int flags) 334{ 335 privateSocketStruct *pss= (privateSocketStruct *)data; 336 FPRINTF((stderr, "acceptHandler(%d, %p ,%d)\n", fd, data, flags)); 337 if (flags & AIO_X) /* -- exception */ 338 { 339 /* error during listen() */ 340 aioDisable(fd); 341 pss->sockError= socketError(fd); 342 pss->sockState= Invalid; 343 pss->s= -1; 344 close(fd); 345 fprintf(stderr, "acceptHandler: aborting server %d pss=%p\n", fd, pss); 346 } 347 else /* (flags & AIO_R) -- accept() is ready */ 348 { 349 int newSock= accept(fd, 0, 0); 350 if (newSock < 0) 351 { 352 if (errno == ECONNABORTED) 353 { 354 /* let's just pretend this never happened */ 355 aioHandle(fd, acceptHandler, AIO_RX); 356 return; 357 } 358 /* something really went wrong */ 359 pss->sockError= errno; 360 pss->sockState= Invalid; 361 perror("acceptHandler"); 362 aioDisable(fd); 363 close(fd); 364 fprintf(stderr, "acceptHandler: aborting server %d pss=%p\n", fd, pss); 365 } 366 else /* newSock >= 0 -- connection accepted */ 367 { 368 pss->sockState= Connected; 369 setLinger(newSock, 1); 370 if (pss->multiListen) 371 { 372 pss->acceptedSock= newSock; 373 } 374 else /* traditional listen -- replace server with client in-place */ 375 { 376 aioDisable(fd); 377 close(fd); 378 pss->s= newSock; 379 aioEnable(newSock, pss, 0); 380 } 381 } 382 } 383 notify(pss, CONN_NOTIFY); 384} 385 386 387/* connect() has completed: check errors, leaving the socket unhandled */ 388 389static void connectHandler(int fd, void *data, int flags) 390{ 391 privateSocketStruct *pss= (privateSocketStruct *)data; 392 FPRINTF((stderr, "connectHandler(%d, %p, %d)\n", fd, data, flags)); 393 if (flags & AIO_X) /* -- exception */ 394 { 395 /* error during asynchronous connect() */ 396 aioDisable(fd); 397 pss->sockError= socketError(fd); 398 pss->sockState= Unconnected; 399 perror("connectHandler"); 400 } 401 else /* (flags & AIO_W) -- connect completed */ 402 { 403 /* connect() has completed */ 404 int error= socketError(fd); 405 if (error) 406 { 407 FPRINTF((stderr, "connectHandler: error %d (%s)\n", error, strerror(error))); 408 pss->sockError= error; 409 pss->sockState= Unconnected; 410 } 411 else 412 { 413 pss->sockState= Connected; 414 setLinger(pss->s, 1); 415 } 416 } 417 notify(pss, CONN_NOTIFY); 418} 419 420 421/* read or write data transfer is now possible for the socket. */ 422 423static void dataHandler(int fd, void *data, int flags) 424{ 425 privateSocketStruct *pss= (privateSocketStruct *)data; 426 FPRINTF((stderr, "dataHandler(%d=%d, %p, %d)\n", fd, pss->s, data, flags)); 427 428 if (pss == NULL) 429 { 430 fprintf(stderr, "dataHandler: pss is NULL fd=%d data=%p flags=0x%x\n", fd, data, flags); 431 return; 432 } 433 434 if (flags & AIO_R) 435 { 436 int n= socketReadable(fd); 437 if (n == 0) 438 { 439 fprintf(stderr, "dataHandler: selected socket fd=%d flags=0x%x would block (why?)\n", fd, flags); 440 } 441 if (n != 1) 442 { 443 pss->sockError= socketError(fd); 444 pss->sockState= OtherEndClosed; 445 } 446 } 447 if (flags & AIO_X) 448 { 449 /* assume out-of-band data has arrived */ 450 /* NOTE: Squeak's socket interface is currently incapable of reading 451 * OOB data. We have no choice but to discard it. Ho hum. */ 452 char buf[1]; 453 int n= recv(fd, (void *)buf, 1, MSG_OOB); 454 if (n == 1) fprintf(stderr, "socket: received OOB data: %02x\n", buf[0]); 455 } 456 if (flags & AIO_R) notify(pss, READ_NOTIFY); 457 if (flags & AIO_W) notify(pss, WRITE_NOTIFY); 458} 459 460 461/* a non-blocking close() has completed -- finish tidying up */ 462 463static void closeHandler(int fd, void *data, int flags) 464{ 465 privateSocketStruct *pss= (privateSocketStruct *)data; 466 aioDisable(fd); 467 FPRINTF((stderr, "closeHandler(%d, %p, %d)\n", fd, data, flags)); 468 pss->sockState= Unconnected; 469 pss->s= -1; 470 notify(pss, CONN_NOTIFY); 471} 472 473 474/*** Squeak network functions ***/ 475 476 477/* start a new network session */ 478 479sqInt sqNetworkInit(sqInt resolverSemaIndex) 480{ 481 if (0 != thisNetSession) 482 return 0; /* already initialised */ 483 gethostname(localHostName, MAXHOSTNAMELEN); 484 localHostAddress= nameToAddr(localHostName); 485 thisNetSession= clock() + time(0); 486 if (0 == thisNetSession) 487 thisNetSession= 1; /* 0 => uninitialised */ 488 resolverSema= resolverSemaIndex; 489 return 0; 490} 491 492 493/* terminate the current network session (invalidates all open sockets) */ 494 495void sqNetworkShutdown(void) 496{ 497 thisNetSession= 0; 498 resolverSema= 0; 499 aioFini(); 500} 501 502 503 504/*** Squeak Generic Socket Functions ***/ 505 506 507/* create a new socket */ 508 509void sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaID(SocketPtr s, sqInt netType, sqInt socketType, sqInt recvBufSize, sqInt sendBufSize, sqInt semaIndex) 510{ 511 sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(s, netType, socketType,recvBufSize, sendBufSize, semaIndex, semaIndex, semaIndex); 512} 513 514void sqSocketCreateNetTypeSocketTypeRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(SocketPtr s, sqInt netType, sqInt socketType, sqInt recvBufSize, sqInt sendBufSize, sqInt semaIndex, sqInt readSemaIndex, sqInt writeSemaIndex) 515{ 516 int newSocket= -1; 517 privateSocketStruct *pss; 518 519 s->sessionID= 0; 520 if (TCPSocketType == socketType) 521 { 522 /* --- TCP --- */ 523 newSocket= socket(AF_INET, SOCK_STREAM, 0); 524 } 525 else if (UDPSocketType == socketType) 526 { 527 /* --- UDP --- */ 528 newSocket= socket(AF_INET, SOCK_DGRAM, 0); 529 } 530 if (-1 == newSocket) 531 { 532 /* socket() failed, or incorrect socketType */ 533 interpreterProxy->success(false); 534 return; 535 } 536 setsockopt(newSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)); 537 /* private socket structure */ 538 pss= (privateSocketStruct *)calloc(1, sizeof(privateSocketStruct)); 539 if (pss == NULL) 540 { 541 fprintf(stderr, "acceptFrom: out of memory\n"); 542 interpreterProxy->success(false); 543 return; 544 } 545 pss->s= newSocket; 546 pss->connSema= semaIndex; 547 pss->readSema= readSemaIndex; 548 pss->writeSema= writeSemaIndex; 549 550 /* UDP sockets are born "connected" */ 551 if (UDPSocketType == socketType) 552 { 553 pss->sockState= Connected; 554 aioEnable(pss->s, pss, 0); 555 } 556 else 557 { 558 pss->sockState= Unconnected; 559 } 560 pss->sockError= 0; 561 /* initial UDP peer := wildcard */ 562 memset(&pss->peer, 0, sizeof(pss->peer)); 563 pss->peer.sin_family= AF_INET; 564 pss->peer.sin_port= 0; 565 pss->peer.sin_addr.s_addr= INADDR_ANY; 566 /* Squeak socket */ 567 s->sessionID= thisNetSession; 568 s->socketType= socketType; 569 s->privateSocketPtr= pss; 570 FPRINTF((stderr, "create(%d) -> %lx\n", SOCKET(s), (unsigned long)PSP(s))); 571 /* Note: socket is in BLOCKING mode until aioEnable is called for it! */ 572} 573 574 575/* return the state of a socket */ 576 577sqInt sqSocketConnectionStatus(SocketPtr s) 578{ 579 if (!socketValid(s)) 580 return Invalid; 581 /* we now know that the net session is valid, so if state is Invalid... */ 582 if (SOCKETSTATE(s) == Invalid) /* see acceptHandler() */ 583 { 584 fprintf(stderr, "socketStatus: freeing invalidated pss=%p\n", PSP(s)); 585 /*free(PSP(s));*/ /* this almost never happens -- safer not to free()?? */ 586 _PSP(s)= 0; 587 interpreterProxy->success(false); 588 return Invalid; 589 } 590#if 0 591 /* check for connection closed by peer */ 592 if (SOCKETSTATE(s) == Connected) 593 { 594 int fd= SOCKET(s); 595 int n= socketReadable(fd); 596 if (n < 0) 597 { 598 FPRINTF((stderr, "socketStatus(%d): detected other end closed\n", fd)); 599 SOCKETSTATE(s)= OtherEndClosed; 600 } 601 } 602#endif 603 FPRINTF((stderr, "socketStatus(%d) -> %d\n", SOCKET(s), SOCKETSTATE(s))); 604 return SOCKETSTATE(s); 605} 606 607 608 609/* TCP => start listening for incoming connections. 610 * UDP => associate the local port number with the socket. 611 */ 612void sqSocketListenOnPort(SocketPtr s, sqInt port) 613{ 614 sqSocketListenOnPortBacklogSize(s, port, 1); 615} 616 617void sqSocketListenOnPortBacklogSizeInterface(SocketPtr s, sqInt port, sqInt backlogSize, sqInt addr) 618{ 619 struct sockaddr_in saddr; 620 621 if (!socketValid(s)) 622 return; 623 624 /* only TCP sockets have a backlog */ 625 if ((backlogSize > 1) && (s->socketType != TCPSocketType)) 626 { 627 interpreterProxy->success(false); 628 return; 629 } 630 631 PSP(s)->multiListen= (backlogSize > 1); 632 FPRINTF((stderr, "listenOnPortBacklogSize(%d, %d)\n", SOCKET(s), backlogSize)); 633 memset(&saddr, 0, sizeof(saddr)); 634 saddr.sin_family= AF_INET; 635 saddr.sin_port= htons((short)port); 636 saddr.sin_addr.s_addr= htonl(addr); 637 bind(SOCKET(s), (struct sockaddr*) &saddr, sizeof(saddr)); 638 if (TCPSocketType == s->socketType) 639 { 640 /* --- TCP --- */ 641 listen(SOCKET(s), backlogSize); 642 SOCKETSTATE(s)= WaitingForConnection; 643 aioEnable(SOCKET(s), PSP(s), 0); 644 aioHandle(SOCKET(s), acceptHandler, AIO_RX); /* R => accept() */ 645 } 646 else 647 { 648 /* --- UDP --- */ 649 } 650} 651 652void sqSocketListenOnPortBacklogSize(SocketPtr s, sqInt port, sqInt backlogSize) 653{ 654 sqSocketListenOnPortBacklogSizeInterface(s, port, backlogSize, INADDR_ANY); 655} 656 657/* TCP => open a connection. 658 * UDP => set remote address. 659 */ 660void sqSocketConnectToPort(SocketPtr s, sqInt addr, sqInt port) 661{ 662 struct sockaddr_in saddr; 663 664 if (!socketValid(s)) 665 return; 666 FPRINTF((stderr, "connectTo(%d)\n", SOCKET(s))); 667 memset(&saddr, 0, sizeof(saddr)); 668 saddr.sin_family= AF_INET; 669 saddr.sin_port= htons((short)port); 670 saddr.sin_addr.s_addr= htonl(addr); 671 if (UDPSocketType == s->socketType) 672 { 673 /* --- UDP --- */ 674 if (SOCKET(s) >= 0) 675 { 676 memcpy((void *)&SOCKETPEER(s), (void *)&saddr, sizeof(SOCKETPEER(s))); 677 SOCKETSTATE(s)= Connected; 678 } 679 } 680 else 681 { 682 /* --- TCP --- */ 683 int result; 684 aioEnable(SOCKET(s), PSP(s), 0); 685 result= connect(SOCKET(s), (struct sockaddr *)&saddr, sizeof(saddr)); 686 FPRINTF((stderr, "connect() => %d\n", result)); 687 if (result == 0) 688 { 689 /* connection completed synchronously */ 690 SOCKETSTATE(s)= Connected; 691 notify(PSP(s), CONN_NOTIFY); 692 setLinger(SOCKET(s), 1); 693 } 694 else 695 { 696 if (errno == EINPROGRESS || errno == EWOULDBLOCK) 697 { 698 /* asynchronous connection in progress */ 699 SOCKETSTATE(s)= WaitingForConnection; 700 aioHandle(SOCKET(s), connectHandler, AIO_WX); /* W => connect() */ 701 } 702 else 703 { 704 /* connection error */ 705 perror("sqConnectToPort"); 706 SOCKETSTATE(s)= Unconnected; 707 SOCKETERROR(s)= errno; 708 notify(PSP(s), CONN_NOTIFY); 709 } 710 } 711 } 712} 713 714 715void sqSocketAcceptFromRecvBytesSendBytesSemaID(SocketPtr s, SocketPtr serverSocket, sqInt recvBufSize, sqInt sendBufSize, sqInt semaIndex) 716{ 717 sqSocketAcceptFromRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(s, serverSocket, recvBufSize, sendBufSize, semaIndex, semaIndex, semaIndex); 718} 719 720 721void sqSocketAcceptFromRecvBytesSendBytesSemaIDReadSemaIDWriteSemaID(SocketPtr s, SocketPtr serverSocket, sqInt recvBufSize, sqInt sendBufSize, sqInt semaIndex, sqInt readSemaIndex, sqInt writeSemaIndex) 722{ 723 /* The image has already called waitForConnection, so there is no 724 need to signal the server's connection semaphore again. */ 725 726 struct privateSocketStruct *pss; 727 728 FPRINTF((stderr, "acceptFrom(%p, %d)\n", s, SOCKET(serverSocket))); 729 730 /* sanity checks */ 731 if (!socketValid(serverSocket) || !PSP(serverSocket)->multiListen) 732 { 733 FPRINTF((stderr, "accept failed: (multi->%d)\n", PSP(serverSocket)->multiListen)); 734 interpreterProxy->success(false); 735 return; 736 } 737 738 /* check that a connection is there */ 739 if (PSP(serverSocket)->acceptedSock < 0) 740 { 741 fprintf(stderr, "acceptFrom: no socket available\n"); 742 interpreterProxy->success(false); 743 return; 744 } 745 746 /* got connection -- fill in the structure */ 747 s->sessionID= 0; 748 pss= (privateSocketStruct *)calloc(1, sizeof(privateSocketStruct)); 749 if (pss == NULL) 750 { 751 fprintf(stderr, "acceptFrom: out of memory\n"); 752 interpreterProxy->success(false); 753 return; 754 } 755 756 _PSP(s)= pss; 757 pss->s= PSP(serverSocket)->acceptedSock; 758 PSP(serverSocket)->acceptedSock= -1; 759 SOCKETSTATE(serverSocket)= WaitingForConnection; 760 aioHandle(SOCKET(serverSocket), acceptHandler, AIO_RX); 761 s->sessionID= thisNetSession; 762 pss->connSema= semaIndex; 763 pss->readSema= readSemaIndex; 764 pss->writeSema= writeSemaIndex; 765 pss->sockState= Connected; 766 pss->sockError= 0; 767 aioEnable(SOCKET(s), PSP(s), 0); 768} 769 770 771/* close the socket */ 772 773void sqSocketCloseConnection(SocketPtr s) 774{ 775 int result= 0; 776 777 if (!socketValid(s)) 778 return; 779 780 FPRINTF((stderr, "closeConnection(%d)\n", SOCKET(s))); 781 782 if (SOCKET(s) < 0) 783 return; /* already closed */ 784 785 aioDisable(SOCKET(s)); 786 SOCKETSTATE(s)= ThisEndClosed; 787 result= close(SOCKET(s)); 788 if ((result == -1) && (errno != EWOULDBLOCK)) 789 { 790 /* error */ 791 SOCKETSTATE(s)= Unconnected; 792 SOCKETERROR(s)= errno; 793 notify(PSP(s), CONN_NOTIFY); 794 perror("closeConnection"); 795 } 796 else if (0 == result) 797 { 798 /* close completed synchronously */ 799 SOCKETSTATE(s)= Unconnected; 800 FPRINTF((stderr, "closeConnection: disconnected\n")); 801 SOCKET(s)= -1; 802 } 803 else 804 { 805 /* asynchronous close in progress */ 806 SOCKETSTATE(s)= ThisEndClosed; 807 aioHandle(SOCKET(s), closeHandler, AIO_RWX); /* => close() done */ 808 FPRINTF((stderr, "closeConnection: deferred [aioHandle is set]\n")); 809 } 810} 811 812 813/* close the socket without lingering */ 814 815void sqSocketAbortConnection(SocketPtr s) 816{ 817 FPRINTF((stderr, "abortConnection(%d)\n", SOCKET(s))); 818 if (!socketValid(s)) 819 return; 820 setLinger(SOCKET(s), 0); 821 sqSocketCloseConnection(s); 822} 823 824 825/* Release the resources associated with this socket. 826 If a connection is open, abort it. */ 827 828void sqSocketDestroy(SocketPtr s) 829{ 830 if (!socketValid(s)) 831 return; 832 833 FPRINTF((stderr, "destroy(%d)\n", SOCKET(s))); 834 835 if (SOCKET(s)) 836 sqSocketAbortConnection(s); /* close if necessary */ 837 838 if (PSP(s)) 839 free(PSP(s)); /* release private struct */ 840 841 _PSP(s)= 0; 842} 843 844 845/* answer the OS error code for the last socket operation */ 846 847sqInt sqSocketError(SocketPtr s) 848{ 849 if (!socketValid(s)) 850 return -1; 851 return SOCKETERROR(s); 852} 853 854 855/* return the local IP address bound to a socket */ 856 857sqInt sqSocketLocalAddress(SocketPtr s) 858{ 859 struct sockaddr_in saddr; 860 socklen_t saddrSize= sizeof(saddr); 861 862 if (!socketValid(s)) 863 return -1; 864 if (getsockname(SOCKET(s), (struct sockaddr *)&saddr, &saddrSize) 865 || (AF_INET != saddr.sin_family)) 866 return 0; 867 return ntohl(saddr.sin_addr.s_addr); 868} 869 870 871/* return the peer's IP address */ 872 873sqInt sqSocketRemoteAddress(SocketPtr s) 874{ 875 struct sockaddr_in saddr; 876 socklen_t saddrSize= sizeof(saddr); 877 878 if (!socketValid(s)) 879 return -1; 880 if (TCPSocketType == s->socketType) 881 { 882 /* --- TCP --- */ 883 if (getpeername(SOCKET(s), (struct sockaddr *)&saddr, &saddrSize) 884 || (AF_INET != saddr.sin_family)) 885 return 0; 886 return ntohl(saddr.sin_addr.s_addr); 887 } 888 /* --- UDP --- */ 889 return ntohl(SOCKETPEER(s).sin_addr.s_addr); 890} 891 892 893/* return the local port number of a socket */ 894 895sqInt sqSocketLocalPort(SocketPtr s) 896{ 897 struct sockaddr_in saddr; 898 socklen_t saddrSize= sizeof(saddr); 899 900 if (!socketValid(s)) 901 return -1; 902 if (getsockname(SOCKET(s), (struct sockaddr *)&saddr, &saddrSize) 903 || (AF_INET != saddr.sin_family)) 904 return 0; 905 return ntohs(saddr.sin_port); 906} 907 908 909/* return the peer's port number */ 910 911sqInt sqSocketRemotePort(SocketPtr s) 912{ 913 struct sockaddr_in saddr; 914 socklen_t saddrSize= sizeof(saddr); 915 916 if (!socketValid(s)) 917 return -1; 918 if (TCPSocketType == s->socketType) 919 { 920 /* --- TCP --- */ 921 if (getpeername(SOCKET(s), (struct sockaddr *)&saddr, &saddrSize) 922 || (AF_INET != saddr.sin_family)) 923 return 0; 924 return ntohs(saddr.sin_port); 925 } 926 /* --- UDP --- */ 927 return ntohs(SOCKETPEER(s).sin_port); 928} 929 930 931/* answer whether the socket has data available for reading: 932 if the socket is not connected, answer "false"; 933 if the socket is open and data can be read, answer "true". 934 if the socket is open and no data is currently readable, answer "false"; 935 if the socket is closed by peer, change the state to OtherEndClosed 936 and answer "false"; 937*/ 938sqInt sqSocketReceiveDataAvailable(SocketPtr s) 939{ 940 if (!socketValid(s)) return false; 941 if (SOCKETSTATE(s) == Connected) 942 { 943 int fd= SOCKET(s); 944 int n= socketReadable(fd); 945 if (n > 0) 946 { 947 FPRINTF((stderr, "receiveDataAvailable(%d) -> true\n", fd)); 948 return true; 949 } 950 else if (n < 0) 951 { 952 FPRINTF((stderr, "receiveDataAvailable(%d): other end closed\n", fd)); 953 SOCKETSTATE(s)= OtherEndClosed; 954 } 955 } 956 else /* (SOCKETSTATE(s) != Connected) */ 957 { 958 FPRINTF((stderr, "receiveDataAvailable(%d): socket not connected\n", SOCKET(s))); 959 } 960 aioHandle(SOCKET(s), dataHandler, AIO_RX); 961 FPRINTF((stderr, "receiveDataAvailable(%d) -> false [aioHandle is set]\n", SOCKET(s))); 962 return false; 963} 964 965 966/* answer whether the socket has space to receive more data */ 967 968sqInt sqSocketSendDone(SocketPtr s) 969{ 970 if (!socketValid(s)) 971 return false; 972 if (SOCKETSTATE(s) == Connected) 973 { 974 if (socketWritable(SOCKET(s))) return true; 975 aioHandle(SOCKET(s), dataHandler, AIO_WX); 976 } 977 return false; 978} 979 980 981/* read data from the socket s into buf for at most bufSize bytes. 982 answer the number actually read. For UDP, fill in the peer's address 983 with the approriate value. 984*/ 985sqInt sqSocketReceiveDataBufCount(SocketPtr s, char *buf, sqInt bufSize) 986{ 987 int nread= 0; 988 989 if (!socketValid(s)) 990 return -1; 991 if (UDPSocketType == s->socketType) 992 { 993 /* --- UDP --- */ 994 socklen_t addrSize= sizeof(SOCKETPEER(s)); 995 if ((nread= recvfrom(SOCKET(s), buf, bufSize, 0, (struct sockaddr *)&SOCKETPEER(s), &addrSize)) <= 0) 996 { 997 if ((nread == -1) && (errno == EWOULDBLOCK)) 998 { 999 FPRINTF((stderr, "UDP receiveData(%d) < 1 [blocked]\n", SOCKET(s))); 1000 return 0; 1001 } 1002 SOCKETERROR(s)= errno; 1003 FPRINTF((stderr, "UDP receiveData(%d) < 1 [a:%d]\n", SOCKET(s), errno)); 1004 return 0; 1005 } 1006 } 1007 else 1008 { 1009 /* --- TCP --- */ 1010 if ((nread= read(SOCKET(s), buf, bufSize)) <= 0) 1011 { 1012 if ((nread == -1) && (errno == EWOULDBLOCK)) 1013 { 1014 FPRINTF((stderr, "TCP receiveData(%d) < 1 [blocked]\n", SOCKET(s))); 1015 return 0; 1016 } 1017 /* connection reset */ 1018 SOCKETSTATE(s)= OtherEndClosed; 1019 SOCKETERROR(s)= errno; 1020 FPRINTF((stderr, "TCP receiveData(%d) < 1 [b:%d]\n", SOCKET(s), errno)); 1021 notify(PSP(s), CONN_NOTIFY); 1022 return 0; 1023 } 1024 } 1025 /* read completed synchronously */ 1026 FPRINTF((stderr, "receiveData(%d) done = %d\n", SOCKET(s), nread)); 1027 return nread; 1028} 1029 1030 1031/* write data to the socket s from buf for at most bufSize bytes. 1032 answer the number of bytes actually written. 1033*/ 1034sqInt sqSocketSendDataBufCount(SocketPtr s, char *buf, sqInt bufSize) 1035{ 1036 int nsent= 0; 1037 1038 if (!socketValid(s)) 1039 return -1; 1040 1041 if (UDPSocketType == s->socketType) 1042 { 1043 /* --- UDP --- */ 1044 FPRINTF((stderr, "UDP sendData(%d, %d)\n", SOCKET(s), bufSize)); 1045 if ((nsent= sendto(SOCKET(s), buf, bufSize, 0, (struct sockaddr *)&SOCKETPEER(s), sizeof(SOCKETPEER(s)))) <= 0) 1046 { 1047 if (errno == EWOULDBLOCK) /* asynchronous write in progress */ 1048 return 0; 1049 FPRINTF((stderr, "UDP send failed\n")); 1050 SOCKETERROR(s)= errno; 1051 return 0; 1052 } 1053 } 1054 else 1055 { 1056 /* --- TCP --- */ 1057 FPRINTF((stderr, "TCP sendData(%d, %d)\n", SOCKET(s), bufSize)); 1058 if ((nsent= write(SOCKET(s), buf, bufSize)) <= 0) 1059 { 1060 if ((nsent == -1) && (errno == EWOULDBLOCK)) 1061 { 1062 FPRINTF((stderr, "TCP sendData(%d, %d) -> %d [blocked]", 1063 SOCKET(s), bufSize, nsent)); 1064 return 0; 1065 } 1066 else 1067 { 1068 /* error: most likely "connection closed by peer" */ 1069 SOCKETSTATE(s)= OtherEndClosed; 1070 SOCKETERROR(s)= errno; 1071 FPRINTF((stderr, "TCP write failed -> %d", errno)); 1072 return 0; 1073 } 1074 } 1075 } 1076 /* write completed synchronously */ 1077 FPRINTF((stderr, "sendData(%d) done = %d\n", SOCKET(s), nsent)); 1078 return nsent; 1079} 1080 1081 1082/* read data from the UDP socket s into buf for at most bufSize bytes. 1083 answer the number of bytes actually read. 1084*/ 1085sqInt sqSocketReceiveUDPDataBufCountaddressportmoreFlag(SocketPtr s, char *buf, sqInt bufSize, sqInt *address, sqInt *port, sqInt *moreFlag) 1086{ 1087 if (socketValid(s) && (UDPSocketType == s->socketType)) 1088 { 1089 struct sockaddr_in saddr; 1090 socklen_t addrSize= sizeof(saddr); 1091 1092 FPRINTF((stderr, "recvFrom(%d)\n", SOCKET(s))); 1093 memset(&saddr, 0, sizeof(saddr)); 1094 { 1095 int nread= recvfrom(SOCKET(s), buf, bufSize, 0, (struct sockaddr *)&saddr, &addrSize); 1096 if (nread >= 0) 1097 { 1098 *address= ntohl(saddr.sin_addr.s_addr); 1099 *port= ntohs(saddr.sin_port); 1100 return nread; 1101 } 1102 if (errno == EWOULDBLOCK) /* asynchronous read in progress */ 1103 return 0; 1104 SOCKETERROR(s)= errno; 1105 FPRINTF((stderr, "receiveData(%d)= %da\n", SOCKET(s), 0)); 1106 } 1107 } 1108 interpreterProxy->success(false); 1109 return 0; 1110} 1111 1112 1113/* write data to the UDP socket s from buf for at most bufSize bytes. 1114 * answer the number of bytes actually written. 1115 */ 1116sqInt sqSockettoHostportSendDataBufCount(SocketPtr s, sqInt address, sqInt port, char *buf, sqInt bufSize) 1117{ 1118 if (socketValid(s) && (UDPSocketType == s->socketType)) 1119 { 1120 struct sockaddr_in saddr; 1121 1122 FPRINTF((stderr, "sendTo(%d)\n", SOCKET(s))); 1123 memset(&saddr, 0, sizeof(saddr)); 1124 saddr.sin_family= AF_INET; 1125 saddr.sin_port= htons((short)port); 1126 saddr.sin_addr.s_addr= htonl(address); 1127 { 1128 int nsent= sendto(SOCKET(s), buf, bufSize, 0, (struct sockaddr *)&saddr, sizeof(saddr)); 1129 if (nsent >= 0) 1130 return nsent; 1131 1132 if (errno == EWOULDBLOCK) /* asynchronous write in progress */ 1133 return 0; 1134 FPRINTF((stderr, "UDP send failed\n")); 1135 SOCKETERROR(s)= errno; 1136 } 1137 } 1138 interpreterProxy->success(false); 1139 return 0; 1140} 1141 1142 1143/*** socket options ***/ 1144 1145 1146/* NOTE: we only support the portable options here as an incentive for 1147 people to write portable Squeak programs. If you need 1148 non-portable socket options then go write yourself a plugin 1149 specific to your platform. This decision is unilateral and 1150 non-negotiable. - ikp 1151 NOTE: we only support the integer-valued options because the code 1152 in SocketPlugin doesn't seem able to cope with the others. 1153 (Personally I think that things like SO_SNDTIMEO et al would 1154 by far more interesting than the majority of things on this 1155 list, but there you go...) 1156 NOTE: if your build fails because of a missing option in this list, 1157 simply DELETE THE OPTION (or comment it out) and then send 1158 me mail (ian.piumarta@inria.fr) to let me know about it. 1159 */ 1160 1161typedef struct 1162{ 1163 char *name; /* name as known to Squeak */ 1164 int optlevel; /* protocol level */ 1165 int optname; /* name as known to Unix */ 1166} socketOption; 1167 1168#ifndef SOL_IP 1169# define SOL_IP IPPROTO_IP 1170#endif 1171 1172#ifndef SOL_UDP 1173# define SOL_UDP IPPROTO_UDP 1174#endif 1175 1176#ifndef SOL_TCP 1177# define SOL_TCP IPPROTO_TCP 1178#endif 1179 1180static socketOption socketOptions[]= { 1181 { "SO_DEBUG", SOL_SOCKET, SO_DEBUG }, 1182 { "SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR }, 1183 { "SO_DONTROUTE", SOL_SOCKET, SO_DONTROUTE }, 1184 { "SO_BROADCAST", SOL_SOCKET, SO_BROADCAST }, 1185 { "SO_SNDBUF", SOL_SOCKET, SO_SNDBUF }, 1186 { "SO_RCVBUF", SOL_SOCKET, SO_RCVBUF }, 1187 { "SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE }, 1188 { "SO_OOBINLINE", SOL_SOCKET, SO_OOBINLINE }, 1189 { "SO_LINGER", SOL_SOCKET, SO_LINGER }, 1190 { "IP_TTL", SOL_IP, IP_TTL }, 1191 { "IP_HDRINCL", SOL_IP, IP_HDRINCL }, 1192 { "IP_MULTICAST_IF", SOL_IP, IP_MULTICAST_IF }, 1193 { "IP_MULTICAST_TTL", SOL_IP, IP_MULTICAST_TTL }, 1194 { "IP_MULTICAST_LOOP", SOL_IP, IP_MULTICAST_LOOP }, 1195#ifdef IP_ADD_MEMBERSHIP 1196 { "IP_ADD_MEMBERSHIP", SOL_IP, IP_ADD_MEMBERSHIP }, 1197 { "IP_DROP_MEMBERSHIP", SOL_IP, IP_DROP_MEMBERSHIP }, 1198#endif 1199 { "TCP_MAXSEG", SOL_TCP, TCP_MAXSEG }, 1200 { "TCP_NODELAY", SOL_TCP, TCP_NODELAY }, 1201#ifdef SO_REUSEPORT 1202 { "SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT }, 1203#endif 1204#if 0 /*** deliberately unsupported options -- do NOT enable these! ***/ 1205 { "SO_PRIORITY", SOL_SOCKET, SO_PRIORITY }, 1206 { "SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT }, 1207 { "SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT }, 1208 { "IP_RCVOPTS", SOL_IP, IP_RCVOPTS }, 1209 { "IP_RCVDSTADDR", SOL_IP, IP_RCVDSTADDR }, 1210 { "UDP_CHECKSUM", SOL_UDP, UDP_CHECKSUM }, 1211 { "TCP_ABORT_THRESHOLD", SOL_TCP, TCP_ABORT_THRESHOLD }, 1212 { "TCP_CONN_NOTIFY_THRESHOLD", SOL_TCP, TCP_CONN_NOTIFY_THRESHOLD }, 1213 { "TCP_CONN_ABORT_THRESHOLD", SOL_TCP, TCP_CONN_ABORT_THRESHOLD }, 1214 { "TCP_NOTIFY_THRESHOLD", SOL_TCP, TCP_NOTIFY_THRESHOLD }, 1215 { "TCP_URGENT_PTR_TYPE", SOL_TCP, TCP_URGENT_PTR_TYPE }, 1216#endif 1217 { (char *)0, 0, 0 } 1218}; 1219 1220 1221static socketOption *findOption(char *name, size_t nameSize) 1222{ 1223 if (nameSize < 32) 1224 { 1225 socketOption *opt= 0; 1226 char buf[32]; 1227 buf[nameSize]= '\0'; 1228 strncpy(buf, name, nameSize); 1229 for (opt= socketOptions; opt->name != 0; ++opt) 1230 if (!strcmp(buf, opt->name)) 1231 return opt; 1232 fprintf(stderr, "SocketPlugin: ignoring unknown option '%s'\n", buf); 1233 } 1234 return 0; 1235} 1236 1237 1238/* set the given option for the socket. the option comes in as a 1239 * String. (why on earth we might think this a good idea eludes me 1240 * ENTIRELY, so... if the string doesn't smell like an integer then we 1241 * copy it verbatim, assuming it's really a ByteArray pretending to be 1242 * a struct. caveat hackor.) 1243 */ 1244sqInt sqSocketSetOptionsoptionNameStartoptionNameSizeoptionValueStartoptionValueSizereturnedValue(SocketPtr s, char *optionName, sqInt optionNameSize, char *optionValue, sqInt optionValueSize, sqInt *result) 1245{ 1246 if (socketValid(s)) 1247 { 1248 socketOption *opt= findOption(optionName, (size_t)optionNameSize); 1249 if (opt != 0) 1250 { 1251 int val= 0; 1252 char buf[32]; 1253 char *endptr; 1254 /* this is JUST PLAIN WRONG (I mean the design in the image rather 1255 than the implementation here, which is probably correct 1256 w.r.t. the broken design) */ 1257 if (optionValueSize > sizeof(buf) - 1) 1258 goto barf; 1259 1260 memset((void *)buf, 0, sizeof(buf)); 1261 memcpy((void *)buf, optionValue, optionValueSize); 1262 if (optionValueSize == 1) /* character `1' or `0' */ 1263 { 1264 val= strtol(buf, &endptr, 0); 1265 if (endptr != buf) 1266 { 1267 memcpy((void *)buf, (void *)&val, sizeof(val)); 1268 optionValueSize= sizeof(val); 1269 } 1270 } 1271 if ((setsockopt(PSP(s)->s, opt->optlevel, opt->optname, 1272 (const void *)buf, optionValueSize)) < 0) 1273 { 1274 perror("setsockopt"); 1275 goto barf; 1276 } 1277 /* it isn't clear what we're supposed to return here, since 1278 setsockopt isn't supposed to have any value-result parameters 1279 (go grok that `const' on the buffer argument if you don't 1280 believe me). the image says "the result of the negotiated 1281 value". what the fuck is there to negotiate? either 1282 setsockopt sets the value or it barfs. and i'm not about to go 1283 calling getsockopt just to see if the value got changed or not 1284 (the image should send getOption: to the Socket if it really 1285 wants to know). if the following is wrong then I could 1286 probably care (a lot) less... fix the logic in the image and 1287 then maybe i'll care about fixing the logic in here. (i know 1288 that isn't very helpful, but it's 05:47 in the morning and i'm 1289 severely grumpy after fixing several very unpleasant bugs that 1290 somebody introduced into this file while i wasn't looking.) */ 1291 *result= val; 1292 return 0; 1293 } 1294 } 1295 barf: 1296 interpreterProxy->success(false); 1297 return false; 1298} 1299 1300 1301/* query the socket for the given option. */ 1302sqInt sqSocketGetOptionsoptionNameStartoptionNameSizereturnedValue(SocketPtr s, char *optionName, sqInt optionNameSize, sqInt *result) 1303{ 1304 if (socketValid(s)) 1305 { 1306 socketOption *opt= findOption(optionName, (size_t)optionNameSize); 1307 if (opt != 0) 1308 { 1309 int optval; /* NOT sqInt */ 1310 socklen_t optlen= sizeof(optval); 1311 if ((getsockopt(PSP(s)->s, opt->optlevel, opt->optname, (void *)&optval, &optlen)) < 0) 1312 goto barf; 1313 if (optlen != sizeof(optval)) 1314 goto barf; 1315 *result= optval; 1316 return 0; 1317 } 1318 } 1319 barf: 1320 interpreterProxy->success(false); 1321 return errno; 1322} 1323 1324void sqSocketBindToPort(SocketPtr s, int addr, int port) 1325{ 1326 int result; 1327 struct sockaddr_in inaddr; 1328 privateSocketStruct *pss= PSP(s); 1329 1330 if (!socketValid(s)) return; 1331 1332 /* bind the socket */ 1333 memset(&inaddr, 0, sizeof(inaddr)); 1334 inaddr.sin_family= AF_INET; 1335 inaddr.sin_port= htons(port); 1336 inaddr.sin_addr.s_addr= htonl(addr); 1337 1338 if (bind(SOCKET(s), (struct sockaddr *)&inaddr, sizeof(struct sockaddr_in)) < 0) 1339 { 1340 pss->sockError= errno; 1341 interpreterProxy->success(false); 1342 return; 1343 } 1344} 1345 1346void sqSocketSetReusable(SocketPtr s) 1347{ 1348 char optionValue[256]; 1349 size_t bufSize; 1350 unsigned char buf[4]; 1351 int err; 1352 1353 if (!socketValid(s)) return; 1354 1355 *(int *)buf= 1; 1356 bufSize= 4; 1357 if (setsockopt(SOCKET(s), SOL_SOCKET, SO_REUSEADDR, buf, bufSize) < 0) 1358 { 1359 PSP(s)->sockError= errno; 1360 interpreterProxy->success(false); 1361 return; 1362 } 1363} 1364 1365/*** Resolver functions ***/ 1366 1367 1368/* Note: the Mac and Win32 implementations implement asynchronous lookups 1369 * in the DNS. I can't think of an easy way to do this in Unix without 1370 * going totally ott with threads or somesuch. If anyone knows differently, 1371 * please tell me about it. - Ian 1372 */ 1373 1374 1375/*** irrelevancies ***/ 1376 1377void sqResolverAbort(void) {} 1378 1379void sqResolverStartAddrLookup(sqInt address) 1380{ 1381 const char *res; 1382 res= addrToName(address); 1383 strncpy(lastName, res, MAXHOSTNAMELEN); 1384 FPRINTF((stderr, "startAddrLookup %s\n", lastName)); 1385} 1386 1387 1388sqInt sqResolverStatus(void) 1389{ 1390 if(!thisNetSession) 1391 return ResolverUninitialised; 1392 if(lastError != 0) 1393 return ResolverError; 1394 return ResolverSuccess; 1395} 1396 1397/*** trivialities ***/ 1398 1399sqInt sqResolverAddrLookupResultSize(void) { return strlen(lastName); } 1400sqInt sqResolverError(void) { return lastError; } 1401sqInt sqResolverLocalAddress(void) { return nameToAddr(localHostName); } 1402sqInt sqResolverNameLookupResult(void) { return lastAddr; } 1403 1404void sqResolverAddrLookupResult(char *nameForAddress, sqInt nameSize) 1405{ 1406 memcpy(nameForAddress, lastName, nameSize); 1407} 1408 1409/*** name resolution ***/ 1410 1411void sqResolverStartNameLookup(char *hostName, sqInt nameSize) 1412{ 1413 int len= (nameSize < MAXHOSTNAMELEN) ? nameSize : MAXHOSTNAMELEN; 1414 memcpy(lastName, hostName, len); 1415 lastName[len]= lastError= 0; 1416 FPRINTF((stderr, "name lookup %s\n", lastName)); 1417 lastAddr= nameToAddr(lastName); 1418 /* we're done before we even started */ 1419 interpreterProxy->signalSemaphoreWithIndex(resolverSema); 1420}