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