chiark / gitweb /
Commit as 2.1.0.
[mLib] / bres-adns.c
CommitLineData
14d7100d 1/* -*-c-*-
2 *
1dc93196 3 * $Id$
14d7100d 4 *
5 * Background reverse name resolution (ADNS version)
6 *
7 * (c) 2003 Straylight/Edgeware
8 */
9
d4efbcd9 10/*----- Licensing notice --------------------------------------------------*
14d7100d 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.
d4efbcd9 18 *
14d7100d 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.
d4efbcd9 23 *
14d7100d 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
a0150d8d
MW
42#include "config.h"
43
14d7100d 44#ifndef HAVE_ADNS
45# error "You need the ADNS library to compile this file."
46#endif
47
48/*----- Header files ------------------------------------------------------*/
49
50#include <assert.h>
51#include <errno.h>
52#include <signal.h>
53#include <stdio.h>
54#include <stdlib.h>
55#include <string.h>
56
57#include <sys/types.h>
58#include <sys/time.h>
59#include <unistd.h>
60#include <sys/wait.h>
61
62#include <sys/socket.h>
63#include <netinet/in.h>
64#include <arpa/inet.h>
65#include <netdb.h>
66
67#include <adns.h>
68
69#include "alloc.h"
70#include "bres.h"
71#include "macros.h"
72#include "report.h"
73#include "sel.h"
74
75/*----- Static variables --------------------------------------------------*/
76
77static adns_state ads;
78static sel_state *sel;
79static sel_hook selhook;
80
81/*----- Main code ---------------------------------------------------------*/
82
83/* --- @bres_abort@ --- *
84 *
85 * Arguments: @bres_client *rc@ = pointer to client block
86 *
87 * Returns: ---
88 *
89 * Use: Removes a queued job.
90 */
91
92void bres_abort(bres_client *rc)
93{
94 if (rc->q == adns_r_addr) xfree(rc->u.name);
95 if (rc->a) free(rc->a);
96 adns_cancel(rc->aq);
97}
98
99/* --- @bres_byaddr@ --- *
100 *
101 * Arguments: @bres_client *rc@ = pointer to client block
102 * @struct in_addr addr@ = address to resolve
103 * @void (*func)(struct hostent *h, void *p)@ = handler function
104 * @void *p@ = argument for handler function
105 *
106 * Returns: ---
107 *
108 * Use: Adds an address lookup job to the queue. The job will be
109 * processed when there's a spare resolver process to deal with
110 * it.
111 */
112
113void bres_byaddr(bres_client *rc, struct in_addr addr,
114 void (*func)(struct hostent */*h*/, void */*p*/),
115 void *p)
116{
117 int e;
118 struct sockaddr_in sin;
119
120 if (!ads) goto fail;
121 sin.sin_family = AF_INET;
122 sin.sin_addr = addr;
123 sin.sin_port = 0;
124 if ((e = adns_submit_reverse(ads, (struct sockaddr *)&sin, adns_r_ptr,
125 0, rc, &rc->aq)) != 0)
126 goto fail;
127 rc->a = 0;
128 rc->q = adns_r_ptr;
129 rc->u.addr = addr;
130 rc->func = func;
131 rc->p = p;
132 return;
133
134fail:
135 func(0, p);
136}
137
138/* --- @bres_byname@ --- *
139 *
140 * Arguments: @bres_client *rc@ = pointer to client block
141 * @const char *name@ = name to resolve
142 * @void (*func)(struct hostent *h, void *p)@ = handler function
143 * @void *p@ = argument for handler function
144 *
145 * Returns: ---
146 *
147 * Use: Adds a name lookup job to the queue. The job will be
148 * processed when there's a spare resolver process to deal with
149 * it.
150 */
151
152void bres_byname(bres_client *rc, const char *name,
153 void (*func)(struct hostent */*h*/, void */*p*/),
154 void *p)
155{
156 int e;
157
158 if (!ads) goto fail;
159 if ((e = adns_submit(ads, name, adns_r_addr,
4f6d400b 160 adns_qf_search | adns_qf_owner, rc, &rc->aq)) != 0)
14d7100d 161 goto fail;
162 rc->a = 0;
163 rc->q = adns_r_addr;
164 rc->u.name = xstrdup(name);
165 rc->func = func;
166 rc->p = p;
167 return;
168
169fail:
170 func(0, p);
171}
172
173/* --- @bres_exec@ --- *
174 *
175 * Arguments: @const char *file@ = file containing server code or null
176 *
177 * Returns: ---
178 *
179 * Use: Makes `bres' use a standalone server rather than copies of
180 * the current process. This can reduce memory consumption for
181 * large processes, at the expense of startup time (which
182 * shouldn't be too bad anyway, because of the resolver design).
183 * If the filename is null, a default set up at install time is
184 * used. It's probably a good idea to leave it alone.
185 */
186
187void bres_exec(const char *file)
188{
189 /* Nothin' doin' */
190}
191
192/* --- @report@ --- *
193 *
194 * Arguments: @bres_client *c@ = client descriptor block
195 * @adns_answer *a@ = A-record answer from resolver library
196 * @adns_rr_addr *av@ = vector of address records
197 * @int an@ = number of address records (must be positive)
198 * @char **nv@ = vector of name strings
199 * @int nn@ = number of name strings (must be positive)
200 *
201 * Returns: ---
202 *
203 * Use: Formats the given answer into a @struct hostent@ and reports
204 * it to the waiting client application.
205 */
206
207static void report(bres_client *rc, adns_answer *a,
208 adns_rr_addr *av, int an,
209 char **nv, int nn)
210{
211 struct hostent h;
212 char *n[16];
213 char *aa[16];
214 int i, j;
215
216 j = 0;
217 if (a->cname) n[j++] = a->cname;
218 else { n[j++] = *nv; nv++; nn--; }
219 for (i = 0; i < nn && j < N(n) - 1; i++)
220 if (strcmp(n[0], nv[i]) != 0) n[j++] = nv[i];
221 n[j++] = 0;
222 for (i = j = 0; i < an && j < N(av) - 1; i++) {
223 if (av[i].addr.sa.sa_family == AF_INET)
224 aa[j++] = (char *)&av[i].addr.inet.sin_addr;
225 }
226 aa[j++] = 0;
227 h.h_name = n[0];
228 h.h_aliases = n + 1;
229 h.h_addrtype = AF_INET;
230 h.h_length = sizeof(struct in_addr);
231 h.h_addr_list = aa;
d4efbcd9 232 rc->func(&h, rc->p);
14d7100d 233}
234
235/* --- @beforehook@, @afterhook@ --- *
236 *
237 * Arguments: @sel_state *s@ = select state
238 * @sel_args *sa@ = argument block
239 * @void *p@ = uninteresting pointer
240 *
241 * Returns: ---
242 *
243 * Use: Processes the selector's arguments before @select@ is
244 * called, to allow ADNS to do its thing.
245 */
246
247static void beforehook(sel_state *s, sel_args *sa, void *p)
248{
249 adns_beforeselect(ads, &sa->maxfd,
250 &sa->fd[SEL_READ], &sa->fd[SEL_WRITE], &sa->fd[SEL_EXC],
251 &sa->tvp, &sa->tv, &sa->now);
252}
253
254static void afterhook(sel_state *s, sel_args *sa, void *p)
255{
256 void *c;
257 bres_client *rc;
258 adns_query q;
24a657cc 259 adns_answer *a, *aa;
14d7100d 260 int e;
261 int i;
262
263 adns_afterselect(ads, sa->maxfd,
264 &sa->fd[SEL_READ], &sa->fd[SEL_WRITE], &sa->fd[SEL_EXC],
265 &sa->now);
266 while (q = 0, (e = adns_check(ads, &q, &a, &c)) == 0) {
267 rc = c;
268 if (a->status != 0)
269 goto fail;
270 else switch (rc->q) {
271 case adns_r_addr:
272 assert(a->type == adns_r_addr);
1dc93196 273 xfree(rc->u.name);
24a657cc 274 report(rc, a, a->rrs.addr, a->nrrs, &a->owner, 1);
14d7100d 275 free(a);
276 break;
277 case adns_r_ptr:
278 if (a->type == adns_r_ptr) {
279 rc->a = a;
280 if ((e = adns_submit(ads, a->rrs.str[0], adns_r_addr,
281 0, rc, &q)) != 0)
282 goto fail;
283 rc->aq = q;
284 } else {
285 assert(a->type == adns_r_addr);
286 for (i = 0; i < a->nrrs; i++) {
287 if (a->rrs.addr[i].addr.sa.sa_family == AF_INET &&
288 a->rrs.addr[i].addr.inet.sin_addr.s_addr ==
289 rc->u.addr.s_addr)
290 goto match;
291 }
292 goto fail;
293 match:
24a657cc 294 aa = rc->a;
295 report(rc, a, &a->rrs.addr[i], 1, aa->rrs.str, aa->nrrs);
296 free(aa);
14d7100d 297 free(a);
298 }
299 break;
300 default:
301 abort();
302 }
303 continue;
304
305 fail:
14d7100d 306 if (rc->q == adns_r_addr) xfree(rc->u.name);
307 if (rc->a) free(rc->a);
24a657cc 308 rc->func(0, rc->p);
14d7100d 309 free(a);
310 }
311}
312
313/* --- @bres_init@ --- *
314 *
315 * Arguments: @sel_state *s@ = pointer to select multiplexor
316 *
317 * Returns: ---
318 *
319 * Use: Initializes the background resolver for use.
320 */
321
322void bres_init(sel_state *s)
323{
324 int e;
325
d46d1a2f 326 if ((e = adns_init(&ads, adns_if_noautosys, 0)) != 0) {
14d7100d 327 moan("adns_init failed: resolver won't work");
328 return;
329 }
330 sel_addhook(s, &selhook, beforehook, afterhook, 0);
331 sel = s;
332}
333
334/*----- That's all, folks -------------------------------------------------*/