整体功能分析
client.c 主要是负责DNS 服务器与用户接口的设置,可以分成三个模块:
1.数据包传送模块
2.用户的创建模块
3.用户管理器的创建模块
用户的创建模块是为用户管理器的创建模块建立的,对于同一用户,他每次建立连接,只要连接不断开和超时,他的用户创建模块不会被再次激发。因此,这两个模块仅是一次性的,在用户创建以后再发送数据包,它们将不会有任何影响。数据包传送模块则是关于数据传输的,每次传送数据包它都会参与其中。
client.h说明
/* This module defines two objects, ns_client_t and ns_clientmgr_t.
*
* An ns_client_t object handles incoming DNS requests from clients
* on a given network interface.
*
* Each ns_client_t object can handle only one TCP connection or UDP
* request at a time. Therefore, several ns_client_t objects are
* typically created to serve each network interface, e.g., one
* for handling TCP requests and a few (one per CPU) for handling
* UDP requests.
*
* Incoming requests are classified as queries, zone transfer
* requests, update requests, notify requests, etc, and handed off
* to the appropriate request handler. When the request has been
* fully handled (which can be much later), the ns_client_t must be
* notified of this by calling one of the following functions
* exactly once in the context of its task:
* \code
* ns_client_send() (sending a non-error response)
* ns_client_sendraw() (sending a raw response)
* ns_client_error() (sending an error response)
* ns_client_next() (sending no response)
*\endcode
* This will release any resources used by the request and
* and allow the ns_client_t to listen for the next request.
*
* A ns_clientmgr_t manages a number of ns_client_t objects.
* New ns_client_t objects are created by calling
* ns_clientmgr_createclients(). They are destroyed by
* destroying their manager.
*/
数据结构
/*% nameserver client structure */
struct ns_client
{
unsigned int magic;
isc_mem_t * mctx;
ns_clientmgr_t * manager;
int state;
int newstate;
int naccepts;
int nreads;
int nsends;
int nrecvs;
int nupdates;
int nctls;
int references;
isc_boolean_t needshutdown; /*
* Used by clienttest to get
* the client to go from
* inactive to free state
* by shutting down the
* client's task.
*/
unsigned int attributes;
isc_task_t * task;
dns_view_t * view;
dns_dispatch_t * dispatch;
isc_socket_t * udpsocket;
isc_socket_t * tcplistener;
isc_socket_t * tcpsocket;
unsigned char * tcpbuf;
dns_tcpmsg_t tcpmsg;
isc_boolean_t tcpmsg_valid;
isc_timer_t * timer;
isc_boolean_t timerset;
dns_message_t * message;
isc_socketevent_t * sendevent;
isc_socketevent_t * recvevent;
unsigned char * recvbuf;
dns_rdataset_t * opt;
isc_uint16_t udpsize;
isc_uint16_t extflags;
isc_int16_t ednsversion; /* -1 noedns */
void (*next)(ns_client_t *);
void (*shutdown)(void *arg, isc_result_t result);
void *shutdown_arg;
ns_query_t query;
isc_stdtime_t requesttime;
isc_stdtime_t now;
dns_name_t signername; /*%< [T]SIG key name */
dns_name_t * signer; /*%< NULL if not valid sig */
isc_boolean_t mortal; /*%< Die after handling request */
isc_quota_t *tcpquota;
isc_quota_t *recursionquota;
ns_interface_t *interface;
isc_sockaddr_t peeraddr;
isc_boolean_t peeraddr_valid;
struct in6_pktinfo pktinfo;
isc_event_t ctlevent;
/*%
* Information about recent FORMERR response(s), for
* FORMERR loop avoidance. This is separate for each
* client object rather than global only to avoid
* the need for locking.
*/
struct {
isc_sockaddr_t addr;
isc_stdtime_t time;
dns_messageid_t id;
} formerrcache;
ISC_LINK(ns_client_t) link;
/*%
* The list 'link' is part of, or NULL if not on any list.
*/
client_list_t *list;
}
函数调用关系
client_create 为建立用户刚模块核心函数
static isc_result_t
client_create(ns_clientmgr_t *manager, ns_client_t **clientp)
ns_client_send 为发送数据。
void
ns_client_send(ns_client_t *client)
sendraw 发送原始请求
void
ns_client_sendraw(ns_client_t *client, dns_message_t *message)
用户管理器创建用户
isc_result_t
ns_clientmgr_createclients(ns_clientmgr_t *manager, unsigned int n,
ns_interface_t *ifp, isc_boolean_t tcp)
重要函数说明
static isc_boolean_t exit_check(ns_client_t *client)
开检查,针对用户的不同状态,逐级往free 方向递减(即从状态4 至0 一步步减少),只要有一项(如更新、发送、接收)数为0,则返回1,表示用户离开。
void
ns_client_next(ns_client_t *client, isc_result_t result)
执行下一请求,当用户为工作或读取状态且上一次请求成功,执行下一请求,否则将失败写于日志中。
static void
client_senddone(isc_task_t *task, isc_event_t *event)
发送完成,发送完成某一任务、事件。当发送事件不成功,日志记录。当tcp缓存非空(即成功),在内存中记录,若用户离开,则函数中止,否则执行下一请求。调用exit_check,ns_client_next函数。
static isc_result_t
client_allocsendbuf(ns_client_t *client, isc_buffer_t *buffer,
isc_buffer_t *tcpbuffer, isc_uint32_t length,
unsigned char *sendbuf, unsigned char **datap)
分配发送缓存,返回分配结果。在client_send,client_sentufraw 中调用。
static isc_result_t
client_sendpkg(ns_client_t *client, isc_buffer_t *buffer)
发送数据包,根据判断是tcp 还是udp 来将用户的任务发向不同的接口,再对得到的结果进行判断,成功则调用client_senddone
函数。返回结果。
1.数据包具体的发送是在socker.c 的isc_send_socket2()和它内部socket_send()函数进行的,client_sendpkg 只是对包进行发送接口的选择,并对结果进行处理。
2.对于不同的操作系统关于socket 的函数是不同的,分成unix 和win32 两类。
void
ns_client_recursing(ns_client_t *client)
域名服务器递归:处理用户的表client->list,将用户的连接加到用户管理器的递归表中,在将用户的表等于用户管理器的递归表,实则是为用户起到递归查找域名服务器的作用。