PageRenderTime 79ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/libgst/sockets.c

https://github.com/stefanizota/smalltalk
C | 549 lines | 397 code | 75 blank | 77 comment | 60 complexity | 382405a8e07866f60e65924a931f60bb MD5 | raw file
  1. /***********************************************************************
  2. *
  3. * C interface to BSD sockets.
  4. *
  5. *
  6. ***********************************************************************/
  7. /***********************************************************************
  8. *
  9. * Copyright 1988,89,90,91,92,94,95,99,2000,2001,2002,2006,2007,2008,2009
  10. * Free Software Foundation, Inc.
  11. * Written by Steve Byrne and Paolo Bonzini.
  12. *
  13. * This file is part of GNU Smalltalk.
  14. *
  15. * GNU Smalltalk is free software; you can redistribute it and/or modify it
  16. * under the terms of the GNU General Public License as published by the Free
  17. * Software Foundation; either version 2, or (at your option) any later
  18. * version.
  19. *
  20. * Linking GNU Smalltalk statically or dynamically with other modules is
  21. * making a combined work based on GNU Smalltalk. Thus, the terms and
  22. * conditions of the GNU General Public License cover the whole
  23. * combination.
  24. *
  25. * In addition, as a special exception, the Free Software Foundation
  26. * give you permission to combine GNU Smalltalk with free software
  27. * programs or libraries that are released under the GNU LGPL and with
  28. * independent programs running under the GNU Smalltalk virtual machine.
  29. *
  30. * You may copy and distribute such a system following the terms of the
  31. * GNU GPL for GNU Smalltalk and the licenses of the other code
  32. * concerned, provided that you include the source code of that other
  33. * code when and as the GNU GPL requires distribution of source code.
  34. *
  35. * Note that people who make modified versions of GNU Smalltalk are not
  36. * obligated to grant this special exception for their modified
  37. * versions; it is their choice whether to do so. The GNU General
  38. * Public License gives permission to release a modified version without
  39. * this exception; this exception also makes it possible to release a
  40. * modified version which carries forward this exception.
  41. *
  42. * GNU Smalltalk is distributed in the hope that it will be useful, but WITHOUT
  43. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  44. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  45. * more details.
  46. *
  47. * You should have received a copy of the GNU General Public License along with
  48. * GNU Smalltalk; see the file COPYING. If not, write to the Free Software
  49. * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  50. *
  51. ***********************************************************************/
  52. #include "gstpriv.h"
  53. #include <signal.h>
  54. #include <fcntl.h>
  55. #include <errno.h>
  56. #ifdef HAVE_UNISTD_H
  57. #include <unistd.h>
  58. #endif
  59. #if __STDC__
  60. #include <string.h>
  61. #include <stdlib.h>
  62. #endif /* STDC_HEADERS */
  63. #include <stdio.h>
  64. #include <errno.h>
  65. #ifdef HAVE_SYS_UTSNAME_H
  66. #include <sys/utsname.h>
  67. #endif
  68. #ifdef HAVE_SOCKETS
  69. #ifndef ntohl
  70. #if WORDS_BIGENDIAN
  71. #define ntohl(x) (x)
  72. #define ntohs(x) (x)
  73. #else
  74. #define ntohl(x) \
  75. ((unsigned long int)((((unsigned long int)(x) & 0x000000ffU) << 24) | \
  76. (((unsigned long int)(x) & 0x0000ff00U) << 8) | \
  77. (((unsigned long int)(x) & 0x00ff0000U) >> 8) | \
  78. (((unsigned long int)(x) & 0xff000000U) >> 24)))
  79. #define ntohs(x) \
  80. ((unsigned short int)((((unsigned short int)(x) & 0x00ff) << 8) | \
  81. (((unsigned short int)(x) & 0xff00) >> 8)))
  82. #endif
  83. #endif /* ntohl */
  84. static char *
  85. myGetHostByAddr (char *addr, int len, int type)
  86. {
  87. struct hostent *hostEnt;
  88. char *result;
  89. #if HAVE_GETIPNODEBYADDR
  90. int error;
  91. hostEnt = getipnodebyaddr (addr, len, type, &error);
  92. #else
  93. hostEnt = gethostbyaddr (addr, len, type);
  94. #endif
  95. if (hostEnt)
  96. {
  97. result = malloc (128); /* out of a hat */
  98. strncpy (result, hostEnt->h_name, 128);
  99. #if HAVE_GETIPNODEBYADDR
  100. freehostent (hostEnt);
  101. #endif
  102. }
  103. else
  104. result = NULL;
  105. return (result);
  106. }
  107. /* The offsets of these two fields are not portable. */
  108. static char **
  109. get_aiCanonname (struct addrinfo *ai)
  110. {
  111. return &ai->ai_canonname;
  112. }
  113. static struct sockaddr **
  114. get_aiAddr (struct addrinfo *ai)
  115. {
  116. return &ai->ai_addr;
  117. }
  118. static char *
  119. myGetHostName (void)
  120. {
  121. char *result;
  122. result = malloc (128);
  123. #ifdef HAVE_UNAME
  124. {
  125. struct utsname utsname;
  126. int ret;
  127. ret = uname (&utsname);
  128. if (ret < 0)
  129. return NULL;
  130. strncpy (result, utsname.nodename, 128);
  131. result[127] = '\0';
  132. }
  133. #else
  134. #ifdef HAVE_GETHOSTNAME
  135. {
  136. extern int gethostname ();
  137. gethostname (result, 128);
  138. }
  139. #else
  140. strcpy (result, "localhost"); /* terrible guess */
  141. #endif
  142. #endif
  143. return (result);
  144. }
  145. #define constantFunction(name, constant) \
  146. static long name(void) { return (constant); }
  147. constantFunction (afUnspec, AF_UNSPEC);
  148. constantFunction (afInet, AF_INET);
  149. constantFunction (afUnix, AF_UNIX);
  150. constantFunction (pfUnspec, PF_UNSPEC);
  151. constantFunction (pfInet, PF_INET);
  152. constantFunction (pfUnix, PF_UNIX);
  153. constantFunction (msgOOB, MSG_OOB);
  154. constantFunction (msgPeek, MSG_PEEK);
  155. constantFunction (solSocket, SOL_SOCKET);
  156. constantFunction (soLinger, SO_LINGER);
  157. constantFunction (soReuseAddr, SO_REUSEADDR);
  158. constantFunction (sockStream, SOCK_STREAM);
  159. constantFunction (sockRaw, SOCK_RAW);
  160. constantFunction (sockRDM, SOCK_RDM);
  161. constantFunction (sockDgram, SOCK_DGRAM);
  162. constantFunction (ipprotoIcmp, IPPROTO_ICMP);
  163. constantFunction (ipprotoUdp, IPPROTO_UDP);
  164. constantFunction (ipprotoTcp, IPPROTO_TCP);
  165. constantFunction (ipprotoIp, IPPROTO_IP);
  166. constantFunction (tcpNodelay, TCP_NODELAY);
  167. #ifdef HAVE_IPV6
  168. constantFunction (afInet6, AF_INET6);
  169. constantFunction (pfInet6, PF_INET6);
  170. constantFunction (ipprotoIcmpv6, IPPROTO_ICMPV6);
  171. #else
  172. constantFunction (afInet6, -1);
  173. constantFunction (pfInet6, -1);
  174. constantFunction (ipprotoIcmpv6, -1);
  175. #endif
  176. #ifdef IP_MULTICAST_TTL
  177. constantFunction (ipMulticastTtl, IP_MULTICAST_TTL);
  178. constantFunction (ipMulticastIf, IP_MULTICAST_IF);
  179. constantFunction (ipAddMembership, IP_ADD_MEMBERSHIP);
  180. constantFunction (ipDropMembership, IP_DROP_MEMBERSHIP);
  181. #else
  182. constantFunction (ipMulticastTtl, -1);
  183. constantFunction (ipMulticastIf, -1);
  184. constantFunction (ipAddMembership, -1);
  185. constantFunction (ipDropMembership, -1);
  186. #endif
  187. #ifndef AI_ADDRCONFIG
  188. #define AI_ADDRCONFIG 0
  189. #endif
  190. #ifndef AI_ALL
  191. #define AI_ALL 0
  192. #endif
  193. #ifndef AI_V4MAPPED
  194. #define AI_V4MAPPED 0
  195. #endif
  196. constantFunction (aiAddrconfig, AI_ADDRCONFIG)
  197. constantFunction (aiCanonname, AI_CANONNAME)
  198. constantFunction (aiAll, AI_ALL)
  199. constantFunction (aiV4mapped, AI_V4MAPPED)
  200. #if defined SOCK_CLOEXEC && !defined __MSVCRT__
  201. /* 0 = unknown, 1 = yes, -1 = no. */
  202. static mst_Boolean have_sock_cloexec;
  203. /* Return 0 if the operation failed and an error can be returned
  204. by the caller. */
  205. static inline int
  206. check_have_sock_cloexec (int fh, int expected_errno)
  207. {
  208. if (have_sock_cloexec == 0 && (fh >= 0 || errno == expected_errno))
  209. have_sock_cloexec = (fh >= 0 ? 1 : -1);
  210. return (have_sock_cloexec != 0);
  211. }
  212. #endif
  213. static void
  214. socket_set_cloexec (SOCKET fh)
  215. {
  216. if (fh == SOCKET_ERROR)
  217. return;
  218. #if defined __MSVCRT__
  219. /* Do not do FD_CLOEXEC under MinGW. */
  220. SetHandleInformation ((HANDLE) fh, HANDLE_FLAG_INHERIT, 0);
  221. #else
  222. fcntl (fh, F_SETFD, fcntl (fh, F_GETFD, 0) | FD_CLOEXEC);
  223. #endif
  224. }
  225. static int
  226. mySocket (int domain, int type, int protocol)
  227. {
  228. SOCKET fh = SOCKET_ERROR;
  229. int fd;
  230. #if defined SOCK_CLOEXEC && !defined __MSVCRT__
  231. if (have_sock_cloexec >= 0)
  232. {
  233. fh = socket (domain, type | SOCK_CLOEXEC, protocol);
  234. if (!check_have_sock_cloexec (fh, EINVAL))
  235. return -1;
  236. }
  237. #endif
  238. if (fh == SOCKET_ERROR)
  239. {
  240. fh = socket (domain, type, protocol);
  241. socket_set_cloexec (fh);
  242. }
  243. fd = (fh == SOCKET_ERROR ? -1 : SOCKET_TO_FD (fh));
  244. if (fd != SOCKET_ERROR)
  245. _gst_register_socket (fd, false);
  246. return fd;
  247. }
  248. /* BSD systems have sa_len, others have not. Smalltalk will always
  249. write sockaddr structs as if they had it. So for Linux and Winsock
  250. we read the second byte (sa_family on BSD systems) and write it in the
  251. entire sa_family field. */
  252. static inline void
  253. fix_sockaddr (struct sockaddr *sockaddr, socklen_t len)
  254. {
  255. #ifndef HAVE_STRUCT_SOCKADDR_SA_LEN
  256. /* Make sure sa_family is a short. */
  257. char verify[sizeof (sockaddr->sa_family) == 2 ? 1 : -1];
  258. if (len >= 2)
  259. sockaddr->sa_family = ((unsigned char *) sockaddr)[1];
  260. #endif
  261. }
  262. /* Same as connect, but forces the socket to be in non-blocking mode */
  263. static int
  264. myConnect (int fd, struct sockaddr *sockaddr, int len)
  265. {
  266. SOCKET sock = FD_TO_SOCKET (fd);
  267. int rc;
  268. #ifdef __MSVCRT__
  269. unsigned long iMode = 1;
  270. ioctlsocket (sock, FIONBIO, &iMode);
  271. #elif defined F_GETFL
  272. #ifndef O_NONBLOCK
  273. #warning Non-blocking I/O could not be enabled
  274. #else
  275. int oldflags = fcntl (sock, F_GETFL, NULL);
  276. if (!(oldflags & O_NONBLOCK))
  277. fcntl (sock, F_SETFL, oldflags | O_NONBLOCK);
  278. #endif
  279. #endif
  280. fix_sockaddr (sockaddr, len);
  281. rc = connect (sock, sockaddr, len);
  282. if (rc == 0 || is_socket_error (EINPROGRESS) || is_socket_error (EWOULDBLOCK))
  283. return 0;
  284. else
  285. return -1;
  286. }
  287. static int
  288. myAccept (int fd, struct sockaddr *addr, socklen_t *addrlen)
  289. {
  290. SOCKET fh = SOCKET_ERROR;
  291. int new_fd;
  292. /* Parameters to system calls are not guaranteed to generate a SIGSEGV
  293. and for this reason we must touch them manually. */
  294. _gst_grey_oop_range (addr, *addrlen);
  295. #if defined SOCK_CLOEXEC && defined HAVE_ACCEPT4 && !defined __MSVCRT__
  296. if (have_sock_cloexec >= 0)
  297. {
  298. fh = accept4 (FD_TO_SOCKET (fd), addr, addrlen, SOCK_CLOEXEC);
  299. if (!check_have_sock_cloexec (fh, ENOSYS))
  300. return -1;
  301. }
  302. #endif
  303. if (fh == SOCKET_ERROR)
  304. {
  305. fh = accept (FD_TO_SOCKET (fd), addr, addrlen);
  306. socket_set_cloexec (fh);
  307. }
  308. new_fd = (fh == SOCKET_ERROR ? -1 : SOCKET_TO_FD (fh));
  309. if (new_fd != SOCKET_ERROR)
  310. _gst_register_socket (new_fd, false);
  311. return new_fd;
  312. }
  313. static int
  314. myBind (int fd, struct sockaddr *addr, socklen_t addrlen)
  315. {
  316. fix_sockaddr (addr, addrlen);
  317. return bind (FD_TO_SOCKET (fd), addr, addrlen);
  318. }
  319. static int
  320. myGetpeername (int fd, struct sockaddr *addr, socklen_t *addrlen)
  321. {
  322. /* Parameters to system calls are not guaranteed to generate a SIGSEGV
  323. and for this reason we must touch them manually. */
  324. _gst_grey_oop_range (addr, *addrlen);
  325. return getpeername (FD_TO_SOCKET (fd), addr, addrlen);
  326. }
  327. static int
  328. myGetsockname (int fd, struct sockaddr *addr, socklen_t *addrlen)
  329. {
  330. /* Parameters to system calls are not guaranteed to generate a SIGSEGV
  331. and for this reason we must touch them manually. */
  332. _gst_grey_oop_range (addr, *addrlen);
  333. return getsockname (FD_TO_SOCKET (fd), addr, addrlen);
  334. }
  335. static int
  336. myGetsockopt (int fd, int level, int optname, char *optval, socklen_t *optlen)
  337. {
  338. /* Parameters to system calls are not guaranteed to generate a SIGSEGV
  339. and for this reason we must touch them manually. */
  340. _gst_grey_oop_range (optval, *optlen);
  341. return getsockopt (FD_TO_SOCKET (fd), level, optname, optval, optlen);
  342. }
  343. static int
  344. myListen (int fd, int backlog)
  345. {
  346. int r = listen (FD_TO_SOCKET (fd), backlog);
  347. if (r != SOCKET_ERROR)
  348. _gst_register_socket (fd, true);
  349. return r;
  350. }
  351. static int
  352. myRecvfrom (int fd, char *buf, int len, int flags, struct sockaddr *from,
  353. socklen_t *fromlen)
  354. {
  355. int frombufsize = *fromlen;
  356. int r;
  357. /* Parameters to system calls are not guaranteed to generate a SIGSEGV
  358. and for this reason we must touch them manually. */
  359. _gst_grey_oop_range (buf, len);
  360. _gst_grey_oop_range (from, *fromlen);
  361. r = recvfrom (FD_TO_SOCKET (fd), buf, len, flags, from, fromlen);
  362. /* Winsock recvfrom() only returns a valid 'from' when the socket is
  363. connectionless. POSIX gives a valid 'from' for all types of sockets. */
  364. if (r != SOCKET_ERROR && frombufsize == *fromlen)
  365. (void) myGetpeername (fd, from, fromlen);
  366. return r;
  367. }
  368. static int
  369. mySendto (int fd, const char *buf, int len, int flags,
  370. struct sockaddr *to, int tolen)
  371. {
  372. fix_sockaddr (to, tolen);
  373. return sendto (FD_TO_SOCKET (fd), buf, len, flags, to, tolen);
  374. }
  375. static int
  376. mySetsockopt (int fd, int level, int optname, const char *optval, int optlen)
  377. {
  378. return setsockopt (FD_TO_SOCKET (fd), level, optname, optval, optlen);
  379. }
  380. static int
  381. getSoError (int fd)
  382. {
  383. int error;
  384. socklen_t size = sizeof (error);
  385. if ((error = _gst_get_fd_error (fd)) != 0)
  386. ;
  387. else if (myGetsockopt (fd, SOL_SOCKET, SO_ERROR, (char *)&error, &size) == -1)
  388. {
  389. #if defined _WIN32 && !defined __CYGWIN__
  390. error = WSAGetLastError ();
  391. #else
  392. error = errno;
  393. #endif
  394. }
  395. /* When we get one of these, we don't return an error. However,
  396. the primitive still fails and the file/socket is closed by the
  397. Smalltalk code. */
  398. if (error == ESHUTDOWN || error == ECONNRESET
  399. || error == ECONNABORTED || error == ENETRESET
  400. || error == EPIPE)
  401. return 0;
  402. else
  403. return error;
  404. }
  405. void
  406. _gst_init_sockets ()
  407. {
  408. #if defined WIN32 && !defined __CYGWIN__
  409. WSADATA wsaData;
  410. int iRet;
  411. iRet = WSAStartup(MAKEWORD(2,2), &wsaData);
  412. if (iRet != 0) {
  413. printf("WSAStartup failed (looking for Winsock 2.2): %d\n", iRet);
  414. return;
  415. }
  416. #endif /* _WIN32 */
  417. _gst_define_cfunc ("TCPgetaddrinfo", getaddrinfo);
  418. _gst_define_cfunc ("TCPfreeaddrinfo", freeaddrinfo);
  419. _gst_define_cfunc ("TCPgetHostByAddr", myGetHostByAddr);
  420. _gst_define_cfunc ("TCPgetLocalName", myGetHostName);
  421. _gst_define_cfunc ("TCPgetAiCanonname", get_aiCanonname);
  422. _gst_define_cfunc ("TCPgetAiAddr", get_aiAddr);
  423. _gst_define_cfunc ("TCPaccept", myAccept);
  424. _gst_define_cfunc ("TCPbind", myBind);
  425. _gst_define_cfunc ("TCPconnect", myConnect);
  426. _gst_define_cfunc ("TCPgetpeername", myGetpeername);
  427. _gst_define_cfunc ("TCPgetsockname", myGetsockname);
  428. _gst_define_cfunc ("TCPlisten", myListen);
  429. _gst_define_cfunc ("TCPrecvfrom", myRecvfrom);
  430. _gst_define_cfunc ("TCPsendto", mySendto);
  431. _gst_define_cfunc ("TCPsetsockopt", mySetsockopt);
  432. _gst_define_cfunc ("TCPgetsockopt", myGetsockopt);
  433. _gst_define_cfunc ("TCPgetSoError", getSoError);
  434. _gst_define_cfunc ("TCPsocket", mySocket);
  435. _gst_define_cfunc ("TCPpfUnspec", pfUnspec);
  436. _gst_define_cfunc ("TCPpfInet", pfInet);
  437. _gst_define_cfunc ("TCPpfInet6", pfInet6);
  438. _gst_define_cfunc ("TCPpfUnix", pfUnix);
  439. _gst_define_cfunc ("TCPafUnspec", afUnspec);
  440. _gst_define_cfunc ("TCPafInet", afInet);
  441. _gst_define_cfunc ("TCPafInet6", afInet6);
  442. _gst_define_cfunc ("TCPafUnix", afUnix);
  443. _gst_define_cfunc ("TCPipMulticastTtl", ipMulticastTtl);
  444. _gst_define_cfunc ("TCPipMulticastIf", ipMulticastIf);
  445. _gst_define_cfunc ("TCPipAddMembership", ipAddMembership);
  446. _gst_define_cfunc ("TCPipDropMembership", ipDropMembership);
  447. _gst_define_cfunc ("TCPtcpNodelay", tcpNodelay);
  448. _gst_define_cfunc ("TCPmsgPeek", msgPeek);
  449. _gst_define_cfunc ("TCPmsgOOB", msgOOB);
  450. _gst_define_cfunc ("TCPsolSocket", solSocket);
  451. _gst_define_cfunc ("TCPsoLinger", soLinger);
  452. _gst_define_cfunc ("TCPsoReuseAddr", soReuseAddr);
  453. _gst_define_cfunc ("TCPsockStream", sockStream);
  454. _gst_define_cfunc ("TCPsockRaw", sockRaw);
  455. _gst_define_cfunc ("TCPsockRDM", sockRDM);
  456. _gst_define_cfunc ("TCPsockDgram", sockDgram);
  457. _gst_define_cfunc ("TCPipprotoIp", ipprotoIp);
  458. _gst_define_cfunc ("TCPipprotoTcp", ipprotoTcp);
  459. _gst_define_cfunc ("TCPipprotoUdp", ipprotoUdp);
  460. _gst_define_cfunc ("TCPipprotoIcmp", ipprotoIcmp);
  461. _gst_define_cfunc ("TCPipprotoIcmpv6", ipprotoIcmpv6);
  462. _gst_define_cfunc ("TCPaiAddrconfig", aiAddrconfig);
  463. _gst_define_cfunc ("TCPaiCanonname", aiCanonname);
  464. _gst_define_cfunc ("TCPaiAll", aiAll);
  465. _gst_define_cfunc ("TCPaiV4mapped", aiV4mapped);
  466. }
  467. #else /* !HAVE_SOCKETS */
  468. void
  469. _gst_init_sockets ()
  470. {
  471. }
  472. #endif