3 * Background reverse name resolution (ADNS version)
5 * (c) 2003 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the mLib utilities library.
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.
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.
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,
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.
43 # error "You need the ADNS library to compile this file."
46 /*----- Header files ------------------------------------------------------*/
53 #include <sys/types.h>
58 #include <sys/socket.h>
59 #include <netinet/in.h>
60 #include <arpa/inet.h>
71 /*----- Static variables --------------------------------------------------*/
73 static adns_state ads;
74 static sel_state *sel;
75 static sel_hook selhook;
77 /*----- Main code ---------------------------------------------------------*/
79 /* --- @bres_abort@ --- *
81 * Arguments: @bres_client *rc@ = pointer to client block
85 * Use: Removes a queued job.
88 void bres_abort(bres_client *rc)
90 if (rc->q == adns_r_addr) xfree(rc->u.name);
91 if (rc->a) free(rc->a);
95 /* --- @bres_byaddr@ --- *
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
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
109 void bres_byaddr(bres_client *rc, struct in_addr addr,
110 void (*func)(struct hostent */*h*/, void */*p*/),
114 struct sockaddr_in sin;
117 sin.sin_family = AF_INET;
120 if ((e = adns_submit_reverse(ads, (struct sockaddr *)&sin, adns_r_ptr,
121 0, rc, &rc->aq)) != 0)
134 /* --- @bres_byname@ --- *
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
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
148 void bres_byname(bres_client *rc, const char *name,
149 void (*func)(struct hostent */*h*/, void */*p*/),
155 if ((e = adns_submit(ads, name, adns_r_addr,
156 adns_qf_search | adns_qf_owner, rc, &rc->aq)) != 0)
160 rc->u.name = xstrdup(name);
169 /* --- @bres_exec@ --- *
171 * Arguments: @const char *file@ = file containing server code or null
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.
183 void bres_exec(const char *file)
188 /* --- @report@ --- *
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)
199 * Use: Formats the given answer into a @struct hostent@ and reports
200 * it to the waiting client application.
203 static void report(bres_client *rc, adns_answer *a,
204 adns_rr_addr *av, int an,
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];
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;
225 h.h_addrtype = AF_INET;
226 h.h_length = sizeof(struct in_addr);
231 /* --- @beforehook@, @afterhook@ --- *
233 * Arguments: @sel_state *s@ = select state
234 * @sel_args *sa@ = argument block
235 * @void *p@ = uninteresting pointer
239 * Use: Processes the selector's arguments before @select@ is
240 * called, to allow ADNS to do its thing.
243 static void beforehook(sel_state *s, sel_args *sa, void *p)
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);
250 static void afterhook(sel_state *s, sel_args *sa, void *p)
259 adns_afterselect(ads, sa->maxfd,
260 &sa->fd[SEL_READ], &sa->fd[SEL_WRITE], &sa->fd[SEL_EXC],
262 while (q = 0, (e = adns_check(ads, &q, &a, &c)) == 0) {
266 else switch (rc->q) {
268 assert(a->type == adns_r_addr);
270 report(rc, a, a->rrs.addr, a->nrrs, &a->owner, 1);
274 if (a->type == adns_r_ptr) {
276 if ((e = adns_submit(ads, a->rrs.str[0], adns_r_addr,
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 ==
291 report(rc, a, &a->rrs.addr[i], 1, aa->rrs.str, aa->nrrs);
302 if (rc->q == adns_r_addr) xfree(rc->u.name);
303 if (rc->a) free(rc->a);
309 /* --- @bres_init@ --- *
311 * Arguments: @sel_state *s@ = pointer to select multiplexor
315 * Use: Initializes the background resolver for use.
318 void bres_init(sel_state *s)
322 if ((e = adns_init(&ads, adns_if_noautosys, 0)) != 0) {
323 moan("adns_init failed: resolver won't work");
326 sel_addhook(s, &selhook, beforehook, afterhook, 0);
330 /*----- That's all, folks -------------------------------------------------*/