chiark / gitweb /
Remove "junk".
[adns.git] / src / internal.h
index 672e3a946d2661500d7323d6a57d63d895c16883..e6b16aaa9c4bd6eb62bab47f739ba05355309668 100644 (file)
@@ -5,7 +5,7 @@
  * - comments regarding library data structures
  */
 /*
- *  This file is part of adns, which is Copyright (C) 1997, 1998 Ian Jackson
+ *  This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #ifndef ADNS_INTERNAL_H_INCLUDED
 #define ADNS_INTERNAL_H_INCLUDED
 
-#define PRINTFFORMAT(a,b) __attribute__((format(printf,a,b)))
+#include "config.h"
 typedef unsigned char byte;
 
 #include <stdarg.h>
 #include <assert.h>
 #include <unistd.h>
+#include <signal.h>
+#include <errno.h>
 
 #include <sys/time.h>
 
@@ -39,19 +41,23 @@ typedef unsigned char byte;
 /* Configuration and constants */
 
 #define MAXSERVERS 5
-#define UDPMAXRETRIES /*15*/5
+#define MAXSORTLIST 15
+#define UDPMAXRETRIES 15
 #define UDPRETRYMS 2000
 #define TCPMS 30000
-#define LOCALRESOURCEMS 20
+#define MAXTTLBELIEVE (7*86400) /* any TTL > 7 days is capped */
 
 #define DNS_PORT 53
 #define DNS_MAXUDP 512
 #define DNS_MAXDOMAIN 255
 #define DNS_HDRSIZE 12
+#define DNS_IDOFFSET 0
 #define DNS_CLASS_IN 1
 
 #define DNS_INADDR_ARPA "in-addr", "arpa"
 
+#define MAX_POLLFDS  ADNS_POLLFDS_RECOMMENDED
+
 typedef enum {
   rcode_noerror,
   rcode_formaterror,
@@ -115,7 +121,7 @@ typedef struct {
    * 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.
    */
@@ -152,7 +158,7 @@ struct adns__query {
   struct { allocnode *head, *tail; } allocations;
   int interim_allocd;
   void *final_allocspace;
-  
+
   const typeinfo *typei;
   byte *query_dgram;
   int query_dglen;
@@ -170,16 +176,30 @@ struct adns__query {
    * we found a cname (this corresponds to cname_dgram in the query
    * structure).  type is set from the word go.  nrrs and rrs
    * are set together, when we find how many rrs there are.
+   * owner is set during querying unless we're doing searchlist,
+   * in which case it is set only when we find an answer.
    */
   
   byte *cname_dgram;
   int cname_dglen, cname_begin;
   /* If non-0, has been allocated using . */
+
+  vbuf search_vb;
+  int search_origlen, search_pos, search_doneabs;
+  /* Used by the searching algorithm.  The query domain in textual form
+   * is copied into the vbuf, and _origlen set to its length.  Then
+   * we walk the searchlist, if we want to.  _pos says where we are
+   * (next entry to try), and _doneabs says whether we've done the
+   * absolute query yet (0=not yet, 1=done, -1=must do straight away,
+   * but not done yet).  If flags doesn't have adns_qf_search then
+   * the vbuf is initialised but empty and everything else is zero.
+   */
   
   int id, flags, udpretries;
   int udpnextserver;
   unsigned long udpsent, tcpfailed; /* bitmap indexed by server */
   struct timeval timeout;
+  time_t expires; /* Earliest expiry time of any record we used. */
 
   qcontext ctx;
 
@@ -195,8 +215,11 @@ struct adns__query {
    *  tcpsent timew   null   >=0  irrelevant     zero        any
    *                             
    *  child   childw  set    >=0  irrelevant     irrelevant  irrelevant
+   *  child   NONE    null   >=0  irrelevant     irrelevant  irrelevant
    *  done    output  null   -1   irrelevant     irrelevant  irrelevant
    *
+   * Queries are only not on a queue when they are actually being processed.
+   *
    *                         +------------------------+
    *             START -----> |      udp/NONE          |
    *                         +------------------------+
@@ -239,15 +262,24 @@ struct adns__query {
 struct adns__state {
   adns_initflags iflags;
   FILE *diagfile;
+  int configerrno;
   struct { adns_query head, tail; } timew, childw, output;
+  adns_query forallnext;
   int nextid, udpsocket, tcpsocket;
   vbuf tcpsend, tcprecv;
-  int nservers, tcpserver;
+  int nservers, nsortlist, nsearchlist, searchndots, tcpserver;
   enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
   struct timeval tcptimeout;
+  struct sigaction stdsigpipe;
+  sigset_t stdsigmask;
+  struct pollfd pollfds_buf[MAX_POLLFDS];
   struct server {
     struct in_addr addr;
   } servers[MAXSERVERS];
+  struct sortlist {
+    struct in_addr base, mask;
+  } sortlist[MAXSORTLIST];
+  char **searchlist;
 };
 
 /* From setup.c: */
@@ -288,19 +320,29 @@ const char *adns__diag_domain(adns_state ads, int serv, adns_query qu,
  */
   
 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
  * wrong order) 0 if a<=b (ie, order is fine).
  */
-  
+
+void adns__sigpipe_protect(adns_state);
+void adns__sigpipe_unprotect(adns_state);
+/* If SIGPIPE protection is not disabled, will block all signals except
+ * SIGPIPE, and set SIGPIPE's disposition to SIG_IGN.  (And then restore.)
+ * Each call to _protect must be followed by a call to _unprotect before
+ * any significant amount of code gets to run.
+ */
+
 /* From transmit.c: */
 
 adns_status adns__mkquery(adns_state ads, vbuf *vb, int *id_r,
                          const char *owner, int ol,
                          const typeinfo *typei, adns_queryflags flags);
-/* Assembles a query packet in vb, and returns id at *id_r. */
+/* Assembles a query packet in vb.  A new id is allocated and returned.
+ */
 
 adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r,
                                  const byte *qd_dgram, int qd_dglen, int qd_begin,
@@ -330,10 +372,10 @@ void adns__query_udp(adns_query qu, struct timeval now);
 
 /* From query.c: */
 
-int adns__internal_submit(adns_state ads, adns_query *query_r,
-                         const typeinfo *typei, vbuf *qumsg_vb, int id,
-                         adns_queryflags flags, struct timeval now,
-                         adns_status failstat, const qcontext *ctx);
+adns_status adns__internal_submit(adns_state ads, adns_query *query_r,
+                                 const typeinfo *typei, vbuf *qumsg_vb, int id,
+                                 adns_queryflags flags, struct timeval now,
+                                 const qcontext *ctx);
 /* Submits a query (for internal use, called during external submits).
  *
  * The new query is returned in *query_r, or we return adns_s_nomemory.
@@ -342,10 +384,28 @@ int adns__internal_submit(adns_state ads, adns_query *query_r,
  * the memory for it is _taken over_ by this routine whether it
  * succeeds or fails (if it succeeds, the vbuf is reused for qu->vb).
  *
- * 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.
+ *
+ * When the child query is done, ctx->callback will be called.  The
+ * child will already have been taken off both the global list of
+ * queries in ads and the list of children in the parent.  The child
+ * will be freed when the callback returns.  The parent will have been
+ * taken off the global childw queue iff this is the last child for
+ * that parent.  If there is no error detected in the callback, then
+ * it should call adns__query_done if and only if there are no more
+ * children (by checking parent->children.head).  If an error is
+ * detected in the callback it should call adns__query_fail and any
+ * remaining children will automatically be cancelled.
+ */
+
+void adns__search_next(adns_state ads, adns_query qu, struct timeval now);
+/* Walks down the searchlist for a query with adns_qf_search.
+ * The query should have just had a negative response, or not had
+ * any queries sent yet, and should not be on any queue.
+ * The query_dgram if any will be freed and forgotten and a new
+ * one constructed from the search_* members of the query.
+ *
+ * Cannot fail (in case of error, calls adns__query_fail).
  */
 
 void *adns__alloc_interim(adns_query qu, size_t sz);
@@ -373,6 +433,10 @@ void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t
  *
  * It is legal to call adns__transfer_interim with a null pointer; this
  * has no effect.
+ *
+ * _transfer_interim also ensures that the expiry time of the `to' query
+ * is no later than that of the `from' query, so that child queries'
+ * TTLs get inherited by their parents.
  */
 
 void *adns__alloc_mine(adns_query qu, size_t sz);
@@ -470,18 +534,28 @@ adns_status adns__parse_domain(adns_state ads, int serv, adns_query qu,
  * serv may be -1 and qu may be 0 - they are used for error reporting only.
  */
 
+adns_status adns__parse_domain_more(findlabel_state *fls, adns_state ads,
+                                   adns_query qu, vbuf *vb, parsedomain_flags flags,
+                                   const byte *dgram);
+/* Like adns__parse_domain, but you pass it a pre-initialised findlabel_state,
+ * for continuing an existing domain or some such of some kind.  Also, unlike
+ * _parse_domain, the domain data will be appended to vb, rather than replacing
+ * the existing contents.
+ */
+
 adns_status adns__findrr(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,
+                        int *type_r, int *class_r, unsigned long *ttl_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.
+ * The type, class, TTL and RRdata length and start are returned iff
+ * the corresponding pointer variables are not null.  type_r, class_r
+ * and ttl_r may not be null.  The TTL will be capped.
  *
  * If ownermatchedquery_r != 0 then the owner domain of this
  * RR will be compared with that in the query (or, if the query
@@ -500,7 +574,8 @@ adns_status adns__findrr(adns_query qu, int serv,
 
 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,
+                               int *type_r, int *class_r, unsigned long *ttl_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
@@ -517,16 +592,34 @@ adns_status adns__findrr_anychk(adns_query qu, int serv,
  * untruncated.
  */
 
+void adns__update_expires(adns_query qu, unsigned long ttl, struct timeval now);
+/* Updates the `expires' field in the query, so that it doesn't exceed
+ * now + ttl.
+ */
+
 int vbuf__append_quoted1035(vbuf *vb, const byte *buf, int len);
 
 /* From event.c: */
 
 void adns__tcp_broken(adns_state ads, const char *what, const char *why);
+void adns__tcp_closenext(adns_state ads);
 void adns__tcp_tryconnect(adns_state ads, struct timeval now);
 
 void adns__autosys(adns_state ads, struct timeval now);
 /* Make all the system calls we want to if the application wants us to. */
 
+void adns__must_gettimeofday(adns_state ads, const struct timeval **now_io,
+                            struct timeval *tv_buf);
+void adns__timeouts(adns_state ads, int act,
+                   struct timeval **tv_io, struct timeval *tvbuf,
+                   struct timeval now);
+int adns__pollfds(adns_state ads, struct pollfd pollfds_buf[MAX_POLLFDS]);
+void adns__fdevents(adns_state ads,
+                   const struct pollfd *pollfds, int npollfds,
+                   int maxfd, const fd_set *readfds,
+                   const fd_set *writefds, const fd_set *exceptfds,
+                   struct timeval now, int *r_r);
+
 /* Useful static inline functions: */
 
 static inline void timevaladd(struct timeval *tv_io, long ms) {
@@ -542,9 +635,11 @@ static inline void timevaladd(struct timeval *tv_io, long ms) {
 static inline int ctype_whitespace(int c) { return c==' ' || c=='\n' || c=='\t'; }
 static inline int ctype_digit(int c) { return c>='0' && c<='9'; }
 static inline int ctype_alpha(int c) {
-  return (c >= 'a' && c <= 'z') || (c >= 'A' || c <= 'Z');
+  return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
 }
 
+static inline int errno_resources(int e) { return e==ENOMEM || e==ENOBUFS; }
+
 /* Useful macros */
 
 #define MEM_ROUND(sz) \
@@ -552,6 +647,7 @@ static inline int ctype_alpha(int c) {
    * sizeof(union maxalign) )
 
 #define LIST_INIT(list) ((list).head= (list).tail= 0)
+#define LINK_INIT(link) ((link).next= (link).back= 0)
 
 #define LIST_UNLINK_PART(list,node,part) \
   do { \
@@ -575,5 +671,11 @@ static inline int ctype_alpha(int c) {
 #define GETIL_B(cb) (((dgram)[(cb)++]) & 0x0ff)
 #define GET_B(cb,tv) ((tv)= GETIL_B((cb)))
 #define GET_W(cb,tv) ((tv)=0, (tv)|=(GETIL_B((cb))<<8), (tv)|=GETIL_B(cb), (tv))
+#define GET_L(cb,tv) ( (tv)=0, \
+                      (tv)|=(GETIL_B((cb))<<24), \
+                      (tv)|=(GETIL_B((cb))<<16), \
+                      (tv)|=(GETIL_B((cb))<<8), \
+                      (tv)|=GETIL_B(cb), \
+                      (tv) )
 
 #endif