Ejemplo n.º 1
0
static int knet_vty_init_listener(const char *ip_addr, const char *port)
{
    int sockfd = -1, sockopt = 1;
    int socktype = SOCK_STREAM;
    int err = 0;
    struct sockaddr_storage ss;

    memset(&ss, 0, sizeof(struct sockaddr_storage));

    if (strtoaddr(ip_addr, port, (struct sockaddr *)&ss, sizeof(struct sockaddr_storage)) != 0)
        return -1;

    pthread_mutex_lock(&knet_vty_mutex);

    /* handle sigpipe if we decide to use KEEPALIVE */

    sockfd = socket(ss.ss_family, socktype, 0);
    if (sockfd < 0) {
        err = sockfd;
        goto out_clean;
    }

    if (ss.ss_family == AF_INET6) {
        err = setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY,
                         (void *)&sockopt, sizeof(sockopt));
        if (err)
            goto out_clean;
    }

    err = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
                     (void *)&sockopt, sizeof(sockopt));
    if (err)
        goto out_clean;

    if (_fdset_cloexec(sockfd)) {
        err = -1;
        goto out_clean;
    }

    err = bind(sockfd, (struct sockaddr *)&ss, sizeof(struct sockaddr_storage));
    if (err)
        goto out_clean;

    err = listen(sockfd, 0);
    if (err)
        goto out_clean;

    pthread_mutex_unlock(&knet_vty_mutex);

    return sockfd;

out_clean:
    if (sockfd >= 0)
        close(sockfd);

    pthread_mutex_unlock(&knet_vty_mutex);

    return err;
}
Ejemplo n.º 2
0
static int _init_socketpair(knet_handle_t knet_h, int (*sock)[2])
{
	int savederrno = 0;

	if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, *sock) != 0) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to initialize socketpair: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	if (_fdset_cloexec(*sock[0])) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on sock[0]: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	if (_fdset_nonblock(*sock[0])) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to set NONBLOCK on sock[0]: %s", 
			strerror(savederrno));
		goto exit_fail;
	}

	if (_fdset_cloexec(*sock[1])) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on sock[1]: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	if (_fdset_nonblock(*sock[1])) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to set NONBLOCK on sock[1]: %s", 
			strerror(savederrno));
		goto exit_fail;
	}

	return 0;

exit_fail:
	errno = savederrno;
	return -1;
}
Ejemplo n.º 3
0
int _configure_common_socket(knet_handle_t knet_h, int sock, uint64_t flags, const char *type)
{
	int err = 0, savederrno = 0;
	int value;

	if (_fdset_cloexec(sock)) {
		savederrno = errno;
		err = -1;
		log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to set %s CLOEXEC socket opts: %s",
			type, strerror(savederrno));
		goto exit_error;
	}

	if (_fdset_nonblock(sock)) {
		savederrno = errno;
		err = -1;
		log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to set %s NONBLOCK socket opts: %s",
			type, strerror(savederrno));
		goto exit_error;
	}

	if (_configure_sockbuf(knet_h, sock, SO_RCVBUF, SO_RCVBUFFORCE, KNET_RING_RCVBUFF)) {
		savederrno = errno;
		err = -1;
		log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to set %s receive buffer: %s",
			type, strerror(savederrno));
		goto exit_error;
	}

	if (_configure_sockbuf(knet_h, sock, SO_SNDBUF, SO_SNDBUFFORCE, KNET_RING_RCVBUFF)) {
		savederrno = errno;
		err = -1;
		log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to set %s send buffer: %s",
			type, strerror(savederrno));
		goto exit_error;
	}

	if (flags & KNET_LINK_FLAG_TRAFFICHIPRIO) {
#ifdef KNET_LINUX
#ifdef SO_PRIORITY
		value = 6; /* TC_PRIO_INTERACTIVE */
		if (setsockopt(sock, SOL_SOCKET, SO_PRIORITY, &value, sizeof(value)) < 0) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to set %s priority: %s",
				type, strerror(savederrno));
			goto exit_error;
		}
		log_debug(knet_h, KNET_SUB_TRANSPORT, "TC_PRIO_INTERACTIVE enabled on socket: %i", sock);
#else
		log_debug(knet_h, KNET_SUB_TRANSPORT, "TC_PRIO_INTERACTIVE not available in this build/platform");
#endif
#endif
#if defined(IP_TOS) && defined(IPTOS_LOWDELAY)
		value = IPTOS_LOWDELAY;
		if (setsockopt(sock, IPPROTO_IP, IP_TOS, &value, sizeof(value)) < 0) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_TRANSPORT, "Unable to set %s priority: %s",
				type, strerror(savederrno));
			goto exit_error;
		}
		log_debug(knet_h, KNET_SUB_TRANSPORT, "IPTOS_LOWDELAY enabled on socket: %i", sock);
#else
		log_debug(knet_h, KNET_SUB_TRANSPORT, "IPTOS_LOWDELAY not available in this build/platform");
#endif
	}

exit_error:
	errno = savederrno;
	return err;
}
Ejemplo n.º 4
0
int knet_handle_add_datafd(knet_handle_t knet_h, int *datafd, int8_t *channel)
{
	int err = 0, savederrno = 0;
	int i;
	struct epoll_event ev;

	if (!knet_h) {
		errno = EINVAL;
		return -1;
	}

	if (datafd == NULL) {
		errno = EINVAL;
		return -1;
	}

	if (channel == NULL) {
		errno = EINVAL;
		return -1;
	}

	if (*channel >= KNET_DATAFD_MAX) {
		errno = EINVAL;
		return -1;
	}

	savederrno = pthread_rwlock_wrlock(&knet_h->list_rwlock);
	if (savederrno) {
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to get write lock: %s",
			strerror(savederrno));
		errno = savederrno;
		return -1;
	}

	if (!knet_h->sock_notify_fn) {
		log_err(knet_h, KNET_SUB_HANDLE, "Adding datafd requires sock notify callback enabled!");
		savederrno = EINVAL;
		err = -1;
		goto out_unlock;
	}

	if (*datafd > 0) {
		for (i = 0; i < KNET_DATAFD_MAX; i++) {
			if  ((knet_h->sockfd[i].in_use) && (knet_h->sockfd[i].sockfd[0] == *datafd)) {
				log_err(knet_h, KNET_SUB_HANDLE, "requested datafd: %d already exist in index: %d", *datafd, i);
				savederrno = EEXIST;
				err = -1;
				goto out_unlock;
			}
		}
	}

	/*
	 * auto allocate a channel
	 */
	if (*channel < 0) {
		for (i = 0; i < KNET_DATAFD_MAX; i++) {
			if (!knet_h->sockfd[i].in_use) {
				*channel = i;
				break;
			}
		}
		if (*channel < 0) {
			savederrno = EBUSY;
			err = -1;
			goto out_unlock;
		}
	} else {
		if (knet_h->sockfd[*channel].in_use) {
			savederrno = EBUSY;
			err = -1;
			goto out_unlock;
		}
	}

	knet_h->sockfd[*channel].is_created = 0;
	knet_h->sockfd[*channel].is_socket = 0;
	knet_h->sockfd[*channel].has_error = 0;

	if (*datafd > 0) {
		int sockopt;
		socklen_t sockoptlen = sizeof(sockopt);

		if (_fdset_cloexec(*datafd)) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on datafd: %s",
				strerror(savederrno));
			goto out_unlock;
		}

		if (_fdset_nonblock(*datafd)) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_HANDLE, "Unable to set NONBLOCK on datafd: %s",
				strerror(savederrno));
			goto out_unlock;
		}

		knet_h->sockfd[*channel].sockfd[0] = *datafd;
		knet_h->sockfd[*channel].sockfd[1] = 0;

		if (!getsockopt(knet_h->sockfd[*channel].sockfd[0], SOL_SOCKET, SO_TYPE, &sockopt, &sockoptlen)) {
			knet_h->sockfd[*channel].is_socket = 1;
		}
	} else {
		if (_init_socketpair(knet_h, &knet_h->sockfd[*channel].sockfd)) {
			savederrno = errno;
			err = -1;
			goto out_unlock;
		}

		knet_h->sockfd[*channel].is_created = 1;
		knet_h->sockfd[*channel].is_socket = 1;
		*datafd = knet_h->sockfd[*channel].sockfd[0];
	}

	memset(&ev, 0, sizeof(struct epoll_event));
	ev.events = EPOLLIN;
	ev.data.fd = knet_h->sockfd[*channel].sockfd[knet_h->sockfd[*channel].is_created];

	if (epoll_ctl(knet_h->send_to_links_epollfd,
		      EPOLL_CTL_ADD, knet_h->sockfd[*channel].sockfd[knet_h->sockfd[*channel].is_created], &ev)) {
		savederrno = errno;
		err = -1;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to add datafd %d to linkfd epoll pool: %s",
			knet_h->sockfd[*channel].sockfd[knet_h->sockfd[*channel].is_created], strerror(savederrno));
		if (knet_h->sockfd[*channel].is_created) {
			_close_socketpair(knet_h, &knet_h->sockfd[*channel].sockfd);
		}
		goto out_unlock;
	}

	knet_h->sockfd[*channel].in_use = 1;

out_unlock:
	pthread_rwlock_unlock(&knet_h->list_rwlock);
	errno = savederrno;
	return err;
}
Ejemplo n.º 5
0
static int _init_epolls(knet_handle_t knet_h)
{
	struct epoll_event ev;
	int savederrno = 0;

	/*
	 * even if the kernel does dynamic allocation with epoll_ctl
	 * we need to reserve one extra for host to host communication
	 */
	knet_h->send_to_links_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS + 1);
	if (knet_h->send_to_links_epollfd < 0) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to create epoll datafd to link fd: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	knet_h->recv_from_links_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS);
	if (knet_h->recv_from_links_epollfd < 0) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to create epoll link to datafd fd: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	knet_h->dst_link_handler_epollfd = epoll_create(KNET_EPOLL_MAX_EVENTS);
	if (knet_h->dst_link_handler_epollfd < 0) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to create epoll dst cache fd: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	if (_fdset_cloexec(knet_h->send_to_links_epollfd)) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on datafd to link epoll fd: %s",
			strerror(savederrno)); 
		goto exit_fail;
	}

	if (_fdset_cloexec(knet_h->recv_from_links_epollfd)) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on link to datafd epoll fd: %s",
			strerror(savederrno)); 
		goto exit_fail;
	}

	if (_fdset_cloexec(knet_h->dst_link_handler_epollfd)) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to set CLOEXEC on dst cache epoll fd: %s",
			strerror(savederrno)); 
		goto exit_fail;
	}

	memset(&ev, 0, sizeof(struct epoll_event));
	ev.events = EPOLLIN;
	ev.data.fd = knet_h->hostsockfd[0];

	if (epoll_ctl(knet_h->send_to_links_epollfd,
		      EPOLL_CTL_ADD, knet_h->hostsockfd[0], &ev)) {
		savederrno = errno;
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to add hostsockfd[0] to epoll pool: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	memset(&ev, 0, sizeof(struct epoll_event));
	ev.events = EPOLLIN;
	ev.data.fd = knet_h->dstsockfd[0];

	if (epoll_ctl(knet_h->dst_link_handler_epollfd,
		      EPOLL_CTL_ADD, knet_h->dstsockfd[0], &ev)) {
		log_err(knet_h, KNET_SUB_HANDLE, "Unable to add dstsockfd[0] to epoll pool: %s",
			strerror(savederrno));
		goto exit_fail;
	}

	return 0;

exit_fail:
	errno = savederrno;
	return -1;
}
Ejemplo n.º 6
0
int _listener_add(knet_handle_t knet_h, struct knet_link *lnk)
{
	int value;
	struct epoll_event ev;
	int save_errno = 0;
	struct knet_listener *listener;

	if (pthread_rwlock_wrlock(&knet_h->list_rwlock) != 0) {
		save_errno = errno;
		log_err(knet_h, KNET_SUB_LISTENER, "listener_add: Unable to get write lock");
		errno = save_errno;
		return -1;
	}

	listener = knet_h->listener_head;

	while (listener) {
		if (!memcmp(&lnk->src_addr, &listener->address, sizeof(struct sockaddr_storage))) {
			log_debug(knet_h, KNET_SUB_LISTENER, "found active listener");
			break;
		}
		listener = listener->next;
	}

	if (!listener) {
		listener = malloc(sizeof(struct knet_listener));
		if (!listener) {
			save_errno = errno;
			log_debug(knet_h, KNET_SUB_LISTENER, "out of memory to allocate listener");
			goto exit_fail1;
		}

		memset(listener, 0, sizeof(struct knet_listener));
		memcpy(&listener->address, &lnk->src_addr, sizeof(struct sockaddr_storage));

		listener->sock = socket(listener->address.ss_family, SOCK_DGRAM, 0);
		if (listener->sock < 0) {
			save_errno = errno;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to create listener socket");
			goto exit_fail2;
		}

		value = KNET_RING_RCVBUFF;
		setsockopt(listener->sock, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value));

		if (listener->address.ss_family == AF_INET6) {
			value = 1;
			setsockopt(listener->sock, IPPROTO_IPV6, IPV6_V6ONLY,
				   &value, sizeof(value));
		}

		if (_fdset_cloexec(listener->sock) != 0) {
			save_errno = errno;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to set listener socket opts");
			goto exit_fail3;
		}

		if (bind(listener->sock, (struct sockaddr *) &listener->address,
						sizeof(struct sockaddr_storage)) != 0) {
			save_errno = errno;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to bind listener socket");
			goto exit_fail3;
		}

		memset(&ev, 0, sizeof(struct epoll_event));

		ev.events = EPOLLIN;
		ev.data.fd = listener->sock;

		if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_ADD, listener->sock, &ev) != 0) {
			save_errno = errno;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to add listener to epoll pool");
			goto exit_fail3;
		}

		/* pushing new host to the front */
		listener->next		= knet_h->listener_head;
		knet_h->listener_head	= listener;
	}
	lnk->listener_sock = listener->sock;

	pthread_rwlock_unlock(&knet_h->list_rwlock);

	return 0;

 exit_fail3:
	close(listener->sock);

 exit_fail2:
	if (listener)
		free(listener);

 exit_fail1:
	pthread_rwlock_unlock(&knet_h->list_rwlock);
	errno = save_errno;
	return -1;
}
Ejemplo n.º 7
0
int _listener_add(knet_handle_t knet_h, uint16_t host_id, uint8_t link_id)
{
	int value, count = 0;
	struct epoll_event ev;
	int savederrno = 0, err = 0;
	struct knet_link *lnk = &knet_h->host_index[host_id]->link[link_id];
	struct knet_listener *listener = NULL;

	savederrno = pthread_rwlock_wrlock(&knet_h->listener_rwlock);
	if (savederrno) {
		log_err(knet_h, KNET_SUB_LISTENER, "Unable to get write lock: %s",
			strerror(savederrno));
		errno = savederrno;
		return -1;
	}

	listener = knet_h->listener_head;

	while (listener) {
		count++;
		log_debug(knet_h, KNET_SUB_LISTENER, "checking listener: %d", count);
		if (!memcmp(&lnk->src_addr, &listener->address, sizeof(struct sockaddr_storage))) {
			log_debug(knet_h, KNET_SUB_LISTENER, "found active listener");
			break;
		}
		listener = listener->next;
	}

	if (!listener) {
		listener = malloc(sizeof(struct knet_listener));
		if (!listener) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "out of memory to allocate listener: %s",
				  strerror(savederrno));
			goto exit_unlock;
		}

		memset(listener, 0, sizeof(struct knet_listener));
		memmove(&listener->address, &lnk->src_addr, sizeof(struct sockaddr_storage));

		listener->sock = socket(listener->address.ss_family, SOCK_DGRAM, 0);
		if (listener->sock < 0) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to create listener socket: %s",
				strerror(savederrno));
			goto exit_unlock;
		}

		value = KNET_RING_RCVBUFF;
		if (setsockopt(listener->sock, SOL_SOCKET, SO_RCVBUFFORCE, &value, sizeof(value)) < 0) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to set listener receive buffer: %s",
				strerror(savederrno));
			goto exit_unlock;
		}

		value = 1;
		if (setsockopt(listener->sock, SOL_IP, IP_FREEBIND, &value, sizeof(value)) <0) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to set FREEBIND on listener socket: %s",
				strerror(savederrno));
			goto exit_unlock;
		}

		if (listener->address.ss_family == AF_INET6) {
			value = 1;
			if (setsockopt(listener->sock, IPPROTO_IPV6, IPV6_V6ONLY,
				       &value, sizeof(value)) < 0) {
				savederrno = errno;
				err = -1;
				log_err(knet_h, KNET_SUB_LISTENER, "Unable to set listener IPv6 only: %s",
					strerror(savederrno));
				goto exit_unlock;

			}
			value = IPV6_PMTUDISC_PROBE;
			if (setsockopt(listener->sock, SOL_IPV6, IPV6_MTU_DISCOVER, &value, sizeof(value)) <0) {
				savederrno = errno;
				err = -1;
				log_err(knet_h, KNET_SUB_LISTENER, "Unable to set PMTUDISC on listener socket: %s",
					strerror(savederrno));
				goto exit_unlock;
			}
		} else {
			value = IP_PMTUDISC_PROBE;
			if (setsockopt(listener->sock, SOL_IP, IP_MTU_DISCOVER, &value, sizeof(value)) <0) {
				savederrno = errno;
				err = -1;
				log_err(knet_h, KNET_SUB_LISTENER, "Unable to set PMTUDISC on listener socket: %s",
					strerror(savederrno));
				goto exit_unlock;
			}
		}

		if (_fdset_cloexec(listener->sock)) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to set listener CLOEXEC socket opts: %s",
				strerror(savederrno));
			goto exit_unlock;
		}

		if (_fdset_nonblock(listener->sock)) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to set listener NONBLOCK socket opts: %s",
				strerror(savederrno));
			goto exit_unlock;
		}

		if (bind(listener->sock, (struct sockaddr *)&listener->address, sizeof(struct sockaddr_storage)) < 0) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to bind listener socket: %s",
				strerror(savederrno));
			goto exit_unlock;
		}

		memset(&ev, 0, sizeof(struct epoll_event));

		ev.events = EPOLLIN;
		ev.data.fd = listener->sock;

		if (epoll_ctl(knet_h->recv_from_links_epollfd, EPOLL_CTL_ADD, listener->sock, &ev)) {
			savederrno = errno;
			err = -1;
			log_err(knet_h, KNET_SUB_LISTENER, "Unable to add listener to epoll pool: %s",
				strerror(savederrno));
			goto exit_unlock;
		}

		/* pushing new host to the front */
		listener->next		= knet_h->listener_head;
		knet_h->listener_head	= listener;
	}
	lnk->listener_sock = listener->sock;

exit_unlock:
	if ((err) && (listener)) {
		if (listener->sock >= 0) {
			close(listener->sock);
		}
		free(listener);
		listener = NULL;
	}

	pthread_rwlock_unlock(&knet_h->listener_rwlock);
	errno = savederrno;
	return err;
}
Ejemplo n.º 8
0
/*
 * mainloop is not thread safe as there should only be one
 */
int knet_vty_main_loop(int debug)
{
    int logfd[2];
    int vty_listener6_fd;
    int vty_listener4_fd;
    int vty_listener_fd;
    int vty_accept_fd;
    struct sockaddr_storage incoming_sa;
    socklen_t salen;
    fd_set rfds;
    int se_result = 0;
    struct timeval tv;
    int err = 0;
    int conn_index, found;

    signal(SIGTERM, sigterm_handler);
    signal(SIGINT, sigterm_handler);
    signal(SIGPIPE, sigpipe_handler);

    if (pipe(logfd)) {
        log_error("Unable to create logging pipe");
        return -1;
    }

    if ((_fdset_cloexec(logfd[0])) ||
            (_fdset_cloexec(logfd[1]))) {
        log_error("Unable to set FD_CLOEXEC on logfd pipe");
        return -1;
    }

    memset(&knet_vtys, 0, sizeof(knet_vtys));

    for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) {
        knet_vtys[conn_index].logfd = logfd[1];
        if (debug) {
            knet_vtys[conn_index].loglevel = KNET_LOG_DEBUG;
        } else {
            knet_vtys[conn_index].loglevel = KNET_LOG_INFO;
        }
    }

    if (knet_read_conf() < 0) {
        log_error("Unable to read config file %s", knet_cfg_head.conffile);
        return -1;
    }

    vty_listener6_fd = knet_vty_init_listener(knet_cfg_head.vty_ipv6,
                       knet_cfg_head.vty_port);
    if (vty_listener6_fd < 0) {
        log_error("Unable to setup vty listener for ipv6");
        return -1;
    }

    vty_listener4_fd = knet_vty_init_listener(knet_cfg_head.vty_ipv4,
                       knet_cfg_head.vty_port);

    if (vty_listener4_fd < 0) {
        log_error("Unable to setup vty listener for ipv4");
        goto out;
    }

    while (se_result >= 0 && !daemon_quit) {
        FD_ZERO (&rfds);
        FD_SET (vty_listener6_fd, &rfds);
        FD_SET (vty_listener4_fd, &rfds);
        FD_SET (logfd[0], &rfds);

        tv.tv_sec = 1;
        tv.tv_usec = 0;

        se_result = select(FD_SETSIZE, &rfds, 0, 0, &tv);

        if ((se_result == -1) && (daemon_quit)) {
            log_info("Got a SIGTERM, requesting CLI threads to exit");
            for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) {
                if (knet_vtys[conn_index].active) {
                    knet_vty_write(&knet_vtys[conn_index], "%s%sServer is going down..%s%s",
                                   telnet_newline, telnet_newline, telnet_newline, telnet_newline);
                    knet_vty_close(&knet_vtys[conn_index]);
                    knet_vtys[conn_index].got_epipe = 1;
                }
            }
            sleep(2); /* give time to all vty to exit */
            knet_close_down();
            log_info("Have a nice day! Goodbye");
            goto out;
        }

        if (se_result == -1) {
            err = se_result;
            log_error("Unable to select on vty listener socket!");
            goto out;
        }

        if (se_result == 0) {
            pthread_mutex_lock(&knet_vty_mutex);
            for(conn_index = 0; conn_index < KNET_VTY_TOTAL_MAX_CONN; conn_index++) {
                if ((knet_vtys[conn_index].active) &&
                        (!knet_vtys[conn_index].disable_idle)) {
                    knet_vtys[conn_index].idle++;
                    if (knet_vtys[conn_index].idle > KNET_VTY_CLI_TIMEOUT) {
                        knet_vty_close(&knet_vtys[conn_index]);
                        knet_vtys[conn_index].got_epipe = 1;
                    }
                }
            }
            pthread_mutex_unlock(&knet_vty_mutex);
            continue;
        }

        if (FD_ISSET(vty_listener6_fd, &rfds)) {
            vty_listener_fd = vty_listener6_fd;
        } else if (FD_ISSET(vty_listener4_fd, &rfds)) {
            vty_listener_fd = vty_listener4_fd;
        } else if (FD_ISSET(logfd[0], &rfds))  {
            struct knet_log_msg msg;
            size_t bytes_read = 0;
            size_t len;

            while (bytes_read < sizeof(struct knet_log_msg)) {
                len = read(logfd[0], &msg + bytes_read,
                           sizeof(struct knet_log_msg) - bytes_read);
                if (len <= 0) {
                    break;
                }
                bytes_read += len;
            }

            if (bytes_read != sizeof(struct knet_log_msg))
                continue;

            switch(msg.msglevel) {
            case KNET_LOG_WARN:
                log_warn("(%s) %s", knet_get_subsystem_name(msg.subsystem), msg.msg);
                break;
            case KNET_LOG_INFO:
                log_info("(%s) %s", knet_get_subsystem_name(msg.subsystem), msg.msg);
                break;
            case KNET_LOG_DEBUG:
                log_kdebug("(%s) %s", knet_get_subsystem_name(msg.subsystem), msg.msg);
                break;
            case KNET_LOG_ERR:
            default:
                log_error("(%s) %s", knet_get_subsystem_name(msg.subsystem), msg.msg);
            }
            continue;
        } else {
            continue;
        }

        memset(&incoming_sa, 0, sizeof(struct sockaddr_storage));
        salen = sizeof(struct sockaddr_storage);

        vty_accept_fd = accept(vty_listener_fd, (struct sockaddr *)&incoming_sa, &salen);
        if (vty_accept_fd < 0) {
            log_error("Unable to accept connection to vty");
            continue;
        }

        // check for ip address access list here against incoming_sa

        pthread_mutex_lock(&knet_vty_mutex);

        found = 0;
        for(conn_index = 0; conn_index <= vty_max_connections; conn_index++) {
            if (knet_vtys[conn_index].active == 0) {
                found = 1;
                break;
            }
        }

        if ((vty_current_connections == vty_max_connections) || (!found)) {
            errno = ECONNREFUSED;
            log_error("Too many connections to VTY or no available slots");
            close(vty_accept_fd);
            pthread_mutex_unlock(&knet_vty_mutex);
            continue;
        }

        vty_current_connections++;

        memset(&knet_vtys[conn_index], 0,
               sizeof(struct knet_vty));

        knet_vtys[conn_index].vty_sock = vty_accept_fd;
        knet_vtys[conn_index].conn_num = conn_index;
        memcpy(&knet_vtys[conn_index].src_sa, &incoming_sa, salen);
        knet_vtys[conn_index].src_sa_len = salen;
        knet_vtys[conn_index].active = 1;
        knet_vtys[conn_index].logfd = logfd[1];
        if (debug) {
            knet_vtys[conn_index].loglevel = KNET_LOG_DEBUG;
        } else {
            knet_vtys[conn_index].loglevel = KNET_LOG_INFO;
        }

        err = pthread_create(&knet_vtys[conn_index].vty_thread,
                             NULL, vty_accept_thread,
                             (void *)&conn_index);
        if (err < 0) {
            log_error("Unable to spawn vty thread");
            memset(&knet_vtys[conn_index], 0,
                   sizeof(struct knet_vty));
            vty_current_connections--;
        }

        pthread_mutex_unlock(&knet_vty_mutex);
    }

out:
    knet_vty_close_listener(vty_listener6_fd);
    knet_vty_close_listener(vty_listener4_fd);
    close(logfd[0]);
    close(logfd[1]);

    return err;
}