chiark / gitweb /
Use struct sockaddr in several places; distinguish various places where
[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, 1998 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
26 #include <arpa/inet.h>
27
28 #include "internal.h"
29
30 /* Core diagnostic functions */
31
32 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
33                  int serv, adns_query qu, const char *fmt, va_list al) {
34   const char *bef, *aft;
35   vbuf vb;
36   if (!(ads->iflags & adns_if_debug) && (!prevent || (ads->iflags & prevent))) return;
37
38   fprintf(stderr,"adns%s: ",pfx);
39
40   vfprintf(stderr,fmt,al);
41
42   bef= " (";
43   aft= "\n";
44
45   if (qu && qu->query_dgram) {
46     adns__vbuf_init(&vb);
47     fprintf(stderr,"%sQNAME=%s, QTYPE=%s",
48             bef,
49             adns__diag_domain(qu->ads,-1,0, &vb,
50                               qu->query_dgram,qu->query_dglen,DNS_HDRSIZE),
51             qu->typei ? qu->typei->rrtname : "<unknown>");
52     if (qu->typei && qu->typei->fmtname)
53       fprintf(stderr,"(%s)",qu->typei->fmtname);
54     bef=", "; aft=")\n";
55   }
56   
57   if (serv>=0) {
58     fprintf(stderr,"%sNS=%s",bef,inet_ntoa(ads->servers[serv].addr));
59     bef=", "; aft=")\n";
60   }
61
62   fputs(aft,stderr);
63 }
64
65 void adns__debug(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
66   va_list al;
67
68   va_start(al,fmt);
69   adns__vdiag(ads," debug",0,serv,qu,fmt,al);
70   va_end(al);
71 }
72
73 void adns__warn(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
74   va_list al;
75
76   va_start(al,fmt);
77   adns__vdiag(ads," warning",adns_if_noerrprint|adns_if_noserverwarn,serv,qu,fmt,al);
78   va_end(al);
79 }
80
81 void adns__diag(adns_state ads, int serv, adns_query qu, const char *fmt, ...) {
82   va_list al;
83
84   va_start(al,fmt);
85   adns__vdiag(ads,"",adns_if_noerrprint,serv,qu,fmt,al);
86   va_end(al);
87 }
88
89 /* vbuf functions */
90
91 void adns__vbuf_init(vbuf *vb) {
92   vb->used= vb->avail= 0; vb->buf= 0;
93 }
94
95 int adns__vbuf_ensure(vbuf *vb, int want) {
96   void *nb;
97   
98   if (vb->avail >= want) return 1;
99   nb= realloc(vb->buf,want); if (!nb) return 0;
100   vb->buf= nb;
101   vb->avail= want;
102   return 1;
103 }
104   
105 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len) {
106   memcpy(vb->buf+vb->used,data,len);
107   vb->used+= len;
108 }
109
110 int adns__vbuf_append(vbuf *vb, const byte *data, int len) {
111   int newlen;
112   void *nb;
113
114   newlen= vb->used+len;
115   if (vb->avail < newlen) {
116     if (newlen<20) newlen= 20;
117     newlen <<= 1;
118     nb= realloc(vb->buf,newlen);
119     if (!nb) { newlen= vb->used+len; nb= realloc(vb->buf,newlen); }
120     if (!nb) return 0;
121     vb->buf= nb;
122     vb->avail= newlen;
123   }
124   adns__vbuf_appendq(vb,data,len);
125   return 1;
126 }
127
128 int adns__vbuf_appendstr(vbuf *vb, const char *data) {
129   int l;
130   l= strlen(data);
131   return adns__vbuf_append(vb,data,l);
132 }
133
134 void adns__vbuf_free(vbuf *vb) {
135   free(vb->buf);
136   adns__vbuf_init(vb);
137 }
138
139 /* Additional diagnostic functions */
140
141 const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
142                               vbuf *vb, const byte *dgram, int dglen, int cbyte) {
143   adns_status st;
144
145   st= adns__parse_domain(ads,serv,qu,vb, pdf_quoteok, dgram,dglen,&cbyte,dglen);
146   if (st == adns_s_nolocalmem) {
147     return "<cannot report domain... out of memory>";
148   }
149   if (st) {
150     vb->used= 0;
151     if (!(adns__vbuf_appendstr(vb,"<bad format... ") &&
152           adns__vbuf_appendstr(vb,adns_strerror(st)) &&
153           adns__vbuf_appendstr(vb,">") &&
154           adns__vbuf_append(vb,"",1))) {
155       return "<cannot report bad format... out of memory>";
156     }
157   }
158   if (!vb->used) {
159     adns__vbuf_appendstr(vb,"<truncated ...>");
160     adns__vbuf_append(vb,"",1);
161   }
162   return vb->buf;
163 }
164
165 adns_status adns_rr_info(adns_rrtype type,
166                          const char **rrtname_r, const char **fmtname_r,
167                          int *len_r,
168                          const void *datap, char **data_r) {
169   const typeinfo *typei;
170   vbuf vb;
171   adns_status st;
172
173   typei= adns__findtype(type);
174   if (!typei) return adns_s_notimplemented;
175
176   if (rrtname_r) *rrtname_r= typei->rrtname;
177   if (fmtname_r) *fmtname_r= typei->fmtname;
178   if (len_r) *len_r= typei->rrsz;
179
180   if (!datap) return adns_s_ok;
181   
182   adns__vbuf_init(&vb);
183   st= typei->convstring(&vb,datap);
184   if (st) goto x_freevb;
185   if (!adns__vbuf_append(&vb,"",1)) { st= adns_s_nolocalmem; goto x_freevb; }
186   assert(strlen(vb.buf) == vb.used-1);
187   *data_r= realloc(vb.buf,vb.used);
188   if (!*data_r) *data_r= vb.buf;
189   return adns_s_ok;
190
191  x_freevb:
192   adns__vbuf_free(&vb);
193   return st;
194 }
195
196 #define SINFO(n,s) { adns_s_##n, s }
197
198 static const struct sinfo {
199   adns_status st;
200   const char *string;
201 } sinfos[]= {
202   SINFO(  ok,                  "OK"                                    ),
203   SINFO(  timeout,             "Timed out"                             ),
204   SINFO(  nolocalmem,          "Out of memory"                         ),
205   SINFO(  allservfail,         "No working nameservers"                ),
206   SINFO(  servfail,            "Nameserver failure"                    ),
207   SINFO(  notimplemented,      "Query not implemented"                 ),
208   SINFO(  refused,             "Refused by nameserver"                 ),
209   SINFO(  reasonunknown,       "Reason unknown"                        ),
210   SINFO(  norecurse,           "Recursion denied by nameserver"        ),
211   SINFO(  serverfaulty,        "Nameserver sent bad data"              ),
212   SINFO(  unknownreply,        "Reply from nameserver not understood"  ),
213   SINFO(  invaliddata,         "Invalid data"                          ),
214   SINFO(  inconsistent,        "Inconsistent data"                     ),
215   SINFO(  cname,               "RR refers to an alias"                 ),
216   SINFO(  invalidanswerdomain, "Received syntactically invalid domain" ),
217   SINFO(  nxdomain,            "No such domain"                        ),
218   SINFO(  nodata,              "No such data"                          ),
219   SINFO(  invalidquerydomain,  "Domain syntactically invalid"          ),
220   SINFO(  domaintoolong,       "Domain name too long"                  )
221 };
222
223 static int si_compar(const void *key, const void *elem) {
224   const adns_status *st= key;
225   const struct sinfo *si= elem;
226
227   return *st < si->st ? -1 : *st > si->st ? 1 : 0;
228 }
229
230 const char *adns_strerror(adns_status st) {
231   static char buf[100];
232
233   const struct sinfo *si;
234
235   si= bsearch(&st,sinfos,sizeof(sinfos)/sizeof(*si),sizeof(*si),si_compar);
236   if (si) return si->string;
237   
238   snprintf(buf,sizeof(buf),"code %d",st);
239   return buf;
240 }