chiark / gitweb /
Manpages: Move manpages (back?) into the top-level directory.
[mLib] / bres-adns.c
1 /* -*-c-*-
2  *
3  * $Id$
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 #include "config.h"
43
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
77 static adns_state ads;
78 static sel_state *sel;
79 static 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
92 void 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
113 void 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
134 fail:
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
152 void 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,
160                        adns_qf_search | adns_qf_owner, rc, &rc->aq)) != 0)
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
169 fail:
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
187 void 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
207 static 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;
232   rc->func(&h, rc->p);
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
247 static 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
254 static void afterhook(sel_state *s, sel_args *sa, void *p)
255 {
256   void *c;
257   bres_client *rc;
258   adns_query q;
259   adns_answer *a, *aa;
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);
273         xfree(rc->u.name);
274         report(rc, a, a->rrs.addr, a->nrrs, &a->owner, 1);
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:
294           aa = rc->a;
295           report(rc, a, &a->rrs.addr[i], 1, aa->rrs.str, aa->nrrs);
296           free(aa);
297           free(a);
298         }
299         break;
300       default:
301         abort();
302     }
303     continue;
304
305   fail:
306     if (rc->q == adns_r_addr) xfree(rc->u.name);
307     if (rc->a) free(rc->a);
308     rc->func(0, rc->p);
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
322 void bres_init(sel_state *s)
323 {
324   int e;
325
326   if ((e = adns_init(&ads, adns_if_noautosys, 0)) != 0) {
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 -------------------------------------------------*/