A tool for adding anime to your anidb list.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

274 lignes
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. }