chiark / gitweb /
Fix typo in changelog entry for 1.6.1
[adns.git] / src / check.c
1 /*
2  * check.c
3  * - consistency checks
4  */
5 /*
6  *  This file is part of adns, which is Copyright Ian Jackson
7  *  and contributors (see the file INSTALL for full details).
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 3, 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  */
22
23 #include "internal.h"
24
25 void adns_checkconsistency(adns_state ads, adns_query qu) {
26   adns__consistency(ads,qu,cc_user);
27 }
28
29 #define DLIST_CHECK(list, nodevar, part, body)                  \
30   if ((list).head) {                                            \
31     assert(! (list).head->part back);                           \
32     for ((nodevar)= (list).head;                                \
33          (nodevar);                                             \
34          (nodevar)= (nodevar)->part next) {                     \
35       assert((nodevar)->part next                               \
36              ? (nodevar) == (nodevar)->part next->part back     \
37              : (nodevar) == (list).tail);                       \
38       body                                                      \
39     }                                                           \
40   }
41
42 #define DLIST_ASSERTON(node, nodevar, list, part)       \
43   do {                                                  \
44     for ((nodevar)= (list).head;                        \
45          (nodevar) != (node);                           \
46          (nodevar)= (nodevar)->part next) {             \
47       assert((nodevar));                                \
48     }                                                   \
49   } while(0)
50
51 static void checkc_query_alloc(adns_state ads, adns_query qu) {
52   allocnode *an;
53
54   DLIST_CHECK(qu->allocations, an, , {
55   });
56 }
57
58 static void checkc_query(adns_state ads, adns_query qu) {
59   adns_query child;
60
61   assert(qu->udpnextserver < ads->nservers);
62   assert(!(qu->udpsent & (~0UL << ads->nservers)));
63   assert(qu->search_pos <= ads->nsearchlist);
64   if (qu->parent) DLIST_ASSERTON(qu, child, qu->parent->children, siblings.);
65 }
66
67 static void checkc_notcpbuf(adns_state ads) {
68   assert(!ads->tcpsend.used);
69   assert(!ads->tcprecv.used);
70   assert(!ads->tcprecv_skip);
71 }
72
73 static void checkc_global(adns_state ads) {
74   const struct sortlist *sl;
75   int i;
76   
77   assert(ads->udpsockets >= 0);
78
79   for (i=0; i<ads->nsortlist; i++) {
80     sl= &ads->sortlist[i];
81     assert(adns__addr_matches(sl->base.sa.sa_family,
82                               adns__sockaddr_addr(&sl->base.sa),
83                               &sl->base,&sl->mask));
84   }
85
86   assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers);
87   
88   switch (ads->tcpstate) {
89   case server_connecting:
90     assert(ads->tcpsocket >= 0);
91     checkc_notcpbuf(ads);
92     break;
93   case server_disconnected:
94   case server_broken:
95     assert(ads->tcpsocket == -1);
96     checkc_notcpbuf(ads);
97     break;
98   case server_ok:
99     assert(ads->tcpsocket >= 0);
100     assert(ads->tcprecv_skip <= ads->tcprecv.used);
101     break;
102   default:
103     assert(!"ads->tcpstate value");
104   }
105
106   assert(ads->searchlist || !ads->nsearchlist);
107 }
108
109 static void checkc_queue_udpw(adns_state ads) {
110   adns_query qu;
111   
112   DLIST_CHECK(ads->udpw, qu, , {
113     assert(qu->state==query_tosend);
114     assert(qu->retries <= UDPMAXRETRIES);
115     assert(qu->udpsent);
116     assert(!qu->children.head && !qu->children.tail);
117     checkc_query(ads,qu);
118     checkc_query_alloc(ads,qu);
119   });
120 }
121
122 static void checkc_queue_tcpw(adns_state ads) {
123   adns_query qu;
124   
125   DLIST_CHECK(ads->tcpw, qu, , {
126     assert(qu->state==query_tcpw);
127     assert(!qu->children.head && !qu->children.tail);
128     assert(qu->retries <= ads->nservers+1);
129     checkc_query(ads,qu);
130     checkc_query_alloc(ads,qu);
131   });
132 }
133
134 static void checkc_queue_childw(adns_state ads) {
135   adns_query parent, child, search;
136
137   DLIST_CHECK(ads->childw, parent, , {
138     assert(parent->state == query_childw);
139     assert(parent->children.head);
140     DLIST_CHECK(parent->children, child, siblings., {
141       assert(child->parent == parent);
142       if (child->state == query_done) {
143         for (search= ads->intdone.head; search; search= search->next)
144           if (search==child) goto child_done_ok;
145         assert(!"done child not on intdone");
146       child_done_ok:;
147       }
148     });
149     checkc_query(ads,parent);
150     checkc_query_alloc(ads,parent);
151   });
152 }
153
154 static void checkc_query_done(adns_state ads, adns_query qu) {
155   assert(qu->state == query_done);
156   assert(!qu->children.head && !qu->children.tail);
157   checkc_query(ads,qu);
158 }
159
160 static void checkc_queue_output(adns_state ads) {
161   adns_query qu;
162   
163   DLIST_CHECK(ads->output, qu, , {
164     assert(!qu->parent);
165     assert(!qu->allocations.head && !qu->allocations.tail);
166     checkc_query_done(ads,qu);
167   });
168 }
169
170 static void checkc_queue_intdone(adns_state ads) {
171   adns_query qu;
172   
173   DLIST_CHECK(ads->intdone, qu, , {
174     assert(qu->parent);
175     assert(qu->ctx.callback);
176     checkc_query_done(ads,qu);
177   });
178 }
179
180 void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc) {
181   adns_query search;
182   
183   switch (cc) {
184   case cc_user:
185     break;
186   case cc_enter:
187     if (!(ads->iflags & adns_if_checkc_entex)) return;
188     break;
189   case cc_exit:
190     if (!(ads->iflags & adns_if_checkc_entex)) return;
191     assert(!ads->intdone.head);
192     break;
193   case cc_freq:
194     if ((ads->iflags & adns_if_checkc_freq) != adns_if_checkc_freq) return;
195     break;
196   default:
197     abort();
198   }
199
200   checkc_global(ads);
201   checkc_queue_udpw(ads);
202   checkc_queue_tcpw(ads);
203   checkc_queue_childw(ads);
204   checkc_queue_output(ads);
205   checkc_queue_intdone(ads);
206
207   if (qu) {
208     switch (qu->state) {
209     case query_tosend:
210       DLIST_ASSERTON(qu, search, ads->udpw, );
211       break;
212     case query_tcpw:
213       DLIST_ASSERTON(qu, search, ads->tcpw, );
214       break;
215     case query_childw:
216       DLIST_ASSERTON(qu, search, ads->childw, );
217       break;
218     case query_done:
219       if (qu->parent)
220         DLIST_ASSERTON(qu, search, ads->intdone, );
221       else
222         DLIST_ASSERTON(qu, search, ads->output, );
223       break;
224     default:
225       assert(!"specific query state");
226     }
227   }
228 }