+ if (ret > 0)
+ return -EIO;
+ return ret;
+}
+
+/*
+ * chan_data is allocated internally if this function returns the
+ * expected var_len.
+ */
+ssize_t ustcomm_recv_channel_from_sessiond(int sock,
+ void **_chan_data, uint64_t var_len,
+ int *_wakeup_fd)
+{
+ void *chan_data;
+ ssize_t len, nr_fd;
+ int wakeup_fd, ret;
+
+ if (var_len > LTTNG_UST_ABI_CHANNEL_DATA_MAX_LEN) {
+ len = -EINVAL;
+ goto error_check;
+ }
+ /* Receive variable length data */
+ chan_data = zmalloc(var_len);
+ if (!chan_data) {
+ len = -ENOMEM;
+ goto error_alloc;
+ }
+ len = ustcomm_recv_unix_sock(sock, chan_data, var_len);
+ if (len != var_len) {
+ goto error_recv;
+ }
+ /* recv wakeup fd */
+ lttng_ust_lock_fd_tracker();
+ nr_fd = ustcomm_recv_fds_unix_sock(sock, &wakeup_fd, 1);
+ if (nr_fd <= 0) {
+ lttng_ust_unlock_fd_tracker();
+ if (nr_fd < 0) {
+ len = nr_fd;
+ goto error_recv;
+ } else {
+ len = -EIO;
+ goto error_recv;
+ }
+ }
+
+ ret = lttng_ust_add_fd_to_tracker(wakeup_fd);
+ if (ret < 0) {
+ ret = close(wakeup_fd);
+ if (ret) {
+ PERROR("close on wakeup_fd");
+ }
+ len = -EIO;
+ lttng_ust_unlock_fd_tracker();
+ goto error_recv;
+ }
+
+ *_wakeup_fd = ret;
+ lttng_ust_unlock_fd_tracker();
+
+ *_chan_data = chan_data;
+ return len;
+
+error_recv:
+ free(chan_data);
+error_alloc:
+error_check:
+ return len;
+}
+
+ssize_t ustcomm_recv_event_notifier_notif_fd_from_sessiond(int sock,
+ int *_event_notifier_notif_fd)
+{
+ ssize_t nr_fd;
+ int event_notifier_notif_fd, ret;
+
+ /* Receive event_notifier notification fd */
+ lttng_ust_lock_fd_tracker();
+ nr_fd = ustcomm_recv_fds_unix_sock(sock, &event_notifier_notif_fd, 1);
+ if (nr_fd <= 0) {
+ lttng_ust_unlock_fd_tracker();
+ if (nr_fd < 0) {
+ ret = nr_fd;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
+ }
+ }
+
+ ret = lttng_ust_add_fd_to_tracker(event_notifier_notif_fd);
+ if (ret < 0) {
+ ret = close(event_notifier_notif_fd);
+ if (ret) {
+ PERROR("close on event_notifier notif fd");
+ }
+ ret = -EIO;
+ lttng_ust_unlock_fd_tracker();
+ goto error;
+ }
+
+ *_event_notifier_notif_fd = ret;
+ lttng_ust_unlock_fd_tracker();
+
+ ret = nr_fd;
+
+error:
+ return ret;
+}
+
+int ustcomm_recv_stream_from_sessiond(int sock,
+ uint64_t *memory_map_size,
+ int *shm_fd, int *wakeup_fd)
+{
+ ssize_t len;
+ int ret;
+ int fds[2];
+
+ /* recv shm fd and wakeup fd */
+ lttng_ust_lock_fd_tracker();
+ len = ustcomm_recv_fds_unix_sock(sock, fds, 2);
+ if (len <= 0) {
+ lttng_ust_unlock_fd_tracker();
+ if (len < 0) {
+ ret = len;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
+ }
+ }
+
+ ret = lttng_ust_add_fd_to_tracker(fds[0]);
+ if (ret < 0) {
+ ret = close(fds[0]);
+ if (ret) {
+ PERROR("close on received shm_fd");
+ }
+ ret = -EIO;
+ lttng_ust_unlock_fd_tracker();
+ goto error;
+ }
+ *shm_fd = ret;
+
+ ret = lttng_ust_add_fd_to_tracker(fds[1]);
+ if (ret < 0) {
+ ret = close(*shm_fd);
+ if (ret) {
+ PERROR("close on shm_fd");
+ }
+ *shm_fd = -1;
+ ret = close(fds[1]);
+ if (ret) {
+ PERROR("close on received wakeup_fd");
+ }
+ ret = -EIO;
+ lttng_ust_unlock_fd_tracker();
+ goto error;
+ }
+ *wakeup_fd = ret;
+ lttng_ust_unlock_fd_tracker();
+ return 0;
+
+error:
+ return ret;
+}
+
+ssize_t ustcomm_recv_counter_from_sessiond(int sock,
+ void **_counter_data, uint64_t var_len)
+{
+ void *counter_data;
+ ssize_t len;
+
+ if (var_len > LTTNG_UST_ABI_COUNTER_DATA_MAX_LEN) {
+ len = -EINVAL;
+ goto error_check;
+ }
+ /* Receive variable length data */
+ counter_data = zmalloc(var_len);
+ if (!counter_data) {
+ len = -ENOMEM;
+ goto error_alloc;
+ }
+ len = ustcomm_recv_unix_sock(sock, counter_data, var_len);
+ if (len != var_len) {
+ goto error_recv;
+ }
+ *_counter_data = counter_data;
+ return len;
+
+error_recv:
+ free(counter_data);
+error_alloc:
+error_check:
+ return len;
+}
+
+int ustcomm_recv_counter_shm_from_sessiond(int sock,
+ int *shm_fd)
+{
+ ssize_t len;
+ int ret;
+ int fds[1];
+
+ /* recv shm fd fd */
+ lttng_ust_lock_fd_tracker();
+ len = ustcomm_recv_fds_unix_sock(sock, fds, 1);
+ if (len <= 0) {
+ lttng_ust_unlock_fd_tracker();
+ if (len < 0) {
+ ret = len;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
+ }
+ }
+
+ ret = lttng_ust_add_fd_to_tracker(fds[0]);
+ if (ret < 0) {
+ ret = close(fds[0]);
+ if (ret) {
+ PERROR("close on received shm_fd");
+ }
+ ret = -EIO;
+ lttng_ust_unlock_fd_tracker();
+ goto error;
+ }
+ *shm_fd = ret;
+ lttng_ust_unlock_fd_tracker();
+ return 0;
+
+error:
+ return ret;
+}
+
+/*
+ * Returns 0 on success, negative error value on error.
+ */
+int ustcomm_send_reg_msg(int sock,
+ enum ustctl_socket_type type,
+ uint32_t bits_per_long,
+ uint32_t uint8_t_alignment,
+ uint32_t uint16_t_alignment,
+ uint32_t uint32_t_alignment,
+ uint32_t uint64_t_alignment,
+ uint32_t long_alignment)
+{
+ ssize_t len;
+ struct ustctl_reg_msg reg_msg;
+
+ reg_msg.magic = LTTNG_UST_ABI_COMM_MAGIC;
+ reg_msg.major = LTTNG_UST_ABI_MAJOR_VERSION;
+ reg_msg.minor = LTTNG_UST_ABI_MINOR_VERSION;
+ reg_msg.pid = getpid();
+ reg_msg.ppid = getppid();
+ reg_msg.uid = getuid();
+ reg_msg.gid = getgid();
+ reg_msg.bits_per_long = bits_per_long;
+ reg_msg.uint8_t_alignment = uint8_t_alignment;
+ reg_msg.uint16_t_alignment = uint16_t_alignment;
+ reg_msg.uint32_t_alignment = uint32_t_alignment;
+ reg_msg.uint64_t_alignment = uint64_t_alignment;
+ reg_msg.long_alignment = long_alignment;
+ reg_msg.socket_type = type;
+ lttng_pthread_getname_np(reg_msg.name, LTTNG_UST_ABI_PROCNAME_LEN);
+ memset(reg_msg.padding, 0, sizeof(reg_msg.padding));
+
+ len = ustcomm_send_unix_sock(sock, ®_msg, sizeof(reg_msg));
+ if (len > 0 && len != sizeof(reg_msg))
+ return -EIO;
+ if (len < 0)
+ return len;
+ return 0;
+}
+
+static
+ssize_t count_one_type(struct lttng_ust_type_common *lt)
+{
+ switch (lt->type) {
+ case lttng_ust_type_integer:
+ case lttng_ust_type_float:
+ case lttng_ust_type_string:
+ return 1;
+ case lttng_ust_type_enum:
+ return count_one_type(lttng_ust_get_type_enum(lt)->container_type) + 1;
+ case lttng_ust_type_array:
+ return count_one_type(lttng_ust_get_type_array(lt)->elem_type) + 1;
+ case lttng_ust_type_sequence:
+ return count_one_type(lttng_ust_get_type_sequence(lt)->elem_type) + 1;
+ case lttng_ust_type_struct:
+ return count_fields_recursive(lttng_ust_get_type_struct(lt)->nr_fields,
+ lttng_ust_get_type_struct(lt)->fields) + 1;
+
+ case lttng_ust_type_dynamic:
+ {
+ struct lttng_ust_event_field **choices;
+ size_t nr_choices;
+ int ret;
+
+ ret = lttng_ust_dynamic_type_choices(&nr_choices,
+ &choices);
+ if (ret)
+ return ret;
+ /*
+ * Two fields for enum, one field for variant, and
+ * one field per choice.
+ */
+ return count_fields_recursive(nr_choices, choices) + 3;
+ }
+
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+ssize_t count_fields_recursive(size_t nr_fields,
+ struct lttng_ust_event_field **lttng_fields)
+{
+ int i;
+ ssize_t ret, count = 0;
+
+ for (i = 0; i < nr_fields; i++) {
+ const struct lttng_ust_event_field *lf;
+
+ lf = lttng_fields[i];
+ /* skip 'nowrite' fields */
+ if (lf->nowrite)
+ continue;
+ ret = count_one_type(lf->type);
+ if (ret < 0)
+ return ret; /* error */
+ count += ret;
+ }
+ return count;
+}
+
+static
+ssize_t count_ctx_fields_recursive(size_t nr_fields,
+ struct lttng_ust_ctx_field **lttng_fields)
+{
+ int i;
+ ssize_t ret, count = 0;
+
+ for (i = 0; i < nr_fields; i++) {
+ const struct lttng_ust_event_field *lf;
+
+ lf = lttng_fields[i]->event_field;
+ /* skip 'nowrite' fields */
+ if (lf->nowrite)
+ continue;
+ ret = count_one_type(lf->type);
+ if (ret < 0)
+ return ret; /* error */
+ count += ret;
+ }
+ return count;
+}
+
+static
+int serialize_string_encoding(int32_t *ue,
+ enum lttng_ust_string_encoding le)
+{
+ switch (le) {
+ case lttng_ust_string_encoding_none:
+ *ue = ustctl_encode_none;
+ break;
+ case lttng_ust_string_encoding_UTF8:
+ *ue = ustctl_encode_UTF8;
+ break;
+ case lttng_ust_string_encoding_ASCII:
+ *ue = ustctl_encode_ASCII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+int serialize_integer_type(struct ustctl_integer_type *uit,
+ const struct lttng_ust_type_integer *lit,
+ enum lttng_ust_string_encoding lencoding)
+{
+ int32_t encoding;
+
+ uit->size = lit->size;
+ uit->signedness = lit->signedness;
+ uit->reverse_byte_order = lit->reverse_byte_order;
+ uit->base = lit->base;
+ if (serialize_string_encoding(&encoding, lencoding))
+ return -EINVAL;
+ uit->encoding = encoding;
+ uit->alignment = lit->alignment;
+ return 0;
+}
+
+static
+int serialize_dynamic_type(struct lttng_ust_session *session,
+ struct ustctl_field *fields, size_t *iter_output,
+ const char *field_name)
+{
+ struct lttng_ust_event_field **choices;
+ char tag_field_name[LTTNG_UST_ABI_SYM_NAME_LEN];
+ struct lttng_ust_type_common *tag_type;
+ struct lttng_ust_event_field *tag_field_generic;
+ struct lttng_ust_event_field tag_field = {
+ .name = tag_field_name,
+ .nowrite = 0,
+ };
+ struct ustctl_field *uf;
+ size_t nr_choices, i;
+ int ret;
+
+ tag_field_generic = lttng_ust_dynamic_type_tag_field();
+ tag_type = tag_field_generic->type;
+
+ /* Serialize enum field. */
+ strncpy(tag_field_name, field_name, LTTNG_UST_ABI_SYM_NAME_LEN);
+ tag_field_name[LTTNG_UST_ABI_SYM_NAME_LEN - 1] = '\0';
+ strncat(tag_field_name,
+ "_tag",
+ LTTNG_UST_ABI_SYM_NAME_LEN - strlen(tag_field_name) - 1);
+ tag_field.type = tag_type;
+ ret = serialize_one_field(session, fields, iter_output,
+ &tag_field);
+ if (ret)
+ return ret;
+
+ /* Serialize variant field. */
+ uf = &fields[*iter_output];
+ ret = lttng_ust_dynamic_type_choices(&nr_choices, &choices);