1 /* 2 * check.c 3 * - consistency checks 4 */ 5 /* 6 * This file is 7 * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk> 8 * 9 * It is part of adns, which is 10 * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk> 11 * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at> 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License as published by 15 * the Free Software Foundation; either version 2, or (at your option) 16 * any later version. 17 * 18 * This program is distributed in the hope that it will be useful, 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 21 * GNU General Public License for more details. 22 * 23 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software Foundation, 25 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 26 */ 27 28 #include "internal.h" 29 30 void adns_checkconsistency(adns_state ads, adns_query qu) { 31 adns__consistency(ads,qu,cc_user); 32 } 33 34 /* The original macro. Too gnuish for other compilers */ 35 #if 0 36 #define DLIST_CHECK(list, nodevar, part, body) \ 37 if ((list).head) { \ 38 assert(! (list).head->part back); \ 39 for ((nodevar)= (list).head; (nodevar); (nodevar)= (nodevar)->part next) { \ 40 assert((nodevar)->part next \ 41 ? (nodevar) == (nodevar)->part next->part back \ 42 : (nodevar) == (list).tail); \ 43 body \ 44 } \ 45 } 46 #endif /* 0 */ 47 48 #define DLIST_CHECK1(list, nodevar, body) \ 49 if ((list).head) { \ 50 assert(! (list).head->back); \ 51 for ((nodevar)= (list).head; (nodevar); (nodevar)= (nodevar)->next) { \ 52 assert((nodevar)->next \ 53 ? (nodevar) == (nodevar)->next->back \ 54 : (nodevar) == (list).tail); \ 55 body \ 56 } \ 57 } 58 59 #define DLIST_CHECK2(list, nodevar, part, body) \ 60 if ((list).head) { \ 61 assert(! (list).head->part.back); \ 62 for ((nodevar)= (list).head; (nodevar); (nodevar)= (nodevar)->part.next) { \ 63 assert((nodevar)->part.next \ 64 ? (nodevar) == (nodevar)->part.next->part.back \ 65 : (nodevar) == (list).tail); \ 66 body \ 67 } \ 68 } 69 70 #define DLIST_ASSERTON(node, nodevar, list, part) \ 71 do { \ 72 for ((nodevar)= (list).head; \ 73 (nodevar) != (node); \ 74 (nodevar)= (nodevar)->part next) { \ 75 assert((nodevar)); \ 76 } \ 77 } while(0) 78 79 static void checkc_query_alloc(adns_state ads, adns_query qu) { 80 allocnode *an; 81 82 83 DLIST_CHECK1(qu->allocations, an, { 84 }); 85 } 86 87 static void checkc_query(adns_state ads, adns_query qu) { 88 adns_query child; 89 90 assert(qu->udpnextserver < ads->nservers); 91 assert(!(qu->udpsent & (~0UL << ads->nservers))); 92 assert(qu->search_pos <= ads->nsearchlist); 93 if (qu->parent) DLIST_ASSERTON(qu, child, qu->parent->children, siblings.); 94 } 95 96 static void checkc_notcpbuf(adns_state ads) { 97 assert(!ads->tcpsend.used); 98 assert(!ads->tcprecv.used); 99 assert(!ads->tcprecv_skip); 100 } 101 102 static void checkc_global(adns_state ads) { 103 int i; 104 105 assert(ads->udpsocket >= 0); 106 107 for (i=0; i<ads->nsortlist; i++) 108 assert(!(ads->sortlist[i].base.s_addr & ~ads->sortlist[i].mask.s_addr)); 109 110 assert(ads->tcpserver >= 0 && ads->tcpserver < ads->nservers); 111 112 switch (ads->tcpstate) { 113 case server_connecting: 114 assert(ads->tcpsocket >= 0); 115 checkc_notcpbuf(ads); 116 break; 117 case server_disconnected: 118 case server_broken: 119 assert(ads->tcpsocket == -1); 120 checkc_notcpbuf(ads); 121 break; 122 case server_ok: 123 assert(ads->tcpsocket >= 0); 124 assert(ads->tcprecv_skip <= ads->tcprecv.used); 125 break; 126 default: 127 assert(!"ads->tcpstate value"); 128 } 129 130 assert(ads->searchlist || !ads->nsearchlist); 131 } 132 133 static void checkc_queue_udpw(adns_state ads) { 134 adns_query qu; 135 136 DLIST_CHECK1(ads->udpw, qu, { 137 assert(qu->state==query_tosend); 138 assert(qu->retries <= UDPMAXRETRIES); 139 assert(qu->udpsent); 140 assert(!qu->children.head && !qu->children.tail); 141 checkc_query(ads,qu); 142 checkc_query_alloc(ads,qu); 143 }); 144 } 145 146 static void checkc_queue_tcpw(adns_state ads) { 147 adns_query qu; 148 149 DLIST_CHECK1(ads->tcpw, qu, { 150 assert(qu->state==query_tcpw); 151 assert(!qu->children.head && !qu->children.tail); 152 assert(qu->retries <= ads->nservers+1); 153 checkc_query(ads,qu); 154 checkc_query_alloc(ads,qu); 155 }); 156 } 157 158 static void checkc_queue_childw(adns_state ads) { 159 adns_query parent, child; 160 161 DLIST_CHECK1(ads->childw, parent, { 162 assert(parent->state == query_childw); 163 assert(parent->children.head); 164 DLIST_CHECK2(parent->children, child, siblings, { 165 assert(child->parent == parent); 166 assert(child->state != query_done); 167 }); 168 checkc_query(ads,parent); 169 checkc_query_alloc(ads,parent); 170 }); 171 } 172 173 static void checkc_queue_output(adns_state ads) { 174 adns_query qu; 175 176 DLIST_CHECK1(ads->output, qu, { 177 assert(qu->state == query_done); 178 assert(!qu->children.head && !qu->children.tail); 179 assert(!qu->parent); 180 assert(!qu->allocations.head && !qu->allocations.tail); 181 checkc_query(ads,qu); 182 }); 183 } 184 185 void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc) { 186 adns_query search; 187 188 switch (cc) { 189 case cc_user: 190 break; 191 case cc_entex: 192 if (!(ads->iflags & adns_if_checkc_entex)) return; 193 break; 194 case cc_freq: 195 if ((ads->iflags & adns_if_checkc_freq) != adns_if_checkc_freq) return; 196 break; 197 default: 198 abort(); 199 } 200 201 checkc_global(ads); 202 checkc_queue_udpw(ads); 203 checkc_queue_tcpw(ads); 204 checkc_queue_childw(ads); 205 checkc_queue_output(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 DLIST_ASSERTON(qu, search, ads->output, ); 220 break; 221 default: 222 assert(!"specific query state"); 223 } 224 } 225 } 226