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