📄 interfacemgr.c
字号:
/* * Copyright (C) 2004 Internet Systems Consortium, Inc. ("ISC") * Copyright (C) 1999-2002 Internet Software Consortium. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. *//* $Id: interfacemgr.c,v 1.59.2.5.8.15 2004/08/10 04:56:23 jinmei Exp $ */#include <config.h>#include <isc/interfaceiter.h>#include <isc/string.h>#include <isc/task.h>#include <isc/util.h>#include <dns/acl.h>#include <dns/dispatch.h>#include <named/client.h>#include <named/log.h>#include <named/interfacemgr.h>#define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G')#define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC)#define IFMGR_COMMON_LOGARGS \ ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGRstruct ns_interfacemgr { unsigned int magic; /* Magic number. */ int references; isc_mutex_t lock; isc_mem_t * mctx; /* Memory context. */ isc_taskmgr_t * taskmgr; /* Task manager. */ isc_socketmgr_t * socketmgr; /* Socket manager. */ dns_dispatchmgr_t * dispatchmgr; unsigned int generation; /* Current generation no. */ ns_listenlist_t * listenon4; ns_listenlist_t * listenon6; dns_aclenv_t aclenv; /* Localhost/localnets ACLs */ ISC_LIST(ns_interface_t) interfaces; /* List of interfaces. */};static voidpurge_old_interfaces(ns_interfacemgr_t *mgr);isc_result_tns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr, dns_dispatchmgr_t *dispatchmgr, ns_interfacemgr_t **mgrp){ isc_result_t result; ns_interfacemgr_t *mgr; REQUIRE(mctx != NULL); REQUIRE(mgrp != NULL); REQUIRE(*mgrp == NULL); mgr = isc_mem_get(mctx, sizeof(*mgr)); if (mgr == NULL) return (ISC_R_NOMEMORY); result = isc_mutex_init(&mgr->lock); if (result != ISC_R_SUCCESS) goto cleanup_mem; mgr->mctx = mctx; mgr->taskmgr = taskmgr; mgr->socketmgr = socketmgr; mgr->dispatchmgr = dispatchmgr; mgr->generation = 1; mgr->listenon4 = NULL; mgr->listenon6 = NULL; ISC_LIST_INIT(mgr->interfaces); /* * The listen-on lists are initially empty. */ result = ns_listenlist_create(mctx, &mgr->listenon4); if (result != ISC_R_SUCCESS) goto cleanup_mem; ns_listenlist_attach(mgr->listenon4, &mgr->listenon6); result = dns_aclenv_init(mctx, &mgr->aclenv); if (result != ISC_R_SUCCESS) goto cleanup_listenon; mgr->references = 1; mgr->magic = IFMGR_MAGIC; *mgrp = mgr; return (ISC_R_SUCCESS); cleanup_listenon: ns_listenlist_detach(&mgr->listenon4); ns_listenlist_detach(&mgr->listenon6); cleanup_mem: isc_mem_put(mctx, mgr, sizeof(*mgr)); return (result);}static voidns_interfacemgr_destroy(ns_interfacemgr_t *mgr) { REQUIRE(NS_INTERFACEMGR_VALID(mgr)); dns_aclenv_destroy(&mgr->aclenv); ns_listenlist_detach(&mgr->listenon4); ns_listenlist_detach(&mgr->listenon6); DESTROYLOCK(&mgr->lock); mgr->magic = 0; isc_mem_put(mgr->mctx, mgr, sizeof(*mgr));}dns_aclenv_t *ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) { return (&mgr->aclenv);}voidns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) { REQUIRE(NS_INTERFACEMGR_VALID(source)); LOCK(&source->lock); INSIST(source->references > 0); source->references++; UNLOCK(&source->lock); *target = source;}voidns_interfacemgr_detach(ns_interfacemgr_t **targetp) { isc_result_t need_destroy = ISC_FALSE; ns_interfacemgr_t *target = *targetp; REQUIRE(target != NULL); REQUIRE(NS_INTERFACEMGR_VALID(target)); LOCK(&target->lock); REQUIRE(target->references > 0); target->references--; if (target->references == 0) need_destroy = ISC_TRUE; UNLOCK(&target->lock); if (need_destroy) ns_interfacemgr_destroy(target); *targetp = NULL;}voidns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) { REQUIRE(NS_INTERFACEMGR_VALID(mgr)); /* * Shut down and detach all interfaces. * By incrementing the generation count, we make purge_old_interfaces() * consider all interfaces "old". */ mgr->generation++; purge_old_interfaces(mgr);}static isc_result_tns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, ns_interface_t **ifpret){ ns_interface_t *ifp; isc_result_t result; REQUIRE(NS_INTERFACEMGR_VALID(mgr)); ifp = isc_mem_get(mgr->mctx, sizeof(*ifp)); if (ifp == NULL) return (ISC_R_NOMEMORY); ifp->mgr = NULL; ifp->generation = mgr->generation; ifp->addr = *addr; strncpy(ifp->name, name, sizeof(ifp->name)); ifp->name[sizeof(ifp->name)-1] = '\0'; ifp->clientmgr = NULL; result = isc_mutex_init(&ifp->lock); if (result != ISC_R_SUCCESS) goto lock_create_failure; result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr, ns_g_timermgr, &ifp->clientmgr); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "ns_clientmgr_create() failed: %s", isc_result_totext(result)); goto clientmgr_create_failure; } ifp->udpdispatch = NULL; ifp->tcpsocket = NULL; /* * Create a single TCP client object. It will replace itself * with a new one as soon as it gets a connection, so the actual * connections will be handled in parallel even though there is * only one client initially. */ ifp->ntcptarget = 1; ifp->ntcpcurrent = 0; ISC_LINK_INIT(ifp, link); ns_interfacemgr_attach(mgr, &ifp->mgr); ISC_LIST_APPEND(mgr->interfaces, ifp, link); ifp->references = 1; ifp->magic = IFACE_MAGIC; *ifpret = ifp; return (ISC_R_SUCCESS); clientmgr_create_failure: DESTROYLOCK(&ifp->lock); lock_create_failure: ifp->magic = 0; isc_mem_put(mgr->mctx, ifp, sizeof(*ifp)); return (ISC_R_UNEXPECTED);}static isc_result_tns_interface_listenudp(ns_interface_t *ifp) { isc_result_t result; unsigned int attrs; unsigned int attrmask; attrs = 0; attrs |= DNS_DISPATCHATTR_UDP; if (isc_sockaddr_pf(&ifp->addr) == AF_INET) attrs |= DNS_DISPATCHATTR_IPV4; else attrs |= DNS_DISPATCHATTR_IPV6; attrs |= DNS_DISPATCHATTR_NOLISTEN; attrmask = 0; attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr, ns_g_taskmgr, &ifp->addr, 4096, 1000, 32768, 8219, 8237, attrs, attrmask, &ifp->udpdispatch); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "could not listen on UDP socket: %s", isc_result_totext(result)); goto udp_dispatch_failure; } result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus, ifp, ISC_FALSE); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "UDP ns_clientmgr_createclients(): %s", isc_result_totext(result)); goto addtodispatch_failure; } return (ISC_R_SUCCESS); addtodispatch_failure: dns_dispatch_changeattributes(ifp->udpdispatch, 0, DNS_DISPATCHATTR_NOLISTEN); dns_dispatch_detach(&ifp->udpdispatch); udp_dispatch_failure: return (result);}static isc_result_tns_interface_accepttcp(ns_interface_t *ifp) { isc_result_t result; /* * Open a TCP socket. */ result = isc_socket_create(ifp->mgr->socketmgr, isc_sockaddr_pf(&ifp->addr), isc_sockettype_tcp, &ifp->tcpsocket); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "creating TCP socket: %s", isc_result_totext(result)); goto tcp_socket_failure; }#ifndef ISC_ALLOW_MAPPED isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);#endif result = isc_socket_bind(ifp->tcpsocket, &ifp->addr); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "binding TCP socket: %s", isc_result_totext(result)); goto tcp_bind_failure; } result = isc_socket_listen(ifp->tcpsocket, ns_g_listen); if (result != ISC_R_SUCCESS) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "listening on TCP socket: %s", isc_result_totext(result)); goto tcp_listen_failure; } /* * If/when there a multiple filters listen to the * result. */ (void)isc_socket_filter(ifp->tcpsocket, "dataready"); result = ns_clientmgr_createclients(ifp->clientmgr, ifp->ntcptarget, ifp, ISC_TRUE); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "TCP ns_clientmgr_createclients(): %s", isc_result_totext(result)); goto accepttcp_failure; } return (ISC_R_SUCCESS); accepttcp_failure: tcp_listen_failure: tcp_bind_failure: isc_socket_detach(&ifp->tcpsocket); tcp_socket_failure: return (ISC_R_SUCCESS);}static isc_result_tns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, const char *name, ns_interface_t **ifpret, isc_boolean_t accept_tcp){ isc_result_t result; ns_interface_t *ifp = NULL; REQUIRE(ifpret != NULL && *ifpret == NULL); result = ns_interface_create(mgr, addr, name, &ifp); if (result != ISC_R_SUCCESS) return (result); result = ns_interface_listenudp(ifp); if (result != ISC_R_SUCCESS) goto cleanup_interface; if (accept_tcp == ISC_TRUE) { result = ns_interface_accepttcp(ifp); if (result != ISC_R_SUCCESS) { /* * XXXRTH We don't currently have a way to easily stop * dispatch service, so we currently return * ISC_R_SUCCESS (the UDP stuff will work even if TCP * creation failed). This will be fixed later. */ result = ISC_R_SUCCESS; } } *ifpret = ifp; return (ISC_R_SUCCESS); cleanup_interface: ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link); ns_interface_detach(&ifp); return (result);}voidns_interface_shutdown(ns_interface_t *ifp) { if (ifp->clientmgr != NULL) ns_clientmgr_destroy(&ifp->clientmgr);}static voidns_interface_destroy(ns_interface_t *ifp) { isc_mem_t *mctx = ifp->mgr->mctx; REQUIRE(NS_INTERFACE_VALID(ifp)); ns_interface_shutdown(ifp); if (ifp->udpdispatch != NULL) { dns_dispatch_changeattributes(ifp->udpdispatch, 0, DNS_DISPATCHATTR_NOLISTEN); dns_dispatch_detach(&ifp->udpdispatch); } if (ifp->tcpsocket != NULL) isc_socket_detach(&ifp->tcpsocket); DESTROYLOCK(&ifp->lock); ns_interfacemgr_detach(&ifp->mgr); ifp->magic = 0; isc_mem_put(mctx, ifp, sizeof(*ifp));}voidns_interface_attach(ns_interface_t *source, ns_interface_t **target) { REQUIRE(NS_INTERFACE_VALID(source)); LOCK(&source->lock); INSIST(source->references > 0); source->references++; UNLOCK(&source->lock); *target = source;}voidns_interface_detach(ns_interface_t **targetp) { isc_result_t need_destroy = ISC_FALSE; ns_interface_t *target = *targetp; REQUIRE(target != NULL); REQUIRE(NS_INTERFACE_VALID(target)); LOCK(&target->lock); REQUIRE(target->references > 0); target->references--; if (target->references == 0) need_destroy = ISC_TRUE; UNLOCK(&target->lock); if (need_destroy) ns_interface_destroy(target); *targetp = NULL;}/* * Search the interface list for an interface whose address and port * both match those of 'addr'. Return a pointer to it, or NULL if not found. */static ns_interface_t *find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) { ns_interface_t *ifp; for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = ISC_LIST_NEXT(ifp, link)) { if (isc_sockaddr_equal(&ifp->addr, addr)) break; } return (ifp);}/* * Remove any interfaces whose generation number is not the current one. */static voidpurge_old_interfaces(ns_interfacemgr_t *mgr) { ns_interface_t *ifp, *next; for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) { INSIST(NS_INTERFACE_VALID(ifp));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -