DNS响应流程:
在DNS初始化流程的说明时已经说过,DNS启动后会打开到DNS server的链接,然后定时调用DNSHandler::mainEvent()进行DNS响应的接收和处理。接收是调用DNSHandler::recv_dns()函数来完成的,因此DNS响应处理流程从这里开始
在前面也说过在向DNS server发起链接之前会向NET模块注册READ事件,让NET模块在有DNS响应报文到来时会把之加入DNSHandler的triggered队列中,而DNSHandler::recv_dns会遍历该队列去处理每个DNS响应
main()---> DNSProcessor::start()--->DNSProcessor::open()--->DNSHandler::startEvent()--->DNSHandler::mainEvent()--->DNSHandler::recv_dns()
--->dns_process()
static bool
dns_process(DNSHandler *handler, HostEnt *buf, int len)
{
ProxyMutex *mutex = handler->mutex;
HEADER *h = (HEADER *) (buf->buf);
//获取对应的DNS查询表项
DNSEntry *e = get_dns(handler, (uint16_t) ntohs(h->id));
bool retry = false;
bool server_ok = true;
uint32_t temp_ttl = 0;
if (!e || !e->written_flag) {
Debug("dns", "unknown DNS id = %u", (uint16_t) ntohs(h->id));
return false; // cannot count this as a success
}
//已接收
e->written_flag = false;
--(handler->in_flight);//计数
DNS_DECREMENT_DYN_STAT(dns_in_flight_stat);
DNS_SUM_DYN_STAT(dns_response_time_stat, ink_get_hrtime() - e->send_time);
//下面是解析处理DNS响应报文,看代码前先看看DNS协议,否则云里雾里的
if (h->rcode != NOERROR || !h->ancount) {
Debug("dns", "received rcode = %d", h->rcode);
switch (h->rcode) {
default:
Warning("Unknown DNS error %d for [%s]", h->rcode, e->qname);
retry = true;
server_ok = false; // could be server problems
goto Lerror;
case SERVFAIL: // recoverable error
retry = true;
case FORMERR: // unrecoverable errors
case REFUSED:
case NOTIMP:
Debug("dns", "DNS error %d for [%s]", h->rcode, e->qname);
server_ok = false; // could be server problems
goto Lerror;
case NOERROR:
case NXDOMAIN:
case 6: // YXDOMAIN
case 7: // YXRRSET
case 8: // NOTAUTH
case 9: // NOTAUTH
case 10: // NOTZONE
Debug("dns", "DNS error %d for [%s]", h->rcode, e->qname);
goto Lerror;
}
} else {
//
// Initialize local data
//
// struct in_addr host_addr; unused
u_char tbuf[MAXDNAME + 1];
buf->ent.h_name = NULL;
int ancount = ntohs(h->ancount);
unsigned char *bp = buf->hostbuf;
int buflen = sizeof(buf->hostbuf);
u_char *cp = ((u_char *) h) + HFIXEDSZ;
u_char *eom = (u_char *) h + len;
int n;
ink_assert(buf->srv_hosts.srv_host_count == 0 && buf->srv_hosts.srv_hosts_length == 0);
buf->srv_hosts.srv_host_count = 0;
buf->srv_hosts.srv_hosts_length = 0;
unsigned& num_srv = buf->srv_hosts.srv_host_count;
int rname_len = -1;
//
// Expand name
//
if ((n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen)) < 0)
goto Lerror;
// Should we validate the query name?
if (dns_validate_qname) {
int qlen = e->qname_len;
int rlen = strlen((char *)bp);
rname_len = rlen; // Save for later use
if ((qlen > 0) && ('.' == e->qname[qlen-1]))
--qlen;
if ((rlen > 0) && ('.' == bp[rlen-1]))
--rlen;
// TODO: At some point, we might want to care about the case here, and use an algorithm
// to randomly pick upper case characters in the query, and validate the response with
// case sensitivity.
if ((qlen != rlen) || (strncasecmp(e->qname, (const char*)bp, qlen) != 0)) {
// Bad mojo, forged?
Warning("received DNS response with query name of '%s', but response query name is '%s'", e->qname, bp);
goto Lerror;
} else {
Debug("dns", "query name validated properly for %s", e->qname);
}
}
cp += n + QFIXEDSZ;
if (is_addr_query(e->qtype)) {
if (-1 == rname_len)
n = strlen((char *)bp) + 1;
else
n = rname_len + 1;
buf->ent.h_name = (char *) bp;
bp += n;
buflen -= n;
}
u_char **ap = buf->host_aliases;
buf->ent.h_aliases = (char **) buf->host_aliases;
u_char **hap = (u_char **) buf->h_addr_ptrs;
*hap = NULL;
buf->ent.h_addr_list = (char **) buf->h_addr_ptrs;
if (local_num_entries >= DEFAULT_NUM_TRY_SERVER) {
if ((attempt_num_entries % 50) == 0) {
try_servers = (try_servers + 1) % countof(try_server_names);
ink_strlcpy(try_server_names[try_servers], e->qname, MAXDNAME);
memset(&try_server_names[try_servers][strlen(e->qname)], 0, 1);
attempt_num_entries = 0;
}
++attempt_num_entries;
} else {
// fill up try_server_names for try_primary_named
try_servers = local_num_entries++;
ink_strlcpy(try_server_names[try_servers], e->qname, MAXDNAME);
memset(&try_server_names[try_servers][strlen(e->qname)], 0, 1);
}
/* added for SRV support [ebalsa]
this skips the query section (qdcount)
*/
unsigned char *here = (unsigned char *) buf->buf + HFIXEDSZ;
if (e->qtype == T_SRV) {
for (int ctr = ntohs(h->qdcount); ctr > 0; ctr--) {
int strlen = dn_skipname(here, eom);
here += strlen + QFIXEDSZ;
}
}
//
// Decode each answer
//
int answer = false, error = false;
while (ancount-- > 0 && cp < eom && !error) {
n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen);
if (n < 0) {
++error;
break;
}
cp += n;
short int type;
NS_GET16(type, cp);
cp += NS_INT16SZ; // NS_GET16(cls, cp);
NS_GET32(temp_ttl, cp); // NOTE: this is not a "long" but 32-bits (from nameser_compat.h)
if ((temp_ttl < buf->ttl) || (buf->ttl == 0))
buf->ttl = temp_ttl;
NS_GET16(n, cp);
//
// Decode cname
//
if (is_addr_query(e->qtype) && type == T_CNAME) {
if (ap >= &buf->host_aliases[DNS_MAX_ALIASES - 1])
continue;
n = ink_dn_expand((u_char *) h, eom, cp, tbuf, sizeof(tbuf));
if (n < 0) {
++error;
break;
}
cp += n;
*ap++ = (unsigned char *) bp;
n = strlen((char *) bp) + 1;
bp += n;
buflen -= n;
n = strlen((char *) tbuf) + 1;
if (n > buflen) {
++error;
break;
}
ink_strlcpy((char *) bp, (char *) tbuf, buflen);
bp += n;
buflen -= n;
Debug("dns", "received cname = %s", tbuf);
continue;
}
if (e->qtype != type) {
++error;
break;
}
//
// Decode names
//
if (type == T_PTR) {
n = ink_dn_expand((u_char *) h, eom, cp, bp, buflen);
if (n < 0) {
++error;
break;
}
cp += n;
if (!answer) {
buf->ent.h_name = (char *) bp;
Debug("dns", "received PTR name = %s", bp);
n = strlen((char *) bp) + 1;
bp += n;
buflen -= n;
} else if (ap < &buf->host_aliases[DNS_MAX_ALIASES - 1]) {
*ap++ = bp;
Debug("dns", "received PTR alias = %s", bp);
n = strlen((char *) bp) + 1;
bp += n;
buflen -= n;
}
} else if (type == T_SRV) {
if (num_srv >= HOST_DB_MAX_ROUND_ROBIN_INFO)
break;
cp = here; /* hack */
int strlen = dn_skipname(cp, eom);
cp += strlen;
const unsigned char *srv_off = cp;
cp += SRV_FIXEDSZ;
cp += dn_skipname(cp, eom);
here = cp; /* hack */
SRV *srv = &buf->srv_hosts.hosts[num_srv];
int r = ink_ns_name_ntop(srv_off + SRV_SERVER, srv->host, MAXDNAME);
if (r <= 0) {
/* FIXME: is this really an error? or just a continue; */
++error;
goto Lerror;
}
Debug("dns_srv", "Discovered SRV record [from NS lookup] with cost:%d weight:%d port:%d with host:%s",
ink_get16(srv_off + SRV_COST),
ink_get16(srv_off + SRV_WEIGHT), ink_get16(srv_off + SRV_PORT), srv->host);
srv->port = ink_get16(srv_off + SRV_PORT);
srv->priority = ink_get16(srv_off + SRV_COST);
srv->weight = ink_get16(srv_off + SRV_WEIGHT);
srv->host_len = r;
srv->host[r-1] = '\0';
srv->key = makeHostHash(srv->host);
if (srv->host[0] != '\0')
buf->srv_hosts.srv_hosts_length += r;
else
continue;
++num_srv;
} else if (is_addr_query(type)) {
if (answer) {
if (n != buf->ent.h_length) {
cp += n;
continue;
}
} else {
int nn;
buf->ent.h_length = n;
buf->ent.h_addrtype = T_A == type ? AF_INET : AF_INET6;
buf->ent.h_name = (char *) bp;
nn = strlen((char *) bp) + 1;
Debug("dns", "received %s name = %s", QtypeName(type), bp);
bp += nn;
buflen -= nn;
}
// attempt to use the original buffer (if it is word aligned)
if (!(((uintptr_t) cp) % sizeof(unsigned int))) {
*hap++ = cp;
cp += n;
} else {
ip_text_buffer ip_string;
bp = (unsigned char *) align_pointer_forward(bp, sizeof(int));
if (bp + n >= buf->hostbuf + DNS_HOSTBUF_SIZE) {
++error;
break;
}
memcpy((*hap++ = bp), cp, n);
Debug("dns", "received %s = %s", QtypeName(type),
inet_ntop(T_AAAA == type ? AF_INET6 : AF_INET, bp, ip_string, sizeof(ip_string))
);
bp += n;
cp += n;
}
} else
goto Lerror;
++answer;
}
if (answer) {
*ap = NULL;
*hap = NULL;
//
// If the named didn't send us the name, insert the one
// the user gave us...
//
if (!buf->ent.h_name) {
Debug("dns", "inserting name = %s", e->qname);
ink_strlcpy((char *) bp, e->qname, sizeof(buf->hostbuf) - (bp - buf->hostbuf));
buf->ent.h_name = (char *) bp;
}
//处理DNS响应结果
dns_result(handler, e, buf, retry);
return server_ok;
}
}
Lerror:;
DNS_INCREMENT_DYN_STAT(dns_lookup_fail_stat);
dns_result(handler, e, NULL, retry);
return server_ok;
}
main()---> DNSProcessor::start()--->DNSProcessor::open()--->DNSHandler::startEvent()--->DNSHandler::mainEvent()--->DNSHandler::recv_dns()
--->dns_process()--->dns_result()
这个函数的功能是处理DNS响应的结果
static void
dns_result(DNSHandler *h, DNSEntry *e, HostEnt *ent, bool retry) {
ProxyMutex *mutex = h->mutex;
bool cancelled = (e->action.cancelled ? true : false);
//如果查询结果没有ip地址,则重试
//如果重试次数还没用完,则继续重试
if (!ent && !cancelled) {
// try to retry operation
if (retry && e->retries) {
Debug("dns", "doing retry for %s", e->qname);
DNS_INCREMENT_DYN_STAT(dns_retries_stat);
--(e->retries);
write_dns(h);
return;
//如果重试次数已用完,则扩展主机名后继续重新发DNS查询
} else if (e->domains && *e->domains) {
do {
Debug("dns", "domain extending %s", e->qname);
//int l = _strlen(e->qname);
char *dot = strchr(e->qname, '.');
if (dot) {
if (e->qname_len + strlen(*e->domains) + 2 > MAXDNAME) {
Debug("dns", "domain too large %s + %s", e->qname, *e->domains);
goto LnextDomain;
}
if (e->qname[e->qname_len - 1] != '.') {
e->qname[e->qname_len] = '.';
ink_strlcpy(e->qname + e->qname_len + 1, *e->domains, MAXDNAME - (e->qname_len + 1));
e->qname_len = strlen(e->qname);
} else {
ink_strlcpy(e->qname + e->qname_len, *e->domains, MAXDNAME - e->qname_len);
e->qname_len = strlen(e->qname);
}
} else {
if (e->qname_len + strlen(*e->domains) + 2 > MAXDNAME) {
Debug("dns", "domain too large %s + %s", e->qname, *e->domains);
goto LnextDomain;
}
e->qname[e->qname_len] = '.';
ink_strlcpy(e->qname + e->qname_len + 1, *e->domains, MAXDNAME - (e->qname_len + 1));
e->qname_len = strlen(e->qname);
}
++(e->domains);
e->retries = dns_retries;
Debug("dns", "new name = %s retries = %d", e->qname, e->retries);
write_dns(h);
return;
LnextDomain:
++(e->domains);
} while (*e->domains);
} else {
e->qname[e->qname_len] = 0;
if (!strchr(e->qname, '.') && !e->last) {
e->last = true;
write_dns(h);
return;
}
}
if (retry) {
DNS_INCREMENT_DYN_STAT(dns_max_retries_exceeded_stat);
}
}
//失败处理
if (ent == BAD_DNS_RESULT)
ent = NULL;
if (!cancelled) {
if (!ent) {
DNS_SUM_DYN_STAT(dns_fail_time_stat, ink_get_hrtime() - e->submit_time);
} else {
DNS_SUM_DYN_STAT(dns_success_time_stat, ink_get_hrtime() - e->submit_time);
}
}
//从DNSHandler的entries队列中删除
h->entries.remove(e);
if (is_debug_tag_set("dns")) {
if (is_addr_query(e->qtype)) {
ip_text_buffer buff;
char const* ptr = "<none>";
char const* result = "FAIL";
if (ent) {
result = "SUCCESS";
ptr = inet_ntop(e->qtype == T_AAAA ? AF_INET6 : AF_INET, ent->ent.h_addr_list[0], buff, sizeof(buff));
}
Debug("dns", "%s result for %s = %s retry %d", result, e->qname, ptr, retry);
} else {
if (ent) {
Debug("dns", "SUCCESS result for %s = %s af=%d retry %d", e->qname, ent->ent.h_name, ent->ent.h_addrtype, retry);
} else {
Debug("dns", "FAIL result for %s = <not found> retry %d", e->qname, retry);
}
}
}
if (ent) {
DNS_INCREMENT_DYN_STAT(dns_lookup_success_stat);
} else {
DNS_INCREMENT_DYN_STAT(dns_lookup_fail_stat);
}
//如果是在重复队列上,则先从该队列中删除后告诉上层进行处理,如果处理出错重新加入重复队列
DNSEntry *dup = NULL;
while ((dup = e->dups.dequeue())) {
if (dup->post(h, ent)) {
e->dups.enqueue(dup);
goto Lretry;
}
}
if (e->timeout) {
e->timeout->cancel(e);
e->timeout = NULL;
}
//设置查询结果
e->result_ent = ent;
if (h->mutex->thread_holding == e->submit_thread) {
MUTEX_TRY_LOCK(lock, e->action.mutex, h->mutex->thread_holding);
if (!lock) {
Debug("dns", "failed lock for result %s", e->qname);
goto Lretry;
}
for (int i = 0; i < MAX_DNS_RETRIES; i++) {
if (e->id[i] < 0)
break;
h->release_query_id(e->id[i]);
}
e->postEvent(0, 0);
//清除报文的id
} else {
for (int i = 0; i < MAX_DNS_RETRIES; i++) {
if (e->id[i] < 0)
break;
h->release_query_id(e->id[i]);
}
e->mutex = e->action.mutex;
//进行post操作,即回调上层来处理查询结果
SET_CONTINUATION_HANDLER(e, &DNSEntry::postEvent);
e->submit_thread->schedule_imm_signal(e);
}
return;
Lretry:
e->result_ent = ent;
e->retries = 0;
if (e->timeout)
e->timeout->cancel();
e->timeout = h->mutex->thread_holding->schedule_in(e, DNS_PERIOD);
}
main()---> DNSProcessor::start()--->DNSProcessor::open()--->DNSHandler::startEvent()--->DNSHandler::mainEvent()--->DNSHandler::recv_dns()
--->dns_process()--->dns_result()--->DNSEntry::postEvent()
这个函数的功能是回调上层函数处理查询结果,处理完成后释放响应的结构
int
DNSEntry::postEvent(int /* event ATS_UNUSED */, Event * /* e ATS_UNUSED */)
{
if (!action.cancelled) {
Debug("dns", "called back continuation for %s", qname);
//回调上层处理函数
action.continuation->handleEvent(DNS_EVENT_LOOKUP, result_ent);
}
//清理结果
result_ent = NULL;
action.mutex = NULL;
mutex = NULL;
dnsEntryAllocator.free(this);
return EVENT_DONE;
}
main()---> DNSProcessor::start()--->DNSProcessor::open()--->DNSHandler::startEvent()--->DNSHandler::mainEvent()--->DNSHandler::recv_dns()
--->dns_process()--->dns_result()--->DNSEntry::postEvent()--->HostDBContinuation::dnsEvent()
这个函数的功能是接收DNS的响应结果HostEnt,根据这个结果创建HostDBInfo结果写入hostdb数据库,最后把结果传给HTTPSM处理
int
HostDBContinuation::dnsEvent(int event, HostEnt * e)
{
ink_assert(this_ethread() == hostDB.lock_for_bucket(fold_md5(md5.hash) % hostDB.buckets)->thread_holding);
if (timeout) {
timeout->cancel(this);
timeout = NULL;
}
EThread *thread = mutex->thread_holding;
if (event == EVENT_INTERVAL) {
if (!action.continuation) {
remove_trigger_pending_dns();
hostdb_cont_free(this);
return EVENT_DONE;
}
MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
if (!lock) {
timeout = thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
return EVENT_CONT;
}
if (!action.cancelled && action.continuation)
action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
action = NULL;
timeout = thread->schedule_in(this, HRTIME_SECONDS(hostdb_insert_timeout));
return EVENT_DONE;
} else {
//来,从这里开始
bool failed = !e;
bool rr = false;
pending_action = NULL;
//当响应的ip地址大于一个时,rr为true
if (is_srv()) {
rr = !failed && (e->srv_hosts.srv_host_count > 0);
} else if (!failed) {
rr = 0 != e->ent.h_addr_list[1];
} else {
}
ttl = failed ? 0 : e->ttl / 60;
int ttl_seconds = failed ? 0 : e->ttl;
//再查一下hostdb
HostDBInfo *old_r = probe(mutex, md5, true);
HostDBInfo old_info;
if (old_r)
old_info = *old_r;
HostDBRoundRobin *old_rr_data = old_r ? old_r->rr() : NULL;
int n = 0, nn = 0;
void* first = 0;
uint8_t af = e ? e->ent.h_addrtype : AF_UNSPEC;
//记录合法的ip地址的个数
if (rr) {
if (is_srv() && !failed) {
n = e->srv_hosts.srv_host_count;
} else {
void* ptr; // tmp for current entry.
for (
; nn < HOST_DB_MAX_ROUND_ROBIN_INFO
&& 0 != (ptr = e->ent.h_addr_list[nn])
; ++nn
) {
if (is_addr_valid(af, ptr)) {
if (! first) first = ptr;
++n;
} else {
Warning("Zero address removed from round-robin list for '%s'", md5.host_name);
}
}
if (!first) {
failed = true;
rr = false;
}
}
} else if (!failed) {
first = e->ent.h_addr_list[0];
}
HostDBInfo *r = NULL;
IpAddr tip; // temp storage if needed.
if (is_byname()) {
//设置第一个ip地址
if (first) ip_addr_set(tip, af, first);
//把结果(第一个合法的ip地址)写入hostdb
r = lookup_done(tip, md5.host_name, rr, ttl_seconds, failed ? 0 : &e->srv_hosts);
} else if (is_srv()) {
if (!failed)
tip._family = AF_INET; // force the tip valid, or else the srv will fail
r = lookup_done(tip, /* junk: FIXME: is the code in lookup_done() wrong to NEED this? */
md5.host_name, /* hostname */
rr, /* is round robin, doesnt matter for SRV since we recheck getCount() inside lookup_done() */
ttl_seconds, /* ttl in seconds */
failed ? 0 : &e->srv_hosts);
} else if (failed) {
r = lookup_done(tip, md5.host_name, false, ttl_seconds, 0);
} else {
r = lookup_done(md5.ip, e->ent.h_name, false, ttl_seconds, &e->srv_hosts);
}
ink_assert(!r || (r->app.allotment.application1 == 0 && r->app.allotment.application2 == 0));
//下面出要是响应结果有多个ip地址时的处理:每个ip地址对应一个HostDBInfo结构,然后放到 HostDBRoundRobin的数组info中
if (rr) {
const int rrsize = HostDBRoundRobin::size(n, e->srv_hosts.srv_hosts_length);
HostDBRoundRobin *rr_data = (HostDBRoundRobin *) hostDB.alloc(&r->app.rr.offset, rrsize);
Debug("hostdb", "allocating %d bytes for %d RR at %p %d", rrsize, n, rr_data, r->app.rr.offset);
if (rr_data) {
rr_data->length = rrsize;
int i = 0, ii = 0;
if (is_srv()) {
int skip = 0;
char *pos = (char *) rr_data + sizeof(HostDBRoundRobin) + n * sizeof(HostDBInfo);
SRV *q[HOST_DB_MAX_ROUND_ROBIN_INFO];
ink_assert(n <= HOST_DB_MAX_ROUND_ROBIN_INFO);
// sort
for (i = 0; i < n; ++i) {
q[i] = &e->srv_hosts.hosts[i];
}
for (i = 0; i < n; ++i) {
for (ii = i + 1; ii < n; ++ii) {
if (*q[ii] < *q[i]) {
SRV *tmp = q[i];
q[i] = q[ii];
q[ii] = tmp;
}
}
}
for (i = 0; i < n; ++i) {
SRV *t = q[i];
HostDBInfo& item = rr_data->info[i];
memset(&item, 0, sizeof(item));
item.round_robin = 0;
item.reverse_dns = 0;
item.is_srv = 1;
item.data.srv.srv_weight = t->weight;
item.data.srv.srv_priority = t->priority;
item.data.srv.srv_port = t->port;
item.data.srv.key = t->key;
ink_assert((skip + t->host_len) <= e->srv_hosts.srv_hosts_length);
memcpy(pos + skip, t->host, t->host_len);
item.data.srv.srv_offset = (pos - (char *) rr_data) + skip;
skip += t->host_len;
item.md5_high = r->md5_high;
item.md5_low = r->md5_low;
item.md5_low_low = r->md5_low_low;
item.full = 1;
item.app.allotment.application1 = 0;
item.app.allotment.application2 = 0;
Debug("dns_srv", "inserted SRV RR record [%s] into HostDB with TTL: %d seconds", t->host, ttl_seconds);
}
rr_data->good = rr_data->rrcount = n;
rr_data->current = 0;
if (old_rr_data) {
for (i = 0; i < rr_data->rrcount; ++i) {
for (ii = 0; ii < old_rr_data->rrcount; ++ii) {
if (rr_data->info[i].data.srv.key == old_rr_data->info[ii].data.srv.key) {
char *new_host = rr_data->info[i].srvname(rr_data);
char *old_host = old_rr_data->info[ii].srvname(old_rr_data);
if (!strcmp(new_host, old_host))
rr_data->info[i].app = old_rr_data->info[ii].app;
}
}
}
}
} else {
for (ii = 0; ii < nn; ++ii) {
if (is_addr_valid(af, e->ent.h_addr_list[ii])) {
HostDBInfo& item = rr_data->info[i];
ip_addr_set(item.ip(), af, e->ent.h_addr_list[ii]);
// rr_data->info[i].ip() = *(unsigned int *) e->ent.h_addr_list[ii];
item.full = 1;
item.round_robin = 0;
item.reverse_dns = 0;
item.is_srv = 0;
item.md5_high = r->md5_high;
item.md5_low = r->md5_low;
item.md5_low_low = r->md5_low_low;
if (!restore_info(&item, old_r, old_info, old_rr_data)) {
item.app.allotment.application1 = 0;
item.app.allotment.application2 = 0;
}
++i;
}
}
rr_data->good = rr_data->rrcount = n;
rr_data->current = 0;
}
} else {
ink_assert(!"out of room in hostdb data area");
Warning("out of room in hostdb for round-robin DNS data");
r->round_robin = 0;
}
}
if (!failed && !rr && !is_srv())
restore_info(r, old_r, old_info, old_rr_data);
ink_assert(!r || !r->round_robin || !r->reverse_dns);
ink_assert(failed || !r->round_robin || r->app.rr.offset);
#ifdef NON_MODULAR
//cluster模式时的处理,留到cluster再分析
ClusterMachine *m = cluster_machine_at_depth(master_hash(md5.hash));
if (m)
do_put_response(m, r, NULL);
#endif
if (action.continuation) {
if (failed && check_for_retry(md5.db_mark, host_res_style)) {
this->refresh_MD5();
SET_CONTINUATION_HANDLER(this, (HostDBContHandler) & HostDBContinuation::probeEvent);
thread->schedule_in(this, MUTEX_RETRY_DELAY);
return EVENT_CONT;
}
MUTEX_TRY_LOCK_FOR(lock, action.mutex, thread, action.continuation);
if (!lock) {
remove_trigger_pending_dns();
SET_HANDLER((HostDBContHandler) & HostDBContinuation::probeEvent);
thread->schedule_in(this, HOST_DB_RETRY_PERIOD);
return EVENT_CONT;
}
//把结果传给上层处理:最终调到HttpSM::state_hostdb_lookup来处理
if (!action.cancelled)
reply_to_cont(action.continuation, r, is_srv());
}
remove_trigger_pending_dns();
hostdb_cont_free(this);
return EVENT_DONE;
}
}
main()---> DNSProcessor::start()--->DNSProcessor::open()--->DNSHandler::startEvent()--->DNSHandler::mainEvent()--->DNSHandler::recv_dns()
--->dns_process()--->dns_result()--->DNSEntry::postEvent()--->HostDBContinuation::dnsEvent()--->HttpSM::process_hostdb_info()
在这里这个函数接收DNS响应并调用process_hostdb_info进行处理
int
HttpSM::state_hostdb_lookup(int event, void *data)
{
switch (event) {
case EVENT_HOST_DB_LOOKUP:
pending_action = NULL;
//直接调用process_hostdb_info处理
process_hostdb_info((HostDBInfo *) data);
call_transact_and_set_next_state(NULL);
break;
......
}
main()---> DNSProcessor::start()--->DNSProcessor::open()--->DNSHandler::startEvent()--->DNSHandler::mainEvent()--->DNSHandler::recv_dns()
--->dns_process()--->dns_result()--->DNSEntry::postEvent()--->HostDBContinuation::dnsEvent()--->HttpSM::process_hostdb_info()--->HttpSM::process_hostdb_info()
这个函数功能是把DNS查询结果设置到HTTP状态机的host_db_info上,DNS响应大概流程到此结束
void
HttpSM::process_hostdb_info(HostDBInfo * r)
{
//判断查询结果是否成功
if (r && !r->failed()) {
ink_time_t now = ink_cluster_time();
HostDBInfo *ret = NULL;
//设置为查询成功
t_state.dns_info.lookup_success = true;
//如果开启round_robin功能,则根据客户端ip地址选择一个ip地址
if (r->round_robin) {
HostDBRoundRobin *rr = r->rr();
ret = rr->select_best_http(&t_state.client_info.addr.sa, now, (int) t_state.txn_conf->down_server_timeout);
if (t_state.dns_info.srv_lookup_success) {
uint32_t last_failure = 0xFFFFFFFF;
for (int i = 0; i < rr->rrcount && last_failure != 0; ++i) {
if (last_failure > rr->info[i].app.http_data.last_failure)
last_failure = rr->info[i].app.http_data.last_failure;
}
if (last_failure != 0 && (uint32_t) (now - t_state.txn_conf->down_server_timeout) < last_failure) {
HostDBApplicationInfo app;
app.allotment.application1 = 0;
app.allotment.application2 = 0;
app.http_data.last_failure = last_failure;
hostDBProcessor.setby_srv(t_state.dns_info.lookup_name, 0, t_state.dns_info.srv_hostname, &app);
}
}
} else {
ret = r;
}
if (ret) {
t_state.host_db_info = *ret;
ink_release_assert(!t_state.host_db_info.reverse_dns);
ink_release_assert(ats_is_ip(t_state.host_db_info.ip()));
}
} else {
//DNS查询失败
DebugSM("http", "[%" PRId64 "] DNS lookup failed for '%s'", sm_id, t_state.dns_info.lookup_name);
t_state.dns_info.lookup_success = false;
t_state.host_db_info.app.allotment.application1 = 0;
t_state.host_db_info.app.allotment.application2 = 0;
ink_assert(!t_state.host_db_info.round_robin);
}
//DNS查询结束时间
milestones.dns_lookup_end = ink_get_hrtime();
if (is_debug_tag_set("http_timeout")) {
if (t_state.api_txn_dns_timeout_value != -1) {
int foo = (int) (milestone_difference_msec(milestones.dns_lookup_begin, milestones.dns_lookup_end));
DebugSM("http_timeout", "DNS took: %d msec", foo);
}
}
}