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