23f5d145ec
outstanding queries, and processing a DNS response packet was O(n) in the number of outstanding queries. To speed things up in Google, we added a few circular, doubly-linked lists of queries that are hash-bucketed based on the attributes we care about, so most important operations are now O(1). It might be that the number of buckets are higher than most people would need, but on a quick calculation it should only be 100kB or so even on a 64-bit system, so I've let it stay as-is.
124 lines
3.6 KiB
C
124 lines
3.6 KiB
C
/* $Id$ */
|
|
|
|
/* Copyright 1998 by the Massachusetts Institute of Technology.
|
|
*
|
|
* Permission to use, copy, modify, and distribute this
|
|
* software and its documentation for any purpose and without
|
|
* fee is hereby granted, provided that the above copyright
|
|
* notice appear in all copies and that both that copyright
|
|
* notice and this permission notice appear in supporting
|
|
* documentation, and that the name of M.I.T. not be used in
|
|
* advertising or publicity pertaining to distribution of the
|
|
* software without specific, written prior permission.
|
|
* M.I.T. makes no representations about the suitability of
|
|
* this software for any purpose. It is provided "as is"
|
|
* without express or implied warranty.
|
|
*/
|
|
|
|
#include "setup.h"
|
|
|
|
#if defined(WIN32) && !defined(WATT32)
|
|
#include "nameser.h"
|
|
#else
|
|
#include <netinet/in.h>
|
|
#include <arpa/nameser.h>
|
|
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
|
|
#include <arpa/nameser_compat.h>
|
|
#endif
|
|
#endif
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include "ares.h"
|
|
#include "ares_dns.h"
|
|
#include "ares_private.h"
|
|
|
|
void ares_send(ares_channel channel, const unsigned char *qbuf, int qlen,
|
|
ares_callback callback, void *arg)
|
|
{
|
|
struct query *query;
|
|
int i;
|
|
time_t now;
|
|
|
|
/* Verify that the query is at least long enough to hold the header. */
|
|
if (qlen < HFIXEDSZ || qlen >= (1 << 16))
|
|
{
|
|
callback(arg, ARES_EBADQUERY, 0, NULL, 0);
|
|
return;
|
|
}
|
|
|
|
/* Allocate space for query and allocated fields. */
|
|
query = malloc(sizeof(struct query));
|
|
if (!query)
|
|
{
|
|
callback(arg, ARES_ENOMEM, 0, NULL, 0);
|
|
return;
|
|
}
|
|
query->tcpbuf = malloc(qlen + 2);
|
|
if (!query->tcpbuf)
|
|
{
|
|
free(query);
|
|
callback(arg, ARES_ENOMEM, 0, NULL, 0);
|
|
return;
|
|
}
|
|
query->server_info = malloc(channel->nservers *
|
|
sizeof(query->server_info[0]));
|
|
if (!query->server_info)
|
|
{
|
|
free(query->tcpbuf);
|
|
free(query);
|
|
callback(arg, ARES_ENOMEM, 0, NULL, 0);
|
|
return;
|
|
}
|
|
|
|
/* Compute the query ID. Start with no timeout. */
|
|
query->qid = (unsigned short)DNS_HEADER_QID(qbuf);
|
|
query->timeout = 0;
|
|
|
|
/* Form the TCP query buffer by prepending qlen (as two
|
|
* network-order bytes) to qbuf.
|
|
*/
|
|
query->tcpbuf[0] = (unsigned char)((qlen >> 8) & 0xff);
|
|
query->tcpbuf[1] = (unsigned char)(qlen & 0xff);
|
|
memcpy(query->tcpbuf + 2, qbuf, qlen);
|
|
query->tcplen = qlen + 2;
|
|
|
|
/* Fill in query arguments. */
|
|
query->qbuf = query->tcpbuf + 2;
|
|
query->qlen = qlen;
|
|
query->callback = callback;
|
|
query->arg = arg;
|
|
|
|
/* Initialize query status. */
|
|
query->try = 0;
|
|
query->server = 0;
|
|
for (i = 0; i < channel->nservers; i++)
|
|
{
|
|
query->server_info[i].skip_server = 0;
|
|
query->server_info[i].tcp_connection_generation = 0;
|
|
}
|
|
query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;
|
|
query->error_status = ARES_ECONNREFUSED;
|
|
query->timeouts = 0;
|
|
|
|
/* Initialize our list nodes. */
|
|
ares__init_list_node(&(query->queries_by_qid), query);
|
|
ares__init_list_node(&(query->queries_by_timeout), query);
|
|
ares__init_list_node(&(query->queries_to_server), query);
|
|
ares__init_list_node(&(query->all_queries), query);
|
|
|
|
/* Chain the query into the list of all queries. */
|
|
ares__insert_in_list(&(query->all_queries), &(channel->all_queries));
|
|
/* Keep track of queries bucketed by qid, so we can process DNS
|
|
* responses quickly.
|
|
*/
|
|
ares__insert_in_list(
|
|
&(query->queries_by_qid),
|
|
&(channel->queries_by_qid[query->qid % ARES_QID_TABLE_SIZE]));
|
|
|
|
/* Perform the first query action. */
|
|
time(&now);
|
|
ares__send_query(channel, query, now);
|
|
}
|