chiark / gitweb /
Add adns support in background resolver.
[mLib] / bres-adns.c
CommitLineData
14d7100d 1/* -*-c-*-
2 *
3 * $Id: bres-adns.c,v 1.1 2003/12/13 20:37:59 mdw Exp $
4 *
5 * Background reverse name resolution (ADNS version)
6 *
7 * (c) 2003 Straylight/Edgeware
8 */
9
10/*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of the mLib utilities library.
13 *
14 * mLib is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
18 *
19 * mLib is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
23 *
24 * You should have received a copy of the GNU Library General Public
25 * License along with mLib; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
27 * MA 02111-1307, USA.
28 *
29 *
30 * HOWEVER, since GNU adns is covered by the full GNU General Public
31 * License, this file (only) is also covered by the full GNU GPL, and
32 * you may NOT take advantage of the more liberal conditions of the
33 * LGPL when modifying or redistributing this file. This doesn't mean
34 * that a program which uses the interface provided by this file is
35 * covered by the GPL, since @bres.c@ provides the same interface and
36 * is LGPL. However, it does mean that if your program depends, for
37 * some reason (e.g., to meet particular performance criteria), on
38 * this adns-based implementation of mLib's background resolver then it
39 * must be licensed under the full GPL.
40 */
41
42/*----- Revision history --------------------------------------------------*
43 *
44 * $Log: bres-adns.c,v $
45 * Revision 1.1 2003/12/13 20:37:59 mdw
46 * Add adns support in background resolver.
47 *
48 */
49
50#ifndef HAVE_ADNS
51# error "You need the ADNS library to compile this file."
52#endif
53
54/*----- Header files ------------------------------------------------------*/
55
56#include <assert.h>
57#include <errno.h>
58#include <signal.h>
59#include <stdio.h>
60#include <stdlib.h>
61#include <string.h>
62
63#include <sys/types.h>
64#include <sys/time.h>
65#include <unistd.h>
66#include <sys/wait.h>
67
68#include <sys/socket.h>
69#include <netinet/in.h>
70#include <arpa/inet.h>
71#include <netdb.h>
72
73#include <adns.h>
74
75#include "alloc.h"
76#include "bres.h"
77#include "macros.h"
78#include "report.h"
79#include "sel.h"
80
81/*----- Static variables --------------------------------------------------*/
82
83static adns_state ads;
84static sel_state *sel;
85static sel_hook selhook;
86
87/*----- Main code ---------------------------------------------------------*/
88
89/* --- @bres_abort@ --- *
90 *
91 * Arguments: @bres_client *rc@ = pointer to client block
92 *
93 * Returns: ---
94 *
95 * Use: Removes a queued job.
96 */
97
98void bres_abort(bres_client *rc)
99{
100 if (rc->q == adns_r_addr) xfree(rc->u.name);
101 if (rc->a) free(rc->a);
102 adns_cancel(rc->aq);
103}
104
105/* --- @bres_byaddr@ --- *
106 *
107 * Arguments: @bres_client *rc@ = pointer to client block
108 * @struct in_addr addr@ = address to resolve
109 * @void (*func)(struct hostent *h, void *p)@ = handler function
110 * @void *p@ = argument for handler function
111 *
112 * Returns: ---
113 *
114 * Use: Adds an address lookup job to the queue. The job will be
115 * processed when there's a spare resolver process to deal with
116 * it.
117 */
118
119void bres_byaddr(bres_client *rc, struct in_addr addr,
120 void (*func)(struct hostent */*h*/, void */*p*/),
121 void *p)
122{
123 int e;
124 struct sockaddr_in sin;
125
126 if (!ads) goto fail;
127 sin.sin_family = AF_INET;
128 sin.sin_addr = addr;
129 sin.sin_port = 0;
130 if ((e = adns_submit_reverse(ads, (struct sockaddr *)&sin, adns_r_ptr,
131 0, rc, &rc->aq)) != 0)
132 goto fail;
133 rc->a = 0;
134 rc->q = adns_r_ptr;
135 rc->u.addr = addr;
136 rc->func = func;
137 rc->p = p;
138 return;
139
140fail:
141 func(0, p);
142}
143
144/* --- @bres_byname@ --- *
145 *
146 * Arguments: @bres_client *rc@ = pointer to client block
147 * @const char *name@ = name to resolve
148 * @void (*func)(struct hostent *h, void *p)@ = handler function
149 * @void *p@ = argument for handler function
150 *
151 * Returns: ---
152 *
153 * Use: Adds a name lookup job to the queue. The job will be
154 * processed when there's a spare resolver process to deal with
155 * it.
156 */
157
158void bres_byname(bres_client *rc, const char *name,
159 void (*func)(struct hostent */*h*/, void */*p*/),
160 void *p)
161{
162 int e;
163
164 if (!ads) goto fail;
165 if ((e = adns_submit(ads, name, adns_r_addr,
166 adns_qf_search, rc, &rc->aq)) != 0)
167 goto fail;
168 rc->a = 0;
169 rc->q = adns_r_addr;
170 rc->u.name = xstrdup(name);
171 rc->func = func;
172 rc->p = p;
173 return;
174
175fail:
176 func(0, p);
177}
178
179/* --- @bres_exec@ --- *
180 *
181 * Arguments: @const char *file@ = file containing server code or null
182 *
183 * Returns: ---
184 *
185 * Use: Makes `bres' use a standalone server rather than copies of
186 * the current process. This can reduce memory consumption for
187 * large processes, at the expense of startup time (which
188 * shouldn't be too bad anyway, because of the resolver design).
189 * If the filename is null, a default set up at install time is
190 * used. It's probably a good idea to leave it alone.
191 */
192
193void bres_exec(const char *file)
194{
195 /* Nothin' doin' */
196}
197
198/* --- @report@ --- *
199 *
200 * Arguments: @bres_client *c@ = client descriptor block
201 * @adns_answer *a@ = A-record answer from resolver library
202 * @adns_rr_addr *av@ = vector of address records
203 * @int an@ = number of address records (must be positive)
204 * @char **nv@ = vector of name strings
205 * @int nn@ = number of name strings (must be positive)
206 *
207 * Returns: ---
208 *
209 * Use: Formats the given answer into a @struct hostent@ and reports
210 * it to the waiting client application.
211 */
212
213static void report(bres_client *rc, adns_answer *a,
214 adns_rr_addr *av, int an,
215 char **nv, int nn)
216{
217 struct hostent h;
218 char *n[16];
219 char *aa[16];
220 int i, j;
221
222 j = 0;
223 if (a->cname) n[j++] = a->cname;
224 else { n[j++] = *nv; nv++; nn--; }
225 for (i = 0; i < nn && j < N(n) - 1; i++)
226 if (strcmp(n[0], nv[i]) != 0) n[j++] = nv[i];
227 n[j++] = 0;
228 for (i = j = 0; i < an && j < N(av) - 1; i++) {
229 if (av[i].addr.sa.sa_family == AF_INET)
230 aa[j++] = (char *)&av[i].addr.inet.sin_addr;
231 }
232 aa[j++] = 0;
233 h.h_name = n[0];
234 h.h_aliases = n + 1;
235 h.h_addrtype = AF_INET;
236 h.h_length = sizeof(struct in_addr);
237 h.h_addr_list = aa;
238 rc->func(&h, rc->p);
239}
240
241/* --- @beforehook@, @afterhook@ --- *
242 *
243 * Arguments: @sel_state *s@ = select state
244 * @sel_args *sa@ = argument block
245 * @void *p@ = uninteresting pointer
246 *
247 * Returns: ---
248 *
249 * Use: Processes the selector's arguments before @select@ is
250 * called, to allow ADNS to do its thing.
251 */
252
253static void beforehook(sel_state *s, sel_args *sa, void *p)
254{
255 adns_beforeselect(ads, &sa->maxfd,
256 &sa->fd[SEL_READ], &sa->fd[SEL_WRITE], &sa->fd[SEL_EXC],
257 &sa->tvp, &sa->tv, &sa->now);
258}
259
260static void afterhook(sel_state *s, sel_args *sa, void *p)
261{
262 void *c;
263 bres_client *rc;
264 adns_query q;
265 adns_answer *a;
266 int e;
267 int i;
268
269 adns_afterselect(ads, sa->maxfd,
270 &sa->fd[SEL_READ], &sa->fd[SEL_WRITE], &sa->fd[SEL_EXC],
271 &sa->now);
272 while (q = 0, (e = adns_check(ads, &q, &a, &c)) == 0) {
273 rc = c;
274 if (a->status != 0)
275 goto fail;
276 else switch (rc->q) {
277 case adns_r_addr:
278 assert(a->type == adns_r_addr);
279 report(rc, a, a->rrs.addr, a->nrrs, &rc->u.name, 1);
280 free(rc->u.name);
281 free(a);
282 break;
283 case adns_r_ptr:
284 if (a->type == adns_r_ptr) {
285 rc->a = a;
286 if ((e = adns_submit(ads, a->rrs.str[0], adns_r_addr,
287 0, rc, &q)) != 0)
288 goto fail;
289 rc->aq = q;
290 } else {
291 assert(a->type == adns_r_addr);
292 for (i = 0; i < a->nrrs; i++) {
293 if (a->rrs.addr[i].addr.sa.sa_family == AF_INET &&
294 a->rrs.addr[i].addr.inet.sin_addr.s_addr ==
295 rc->u.addr.s_addr)
296 goto match;
297 }
298 goto fail;
299 match:
300 report(rc, a, &a->rrs.addr[i], 1, rc->a->rrs.str, rc->a->nrrs);
301 free(rc->a);
302 free(a);
303 }
304 break;
305 default:
306 abort();
307 }
308 continue;
309
310 fail:
311 rc->func(0, rc->p);
312 if (rc->q == adns_r_addr) xfree(rc->u.name);
313 if (rc->a) free(rc->a);
314 free(a);
315 }
316}
317
318/* --- @bres_init@ --- *
319 *
320 * Arguments: @sel_state *s@ = pointer to select multiplexor
321 *
322 * Returns: ---
323 *
324 * Use: Initializes the background resolver for use.
325 */
326
327void bres_init(sel_state *s)
328{
329 int e;
330
331 if ((e = adns_init(&ads, 0, 0)) != 0) {
332 moan("adns_init failed: resolver won't work");
333 return;
334 }
335 sel_addhook(s, &selhook, beforehook, afterhook, 0);
336 sel = s;
337}
338
339/*----- That's all, folks -------------------------------------------------*/