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