Example #1
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;
}
Example #2
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;
}
Example #3
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;
}
Example #4
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;
}