libfuncs is collection of code (list, queue, circular buffer, io, logging, etc.). https://georgi.unixsol.org/programs/libfuncs/
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.

asyncdns.c 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. /*
  2. * Async DNS resolver
  3. * Copyright (C) 2009-2010 Unix Solutions Ltd.
  4. *
  5. * Released under MIT license.
  6. * See LICENSE-MIT.txt for license terms.
  7. */
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <netdb.h>
  12. #include <unistd.h>
  13. #include <pthread.h>
  14. #include <errno.h>
  15. #include <arpa/inet.h>
  16. #include <sys/socket.h>
  17. #include <netinet/in.h>
  18. #include "log.h"
  19. /* FreeBSD have problems with pathread_cancel so do not use async resolver */
  20. #ifdef __FreeBSD__
  21. int async_resolve_host(char *host, int port, struct sockaddr_in *sockaddr, int msec_timeout, int *active) {
  22. msec_timeout = msec_timeout;
  23. active = active;
  24. struct hostent *hostinfo = gethostbyname(host);
  25. if (hostinfo == NULL) {
  26. int local_h_errno = h_errno;
  27. LOGf("gethostbyname(%s) returned %s", host, hstrerror(local_h_errno));
  28. return 1; // error
  29. }
  30. sockaddr->sin_family = AF_INET;
  31. sockaddr->sin_port = htons(port);
  32. sockaddr->sin_addr = *(struct in_addr *)hostinfo->h_addr;
  33. // LOGf("Not using async resolver! Resolved %s to %s\n", host, inet_ntoa(sockaddr->sin_addr));
  34. return 0;
  35. }
  36. #else
  37. struct url_resolver {
  38. char *host;
  39. int port;
  40. struct sockaddr_in *sockaddr;
  41. int *status;
  42. };
  43. static void resolver_cleanup(void *p) {
  44. if (p)
  45. freeaddrinfo(p);
  46. }
  47. static void *resolver_thread(void *indata) {
  48. struct url_resolver *uri = indata;
  49. *(uri->status) = 0;
  50. char *host = uri->host;
  51. int port = uri->port;
  52. struct sockaddr_in *sockaddr = uri->sockaddr;
  53. int h_err;
  54. struct addrinfo hints, *addrinfo = NULL;
  55. memset(&hints, 0, sizeof hints);
  56. int state;
  57. pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &state);
  58. pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &state);
  59. pthread_cleanup_push(resolver_cleanup, NULL);
  60. hints.ai_family = AF_INET;
  61. hints.ai_socktype = SOCK_STREAM;
  62. h_err = getaddrinfo(host, NULL, &hints, &addrinfo);
  63. pthread_cleanup_pop(0);
  64. if (h_err == 0) {
  65. int num_addrs = 0;
  66. struct addrinfo *p;
  67. for (p=addrinfo; p!=NULL; p=p->ai_next) {
  68. struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
  69. sockaddr->sin_family = AF_INET;
  70. sockaddr->sin_port = htons(port);
  71. sockaddr->sin_addr = ipv4->sin_addr;
  72. char IP[INET_ADDRSTRLEN];
  73. inet_ntop(p->ai_family, &(sockaddr->sin_addr), IP, sizeof IP);
  74. num_addrs++;
  75. // LOGf("Resolved[%d] %s to %s", num_addrs, host, IP);
  76. }
  77. freeaddrinfo(addrinfo);
  78. *(uri->status) = 1;
  79. } else {
  80. *(uri->status) = 2;
  81. }
  82. return NULL;
  83. }
  84. // Returns
  85. // 0 on success
  86. // 1 on error
  87. // 2 on timeout
  88. int async_resolve_host(char *host, int port, struct sockaddr_in *sockaddr, int msec_timeout, int *active) {
  89. pthread_t dns_thread;
  90. struct url_resolver uri;
  91. int status = 0;
  92. uri.host = host;
  93. uri.port = port;
  94. uri.sockaddr = sockaddr;
  95. uri.status = &status;
  96. int lactive = 1;
  97. if (!active)
  98. active = &lactive;
  99. if (pthread_create(&dns_thread, NULL, resolver_thread, &uri)) {
  100. log_perror("Failed to create resolver thread", errno);
  101. return 1;
  102. }
  103. pthread_detach(dns_thread);
  104. #define DNS_SLEEP 20000
  105. long int waitcount = msec_timeout * 1000;
  106. while (!status) {
  107. if (!active) {
  108. // LOG("Client !active, cancel resolver");
  109. pthread_cancel(dns_thread);
  110. return 2;
  111. }
  112. usleep(DNS_SLEEP);
  113. waitcount = waitcount - DNS_SLEEP;
  114. if (waitcount <= 0) {
  115. // LOGf("Timed out resolving: %s", host);
  116. pthread_cancel(dns_thread);
  117. return 2; // Timed out
  118. }
  119. }
  120. if (status == 1)
  121. return 0; // Ok, resolved
  122. return 1; // Error resolving
  123. }
  124. #endif