Exemple #1
0
static void
maybe_free_listener(controllistener_t *listener) {
	if (listener->exiting &&
	    !listener->listening &&
	    ISC_LIST_EMPTY(listener->connections))
		free_listener(listener);
}
Exemple #2
0
/*
 * 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);
}
Exemple #3
0
/*
 * 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);
}
Exemple #5
0
/*
 * 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);
}
Exemple #6
0
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);
}
Exemple #7
0
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? */
}
Exemple #8
0
static void listener_disconnect(void*  _l, atransport*  t)
{
    alistener*  l = _l;

    free_listener(l);
}
Exemple #9
0
void
remove_listener(struct Listener_head *listeners, struct Listener *listener) {
    SLIST_REMOVE(listeners, listener, Listener, entries);
    close_listener(EV_DEFAULT, listener);
    free_listener(listener);
}
Exemple #10
0
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);
}
Exemple #11
0
/*
 * 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));
}