trafficserver的DNS查询源码注释

来源:互联网 发布:淘宝显示多少人付款 编辑:程序博客网 时间:2024/05/18 09:57
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://chenpiaoping.blog.51cto.com/5631143/1365106

HttpSM.cc
DNS的查询(包括hostdb的查询)从以下函数开始
void
HttpSM::set_next_state()
{
   ......
   HTTP_SM_SET_DEFAULT_HANDLER(&HttpSM::state_hostdb_lookup);
   do_hostdb_lookup();
   ......
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()
void
HttpSM::do_hostdb_lookup()
{
 ink_assert(t_state.dns_info.lookup_name != NULL);
 ink_assert(pending_action == NULL);
 milestones.dns_lookup_begin = ink_get_hrtime();
 bool use_srv_records = t_state.srv_lookup;
//在配置proxy.config.srv_enabled情况下的处理
 if (use_srv_records) {
   char d[MAXDNAME];
   memcpy(d, "_http._tcp.", 11); // don't copy '\0'
   ink_strlcpy(d + 11, t_state.server_info.name, sizeof(d) - 11 ); // all in the name of performance!
   DebugSM("dns_srv", "Beginning lookup of SRV records for origin %s", d);

   HostDBProcessor::Options opt;
   if (t_state.api_txn_dns_timeout_value != -1)
     opt.timeout = t_state.api_txn_dns_timeout_value;
   Action *srv_lookup_action_handle =
     hostDBProcessor.getSRVbyname_imm(this, (process_srv_info_pfn) & HttpSM::process_srv_info, d, 0, opt);

   if (srv_lookup_action_handle != ACTION_RESULT_DONE) {
     ink_assert(!pending_action);
     pending_action = srv_lookup_action_handle;
     historical_action = pending_action;
   } else {
     char *host_name = t_state.dns_info.srv_lookup_success ? t_state.dns_info.srv_hostname : t_state.dns_info.lookup_name;
     opt.port = t_state.dns_info.srv_lookup_success ? t_state.dns_info.srv_port : t_state.server_info.port;
     opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing)
           ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS
           : HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD
         ;
     opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0;
     opt.host_res_style = ua_session->host_res_style;
     Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this,
                                                                (process_hostdb_info_pfn) & HttpSM::
                                                                process_hostdb_info,
                                                                host_name, 0,
                                                                opt);
     if (dns_lookup_action_handle != ACTION_RESULT_DONE) {
       ink_assert(!pending_action);
       pending_action = dns_lookup_action_handle;
       historical_action = pending_action;
     } else {
       call_transact_and_set_next_state(NULL);
     }
   }
   return;
 } else {                      /* we arent using SRV stuff... */
   DebugSM("http_seq", "[HttpSM::do_hostdb_lookup] Doing DNS Lookup");
   int server_port = t_state.current.server ? t_state.current.server->port : t_state.server_info.port;
   if (t_state.api_txn_dns_timeout_value != -1) {
     DebugSM("http_timeout", "beginning DNS lookup. allowing %d mseconds for DNS lookup",
           t_state.api_txn_dns_timeout_value);
   }
   HostDBProcessor::Options opt;
   opt.port = server_port;//DNS server端口
   //一些标志为位
   opt.flags = (t_state.cache_info.directives.does_client_permit_dns_storing)
     ? HostDBProcessor::HOSTDB_DO_NOT_FORCE_DNS
     : HostDBProcessor::HOSTDB_FORCE_DNS_RELOAD
   ;
   opt.timeout = (t_state.api_txn_dns_timeout_value != -1) ? t_state.api_txn_dns_timeout_value : 0;//超时时间
   opt.host_res_style = ua_session->host_res_style;//类型:ipv4、ipv6
   //调用getbyname_imm进行DNS查询
   Action *dns_lookup_action_handle = hostDBProcessor.getbyname_imm(this, (process_hostdb_info_pfn) & HttpSM::process_hostdb_info, t_state.dns_info.lookup_name, 0, opt);
   if (dns_lookup_action_handle != ACTION_RESULT_DONE) {
     ink_assert(!pending_action);
     pending_action = dns_lookup_action_handle;
     historical_action = pending_action;
   } else {
     call_transact_and_set_next_state(NULL);
   }
   return;
 }
 ink_assert(!"not reached");
 return;
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()

Action *
HostDBProcessor::getbyname_imm(Continuation * cont, process_hostdb_info_pfn process_hostdb_info,
                              const char *hostname, int len, Options const& opt)
{
 ink_assert(cont->mutex->thread_holding == this_ethread());
 bool force_dns = false;
 EThread *thread = cont->mutex->thread_holding;
 ProxyMutex *mutex = thread->mutex;
 HostDBMD5 md5;
//对标志位进行处理
//是否强制进行DNS查询(不查hostdb)
 if (opt.flags & HOSTDB_FORCE_DNS_ALWAYS)
   force_dns = true;
 else if (opt.flags & HOSTDB_FORCE_DNS_RELOAD) {
   force_dns = (hostdb_re_dns_on_reload ? true : false);
   if (force_dns)
     HOSTDB_INCREMENT_DYN_STAT(hostdb_re_dns_on_reload_stat);
 }
 HOSTDB_INCREMENT_DYN_STAT(hostdb_total_lookups_stat);

 if (!hostdb_enable || !*hostname) {
   (cont->*process_hostdb_info) (NULL);
   return ACTION_RESULT_DONE;
 }
//创建待查询域名的md5结构
 md5.host_name = hostname;
 md5.host_len = hostname ? (len ? len : strlen(hostname)) : 0;
 md5.port = opt.port;
 md5.db_mark = db_mark_for(opt.host_res_style);
#ifdef SPLIT_DNS
//如果开启splitDNS功能,则查找对应的DNS server
 if (SplitDNSConfig::isSplitDNSEnabled()) {
   const char *scan = hostname;
   for (; *scan != '\0' && (ParseRules::is_digit(*scan) || '.' == *scan); scan++);
   if ('\0' != *scan) {
     SplitDNS* pSD = SplitDNSConfig::acquire();
     if (0 != pSD)
       md5.dns_server = static_cast<DNSServer*>(pSD->getDNSRecord(md5.host_name));
     SplitDNSConfig::release(pSD);
   }
 }
#endif // SPLIT_DNS
 md5.refresh();
//先查hostdb,查不到再进行DNS查询
 if (!force_dns) {
   bool loop;
   do {
     loop = false;
     ProxyMutex *bucket_mutex = hostDB.lock_for_bucket((int) (fold_md5(md5.hash) % hostDB.buckets));
     MUTEX_LOCK(lock, bucket_mutex, thread);
     if (lock) {
       HostDBInfo *r = probe(bucket_mutex, md5, false);
       if (r) {
         if (r->failed())
           loop = check_for_retry(md5.db_mark, opt.host_res_style);
         if (!loop) {
           Debug("hostdb", "immediate answer for %.*s", md5.host_len, md5.host_name);
           HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
           (cont->*process_hostdb_info) (r);
           return ACTION_RESULT_DONE;
         }
         md5.refresh();
       }
     }
   } while (loop);
 }

 Debug("hostdb", "delaying force %d answer for %.*s [timeout %d]", force_dns, md5.host_len, md5.host_name, opt.timeout);
//hostdb查询失败,进行DNS查询,遵循ATS的continuation模式(异步),先创建一个HostDBContinuation,再进行下面的DNS查询操作
 HostDBContinuation *c = hostDBContAllocator.alloc();
 HostDBContinuation::Options copt;
 copt.cont = cont;//指向HttpSM的实例
 copt.force_dns = force_dns;
 copt.timeout = opt.timeout;
 copt.host_res_style = opt.host_res_style;
 c->init(md5, copt);
 SET_CONTINUATION_HANDLER(c, (HostDBContHandler) & HostDBContinuation::probeEvent);
 thread->schedule_in(c, HOST_DB_RETRY_PERIOD);
 return &c->action;
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()--->HostDBContinuation::probeEvent()

int
HostDBContinuation::probeEvent(int /* event ATS_UNUSED */, Event * e)
{
 ink_assert(!link.prev && !link.next);
 EThread *t = e ? e->ethread : this_ethread();
 MUTEX_TRY_LOCK_FOR(lock, action.mutex, t, action.continuation);
 if (!lock) {
   mutex->thread_holding->schedule_in(this, HOST_DB_RETRY_PERIOD);
   return EVENT_CONT;
 }
 if (action.cancelled) {
   hostdb_cont_free(this);
   return EVENT_DONE;
 }
//检查一下主机名
 if (!hostdb_enable || (!*md5.host_name && !md5.ip.isValid())) {
   if (action.continuation)
     action.continuation->handleEvent(EVENT_HOST_DB_LOOKUP, NULL);
#ifdef NON_MODULAR
   if (from)
     do_put_response(from, 0, from_cont);
#endif
   hostdb_cont_free(this);
   return EVENT_DONE;
 }
//如果没有强制DNS,先再查一下hostdb
 if (!force_dns) {
   HostDBInfo *r = probe(mutex, md5, false);
   if (r)
     HOSTDB_INCREMENT_DYN_STAT(hostdb_total_hits_stat);
#ifdef NON_MODULAR
   if (action.continuation && r)
     reply_to_cont(action.continuation, r);
//cluster模式,等到分析cluster源码时再说
   if (from)
     do_put_response(from, r, from_cont);
#endif
   if (r || from) {
     hostdb_cont_free(this);
     return EVENT_DONE;
   }
#ifdef NON_MODULAR
   if (do_get_response(e))
     return EVENT_CONT;
#endif
 }
//进行DNS查询吧
 do_dns();
 return EVENT_DONE;
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()--->HostDBContinuation::probeEvent()--->HostDBContinuation::do_dns()

这个函数的功能主要是设置超时处理函数,把请求加入到等待队列和调用 dnsProcessor的相应函数进行DNS查询
void
HostDBContinuation::do_dns()
{
 ink_assert(!action.cancelled);
 if (is_byname()) {
   Debug("hostdb", "DNS %s", md5.host_name);
   IpAddr tip;
//如果待查询的域名是ip地址了,直接通知HttpSM吧,不用往下查询了
   if (0 == tip.load(md5.host_name)) {
     // check 127.0.0.1 format // What the heck does that mean? - AMC
     if (action.continuation) {
       HostDBInfo *r = lookup_done(tip, md5.host_name, false, HOST_DB_MAX_TTL, NULL);
       reply_to_cont(action.continuation, r);
     }
     hostdb_cont_free(this);
     return;
   }
 }
//超时调用HostDBContinuation::dnsEvent处理
 if (hostdb_lookup_timeout)
   timeout = mutex->thread_holding->schedule_in(this, HRTIME_SECONDS(hostdb_lookup_timeout));
 else
   timeout = NULL;
 if (set_check_pending_dns()) {//加入等待队列
   DNSProcessor::Options opt;//初始化一些选项
   opt.timeout = dns_lookup_timeout;
   opt.host_res_style = host_res_style_for(md5.db_mark);
   SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsEvent);
   if (is_byname()) {
     if (md5.dns_server)
       opt.handler = md5.dns_server->x_dnsH;
//进行真正的查询处理
     pending_action = dnsProcessor.gethostbyname(this, md5.host_name, opt);
   } else if (is_srv()) {
     Debug("dns_srv", "SRV lookup of %s", md5.host_name);
     pending_action = dnsProcessor.getSRVbyname(this, md5.host_name, opt);
   } else {
     ip_text_buffer ipb;
     Debug("hostdb", "DNS IP %s", md5.ip.toString(ipb, sizeof ipb));
     pending_action = dnsProcessor.gethostbyaddr(this, &md5.ip, opt);
   }
 } else {
   SET_HANDLER((HostDBContHandler) & HostDBContinuation::dnsPendingEvent);
 }
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()--->HostDBContinuation::probeEvent()--->HostDBContinuation::do_dns()--->DNSProcessor::gethostbyname()--->DNSProcessor::getby()
这个函数的功能是创建并初始化查询表项,这个表项要放到一个表中,然后由专门的线程从这个表中取出该表项进行DNS查询(异步嘛)
Action *
DNSProcessor::getby(const char *x, int len, int type, Continuation *cont, Options const& opt)
{
 Debug("dns", "received query %s type = %d, timeout = %d", x, type, opt.timeout);
 if (type == T_SRV) {
   Debug("dns_srv", "DNSProcessor::getby attempting an SRV lookup for %s, timeout = %d", x, opt.timeout);
 }
//创建查询表项
 DNSEntry *e = dnsEntryAllocator.alloc();
 e->retries = dns_retries;
//初始化查询表项
 e->init(x, len, type, cont, opt);
 MUTEX_TRY_LOCK(lock, e->mutex, this_ethread());
 if (!lock)
   thread->schedule_imm(e);
 else
//调度DNSEntry::mainEvent执行
   e->handleEvent(EVENT_IMMEDIATE, 0);
 return &e->action;
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()--->HostDBContinuation::probeEvent()--->HostDBContinuation::do_dns()--->DNSProcessor::gethostbyname()--->DNSProcessor::getby()--->DNSEntry::init()

这个函数的功能是初始化DNS查询表项

void
DNSEntry::init(const char *x, int len, int qtype_arg, Continuation* acont,
              DNSProcessor::Options const& opt)
{
 qtype = qtype_arg;//查询类型:T_A、T_NS、T_CNAME...
 host_res_style = opt.host_res_style;//ip类型:ipv4、ipv6
 if (is_addr_query(qtype)) {
     // adjust things based on family preference.
     if (HOST_RES_IPV4 == host_res_style ||
         HOST_RES_IPV4_ONLY == host_res_style) {
         qtype = T_A;
     } else if (HOST_RES_IPV6 == host_res_style ||
                HOST_RES_IPV6_ONLY == host_res_style) {
         qtype = T_AAAA;
     }
 }
 submit_time = ink_get_hrtime();//提交时间
 action = acont;//指向HostDBContinuation
 submit_thread = acont->mutex->thread_holding;

#ifdef SPLIT_DNS
//如果开启splitDNS功能,那使用的DNSHandler是该DNS server对应的handler,否则使用DNS初始化时创建的吧
 if (SplitDNSConfig::gsplit_dns_enabled) {
   dnsH = opt.handler ? opt.handler : dnsProcessor.handler;
 } else {
   dnsH = dnsProcessor.handler;
 }
#else
 INK_NOWARN(adnsH);
 dnsH = dnsProcessor.handler;
#endif // SPLIT_DNS
 dnsH->txn_lookup_timeout = opt.timeout;
 mutex = dnsH->mutex;
//根据DNS查询类型设置查询的主机名
 if (is_addr_query(qtype) || qtype == T_SRV) {
   if (len) {
     len = len > (MAXDNAME - 1) ? (MAXDNAME - 1) : len;
     memcpy(qname, x, len);
     qname_len = len;
     qname[len] = 0;
   } else {
     ink_strlcpy(qname, x, MAXDNAME);
     qname_len = strlen(qname);
   }
 } else {                    //T_PTR
   IpAddr const* ip = reinterpret_cast<IpAddr const*>(x);
   if (ip->isIp6())
     make_ipv6_ptr(&ip->_addr._ip6, qname);
   else if (ip->isIp4())
     make_ipv4_ptr(ip->_addr._ip4, qname);
   else
     ink_assert(!"T_PTR query to DNS must be IP address.");
 }
//设置DNSEntry的handler为DNSEntry::mainEvent
 SET_HANDLER((DNSEntryHandler) & DNSEntry::mainEvent);
}
HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()--->HostDBContinuation::probeEvent()--->HostDBContinuation::do_dns()--->DNSProcessor::gethostbyname()--->DNSProcessor::getby()--->DNSEntry::init()--->DNSEntry::mainEvent()

这个函数的功能是把创建的DNS查询表项到DNSHandler的队列entries中,然后调用write_dns遍历该队列处理每个表项
int
DNSEntry::mainEvent(int event, Event *e)
{
 switch (event) {
 default:
   ink_assert(!"bad case");
   return EVENT_DONE;
 case EVENT_IMMEDIATE:{
       //到这了handler应该设置好了
     if (!dnsH)
       dnsH = dnsProcessor.handler;
     if (!dnsH) {
       Debug("dns", "handler not found, retrying...");
       SET_HANDLER((DNSEntryHandler) & DNSEntry::delayEvent);
       return handleEvent(event, e);
     }
   //看配置是否要在主机名后加上扩展后缀
     if (dns_search)
       domains = dnsH->m_res->dnsrch;
   //如果需要在主机名后加上.org(配置文件中配的)这样的后缀
     if (domains && !strnchr(qname, '.', MAXDNAME)) {
       qname[qname_len] = '.';
       ink_strlcpy(qname + qname_len + 1, *domains, MAXDNAME - (qname_len + 1));
       qname_len = strlen(qname);
       ++domains;
     }
     Debug("dns", "enqueing query %s", qname);
   //在DNSHandler的entries队列中查找该表项,如果已经有了,加到重复队列dups中
     DNSEntry *dup = get_entry(dnsH, qname, qtype);
     if (dup) {
       Debug("dns", "collapsing NS request");
       dup->dups.enqueue(this);
     } else {
       Debug("dns", "adding first to collapsing queue");
       dnsH->entries.enqueue(this);
   //遍历 entries队列处理每一个DNS查询表项
       write_dns(dnsH);
     }
     return EVENT_DONE;
   }
 case EVENT_INTERVAL:
   Debug("dns", "timeout for query %s", qname);
   if (dnsH->txn_lookup_timeout) {
     timeout = NULL;
     dns_result(dnsH, this, result_ent, false);        //do not retry -- we are over TXN timeout on DNS alone!
     return EVENT_DONE;
   }
   if (written_flag) {
     Debug("dns", "marking %s as not-written", qname);
     written_flag = false;
     --(dnsH->in_flight);
     DNS_DECREMENT_DYN_STAT(dns_in_flight_stat);
   }
   timeout = NULL;
   dns_result(dnsH, this, result_ent, true);
   return EVENT_DONE;
 }
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()--->HostDBContinuation::probeEvent()--->HostDBContinuation::do_dns()--->DNSProcessor::gethostbyname()--->DNSProcessor::getby()--->DNSEntry::init()--->DNSEntry::mainEvent()

这个函数的功能是遍历DNSHandler的队列entries处理每个表项

static void
write_dns(DNSHandler *h)
{
 ProxyMutex *mutex = h->mutex;
 DNS_INCREMENT_DYN_STAT(dns_total_lookups_stat);
 int max_nscount = h->m_res->nscount;
 if (max_nscount > MAX_NAMED)
   max_nscount = MAX_NAMED;
//别的线程正在处理中
 if (h->in_write_dns)
   return;
 h->in_write_dns = true;
 if (h->in_flight < dns_max_dns_in_flight) {//dns_max_dns_in_flight控制一次最大发送的DNS请求
   DNSEntry *e = h->entries.head;
   while (e) {
     DNSEntry *n = (DNSEntry *) e->link.next;
     if (!e->written_flag) {
       //如果是round_robin模式,则循环使用DNS server
       if (dns_ns_rr) {
         int ns_start = h->name_server;
         do {
           h->name_server = (h->name_server + 1) % max_nscount;
         } while (h->ns_down[h->name_server] && h->name_server != ns_start);
       }
       //发送一个DNS查询请求,如果失败则不往下处理了
       if (!write_dns_event(h, e))
         break;
     }
     if (h->in_flight >= dns_max_dns_in_flight)
       break;
     e = n;
   }
 }
 h->in_write_dns = false;
}

HttpSM::set_next_state()--->HttpSM::do_hostdb_lookup()--->HostDBProcessor::getbyname_imm()--->HostDBContinuation::probeEvent()--->HostDBContinuation::do_dns()--->DNSProcessor::gethostbyname()--->DNSProcessor::getby()--->DNSEntry::init()--->DNSEntry::mainEvent()--->write_dns_event()

这个函数的功能是构建DNS查询报文并发送一个DNS查询请求,发送DNS查询请求流程到此结束

static bool
write_dns_event(DNSHandler *h, DNSEntry *e)
{
 ProxyMutex *mutex = h->mutex;
 union {
   HEADER _h;
   char _b[MAX_DNS_PACKET_LEN];
 } blob;
 int r = 0;
//创建DNS查询报文,其中qname为待查询的域名
 if ((r = _ink_res_mkquery(h->m_res, e->qname, e->qtype, blob._b)) <= 0) {
   Debug("dns", "cannot build query: %s", e->qname);
   //处理以一个表项的查询结果:重试
   dns_result(h, e, NULL, false);
   return true;
 }
//生成该报文的id
 uint16_t i = h->get_query_id();
 blob._h.id = htons(i);
 if (e->id[dns_retries - e->retries] >= 0) {
   //clear previous id in case named was switched or domain was expanded
   h->release_query_id(e->id[dns_retries - e->retries]);
 }
//记录每次查询的报文id
 e->id[dns_retries - e->retries] = i;
 Debug("dns", "send query (qtype=%d) for %s to fd %d", e->qtype, e->qname, h->con[h->name_server].fd);
//发送DNS查询请求
 int s = socketManager.send(h->con[h->name_server].fd, blob._b, r, 0);
//发送失败处理
 if (s != r) {
   Debug("dns", "send() failed: qname = %s, %d != %d, nameserver= %d", e->qname, s, r, h->name_server);
   // changed if condition from 'r < 0' to 's < 0' - 8/2001 pas
   if (s < 0) {
     if (dns_ns_rr)
       h->rr_failure(h->name_server);
     else
       h->failover();
   }
   return false;
 }
//设置相应的标志和计数
 e->written_flag = true;//已经发送
 e->which_ns = h->name_server;//指向使用的DNS server
 e->once_written_flag = true;
 ++h->in_flight;//计数
 DNS_INCREMENT_DYN_STAT(dns_in_flight_stat);
 e->send_time = ink_get_hrtime();//发送时间

 if (e->timeout)
   e->timeout->cancel();
//设置超时处理,超时后执行DNSEntry::mainEvent
 if (h->txn_lookup_timeout) {
   e->timeout = h->mutex->thread_holding->schedule_in(e, HRTIME_MSECONDS(h->txn_lookup_timeout));
 } else {
   e->timeout = h->mutex->thread_holding->schedule_in(e, HRTIME_SECONDS(dns_timeout));
 }
 Debug("dns", "sent qname = %s, id = %u, nameserver = %d", e->qname, e->id[dns_retries - e->retries], h->name_server);
//最后,记录失败的次数和时间,先假设失败,等响应了再置成功
 h->sent_one();
 return true;
}

本文出自 “陈漂评的博客” 博客,请务必保留此出处http://chenpiaoping.blog.51cto.com/5631143/1365106

0 0