resolver.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /* C-Ares integration to Quagga mainloop
  2. * Copyright (c) 2014-2015 Timo Teräs
  3. *
  4. * This file is free software: you may copy, redistribute and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 2 of the License, or
  7. * (at your option) any later version.
  8. */
  9. #include <ares.h>
  10. #include <ares_version.h>
  11. #include "vector.h"
  12. #include "thread.h"
  13. #include "nhrpd.h"
  14. struct resolver_state {
  15. ares_channel channel;
  16. struct thread *timeout;
  17. vector read_threads, write_threads;
  18. };
  19. static struct resolver_state state;
  20. #define THREAD_RUNNING ((struct thread *)-1)
  21. static void resolver_update_timeouts(struct resolver_state *r);
  22. static int resolver_cb_timeout(struct thread *t)
  23. {
  24. struct resolver_state *r = THREAD_ARG(t);
  25. r->timeout = THREAD_RUNNING;
  26. ares_process(r->channel, NULL, NULL);
  27. r->timeout = NULL;
  28. resolver_update_timeouts(r);
  29. return 0;
  30. }
  31. static int resolver_cb_socket_readable(struct thread *t)
  32. {
  33. struct resolver_state *r = THREAD_ARG(t);
  34. int fd = THREAD_FD(t);
  35. vector_set_index(r->read_threads, fd, THREAD_RUNNING);
  36. ares_process_fd(r->channel, fd, ARES_SOCKET_BAD);
  37. if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) {
  38. t = NULL;
  39. THREAD_READ_ON(master, t, resolver_cb_socket_readable, r, fd);
  40. vector_set_index(r->read_threads, fd, t);
  41. }
  42. resolver_update_timeouts(r);
  43. return 0;
  44. }
  45. static int resolver_cb_socket_writable(struct thread *t)
  46. {
  47. struct resolver_state *r = THREAD_ARG(t);
  48. int fd = THREAD_FD(t);
  49. vector_set_index(r->write_threads, fd, THREAD_RUNNING);
  50. ares_process_fd(r->channel, ARES_SOCKET_BAD, fd);
  51. if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) {
  52. t = NULL;
  53. THREAD_WRITE_ON(master, t, resolver_cb_socket_writable, r, fd);
  54. vector_set_index(r->write_threads, fd, t);
  55. }
  56. resolver_update_timeouts(r);
  57. return 0;
  58. }
  59. static void resolver_update_timeouts(struct resolver_state *r)
  60. {
  61. struct timeval *tv, tvbuf;
  62. if (r->timeout == THREAD_RUNNING) return;
  63. THREAD_OFF(r->timeout);
  64. tv = ares_timeout(r->channel, NULL, &tvbuf);
  65. if (tv) {
  66. unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
  67. THREAD_TIMER_MSEC_ON(master, r->timeout, resolver_cb_timeout, r, timeoutms);
  68. }
  69. }
  70. static void ares_socket_cb(void *data, ares_socket_t fd, int readable, int writable)
  71. {
  72. struct resolver_state *r = (struct resolver_state *) data;
  73. struct thread *t;
  74. if (readable) {
  75. t = vector_lookup_ensure(r->read_threads, fd);
  76. if (!t) {
  77. THREAD_READ_ON(master, t, resolver_cb_socket_readable, r, fd);
  78. vector_set_index(r->read_threads, fd, t);
  79. }
  80. } else {
  81. t = vector_lookup(r->read_threads, fd);
  82. if (t) {
  83. if (t != THREAD_RUNNING) {
  84. THREAD_OFF(t);
  85. }
  86. vector_unset(r->read_threads, fd);
  87. }
  88. }
  89. if (writable) {
  90. t = vector_lookup_ensure(r->write_threads, fd);
  91. if (!t) {
  92. THREAD_READ_ON(master, t, resolver_cb_socket_writable, r, fd);
  93. vector_set_index(r->write_threads, fd, t);
  94. }
  95. } else {
  96. t = vector_lookup(r->write_threads, fd);
  97. if (t) {
  98. if (t != THREAD_RUNNING) {
  99. THREAD_OFF(t);
  100. }
  101. vector_unset(r->write_threads, fd);
  102. }
  103. }
  104. }
  105. void resolver_init(void)
  106. {
  107. struct ares_options ares_opts;
  108. state.read_threads = vector_init(1);
  109. state.write_threads = vector_init(1);
  110. ares_opts = (struct ares_options) {
  111. .sock_state_cb = &ares_socket_cb,
  112. .sock_state_cb_data = &state,
  113. .timeout = 2,
  114. .tries = 3,
  115. };
  116. ares_init_options(&state.channel, &ares_opts,
  117. ARES_OPT_SOCK_STATE_CB | ARES_OPT_TIMEOUT |
  118. ARES_OPT_TRIES);
  119. }
  120. static void ares_address_cb(void *arg, int status, int timeouts, struct hostent *he)
  121. {
  122. struct resolver_query *query = (struct resolver_query *) arg;
  123. union sockunion addr[16];
  124. size_t i;
  125. if (status != ARES_SUCCESS) {
  126. debugf(NHRP_DEBUG_COMMON, "[%p] Resolving failed", query);
  127. query->callback(query, -1, NULL);
  128. query->callback = NULL;
  129. return;
  130. }
  131. for (i = 0; he->h_addr_list[i] != NULL && i < ZEBRA_NUM_OF(addr); i++) {
  132. memset(&addr[i], 0, sizeof(addr[i]));
  133. addr[i].sa.sa_family = he->h_addrtype;
  134. switch (he->h_addrtype) {
  135. case AF_INET:
  136. memcpy(&addr[i].sin.sin_addr, (uint8_t *) he->h_addr_list[i], he->h_length);
  137. break;
  138. case AF_INET6:
  139. memcpy(&addr[i].sin6.sin6_addr, (uint8_t *) he->h_addr_list[i], he->h_length);
  140. break;
  141. }
  142. }
  143. debugf(NHRP_DEBUG_COMMON, "[%p] Resolved with %d results", query, (int) i);
  144. query->callback(query, i, &addr[0]);
  145. query->callback = NULL;
  146. }
  147. void resolver_resolve(struct resolver_query *query, int af, const char *hostname, void (*callback)(struct resolver_query *, int, union sockunion *))
  148. {
  149. if (query->callback != NULL) {
  150. zlog_err("Trying to resolve '%s', but previous query was not finished yet", hostname);
  151. return;
  152. }
  153. debugf(NHRP_DEBUG_COMMON, "[%p] Resolving '%s'", query, hostname);
  154. query->callback = callback;
  155. ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query);
  156. resolver_update_timeouts(&state);
  157. }