You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

netlib.c 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * This file is Copyright (c) 2010-2018 by the GPSD project
  3. * SPDX-License-Identifier: BSD-2-clause
  4. */
  5. #include "gpsd_config.h" /* must be before all includes */
  6. #include <string.h>
  7. #include <fcntl.h>
  8. #ifdef HAVE_NETDB_H
  9. #include <netdb.h>
  10. #endif /* HAVE_NETDB_H */
  11. #ifndef AF_UNSPEC
  12. #include <sys/types.h>
  13. #include <sys/stat.h>
  14. #ifdef HAVE_SYS_SOCKET_H
  15. #include <sys/socket.h>
  16. #endif /* HAVE_SYS_SOCKET_H */
  17. #endif /* AF_UNSPEC */
  18. #ifdef HAVE_SYS_UN_H
  19. #include <sys/un.h>
  20. #endif /* HAVE_SYS_UN_H */
  21. #ifndef INADDR_ANY
  22. #ifdef HAVE_NETINET_IN_H
  23. #include <netinet/in.h>
  24. #endif /* HAVE_NETINET_IN_H */
  25. #endif /* INADDR_ANY */
  26. #ifdef HAVE_ARPA_INET_H
  27. #include <arpa/inet.h> /* for htons() and friends */
  28. #endif /* HAVE_ARPA_INET_H */
  29. #include <unistd.h>
  30. #ifdef HAVE_NETINET_IN_H
  31. #include <netinet/ip.h>
  32. #endif /* HAVE_NETINET_IN_H */
  33. #ifdef HAVE_WINSOCK2_H
  34. #include <winsock2.h>
  35. #include <ws2tcpip.h>
  36. #endif
  37. #include "gpsd.h"
  38. #include "sockaddr.h"
  39. /* work around the unfinished ipv6 implementation on hurd and OSX <10.6 */
  40. #ifndef IPV6_TCLASS
  41. # if defined(__GNU__)
  42. # define IPV6_TCLASS 61
  43. # elif defined(__APPLE__)
  44. # define IPV6_TCLASS 36
  45. # endif
  46. #endif
  47. socket_t netlib_connectsock(int af, const char *host, const char *service,
  48. const char *protocol)
  49. {
  50. struct protoent *ppe;
  51. struct addrinfo hints;
  52. struct addrinfo *result, *rp;
  53. int ret, type, proto, one = 1;
  54. socket_t s;
  55. bool bind_me;
  56. INVALIDATE_SOCKET(s);
  57. ppe = getprotobyname(protocol);
  58. if (strcmp(protocol, "udp") == 0) {
  59. type = SOCK_DGRAM;
  60. proto = (ppe) ? ppe->p_proto : IPPROTO_UDP;
  61. } else {
  62. type = SOCK_STREAM;
  63. proto = (ppe) ? ppe->p_proto : IPPROTO_TCP;
  64. }
  65. /* we probably ought to pass this in as an explicit flag argument */
  66. bind_me = (type == SOCK_DGRAM);
  67. memset(&hints, 0, sizeof(struct addrinfo));
  68. hints.ai_family = af;
  69. hints.ai_socktype = type;
  70. hints.ai_protocol = proto;
  71. if (bind_me)
  72. hints.ai_flags = AI_PASSIVE;
  73. if ((ret = getaddrinfo(host, service, &hints, &result))) {
  74. return NL_NOHOST;
  75. }
  76. /*
  77. * From getaddrinfo(3):
  78. * Normally, the application should try using the addresses in the
  79. * order in which they are returned. The sorting function used within
  80. * getaddrinfo() is defined in RFC 3484).
  81. * From RFC 3484 (Section 10.3):
  82. * The default policy table gives IPv6 addresses higher precedence than
  83. * IPv4 addresses.
  84. * Thus, with the default parameters, we get IPv6 addresses first.
  85. */
  86. for (rp = result; rp != NULL; rp = rp->ai_next) {
  87. ret = NL_NOCONNECT;
  88. if ((s = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0)
  89. ret = NL_NOSOCK;
  90. else if (setsockopt
  91. (s, SOL_SOCKET, SO_REUSEADDR, (char *)&one,
  92. sizeof(one)) == -1) {
  93. ret = NL_NOSOCKOPT;
  94. } else {
  95. if (bind_me) {
  96. if (bind(s, rp->ai_addr, rp->ai_addrlen) == 0) {
  97. ret = 0;
  98. break;
  99. }
  100. } else {
  101. if (connect(s, rp->ai_addr, rp->ai_addrlen) == 0) {
  102. ret = 0;
  103. break;
  104. }
  105. }
  106. }
  107. if (!BAD_SOCKET(s)) {
  108. #ifdef HAVE_WINSOCK2_H
  109. (void)closesocket(s);
  110. #else
  111. (void)close(s);
  112. #endif
  113. }
  114. }
  115. freeaddrinfo(result);
  116. if (ret != 0 || BAD_SOCKET(s))
  117. return ret;
  118. #ifdef IPTOS_LOWDELAY
  119. {
  120. int opt = IPTOS_LOWDELAY;
  121. (void)setsockopt(s, IPPROTO_IP, IP_TOS, &opt, sizeof(opt));
  122. #ifdef IPV6_TCLASS
  123. (void)setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt));
  124. #endif
  125. }
  126. #endif
  127. #ifdef TCP_NODELAY
  128. /*
  129. * This is a good performance enhancement when the socket is going to
  130. * be used to pass a lot of short commands. It prevents them from being
  131. * delayed by the Nagle algorithm until they can be aggreagated into
  132. * a large packet. See https://en.wikipedia.org/wiki/Nagle%27s_algorithm
  133. * for discussion.
  134. */
  135. if (type == SOCK_STREAM)
  136. setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one));
  137. #endif
  138. /* set socket to noblocking */
  139. #ifdef HAVE_FCNTL
  140. (void)fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
  141. #elif defined(HAVE_WINSOCK2_H)
  142. u_long one1 = 1;
  143. (void)ioctlsocket(s, FIONBIO, &one1);
  144. #endif
  145. return s;
  146. }
  147. const char *netlib_errstr(const int err)
  148. {
  149. switch (err) {
  150. case NL_NOSERVICE:
  151. return "can't get service entry";
  152. case NL_NOHOST:
  153. return "can't get host entry";
  154. case NL_NOPROTO:
  155. return "can't get protocol entry";
  156. case NL_NOSOCK:
  157. return "can't create socket";
  158. case NL_NOSOCKOPT:
  159. return "error SETSOCKOPT SO_REUSEADDR";
  160. case NL_NOCONNECT:
  161. return "can't connect to host/port pair";
  162. default:
  163. return "unknown error";
  164. }
  165. }
  166. socket_t netlib_localsocket(const char *sockfile, int socktype)
  167. /* acquire a connection to an existing Unix-domain socket */
  168. {
  169. #ifdef HAVE_SYS_UN_H
  170. int sock;
  171. if ((sock = socket(AF_UNIX, socktype, 0)) < 0) {
  172. return -1;
  173. } else {
  174. struct sockaddr_un saddr;
  175. memset(&saddr, 0, sizeof(struct sockaddr_un));
  176. saddr.sun_family = AF_UNIX;
  177. (void)strlcpy(saddr.sun_path,
  178. sockfile,
  179. sizeof(saddr.sun_path));
  180. if (connect(sock, (struct sockaddr *)&saddr, SUN_LEN(&saddr)) < 0) {
  181. (void)close(sock);
  182. return -2;
  183. }
  184. return sock;
  185. }
  186. #else
  187. return -1;
  188. #endif /* HAVE_SYS_UN_H */
  189. }
  190. char *netlib_sock2ip(socket_t fd)
  191. /* retrieve the IP address corresponding to a socket */
  192. {
  193. static char ip[INET6_ADDRSTRLEN];
  194. #ifdef HAVE_INET_NTOP
  195. int r;
  196. sockaddr_t fsin;
  197. socklen_t alen = (socklen_t) sizeof(fsin);
  198. r = getpeername(fd, &(fsin.sa), &alen);
  199. if (r == 0) {
  200. switch (fsin.sa.sa_family) {
  201. case AF_INET:
  202. r = !inet_ntop(fsin.sa_in.sin_family, &(fsin.sa_in.sin_addr),
  203. ip, sizeof(ip));
  204. break;
  205. case AF_INET6:
  206. r = !inet_ntop((int)fsin.sa_in6.sin6_family,
  207. &(fsin.sa_in6.sin6_addr), ip, sizeof(ip));
  208. break;
  209. default:
  210. (void)strlcpy(ip, "<unknown AF>", sizeof(ip));
  211. return ip;
  212. }
  213. }
  214. /* Ugh... */
  215. if (r != 0)
  216. #endif /* HAVE_INET_NTOP */
  217. (void)strlcpy(ip, "<unknown>", sizeof(ip));
  218. return ip;
  219. }