source: src/router/quagga/nhrpd/resolver.c @ 31640

Last change on this file since 31640 was 31640, checked in by brainslayer, 2 weeks ago

update quagga

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