* It is part of adns, which is
* Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
* Copyright (C) 1999 Tony Finch <dot@dotat.at>
- *
+ *
* 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
#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
struct adns__query {
adns_state ads;
- enum { query_tosend, 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;
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
* 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 . */
* 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. */
/* Possible states:
*
* state Queue child id nextudpserver udpsent tcpfailed
- *
+ *
* tosend NONE null >=0 0 zero zero
- * tosend timew null >=0 any nonzero zero
+ * tosend udpw null >=0 any nonzero zero
* tosend NONE null >=0 any nonzero zero
- *
- * tcpwait timew null >=0 irrelevant any any
- * tcpsent timew null >=0 irrelevant any any
- *
+ *
+ * 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 | /
* \ +------------------+ /
* 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;
vbuf tcpsend, tcprecv;
int nservers, nsortlist, nsearchlist, searchndots, tcpserver, tcprecv_skip;
- enum adns__tcpstate { server_disconnected, server_connecting, server_ok } tcpstate;
+ 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) and counting down.
+ */
struct sigaction stdsigpipe;
sigset_t stdsigmask;
struct pollfd pollfds_buf[MAX_POLLFDS];
* 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);
* 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 is 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_send(adns_query qu, struct timeval now);
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,
* 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: */
/* 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);
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,
adns_answer **answer,
void **context_r);
+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.
+ */
+
/* From check.c: */
void adns__consistency(adns_state ads, adns_query qu, consistency_checks cc);
/* Useful static inline functions: */
-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;
-}
-
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; }