QNGetAddrInfo.m 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. //
  2. // QNGetAddrInfo.c
  3. // HappyDNS
  4. //
  5. // Created by bailong on 16/7/19.
  6. // Copyright © 2016年 Qiniu Cloud Storage. All rights reserved.
  7. //
  8. #include <arpa/inet.h>
  9. #include <netdb.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include "QNGetAddrInfo.h"
  13. //fast judge domain or ip, not verify ip right.
  14. static int isIp(const char* domain) {
  15. size_t l = strlen(domain);
  16. if (l > 15 || l < 7) {
  17. return 0;
  18. }
  19. for (const char* p = domain; p < domain + l; p++) {
  20. if ((*p < '0' || *p > '9') && *p != '.') {
  21. return 0;
  22. }
  23. }
  24. return 1;
  25. }
  26. static struct addrinfo* addrinfo_clone(struct addrinfo* addr) {
  27. struct addrinfo* ai;
  28. ai = (struct addrinfo*)calloc(sizeof(struct addrinfo) + addr->ai_addrlen, 1);
  29. if (ai) {
  30. memcpy(ai, addr, sizeof(struct addrinfo));
  31. ai->ai_addr = (struct sockaddr*)(ai + 1);
  32. memcpy(ai->ai_addr, addr->ai_addr, addr->ai_addrlen);
  33. if (addr->ai_canonname) {
  34. ai->ai_canonname = strdup(addr->ai_canonname);
  35. }
  36. ai->ai_next = NULL;
  37. }
  38. return ai;
  39. }
  40. static void append_addrinfo(struct addrinfo** head, struct addrinfo* addr) {
  41. if (*head == NULL) {
  42. *head = addr;
  43. return;
  44. }
  45. struct addrinfo* ai = *head;
  46. while (ai->ai_next != NULL) {
  47. ai = ai->ai_next;
  48. }
  49. ai->ai_next = addr;
  50. }
  51. void qn_free_ips_ret(qn_ips_ret* ip_list) {
  52. if (ip_list == NULL) {
  53. return;
  54. }
  55. char** p = ip_list->ips;
  56. while (*p != NULL) {
  57. free(*p);
  58. p++;
  59. }
  60. free(ip_list);
  61. }
  62. static qn_dns_callback dns_callback = NULL;
  63. int qn_getaddrinfo(const char* hostname, const char* servname, const struct addrinfo* hints, struct addrinfo** res) {
  64. if (dns_callback == NULL || hostname == NULL || isIp(hostname)) {
  65. return getaddrinfo(hostname, servname, hints, res);
  66. }
  67. qn_ips_ret* ret = dns_callback(hostname);
  68. if (ret == NULL) {
  69. return EAI_NODATA;
  70. }
  71. if (ret->ips[0] == NULL) {
  72. qn_free_ips_ret(ret);
  73. return EAI_NODATA;
  74. }
  75. int i;
  76. struct addrinfo* ai = NULL;
  77. struct addrinfo* store = NULL;
  78. int r = 0;
  79. for (i = 0; ret->ips[i] != NULL; i++) {
  80. r = getaddrinfo(ret->ips[i], servname, hints, &ai);
  81. if (r != 0) {
  82. break;
  83. }
  84. struct addrinfo* temp = ai;
  85. ai = addrinfo_clone(ai);
  86. append_addrinfo(&store, ai);
  87. freeaddrinfo(temp);
  88. ai = NULL;
  89. }
  90. qn_free_ips_ret(ret);
  91. if (r != 0) {
  92. qn_freeaddrinfo(store);
  93. return r;
  94. }
  95. *res = store;
  96. return 0;
  97. }
  98. void qn_freeaddrinfo(struct addrinfo* ai) {
  99. if (ai == NULL) {
  100. return;
  101. }
  102. struct addrinfo* next;
  103. do {
  104. next = ai->ai_next;
  105. if (ai->ai_canonname)
  106. free(ai->ai_canonname);
  107. /* no need to free(ai->ai_addr) */
  108. free(ai);
  109. ai = next;
  110. } while (ai);
  111. }
  112. void qn_set_dns_callback(qn_dns_callback cb) {
  113. dns_callback = cb;
  114. }
  115. static qn_ip_report_callback ip_report_cb = NULL;
  116. void qn_set_ip_report_callback(qn_ip_report_callback cb) {
  117. ip_report_cb = cb;
  118. }
  119. void qn_ip_report(const struct addrinfo* info, int code, int time_ms) {
  120. if (ip_report_cb == NULL || info == NULL) {
  121. return;
  122. }
  123. char ip_str_buf[32] = {0};
  124. const char* c_ip;
  125. if (info->ai_family == AF_INET6) {
  126. c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in6*)(info->ai_addr))->sin6_addr, ip_str_buf, sizeof(ip_str_buf));
  127. } else {
  128. c_ip = inet_ntop(info->ai_family, &((struct sockaddr_in*)(info->ai_addr))->sin_addr, ip_str_buf, sizeof(ip_str_buf));
  129. }
  130. if (c_ip == NULL) {
  131. c_ip = "";
  132. }
  133. ip_report_cb(c_ip, code, time_ms);
  134. }