/vm/platforms/unix/plugins/SocketPlugin/sqUnixSocket.c

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