/*
- * $Id: dns_internal.cc,v 1.63 2004/04/10 13:10:17 hno Exp $
+ * $Id: dns_internal.cc,v 1.64 2004/10/10 02:53:26 hno Exp $
*
* DEBUG: section 78 DNS lookups; interacts with lib/rfc1035.c
* AUTHOR: Duane Wessels
struct _idns_query
{
+ hash_link hash;
+ char query[RFC1035_MAXHOSTNAMESZ+1];
char buf[512];
size_t sz;
unsigned short id;
int attempt;
const char *error;
int rcode;
+ idns_query *queue;
};
struct _ns
static int nns_alloc = 0;
static dlink_list lru_list;
static int event_queued = 0;
+static hash_table *idns_lookup_hash = NULL;
static OBJH idnsStats;
static void idnsAddNameserver(const char *buf);
return NULL;
}
+static void
+idnsCallback(idns_query *q, rfc1035_rr *answers, int n, const char *error)
+{
+ IDNSCB *callback;
+ void *cbdata;
+
+ callback = q->callback;
+ q->callback = NULL;
+
+ if (cbdataReferenceValidDone(q->callback_data, &cbdata))
+ callback(cbdata, answers, n, error);
+
+ while(q->queue) {
+ idns_query *q2 = q->queue;
+ q->queue = q2->queue;
+ callback = q2->callback;
+ q2->callback = NULL;
+
+ if (cbdataReferenceValidDone(q2->callback_data, &cbdata))
+ callback(cbdata, answers, n, error);
+
+ memFree(q2, MEM_IDNS_QUERY);
+ }
+
+ if (q->hash.key) {
+ hash_remove_link(idns_lookup_hash, &q->hash);
+ q->hash.key = NULL;
+ }
+}
+
static void
idnsGrokReply(const char *buf, size_t sz)
{
rfc1035_rr *answers = NULL;
unsigned short rid = 0xFFFF;
idns_query *q;
- IDNSCB *callback;
- void *cbdata;
+
n = rfc1035AnswersUnpack(buf,
sz,
&answers,
}
}
- callback = q->callback;
- q->callback = NULL;
-
- if (cbdataReferenceValidDone(q->callback_data, &cbdata))
- callback(cbdata, answers, n, q->error);
-
+ idnsCallback(q, answers, n, q->error);
rfc1035RRDestroy(answers, n);
memFree(q, MEM_IDNS_QUERY);
if (tvSubDsec(q->start_t, current_time) < Config.Timeout.idns_query) {
idnsSendQuery(q);
} else {
- IDNSCB *callback;
- void *cbdata;
debug(78, 2) ("idnsCheckQueue: ID %x: giving up after %d tries and %5.1f seconds\n",
(int) q->id, q->nsends,
tvSubDsec(q->start_t, current_time));
- callback = q->callback;
- q->callback = NULL;
-
- if (cbdataReferenceValidDone(q->callback_data, &cbdata)) {
- if (q->rcode != 0)
- callback(cbdata, NULL, -q->rcode, q->error);
- else
- callback(cbdata, NULL, -16, "Timeout");
- }
+
+ if (q->rcode != 0)
+ idnsCallback(q, NULL, -q->rcode, q->error);
+ else
+ idnsCallback(q, NULL, -16, "Timeout");
memFree(q, MEM_IDNS_QUERY);
}
"Internal DNS Statistics",
idnsStats, 0, 1);
memset(RcodeMatrix, '\0', sizeof(RcodeMatrix));
+ idns_lookup_hash = hash_create((HASHCMP *) strcmp, 103, hash_string);
init++;
}
}
idnsFreeNameservers();
}
+static int
+idnsCachedLookup(const char *key, IDNSCB * callback, void *data)
+{
+ idns_query *q;
+
+ idns_query *old = (idns_query *) hash_lookup(idns_lookup_hash, key);
+
+ if (!old)
+ return 0;
+
+ q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
+
+ q->callback = callback;
+
+ q->callback_data = cbdataReference(data);
+
+ q->queue = old->queue;
+
+ old->queue = q;
+
+ return 1;
+}
+
+static void
+idnsCacheQuery(idns_query *q, const char *key)
+{
+ xstrncpy(q->query, key, sizeof(q->query));
+ q->hash.key = q->query;
+ hash_join(idns_lookup_hash, &q->hash);
+}
+
void
idnsALookup(const char *name, IDNSCB * callback, void *data)
{
- idns_query *q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
+ idns_query *q;
+
+ if (idnsCachedLookup(name, callback, data))
+ return;
+
+ q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
+
q->sz = sizeof(q->buf);
+
q->id = rfc1035BuildAQuery(name, q->buf, &q->sz);
if (0 == q->id) {
q->callback = callback;
q->callback_data = cbdataReference(data);
q->start_t = current_time;
+ idnsCacheQuery(q, name);
idnsSendQuery(q);
}
idnsPTRLookup(const struct in_addr addr, IDNSCB * callback, void *data)
{
- idns_query *q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
+ idns_query *q;
+
+ const char *ip = inet_ntoa(addr);
+
+ if (idnsCachedLookup(ip, callback, data))
+ return;
+
+ q = (idns_query *)memAllocate(MEM_IDNS_QUERY);
+
q->sz = sizeof(q->buf);
+
q->id = rfc1035BuildPTRQuery(addr, q->buf, &q->sz);
+
debug(78, 3) ("idnsPTRLookup: buf is %d bytes for %s, id = %#hx\n",
- (int) q->sz, inet_ntoa(addr), q->id);
+ (int) q->sz, ip, q->id);
+
q->callback = callback;
+
q->callback_data = cbdataReference(data);
+
q->start_t = current_time;
+
+ idnsCacheQuery(q, ip);
+
idnsSendQuery(q);
}