接上篇文章,回根查询流程业务部分,本篇主要分析回根通信部分
1。 本部分激发入口是fctx_start(isc_task_t *task, isc_event_t *event)
if (!done) {
isc_result_t result;
INSIST(!dodestroy);
/*
* All is well. Start working on the fetch.
*/
result = fctx_starttimer(fctx);
if (result == ISC_R_SUCCESS && fctx->timer_try_stale != NULL) {
result = fctx_starttimer_trystale(fctx);
}
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__);
} else {
fctx_try(fctx, false, false);
}
} else if (dodestroy) {
fctx_destroy(fctx);
if (bucket_empty) {
empty_bucket(res);
}
}
此部分代码,就是对通信查询部分的开始,首先将自己这个查询上下文置一下陈旧定时器,若超时到期望,则停掉本次查询
若定时器设置成功,则fctx_try(fctx, false, false)
2。 函数实际,不需要重试,不是坏的缓存
static void
fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) {
在如下代码是查询可用的ns名字,代码如下,此代码封装比较好,多多种处理,包括forward转发,cache缓存,等等等等,查询机制,重点在于fctx_nextaddress内
addrinfo = fctx_nextaddress(fctx);
/* Try to find an address that isn't over quota */
while (addrinfo != NULL && dns_adbentry_overquota(addrinfo->entry)) {
addrinfo = fctx_nextaddress(fctx);
}
若查询到合适的addrinfo
最终到向ns发送查询数据:代码:
result = fctx_query(fctx, addrinfo, fctx->options);
if (result != ISC_R_SUCCESS) {
fctx_done(fctx, result, __LINE__);
LOCK(&res->buckets[bucketnum].lock);
bucket_empty = fctx_decreference(fctx);
UNLOCK(&res->buckets[bucketnum].lock);
if (bucket_empty) {
empty_bucket(res);
}
} else if (retrying) {
inc_stats(res, dns_resstatscounter_retry);
}
3。 fctx_query
在代码位置:
fctx_setretryinterval(fctx, srtt);
result = fctx_startidletimer(fctx, &fctx->interval);
if (result != ISC_R_SUCCESS) {
return (result);
}
此部分设置定时器,防止网络不通等异常机制
数据的真正发送位置在本函数的代码
result = resquery_send(query);
if (result != ISC_R_SUCCESS) {
goto cleanup_dispatch;
}
此地方使用了sendmsg方式
4。 函数static isc_result_t resquery_send(resquery_t *query) {
是实际的发送函数
具体发送位置
result = isc_socket_sendto2(sock, &r, task, address, NULL,
&query->sendevent, 0);
5。 函数isc_socket_sendto2
isc_result_t
isc_socket_sendto2(isc_socket_t *sock0, isc_region_t *region, isc_task_t *task,
const isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
isc_socketevent_t *event, unsigned int flags) {
本函数调用如下函数:
6。
static isc_result_t
socket_send(isc__socket_t *sock, isc_socketevent_t *dev, isc_task_t *task,
const isc_sockaddr_t *address, struct in6_pktinfo *pktinfo,
unsigned int flags) {
本函数做一些一场判断,在继续调用函数
if (sock->type == isc_sockettype_udp) {
io_state = doio_send(sock, dev);
} else {
LOCK(&sock->lock);
have_lock = true;
if (ISC_LIST_EMPTY(sock->send_list)) {
io_state = doio_send(sock, dev);
} else {
io_state = DOIO_SOFT;
}
}
7。 doio_send就是实际 的发送函数
static int
doio_send(isc__socket_t *sock, isc_socketevent_t *dev) {
int cc;
struct iovec iov[MAXSCATTERGATHER_SEND];
size_t write_count;
struct msghdr msghdr;
char addrbuf[ISC_SOCKADDR_FORMATSIZE];
int attempts = 0;
int send_errno;
char strbuf[ISC_STRERRORSIZE];
char cmsgbuf[SENDCMSGBUFLEN] = { 0 };
build_msghdr_send(sock, cmsgbuf, dev, &msghdr, iov, &write_count);
resend:
if (sock->type == isc_sockettype_udp && sock->manager->maxudp != 0 &&
write_count > sock->manager->maxudp)
{
cc = write_count;
} else {
cc = sendmsg(sock->fd, &msghdr, 0);
}
send_errno = errno;
到现在就是发送数据的整个流程