socket.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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 *) 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. 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. typedef struct {
  87. int len;
  88. int family;
  89. union {
  90. struct sockaddr addr;
  91. struct sockaddr_in ipv4;
  92. #ifdef USE_IPV6
  93. struct sockaddr_in6 ipv6;
  94. #endif
  95. } u;
  96. } sockname_t;
  97. static int socket_name(sockname_t *name, const char *ipaddr, int port)
  98. {
  99. egg_bzero(name, sizeof(*name));
  100. if (inet_pton(AF_INET, ipaddr, &name->u.ipv4.sin_addr) > 0) {
  101. name->len = sizeof(name->u.ipv4);
  102. name->family = PF_INET;
  103. name->u.ipv4.sin_port = htons(port);
  104. name->u.ipv4.sin_family = AF_INET;
  105. return(0);
  106. }
  107. #ifdef USE_IPV6
  108. if (inet_pton(AF_INET6, ipaddr, &name->u.ipv6.sin6_addr) > 0) {
  109. name->len = sizeof(name->u.ipv6);
  110. name->family = PF_INET6;
  111. name->u.ipv6.sin6_port = htons(port);
  112. name->u.ipv6.sin6_family = AF_INET6;
  113. return(0);
  114. }
  115. #endif
  116. /* Invalid name? Then use passive. */
  117. name->len = sizeof(name->u.ipv4);
  118. name->family = PF_INET;
  119. name->u.ipv4.sin_port = htons(port);
  120. name->u.ipv4.sin_family = AF_INET;
  121. return(0);
  122. }
  123. int socket_set_nonblock(int sock, int value)
  124. {
  125. int oldflags = fcntl(sock, F_GETFL, 0);
  126. if (oldflags == -1) return -1;
  127. if (value != 0) oldflags |= O_NONBLOCK;
  128. else oldflags &= ~O_NONBLOCK;
  129. return fcntl(sock, F_SETFL, oldflags);
  130. }
  131. int socket_create(const char *dest_ip, int dest_port, const char *src_ip, int src_port, int flags)
  132. {
  133. char *passive[] = {"::", "0.0.0.0"};
  134. int sock = -1, pfamily, try_ok;
  135. sockname_t dest_name, src_name;
  136. /* If no source ip address is given, try :: and 0.0.0.0 (passive). */
  137. for (try_ok = 0; try_ok < 2; try_ok++) {
  138. /* Resolve the ip addresses. */
  139. socket_name(&dest_name, dest_ip ? dest_ip : passive[try_ok], dest_port);
  140. socket_name(&src_name, src_ip ? src_ip : passive[try_ok], src_port);
  141. if (src_ip || src_port) flags |= SOCKET_BIND;
  142. if (flags & SOCKET_CLIENT) pfamily = dest_name.family;
  143. else if (flags & SOCKET_SERVER) pfamily = src_name.family;
  144. else {
  145. errno = EADDRNOTAVAIL;
  146. return(-1);
  147. }
  148. /* Create the socket. */
  149. if (flags & SOCKET_UDP) sock = socket(pfamily, SOCK_DGRAM, 0);
  150. else sock = socket(pfamily, SOCK_STREAM, 0);
  151. if (sock >= 0) break;
  152. }
  153. if (sock < 0) return(-2);
  154. allocsock(sock, 0);
  155. if (flags & SOCKET_NONBLOCK) socket_set_nonblock(sock, 1);
  156. /* Do the bind if necessary. */
  157. if (flags & (SOCKET_SERVER|SOCKET_BIND)) {
  158. int yes = 1;
  159. setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
  160. if (bind(sock, &src_name.u.addr, src_name.len) != 0) return(-3);
  161. if (flags & SOCKET_SERVER) listen(sock, 50);
  162. }
  163. if (flags & SOCKET_CLIENT) {
  164. for (int i = 0; i < MAXSOCKS; i++) {
  165. if (!(socklist[i].flags & SOCK_UNUSED) && (socklist[i].sock == sock)) {
  166. socklist[i].flags = (socklist[i].flags & ~SOCK_VIRTUAL) | SOCK_CONNECT | SOCK_PASS;
  167. socklist[i].host = strdup(dest_ip);
  168. socklist[i].port = dest_port;
  169. }
  170. }
  171. if (connect(sock, &dest_name.u.addr, dest_name.len) != 0) {
  172. if (errno != EINPROGRESS) return(-4);
  173. }
  174. }
  175. errno = 0;
  176. /* Yay, we're done. */
  177. return(sock);
  178. }
  179. int socket_ip_to_uint(const char *ip, unsigned int *longip)
  180. {
  181. struct in_addr addr;
  182. inet_pton(AF_INET, ip, &addr);
  183. *longip = htonl(addr.s_addr);
  184. return(0);
  185. }
  186. /* Converts shorthand ipv6 notation (123:456::789) into long dotted-decimal
  187. * notation. 'dots' must be 16*4+1 = 65 bytes long. */
  188. int socket_ipv6_to_dots(const char *ip, char *dots)
  189. {
  190. #ifndef USE_IPV6
  191. dots[0] = 0;
  192. return(-1);
  193. #else
  194. struct in6_addr buf;
  195. dots[0] = 0;
  196. if (inet_pton(AF_INET6, ip, &buf) <= 0) return(-1);
  197. sprintf(dots, "%u.%u.%u.%u.%u.%u.%u.%u.%u.%u.%u.%u.%u.%u.%u.%u",
  198. buf.s6_addr[0], buf.s6_addr[1],
  199. buf.s6_addr[2], buf.s6_addr[3],
  200. buf.s6_addr[4], buf.s6_addr[5],
  201. buf.s6_addr[6], buf.s6_addr[7],
  202. buf.s6_addr[8], buf.s6_addr[9],
  203. buf.s6_addr[10], buf.s6_addr[11],
  204. buf.s6_addr[12], buf.s6_addr[13],
  205. buf.s6_addr[14], buf.s6_addr[15]
  206. );
  207. return(0);
  208. #endif
  209. }