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