socket.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. #include "common.h"
  2. #include "socket.h"
  3. #include "adns.h"
  4. #include "net.h"
  5. #include "egg_timer.h"
  6. #include <fcntl.h>
  7. #include <sys/types.h>
  8. #include <sys/socket.h>
  9. #include <arpa/inet.h>
  10. int is_dotted_ip(const char *ip)
  11. {
  12. char buf[512];
  13. #ifdef USE_IPV6
  14. if (inet_pton(AF_INET6, ip, buf) > 0)
  15. return AF_INET6;
  16. #endif
  17. if (inet_pton(AF_INET, ip, buf) > 0)
  18. return AF_INET;
  19. return(0);
  20. }
  21. typedef struct connect_info {
  22. int dns_id;
  23. int timer_id;
  24. int idx;
  25. int port;
  26. } connect_info_t;
  27. /* If a connection times out, due to dns timeout or connect timeout. */
  28. static int egg_connect_timeout(void *client_data)
  29. {
  30. connect_info_t *connect_info = (connect_info_t *) client_data;
  31. int idx, dns_id;
  32. idx = connect_info->idx;
  33. dns_id = connect_info->dns_id;
  34. connect_info->timer_id = -1;
  35. if (dns_id != -1) {
  36. /* dns_cancel will call connect_host_resolved for us, which
  37. * will filter up a "dns failed" error. */
  38. egg_dns_cancel(dns_id, 1);
  39. }
  40. // else {
  41. // detach(client_data, idx);
  42. // sockbuf_on_eof(idx, EGGNET_LEVEL, -1, "Connect timed out");
  43. // }
  44. return(0);
  45. }
  46. static connect_info_t *attach(int idx, const char *host, int port, int timeout)
  47. {
  48. connect_info_t *connect_info = (connect_info_t *) my_calloc(1, sizeof(*connect_info));
  49. connect_info->port = port;
  50. connect_info->idx = idx;
  51. connect_info->dns_id = -1;
  52. connect_info->timer_id = -1;
  53. // sockbuf_attach_filter(connect_info->idx, &net_connect_filter, connect_info);
  54. if (timeout == 0) timeout = resolve_timeout;
  55. if (timeout > 0) {
  56. char buf[128];
  57. egg_timeval_t howlong;
  58. simple_snprintf(buf, sizeof(buf), "idx %d to %s/%d", idx, host, port);
  59. howlong.sec = timeout;
  60. howlong.usec = 0;
  61. connect_info->timer_id = timer_create_complex(&howlong, buf,
  62. (Function) egg_connect_timeout, connect_info, 0);
  63. }
  64. return(connect_info);
  65. }
  66. static int detach(void *client_data, int idx)
  67. {
  68. connect_info_t *connect_info = (connect_info_t *) client_data;
  69. if (connect_info->timer_id != -1) timer_destroy(connect_info->timer_id);
  70. // sockbuf_detach_filter(idx, &net_connect_filter, NULL);
  71. free(connect_info);
  72. return(0);
  73. }
  74. /*
  75. int egg_client(int idx, const char *host, int port, const char *vip, int vport, int timeout)
  76. {
  77. connect_info_t *connect_info;
  78. // If they don't have their own idx (-1), create one.
  79. if (idx < 0) idx = sockbuf_new();
  80. // Resolve the hostname.
  81. connect_info = attach(idx, host, port, timeout);
  82. connect_info->dns_id = egg_dns_lookup(host, -1, connect_host_resolved, connect_info);
  83. return(idx);
  84. }
  85. */
  86. int socket_name(sockname_t *name, const char *ipaddr, int port)
  87. {
  88. egg_bzero(name, sizeof(*name));
  89. if (inet_pton(AF_INET, ipaddr, &name->u.ipv4.sin_addr) > 0) {
  90. name->len = sizeof(name->u.ipv4);
  91. name->family = PF_INET;
  92. name->u.ipv4.sin_port = htons(port);
  93. name->u.ipv4.sin_family = AF_INET;
  94. return(0);
  95. }
  96. #ifdef USE_IPV6
  97. if (inet_pton(AF_INET6, ipaddr, &name->u.ipv6.sin6_addr) > 0) {
  98. name->len = sizeof(name->u.ipv6);
  99. name->family = PF_INET6;
  100. name->u.ipv6.sin6_port = htons(port);
  101. name->u.ipv6.sin6_family = AF_INET6;
  102. return(0);
  103. }
  104. #endif
  105. /* Invalid name? Then use passive. */
  106. name->len = sizeof(name->u.ipv4);
  107. name->family = PF_INET;
  108. name->u.ipv4.sin_port = htons(port);
  109. name->u.ipv4.sin_family = AF_INET;
  110. return(0);
  111. }
  112. int socket_set_nonblock(int sock, int value)
  113. {
  114. int oldflags = fcntl(sock, F_GETFL, 0);
  115. if (oldflags == -1) return -1;
  116. if (value != 0) oldflags |= O_NONBLOCK;
  117. else oldflags &= ~O_NONBLOCK;
  118. return fcntl(sock, F_SETFL, oldflags);
  119. }
  120. int socket_create(const char *dest_ip, int dest_port, const char *src_ip, int src_port, int flags)
  121. {
  122. char *passive[] = {"::", "0.0.0.0"};
  123. int sock = -1, pfamily, try_ok;
  124. sockname_t dest_name, src_name;
  125. /* If no source ip address is given, try :: and 0.0.0.0 (passive). */
  126. for (try_ok = 0; try_ok < 2; try_ok++) {
  127. /* Resolve the ip addresses. */
  128. socket_name(&dest_name, dest_ip ? dest_ip : passive[try_ok], dest_port);
  129. socket_name(&src_name, src_ip ? src_ip : passive[try_ok], src_port);
  130. if (src_ip || src_port) flags |= SOCKET_BIND;
  131. if (flags & SOCKET_CLIENT) pfamily = dest_name.family;
  132. else if (flags & SOCKET_SERVER) pfamily = src_name.family;
  133. else {
  134. errno = EADDRNOTAVAIL;
  135. return(-1);
  136. }
  137. /* Create the socket. */
  138. if (flags & SOCKET_UDP) sock = socket(pfamily, SOCK_DGRAM, 0);
  139. else sock = socket(pfamily, SOCK_STREAM, 0);
  140. if (sock >= 0) break;
  141. }
  142. if (sock < 0) return(-2);
  143. allocsock(sock, 0);
  144. if (flags & SOCKET_NONBLOCK) socket_set_nonblock(sock, 1);
  145. /* Do the bind if necessary. */
  146. if (flags & (SOCKET_SERVER|SOCKET_BIND)) {
  147. int yes = 1;
  148. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
  149. if (bind(sock, &src_name.u.addr, src_name.len) != 0) {
  150. killsock(sock);
  151. return(-3);
  152. }
  153. if (flags & SOCKET_SERVER) listen(sock, 50);
  154. }
  155. if (flags & SOCKET_CLIENT) {
  156. for (int i = 0; i < MAXSOCKS; i++) {
  157. if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock)) {
  158. socklist[i].flags = (socklist[i].flags & ~SOCK_VIRTUAL) | SOCK_CONNECT | SOCK_PASS;
  159. socklist[i].host = strdup(dest_ip);
  160. socklist[i].port = dest_port;
  161. }
  162. }
  163. if (connect(sock, &dest_name.u.addr, dest_name.len) != 0) {
  164. if (errno != EINPROGRESS) {
  165. killsock(sock);
  166. return(-4);
  167. }
  168. }
  169. }
  170. errno = 0;
  171. /* Yay, we're done. */
  172. return(sock);
  173. }
  174. int socket_ip_to_uint(const char *ip, unsigned int *longip)
  175. {
  176. struct in_addr addr;
  177. inet_pton(AF_INET, ip, &addr);
  178. *longip = htonl(addr.s_addr);
  179. return(0);
  180. }
  181. #ifdef USE_IPV6
  182. static char hex_digits[] = {
  183. '0', '1', '2', '3', '4', '5', '6', '7',
  184. '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
  185. };
  186. #endif /* USE_IPV6 */
  187. /* Converts shorthand ipv6 notation (123:456::789) into long dotted-decimal
  188. * notation. 'dots' must be 16*4+1 = 128 bytes long. */
  189. int socket_ipv6_to_dots(const char *ip, char *dots)
  190. {
  191. #ifndef USE_IPV6
  192. dots[0] = 0;
  193. return(-1);
  194. #else
  195. struct in6_addr buf;
  196. char *cp = NULL;
  197. unsigned char *bytes = NULL;
  198. int i = 0;
  199. dots[0] = 0;
  200. if (inet_pton(AF_INET6, ip, &buf) <= 0) return(-1);
  201. /* bind9
  202. from lib/dns/byaddr.c
  203. */
  204. bytes = (unsigned char *) (&buf.s6_addr);
  205. cp = dots;
  206. for (i = 15; i >= 0; i--) {
  207. *cp++ = hex_digits[bytes[i] & 0x0f];
  208. *cp++ = '.';
  209. *cp++ = hex_digits[(bytes[i] >> 4) & 0x0f];
  210. *cp++ = '.';
  211. }
  212. return(0);
  213. #endif
  214. }
  215. int get_addr(const char *ip, my_addr_t *addr)
  216. {
  217. if (inet_pton(AF_INET, ip, &addr->u.addr) > 0) {
  218. addr->family = AF_INET;
  219. return AF_INET;
  220. }
  221. #ifdef USE_IPV6
  222. if (inet_pton(AF_INET6, ip, &addr->u.addr6) > 0) {
  223. addr->family = AF_INET6;
  224. return AF_INET6;
  225. }
  226. #endif /* USE_IPV6 */
  227. return 0;
  228. }