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

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