/* Configuration and constants */
#define MAXSERVERS 5
-#define UDPMAXRETRIES /*15*/5
+#define MAXSORTLIST 15
+#define UDPMAXRETRIES /*15 fixme*/5
#define UDPRETRYMS 2000
#define TCPMS 30000
#define LOCALRESOURCEMS 20
#define DNS_HDRSIZE 12
#define DNS_CLASS_IN 1
+#define DNS_INADDR_ARPA "in-addr", "arpa"
+
typedef enum {
rcode_noerror,
rcode_formaterror,
byte *buf;
} vbuf;
-typedef union {
- void *ext;
- int dmaddr_index;
-} qcontext;
+typedef struct {
+ adns_state ads;
+ adns_query qu;
+ int serv;
+ const byte *dgram;
+ int dglen, nsstart, nscount, arcount;
+ struct timeval now;
+} parseinfo;
typedef struct {
adns_rrtype type;
* and will not be null-terminated by convstring.
*/
- adns_status (*parse)(adns_query qu, int serv,
- const byte *dgram, int dglen, int cbyte, int max,
- int nsstart, int *arstart_io, void *store_r);
+ adns_status (*parse)(const parseinfo *pai, int cbyte, int max, void *store_r);
/* Parse one RR, in dgram of length dglen, starting at cbyte and
* extending until at most max.
*
* If there is an overrun which might indicate truncation, it should set
* *rdstart to -1; otherwise it may set it to anything else positive.
*
- * nsstart is the offset of the authority section; *arstart_io is
- * -1 or the offset of the additional section; if it is -1 then
- * parse may set it to the correct offset.
+ * nsstart is the offset of the authority section.
*/
- int (*diff_needswap)(const void *datap_a, const void *datap_b);
+ int (*diff_needswap)(adns_state ads, const void *datap_a, const void *datap_b);
/* Returns !0 if RR a should be strictly after RR b in the sort order,
* 0 otherwise. Must not fail.
*/
} typeinfo;
typedef struct allocnode {
- struct allocnode *next;
+ struct allocnode *next, *back;
} allocnode;
union maxalign {
union maxalign *up;
} data;
+typedef struct {
+ void *ext;
+ void (*callback)(adns_query parent, adns_query child);
+ union {
+ adns_rr_addr ptr_parent_addr;
+ adns_rr_hostaddr *hostaddr;
+ } info;
+} qcontext;
+
struct adns__query {
adns_state ads;
enum { query_udp, query_tcpwait, query_tcpsent, query_child, query_done } state;
adns_query back, next, parent;
struct { adns_query head, tail; } children;
struct { adns_query back, next; } siblings;
- struct allocnode *allocations;
+ struct { allocnode *head, *tail; } allocations;
int interim_allocd;
void *final_allocspace;
int udpnextserver;
unsigned long udpsent, tcpfailed; /* bitmap indexed by server */
struct timeval timeout;
- qcontext context;
+
+ qcontext ctx;
/* Possible states:
*
struct adns__state {
adns_initflags iflags;
FILE *diagfile;
+ int configerrno;
struct { adns_query head, tail; } timew, childw, output;
int nextid, udpsocket, tcpsocket;
vbuf tcpsend, tcprecv;
- int nservers, tcpserver;
+ int nservers, nsortlist, tcpserver;
enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
struct timeval tcptimeout;
struct server {
struct in_addr addr;
} servers[MAXSERVERS];
+ struct sortlist {
+ struct in_addr base, mask;
+ } sortlist[MAXSORTLIST];
};
/* From setup.c: */
*/
void adns__isort(void *array, int nobjs, int sz, void *tempbuf,
- int (*needswap)(const void *a, const void *b));
+ int (*needswap)(void *context, const void *a, const void *b),
+ void *context);
/* Does an insertion sort of array which must contain nobjs objects
* each sz bytes long. tempbuf must point to a buffer at least
* sz bytes long. needswap should return !0 if a>b (strictly, ie
* If failstat is nonzero then if we are successful in creating the query
* it is immediately failed with code failstat (but _submit still succeds).
*
- * ctx is copied byte-for-byte into the query.
+ * *ctx is copied byte-for-byte into the query.
*/
void *adns__alloc_interim(adns_query qu, size_t sz);
* but it will not necessarily return a distinct pointer each time.
*/
+void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz);
+/* Transfers an interim allocation from one query to another, so that
+ * the `to' query will have room for the data when we get to makefinal
+ * and so that the free will happen when the `to' query is freed
+ * rather than the `from' query.
+ *
+ * It is legal to call adns__transfer_interim with a null pointer; this
+ * has no effect.
+ */
+
void *adns__alloc_mine(adns_query qu, size_t sz);
/* Like _interim, but does not record the length for later
* copying into the answer. This just ensures that the memory
const byte *dgram, int dglen, int *cbyte_io,
int *type_r, int *class_r, int *rdlen_r, int *rdstart_r,
int *ownermatchedquery_r);
- /* Finds the extent and some of the contents of an RR in a datagram
- * and does some checks. The datagram is *dgram, length dglen, and
- * the RR starts at *cbyte_io (which is updated afterwards to point
- * to the end of the RR).
- *
- * The type, class and RRdata length and start are returned iff
- * the corresponding pointer variables are not null. type_r and
- * class_r may not be null.
- *
- * If ownermatchedquery_r != 0 then the owner domain of this
- * RR will be compared with that in the query (or, if the query
- * has gone to a CNAME lookup, with the canonical name).
- * In this case, *ownermatchedquery_r will be set to 0 or 1.
- * The query datagram (or CNAME datagram) MUST be valid and not truncated.
- *
- * If there is truncation then *type_r will be set to -1 and
- * *cbyte_io, *class_r, *rdlen_r, *rdstart_r and *eo_matched_r will be
- * undefined.
- *
- * qu must obviously be non-null.
- *
- * If an error is returned then *type_r will be undefined too.
- */
+/* Finds the extent and some of the contents of an RR in a datagram
+ * and does some checks. The datagram is *dgram, length dglen, and
+ * the RR starts at *cbyte_io (which is updated afterwards to point
+ * to the end of the RR).
+ *
+ * The type, class and RRdata length and start are returned iff
+ * the corresponding pointer variables are not null. type_r and
+ * class_r may not be null.
+ *
+ * If ownermatchedquery_r != 0 then the owner domain of this
+ * RR will be compared with that in the query (or, if the query
+ * has gone to a CNAME lookup, with the canonical name).
+ * In this case, *ownermatchedquery_r will be set to 0 or 1.
+ * The query datagram (or CNAME datagram) MUST be valid and not truncated.
+ *
+ * If there is truncation then *type_r will be set to -1 and
+ * *cbyte_io, *class_r, *rdlen_r, *rdstart_r and *eo_matched_r will be
+ * undefined.
+ *
+ * qu must obviously be non-null.
+ *
+ * If an error is returned then *type_r will be undefined too.
+ */
+
+adns_status adns__findrr_anychk(adns_query qu, int serv,
+ const byte *dgram, int dglen, int *cbyte_io,
+ int *type_r, int *class_r, int *rdlen_r, int *rdstart_r,
+ const byte *eo_dgram, int eo_dglen, int eo_cbyte,
+ int *eo_matched_r);
+/* Like adns__findrr_checked, except that the datagram and
+ * owner to compare with can be specified explicitly.
+ *
+ * If the caller thinks they know what the owner of the RR ought to
+ * be they can pass in details in eo_*: this is another (or perhaps
+ * the same datagram), and a pointer to where the putative owner
+ * starts in that datagram. In this case *eo_matched_r will be set
+ * to 1 if the datagram matched or 0 if it did not. Either
+ * both eo_dgram and eo_matched_r must both be non-null, or they
+ * must both be null (in which case eo_dglen and eo_cbyte will be ignored).
+ * The eo datagram and contained owner domain MUST be valid and
+ * untruncated.
+ */
int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len);
#define LIST_UNLINK_PART(list,node,part) \
do { \
- if ((node)->back) (node)->back->part next= (node)->part next; \
- else (list).head= (node)->part next; \
- if ((node)->next) (node)->next->part back= (node)->part back; \
- else (list).tail= (node)->part back; \
+ if ((node)->part back) (node)->part back->part next= (node)->part next; \
+ else (list).head= (node)->part next; \
+ if ((node)->part next) (node)->part next->part back= (node)->part back; \
+ else (list).tail= (node)->part back; \
} while(0)
#define LIST_LINK_TAIL_PART(list,node,part) \
do { \
(node)->part next= 0; \
(node)->part back= (list).tail; \
- if ((list).tail) (list).tail->part next= (node); else (list).part head= (node); \
+ if ((list).tail) (list).tail->part next= (node); else (list).head= (node); \
(list).tail= (node); \
} while(0)