您的位置:首页 > 其它

Radvision H248 DNS解析机制实现

2014-11-19 19:06 295 查看
一、初始化
//获取select引擎对象
RvSelectGetThreadEngine(pRslvMgr->pLogMgr,&pSelect);

//构造DNS引擎对象
RvAresConstruct(.....);
dnsEngine->userQueryId  = 1; //请求ID
dnsEngine->selectEngine = selectEngine; //关联select引擎对象
dnsEngine->newRecordCB  = newRecordCB;
//设置处理回调,这里基于sip的解析器模块实现进行分析,当前回调函数为
//ResolverDNSNewRecordCB
//初始化主机配置文件数据对象
dnsEngine->ehd = 0;
//将select引擎中的定时器队列设置到dnsEngine->timerQueue中
RvSelectGetTimeoutInfo(selectEngine, NULL, &dnsEngine->timerQueue);
dnsEngine->logMgr = logMgr;
dnsEngine->dnsSource = &logMgr->dnsSource;
//memset
RvAresCacheParamsInit(&cacheParams);

RvAresCacheDNew(......)
//设置最大查询数
params->maxActiveQueriesNum = RV_DNS_CACHE_MAX_ACTIVE_QUERIES;

//为dnsEngine->cached分配内存资源,dnsEngine->cached为第一个传入的参数
totalSize = sizeof(**pSelf) +
(params->maxActiveQueriesNum - 1) * sizeof((*pSelf)->pool[0]);
RvMemoryAlloc(0, totalSize, logMgr, (void **)pSelf);

//缓冲对象构造
RvAresCacheDConstruct(*pSelf, seli, logMgr, params);
RvLockConstruct(logMgr, &self->lock);

cache = &self->cache;
RvAresCacheConstruct(cache, params);
RvAresCacheUpdateTime();
//分配一个线路变量gsCacheCtxIdx,同时为该指针变量分配内存
ctx = RvAresCacheGetCtx();
ctx->time = RvAresGetTime();
//从静态全局变量gsTime中获取值,初始为0
pageSize = RV_DNS_CACHE_PAGE_SIZE;
nPages = RV_DNS_CACHE_PAGES_NUMBER;
hashSize = RV_DNS_CACHE_HASH_SIZE;

//构造cell槽,用于DNS请求结果缓存
RvAresCacheCellsConstruct(&self->cells, params->cellsNum,
params->minTTL);
numCells = RV_DNS_CACHE_NUM_CELLS;
//最小及最大缓冲页超时周期
self->minTtl = RV_DNS_CACHE_MIN_TTL;
self->maxTtl = self->minTtl << (numCells - 1);
numCells += 2;
self->maxSize = numCells;
self->curSize = 0;
self->startTime = RvAresGetCacheTime();

RvMemoryAlloc(0, numCells * sizeof(*self->cells), logMgr,
&self->cells);

//构造内存页
RvAresPageAllocatorConstruct(&self->pageAllocator, pageSize, 0,
pageSize * nPages);

RvAresHashConstruct(&self->hash, 0, hashSize);

self->expiredPages.first = 0;
self->expiredPages.last  = 0;
self->domains = 0;
self->domainsSize = 0;

//设置域,当前params中还没有域的设置值
RvAresCacheSetDomains(self, params->domains, params->nDomains);

//构建套接口对象
RvSocketConstruct(RV_ADDRESS_TYPE_IPV4, RvSocketProtocolUdp, logMgr,
&srvSock);
RvAddressConstruct(RV_ADDRESS_TYPE_IPV4, pLocalAddr);
RvAddressSetString("127.0.0.1", pLocalAddr);
RvAddressSetIpPort(pLocalAddr, params->cachedPort);
RvSocketBind(&srvSock, pLocalAddr, 0, logMgr);

self->seli  = seli; //关联select引擎

//将需要监控的套接口及文件描述符对象加入select引擎对象,同时设置该套
//接口的接收处理回调函数为RvAresCacheDOnNet,这里的套接口用于本地
//从缓冲池中获取解析对象,之后异步处理方式的话,则发送到这个套接口
//之后在进行解析结果的处理。
RvFdConstruct(&self->srvFd, &srvSock, logMgr);
RvSelectAdd(seli, &self->srvFd, RvSelectRead, RvAresCacheDOnNet);

//self->activeQuery = 0;
//将self->pool列表进行关联,最后一个列表元素next指向0
RvAresCacheDQueriesConstruct(self, params->maxActiveQueriesNum)

self->sentResults = 0;
self->acceptedResults = 0;

ares_construct(dnsEngine, maxServers, maxDomains, tcpBuffLen, &options, optmask);
channel->flags = -1;
channel->timeout = RvInt64Const(-1,0,1);
channel->tries = -1;
channel->ndots = -1;
channel->udp_port = (RvUint16)-1;
channel->tcp_port = (RvUint16)-1;
channel->max_servers = 0;
channel->max_domains = 0;
channel->ehdOrder = RV_EHD_SEARCH_HOSTS_FIRST;

RvLockConstruct(channel->logMgr, &channel->lock);

//为DNS服务列表分配内存
RvMemoryAlloc(NULL, max_servers * sizeof(rvServerState),channel->logMgr,
(void**)&channel->servers);

channel->max_servers = max_servers;
channel->nservers    = 0;

for (i=0; i < max_servers; ++i)
RvMemoryAlloc(NULL, tcp_bufflen,channel->logMgr,
(void**)&channel->servers[i].tcp_buffer);

channel->tcp_bufflen = tcp_bufflen;

RvMemoryAlloc(NULL, max_domains * sizeof(char*),channel->logMgr,
(void**)&channel->domains);

channel->max_domains      = max_domains;
channel->ndomains         = 0;
channel->longest_domain_i = -1;

for (i=0; i < max_domains; ++i)
RvMemoryAlloc(NULL, RV_DNS_MAX_NAME_LEN+1,hannel->logMgr,
(void**)&channel->domains[i]);

//准备从hosts文件中获取主机列表,这里该功能宏没有开启,不使用。
RvAresConfigureEhd(channel);
dnsEngine->ehd = 0;
dnsEngine->ehdOrder = RV_EHD_SEARCH_HOSTS_FIRST;

//根据用户配置的选项进行设置
ares_set_options(channel, options, optmask);
if (optmask & ARES_OPT_FLAGS)
channel->flags = options->flags;
if (optmask & ARES_OPT_TIMEOUT)
channel->timeout = options->timeout;
if (optmask & ARES_OPT_TRIES)
channel->tries = options->tries;
if (optmask & ARES_OPT_NDOTS)
channel->ndots = options->ndots;
if (optmask & ARES_OPT_UDP_PORT)
channel->udp_port = options->udp_port;
if (optmask & ARES_OPT_TCP_PORT)
channel->tcp_port = options->tcp_port;

if ((optmask & ARES_OPT_SERVERS) && (options->nservers > 0))
//起始服务索引,当前没有使用HOSTS配置文件功能,ehd为false
channel->nservers = channel->ehd ? 1 : 0

//添加DNS服务地址
for (i = 0; i < options->nservers; i++)
init_server(channel, &options->servers[i]);
//如果使用HOSTS配置文件则索引从1开始
if(channel->ehd)
i++;

//如果已经存在则直接返回
for(; i < channel->nservers; ++i)
if (RvAddressCompare(&channel->servers[i].addr, addr,
RV_ADDRESS_BASEADDRESS) == RV_TRUE)
return ARES_SUCCESS;

//加入DNS服务列表
i = channel->nservers;
channel->servers[i].addr = *addr;
channel->servers[i].udp_socket.fd.fd = (RvSocket)-1;
channel->servers[i].tcp_socket.fd.fd = (RvSocket)-1;
channel->nservers++;

//进行配置项修正,如果用户没配置对应值则进行校正为合法的默认值
init_by_defaults(channel);

//如果设置了ARES_FLAG_PRIMARY标记,则限制仅使用1个DNS服务
if ((channel->flags & ARES_FLAG_PRIMARY) && channel->nservers > 1)
channel->nservers = 1;

//初始化请求ID
timeVal = time(NULL);
RvRandomGeneratorConstruct(&randGenObj, timeVal);
RvRandomGeneratorGetInRange(&randGenObj, 0xffff, &randNum);
channel->next_id = (unsigned short)randNum;

channel->queries = NULL;

---------------------------------------------------------------------------------------------------------------------
RvAresCacheDOnNet
//接收从本地缓冲池获取的解析结果
RvSocketReceiveBuffer(sock, (void *)&packet, sizeof(packet), logMgr, &received, 0);

self->acceptedResults++;

//进行包解析,当前包的格式为
//
//  |------------------------------------------------------|
//  |nameLen|nameString| ipv4Addr|<-curPtr
//
RvAresCacheDAnalyzePacket(self, &packet);
//当前未有任何解析结果,返回
nRecords = packet->nRecords;
if(nRecords < 1)
return;

data.dataType = data.recordType = packet->recordType;
data.ttl = 0;
qid = packet->qid;

//从activeQuery请求队列取出当前缓冲请求
RvAresCacheDRemoveQuery(self, qid, &query);

onNewRecordCB = query->cb;
ctx = query->ctx;
query->inCallback = RV_TRUE;

//从解析数据中提供域名设置到data.ownerName
RvAresCacheDeserializeRdata(&data, &curPtr);

switch(data.recordType)
case T_A: //ipv4主机地址类型
deserialize = RvAresCacheDeserializeA; //该类型地址提取回调函数

data.recordNumber = 0;

for(i = 0; i < nRecords; i++)
//更新解析成功后的地址个数
data.recordNumber++;
//提取解析成功的地址设置到data.data.hostAddress中
deserialize(&data, &curPtr);

//这里的回调函数为ResolverDNSNewRecordCB
onNewRecordCB(ctx, qid, &data);

//调用回调通知已经遍历完,该回调为 ResolverDNSNewRecordCB
data.dataType = RV_DNS_ENDOFLIST_TYPE;
onNewRecordCB(ctx, qid, &data);

query->inCallback = RV_FALSE;

二、发送DNS请求
RvAresSendQuery
switch (dnsQuery)
//这里仅分析解析IPv4地址类形
case RV_DNS_HOST_IPV4_TYPE:
queryType = T_A;

//获取当前请求ID,并传回给用户层调用点
*queryId = dnsEngine->userQueryId++;

//先从缓存中查找
RvAresCacheDFind(dnsEngine->cached,queryType,dnsName,strlen(dnsName),RV_TRUE,
dnsEngine->newRecordCB,context,*queryId);
//更新当前时间
RvAresCacheUpdateTime();

ctx.self = self;
ctx.s = RV_OK;
packet = &ctx.packet;
ctx.curPtr = packet->buffer; //将curPtr指向ctx.packet.buffer
ctx.endPtr = packet->buffer + sizeof(packet->buffer);
packet->nRecords = 0;
packet->qid = qid; //记载该次请求ID
packet->recordType = (RvUint8)queryType; //记载该次请求类型

//去记录集中查找
RvAresCacheFindRecordset(&self->cache, queryType, name, nameSize,
RvAresCacheDOnRecord, &ctx);
RvAresCacheFindWithDomains(self, type, name, nameSize)
//结尾是点,则表示全域名
if(*last == '.')
*last = '\0';
fullName = RV_TRUE;

RvAresCacheFind(self, type, name, nameSize, 0);
//从hash缓存表中获取记录
curRec = RvAresHashFind(hash, type, name, nameSize, insertPoint);
//获取当前时间
curTime = RvAresGetCacheTime();

//从hash缓存表中获取记录,如果没有则返回0
curRec = RvAresHashFindAux(self, t, name, nameSize,
insertPoint);
if(curRec == 0)
return 0;

//虽然hash缓存表中有记录,但该记录已经过期,从hash缓
//存池中移去记录,同时返回0
if(curRec->pageEntry.expirationTime < curTime)
RvAresHashRemove(self, curRec);
return 0;

return curRec; //返回找到的记录值

//当查询失败后,继续尝试与CNAME类型进行匹配查找
while(curRec == 0)
curRec = RvAresHashFind(hash, T_CNAME, name, nameSize, 0);
if(curRec == 0)
return 0;

pe = curRec->pageEntry.nextExtension;
if(pe == 0)
RvAresHashRemove(hash, curRec);
return 0;

cname = RvObjectFromField(RvRdataCNAMEExtension,
pageEntry, pe);
name = cname->name;
nameSize = cname->nameSize;

curRec = RvAresHashFind(hash, type, name, nameSize, 0);

//如果全名格式查找,则直接返回结果
if(fullName)
*last = '.';
return rec;

//当前没有设置搜索域,返回查找结果
sdomains = self->domains;
if(rec || sdomains == 0 || sdomains[0] == 0)
return rec;

//进行附加搜索域的处理

//在缓冲中没有找到,返回错误
if(curRec == 0)
return RV_DNS_ERROR_NOTFOUND;

idx = curRec->idx;
first = &curRec->pageEntry;
pe = first->nextExtension;

//调用回调RvAresCacheDOnRecord处理第一个找到的数据
cb(self, type, name, nameSize, &curRec->pageEntry, cookie);

//ipv4主机解析类型的有idx值
if(idx > -1)
//有可能一个域名解析了多个对应ip地址,则根据条目的nextExtension
//扩展链接来重新记录索引数,并将真实记录存储到curRec->idx,这里
//newIdx + 1是因为上面已经处理了第一个记录
for(i = 0; i < idx; i++)
pe = pe->nextExtension;
if(pe == 0)
newIdx = 0;
pe =  first->nextExtension;
else
newIdx++;
curRec->idx = newIdx + 1;

end = pe;

for(;;)
//依次进行RvAresCacheDOnRecord回调处理
if(pe != first)
cb(self, type, name, nameSize, pe, cookie);
pe = pe->nextExtension;
//在上面循环中pe条目已经指向最后,所以这里回环到扩展链表首
if(pe == 0)
pe = first->nextExtension;
if(pe == end)
break;

//如果在缓冲中没有找到,直接返回错误
if(s != RV_OK)
return s;

//更新当前ctx.packet.buffer中已经填充的数据长度。
packet->bufSize = (RvUint16)(ctx.curPtr - packet->buffer);

//将当前请求加入到activeQuery请求队列,当前回调为ResolverDNSNewRecordCB
RvAresCacheDAddQuery(self, qid, cb, cbCtx);
q = self->freeQuery;
self->freeQuery = q->next;
q->cb = cb;
q->ctx = cookie;
q->qid = qid;
q->inCallback = RV_FALSE;
q->next = self->activeQuery;
self->activeQuery = q;

if(!asyncQuery)
//上面传入为异步请求处理,asyncQuery为TRUE
else
bytesToSend =  (RvSize_t)(ctx.curPtr - (RvUint8 *)&ctx.packet);

//这里的套接口句柄是当初在RvAresConstruct进行构造Ares对象时创建的,
//这个套接口对象已经加入到了select引擎对象中,用于进行DNS收发包处理
sock = RvFdGetSocket(&self->srvFd);

//这里是一个比较有意义的点,当前的异步机制实现机制就是,从本地缓冲池
//获取记录后,发给本地的ares监听套接口,该套接口对象已经在
//RvAresCacheDOnNet中创建,对应的回调处理函数为RvAresCacheDOnNet。
RvSocketSendBuffer(sock, (RvUint8 *)packet, bytesToSend, &self->srvAddr,
logMgr, &bytesSent);

//如果在缓冲池中查找成功,则直接返回
if(status == RV_OK)
return status;

//初始化为exception = RV_OK
rvAresInitException(&exception);

//发送请求
ares_query(dnsEngine, dnsName, C_IN, queryType, queryBuffer,qbufLen, rvDnsCallback,
context, *queryId);
//计算请求报文上度(固定的报头长度+查询头的类型+查询头的分类+查询的域名)
qlen = HFIXEDSZ + encoded_name_length(name) + QFIXEDSZ;

//4字节对齐?
queryWords = sizeof(rvQuery) / sizeof(int) + 1;

rvQuery *query = (rvQuery *)query_buf;
query->qid = channel->next_id++;
query->user_qid = qid;
query->timeout = RvInt64Const(0,0,0);
query->user_callback = callback; //这里回调为 rvDnsCallback
query->user_arg = usr_arg;
RvTimerConstruct(&query->timer);

//skip_server先跳过rvQuery结构体
query->skip_server = (int*)((char*)query + queryWords * sizeof(int));
query->try_index = 0;

//当前不支持hosts文件处理,所有server为0
query->server = (channel->ehdOrder == RV_EHD_SEARCH_HOSTS_FIRST) ? 0 : 1;

//根据当前配置的DNS服务器数量,复位skip_server标记位,这里的skip_server
//为1时,表示发起DNS请求时,不再使用该服务器。
for (i = 0; i < channel->nservers; i++)
query->skip_server[i] = 0;

//假设当前没有使用TCP,并且报文总长度也未超过UDP的阀值,则使用UDP
query->using_tcp = (channel->flags & ARES_FLAG_USEVC) || qlen > PACKETSZ;

query->error_status = ARES_ECONNREFUSED;

//qbuf指向缓冲区的server之后
// ---------------------------------------------------------
// | rvQuery | server1 | server2 | qbuf<-----
//----------------------------------------------------------
query->qbuf = (char*)query->skip_server + (channel->nservers * sizeof(int));

query->qlen = qlen;

//前16位记载查询记录头的长度,TCP询问头需要预填充2个字节长度
query->qbuf[0] = (char)((qlen >> 8) & 0xff);
query->qbuf[1] = (char)(qlen & 0xff);
//跳过TCP询问头
query->qbuf += 2;

//是否有扩展
rd = !(channel->flags & ARES_FLAG_NORECURSE);

//填充询问头
ares_mkquery(name, dnsclass, type, query->qid, rd, query->qbuf);

//将当前请求控制块加入到DNS引擎对象的请求列表中
query->qnext = channel->queries;
channel->queries = query;

//发送请求
now = RvTimestampGet(channel->logMgr);
status = ares__send_query(channel, query, now);
//当前没有配置DNS服务器的话返回错误
if (channel->nservers <= 0)
return ARES_ENOSERVERS;

//提取第一个DNS服务
server = &channel->servers[query->server];

if (server->udp_socket.fd.fd == RV_INVALID_SOCKET)
open_socket(channel, query->server, RvSocketProtocolUdp)
//获取当前服务器
server = &channel->servers[whichserver];

port = channel->udp_port;
fd_args = &server->udp_socket;

//创建套接口对象
RvSocketConstruct(RV_ADDRESS_TYPE_IPV4, protocol,
channel->logMgr, &s);
origPort = RvAddressGetIpPort(&server->addr);

//设置为非阻塞
RvSocketSetBlocking(&s, RV_FALSE, channel->logMgr);

//保存这次请求使用的协议,哪个DNS服务索引,DNS控制块对象
fd_args->protocol = protocol;
fd_args->server   = whichserver;
fd_args->channel  = channel;

//将新建的套接口对象加入到select引擎对象中,这里该套接口处理
//的回调函数为 selectCb
RvFdConstruct(&fd_args->fd, &s, channel->logMgr);

RvSelectAdd(channel->selectEngine, &fd_args->fd,
RV_SELECT_READ, selectCb);

---------------------------------------------------------------------------------------------------------------------
//在缓冲池中已经找到解析信息,进行解析处理
RvAresCacheDOnRecord
//如果最高位(无符号字符类型)没有置位,则表明是普通解析数据,否则为扩展
//解析数据。
if((entry->type & 0x7f) == entry->type)
//获取页数据
rdata = RvObjectFromField(RvRdata, pageEntry, entry);

//这里仅仅是要查询的域名及域名长度设置到ctx.packet.buffer中,同时移动
//ctx.packet.buffer指针
//
//  |------------------------------------------------------|
//  |nameLen|nameString| <-curPtr
//
ctx->s = RvAresCacheSerializeRdata(rdata, &ctx->curPtr, ctx->endPtr);
return;

ctx->packet.nRecords++;

switch(type)
case T_A: //仅分析ipv4地址解析类型
//从页中获取扩展数据类型
arec = RvObjectFromField(RvRdataAExtension, pageEntry, entry);

//把获取的解析成功的地址追加到ctx.packet.buffer尾部
//
//  |------------------------------------------------------|
//  |nameLen|nameString| ipv4Addr|<-curPtr
//
RvAresCacheSerializeA(arec, &ctx->curPtr, ctx->endPtr);

---------------------------------------------------------------------------------------------------------------------
//DNS请求的应答处理
selectCb
//获取当前时间
now = RvTimestampGet(channel->logMgr);
if (!error) //没有错误
if (fd_args->protocol == RvSocketProtocolUdp)
//应答处理
read_udp_packets(channel, fd_args, now);
server = &channel->servers[fd_args->server];

//从套接口获取回应消息
RvSocketReceiveBuffer(&server->udp_socket.fd.fd, buf, sizeof(buf),
channel->logMgr, (RvSize_t*)&count, &remoteAddress);

//应答处理
process_answer(channel, buf, count, fd_args->server, 0, now);
//从收到的DNS应答中提取请求ID,之后在DNS引擎对象的
//channel->queries请求队列中查找对应的请求队列块
query = find_query(channel, abuf);

//获取截断标记、应答码
tc = DNS_HEADER_TC(abuf);
rcode = DNS_HEADER_RCODE(abuf);

//如果消息被DNS服务器截断,当前没有使用TCP传输,并且
//没有设置忽略TC标记,则再试尝试使用TCP发送DNS请求
if ((tc || alen > PACKETSZ) && !tcp && !(channel->flags &
ARES_FLAG_IGNTC))
if (!query->using_tcp)
query->using_tcp = 1;
ares__send_query(channel, query, now);
return;

//UDP方式限制仅处理512字节
if (alen > PACKETSZ && !tcp)
alen = PACKETSZ;

//当前没有设置忽略错误响应,则进行错误检测
if (!(channel->flags & ARES_FLAG_NOCHECKRESP))
//当出现服务器失败、不支持的查询类型、拒绝错误情况
//则将请求块中的对应服务器skip_server标记设置为1,
//这样在使用next_server进行其它DNS服务器尝试时,会
//跳过此服务器。
if(rcode == SERVFAIL || rcode == NOTIMP
|| rcode == REFUSED)
query->skip_server[whichserver] = 1;
if (query->server == whichserver)
//切换到下个DNS服务器尝试,下面超时处理中
//有对应的分析,可以参考下面。
next_server(channel, query, now);
Return;

//校验反回的结果,是否是之前请求的域名项,如果不是,
//这台DNS服务器有问题,切到下个服务器
if (!same_questions((const unsigned char*)query->qbuf,
query->qlen, abuf, alen))
if (query->server == whichserver)
next_server(channel, query, now);
return;

//结束查询,处理成功
end_query(channel, query, ARES_SUCCESS, abuf, alen);
//取消已经运行的定时器
if (RvInt64IsNotEqual(query->timeout, RvInt64Const(0,0,0)))
RvTimerCancel(&query->timer,
RV_TIMER_CANCEL_DONT_WAIT_FOR_CB);

if (queryStatus == ARES_SUCCESS && abuf != NULL)
//从响应报文中获取应答码,和响应条目数
rcode = DNS_HEADER_RCODE(abuf);
ancount = DNS_HEADER_ANCOUNT(abuf);

switch (rcode)
case NOERROR:
//如果响应码没有错误,根据获取得响应条目设置
//当前查询状态
queryStatus = (ancount > 0) ? ARES_SUCCESS :
ARES_ENODATA;
.... //其它响应码不一一分析

//将channel->queries请求队列指向下一请求项
for (q = &channel->queries; *q; q = &(*q)->qnext)
if (*q == query)
break;
*q = query->qnext;

//如果已经没有请求项,并且未设置始终保持标记,则关闭
//所有连接DSN服务的套接口
if (!channel->queries && !(channel->flags &
ARES_FLAG_STAYOPEN))
for (i = 0; i < channel->nservers; i++)
ares__close_sockets(channel, i);

//调用用户请求回调进行处理,当前回调函数为
//rvDnsCallback
query->user_callback(channel, query->user_arg, queryStatus,
query->user_qid, abuf, alen);

//超时处理
process_timeouts(channel, now, error);
//遍历之前所有请求控制块
for (query = channel->queries; query; query = next)
next = query->qnext;

//如果当前请求已经超时,或者有错误,则标记错误状态,并切换下一个
//DNS服务器继续处理。
if ((RvInt64IsNotEqual(query->timeout, RvInt64Const(0,0,0)) &&
RvInt64IsGreaterThanOrEqual(now, query->timeout)) || error)
query->error_status = error ? ARES_ECONNREFUSED :
ARES_ETIMEOUT;

next_server(channel, query, now);
query->server++; //切到一个DNS服务器索引

//依次使用下一个DNS服务器发送请求
for (; query->try_index < channel->tries; query->try_index++)
for (; query->server < channel->nservers; query->server++)
if (!query->skip_server[query->server])
query->try_index++;
ares__send_query(channel, query, now);
return;

//如果重试次数比较多,处理到最后一个DNS服务器后,
//进行环绕,再从第一个服务器开始。
query->server = 0;

//全部尝试完,仍有错误则返回ARES_ENDOFSERVERS
end_query(channel, query, ARES_ENDOFSERVERS, NULL, 0);
//取消已经运行的定时器
if (RvInt64IsNotEqual(query->timeout, RvInt64Const(0,0,0)))
RvTimerCancel(&query->timer,
RV_TIMER_CANCEL_DONT_WAIT_FOR_CB);

if (queryStatus == ARES_SUCCESS && abuf != NULL)
//当前为错误,不走此流程

//将channel->queries请求队列指向下一请求项
for (q = &channel->queries; *q; q = &(*q)->qnext)
if (*q == query)
break;
*q = query->qnext;

//如果已经没有请求项,并且未设置始终保持标记,则关闭
//所有连接DSN服务的套接口
if (!channel->queries && !(channel->flags &
ARES_FLAG_STAYOPEN))
for (i = 0; i < channel->nservers; i++)
ares__close_sockets(channel, i);

//调用用户请求回调进行处理,当前回调函数为
//rvDnsCallback
query->user_callback(channel, query->user_arg, queryStatus,
query->user_qid, abuf, alen);
---------------------------------------------------------------------------------------------------------------------
//处理请求结果
rvDnsCallback
if (status != ARES_SUCCESS)
//获取线程变量成功后,则不需要处理错误结果?
isSync = rvAresSetException(status);
if(isSync)
return;

//调用用户侧回调,通知请求错误,这里回调函数为ResolverDNSNewRecordCB
dnsData.dataType    = RV_DNS_STATUS_TYPE;
dnsData.data.status = status;
dnsEngine->newRecordCB(context, queryId, &dnsData);
return;

//跳过DNS响应报文的公共头部
aptr = queryResults + HFIXEDSZ;

//跳过DNS响应报文的请求段
for (qdcount = DNS_HEADER_QDCOUNT(queryResults);  qdcount > 0;  --qdcount)
nameLen = ares_expand_name(aptr, queryResults, alen, nameString,
sizeof(nameString));

aptr += nameLen;
queryType = DNS_QUESTION_TYPE(aptr);
aptr += QFIXEDSZ;

//获取成功的请求结果个数。
ancount = DNS_HEADER_ANCOUNT(queryResults);

dnsData.recordNumber = 0;
savedAptr = aptr;

//开进行进行缓存处理
RvAresCacheDStartCaching(dnsEngine->cached);
//将缓存对象锁住
RvLockGet(&self->lock, logMgr);

//更新ctx->time时间
RvAresCacheUpdateTime();

RvAresCacheBookkeeping(&self->cache);
//获取当前时间
curTime = RvAresGetCacheTime();

//从缓冲控制块的cells对象中依次检测是否有超时的槽,如果有的话返回
//true,同时把超时的槽中的数据页设置到expired临时变量中
while(RvAresCacheCellsRemove(&self->cells, curTime, &expired))
//把超时的数据页加入self->expiredPages队列后面
if(self->expiredPages.last != 0)
self->expiredPages.last->next = expired;
Else
self->expiredPages.first = expired;
while(expired->next)
expired = expired->next;
self->expiredPages.last = expired;

//遍历所有查询结果
for(i = 0; i < ancount; i++)
//调用指定的地址类型解析结果进行结果解析,当前会把解析到的ipv4地址解析到
//dnsData.data.hostAddress中
status = rvDnsCopyData(queryType, queryResults, alen, &aptr, &dnsData);
dnsData.recordNumber++;

//请求类型不匹配则中止缓存处理
if(dnsData.recordType != queryType && dnsData.recordType != T_CNAME)
break;

//将新的请求结果记录到缓冲对象中
RvAresCacheDRecord(dnsEngine->cached, queryId, &dnsData);
RvAresCacheRecord(&self->cache, qid, record);
//根据请求域名,在缓冲的hash桶中查找是否已经有对应的桶链
curRec = RvAresCacheFind(self, record->dataType, name, nameSize,
&insertPoint);

//如果在hash表中找到,当前请求id匹配不上,则删除老的缓冲记录
//否则标记不需要添加到新hash链
if(curRec)
if(qid != curRec->queryId)
RvAresHashRemove(hash, curRec);
else
addBaseRecord = RV_FALSE;

//没在hash表中,则增加新hash链
if(addBaseRecord)
//根据DNS服务器回应的缓存的生存期,从cell槽中获取一个数据页
//,并关联到hahs桶中
RvAresCacheAllocPageEntry(self, record->ttl, recSize,
(RvAresPageEntry **)&curRec);
//从缓冲对象的cell槽中分配一个cell控制块,这个cell控制块
//是一个双向链表,链表的指针类型是数据页,并且cell控制块
//中含有一个expirationTime变量,存储该cell控制块中所有数
//据页的超时时间,并且cell各控制块按expirationTime值从小
//到大排序。
cell = RvAresCacheCellsFindCell(&self->cells, ttl,
&expirationTime);

//从cell槽中获取一个数据页
page = RvAresCacheCellGetPage(cell);

//进行数据页初始化
pe = RvAresPageAllocEntry(page, size);
pe->expirationTime = expirationTime;
//记载当前缓冲页的超时时间

//从当前数据页中取出一个条目
pe = &curRec->pageEntry;
pe->type = (RvUint8)record->recordType; //记载当前条目类型
pe->nextExtension = 0; //记载没有扩展
pe->base = curRec; //base指向当前数据块
if(pe->type == T_A)
curRec->idx = 0;
//当前数据页中name记载之前请求的域名、请求ID
curRec->nameSize = (RvUint8)nameSize;
strcpy(curRec->name, record->ownerName);
curRec->queryId = qid;

//将当前数据页插入到hash表中
RvAresHashAdd(hash, insertPoint, curRec);

switch(record->recordType)
case T_A:
RvAresCacheA(self, record, &er);
//分配一个缓冲条目
RvAresCacheAllocPageEntry(self, record->ttl, sizeof(*arec),
(RvAresPageEntry **)&arec);

//把解析到的地址存储到缓冲条目addr中
paddr = RvAddressGetIpv4(&record->data.hostAddress);
arec->addr = RvAddressIpv4GetIp(paddr);
*ppEntry = &arec->pageEntry;

//设置缓冲条目类型的最高位置1表明是扩展类型
er->type = (RvUint8)(record->recordType | 0x80);

//将含有ip地址解析结果的缓冲条目插入到当前数据页的扩展链表中
//curRec->pageEntry.nextExtension
er->nextExtension = curRec->pageEntry.nextExtension;
er->base = curRec;
curRec->pageEntry.nextExtension = er;

//完成缓存处理
RvAresCacheDFinishCaching(dnsEngine->cached);
//解锁缓存对象
RvLockRelease(&self->lock, logMgr);

dnsData.recordNumber = 0;
aptr = savedAptr;

//遍历所有查询结果
for (i = 0; i < ancount && continueCallbacks; ++i)
//调用指定的地址类型解析结果进行结果解析,当前会把解析到的ipv4地址解析到
//dnsData.data.hostAddress中
status = rvDnsCopyData(queryType, queryResults, alen, &aptr, &dnsData);
//记录结果个数
dnsData.recordNumber++;

if (status == RV_OK)
//如果请求类型正确,则调用用户层回调通过解析结果,这里回调函数为
//ResolverDNSNewRecordCB
if(dnsData.recordType == queryType)
status = dnsEngine->newRecordCB(context, queryId, &dnsData);

if (status != RV_OK)
......
//用户通知回调出错,不再继续处理
continueCallbacks = RV_FALSE;
else if (status == RV_DNS_ERROR_RTNOTSUPP)
continue; //没有找到对应的地址类型处理函数,直接解析下一个响应
else
//解析错误,把错误结果反回给用户,这里回调为ResolverDNSNewRecordCB
dnsData.recordType = RV_DNS_STATUS_TYPE;
dnsData.data.status = status;
dnsEngine->newRecordCB(context, queryId, &dnsData);

不再继续处理
continueCallbacks = RV_FALSE;
不通知用户列表处理结束,因为已经通知过出错了。
sendEndOfList = RV_FALSE;

//不通知用户列表结束,比如上面已经通知过用户解析处理错误
if(!sendEndOfList)
return

//这里查询结果已经处理完成,根据服务器是否回应结果数据通知用户处理情况
//这里回调函数为ResolverDNSNewRecordCB
if (dnsData.recordNumber > 0)
dnsData.dataType = RV_DNS_ENDOFLIST_TYPE;
Else
dnsData.dataType = RV_DNS_NO_DATA_TYPE;
dnsData.recordNumber = ancount;

dnsEngine->newRecordCB(context, queryId, &dnsData);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: