chiark / gitweb /
Include <sys/times.h> in a few more files. Include <unistd.h> and
[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, s }
204
205 static const struct sinfo {
206   adns_status st;
207   const char *string;
208 } sinfos[]= {
209   SINFO(  ok,                  "OK"                                            ),
210
211   SINFO(  nomemory,            "Out of memory"                                 ),
212   SINFO(  unknownrrtype,       "Query not implemented in DNS library"          ),
213
214   SINFO(  timeout,             "DNS query timed out"                           ),
215   SINFO(  allservfail,         "All nameservers failed"                        ),
216   SINFO(  norecurse,           "Recursion denied by nameserver"                ),
217   SINFO(  invalidresponse,     "Nameserver sent bad response"                  ),
218   SINFO(  unknownformat,       "Nameserver used unknown format"                ),
219
220   SINFO(  rcodeservfail,       "Nameserver reports failure"                    ),
221   SINFO(  rcodeformaterror,    "Query not understood by nameserver"            ),
222   SINFO(  rcodenotimplemented, "Query not implemented by nameserver"           ),
223   SINFO(  rcoderefused,        "Query refused by nameserver"                   ),
224   SINFO(  rcodeunknown,        "Nameserver sent unknown response code"         ),
225   
226   SINFO(  inconsistent,        "Inconsistent resource records in DNS"          ),
227   SINFO(  prohibitedcname,     "DNS data refers to an alias"                   ),
228   SINFO(  answerdomaininvalid, "Found syntactically invalid domain name"       ),
229   SINFO(  answerdomaintoolong, "Found overly-long domain name"                 ),
230   SINFO(  invaliddata,         "Found invalid DNS data"                        ),
231
232   SINFO(  querydomainwrong,    "Domain invalid for particular DNS query type"  ),
233   SINFO(  querydomaininvalid,  "Domain name is syntactically invalid"          ),
234   SINFO(  querydomaintoolong,  "Domain name is too long"                       ),
235
236   SINFO(  nxdomain,            "No such domain"                                ),
237   SINFO(  nodata,              "No such data"                                  ),
238 };
239
240 static int si_compar(const void *key, const void *elem) {
241   const adns_status *st= key;
242   const struct sinfo *si= elem;
243
244   return *st < si->st ? -1 : *st > si->st ? 1 : 0;
245 }
246
247 const char *adns_strerror(adns_status st) {
248   static char buf[100];
249
250   const struct sinfo *si;
251
252   si= bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*si),sizeof(*si),si_compar);
253   if (si) return si->string;
254   
255   snprintf(buf,sizeof(buf),"code %d",st);
256   return buf;
257 }
258
259 void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
260                  int (*needswap)(void *context, const void *a, const void *b),
261                  void *context) {
262   byte *data= array;
263   int i, place;
264
265   for (i=0; i<nobjs; i++) {
266     for (place= i;
267          place>0 && needswap(context, data + (place-1)*sz, data + i*sz);
268          place--);
269     if (place != i) {
270       memcpy(tempbuf, data + i*sz, sz);
271       memmove(data + (place+1)*sz, data + place*sz, (i-place)*sz);
272       memcpy(data + place*sz, tempbuf, sz);
273     }
274   }
275 }
276
277 /* SIGPIPE protection. */
278
279 void adns__sigpipe_protect(adns_state ads) {
280   sigset_t toblock;
281   struct sigaction sa;
282   int r;
283
284   if (ads->iflags & adns_if_nosigpipe) return;
285
286   sigfillset(&toblock);
287   sigdelset(&toblock,SIGPIPE);
288
289   sa.sa_handler= SIG_IGN;
290   sigfillset(&sa.sa_mask);
291   sa.sa_flags= 0;
292   
293   r= sigprocmask(SIG_SETMASK,&toblock,&ads->stdsigmask); assert(!r);
294   r= sigaction(SIGPIPE,&sa,&ads->stdsigpipe); assert(!r);
295 }
296
297 void adns__sigpipe_unprotect(adns_state ads) {
298   int r;
299
300   if (ads->iflags & adns_if_nosigpipe) return;
301
302   r= sigaction(SIGPIPE,&ads->stdsigpipe,0); assert(!r);
303   r= sigprocmask(SIG_SETMASK,&ads->stdsigmask,0); assert(!r);
304 }