chiark / gitweb /
ab68ead3814fe18a2d9977003e60333f7cd50f0f
[adns.git] / src / internal.h
1 /**/
2
3 #ifndef ADNS_INTERNAL_H_INCLUDED
4 #define ADNS_INTERNAL_H_INCLUDED
5
6 #define PRINTFFORMAT(a,b) __attribute__((format(printf,a,b)))
7 typedef unsigned char byte;
8
9 #include <stdarg.h>
10 #include <assert.h>
11 #include <unistd.h>
12
13 #include <sys/time.h>
14
15 #include "adns.h"
16
17 /* Configuration and constants */
18
19 #define MAXSERVERS 5
20 #define UDPMAXRETRIES /*15*/5
21 #define UDPRETRYMS 2000
22 #define TCPMS 30000
23 #define LOCALRESOURCEMS 20
24
25 #define DNS_PORT 53
26 #define DNS_MAXUDP 512
27 #define DNS_MAXDOMAIN 255
28 #define DNS_HDRSIZE 12
29 #define DNS_CLASS_IN 1
30
31 typedef enum {
32   rcode_noerror,
33   rcode_formaterror,
34   rcode_servfail,
35   rcode_nxdomain,
36   rcode_notimp,
37   rcode_refused
38 } dns_rcode;
39
40 /* Shared data structures */
41
42 typedef union {
43   adns_status status;
44   char *cp;
45   adns_rrtype type;
46   int i;
47   struct in_addr ia;
48   unsigned long ul;
49 } rr_align;
50
51 typedef struct {
52   int used, avail;
53   byte *buf;
54 } vbuf;
55
56 typedef union {
57   void *ext;
58   int dmaddr_index;
59 } qcontext;
60
61 typedef struct {
62   adns_rrtype type;
63   int rrsz;
64   adns_status (*get_fn)(adns_state ads, adns_query qu, int serv,
65                         const byte *dgram, int dglen,
66                         int *cbyte_io, int max,
67                         int nsstart, int arcount, int *arstart_io,
68                         int roff, int *rcount_io);
69 } typeinfo;
70
71 struct adns__query {
72   /* FIXME: make sure this is all init'd properly */
73   enum { query_udp, query_tcpwait, query_tcpsent, query_child, query_done } state;
74   adns_query back, next, parent;
75   struct { adns_query head, tail; } children;
76   struct { adns_query back, next; } siblings;
77   
78   const typeinfo *typei;
79   vbuf ans;
80   int id, flags, udpretries;
81   int udpnextserver;
82   unsigned long udpsent, tcpfailed; /* bitmap indexed by server */
83   struct timeval timeout;
84   byte *querymsg;
85   int querylen, cnameoff, rrsoff;
86   qcontext context;
87   char owner[1];
88   /* After the owner name and nul comes the query message, pointed to by querymsg */
89
90   /* Possible states:
91    *
92    *  state   Queue   child  id   answer    nextudpserver  sentudp     failedtcp
93    *
94    *  udp     NONE    null   >=0  null      0              zero        zero
95    *  udp     timew   null   >=0  null      any            nonzero     zero
96    *  udp     NONE    null   >=0  null      any            nonzero     zero
97    *
98    *  tcpwait timew   null   >=0  null      irrelevant     zero        any
99    *  tcpsent timew   null   >=0  null      irrelevant     zero        any
100    *
101    *  child   childw  set    >=0  partial   irrelevant     irrelevant  irrelevant
102    *  done    output  null   -1   set/null  irrelevant     irrelevant  irrelevant
103    *
104    *                          +------------------------+
105    *             START -----> |      udp/NONE          |
106    *                          +------------------------+
107    *                         /                       |\  \
108    *        too big for UDP /             UDP timeout  \  \ send via UDP
109    *        do this ASAP!  /              more retries  \  \   do this ASAP!
110    *                     |_                  desired     \  _|
111    *              +---------------+                     +-----------+
112    *              | tcpwait/timew | ____                | udp/timew |
113    *              +---------------+     \               +-----------+
114    *                    |  ^             |                 | |
115    *     TCP conn'd;    |  | TCP died    |                 | |
116    *     send via TCP   |  | more        |     UDP timeout | |
117    *     do this ASAP!  |  | servers     |      no more    | |
118    *                    v  | to try      |      retries    | |
119    *              +---------------+      |      desired    | |
120    *              | tcpsent/timew | ____ |                 | |
121    *              +---------------+     \|                 | |
122    *                  \   \ TCP died     | TCP             | |
123    *                   \   \ no more     | timeout         / |
124    *                    \   \ servers    |                /  |
125    *                     \   \ to try    |               /   |
126    *                  got \   \          v             |_    / got
127    *                 reply \   _| +------------------+      / reply
128    *                        \     | done/output FAIL |     /
129    *                         \    +------------------+    /
130    *                          \                          /
131    *                           _|                      |_
132    *                             (..... got reply ....)
133    *                              /                   \
134    *        need child query/ies /                     \ no child query
135    *                            /                       \
136    *                          |_                         _|
137    *                +--------------+                   +----------------+
138    *                | child/childw | ----------------> | done/output OK |
139    *                +--------------+  children done    +----------------+
140    */
141 };
142
143 struct adns__state {
144   adns_initflags iflags;
145   FILE *diagfile;
146   struct { adns_query head, tail; } timew, childw, output;
147   int nextid, udpsocket, tcpsocket;
148   vbuf rqbuf, tcpsend, tcprecv;
149   int nservers, tcpserver;
150   enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
151   struct timeval tcptimeout;
152   struct server {
153     struct in_addr addr;
154   } servers[MAXSERVERS];
155 };
156
157 /* From setup.c: */
158
159 void adns__vdiag(adns_state ads, const char *pfx, adns_initflags prevent,
160                  int serv, const char *fmt, va_list al);
161 void adns__debug(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
162 void adns__warn(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
163 void adns__diag(adns_state ads, int serv, const char *fmt, ...) PRINTFFORMAT(3,4);
164
165 int adns__vbuf_ensure(vbuf *vb, int want);
166 int adns__vbuf_append(vbuf *vb, const byte *data, int len);
167 int adns__vbuf_malloc(vbuf *vb, size_t len);
168 /* 1=>success, 0=>realloc failed */
169 void adns__vbuf_appendq(vbuf *vb, const byte *data, int len);
170 void adns__vbuf_init(vbuf *vb);
171
172 int adns__setnonblock(adns_state ads, int fd); /* => errno value */
173
174 /* From submit.c: */
175
176 void adns__query_nomem(adns_state ads, adns_query qu);
177 void adns__query_finish(adns_state ads, adns_query qu, adns_status stat);
178 void adns__query_fail(adns_state ads, adns_query qu, adns_status stat);
179
180 /* From query.c: */
181
182 void adns__query_udp(adns_state ads, adns_query qu, struct timeval now);
183 void adns__query_tcp(adns_state ads, adns_query qu, struct timeval now);
184 adns_status adns__mkquery(adns_state ads, const char *owner, int ol, int id,
185                           const typeinfo *typei, adns_queryflags flags);
186
187 /* From reply.c: */
188
189 void adns__procdgram(adns_state ads, const byte *dgram, int len,
190                      int serv, struct timeval now);
191
192 /* From types.c: */
193
194 const typeinfo *adns__findtype(adns_rrtype type);
195
196 /* From parse.c: */
197
198 int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len);
199
200 adns_status adns__get_label(const byte *dgram, int dglen, int *max_io,
201                             int *cbyte_io, int *lablen_r, int *labstart_r,
202                             int *namelen_io);
203 adns_status adns__get_domain_perm(adns_state ads, adns_query qu, int serv,
204                                   const byte *dgram, int dglen,
205                                   int *cbyte_io, int max, int *domainstart_r);
206 adns_status adns__get_domain_temp(adns_state ads, adns_query qu, int serv,
207                                   const byte *dgram, int dglen,
208                                   int *cbyte_io, int max, int *domainstart_r);
209 adns_status adns__get_rr_temp(adns_state ads, adns_query qu, int serv,
210                               const byte *dgram, int dglen, int *cbyte_io,
211                               int *type_r, int *class_r, int *rdlen_r, int *rdstart_r,
212                               const byte *eo_dgram, int eo_dglen, int eo_cbyte,
213                               int *eo_matched_r);
214
215 /* From event.c: */
216
217 void adns__tcp_broken(adns_state ads, const char *what, const char *why);
218 void adns__tcp_tryconnect(adns_state ads, struct timeval now);
219 void adns__autosys(adns_state ads, struct timeval now);
220
221 /* Useful static inline functions: */
222
223 static inline void timevaladd(struct timeval *tv_io, long ms) {
224   struct timeval tmp;
225   assert(ms>=0);
226   tmp= *tv_io;
227   tmp.tv_usec += (ms%1000)*1000000;
228   tmp.tv_sec += ms/1000;
229   if (tmp.tv_usec >= 1000000) { tmp.tv_sec++; tmp.tv_usec -= 1000; }
230   *tv_io= tmp;
231 }
232
233 static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
234 static inline int ctype_digit(int c) { return c>='0' && c<='9'; }
235 static inline int ctype_alpha(int c) {
236   return (c >= 'a' && c <= 'z') || (c >= 'A' || c <= 'Z');
237 }
238
239 /* Useful macros */
240
241 #define LIST_INIT(list) ((list).head= (list).tail= 0)
242
243 #define LIST_UNLINK_PART(list,node,part) \
244   do { \
245     if ((node)->back) (node)->back->part next= (node)->part next; \
246       else                        (list).head= (node)->part next; \
247     if ((node)->next) (node)->next->part back= (node)->part back; \
248       else                        (list).tail= (node)->part back; \
249   } while(0)
250
251 #define LIST_LINK_TAIL_PART(list,node,part) \
252   do { \
253     (node)->part back= 0; \
254     (node)->part next= (list).tail; \
255     if ((list).tail) (list).tail->part back= (node); else (list).part head= (node); \
256     (list).tail= (node); \
257   } while(0)
258
259 #define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,)
260 #define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,)
261
262 #define GETIL_B(cb) (dgram[(cb)++])
263 #define GET_B(cb,tv) ((tv)= GETIL_B((cb)))
264 #define GET_W(cb,tv) ((tv)=0, (tv)|=(GETIL_B((cb))<<8), (tv)|=GETIL_B(cb), (tv))
265
266 #endif