+ 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;
+
+ if (var_len > LTTNG_UST_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 */
+ nr_fd = ustcomm_recv_fds_unix_sock(sock, &wakeup_fd, 1);
+ if (nr_fd <= 0) {
+ if (nr_fd < 0) {
+ len = nr_fd;
+ goto error_recv;
+ } else {
+ len = -EIO;
+ goto error_recv;
+ }
+ }
+ *_wakeup_fd = wakeup_fd;
+ *_chan_data = chan_data;
+ return len;
+
+error_recv:
+ free(chan_data);
+error_alloc:
+error_check:
+ return len;
+}
+
+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 */
+ len = ustcomm_recv_fds_unix_sock(sock, fds, 2);
+ if (len <= 0) {
+ if (len < 0) {
+ ret = len;
+ goto error;
+ } else {
+ ret = -EIO;
+ goto error;
+ }
+ }
+ *shm_fd = fds[0];
+ *wakeup_fd = fds[1];
+ 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_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_ust_getprocname(reg_msg.name);
+ 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(const struct lttng_type *lt)
+{
+ switch (lt->atype) {
+ case atype_integer:
+ case atype_float:
+ case atype_string:
+ case atype_enum:
+ case atype_array:
+ case atype_sequence:
+ return 1;
+ case atype_struct:
+ //TODO: implement non-empty struct.
+ return 1;
+ case atype_dynamic:
+ {
+ const struct lttng_event_field *choices;
+ size_t nr_choices;
+ int ret;
+
+ ret = lttng_ust_dynamic_type_choices(&nr_choices,
+ &choices);
+ if (ret)
+ return ret;
+ /*
+ * One field for enum, one field for variant, and
+ * one field per choice.
+ */
+ return count_fields_recursive(nr_choices, choices) + 2;
+ }
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+ssize_t count_fields_recursive(size_t nr_fields,
+ const struct lttng_event_field *lttng_fields)
+{
+ int i;
+ ssize_t ret, count = 0;
+
+ for (i = 0; i < nr_fields; i++) {
+ const struct lttng_event_field *lf;
+
+ lf = <tng_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,
+ const struct lttng_ctx_field *lttng_fields)
+{
+ int i;
+ ssize_t ret, count = 0;
+
+ for (i = 0; i < nr_fields; i++) {
+ const struct lttng_event_field *lf;
+
+ lf = <tng_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_string_encodings le)
+{
+ switch (le) {
+ case lttng_encode_none:
+ *ue = ustctl_encode_none;
+ break;
+ case lttng_encode_UTF8:
+ *ue = ustctl_encode_UTF8;
+ break;
+ case lttng_encode_ASCII:
+ *ue = ustctl_encode_ASCII;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+int serialize_integer_type(struct ustctl_integer_type *uit,
+ const struct lttng_integer_type *lit)
+{
+ uit->size = lit->size;
+ uit->signedness = lit->signedness;
+ uit->reverse_byte_order = lit->reverse_byte_order;
+ uit->base = lit->base;
+ if (serialize_string_encoding(&uit->encoding, lit->encoding))
+ return -EINVAL;
+ uit->alignment = lit->alignment;
+ return 0;
+}
+
+static
+int serialize_basic_type(struct lttng_session *session,
+ enum ustctl_abstract_types *uatype,
+ enum lttng_abstract_types atype,
+ union _ustctl_basic_type *ubt,
+ const union _lttng_basic_type *lbt)
+{
+ switch (atype) {
+ case atype_integer:
+ {
+ if (serialize_integer_type(&ubt->integer, &lbt->integer))
+ return -EINVAL;
+ *uatype = ustctl_atype_integer;
+ break;
+ }
+ case atype_string:
+ {
+ if (serialize_string_encoding(&ubt->string.encoding,
+ lbt->string.encoding))
+ return -EINVAL;
+ *uatype = ustctl_atype_string;
+ break;
+ }
+ case atype_float:
+ {
+ struct ustctl_float_type *uft;
+ const struct lttng_float_type *lft;
+
+ uft = &ubt->_float;
+ lft = &lbt->_float;
+ uft->exp_dig = lft->exp_dig;
+ uft->mant_dig = lft->mant_dig;
+ uft->alignment = lft->alignment;
+ uft->reverse_byte_order = lft->reverse_byte_order;
+ *uatype = ustctl_atype_float;
+ break;
+ }
+ case atype_enum:
+ {
+ strncpy(ubt->enumeration.name, lbt->enumeration.desc->name,
+ LTTNG_UST_SYM_NAME_LEN);
+ ubt->enumeration.name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+ if (serialize_integer_type(&ubt->enumeration.container_type,
+ &lbt->enumeration.container_type))
+ return -EINVAL;
+ if (session) {
+ const struct lttng_enum *_enum;
+
+ _enum = lttng_ust_enum_get(session,
+ lbt->enumeration.desc->name);
+ if (!_enum)
+ return -EINVAL;
+ ubt->enumeration.id = _enum->id;
+ } else {
+ ubt->enumeration.id = -1ULL;
+ }
+ *uatype = ustctl_atype_enum;
+ break;
+ }
+ case atype_array:
+ case atype_sequence:
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static
+int serialize_dynamic_type(struct lttng_session *session,
+ struct ustctl_field *fields, size_t *iter_output,
+ const struct lttng_event_field *lf)
+{
+ const struct lttng_event_field *choices;
+ char tag_field_name[LTTNG_UST_SYM_NAME_LEN];
+ const struct lttng_type *tag_type;
+ const struct lttng_event_field *tag_field_generic;
+ struct lttng_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, lf->name, LTTNG_UST_SYM_NAME_LEN);
+ tag_field_name[LTTNG_UST_SYM_NAME_LEN - 1] = '\0';
+ strncat(tag_field_name,
+ "_tag",
+ LTTNG_UST_SYM_NAME_LEN - strlen(tag_field_name) - 1);
+ tag_field.type = *tag_type;
+ ret = serialize_one_field(session, fields, iter_output,
+ &tag_field);