]> git.proxmox.com Git - mirror_frr.git/blame - nhrpd/resolver.c
Merge pull request #3506 from opensourcerouting/6.0-init-fixes
[mirror_frr.git] / nhrpd / resolver.c
CommitLineData
2fb975da
TT
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
10#include <ares.h>
11#include <ares_version.h>
12
13#include "vector.h"
14#include "thread.h"
aed07011
DS
15#include "lib_errors.h"
16
2fb975da 17#include "nhrpd.h"
aed07011 18#include "nhrp_errors.h"
2fb975da
TT
19
20struct resolver_state {
21 ares_channel channel;
22 struct thread *timeout;
23 vector read_threads, write_threads;
24};
25
26static struct resolver_state state;
27
28#define THREAD_RUNNING ((struct thread *)-1)
29
30static void resolver_update_timeouts(struct resolver_state *r);
31
32static int resolver_cb_timeout(struct thread *t)
33{
34 struct resolver_state *r = THREAD_ARG(t);
35
36 r->timeout = THREAD_RUNNING;
37 ares_process(r->channel, NULL, NULL);
38 r->timeout = NULL;
39 resolver_update_timeouts(r);
40
41 return 0;
42}
43
44static int resolver_cb_socket_readable(struct thread *t)
45{
46 struct resolver_state *r = THREAD_ARG(t);
47 int fd = THREAD_FD(t);
48
49 vector_set_index(r->read_threads, fd, THREAD_RUNNING);
50 ares_process_fd(r->channel, fd, ARES_SOCKET_BAD);
51 if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) {
52 t = NULL;
996c9314 53 thread_add_read(master, resolver_cb_socket_readable, r, fd, &t);
2fb975da
TT
54 vector_set_index(r->read_threads, fd, t);
55 }
56 resolver_update_timeouts(r);
57
58 return 0;
59}
60
61static int resolver_cb_socket_writable(struct thread *t)
62{
63 struct resolver_state *r = THREAD_ARG(t);
64 int fd = THREAD_FD(t);
65
66 vector_set_index(r->write_threads, fd, THREAD_RUNNING);
67 ares_process_fd(r->channel, ARES_SOCKET_BAD, fd);
68 if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) {
69 t = NULL;
ffa2c898
QY
70 thread_add_write(master, resolver_cb_socket_writable, r, fd,
71 &t);
2fb975da
TT
72 vector_set_index(r->write_threads, fd, t);
73 }
74 resolver_update_timeouts(r);
75
76 return 0;
77}
78
79static void resolver_update_timeouts(struct resolver_state *r)
80{
81 struct timeval *tv, tvbuf;
82
996c9314
LB
83 if (r->timeout == THREAD_RUNNING)
84 return;
2fb975da
TT
85
86 THREAD_OFF(r->timeout);
87 tv = ares_timeout(r->channel, NULL, &tvbuf);
88 if (tv) {
89 unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000;
996c9314
LB
90 thread_add_timer_msec(master, resolver_cb_timeout, r, timeoutms,
91 &r->timeout);
2fb975da
TT
92 }
93}
94
996c9314
LB
95static void ares_socket_cb(void *data, ares_socket_t fd, int readable,
96 int writable)
2fb975da 97{
996c9314 98 struct resolver_state *r = (struct resolver_state *)data;
2fb975da
TT
99 struct thread *t;
100
101 if (readable) {
102 t = vector_lookup_ensure(r->read_threads, fd);
103 if (!t) {
996c9314
LB
104 thread_add_read(master, resolver_cb_socket_readable, r,
105 fd, &t);
2fb975da
TT
106 vector_set_index(r->read_threads, fd, t);
107 }
108 } else {
109 t = vector_lookup(r->read_threads, fd);
110 if (t) {
111 if (t != THREAD_RUNNING) {
112 THREAD_OFF(t);
113 }
114 vector_unset(r->read_threads, fd);
115 }
116 }
117
118 if (writable) {
119 t = vector_lookup_ensure(r->write_threads, fd);
120 if (!t) {
996c9314
LB
121 thread_add_read(master, resolver_cb_socket_writable, r,
122 fd, &t);
2fb975da
TT
123 vector_set_index(r->write_threads, fd, t);
124 }
125 } else {
126 t = vector_lookup(r->write_threads, fd);
127 if (t) {
128 if (t != THREAD_RUNNING) {
129 THREAD_OFF(t);
130 }
131 vector_unset(r->write_threads, fd);
132 }
133 }
134}
135
136void resolver_init(void)
137{
138 struct ares_options ares_opts;
139
140 state.read_threads = vector_init(1);
141 state.write_threads = vector_init(1);
142
996c9314 143 ares_opts = (struct ares_options){
2fb975da
TT
144 .sock_state_cb = &ares_socket_cb,
145 .sock_state_cb_data = &state,
146 .timeout = 2,
147 .tries = 3,
148 };
149
150 ares_init_options(&state.channel, &ares_opts,
996c9314
LB
151 ARES_OPT_SOCK_STATE_CB | ARES_OPT_TIMEOUT
152 | ARES_OPT_TRIES);
2fb975da
TT
153}
154
155
996c9314
LB
156static void ares_address_cb(void *arg, int status, int timeouts,
157 struct hostent *he)
2fb975da 158{
996c9314 159 struct resolver_query *query = (struct resolver_query *)arg;
2fb975da
TT
160 union sockunion addr[16];
161 size_t i;
162
163 if (status != ARES_SUCCESS) {
164 debugf(NHRP_DEBUG_COMMON, "[%p] Resolving failed", query);
165 query->callback(query, -1, NULL);
166 query->callback = NULL;
167 return;
168 }
169
0e3d32f1 170 for (i = 0; i < ZEBRA_NUM_OF(addr) && he->h_addr_list[i] != NULL; i++) {
2fb975da
TT
171 memset(&addr[i], 0, sizeof(addr[i]));
172 addr[i].sa.sa_family = he->h_addrtype;
173 switch (he->h_addrtype) {
174 case AF_INET:
996c9314
LB
175 memcpy(&addr[i].sin.sin_addr,
176 (uint8_t *)he->h_addr_list[i], he->h_length);
2fb975da
TT
177 break;
178 case AF_INET6:
996c9314
LB
179 memcpy(&addr[i].sin6.sin6_addr,
180 (uint8_t *)he->h_addr_list[i], he->h_length);
2fb975da
TT
181 break;
182 }
183 }
184
996c9314
LB
185 debugf(NHRP_DEBUG_COMMON, "[%p] Resolved with %d results", query,
186 (int)i);
2fb975da
TT
187 query->callback(query, i, &addr[0]);
188 query->callback = NULL;
189}
190
996c9314
LB
191void resolver_resolve(struct resolver_query *query, int af,
192 const char *hostname,
193 void (*callback)(struct resolver_query *, int,
194 union sockunion *))
2fb975da
TT
195{
196 if (query->callback != NULL) {
af4c2728 197 flog_err(NHRP_ERR_RESOLVER,
aed07011
DS
198 "Trying to resolve '%s', but previous query was not finished yet",
199 hostname);
2fb975da
TT
200 return;
201 }
202
203 debugf(NHRP_DEBUG_COMMON, "[%p] Resolving '%s'", query, hostname);
204
205 query->callback = callback;
206 ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query);
207 resolver_update_timeouts(&state);
208}