static void maybe_free_listener(controllistener_t *listener) { if (listener->exiting && !listener->listening && ISC_LIST_EMPTY(listener->connections)) free_listener(listener); }
/* * Listener reference counting * * Since when reloading the configuration a listener with active connections * could be removed and connections require a reference to to the listener on * which they where received we need to allow listeners to linger outside the * listeners list in the active configuration, and free them when their last * connection closes. * * Accomplishing this with reference counting, each connection counts as a one * reference, plus one for the active EV watchers and one for the listener * being a member on a configurations listeners list. */ void listener_ref_put(struct Listener *listener) { if (listener == NULL) return; assert(listener->reference_count > 0); listener->reference_count--; if (listener->reference_count == 0) free_listener(listener); }
/* * close_listener - close a single listener */ void close_listener(struct Listener *listener) { s_assert(listener != NULL); if(listener == NULL) return; if(listener->F != NULL) { rb_close(listener->F); listener->F = NULL; } listener->active = 0; if(listener->ref_count) return; free_listener(listener); }
/* * close_listener - close a single listener */ void close_listener(struct Listener *listener) { s_assert(listener != NULL); if(listener == NULL) return; if(listener->fd >= 0) { comm_close(listener->fd); listener->fd = -1; } listener->active = 0; if(listener->ref_count) return; free_listener(listener); }
/* * close_listener - close a single listener */ void close_listener(struct Listener* listener) { assert(0 != listener); /* * remove from listener list */ if (listener == ListenerPollList) ListenerPollList = listener->next; else { struct Listener* prev = ListenerPollList; for ( ; prev; prev = prev->next) { if (listener == prev->next) { prev->next = listener->next; break; } } } if (-1 < listener->fd) CLOSE(listener->fd); free_listener(listener); }
void _free_client(struct Client* client_p) { assert(NULL != client_p); assert(&me != client_p); assert(NULL == client_p->prev); assert(NULL == client_p->next); if (MyConnect(client_p)) { assert(IsClosing(client_p) && IsDead(client_p)); /* * clean up extra sockets from P-lines which have been discarded. */ if (client_p->localClient->listener) { assert(0 < client_p->localClient->listener->ref_count); if (0 == --client_p->localClient->listener->ref_count && !client_p->localClient->listener->active) free_listener(client_p->localClient->listener); client_p->localClient->listener = 0; } if (client_p->localClient->fd >= 0) fd_close(client_p->localClient->fd); BlockHeapFree(lclient_heap, client_p->localClient); --local_client_count; assert(local_client_count >= 0); } else { --remote_client_count; } BlockHeapFree(client_heap, client_p); }
static void add_listener(ns_controls_t *cp, controllistener_t **listenerp, const cfg_obj_t *control, const cfg_obj_t *config, isc_sockaddr_t *addr, cfg_aclconfctx_t *aclconfctx, const char *socktext, isc_sockettype_t type) { isc_mem_t *mctx = cp->server->mctx; controllistener_t *listener; const cfg_obj_t *allow; const cfg_obj_t *global_keylist = NULL; const cfg_obj_t *control_keylist = NULL; dns_acl_t *new_acl = NULL; isc_result_t result = ISC_R_SUCCESS; listener = isc_mem_get(mctx, sizeof(*listener)); if (listener == NULL) result = ISC_R_NOMEMORY; if (result == ISC_R_SUCCESS) { listener->mctx = NULL; isc_mem_attach(mctx, &listener->mctx); listener->controls = cp; listener->task = cp->server->task; listener->address = *addr; listener->sock = NULL; listener->listening = ISC_FALSE; listener->exiting = ISC_FALSE; listener->acl = NULL; listener->type = type; listener->perm = 0; listener->owner = 0; listener->group = 0; ISC_LINK_INIT(listener, link); ISC_LIST_INIT(listener->keys); ISC_LIST_INIT(listener->connections); /* * Make the acl. */ if (control != NULL && type == isc_sockettype_tcp) { allow = cfg_tuple_get(control, "allow"); result = cfg_acl_fromconfig(allow, config, ns_g_lctx, aclconfctx, mctx, 0, &new_acl); } else { result = dns_acl_any(mctx, &new_acl); } } if (result == ISC_R_SUCCESS) { dns_acl_attach(new_acl, &listener->acl); dns_acl_detach(&new_acl); if (config != NULL) get_key_info(config, control, &global_keylist, &control_keylist); if (control_keylist != NULL) { result = controlkeylist_fromcfg(control_keylist, listener->mctx, &listener->keys); if (result == ISC_R_SUCCESS) register_keys(control, global_keylist, &listener->keys, listener->mctx, socktext); } else result = get_rndckey(mctx, &listener->keys); if (result != ISC_R_SUCCESS && control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't install keys for " "command channel %s: %s", socktext, isc_result_totext(result)); } if (result == ISC_R_SUCCESS) { int pf = isc_sockaddr_pf(&listener->address); if ((pf == AF_INET && isc_net_probeipv4() != ISC_R_SUCCESS) || #ifdef ISC_PLATFORM_HAVESYSUNH (pf == AF_UNIX && isc_net_probeunix() != ISC_R_SUCCESS) || #endif (pf == AF_INET6 && isc_net_probeipv6() != ISC_R_SUCCESS)) result = ISC_R_FAMILYNOSUPPORT; } if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) isc_socket_cleanunix(&listener->address, ISC_FALSE); if (result == ISC_R_SUCCESS) result = isc_socket_create(ns_g_socketmgr, isc_sockaddr_pf(&listener->address), type, &listener->sock); if (result == ISC_R_SUCCESS) isc_socket_setname(listener->sock, "control", NULL); #ifndef ISC_ALLOW_MAPPED if (result == ISC_R_SUCCESS) isc_socket_ipv6only(listener->sock, ISC_TRUE); #endif if (result == ISC_R_SUCCESS) result = isc_socket_bind(listener->sock, &listener->address, ISC_SOCKET_REUSEADDRESS); if (result == ISC_R_SUCCESS && type == isc_sockettype_unix) { listener->perm = cfg_obj_asuint32(cfg_tuple_get(control, "perm")); listener->owner = cfg_obj_asuint32(cfg_tuple_get(control, "owner")); listener->group = cfg_obj_asuint32(cfg_tuple_get(control, "group")); result = isc_socket_permunix(&listener->address, listener->perm, listener->owner, listener->group); } if (result == ISC_R_SUCCESS) result = control_listen(listener); if (result == ISC_R_SUCCESS) result = control_accept(listener); if (result == ISC_R_SUCCESS) { isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, "command channel listening on %s", socktext); *listenerp = listener; } else { if (listener != NULL) { listener->exiting = ISC_TRUE; free_listener(listener); } if (control != NULL) cfg_obj_log(control, ns_g_lctx, ISC_LOG_WARNING, "couldn't add command channel %s: %s", socktext, isc_result_totext(result)); else isc_log_write(ns_g_lctx, NS_LOGCATEGORY_GENERAL, NS_LOGMODULE_CONTROL, ISC_LOG_NOTICE, "couldn't add command channel %s: %s", socktext, isc_result_totext(result)); *listenerp = NULL; } /* XXXDCL return error results? fail hard? */ }
static void listener_disconnect(void* _l, atransport* t) { alistener* l = _l; free_listener(l); }
void remove_listener(struct Listener_head *listeners, struct Listener *listener) { SLIST_REMOVE(listeners, listener, Listener, entries); close_listener(EV_DEFAULT, listener); free_listener(listener); }
static int inetport(struct Listener* listener) { struct irc_sockaddr lsin; int fd; int opt = 1; /* * At first, open a new socket */ fd = comm_open(DEF_FAM, SOCK_STREAM, 0, "Listener socket"); #ifdef IPV6 if (!IN6_ARE_ADDR_EQUAL((struct in6_addr *)&listener->addr, &in6addr_any)) { #else if (INADDR_ANY != listener->addr.sins.sin.s_addr) { #endif inetntop(DEF_FAM, &IN_ADDR(listener->addr), listener->vhost, HOSTLEN); listener->name = listener->vhost; } if (fd == -1) { report_error(L_ALL, "opening listener socket %s:%s", get_listener_name(listener), errno); return 0; } else if ((HARD_FDLIMIT - 10) < fd) { report_error(L_ALL, "no more connections left for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - we don't want to do all this crap for a listener * set_sock_opts(listener); */ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*) &opt, sizeof(opt))) { report_error(L_ALL, "setting SO_REUSEADDR for listener %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * Bind a port to listen for new connections if port is non-null, * else assume it is already open and try get something from it. */ memset(&lsin, 0, sizeof(struct irc_sockaddr)); S_FAM(lsin) = DEF_FAM; copy_s_addr(S_ADDR(lsin), IN_ADDR(listener->addr)); S_PORT(lsin) = htons(listener->port); if (bind(fd, (struct sockaddr*) &SOCKADDR(lsin), sizeof(struct irc_sockaddr))) { report_error(L_ALL, "binding listener socket %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } if (listen(fd, HYBRID_SOMAXCONN)) { report_error(L_ALL, "listen failed for %s:%s", get_listener_name(listener), errno); fd_close(fd); return 0; } /* * XXX - this should always work, performance will suck if it doesn't */ if (!set_non_blocking(fd)) report_error(L_ALL, NONB_ERROR_MSG, get_listener_name(listener), errno); listener->fd = fd; /* Listen completion events are READ events .. */ accept_connection(fd, listener); return 1; } static struct Listener* find_listener(int port, struct irc_inaddr *addr) { struct Listener* listener = NULL; struct Listener* last_closed = NULL; for (listener = ListenerPollList; listener; listener = listener->next) { if ( (port == listener->port) && (!memcmp(&PIN_ADDR(addr), &IN_ADDR(listener->addr), sizeof(struct irc_inaddr)))) { /* Try to return an open listener, otherwise reuse a closed one */ if (listener->fd == -1) last_closed = listener; else return listener; } } return last_closed; } /* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in * the format "255.255.255.255" */ void add_listener(int port, const char* vhost_ip) { struct Listener* listener; struct irc_inaddr vaddr; /* * if no port in conf line, don't bother */ if (port == 0) return; #ifdef IPV6 copy_s_addr(IN_ADDR(vaddr), &in6addr_any); #else copy_s_addr(IN_ADDR(vaddr), INADDR_ANY); #endif if (vhost_ip) { if(inetpton(DEF_FAM, vhost_ip, &IN_ADDR(vaddr)) <= 0) return; } if ((listener = find_listener(port, &vaddr))) { if (listener->fd > -1) return; } else { listener = make_listener(port, &vaddr); listener->next = ListenerPollList; ListenerPollList = listener; } listener->fd = -1; if (inetport(listener)) listener->active = 1; else close_listener(listener); } /* * close_listener - close a single listener */ void close_listener(struct Listener* listener) { assert(listener != NULL); if(listener == NULL) return; if (listener->fd >= 0) { fd_close(listener->fd); listener->fd = -1; } listener->active = 0; if (listener->ref_count) return; free_listener(listener); }
/* * add_listener- create a new listener * port - the port number to listen on * vhost_ip - if non-null must contain a valid IP address string in the format "255.255.255.255" * options - listener options * cp - listener default code page */ void add_listener(int port, const char* vhost_ip, char* options, char* cp) { struct Listener* listener; struct IN_ADDR vaddr; /* * if no port in conf line, don't bother */ if (0 == port) return; #ifdef IPV6 vaddr = INADDRANY; #else vaddr.s_addr = INADDRANY; #endif if (vhost_ip) { #ifdef IPV6 if(inetpton(AFINET, vhost_ip, &vaddr) == 0) return; #else vaddr.s_addr = inet_addr(vhost_ip); if (INADDR_NONE == vaddr.s_addr) return; #endif } if ((listener = find_listener(port, vaddr))) { listener->active = 1; return; } if(options && *options) irclog(L_NOTICE,"Adding listener for %s, port %d Options:%s", vhost_ip ? vhost_ip : "ANY", port, options ); else irclog(L_NOTICE,"Adding listener for %s, port %d", vhost_ip ? vhost_ip : "ANY", port); listener = make_listener(port, vaddr); if(options) { while(*options) { switch(*options) { case 's' : #ifdef HAVE_SSL if(no_ssl) irclog(L_WARN,"ignoring port with 's' option!"); else listener->options |= LST_SSL; #else irclog(L_WARN,"ircd compiled without SSL support, ignoring port with 's' option!"); #endif break; case 'S' : listener->options |= LST_SERVER; break; case 'W' : listener->options |= LST_WEBCHAT; break; case 'J' : listener->options |= LST_JAVACR; break; case 'n' : listener->options |= LST_NOSPOOF; break; } ++options; } } if(cp && cp[0]) { listener->codepage = codepage_find(cp); if(listener->codepage==-1) irclog(L_WARN,"Codepage %s defined on P:line was not loaded!", cp); } else listener->codepage=-1; if (inetport(listener)) { listener->active = 1; listener->next = ListenerPollList; ListenerPollList = listener; } else free_listener(listener); }
void listener_disconnect(void* listener, atransport* t) { free_listener(reinterpret_cast<alistener*>(listener)); }