+ * Some better source code formatting/wrapping in a few places.
[adns] / src / general.c
1 /*
2 * general.c
3 * - diagnostic functions
4 * - vbuf handling
5 */
6 /*
7 * This file is
8 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
9 *
10 * It is part of adns, which is
11 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
12 * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
17 * any later version.
18 *
19 * This program 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 General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 #include <stdlib.h>
30 #include <unistd.h>
31
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36
37 #include "internal.h"
38
39 /* Core diagnostic functions */
40
41 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
42 int serv, adns_query qu, const char *fmt, va_list al) {
43 const char *bef, *aft;
44 vbuf vb;
45
46 if (!ads->diagfile ||
47 (!(ads->iflags & adns_if_debug)
48 && (!prevent || (ads->iflags & prevent))))
49 return;
50
51 if (ads->iflags & adns_if_logpid) {
52 fprintf(ads->diagfile,"adns%s [%ld]: ",pfx,(long)getpid());
53 } else {
54 fprintf(ads->diagfile,"adns%s: ",pfx);
55 }
56
57 vfprintf(ads->diagfile,fmt,al);
58
59 bef= " (";
60 aft= "\n";
61
62 if (qu && qu->query_dgram) {
63 adns__vbuf_init(&vb);
64 fprintf(ads->diagfile,"%sQNAME=%s, QTYPE=%s",
65 bef,
66 adns__diag_domain(qu->ads,-1,0, &vb,
67 qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
68 qu->typei ? qu->typei->rrtname : "<unknown>");
69 if (qu->typei && qu->typei->fmtname)
70 fprintf(ads->diagfile,"(%s)",qu->typei->fmtname);
71 bef=", "; aft=")\n";
72 adns__vbuf_free(&vb);
73 }
74
75 if (serv>=0) {
76 fprintf(ads->diagfile,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
77 bef=", "; aft=")\n";
78 }
79
80 fputs(aft,ads->diagfile);
81 }
82
83 void adns__debug(adns_state ads, int serv, adns_query qu,
84 const char *fmt, ...) {
85 va_list al;
86
87 va_start(al,fmt);
88 adns__vdiag(ads," debug",0,serv,qu,fmt,al);
89 va_end(al);
90 }
91
92 void adns__warn(adns_state ads, int serv, adns_query qu,
93 const char *fmt, ...) {
94 va_list al;
95
96 va_start(al,fmt);
97 adns__vdiag(ads," warning",
98 adns_if_noerrprint|adns_if_noserverwarn, serv,qu,fmt,al);
99 va_end(al);
100 }
101
102 void adns__diag(adns_state ads, int serv, adns_query qu,
103 const char *fmt, ...) {
104 va_list al;
105
106 va_start(al,fmt);
107 adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
108 va_end(al);
109 }
110
111 /* vbuf functions */
112
113 void adns__vbuf_init(vbuf *vb) {
114 vb->used= vb->avail= 0; vb->buf= 0;
115 }
116
117 int adns__vbuf_ensure(vbuf *vb, int want) {
118 void *nb;
119
120 if (vb->avail >= want) return 1;
121 nb= realloc(vb->buf,want); if (!nb) return 0;
122 vb->buf= nb;
123 vb->avail= want;
124 return 1;
125 }
126
127 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
128 memcpy(vb->buf+vb->used,data,len);
129 vb->used+= len;
130 }
131
132 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
133 int newlen;
134 void *nb;
135
136 newlen= vb->used+len;
137 if (vb->avail < newlen) {
138 if (newlen<20) newlen= 20;
139 newlen <<= 1;
140 nb= realloc(vb->buf,newlen);
141 if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
142 if (!nb) return 0;
143 vb->buf= nb;
144 vb->avail= newlen;
145 }
146 adns__vbuf_appendq(vb,data,len);
147 return 1;
148 }
149
150 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
151 int l;
152 l= strlen(data);
153 return adns__vbuf_append(vb,data,l);
154 }
155
156 void adns__vbuf_free(vbuf *vb) {
157 free(vb->buf);
158 adns__vbuf_init(vb);
159 }
160
161 /* Additional diagnostic functions */
162
163 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
164 vbuf *vb, const byte *dgram,
165 int dglen, int cbyte) {
166 adns_status st;
167
168 st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok,
169 dgram,dglen,&cbyte,dglen);
170 if (st == adns_s_nomemory) {
171 return "<cannot report domain... out of memory>";
172 }
173 if (st) {
174 vb->used= 0;
175 if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
176 adns__vbuf_appendstr(vb,adns_strerror(st)) &&
177 adns__vbuf_appendstr(vb,">") &&
178 adns__vbuf_append(vb,"",1))) {
179 return "<cannot report bad format... out of memory>";
180 }
181 }
182 if (!vb->used) {
183 adns__vbuf_appendstr(vb,"<truncated ...>");
184 adns__vbuf_append(vb,"",1);
185 }
186 return vb->buf;
187 }
188
189 adns_status adns_rr_info(adns_rrtype type,
190 const char **rrtname_r, const char **fmtname_r,
191 int *len_r,
192 const void *datap, char **data_r) {
193 const typeinfo *typei;
194 vbuf vb;
195 adns_status st;
196
197 typei= adns__findtype(type);
198 if (!typei) return adns_s_unknownrrtype;
199
200 if (rrtname_r) *rrtname_r= typei->rrtname;
201 if (fmtname_r) *fmtname_r= typei->fmtname;
202 if (len_r) *len_r= typei->rrsz;
203
204 if (!datap) return adns_s_ok;
205
206 adns__vbuf_init(&vb);
207 st= typei->convstring(&vb,datap);
208 if (st) goto x_freevb;
209 if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nomemory; goto x_freevb; }
210 assert(strlen(vb.buf) == vb.used-1);
211 *data_r= realloc(vb.buf,vb.used);
212 if (!*data_r) *data_r= vb.buf;
213 return adns_s_ok;
214
215 x_freevb:
216 adns__vbuf_free(&vb);
217 return st;
218 }
219
220
221 #define SINFO(n,s) { adns_s_##n, #n, s }
222
223 static const struct sinfo {
224 adns_status st;
225 const char *abbrev;
226 const char *string;
227 } sinfos[]= {
228 SINFO( ok, "OK" ),
229
230 SINFO( nomemory, "Out of memory" ),
231 SINFO( unknownrrtype, "Query not implemented in DNS library" ),
232 SINFO( systemfail, "General resolver or system failure" ),
233
234 SINFO( timeout, "DNS query timed out" ),
235 SINFO( allservfail, "All nameservers failed" ),
236 SINFO( norecurse, "Recursion denied by nameserver" ),
237 SINFO( invalidresponse, "Nameserver sent bad response" ),
238 SINFO( unknownformat, "Nameserver used unknown format" ),
239
240 SINFO( rcodeservfail, "Nameserver reports failure" ),
241 SINFO( rcodeformaterror, "Query not understood by nameserver" ),
242 SINFO( rcodenotimplemented, "Query not implemented by nameserver" ),
243 SINFO( rcoderefused, "Query refused by nameserver" ),
244 SINFO( rcodeunknown, "Nameserver sent unknown response code" ),
245
246 SINFO( inconsistent, "Inconsistent resource records in DNS" ),
247 SINFO( prohibitedcname, "DNS alias found where canonical name wanted" ),
248 SINFO( answerdomaininvalid, "Found syntactically invalid domain name" ),
249 SINFO( answerdomaintoolong, "Found overly-long domain name" ),
250 SINFO( invaliddata, "Found invalid DNS data" ),
251
252 SINFO( querydomainwrong, "Domain invalid for particular DNS query type" ),
253 SINFO( querydomaininvalid, "Domain name is syntactically invalid" ),
254 SINFO( querydomaintoolong, "Domain name or component is too long" ),
255
256 SINFO( nxdomain, "No such domain" ),
257 SINFO( nodata, "No such data" )
258 };
259
260 static int si_compar(const void *key, const void *elem) {
261 const adns_status *st= key;
262 const struct sinfo *si= elem;
263
264 return *st < si->st ? -1 : *st > si->st ? 1 : 0;
265 }
266
267 static const struct sinfo *findsinfo(adns_status st) {
268 return bsearch(&st,sinfos, sizeof(sinfos)/sizeof(*sinfos),
269 sizeof(*sinfos), si_compar);
270 }
271
272 const char *adns_strerror(adns_status st) {
273 const struct sinfo *si;
274
275 si= findsinfo(st);
276 return si->string;
277 }
278
279 const char *adns_errabbrev(adns_status st) {
280 const struct sinfo *si;
281
282 si= findsinfo(st);
283 return si->abbrev;
284 }
285
286
287 #define STINFO(max) { adns_s_max_##max, #max }
288
289 static const struct stinfo {
290 adns_status stmax;
291 const char *abbrev;
292 } stinfos[]= {
293 { adns_s_ok, "ok" },
294 STINFO( localfail ),
295 STINFO( remotefail ),
296 STINFO( tempfail ),
297 STINFO( misconfig ),
298 STINFO( misquery ),
299 STINFO( permfail )
300 };
301
302 static int sti_compar(const void *key, const void *elem) {
303 const adns_status *st= key;
304 const struct stinfo *sti= elem;
305
306 adns_status here, min, max;
307
308 here= *st;
309 min= (sti==stinfos) ? 0 : sti[-1].stmax+1;
310 max= sti->stmax;
311
312 return here < min ? -1 : here > max ? 1 : 0;
313 }
314
315 const char *adns_errtypeabbrev(adns_status st) {
316 const struct stinfo *sti;
317
318 sti= bsearch(&st,stinfos, sizeof(stinfos)/sizeof(*stinfos),
319 sizeof(*stinfos), sti_compar);
320 return sti->abbrev;
321 }
322
323
324 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
325 int (*needswap)(void *context, const void *a, const void *b),
326 void *context) {
327 byte *data= array;
328 int i, place;
329
330 for (i=0; i<nobjs; i++) {
331 for (place= i;
332 place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
333 place--);
334 if (place != i) {
335 memcpy(tempbuf, data + i*sz, sz);
336 memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
337 memcpy(data + place*sz, tempbuf, sz);
338 }
339 }
340 }
341
342 /* SIGPIPE protection. */
343
344 void adns__sigpipe_protect(adns_state ads) {
345 sigset_t toblock;
346 struct sigaction sa;
347 int r;
348
349 if (ads->iflags & adns_if_nosigpipe) return;
350
351 sigfillset(&toblock);
352 sigdelset(&toblock,SIGPIPE);
353
354 sa.sa_handler= SIG_IGN;
355 sigfillset(&sa.sa_mask);
356 sa.sa_flags= 0;
357
358 r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
359 r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
360 }
361
362 void adns__sigpipe_unprotect(adns_state ads) {
363 int r;
364
365 if (ads->iflags & adns_if_nosigpipe) return;
366
367 r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
368 r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
369 }