启动server

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wellwang1993/article/details/83338251

在上面创建好管理器以后,中间还会有dlz即动态数据的加载,暂且把它们放到后面的部分来讲解,这里重点分析一下server的启动过程,为了和前面socket管理那一块相呼应,所以这里会重点讲一下根socket相关的部分,对于数据部分的加载我会在适当的时候进行分析

重要的数据结构:
1.db的类型,主要有三个
typedef enum {
	dns_dbtype_zone = 0, dns_dbtype_cache = 1, dns_dbtype_stub = 3
} dns_dbtype_t;
2.后面多次用到的name
struct dns_name {
        unsigned int                    magic;
        unsigned char *                 ndata;
        unsigned int                    length;
        unsigned int                    labels;
        unsigned int                    attributes;
        unsigned char *                 offsets;
        isc_buffer_t *                  buffer;
}
static dns_name_t root = 
{
	DNS_NAME_MAGIC,
	root_ndata, 1, 1,
	DNS_NAMEATTR_READONLY | DNS_NAMEATTR_ABSOLUTE,
	root_offsets, NULL,
	{(void *)-1, (void *)-1},
	{NULL, NULL}
};

ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) 
{
    //申请一个server,读取的配置文件就会赋值server里面的一些结构
    ns_server_t *server = isc_mem_get(mctx, sizeof(*server));
    //用默认的值初始化server的结构
    result = isc_quota_init(&server->xfroutquota, 10);
    result = isc_quota_init(&server->tcpquota, 10);
    result = isc_quota_init(&server->recursionquota, 100);
    
    //acl控制列表环境初始化
    result = dns_aclenv_init(mctx, &server->aclenv);
    {
        //初始化ip
        result = dns_acl_create(mctx, 0, &env->localhost);
        //初始化网段
        result = dns_acl_create(mctx, 0, &env->localnets);
    }

    server->zonemgr = NULL;//区管理器
	server->interfacemgr = NULL;
	ISC_LIST_INIT(server->viewlist);
	server->in_roothints = NULL;
	server->blackholeacl = NULL;//acl机制

    //注意这里的记录是IN,这就是创建那十三个根管理器
    dns_rootns_create(mctx, dns_rdataclass_in, NULL,&server->in_roothints)
    {
        //创建一个"rbt"类型的db
        result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_zone,rdclass, 0, NULL, &db);
        {
            //注意这是db的方法类型接口
            dns_dbimplementation_t *impinfo;
            //第一次被初始化的时候,对俩个全局的变量进行赋值,以及将这俩个插入一个全局的链表
            static dns_dbimplementation_t rbtimp;
            static dns_dbimplementation_t rbt64imp;
            static ISC_LIST(dns_dbimplementation_t) implementations;
            isc_once_do(&once, initialize)
            {
                rbtimp.name = "rbt";
	            rbtimp.create = dns_rbtdb_create;
	            rbtimp.mctx = NULL;
	            rbtimp.driverarg = NULL;
	            ISC_LINK_INIT(&rbtimp, link);

	            rbt64imp.name = "rbt64";
	            rbt64imp.create = dns_rbtdb64_create;
	            rbt64imp.mctx = NULL;
	            rbt64imp.driverarg = NULL;
	            ISC_LINK_INIT(&rbt64imp, link);

	            ISC_LIST_INIT(implementations);
	            ISC_LIST_APPEND(implementations, &rbtimp, link);
	            ISC_LIST_APPEND(implementations, &rbt64imp, link);
               
            }
            
            //从列表中找到刚刚创建的那个db,也就是"rbt",这里调用的方法就是上面赋值的dns_rbtdb_create
            impinfo = impfind(db_type);
            result = ((impinfo->create)(mctx, origin, type, rdclass, argc, argv,impinfo->driverarg, dbp))
            {
                dns_rbtdb_t *rbtdb = isc_mem_get(mctx, sizeof(*rbtdb));
                dns_name_init(&rbtdb->common.origin, NULL);
                rbtdb->common.attributes = 0;
                
                //这里依据type赋值不同的创建方法,这里赋值的是zone_method
                if (type == dns_dbtype_cache) {
		            rbtdb->common.methods = &cache_methods;
		            rbtdb->common.attributes |= DNS_DBATTR_CACHE;
	            } else if (type == dns_dbtype_stub) {
		            rbtdb->common.methods = &zone_methods;
		            rbtdb->common.attributes |= DNS_DBATTR_STUB;
	            } else
		            rbtdb->common.methods = &zone_methods;
	            rbtdb->common.rdclass = rdclass;

                //初始化db的三个锁,lock和tree_lock
                //赋值结构,如果type是cache的话则不同,初始化db的node_lock
                rbtdb->node_lock_count = DEFAULT_NODE_LOCK_COUNT;
                rbtdb->node_locks = isc_mem_get(mctx, rbtdb->node_lock_count *sizeof(rbtdb_nodelock_t));

                rbtdb->active = rbtdb->node_lock_count
                for (i = 0; i < (int)(rbtdb->node_lock_count); i++)
                {
                    //顺次初始化数组里面的每一个锁
                }

                //创建红黑树,主要就是hashsize和hashtable的创建
                result = dns_rbt_create(mctx, delete_callback, rbtdb, &rbtdb->tree);
                {
                    dns_rbt_t *rbt;        
                    rbt->hashtable=rbt->hashsize * sizeof(dns_rbtnode_t *);
                }
                //把那个全局的dns_name类型的root转变为rbtnode类型赋值,针对不同的zone文件
                //每一个zone区都对应一个rbtnode_t的结构
				result = dns_rbt_addnode(rbtdb->tree, &rbtdb->common.origin,&rbtdb->origin_node);
                {
                    dns_rbtnode_t * new_current
                    拷贝name到add_name
                    dns_name_clone(name, add_name);
                    result = create_node(rbt->mctx, add_name, &new_current);
                    {    
                        isc_region_t region;
                        dns_name_toregion(name, &region);
                        dns_rbtnode_t *node = (dns_rbtnode_t *)isc_mem_get(mctx,sizeof(*node) +  region.length + labels)
					   后面初始化node的结构
                    }
                    rbt->nodecount++;
			        new_current->is_root = 1;
			        rbt->root = new_current;
			        *nodep = new_current;
                        
                }
					 	
            }
					   
					    
        }
        //就是那十三个根服务器
        len = strlen(root_ns);
        result = dns_db_beginload(db, &callbacks.add,&callbacks.add_private);
	    dns_master_loadbuffer
        eresult = dns_db_endload(db, &callbacks.add_private);	  
			       
    }

    //开始绑定重要的事件,这个是reload事件
    server->reload_event =isc_event_allocate(ns_g_mctx, server,NS_EVENT_RELOAD,ns_server_reload,server,sizeof(isc_event_t));
    //在这个全局的taskmgr中设置server的一个task
	isc_task_create(ns_g_taskmgr, 0, &server->task)
    //在server的task中设置俩个事件
    isc_task_onshutdown(server->task, shutdown_server, server)
    isc_app_onrun(ns_g_mctx, server->task, run_server, server)
    {
        //不是事件添加到全局的on_run列表
        ISC_LIST_APPEND(on_run, event, ev_link);
    }
    //创建zone管理器
    dns_zonemgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,ns_g_socketmgr, &server->zonemgr)
	后面还会初始化server的一些信息		      
			     
}

该函数执行完成以后会进入到main函数的一个主循环,该循环做的事情就是不断的从on_run事件列表中取出事件然后交给工作线程执行,然后就开始运行run_server了

do
{
    result = isc_app_run()
    {
        //刚刚创建server的时候就把run_server事件添加到了on_run中,因此一旦跑到这里就会开始运行run_server
        for (event = ISC_LIST_HEAD(on_run);event != NULL;event = next_event)
        {
            ISC_LIST_UNLINK(on_run, event, ev_link);
            //该task就是ns_g_taskmgr
			task = event->ev_sender;
			event->ev_sender = NULL;
            //交给工作线程去执行,这里是把这个task销毁
			isc_task_sendanddetach(&task, &event);
        }
		     
		     
    }
}while(result!=success)

接下来重点看一下run_server的执行

run_server()
{
    ns_server_t *server = (ns_server_t *)event->ev_arg;
    //这里开始加载核心的配置文件

    char def_conf_fullname[] = “flex”
	char local_conf_fullname[] = "flex";
	char alc_conf_fullname[] = "flex";

    //对三个配置文件的加载以及对某些信息的更新

    //对dns消息的处理,创建dns_dispatchmgr_t 并且初始化
    dns_dispatchmgr_create(ns_g_mctx, ns_g_entropy, &ns_g_dispatchmgr)
    {
        dns_dispatchmgr_t *mgr = isc_mem_get(mctx, sizeof(dns_dispatchmgr_t));
        //创建三个重要的池子
        isc_mempool_create(mgr->mctx, sizeof(dns_dispatchevent_t), &mgr->epool)
			      
    }
					 
    //对tcp消息的处理
    ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,ns_g_socketmgr, ns_g_dispatchmgr, &server->interfacemgr)
	{
        ns_interfacemgr_t *mgr = isc_mem_get(mctx, sizeof(*mgr));
        //由它来存储创建好的三个mgr
        mgr->taskmgr = taskmgr;
	    mgr->socketmgr = socketmgr;
	    mgr->dispatchmgr = dispatchmgr;

        ISC_LIST_INIT(mgr->interfaces);
	    ISC_LIST_INIT(mgr->listenon);
        //初始化监听者的结构
        result = ns_listenlist_create(mctx, &mgr->listenon4);
        //acl
        result = dns_aclenv_init(mctx, &mgr->aclenv);
    }			  
		
    //一个默认的配置文件解析器
    cfg_parser_create(ns_g_mctx, NULL, &ns_g_parser)	
    //加载配置文件
    load_configuration
    //加载区文件
    load_zones(server, ISC_FALSE)		 
    ns_os_started();
}

下面用到的重要的数据结构
struct ns_interface {
	unsigned int		magic;		/*%< Magic number. */
	ns_interfacemgr_t *	mgr;		/*%< Interface manager. */
	isc_mutex_t		lock;
	int			references;	/*%< Locked */
	unsigned int		generation;     /*%< Generation number. */
	isc_sockaddr_t		addr;           /*%< Address and port. */
	unsigned int		flags;		/*%< Interface characteristics */
	char 			name[32];	/*%< Null terminated. */
	dns_dispatch_t *	udpdispatch;	/*%< UDP dispatcher. */
	isc_socket_t *		tcpsocket;	/*%< TCP socket. */
	int			ntcptarget;	/*%< Desired number of concurrent
						     TCP accepts */
	int			ntcpcurrent;	/*%< Current ditto, locked */
	ns_clientmgr_t *	clientmgr;	/*%< Client manager. */
	ISC_LINK(ns_interface_t) link;
};
//这里开始加载配置文件,这个是一个相当重要的函数
//这里小小总结一下这个函数主要做了一些什么,其实主要就是围绕监听的端口展开,注意经过下面的这个函数以后它监听的socket只是由主进程在监听,在执行完成这个函数以后,就会有工作线程执行client_start

首先针对每一个端口会创建一个ns_interface_t *ifp,它会初始化上面的那些结构:具体包括创建ns_clientmgr_t ,并且把它的mgr指向ns_g_taskmgr;赋值ifp->udpdispatch ,ifp->tcpsocket为空,ns_interfacemgr_t类型的引用计数+1,也就是每创建一个ifp,mgr的引用计数就增加;ifp->mgr=ns_interfacemgr_t类型的mgr,同时会把该ifp添加到ns_interfacemgr_t类型的interfaces中


对于udp来说
它是dispatchmgr,因为它的端口要通过dispatch_t来管理
1.会根据给的的值设置ifp->mgr->dispatchmgr的信息;然后根据它的值创建一个dns_dispatch_t *disp,然后创建isc_socket_t *socket并且设置ns_g_socket的一些信息,比如fds,maxfd等,然后主进程bind,同时把socket信息赋值到disp上,并且注册disp事件,然后把disp赋值到ifp->mgr->dispatchmgr->list上
2.设置ifp->clientmgr,创建n个client,为每个client创建task,client的task也是设置到ns_g_taskmgr的,为每个client设置三个事件,为client设置message,设置recvbuf,最后把client添加到manager的active中
在执行完该函数以后,ifp->reference=client的个数,client->interface = ifp,ifp->udpdispatch->reference=client的个数,client->udpsocket=client->dispatch->sock=ifp->udpdispatch->sock
3.调用的函数:
dns_dispatch_getudp
ns_clientmgr_createclients

对于tcp来说
1.通过ifp->mgr->socketmgr创建socket,由前面可知这个数据依然是ns_g_socketmgr,因此后续同样对ns_g_socktmgr设置fd,maxfd等信息,然后主进程bind,listen.
2.设置ifp->clientmgr,所有的内容同udp一样,不同的在于,ifp->tcpsocket->reference=client的个数,client->tcplistener=ifp->tcpsocket(代表他有client个监听者)



load_configuration()
{
    //加载配置文件之前,当发现对于ns_g_taskmgr有好几个running的task,那么则wait直到剩下一个为止
    result = isc_task_beginexclusive(server->task);
    //将acl的放到ns_g_dispatchmgr
    if (server->blackholeacl != NULL)
		dns_dispatchmgr_setblackhole(ns_g_dispatchmgr, server->blackholeacl);
    //这些端口不能被监听
    (void)ns_config_get(maps, "avoid-v4-udp-ports", &v4ports);
	dns_dispatchmgr_setblackportlist(ns_g_dispatchmgr, portlist);			    
    //开始获取监听的端口    
    ns_listenlist_t *listenon = NULL;
    void)cfg_map_get(options, "listen-on", &clistenon);
    //把监听的端口放到interfacemgr中进行管理
    ns_interfacemgr_setlistenon4(server->interfacemgr,listenon);
		
    //这个也是个重要的函数,上面确定了监听的端口,包括ipv4和ipv6的,下面开始进行处理				     
    scan_interfaces(server, ISC_TRUE);
    {
        ns_interfacemgr_scan(server->interfacemgr, verbose);
        {
            ns_interfacemgr_scan0(mgr, NULL, verbose);
            {
                do_scan(mgr, ext_listen, verbose)
                {
                    //处理ipv6的部分暂且不分析
                    //开始处理监听的端口
                    for (result = isc_interfaceiter_first(iter);result == ISC_R_SUCCESS;result = isc_interfaceiter_next(iter))
                    {
                        isc_interface_t interface;
                        result = isc_interfaceiter_current(iter, &interface);
                        ns_listenlist_t *ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
                        ns_interface_t *ifp;
                        ns_interface_setup
                        {
                            ns_interface_t *ifp = NULL;
                            //下面这个赋值好ifp
                            result = ns_interface_create(mgr, addr, name, &ifp);
                            {
                                ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
                                //赋值
                                strncpy(ifp->name, name, sizeof(ifp->name));
                                result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,ns_g_timermgr,&ifp->clientmgr);
                                {
                                    ns_clientmgr_t *manager;
                                    manager->taskmgr = taskmgr;
	                                manager->timermgr = timermgr;
	                                manager->exiting = ISC_FALSE;
	                                ISC_LIST_INIT(manager->active);
	                                ISC_LIST_INIT(manager->inactive);
	                                ISC_LIST_INIT(manager->recursing);
                                    ifp->udpdispatch = NULL;

	                                ifp->tcpsocket = NULL;
                                    ifp->mgr = mgr
                                }
				     
				     
                            }
                        }

                        //创建udp的端口
                        result = ns_interface_listenudp(ifp);
                        {
                            result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr, ns_g_taskmgr, &ifp->addr, 4096, 1000, 32768, 8219, 8237,attrs, attrmask, &ifp->udpdispatch);
                            {
                                result = dns_dispatchmgr_setudp(mgr, buffersize,maxbuffers,buckets, increment);
                                {
                                    设置dns_dispatchmgr_t的一些内容
                                    mgr->bpool;
                                    mgr->maxbuffers = maxbuffers;
                                }
                                //查看是否已经有一个了,如果没有的话就创建
                                result = dispatch_find(mgr, localaddr, attributes, mask, &disp);
                                这里就是创建socket的代码了
                                result = dispatch_createudp(mgr, sockmgr, taskmgr,localaddr,maxrequests, attributes, &disp);
                                {
                                    dns_dispatch_t *disp;
                                    isc_socket_t *held[DNS_DISPATCH_HELD];
                                    isc_socket_t *sock = NULL;
                                    result = dispatch_allocate(mgr, maxrequests, &disp);
                                    {
                                        //从mgr->dpool申请空间
                                        disp = isc_mempool_get(mgr->dpool);
                                        赋值disp的一些属性
                                    }
                                    //创建isc_socket_t 类型的socket,初始化它的一些基本性质,并且调用socket
                                    result = create_socket(sockmgr, localaddr, &sock);
                                    {
                                        result = isc_socket_create(mgr,isc_sockaddr_pf(local),isc_sockettype_udp, &sock);
                                        {
                                            sock = isc_mem_get(manager->mctx,sizeof(*sock));
                                            sock->manager = manager;
	                                        sock->type = type;
	                                        sock->fd = -1; 
                                            //初始化socket的一些类型
                                            ISC_LIST_INIT(sock->recv_list);
	                                        ISC_LIST_INIT(sock->send_list);
	                                        ISC_LIST_INIT(sock->accept_list);

                                            //以及一些事件类型
                                            ISC_EVENT_INIT(&sock->readable_ev, sizeof(intev_t),
                                        } 
                                        switch (type) {
	                                        case isc_sockettype_udp:
		                                        sock->fd=socket(pf,SOCK_DGRAM,IPPROTO_UDP);
		                                        break;    
                                        }
                                        下面是设置一些socket的属性
                                        这里把socket设置到manger中,以便watcher线程可以开始监控它,但是注意这里还没有添加到manger的read_set中,所以select这个时候还不能检测到它
                                        manager->fds[sock->fd] = sock;
	                                    manager->fdstate[sock->fd] = MANAGED;
	                                    ISC_LIST_APPEND(manager->socklist, sock, link);
	                                    if (manager->maxfd < sock->fd)
		                                    manager->maxfd = sock->fd;
				   
                                  
                                    //主线程开始监听该socket
                                    result = isc_socket_bind(sock, local);
                                    {
                                        bind(sock->fd, &sockaddr->type.sa, sockaddr->length
                                     }
                                   } 
                                   //下面是设置disp的一些属性
                                    disp->socktype = isc_sockettype_udp;
	                                disp->socket = sock;
	                                disp->local = *localaddr;
                                    //创建一个task,指向ns_g_taskmgr,从他的mxtc申请内存
                                    result = isc_task_create(taskmgr, 0, &disp->task);
                                    disp->ctlevent = isc_event_allocate(mgr->mctx, disp,DNS_EVENT_DISPATCHCONTROL,destroy_disp, disp,sizeof(isc_event_t));
					    
					    
					    
                                } 
				    
					            
                            }//getudp
                            //创建cpu个clients,以上只是一个主进程在监听udp端口
				            result = ns_clientmgr_createclients(ifp->clientmgr,ns_g_cpus,ifp, ISC_FALSE);
                            {
                                for (i = 0; i < n; i++)
                                {
                                    result = client_create(manager, &client);
                                    {
                                        client = isc_mem_get(mctx, sizeof(*client));
                                        //让client->task=ns_g_taskmgr
                                        result = isc_task_create(manager->taskmgr, 0, &client->task);
                                        result = dns_message_create(client->mctx,DNS_MESSAGE_INTENTPARSE,&client->message);
                                        {
                                            dns_message_t *m = isc_mem_get(mctx, sizeof(dns_message_t));
                                            //创建m的一些结构,
                                        } 
                                        //创建client的三个最主要的事件
                                        client->sendevent = (isc_socketevent_t *)isc_event_allocate(client->mctx, client,ISC_SOCKEVENT_SENDDONE,client_senddone, client,sizeof(isc_socketevent_t));
		
				
				                        //设置recvbuf
                                        client->recvbuf
                                        //创建recevent
                                        client->recvevent =isc_event_allocate(client_request)
				                        //创建start事件,并且放到client->ctlevent中
			                            ISC_EVENT_INIT(&client->ctlevent, sizeof(client->ctlevent), 0, NULL,NS_EVENT_CLIENTCONTROL, client_start, 
                                        //初始化query
                                        result = ns_query_init(client);
			
                                    }
                                    //赋值上去,注意这里ifp的reference会++cp个数次
                                    ns_interface_attach(ifp, &client->interface);
                                    //如果是tcp的话
                                    if(tcp)
                                    {
                                        ifp的tcpsocket引用计数会++,同时设置为client->tcplistenr
                                        isc_socket_attach(ifp->tcpsocket,&client->tcplistener);
					
                                    }
                                    else//如果是udp的话
                                    {
                                        isc_socket_t *sock;
                                        //ifp->udpdispatch的reference会++cpu个数次,client->dispatch会等于左边的
			                            dns_dispatch_attach(ifp->udpdispatch,&client->dispatch);
					                    //下面的这俩个操作就是client->udpsocket会赋值左边的,client->dispatch的引用计数会++
			                            sock = dns_dispatch_getsocket(client->dispatch);
      		                            isc_socket_attach(sock, &client->udpsocket);
                                    }
                                    //每个client添加到active中,并且通过list可以找到下一个
                                    ISC_LIST_APPEND(manager->active, client, link);
		                            client->list = &manager->active;
                                    //取出client_start事件,交给工作线程去执行client_start
                                    ev = &client->ctlevent;
		                            isc_task_send(client->task, &ev);
                                }
                            } 
					    
				    
				     
                        }//listenudp
                        //这是tcp的
                        result = ns_interface_accepttcp(ifp);
                        {
                            //创建一个tcpsocket,注意ifp->mgr->socketmgr也是ns_g_socketmgr
                            result = isc_socket_create(ifp->mgr->socketmgr,isc_sockaddr_pf(&ifp->addr),isc_sockettype_tcp,&ifp->tcpsocket);
				            {
                                //同上创建socket,并且把该fd赋值manger的一些信息
                            }
                            //调用bind
				            result = isc_socket_bind(ifp->tcpsocket, &ifp->addr);
                            //调用listen
                            result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
                            {
                                listen(sock->fd)
                            }
                            //注意以上都是主进程在监听端口
                            ns_clientmgr_createclients(ifp->clientmgr,ifp->ntcptarget, ifp,ISC_TRUE);
                            {
                                同udp一样创建n个client以及赋值事件
                            }
					    
					    
				   
                        }//listentcp
                    }
	     
	     
                }
            }
        }
    }
    //注意在扫描完监听的端口以后,这里还有一个比较重要的函数,就是和view相关的函数
    views = NULL;
    //获取到view的配置项
	(void)cfg_map_get(config, "view", &views);
    //可能会配置多个view
    for (element = cfg_list_first(views);element != NULL;element = cfg_list_next(element))
    {
        //下面先创建view,然后配置
        const cfg_obj_t *vconfig = cfg_listelt_value(element);
        create_view(vconfig, &viewlist, &view)
        //注意如果要使用dlz的话则需要在配置文件中进行相关配置
        configure_view(view, config, vconfig,ns_g_mctx, &aclconfctx, ISC_TRUE)
        {
            #ifdef DLZ
            //赋值配置项dlz
            cfg_map_get(voptions, "dlz", &dlz);
            if (dlz != NULL)
            {
                obj = cfg_tuple_get(dlz, "name");
			    result = dns_dlzcreate(mctx, cfg_obj_asstring(obj),dlzargv[0], dlzargc, dlzargv,&view->dlzdatabase);
                {
                    //注意这里的dlzname就是dlz后面配置的内容,drivername则是空格前面的内容
                    //那个通用的接口,它的method是通用的方法
                    dns_dlzimplementation_t *impinfo;
                    //在dlz_implementations list中找到该驱动对应的结构,这个是在driver_init的时候已经做好了
                    impinfo = dlz_impfind(drivername);
                    //声明一个dns_dlzdb_t的结构
                    (*dbp) = isc_mem_get(mctx, sizeof(dns_dlzdb_t));
                    //赋值该db的implementation结构
                    (*dbp)->implementation = impinfo;
                    //使用create创造db,注意这个create就是所有的dlz公有的方法dns_sdlzcreate
                    result = ((impinfo->methods->create)(mctx, dlzname, argc, argv,impinfo->driverarg, &(*dbp)->dbdata));
                    {
                        //这个结构的method就是每个dlz自己私有的数据了
                        dns_sdlzimplementation_t *imp;
                        //取到dlz带有自己的属性的那个结构
                        imp = driverarg;
                        //注意这里的这个方法就是dlz自己特有的方法,也就是F_dns_create方法
                        result = imp->methods->create(dlzname, argc, argv,imp->driverarg, dbdata);
                       {
                              
                        }
					      
                    }
					     
					    
                    
                }
					       
					       
            }
        }
				     
    }
	     
	     
}

//下面是对load_zones的分析,该函数其实是数据资源
load_zones()
{
    //同样加载区文件的时候工作线程也是停止工作的
    result = isc_task_beginexclusive(server->task);
    for (view = ISC_LIST_HEAD(server->viewlist); view != NULL; view = ISC_LIST_NEXT(view, link))
	{
		CHECK(dns_view_load(view, stop));
        {
            return (dns_zt_load(view->zonetable, stop));
            {
                result = dns_zt_apply(zt, stop, load, NULL);
                {
                    return (dns_zt_apply2(zt, stop, NULL, action, uap));
                    {
                        dns_rbtnode_t *node;
	                    dns_rbtnodechain_t chain;
                        //申请chain空间
                        dns_rbtnodechain_init(&chain, zt->mctx);
                        zt->table转向chain链
                        result = dns_rbtnodechain_first(&chain, zt->table, NULL, NULL);
                        while()
                        {
                            //开始加载zone区
                            result = (action)(zone, uap);
                        }
                    }
                    //这里重点分析一下load函数
                    load
                    {
                        result = dns_zone_load(zone);
                        return (zone_load(zone, 0));
                        {
                            //这个就是前面创建十三个根服务器的那个函数,这里相当于创建zone文件,创建一个rbt类型的db,给他赋予了zone_method,同时把它赋值给db
                            result = dns_db_create(zone->mctx, zone->db_argv[0],&zone->origin, (zone->type == dns_zone_stub) ?dns_dbtype_stub : dns_dbtype_zone,1,zone->rdclass, zone->db_argc - 1, zone->db_argv +1,&db);
                             //调用db的method
			                 dns_db_settask(db, zone->task);
    
			                 //这里就创建了db,同时使用db的一些方法对zone文件进行加载                   
			                 result = zone_startload(db, zone, loadtime);                             
			                 {
                                dns_load_t *load=isc_mem_get(zone->mctx, sizeof(*load))
                                
                             }                
			       
                        }
                    }
                }
            }
        }
	}

}

在此之前只有一个线程在监听端口,当发送完事件以后,多个client同时开始执行client_start

对于要发给工作线程的事件,它的事件的ev_sender装的是socket,对于要发给watcher线程去监听的事件,它的ev_sender装的是task

一定要注意在client_start中才让watcher线程开始监听该端口
对于udp来说,在通讯的时候不需要建立连接,到达的数据就直接是请求,因此client_start做的就是在内部调用doio_recv函数,如果这个时候没有查询请求的话,那就把该事件放到sock->recv_list中,同时把该socket放到watcher线程中监听,如果有请求的话,那就从事件的ev_sender中取出task,然后把它换成sock,然后发送给工作线程去处理,然后工作线程就可以处理eventrecv事件了
对于tcp来说,他还是一个监听端口,因此需要交给watcher线程去监听

client_start
{
    if(udp)
    {
        client_udprecv(client)
        {
            isc_region_t r;
            r.base = client->recvbuf;
	        r.length = RECV_BUFFER_SIZE;
            //对于udp来说,线程已经开始监听端口了,那么当有数据来的时候应该去读数据,所以这里开始转换client的recevent作为下次数据来时候的action
            result = isc_socket_recv2(client->udpsocket, &r, 1,client->task, client->recvevent, 0);
            {
                //设置事件对应的端口
                event->ev_sender = sock;
                ISC_LIST_INIT(event->bufferlist);
                event->region = *region;
                if (sock->type == isc_sockettype_udp)
                {
                    event->minimum = 1;
                }    
                else
                {
                    if (minimum == 0)
			            event->minimum = region->length;
		            else
			            event->minimum = minimum;
                }
                return (socket_recv(sock, event, task, flags));
                {
                    dev->ev_sender = task;
                    //如果是udp的话,则直接调用recvmsg
                    if (sock->type == isc_sockettype_udp) {
		                io_state = doio_recv(sock, dev);
	                } else {
		                    LOCK(&sock->lock);
		                    have_lock = ISC_TRUE;

		                    if (ISC_LIST_EMPTY(sock->recv_list))
			                    io_state = doio_recv(sock, dev);
		                    else
			                    io_state = DOIO_SOFT;
	                }

                    switch (io_state)
                    {
                        //这个时候该端口并没有请求过来,因此排队处理
                        case DOIO_SOFT:
                            task->referencr++;
                            ntask = task
                            //这里把该端口加入到watcher线程中
                            if (ISC_LIST_EMPTY(sock->recv_list))
			                    select_poke(sock->manager, sock->fd, SELECT_POKE_READ);
                            //把该事件放入到recv_list中
                            ISC_LIST_ENQUEUE(sock->recv_list, dev, ev_link);
                            break
                        case DOIO_HARD:
                        case DOIO_SUCCESS:
                            //返回他意味着有消息来了,那么立刻让工作线程去处理,在发送之前会从事件的ev_sender中取出task,会赋值该字段为sock,这样的话工作线程在处理的时候就知道该往那个sock发送数据了
                            if ((flags & ISC_SOCKFLAG_IMMEDIATE) == 0)
			                    send_recvdone_event(sock, &dev);
                                {
                                    //这下可以很好的理解了,因为这件事情已经处理完了,因此从recv_list中移除该事件
                                }
		                    break;
                        
                    }
                }
            }
			
        }
    }
    //这是tcp的情况,对于tcp来说接下来应该调用accept了,他要比udp多一道程序,它首先要建立连接拿到新的fd
    else
    {
        client_accept(client);
        {
            //new_conn就是连接请求过来以后调用的程序,就是建立好连接
            result = isc_socket_accept(client->tcplistener, client->task,client_newconn, client);
            {
                
                isc_socketmgr_t *manager = sock->manager
                //这里在初始化一个事件,就是建立连接的事件
                isc_socket_newconnev_t *dev = (isc_socket_newconnev_t *)isc_event_allocate(manager->mctx, task, ISC_SOCKEVENT_NEWCONN,action, arg, sizeof(*dev));
                
                //声明一个新的isc_socket_t的结构,因为accept以后拿到的就是新的socket
		        result = allocate_socket(manager, sock->type, &nsock);
                //发送事件之前要把他的ev_sender换成task,因为它这个时候还是需要监听该socket,所以要把这件事情交给watcher线程来做,
				dev->ev_sender = ntask;
                dev->newsocket = nsock;
                //下面就是把该socket放到watcher线程中去监听,也就是他现在是一个listen的状态
                if (ISC_LIST_EMPTY(sock->accept_list))
		            do_poke = ISC_TRUE;

	            ISC_LIST_ENQUEUE(sock->accept_list, dev, ev_link);

	            if (do_poke)
		            select_poke(manager, sock->fd, SELECT_POKE_ACCEPT);

            }
			
        }
    }
}

猜你喜欢

转载自blog.csdn.net/wellwang1993/article/details/83338251