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; }
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; }
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; }
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; }
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; }
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; }
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; }
/* * 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; }