+ if (errno == EINTR) {
+ goto retry;
+ } else {
+ /* We consider EPIPE and EAGAIN as expected. */
+ if (!lttng_opt_quiet &&
+ (errno != EPIPE && errno != EAGAIN)) {
+ PERROR("recvmsg");
+ }
+ goto end;
+ }
+ }
+
+ if (ret != 1) {
+ fprintf(stderr, "Error: Received %zd bytes, expected %d\n",
+ ret, 1);
+ goto end;
+ }
+
+ if (msg.msg_flags & MSG_CTRUNC) {
+ fprintf(stderr, "Error: Control message truncated.\n");
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * If the socket was configured with SO_PASSCRED, the kernel will add a
+ * control message (cmsg) to the ancillary data of the unix socket. We
+ * need to expect a cmsg of the SCM_CREDENTIALS as the first control
+ * message.
+ */
+ for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if (cmsg->cmsg_level != SOL_SOCKET) {
+ fprintf(stderr, "Error: The socket needs to be of type SOL_SOCKET\n");
+ ret = -1;
+ goto end;
+ }
+ if (cmsg->cmsg_type == SCM_RIGHTS) {
+ /*
+ * We found the controle message for file descriptors,
+ * now copy the fds to the fds ptr and return success.
+ */
+ if (cmsg->cmsg_len != CMSG_LEN(sizeof_fds)) {
+ fprintf(stderr, "Error: Received %zu bytes of"
+ "ancillary data for FDs, expected %zu\n",
+ (size_t) cmsg->cmsg_len,
+ (size_t) CMSG_LEN(sizeof_fds));
+ ret = -1;
+ goto end;
+ }
+ memcpy(fds, CMSG_DATA(cmsg), sizeof_fds);
+ ret = sizeof_fds;
+ goto end;
+ }
+#ifdef __linux__
+ if (cmsg->cmsg_type == SCM_CREDENTIALS) {
+ /*
+ * Expect credentials to be sent when expecting fds even
+ * if no credential were include in the send(). The
+ * kernel adds them...
+ */
+ ret = -1;
+ }
+#endif /* __linux__ */
+ }
+end:
+ return ret;
+}
+
+static
+void close_raw_fd(void *ptr)
+{
+ const int raw_fd = *((const int *) ptr);
+
+ if (raw_fd >= 0) {
+ const int ret = close(raw_fd);
+
+ if (ret) {
+ PERROR("Failed to close file descriptor %d", raw_fd);
+ }
+ }
+}
+
+static
+enum lttng_error_code add_fds_to_payload(struct lttng_dynamic_array *raw_fds,
+ struct lttng_payload *payload)
+{
+ int i;
+ enum lttng_error_code ret_code = LTTNG_OK;
+ const int fd_count = lttng_dynamic_array_get_count(raw_fds);
+
+ for (i = 0; i < fd_count; i++) {
+ int ret;
+ struct fd_handle *handle;
+ int *raw_fd = (int *) lttng_dynamic_array_get_element(
+ raw_fds, i);
+
+ LTTNG_ASSERT(*raw_fd != -1);
+
+ handle = fd_handle_create(*raw_fd);
+ if (!handle) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ /* FD ownership transferred to the handle. */
+ *raw_fd = -1;
+
+ ret = lttng_payload_push_fd_handle(payload, handle);
+ fd_handle_put(handle);
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+ }
+
+end:
+ return ret_code;
+}
+
+static
+ssize_t _lttcomm_recv_payload_fds_unix_sock(int sock, size_t nb_fd,
+ struct lttng_payload *payload, bool blocking)
+{
+ int i = 0;
+ enum lttng_error_code add_ret;
+ ssize_t ret;
+ int default_value = -1;
+ struct lttng_dynamic_array raw_fds;
+
+ LTTNG_ASSERT(sock);
+ LTTNG_ASSERT(payload);
+ LTTNG_ASSERT(nb_fd > 0);
+
+ lttng_dynamic_array_init(&raw_fds, sizeof(int), close_raw_fd);
+
+ for (i = 0; i < nb_fd; i++) {
+ if (lttng_dynamic_array_add_element(&raw_fds, &default_value)) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end;
+ }
+ }
+
+ if (blocking) {
+ ret = lttcomm_recv_fds_unix_sock(
+ sock, (int *) raw_fds.buffer.data, nb_fd);
+ } else {
+ ret = lttcomm_recv_fds_unix_sock_non_block(
+ sock, (int *) raw_fds.buffer.data, nb_fd);
+ }
+
+ if (ret <= 0) {
+ goto end;
+ }
+
+ add_ret = add_fds_to_payload(&raw_fds, payload);
+ if (add_ret != LTTNG_OK) {
+ ret = - (int) add_ret;