X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=blobdiff_plain;f=src%2Finternal.h;h=719a592255c3c0a0f7002b88257bfc73ce5b0845;hp=e6b16aaa9c4bd6eb62bab47f739ba05355309668;hb=34a2240e6d24d133cd1ca0ab1845c57e28e9e9e5;hpb=8ce38e76272e9164cabef2c7fc1ea24f31364a86 diff --git a/src/internal.h b/src/internal.h index e6b16aa..719a592 100644 --- a/src/internal.h +++ b/src/internal.h @@ -5,21 +5,26 @@ * - comments regarding library data structures */ /* - * This file is part of adns, which is Copyright (C) 1997-1999 Ian Jackson - * + * This file is + * Copyright (C) 1997-1999 Ian Jackson + * + * It is part of adns, which is + * Copyright (C) 1997-1999 Ian Jackson + * Copyright (C) 1999 Tony Finch + * * 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 * the Free Software Foundation; either version 2, or (at your option) * any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef ADNS_INTERNAL_H_INCLUDED @@ -33,10 +38,12 @@ typedef unsigned char byte; #include #include #include +#include #include #include "adns.h" +#include "dlist.h" /* Configuration and constants */ @@ -44,11 +51,14 @@ typedef unsigned char byte; #define MAXSORTLIST 15 #define UDPMAXRETRIES 15 #define UDPRETRYMS 2000 -#define TCPMS 30000 +#define TCPWAITMS 30000 +#define TCPCONNMS 14000 +#define TCPIDLEMS 30000 #define MAXTTLBELIEVE (7*86400) /* any TTL > 7 days is capped */ #define DNS_PORT 53 #define DNS_MAXUDP 512 +#define DNS_MAXLABEL 63 #define DNS_MAXDOMAIN 255 #define DNS_HDRSIZE 12 #define DNS_IDOFFSET 0 @@ -58,6 +68,12 @@ typedef unsigned char byte; #define MAX_POLLFDS ADNS_POLLFDS_RECOMMENDED +typedef enum { + cc_user, + cc_entex, + cc_freq +} consistency_checks; + typedef enum { rcode_noerror, rcode_formaterror, @@ -151,18 +167,18 @@ typedef struct { struct adns__query { adns_state ads; - enum { query_udp, query_tcpwait, query_tcpsent, query_child, query_done } state; + enum { query_tosend, query_tcpw, query_childw, query_done } state; adns_query back, next, parent; struct { adns_query head, tail; } children; struct { adns_query back, next; } siblings; struct { allocnode *head, *tail; } allocations; - int interim_allocd; + int interim_allocd, preserved_allocd; void *final_allocspace; const typeinfo *typei; byte *query_dgram; int query_dglen; - + vbuf vb; /* General-purpose messing-about buffer. * Wherever a `big' interface is crossed, this may be corrupted/changed @@ -179,7 +195,7 @@ struct adns__query { * 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 . */ @@ -194,10 +210,10 @@ struct adns__query { * 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 id, flags, retries; int udpnextserver; - unsigned long udpsent, tcpfailed; /* bitmap indexed by server */ + unsigned long udpsent; /* bitmap indexed by server */ struct timeval timeout; time_t expires; /* Earliest expiry time of any record we used. */ @@ -205,44 +221,42 @@ struct adns__query { /* Possible states: * - * state Queue child id nextudpserver sentudp failedtcp - * - * udp NONE null >=0 0 zero zero - * udp timew null >=0 any nonzero zero - * udp NONE null >=0 any nonzero zero - * - * tcpwait timew null >=0 irrelevant zero any - * tcpsent timew null >=0 irrelevant zero any - * + * state Queue child id nextudpserver udpsent tcpfailed + * + * tosend NONE null >=0 0 zero zero + * tosend udpw null >=0 any nonzero zero + * tosend NONE null >=0 any nonzero zero + * + * tcpw tcpw null >=0 irrelevant any 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. + * Queries in state tcpw/tcpw have been sent (or are in the to-send buffer) + * iff the tcp connection is in state server_ok. * * +------------------------+ - * START -----> | udp/NONE | + * START -----> | tosend/NONE | * +------------------------+ * / |\ \ * too big for UDP / UDP timeout \ \ send via UDP - * do this ASAP! / more retries \ \ do this ASAP! - * |_ desired \ _| - * +---------------+ +-----------+ - * | tcpwait/timew | ____ | udp/timew | - * +---------------+ \ +-----------+ - * | ^ | | | - * TCP conn'd; | | TCP died | | | - * send via TCP | | more | UDP timeout | | - * do this ASAP! | | servers | no more | | - * v | to try | retries | | - * +---------------+ | desired | | - * | tcpsent/timew | ____ | | | - * +---------------+ \| | | - * \ \ TCP died | TCP | | - * \ \ no more | timeout / | - * \ \ servers | / | - * \ \ to try | / | - * got \ \ v |_ / got + * send via TCP / more retries \ \ + * when conn'd / desired \ \ + * | | | + * v | v + * +-----------+ +-------------+ + * | tcpw/tcpw | ________ | tosend/udpw | + * +-----------+ \ +-------------+ + * | | | UDP timeout | | + * | | | no more | | + * | | | retries | | + * \ | TCP died | desired | | + * \ \ no more | | | + * \ \ servers | TCP / | + * \ \ to try | timeout / | + * got \ \ v |_ | got * reply \ _| +------------------+ / reply * \ | done/output FAIL | / * \ +------------------+ / @@ -253,23 +267,34 @@ struct adns__query { * need child query/ies / \ no child query * / \ * |_ _| - * +--------------+ +----------------+ - * | child/childw | ----------------> | done/output OK | - * +--------------+ children done +----------------+ + * +---------------+ +----------------+ + * | childw/childw | ----------------> | done/output OK | + * +---------------+ children done +----------------+ */ }; +struct query_queue { adns_query head, tail; }; + struct adns__state { adns_initflags iflags; FILE *diagfile; int configerrno; - struct { adns_query head, tail; } timew, childw, output; + struct query_queue udpw, tcpw, childw, output; adns_query forallnext; int nextid, udpsocket, tcpsocket; + int bug_if_query_done_now; vbuf tcpsend, tcprecv; - int nservers, nsortlist, nsearchlist, searchndots, tcpserver; - enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate; + int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip; + enum adns__tcpstate { + server_disconnected, server_connecting, + server_ok, server_broken + } tcpstate; struct timeval tcptimeout; + /* This will have tv_sec==0 if it is not valid. It will always be + * valid if tcpstate _connecting. When _ok, it will be nonzero if + * we are idle (ie, tcpw queue is empty), in which case it is the + * absolute time when we will close the connection. + */ struct sigaction stdsigpipe; sigset_t stdsigmask; struct pollfd pollfds_buf[MAX_POLLFDS]; @@ -318,7 +343,7 @@ const char *adns__diag_domain(adns_state ads, int serv, adns_query qu, * Returns either vb->buf, or a pointer to a string literal. Do not modify * vb before using the return value. */ - + void adns__isort(void *array, int nobjs, int sz, void *tempbuf, int (*needswap)(void *context, const void *a, const void *b), void *context); @@ -333,7 +358,8 @@ 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. + * any significant amount of code gets to run, since the old signal mask + * is stored in the adns structure. */ /* From transmit.c: */ @@ -351,23 +377,20 @@ adns_status adns__mkquery_frdgram(adns_state ads, vbuf *vb, int *id_r, * That domain must be correct and untruncated. */ -void adns__query_tcp(adns_query qu, struct timeval now); -/* Query must be in state tcpwait/timew; it will be moved to a new state - * if possible and no further processing can be done on it for now. - * (Resulting state is one of tcpwait/timew (if server not connected), - * tcpsent/timew, child/childw or done/output.) - * - * adns__tcp_tryconnect should already have been called - _tcp - * will only use an existing connection (if there is one), which it - * may break. If the conn list lost then the caller is responsible for any - * reestablishment and retry. +void adns__querysend_tcp(adns_query qu, struct timeval now); +/* Query must be in state tcpw/tcpw; it will be sent if possible and + * no further processing can be done on it for now. The connection + * might be broken, but no reconnect will be attempted. */ -void adns__query_udp(adns_query qu, struct timeval now); -/* Query must be in state udp/NONE; it will be moved to a new state, +void adns__query_send(adns_query qu, struct timeval now); +/* Query must be in state tosend/NONE; it will be moved to a new state, * and no further processing can be done on it for now. * (Resulting state is one of udp/timew, tcpwait/timew (if server not connected), * tcpsent/timew, child/childw or done/output.) + * __query_send may decide to use either UDP or TCP depending whether + * _qf_usevc is set (or has become set) and whether the query is too + * large. */ /* From query.c: */ @@ -390,12 +413,14 @@ adns_status adns__internal_submit(adns_state ads, adns_query *query_r, * 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. + * taken off the global childw queue. + * + * The callback should either call adns__query_done, if it is + * complete, or adns__query_fail, if an error has occurred, in which + * case the other children (if any) will be cancelled. If the parent + * has more unfinished children (or has just submitted more) then the + * callback may choose to wait for them - it must then put the parent + * back on the childw queue. */ void adns__search_next(adns_state ads, adns_query qu, struct timeval now); @@ -409,20 +434,27 @@ void adns__search_next(adns_state ads, adns_query qu, struct timeval now); */ void *adns__alloc_interim(adns_query qu, size_t sz); +void *adns__alloc_preserved(adns_query qu, size_t sz); /* Allocates some memory, and records which query it came from * and how much there was. * - * If an error occurs in the query, all its memory is simply freed. - * - * If the query succeeds, one large buffer will be made which is - * big enough for all these allocations, and then adns__alloc_final - * will get memory from this buffer. + * If an error occurs in the query, all the memory from _interim is + * simply freed. If the query succeeds, one large buffer will be made + * which is big enough for all these allocations, and then + * adns__alloc_final will get memory from this buffer. * * _alloc_interim can fail (and return 0). * The caller must ensure that the query is failed. * - * adns__alloc_interim_{only,fail}(qu,0) will not return 0, - * but it will not necessarily return a distinct pointer each time. + * The memory from _preserved is is kept and transferred into the + * larger buffer - unless we run out of memory, in which case it too + * is freed. When you use _preserved you have to add code to the + * x_nomem error exit case in adns__makefinal_query to clear out the + * pointers you made to those allocations, because that's when they're + * thrown away; you should also make a note in the declaration of + * those pointer variables, to note that they are _preserved rather + * than _interim. If they're in the answer, note it here: + * answer->cname and answer->owner are _preserved. */ void adns__transfer_interim(adns_query from, adns_query to, void *block, size_t sz); @@ -452,21 +484,29 @@ void *adns__alloc_final(adns_query qu, size_t sz); void adns__makefinal_block(adns_query qu, void **blpp, size_t sz); void adns__makefinal_str(adns_query qu, char **strp); -void adns__reset_cnameonly(adns_query qu); -/* Resets all of the memory management stuff etc. to - * take account of only the CNAME. Used when we find an error somewhere - * and want to just report the error (with perhaps CNAME info), and also - * when we're halfway through RRs in a datagram and discover that we - * need to retry the query. +void adns__reset_preserved(adns_query qu); +/* Resets all of the memory management stuff etc. to take account of + * only the _preserved stuff from _alloc_preserved. Used when we find + * an error somewhere and want to just report the error (with perhaps + * CNAME, owner, etc. info), and also when we're halfway through RRs + * in a datagram and discover that we need to retry the query. */ void adns__query_done(adns_query qu); void adns__query_fail(adns_query qu, adns_status stat); - + /* From reply.c: */ void adns__procdgram(adns_state ads, const byte *dgram, int len, - int serv, struct timeval now); + int serv, int viatcp, struct timeval now); +/* This function is allowed to cause new datagrams to be constructed + * and sent, or even new queries to be started. However, + * query-sending functions are not allowed to call any general event + * loop functions in case they accidentally call this. + * + * Ie, receiving functions may call sending functions. + * Sending functions may NOT call receiving functions. + */ /* From types.c: */ @@ -602,41 +642,52 @@ 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); +/* what and why may be both 0, or both non-0. */ + 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. */ +/* Make all the system calls we want to if the application wants us to. + * Must not be called from within adns internal processing functions, + * lest we end up in recursive descent ! + */ 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); +int adns__internal_check(adns_state ads, + adns_query *query_io, + adns_answer **answer, + void **context_r); -/* Useful static inline functions: */ +void adns__timeouts(adns_state ads, int act, + struct timeval **tv_io, struct timeval *tvbuf, + struct timeval now); +/* If act is !0, then this will also deal with the TCP connection + * if previous events broke it or require it to be connected. + */ -static inline void timevaladd(struct timeval *tv_io, long ms) { - struct timeval tmp; - assert(ms>=0); - tmp= *tv_io; - tmp.tv_usec += (ms%1000)*1000000; - tmp.tv_sec += ms/1000; - if (tmp.tv_usec >= 1000000) { tmp.tv_sec++; tmp.tv_usec -= 1000; } - *tv_io= tmp; -} +/* From check.c: */ + +void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc); + +/* Useful static inline functions: */ 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'); } +static inline int ctype_822special(int c) { return strchr("()<>@,;:\\\".[]",c) != 0; } +static inline int ctype_domainunquoted(int c) { + return ctype_alpha(c) || ctype_digit(c) || (strchr("-_/+",c) != 0); +} static inline int errno_resources(int e) { return e==ENOMEM || e==ENOBUFS; } @@ -646,28 +697,6 @@ static inline int errno_resources(int e) { return e==ENOMEM || e==ENOBUFS; } (( ((sz)+sizeof(union maxalign)-1) / sizeof(union maxalign) ) \ * 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 { \ - 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).head= (node); \ - (list).tail= (node); \ - } while(0) - -#define LIST_UNLINK(list,node) LIST_UNLINK_PART(list,node,) -#define LIST_LINK_TAIL(list,node) LIST_LINK_TAIL_PART(list,node,) - #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))