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);
相关文章推荐
- 学习委托(2)-------解析委托的实现机制
- 学习委托(3)-----解析委托的实现机制续篇
- Android系统中长按事件的实现机制解析
- RHEL6.3 DNS高级技术一 通过DNS View实现不同区域访问域名解析的速度 推荐
- 学习委托(2)-------解析委托的实现机制
- C#实现DNS解析服务
- PHP的autoload机制的实现解析
- Android系统中长按事件的实现机制解析
- 用DHCP实现网关配置和DNS解析
- 学习委托(3)-----解析委托的实现机制续篇
- PHP的autoload机制的实现解析
- IE解析codebase实现控件自动更新的机制
- PHP的autoload机制的实现解析
- Java的ReadWriteLock实现机制解析(1)
- 学习委托(3)-----解析委托的实现机制续篇
- c语言winsock 实现简单的域名解析功能(DNS. v 1.0)
- DNS解析协议的C语言简单实现
- feathers ui 实现机制深入解析
- 8、使用Struts2实现异步调用机制剖析(XML与JSON方式解析)