1. 程式人生 > >trafficserver的DNS響應主要流程原始碼註釋

trafficserver的DNS響應主要流程原始碼註釋

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);
   }
 }
}