A tool for adding anime to your anidb list.
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.

274 lines
6.8KB

  1. #include <arpa/inet.h>
  2. #include <sys/socket.h>
  3. #include <sys/time.h>
  4. #include <netdb.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <limits.h>
  8. #include <ctype.h>
  9. #include <assert.h>
  10. #include <unistd.h>
  11. #include <stdbool.h>
  12. #include <errno.h>
  13. #include "net.h"
  14. #include "config.h"
  15. #include "uio.h"
  16. static struct addrinfo net_server;
  17. static bool net_server_set = false;
  18. static bool net_connected = false;
  19. static int net_socket = -1;
  20. static bool net_parse_address(const char* srv, size_t *out_domain_len,
  21. char **out_port_start)
  22. {
  23. char *port_iter;
  24. char *port_start = strchr(srv, ':');
  25. if (!port_start) {
  26. *out_port_start = NULL;
  27. *out_domain_len = strlen(srv);
  28. return true;
  29. }
  30. /* Only one ':' is allowed */
  31. if (strchr(port_start + 1, ':'))
  32. return false;
  33. *out_domain_len = port_start - srv;
  34. /*port = strtol(port_start + 1, &port_end, 10);
  35. if (port_end == port_start || *port_end != '\0' ||
  36. ((port == LONG_MIN || port == LONG_MAX) && errno))
  37. return false;*/
  38. /*if (port <= 0 || port > 65535)
  39. return false;*/
  40. port_iter = port_start + 1;
  41. if (*port_iter == '\0')
  42. return false;
  43. while (*port_iter) {
  44. if (!isdigit(*port_iter))
  45. return false;
  46. port_iter++;
  47. }
  48. *out_port_start = port_start + 1;
  49. return true;
  50. }
  51. static const void *net_get_sockaddr_addr(const struct sockaddr *sa)
  52. {
  53. switch (sa->sa_family) {
  54. case AF_INET:
  55. return &((struct sockaddr_in*)sa)->sin_addr;
  56. case AF_INET6:
  57. return &((struct sockaddr_in6*)sa)->sin6_addr;
  58. default:
  59. uio_error("Sockaddr is not ipv4 or ipv6");
  60. exit(1);
  61. }
  62. }
  63. static bool net_lookup_server(const char *domain, const char *port,
  64. struct addrinfo *out_addr)
  65. {
  66. struct addrinfo hints = {
  67. .ai_family = AF_UNSPEC,
  68. //.ai_family = AF_INET6,
  69. .ai_socktype = SOCK_DGRAM,
  70. .ai_flags = AI_NUMERICSERV | AI_ADDRCONFIG,
  71. //.ai_flags = AI_NUMERICSERV,
  72. }, *res = NULL, *curr_res;
  73. int ret = getaddrinfo(domain, port, &hints, &res);
  74. if (ret != 0) {
  75. uio_error("Cannot get addrinfo from address: '%s:%s' (%s)",
  76. domain, port, gai_strerror(ret));
  77. return false;
  78. }
  79. curr_res = res;
  80. while (curr_res) {
  81. char ip_buffer[INET6_ADDRSTRLEN] = {0};
  82. if (inet_ntop(curr_res->ai_family,
  83. net_get_sockaddr_addr(curr_res->ai_addr),
  84. ip_buffer, sizeof(ip_buffer)))
  85. uio_debug("Lookup addrinfo entry: %s", ip_buffer);
  86. else
  87. uio_debug("Cannot convert binary ip to string: %s",
  88. strerror(errno));
  89. /* For now, always choose the first one */
  90. break;
  91. curr_res = curr_res->ai_next;
  92. }
  93. if (!curr_res) {
  94. uio_error("Cannot select a usable address.");
  95. freeaddrinfo(res);
  96. return false;
  97. }
  98. *out_addr = *curr_res;
  99. out_addr->ai_addr = malloc(sizeof(struct sockaddr));
  100. *out_addr->ai_addr = *curr_res->ai_addr;
  101. out_addr->ai_next = NULL;
  102. out_addr->ai_canonname = NULL;
  103. freeaddrinfo(res);
  104. return true;
  105. }
  106. int net_socket_setup()
  107. {
  108. struct sockaddr l_addr = {0};
  109. socklen_t l_addr_len;
  110. int sock;
  111. uint16_t *port;
  112. enum error err;
  113. if ((err = config_get("port", (void**)&port)) != NOERR) {
  114. uio_error("Cannot get UDP binding port from config (%s)",
  115. error_to_string(err));
  116. return -1;
  117. }
  118. sock = socket(net_server.ai_family, net_server.ai_socktype,
  119. net_server.ai_protocol);
  120. if (sock == -1) {
  121. uio_error("Cannot create new socket: %s", strerror(errno));
  122. return -1;
  123. }
  124. l_addr.sa_family = net_server.ai_family;
  125. if (net_server.ai_family == AF_INET) {
  126. struct sockaddr_in *tmp = (struct sockaddr_in*)&l_addr;
  127. l_addr_len = sizeof(struct sockaddr_in);
  128. tmp->sin_port = htons(*port);
  129. tmp->sin_addr.s_addr = INADDR_ANY;
  130. } else {
  131. struct sockaddr_in6 *tmp = (struct sockaddr_in6*)&l_addr;
  132. l_addr_len = sizeof(struct sockaddr_in6);
  133. tmp->sin6_port = htons(*port);
  134. tmp->sin6_addr = in6addr_any;
  135. }
  136. if (bind(sock, &l_addr, l_addr_len) != 0) {
  137. uio_error("Cannot bind UDP socket to local port: %s", strerror(errno));
  138. close(sock);
  139. return -1;
  140. }
  141. return sock;
  142. }
  143. static enum error net_connect(int sock, struct addrinfo *ai)
  144. {
  145. if (net_connected)
  146. return ERR_NET_CONNECTED;
  147. if (connect(sock, ai->ai_addr, ai->ai_addrlen) != 0) {
  148. uio_error("Cannot connect to the server: %s\n", strerror(errno));
  149. return ERR_NET_CONNECT_FAIL;
  150. }
  151. net_connected = true;
  152. return NOERR;
  153. }
  154. enum error net_init()
  155. {
  156. enum error err;
  157. const char **srv = NULL;
  158. char *port_start = NULL;
  159. size_t domain_len;
  160. int sock;
  161. err = config_get("api-server", (void**)&srv);
  162. if (err != NOERR) {
  163. uio_error("Cannot get the api servers address (%s).", error_to_string(err));
  164. return ERR_NET_APIADDR;
  165. }
  166. if (!net_parse_address(*srv, &domain_len, &port_start)) {
  167. uio_error("Cannot parse the api server address: '%s'.", *srv);
  168. return ERR_NET_APIADDR;
  169. }
  170. /* Port will be set to NULL, if its not in the address */
  171. if (port_start == NULL)
  172. port_start = "9000";
  173. char api_domain[domain_len + 1];
  174. memcpy(api_domain, *srv, domain_len);
  175. api_domain[domain_len] = '\0';
  176. if (!net_lookup_server(api_domain, port_start, &net_server)) {
  177. //uio_error("Cannot look up the api server address");
  178. return ERR_NET_APIADDR;
  179. }
  180. net_server_set = true;
  181. sock = net_socket_setup();
  182. if (sock == -1) {
  183. return ERR_NET_SOCKET;
  184. }
  185. err = net_connect(sock, &net_server);
  186. if (err != NOERR) {
  187. net_free();
  188. return err;
  189. }
  190. net_socket = sock;
  191. return NOERR;
  192. }
  193. void net_free()
  194. {
  195. if (net_server_set) {
  196. free(net_server.ai_addr);
  197. memset(&net_server, 0, sizeof(net_server));
  198. net_server_set = false;
  199. }
  200. if (net_socket != -1) {
  201. if (net_connected)
  202. shutdown(net_socket, SHUT_RDWR);
  203. close(net_socket);
  204. net_socket = -1;
  205. }
  206. net_connected = false;
  207. }
  208. ssize_t net_send(const void *msg, size_t msg_len)
  209. {
  210. ssize_t w_len = send(net_socket, msg, msg_len, 0);
  211. if (w_len == -1) {
  212. int en = errno;
  213. uio_error("{net} Send failed: %s", strerror(en));
  214. if (en == EINTR)
  215. return -2;
  216. return -1;
  217. }
  218. return w_len;
  219. }
  220. ssize_t net_read(void* out_data, size_t read_size)
  221. {
  222. ssize_t read = recv(net_socket, out_data, read_size, 0);
  223. if (read == -1) {
  224. int en = errno;
  225. uio_error("{net} Read failed: %s", strerror(errno));
  226. return -en;
  227. }
  228. if (read == read_size)
  229. uio_warning("{net} Data may have been discarded!");
  230. return read;
  231. }