Fix: liblttng-ctl comm: lttng_channel is not packed
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Wed, 12 Jan 2022 23:18:08 +0000 (18:18 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 28 Feb 2022 21:46:10 +0000 (16:46 -0500)
Observed issue
==============

The size of the struct differs between bitness for x86-64 and x86
leading to serialization/deserialization problem across client
(liblttng-ctl) and lttng-sessiond.

sizeof(struct lttng_channel):

  x86: 608
  x86-64: 624

The struct cannot be marked as LTTNG_PACKED since it is part of the API.

Solution
========

Adopt a similar pattern to the new API with a "serialize" &
"create_from_buffer" approach. The only particularity is that we need to
flatten the channels on listing.

Most of the complexity is moved to `src/common/channel.c`

Known drawbacks
=========

None.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Change-Id: Id5c9aaf3cf8b3d739b71263c02cae8d4d2fedfe3

include/lttng/channel-internal.h
src/bin/lttng-sessiond/channel.cpp
src/bin/lttng-sessiond/channel.h
src/bin/lttng-sessiond/client.cpp
src/bin/lttng-sessiond/cmd.cpp
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/trace-ust.h
src/common/Makefile.am
src/common/channel.cpp [new file with mode: 0644]
src/common/sessiond-comm/sessiond-comm.h
src/lib/lttng-ctl/lttng-ctl.cpp

index 04b19322f96ea35f1340b6e5d6f74ac569ca3246..c3e1230635558fad9df00c711b7f6d7c5b957616 100644 (file)
@@ -9,6 +9,11 @@
 #define LTTNG_CHANNEL_INTERNAL_H
 
 #include <common/macros.h>
+#include <lttng/channel.h>
+#include <lttng/lttng-error.h>
+
+struct lttng_dynamic_buffer;
+struct lttng_buffer_view;
 
 struct lttng_channel_extended {
        uint64_t discarded_events;
@@ -17,4 +22,45 @@ struct lttng_channel_extended {
        int64_t blocking_timeout;
 } LTTNG_PACKED;
 
+struct lttng_channel_comm {
+       /* Includes terminator `\0`. */
+       uint32_t name_len;
+       uint8_t enabled;
+
+       /* attr */
+       int8_t overwrite;
+       uint64_t subbuf_size;
+       uint64_t num_subbuf;
+       uint32_t switch_timer_interval;
+       uint32_t read_timer_interval;
+       uint8_t output;
+       uint64_t tracefile_size;
+       uint64_t tracefile_count;
+       uint32_t live_timer_interval;
+
+       /* Extended struct */
+       uint64_t discarded_events;
+       uint64_t lost_packets;
+       uint64_t monitor_timer_interval;
+       int64_t blocking_timeout;
+} LTTNG_PACKED;
+
+struct lttng_channel *lttng_channel_create_internal(void);
+
+struct lttng_channel *lttng_channel_copy(const struct lttng_channel *src);
+
+ssize_t lttng_channel_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_channel **event);
+
+int lttng_channel_serialize(struct lttng_channel *channel,
+               struct lttng_dynamic_buffer *buf);
+
+void lttng_channel_set_default_extended_attr(struct lttng_domain *domain,
+               struct lttng_channel_extended *extended_attr);
+
+enum lttng_error_code lttng_channels_create_and_flatten_from_buffer(
+               const struct lttng_buffer_view *view,
+               unsigned int count,
+               struct lttng_channel **channels);
+
 #endif /* LTTNG_CHANNEL_INTERNAL_H */
index bfa6d4b499019a16cb939011027b3c03295b002d..9ad71ca16f38169a950e73fdf6916d923ee58a1d 100644 (file)
@@ -549,3 +549,57 @@ end:
 error:
        return ret;
 }
+
+struct lttng_channel *trace_ust_channel_to_lttng_channel(
+               const struct ltt_ust_channel *uchan)
+{
+       struct lttng_channel *channel = NULL, *ret = NULL;
+
+       channel = lttng_channel_create_internal();
+       if (!channel) {
+               ERR("Failed to create lttng_channel during conversion from ltt_ust_channel to lttng_channel");
+               goto end;
+       }
+
+       if (lttng_strncpy(channel->name, uchan->name, LTTNG_SYMBOL_NAME_LEN)) {
+               ERR("Failed to set channel name during conversion from ltt_ust_channel to lttng_channel");
+               goto end;
+       }
+
+       channel->attr.overwrite = uchan->attr.overwrite;
+       channel->attr.subbuf_size = uchan->attr.subbuf_size;
+       channel->attr.num_subbuf = uchan->attr.num_subbuf;
+       channel->attr.switch_timer_interval = uchan->attr.switch_timer_interval;
+       channel->attr.read_timer_interval = uchan->attr.read_timer_interval;
+       channel->enabled = uchan->enabled;
+       channel->attr.tracefile_size = uchan->tracefile_size;
+       channel->attr.tracefile_count = uchan->tracefile_count;
+
+       /*
+        * Map enum lttng_ust_output to enum lttng_event_output.
+        */
+       switch (uchan->attr.output) {
+       case LTTNG_UST_ABI_MMAP:
+               channel->attr.output = LTTNG_EVENT_MMAP;
+               break;
+       default:
+               /*
+                * LTTNG_UST_MMAP is the only supported UST
+                * output mode.
+                */
+               abort();
+               break;
+       }
+
+       lttng_channel_set_blocking_timeout(
+                       channel, uchan->attr.u.s.blocking_timeout);
+       lttng_channel_set_monitor_timer_interval(
+                       channel, uchan->monitor_timer_interval);
+
+       ret = channel;
+       channel = NULL;
+
+end:
+       lttng_channel_destroy(channel);
+       return ret;
+}
index b4ff9f4fda0a2387c1b2dcde6c4f74b99977bbab..1b6e29bd758a77b0087de202cfa06f45cb7c861c 100644 (file)
@@ -31,4 +31,7 @@ int channel_ust_enable(struct ltt_ust_session *usess,
 int channel_ust_disable(struct ltt_ust_session *usess,
                struct ltt_ust_channel *uchan);
 
+struct lttng_channel *trace_ust_channel_to_lttng_channel(
+               const struct ltt_ust_channel *uchan);
+
 #endif /* _LTT_CHANNEL_H */
index 7f3c81782d50c3ed7e9812aacbcaed41dbcaf3ef..46f524896ed2dd82e1a1ced94cff9092b937a8c2 100644 (file)
@@ -29,6 +29,7 @@
 #include <pthread.h>
 #include <signal.h>
 #include <stddef.h>
+#include <stdint.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -1432,14 +1433,8 @@ error_add_context:
        }
        case LTTNG_ENABLE_CHANNEL:
        {
-               cmd_ctx->lsm.u.channel.chan.attr.extended.ptr =
-                               (struct lttng_channel_extended *) &cmd_ctx->lsm.u.channel.extended;
-               lttng_domain domain = cmd_ctx->lsm.domain;
-               lttng_channel chan = cmd_ctx->lsm.u.channel.chan;
-               ret = cmd_enable_channel(cmd_ctx->session,
-                               &domain,
-                               &chan,
-                               the_kernel_poll_pipe[1]);
+               ret = cmd_enable_channel(
+                               cmd_ctx, *sock, the_kernel_poll_pipe[1]);
                break;
        }
        case LTTNG_PROCESS_ATTR_TRACKER_ADD_INCLUDE_VALUE:
@@ -1962,25 +1957,30 @@ error_add_context:
        }
        case LTTNG_LIST_CHANNELS:
        {
-               ssize_t payload_size;
-               struct lttng_channel *channels = NULL;
+               enum lttng_error_code ret_code;
+               size_t original_payload_size;
+               size_t payload_size;
+               const size_t command_header_size = sizeof(struct lttcomm_list_command_header);
 
-               payload_size = cmd_list_channels(cmd_ctx->lsm.domain.type,
-                               cmd_ctx->session, &channels);
-               if (payload_size < 0) {
-                       /* Return value is a negative lttng_error_code. */
-                       ret = -payload_size;
-                       goto error;
+               ret = setup_empty_lttng_msg(cmd_ctx);
+               if (ret) {
+                       ret = LTTNG_ERR_NOMEM;
+                       goto setup_error;
                }
 
-               ret = setup_lttng_msg_no_cmd_header(cmd_ctx, channels,
-                       payload_size);
-               free(channels);
+               original_payload_size = cmd_ctx->reply_payload.buffer.size;
 
-               if (ret < 0) {
-                       goto setup_error;
+               ret_code = cmd_list_channels(cmd_ctx->lsm.domain.type,
+                               cmd_ctx->session, &cmd_ctx->reply_payload);
+               if (ret_code != LTTNG_OK) {
+                       ret = (int) ret_code;
+                       goto error;
                }
 
+               payload_size = cmd_ctx->reply_payload.buffer.size -
+                               command_header_size - original_payload_size;
+               update_lttng_msg(cmd_ctx, command_header_size, payload_size);
+
                ret = LTTNG_OK;
                break;
        }
index b4bd6b43fca8826850a83d4f0fd6b0ec4579b735..5bfa64530ec53262b1b6d0f4bcd80cd57d814a33 100644 (file)
@@ -121,6 +121,10 @@ static int cmd_enable_event_internal(struct ltt_session *session,
                struct lttng_bytecode *filter,
                struct lttng_event_exclusion *exclusion,
                int wpipe);
+static int cmd_enable_channel_internal(struct ltt_session *session,
+               const struct lttng_domain *domain,
+               const struct lttng_channel *_attr,
+               int wpipe);
 
 /*
  * Create a session path used by list_lttng_sessions for the case that the
@@ -291,118 +295,6 @@ end:
        return ret;
 }
 
-/*
- * Fill lttng_channel array of all channels.
- */
-static ssize_t list_lttng_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel *channels,
-               struct lttng_channel_extended *chan_exts)
-{
-       int i = 0, ret = 0;
-       struct ltt_kernel_channel *kchan;
-
-       DBG("Listing channels for session %s", session->name);
-
-       switch (domain) {
-       case LTTNG_DOMAIN_KERNEL:
-               /* Kernel channels */
-               if (session->kernel_session != NULL) {
-                       cds_list_for_each_entry(kchan,
-                                       &session->kernel_session->channel_list.head, list) {
-                               uint64_t discarded_events, lost_packets;
-                               struct lttng_channel_extended *extended;
-
-                               extended = (struct lttng_channel_extended *)
-                                               kchan->channel->attr.extended.ptr;
-
-                               ret = get_kernel_runtime_stats(session, kchan,
-                                               &discarded_events, &lost_packets);
-                               if (ret < 0) {
-                                       goto end;
-                               }
-                               /* Copy lttng_channel struct to array */
-                               memcpy(&channels[i], kchan->channel, sizeof(struct lttng_channel));
-                               channels[i].enabled = kchan->enabled;
-                               chan_exts[i].discarded_events =
-                                               discarded_events;
-                               chan_exts[i].lost_packets = lost_packets;
-                               chan_exts[i].monitor_timer_interval =
-                                               extended->monitor_timer_interval;
-                               chan_exts[i].blocking_timeout = 0;
-                               i++;
-                       }
-               }
-               break;
-       case LTTNG_DOMAIN_UST:
-       {
-               struct lttng_ht_iter iter;
-               struct ltt_ust_channel *uchan;
-
-               rcu_read_lock();
-               cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht,
-                               &iter.iter, uchan, node.node) {
-                       uint64_t discarded_events = 0, lost_packets = 0;
-
-                       if (lttng_strncpy(channels[i].name, uchan->name,
-                                       LTTNG_SYMBOL_NAME_LEN)) {
-                               break;
-                       }
-                       channels[i].attr.overwrite = uchan->attr.overwrite;
-                       channels[i].attr.subbuf_size = uchan->attr.subbuf_size;
-                       channels[i].attr.num_subbuf = uchan->attr.num_subbuf;
-                       channels[i].attr.switch_timer_interval =
-                               uchan->attr.switch_timer_interval;
-                       channels[i].attr.read_timer_interval =
-                               uchan->attr.read_timer_interval;
-                       channels[i].enabled = uchan->enabled;
-                       channels[i].attr.tracefile_size = uchan->tracefile_size;
-                       channels[i].attr.tracefile_count = uchan->tracefile_count;
-
-                       /*
-                        * Map enum lttng_ust_output to enum lttng_event_output.
-                        */
-                       switch (uchan->attr.output) {
-                       case LTTNG_UST_ABI_MMAP:
-                               channels[i].attr.output = LTTNG_EVENT_MMAP;
-                               break;
-                       default:
-                               /*
-                                * LTTNG_UST_MMAP is the only supported UST
-                                * output mode.
-                                */
-                               abort();
-                               break;
-                       }
-
-                       chan_exts[i].monitor_timer_interval =
-                                       uchan->monitor_timer_interval;
-                       chan_exts[i].blocking_timeout =
-                               uchan->attr.u.s.blocking_timeout;
-
-                       ret = get_ust_runtime_stats(session, uchan,
-                                       &discarded_events, &lost_packets);
-                       if (ret < 0) {
-                               break;
-                       }
-                       chan_exts[i].discarded_events = discarded_events;
-                       chan_exts[i].lost_packets = lost_packets;
-                       i++;
-               }
-               rcu_read_unlock();
-               break;
-       }
-       default:
-               break;
-       }
-
-end:
-       if (ret < 0) {
-               return -LTTNG_ERR_FATAL;
-       } else {
-               return LTTNG_OK;
-       }
-}
-
 static int append_extended_info(const char *filter_expression,
                struct lttng_event_exclusion *exclusion,
                struct lttng_userspace_probe_location *probe_location,
@@ -1360,30 +1252,84 @@ error:
  *
  * The wpipe arguments is used as a notifier for the kernel thread.
  */
-int cmd_enable_channel(struct ltt_session *session,
-               const struct lttng_domain *domain, const struct lttng_channel *_attr, int wpipe)
+int cmd_enable_channel(struct command_ctx *cmd_ctx, int sock, int wpipe)
+{
+       int ret;
+       size_t channel_len;
+       ssize_t sock_recv_len;
+       struct lttng_channel *channel = NULL;
+       struct lttng_buffer_view view;
+       struct lttng_dynamic_buffer channel_buffer;
+       const struct lttng_domain command_domain = cmd_ctx->lsm.domain;
+
+       lttng_dynamic_buffer_init(&channel_buffer);
+       channel_len = (size_t) cmd_ctx->lsm.u.channel.length;
+       ret = lttng_dynamic_buffer_set_size(&channel_buffer, channel_len);
+       if (ret) {
+               ret = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       sock_recv_len = lttcomm_recv_unix_sock(sock, channel_buffer.data,
+                       channel_len);
+       if (sock_recv_len < 0 || sock_recv_len != channel_len) {
+               ERR("Failed to receive \"enable channel\" command payload");
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       view = lttng_buffer_view_from_dynamic_buffer(&channel_buffer, 0, channel_len);
+       if (!lttng_buffer_view_is_valid(&view)) {
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       if (lttng_channel_create_from_buffer(&view, &channel) != channel_len) {
+               ERR("Invalid channel payload received in \"enable channel\" command");
+               ret = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret = cmd_enable_channel_internal(
+                       cmd_ctx->session, &command_domain, channel, wpipe);
+
+end:
+       lttng_dynamic_buffer_reset(&channel_buffer);
+       lttng_channel_destroy(channel);
+       return ret;
+}
+
+static int cmd_enable_channel_internal(struct ltt_session *session,
+               const struct lttng_domain *domain,
+               const struct lttng_channel *_attr,
+               int wpipe)
 {
        int ret;
        struct ltt_ust_session *usess = session->ust_session;
        struct lttng_ht *chan_ht;
        size_t len;
-       struct lttng_channel attr;
+       struct lttng_channel *attr = NULL;
 
        LTTNG_ASSERT(session);
        LTTNG_ASSERT(_attr);
        LTTNG_ASSERT(domain);
 
-       attr = *_attr;
-       len = lttng_strnlen(attr.name, sizeof(attr.name));
+       attr = lttng_channel_copy(_attr);
+       if (!attr) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       len = lttng_strnlen(attr->name, sizeof(attr->name));
 
        /* Validate channel name */
-       if (attr.name[0] == '.' ||
-               memchr(attr.name, '/', len) != NULL) {
+       if (attr->name[0] == '.' ||
+               memchr(attr->name, '/', len) != NULL) {
                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                goto end;
        }
 
-       DBG("Enabling channel %s for session %s", attr.name, session->name);
+       DBG("Enabling channel %s for session %s", attr->name, session->name);
 
        rcu_read_lock();
 
@@ -1393,8 +1339,8 @@ int cmd_enable_channel(struct ltt_session *session,
         * beacons for inactive streams.
         */
        if (session->live_timer > 0) {
-               attr.attr.live_timer_interval = session->live_timer;
-               attr.attr.switch_timer_interval = 0;
+               attr->attr.live_timer_interval = session->live_timer;
+               attr->attr.switch_timer_interval = 0;
        }
 
        /* Check for feature support */
@@ -1406,8 +1352,8 @@ int cmd_enable_channel(struct ltt_session *session,
                        WARN("Kernel tracer does not support buffer monitoring. "
                                        "Setting the monitor interval timer to 0 "
                                        "(disabled) for channel '%s' of session '%s'",
-                                       attr.name, session->name);
-                       lttng_channel_set_monitor_timer_interval(&attr, 0);
+                                       attr->name, session->name);
+                       lttng_channel_set_monitor_timer_interval(attr, 0);
                }
                break;
        }
@@ -1432,8 +1378,8 @@ int cmd_enable_channel(struct ltt_session *session,
        {
                struct ltt_kernel_channel *kchan;
 
-               kchan = trace_kernel_get_channel_by_name(attr.name,
-                               session->kernel_session);
+               kchan = trace_kernel_get_channel_by_name(
+                               attr->name, session->kernel_session);
                if (kchan == NULL) {
                        /*
                         * Don't try to create a channel if the session has been started at
@@ -1447,10 +1393,11 @@ int cmd_enable_channel(struct ltt_session *session,
                        if (session->snapshot.nb_output > 0 ||
                                        session->snapshot_mode) {
                                /* Enforce mmap output for snapshot sessions. */
-                               attr.attr.output = LTTNG_EVENT_MMAP;
+                               attr->attr.output = LTTNG_EVENT_MMAP;
                        }
-                       ret = channel_kernel_create(session->kernel_session, &attr, wpipe);
-                       if (attr.name[0] != '\0') {
+                       ret = channel_kernel_create(
+                                       session->kernel_session, attr, wpipe);
+                       if (attr->name[0] != '\0') {
                                session->kernel_session->has_non_default_channel = 1;
                        }
                } else {
@@ -1480,19 +1427,19 @@ int cmd_enable_channel(struct ltt_session *session,
                 * adhered to.
                 */
                if (domain->type == LTTNG_DOMAIN_JUL) {
-                       if (strncmp(attr.name, DEFAULT_JUL_CHANNEL_NAME,
+                       if (strncmp(attr->name, DEFAULT_JUL_CHANNEL_NAME,
                                        LTTNG_SYMBOL_NAME_LEN)) {
                                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                                goto error;
                        }
                } else if (domain->type == LTTNG_DOMAIN_LOG4J) {
-                       if (strncmp(attr.name, DEFAULT_LOG4J_CHANNEL_NAME,
+                       if (strncmp(attr->name, DEFAULT_LOG4J_CHANNEL_NAME,
                                        LTTNG_SYMBOL_NAME_LEN)) {
                                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                                goto error;
                        }
                } else if (domain->type == LTTNG_DOMAIN_PYTHON) {
-                       if (strncmp(attr.name, DEFAULT_PYTHON_CHANNEL_NAME,
+                       if (strncmp(attr->name, DEFAULT_PYTHON_CHANNEL_NAME,
                                        LTTNG_SYMBOL_NAME_LEN)) {
                                ret = LTTNG_ERR_INVALID_CHANNEL_NAME;
                                goto error;
@@ -1501,7 +1448,7 @@ int cmd_enable_channel(struct ltt_session *session,
 
                chan_ht = usess->domain_global.channels;
 
-               uchan = trace_ust_find_channel_by_name(chan_ht, attr.name);
+               uchan = trace_ust_find_channel_by_name(chan_ht, attr->name);
                if (uchan == NULL) {
                        /*
                         * Don't try to create a channel if the session has been started at
@@ -1512,8 +1459,8 @@ int cmd_enable_channel(struct ltt_session *session,
                                goto error;
                        }
 
-                       ret = channel_ust_create(usess, &attr, domain->buf_type);
-                       if (attr.name[0] != '\0') {
+                       ret = channel_ust_create(usess, attr, domain->buf_type);
+                       if (attr->name[0] != '\0') {
                                usess->has_non_default_channel = 1;
                        }
                } else {
@@ -1526,12 +1473,13 @@ int cmd_enable_channel(struct ltt_session *session,
                goto error;
        }
 
-       if (ret == LTTNG_OK && attr.attr.output != LTTNG_EVENT_MMAP) {
+       if (ret == LTTNG_OK && attr->attr.output != LTTNG_EVENT_MMAP) {
                session->has_non_mmap_channel = true;
        }
 error:
        rcu_read_unlock();
 end:
+       lttng_channel_destroy(attr);
        return ret;
 }
 
@@ -2158,7 +2106,8 @@ static int _cmd_enable_event(struct ltt_session *session,
                                goto error;
                        }
 
-                       ret = cmd_enable_channel(session, domain, attr, wpipe);
+                       ret = cmd_enable_channel_internal(
+                                       session, domain, attr, wpipe);
                        if (ret != LTTNG_OK) {
                                goto error;
                        }
@@ -2297,7 +2246,8 @@ static int _cmd_enable_event(struct ltt_session *session,
                                goto error;
                        }
 
-                       ret = cmd_enable_channel(session, domain, attr, wpipe);
+                       ret = cmd_enable_channel_internal(
+                                       session, domain, attr, wpipe);
                        if (ret != LTTNG_OK) {
                                goto error;
                        }
@@ -3603,67 +3553,138 @@ error:
 /*
  * Command LTTNG_LIST_CHANNELS processed by the client thread.
  */
-ssize_t cmd_list_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel **channels)
+enum lttng_error_code cmd_list_channels(enum lttng_domain_type domain,
+               struct ltt_session *session,
+               struct lttng_payload *payload)
 {
-       ssize_t nb_chan = 0, payload_size = 0, ret;
+       int ret = 0;
+       unsigned int i = 0;
+       struct lttcomm_list_command_header cmd_header = {};
+       size_t cmd_header_offset;
+       enum lttng_error_code ret_code;
+
+       assert(session);
+       assert(payload);
+
+       DBG("Listing channels for session %s", session->name);
+
+       cmd_header_offset = payload->buffer.size;
+
+       /* Reserve space for command reply header. */
+       ret = lttng_dynamic_buffer_set_size(&payload->buffer,
+                       cmd_header_offset + sizeof(cmd_header));
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
 
        switch (domain) {
        case LTTNG_DOMAIN_KERNEL:
+       {
+               /* Kernel channels */
+               struct ltt_kernel_channel *kchan;
                if (session->kernel_session != NULL) {
-                       nb_chan = session->kernel_session->channel_count;
-               }
-               DBG3("Number of kernel channels %zd", nb_chan);
-               if (nb_chan <= 0) {
-                       ret = -LTTNG_ERR_KERN_CHAN_NOT_FOUND;
-                       goto end;
+                       cds_list_for_each_entry(kchan,
+                                       &session->kernel_session->channel_list.head, list) {
+                               uint64_t discarded_events, lost_packets;
+                               struct lttng_channel_extended *extended;
+
+                               extended = (struct lttng_channel_extended *)
+                                               kchan->channel->attr.extended.ptr;
+
+                               ret = get_kernel_runtime_stats(session, kchan,
+                                               &discarded_events, &lost_packets);
+                               if (ret < 0) {
+                                       ret_code = LTTNG_ERR_UNK;
+                                       goto end;
+                               }
+
+                               /*
+                                * Update the discarded_events and lost_packets
+                                * count for the channel
+                                */
+                               extended->discarded_events = discarded_events;
+                               extended->lost_packets = lost_packets;
+
+                               ret = lttng_channel_serialize(
+                                               kchan->channel, &payload->buffer);
+                               if (ret) {
+                                       ERR("Failed to serialize lttng_channel: channel name = '%s'",
+                                                       kchan->channel->name);
+                                       ret_code = LTTNG_ERR_UNK;
+                                       goto end;
+                               }
+
+                               i++;
+                       }
                }
                break;
+       }
        case LTTNG_DOMAIN_UST:
-               if (session->ust_session != NULL) {
-                       rcu_read_lock();
-                       nb_chan = lttng_ht_get_count(
-                               session->ust_session->domain_global.channels);
-                       rcu_read_unlock();
-               }
-               DBG3("Number of UST global channels %zd", nb_chan);
-               if (nb_chan < 0) {
-                       ret = -LTTNG_ERR_UST_CHAN_NOT_FOUND;
-                       goto end;
+       {
+               struct lttng_ht_iter iter;
+               struct ltt_ust_channel *uchan;
+
+               rcu_read_lock();
+               cds_lfht_for_each_entry(session->ust_session->domain_global.channels->ht,
+                               &iter.iter, uchan, node.node) {
+                       uint64_t discarded_events = 0, lost_packets = 0;
+                       struct lttng_channel *channel = NULL;
+                       struct lttng_channel_extended *extended;
+
+                       channel = trace_ust_channel_to_lttng_channel(uchan);
+                       if (!channel) {
+                               ret = LTTNG_ERR_NOMEM;
+                               break;
+                       }
+
+                       extended = (struct lttng_channel_extended *)
+                                                  channel->attr.extended.ptr;
+
+                       ret = get_ust_runtime_stats(session, uchan,
+                                       &discarded_events, &lost_packets);
+                       if (ret < 0) {
+                               lttng_channel_destroy(channel);
+                               ret_code = LTTNG_ERR_UNK;
+                               break;
+                       }
+
+                       extended->discarded_events = discarded_events;
+                       extended->lost_packets = lost_packets;
+
+                       ret = lttng_channel_serialize(
+                                       channel, &payload->buffer);
+                       if (ret) {
+                               ERR("Failed to serialize lttng_channel: channel name = '%s'",
+                                               channel->name);
+                               ret_code = LTTNG_ERR_UNK;
+                               ret = -1;
+                               break;
+                       }
+
+                       i++;
                }
+               rcu_read_unlock();
                break;
+       }
        default:
-               ret = -LTTNG_ERR_UND;
-               goto end;
+               break;
        }
 
-       if (nb_chan > 0) {
-               const size_t channel_size = sizeof(struct lttng_channel) +
-                       sizeof(struct lttng_channel_extended);
-               struct lttng_channel_extended *channel_exts;
-
-               payload_size = nb_chan * channel_size;
-               *channels = (lttng_channel *) zmalloc(payload_size);
-               if (*channels == NULL) {
-                       ret = -LTTNG_ERR_FATAL;
-                       goto end;
-               }
-
-               channel_exts = (lttng_channel_extended *)
-                       (((char *) *channels) + (nb_chan * sizeof(struct lttng_channel)));
-               ret = list_lttng_channels(domain, session, *channels, channel_exts);
-               if (ret != LTTNG_OK) {
-                       free(*channels);
-                       *channels = NULL;
-                       goto end;
-               }
-       } else {
-               *channels = NULL;
+       if (i > UINT32_MAX) {
+               ERR("Channel count would overflow the channel listing command's reply");
+               ret_code = LTTNG_ERR_OVERFLOW;
+               goto end;
        }
 
-       ret = payload_size;
+       /* Update command reply header. */
+       cmd_header.count = (uint32_t) i;
+       memcpy(payload->buffer.data + cmd_header_offset, &cmd_header,
+                       sizeof(cmd_header));
+       ret_code = LTTNG_OK;
+
 end:
-       return ret;
+       return ret_code;
 }
 
 /*
index 03f7cc1a40d88902e49677a2a07d414b8f35a8b0..66897afba53af42527ed53754a8468fff5efb528 100644 (file)
@@ -15,6 +15,7 @@
 #include <common/tracker.h>
 
 struct notification_thread_handle;
+struct lttng_dynamic_buffer;
 
 /*
  * A callback (and associated user data) that should be run after a command
@@ -46,9 +47,7 @@ int cmd_destroy_session(struct ltt_session *session,
 /* Channel commands */
 int cmd_disable_channel(struct ltt_session *session,
                enum lttng_domain_type domain, char *channel_name);
-int cmd_enable_channel(struct ltt_session *session,
-               const struct lttng_domain *domain, const struct lttng_channel *attr,
-               int wpipe);
+int cmd_enable_channel(struct command_ctx *cmd_ctx, int sock, int wpipe);
 
 /* Process attribute tracker commands */
 enum lttng_error_code cmd_process_attr_tracker_get_tracking_policy(
@@ -112,8 +111,9 @@ ssize_t cmd_list_domains(struct ltt_session *session,
 ssize_t cmd_list_events(enum lttng_domain_type domain,
                struct ltt_session *session, char *channel_name,
                struct lttng_payload *payload);
-ssize_t cmd_list_channels(enum lttng_domain_type domain,
-               struct ltt_session *session, struct lttng_channel **channels);
+enum lttng_error_code cmd_list_channels(enum lttng_domain_type domain,
+               struct ltt_session *session,
+               struct lttng_payload *payload);
 ssize_t cmd_list_domains(struct ltt_session *session,
                struct lttng_domain **domains);
 void cmd_list_lttng_sessions(struct lttng_session *sessions,
index 64d5105f84245dfe0662bad68b2282d053d80a3a..c312dd970768db6135c9bfb0a98a068f12146e3d 100644 (file)
@@ -196,6 +196,7 @@ struct agent *trace_ust_find_agent(struct ltt_ust_session *session,
 struct ltt_ust_session *trace_ust_create_session(uint64_t session_id);
 struct ltt_ust_channel *trace_ust_create_channel(struct lttng_channel *attr,
                enum lttng_domain_type domain);
+
 enum lttng_error_code trace_ust_create_event(struct lttng_event *ev,
                char *filter_expression,
                struct lttng_bytecode *filter,
index 613e03a4af34042d4f51a51a4964cb6f0d533fd0..902e2c174bcea74e185b5da5a05579c326826560 100644 (file)
@@ -56,6 +56,7 @@ libcommon_lgpl_la_SOURCES = \
        actions/stop-session.cpp \
        actions/rate-policy.cpp \
        buffer-view.h buffer-view.cpp \
+       channel.cpp \
        conditions/buffer-usage.cpp \
        conditions/condition.cpp \
        conditions/event-rule-matches.cpp \
diff --git a/src/common/channel.cpp b/src/common/channel.cpp
new file mode 100644 (file)
index 0000000..db8d6fd
--- /dev/null
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <common/macros.h>
+#include <lttng/channel.h>
+#include <lttng/constant.h>
+#include <lttng/channel-internal.h>
+#include <lttng/userspace-probe-internal.h>
+#include <common/dynamic-buffer.h>
+#include <common/error.h>
+#include <assert.h>
+#include <string.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/dynamic-array.h>
+#include <common/buffer-view.h>
+
+static enum lttng_error_code flatten_lttng_channels(
+               struct lttng_dynamic_pointer_array *channels,
+               struct lttng_channel **flattened_channels);
+
+static enum lttng_error_code channel_list_create_from_buffer(
+               const struct lttng_buffer_view *buffer,
+               uint32_t count,
+               struct lttng_dynamic_pointer_array *channel_list);
+
+static void channel_list_destructor(void *ptr)
+{
+       struct lttng_channel *element = (struct lttng_channel *) ptr;
+
+       lttng_channel_destroy(element);
+}
+
+struct lttng_channel *lttng_channel_copy(const struct lttng_channel *src)
+{
+       struct lttng_channel_extended *extended = nullptr;
+       struct lttng_channel *channel = nullptr, *ret = nullptr;
+
+       channel = (struct lttng_channel *) zmalloc(sizeof(*channel));
+       if (!channel) {
+               goto end;
+       }
+
+       *channel = *src;
+
+       if (src->attr.extended.ptr) {
+               extended = (struct lttng_channel_extended *) zmalloc(
+                               sizeof(*extended));
+               if (!extended) {
+                       goto end;
+               }
+               memcpy(extended, src->attr.extended.ptr, sizeof(*extended));
+               channel->attr.extended.ptr = extended;
+               extended = nullptr;
+       }
+
+       ret = channel;
+       channel = nullptr;
+end:
+       free(channel);
+       free(extended);
+       return ret;
+}
+
+/*
+ * The channel object is NOT populated.
+ */
+struct lttng_channel *lttng_channel_create_internal(void)
+{
+       struct lttng_channel *local_channel = nullptr, *ret = nullptr;
+       struct lttng_channel_extended *extended = nullptr;
+
+       local_channel = (struct lttng_channel *) zmalloc(
+                       sizeof(struct lttng_channel));
+       if (!local_channel) {
+               goto end;
+       }
+
+       /* Extended struct */
+       extended = (struct lttng_channel_extended *) zmalloc(
+                       sizeof(*extended));
+       if (!extended) {
+               goto end;
+       }
+
+       local_channel->attr.extended.ptr = extended;
+       extended = nullptr;
+
+       ret = local_channel;
+       local_channel = nullptr;
+end:
+       free(extended);
+       free(local_channel);
+       return ret;
+}
+
+ssize_t lttng_channel_create_from_buffer(const struct lttng_buffer_view *view,
+               struct lttng_channel **channel)
+{
+       ssize_t ret, offset = 0;
+       struct lttng_channel *local_channel = nullptr;
+       const struct lttng_channel_comm *channel_comm;
+       struct lttng_channel_extended *extended = nullptr;
+
+       assert(channel);
+
+       if (!view || !channel) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Create an 'internal' channel since `lttng_create_channel` requires a
+        * domain and we cannot infer the domain from the payload.
+        */
+       local_channel = lttng_channel_create_internal();
+       if (!local_channel) {
+               ret = -1;
+               goto end;
+       }
+
+       extended = (typeof(extended)) local_channel->attr.extended.ptr;
+
+       /* lttng_trigger_comm header */
+       {
+               const struct lttng_buffer_view comm_view =
+                               lttng_buffer_view_from_view(view, offset,
+                                               sizeof(*channel_comm));
+
+               if (!lttng_buffer_view_is_valid(&comm_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               channel_comm = (const struct lttng_channel_comm *)
+                                              comm_view.data;
+               offset += sizeof(*channel_comm);
+       }
+
+       {
+               const char *name;
+               const struct lttng_buffer_view name_view =
+                               lttng_buffer_view_from_view(view, offset,
+                                               channel_comm->name_len);
+
+               if (channel_comm->name_len > LTTNG_SYMBOL_NAME_LEN - 1) {
+                       ret = -1;
+                       goto end;
+               }
+
+               name = name_view.data;
+               if (!lttng_buffer_view_contains_string(
+                                   &name_view, name, channel_comm->name_len)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               strcpy(local_channel->name, name);
+               offset += channel_comm->name_len;
+       }
+
+       /* Populate the channel */
+       local_channel->enabled = channel_comm->enabled;
+
+       /* attr */
+       local_channel->attr.overwrite = channel_comm->overwrite;
+       local_channel->attr.subbuf_size = channel_comm->subbuf_size;
+       local_channel->attr.num_subbuf = channel_comm->num_subbuf;
+       local_channel->attr.switch_timer_interval =
+                       channel_comm->switch_timer_interval;
+       local_channel->attr.read_timer_interval =
+                       channel_comm->read_timer_interval;
+       local_channel->attr.output = (enum lttng_event_output) channel_comm->output;
+       local_channel->attr.tracefile_size = channel_comm->tracefile_size;
+       local_channel->attr.tracefile_count = channel_comm->tracefile_count;
+       local_channel->attr.live_timer_interval =
+                       channel_comm->live_timer_interval;
+
+       extended->discarded_events = channel_comm->discarded_events;
+       extended->lost_packets = channel_comm->lost_packets;
+       extended->monitor_timer_interval = channel_comm->monitor_timer_interval;
+       extended->blocking_timeout = channel_comm->blocking_timeout;
+
+       *channel = local_channel;
+       local_channel = nullptr;
+
+       ret = offset;
+end:
+       lttng_channel_destroy(local_channel);
+       return ret;
+}
+
+int lttng_channel_serialize(
+               struct lttng_channel *channel, struct lttng_dynamic_buffer *buf)
+{
+       int ret;
+       size_t name_len;
+       struct lttng_channel_comm channel_comm = { 0 };
+       struct lttng_channel_extended *extended;
+
+       assert(channel);
+       assert(buf);
+
+       extended = (struct lttng_channel_extended *) channel->attr.extended.ptr;
+
+       name_len = lttng_strnlen(channel->name, LTTNG_SYMBOL_NAME_LEN);
+       if (name_len == LTTNG_SYMBOL_NAME_LEN) {
+               /* channel name is not nullptr-terminated. */
+               ret = -1;
+               goto end;
+       }
+
+       /* Include string termination. */
+       name_len += 1;
+
+       /* Base field */
+       channel_comm.name_len = (uint32_t) name_len;
+       channel_comm.enabled = channel->enabled;
+
+       /* attr */
+       channel_comm.overwrite = channel->attr.overwrite;
+       channel_comm.subbuf_size = channel->attr.subbuf_size;
+       channel_comm.num_subbuf = channel->attr.num_subbuf;
+       channel_comm.switch_timer_interval =
+                       channel->attr.switch_timer_interval;
+       channel_comm.read_timer_interval = channel->attr.read_timer_interval;
+       channel_comm.output = channel->attr.output;
+       channel_comm.tracefile_size = channel->attr.tracefile_size;
+       channel_comm.tracefile_count = channel->attr.tracefile_count;
+       channel_comm.live_timer_interval = channel->attr.live_timer_interval;
+
+       /* Extended struct */
+       channel_comm.discarded_events = extended->discarded_events;
+       channel_comm.lost_packets = extended->lost_packets;
+       channel_comm.monitor_timer_interval = extended->monitor_timer_interval;
+       channel_comm.blocking_timeout = extended->blocking_timeout;
+
+       /* Header */
+       ret = lttng_dynamic_buffer_append(
+                       buf, &channel_comm, sizeof(channel_comm));
+       if (ret) {
+               goto end;
+       }
+
+       /* channel name */
+       ret = lttng_dynamic_buffer_append(buf, channel->name, name_len);
+       if (ret) {
+               goto end;
+       }
+end:
+       return ret;
+}
+
+void lttng_channel_set_default_extended_attr(struct lttng_domain *domain,
+               struct lttng_channel_extended *extended_attr)
+{
+       assert(domain);
+       assert(extended_attr);
+
+       memset(extended_attr, 0, sizeof(*extended_attr));
+
+       switch (domain->type) {
+       case LTTNG_DOMAIN_KERNEL:
+               extended_attr->monitor_timer_interval =
+                               DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER;
+               extended_attr->blocking_timeout =
+                               DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT;
+               break;
+       case LTTNG_DOMAIN_UST:
+               switch (domain->buf_type) {
+               case LTTNG_BUFFER_PER_UID:
+                       extended_attr->monitor_timer_interval =
+                                       DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER;
+                       extended_attr->blocking_timeout =
+                                       DEFAULT_UST_UID_CHANNEL_BLOCKING_TIMEOUT;
+                       break;
+               case LTTNG_BUFFER_PER_PID:
+               default:
+                       if (extended_attr) {
+                               extended_attr->monitor_timer_interval =
+                                               DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER;
+                               extended_attr->blocking_timeout =
+                                               DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT;
+                       }
+                       break;
+               }
+       default:
+               /* Default behavior: leave set to 0. */
+               break;
+       }
+}
+
+static enum lttng_error_code channel_list_create_from_buffer(
+               const struct lttng_buffer_view *view,
+               unsigned int count,
+               struct lttng_dynamic_pointer_array *channel_list)
+{
+       enum lttng_error_code ret_code;
+       int ret, i;
+       int offset = 0;
+
+       assert(view);
+       assert(channel_list);
+
+       for (i = 0; i < count; i++) {
+               ssize_t channel_size;
+               struct lttng_channel *channel = nullptr;
+               const struct lttng_buffer_view channel_view =
+                               lttng_buffer_view_from_view(view, offset, -1);
+
+               channel_size = lttng_channel_create_from_buffer(
+                               &channel_view, &channel);
+               if (channel_size < 0) {
+                       ret_code = LTTNG_ERR_INVALID;
+                       goto end;
+               }
+
+               /* Lifetime and management of the object is now bound to the array. */
+               ret = lttng_dynamic_pointer_array_add_pointer(channel_list, channel);
+               if (ret) {
+                       lttng_channel_destroy(channel);
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+               offset += channel_size;
+       }
+
+       if (view->size != offset) {
+               ret_code = LTTNG_ERR_INVALID;
+               goto end;
+       }
+
+       ret_code = LTTNG_OK;
+
+end:
+       return ret_code;
+}
+
+static enum lttng_error_code flatten_lttng_channels(struct lttng_dynamic_pointer_array *channels,
+               struct lttng_channel **flattened_channels)
+{
+       enum lttng_error_code ret_code;
+       int ret, i;
+       size_t storage_req = 0;
+       struct lttng_dynamic_buffer local_flattened_channels;
+       int nb_channels;
+
+       assert(channels);
+       assert(flattened_channels);
+
+       lttng_dynamic_buffer_init(&local_flattened_channels);
+       nb_channels = lttng_dynamic_pointer_array_get_count(channels);
+
+       storage_req += sizeof(struct lttng_channel) * nb_channels;
+       storage_req += sizeof(struct lttng_channel_extended) * nb_channels;
+
+       /*
+        * We must ensure that "local_flattened_channels" is never resized so as
+        * to preserve the validity of the flattened objects.
+        */
+       ret = lttng_dynamic_buffer_set_capacity(
+                       &local_flattened_channels, storage_req);
+       if (ret) {
+               ret_code = LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Start by laying the struct lttng_channel */
+       for (i = 0; i < nb_channels; i++) {
+               const auto *element = (const struct lttng_channel *)
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               channels, i);
+
+               if (!element) {
+                       ret_code = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+
+               ret = lttng_dynamic_buffer_append(&local_flattened_channels,
+                               element, sizeof(struct lttng_channel));
+               if (ret) {
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+       }
+
+       /* Flatten the extended data */
+       for (i = 0; i < nb_channels; i++) {
+               const auto *element = (const struct lttng_channel *)
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               channels, i);
+               /*
+                * Sample the location of the flattened channel we are about
+                * to modify.
+                */
+               auto *channel = (struct lttng_channel *)
+                               (local_flattened_channels.data + (sizeof(struct lttng_channel) * i));
+               /*
+                * Sample the location of the extended attributes we are about
+                * to add.
+                */
+               const auto *channel_extended = (struct lttng_channel_extended *)
+                               (local_flattened_channels.data + local_flattened_channels.size);
+
+               if (!element) {
+                       ret_code = LTTNG_ERR_FATAL;
+                       goto end;
+               }
+
+               ret = lttng_dynamic_buffer_append(&local_flattened_channels,
+                               element->attr.extended.ptr,
+                               sizeof(struct lttng_channel_extended));
+               if (ret) {
+                       ret_code = LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /*
+                * Update the flattened lttng_channel object with its flattened
+                * extended object location.
+                */
+               channel->attr.extended.ptr = (void *) channel_extended;
+       }
+
+       /* Don't reset local_flattened_channels buffer as we return its content. */
+       *flattened_channels = (struct lttng_channel *) local_flattened_channels.data;
+       lttng_dynamic_buffer_init(&local_flattened_channels);
+       ret_code = LTTNG_OK;
+end:
+       lttng_dynamic_buffer_reset(&local_flattened_channels);
+       return ret_code;
+}
+
+enum lttng_error_code lttng_channels_create_and_flatten_from_buffer(
+               const struct lttng_buffer_view *view,
+               uint32_t count,
+               struct lttng_channel **channels)
+{
+       enum lttng_error_code ret_code;
+       struct lttng_dynamic_pointer_array local_channels;
+
+       lttng_dynamic_pointer_array_init(&local_channels, channel_list_destructor);
+
+       /* Deserialize the channels */
+       {
+               const struct lttng_buffer_view channels_view =
+                               lttng_buffer_view_from_view(view, 0, -1);
+
+               ret_code = channel_list_create_from_buffer(
+                               &channels_view, count, &local_channels);
+               if (ret_code != LTTNG_OK) {
+                       goto end;
+               }
+       }
+
+       ret_code = flatten_lttng_channels(&local_channels, channels);
+
+end:
+       lttng_dynamic_pointer_array_reset(&local_channels);
+       return ret_code;
+}
index adb179675cad881f239a30fff00ed0627c993a70..318753d978240142ed9fadc08238df99dd44c19c 100644 (file)
@@ -461,8 +461,7 @@ struct lttcomm_session_msg {
                } LTTNG_PACKED disable;
                /* Create channel */
                struct {
-                       struct lttng_channel chan;
-                       struct lttng_channel_extended extended;
+                       uint32_t length;
                } LTTNG_PACKED channel;
                /* Context */
                struct {
@@ -608,6 +607,14 @@ struct lttcomm_event_command_header {
        uint32_t nb_events;
 } LTTNG_PACKED;
 
+/*
+ * Listing command header.
+ */
+struct lttcomm_list_command_header {
+       /* Number of elements */
+       uint32_t count;
+} LTTNG_PACKED;
+
 /*
  * Event extended info header. This is the structure preceding each
  * extended info data.
index 1743e7546c1071713aff10d9f10c73ad30ee955a..3e39b5b0cc216ad229b91bce5add89872cba24d2 100644 (file)
@@ -1534,10 +1534,9 @@ end:
 struct lttng_channel *lttng_channel_create(struct lttng_domain *domain)
 {
        struct lttng_channel *channel = NULL;
-       struct lttng_channel_extended *extended = NULL;
 
        if (!domain) {
-               goto error;
+               goto end;
        }
 
        /* Validate domain. */
@@ -1548,36 +1547,26 @@ struct lttng_channel *lttng_channel_create(struct lttng_domain *domain)
                case LTTNG_BUFFER_PER_PID:
                        break;
                default:
-                       goto error;
+                       goto end;
                }
                break;
        case LTTNG_DOMAIN_KERNEL:
                if (domain->buf_type != LTTNG_BUFFER_GLOBAL) {
-                       goto error;
+                       goto end;
                }
                break;
        default:
-               goto error;
+               goto end;
        }
 
-       channel = (lttng_channel *) zmalloc(sizeof(*channel));
+       channel = lttng_channel_create_internal();
        if (!channel) {
-               goto error;
-       }
-
-       extended = (lttng_channel_extended *) zmalloc(sizeof(*extended));
-       if (!extended) {
-               goto error;
+               goto end;
        }
 
-       channel->attr.extended.ptr = extended;
-
        lttng_channel_set_default_attr(domain, &channel->attr);
+end:
        return channel;
-error:
-       free(channel);
-       free(extended);
-       return NULL;
 }
 
 void lttng_channel_destroy(struct lttng_channel *channel)
@@ -1601,56 +1590,32 @@ int lttng_enable_channel(struct lttng_handle *handle,
 {
        enum lttng_error_code ret_code;
        int ret;
+       struct lttng_dynamic_buffer buffer;
        struct lttcomm_session_msg lsm;
        uint64_t total_buffer_size_needed_per_cpu = 0;
+       struct lttng_channel *channel = NULL;
+
+       lttng_dynamic_buffer_init(&buffer);
 
        /* NULL arguments are forbidden. No default values. */
        if (handle == NULL || in_chan == NULL) {
-               return -LTTNG_ERR_INVALID;
-       }
-
-       memset(&lsm, 0, sizeof(lsm));
-       memcpy(&lsm.u.channel.chan, in_chan, sizeof(lsm.u.channel.chan));
-       lsm.u.channel.chan.attr.extended.ptr = NULL;
-
-       if (!in_chan->attr.extended.ptr) {
-               struct lttng_channel *channel;
-               struct lttng_channel_extended *extended;
-
-               channel = lttng_channel_create(&handle->domain);
-               if (!channel) {
-                       return -LTTNG_ERR_NOMEM;
-               }
-
-               /*
-                * Create a new channel in order to use default extended
-                * attribute values.
-                */
-               extended = (struct lttng_channel_extended *)
-                               channel->attr.extended.ptr;
-               memcpy(&lsm.u.channel.extended, extended, sizeof(*extended));
-               lttng_channel_destroy(channel);
-       } else {
-               struct lttng_channel_extended *extended;
-
-               extended = (struct lttng_channel_extended *)
-                               in_chan->attr.extended.ptr;
-               memcpy(&lsm.u.channel.extended, extended, sizeof(*extended));
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
        }
 
        /*
         * Verify that the amount of memory required to create the requested
         * buffer is available on the system at the moment.
         */
-       if (lsm.u.channel.chan.attr.num_subbuf >
-                       UINT64_MAX / lsm.u.channel.chan.attr.subbuf_size) {
+       if (in_chan->attr.num_subbuf >
+                       UINT64_MAX / in_chan->attr.subbuf_size) {
                /* Overflow */
                ret = -LTTNG_ERR_OVERFLOW;
                goto end;
        }
 
-       total_buffer_size_needed_per_cpu = lsm.u.channel.chan.attr.num_subbuf *
-               lsm.u.channel.chan.attr.subbuf_size;
+       total_buffer_size_needed_per_cpu =
+                       in_chan->attr.num_subbuf * in_chan->attr.subbuf_size;
        ret_code = check_enough_available_memory(
                        total_buffer_size_needed_per_cpu);
        if (ret_code != LTTNG_OK) {
@@ -1658,6 +1623,31 @@ int lttng_enable_channel(struct lttng_handle *handle,
                goto end;
        }
 
+       /* Copy the channel for easier manipulation. */
+       channel = lttng_channel_copy(in_chan);
+       if (!channel) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Populate the channel extended attribute if necessary. */
+       if (!channel->attr.extended.ptr) {
+               struct lttng_channel_extended *extended =
+                               (struct lttng_channel_extended *) zmalloc(
+                                               sizeof(*extended));
+
+               if (!extended) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+               lttng_channel_set_default_extended_attr(
+                               &handle->domain, extended);
+               channel->attr.extended.ptr = extended;
+       }
+
+       /* Prepare the payload */
+       memset(&lsm, 0, sizeof(lsm));
+
        lsm.cmd_type = LTTNG_ENABLE_CHANNEL;
        COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
 
@@ -1668,8 +1658,19 @@ int lttng_enable_channel(struct lttng_handle *handle,
                goto end;
        }
 
-       ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+       ret = lttng_channel_serialize(channel, &buffer);
+       if (ret) {
+               ret = -LTTNG_ERR_FATAL;
+               goto end;
+       }
+
+       lsm.u.channel.length = buffer.size;
+
+       ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(
+                       &lsm, buffer.data, buffer.size, NULL);
 end:
+       lttng_channel_destroy(channel);
+       lttng_dynamic_buffer_reset(&buffer);
        return ret;
 }
 
@@ -2271,12 +2272,14 @@ error:
 int lttng_list_channels(struct lttng_handle *handle,
                struct lttng_channel **channels)
 {
-       int ret;
-       size_t channel_count, i;
-       const size_t channel_size = sizeof(struct lttng_channel) +
-                       sizeof(struct lttng_channel_extended);
+       int ret, total_payload_received;
        struct lttcomm_session_msg lsm;
-       char *extended_at;
+       char *reception_buffer = NULL;
+       size_t cmd_header_len = 0;
+       struct lttcomm_list_command_header *cmd_header = NULL;
+       struct lttng_dynamic_buffer tmp_buffer;
+
+       lttng_dynamic_buffer_init(&tmp_buffer);
 
        if (handle == NULL) {
                ret = -LTTNG_ERR_INVALID;
@@ -2294,31 +2297,48 @@ int lttng_list_channels(struct lttng_handle *handle,
 
        COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
 
-       ret = lttng_ctl_ask_sessiond(&lsm, (void**) channels);
+       ret = lttng_ctl_ask_sessiond_fds_varlen(&lsm, NULL, 0, NULL, 0,
+                       (void **) &reception_buffer, (void **) &cmd_header,
+                       &cmd_header_len);
        if (ret < 0) {
                goto end;
        }
 
-       if (ret % channel_size) {
-               ret = -LTTNG_ERR_UNK;
-               free(*channels);
-               *channels = NULL;
+       total_payload_received = ret;
+
+       if (cmd_header_len != sizeof(*cmd_header)) {
+               ret = -LTTNG_ERR_FATAL;
                goto end;
        }
-       channel_count = (size_t) ret / channel_size;
 
-       /* Set extended info pointers */
-       extended_at = ((char *) *channels) +
-                       channel_count * sizeof(struct lttng_channel);
-       for (i = 0; i < channel_count; i++) {
-               struct lttng_channel *chan = &(*channels)[i];
+       if (!cmd_header) {
+               ret = LTTNG_ERR_UNK;
+               goto end;
+       }
+
+       if (cmd_header->count > INT_MAX) {
+               ret = -LTTNG_ERR_OVERFLOW;
+               goto end;
+       }
 
-               chan->attr.extended.ptr = extended_at;
-               extended_at += sizeof(struct lttng_channel_extended);
+       {
+               enum lttng_error_code ret_code;
+               const struct lttng_buffer_view events_view =
+                               lttng_buffer_view_init(reception_buffer, 0,
+                                               total_payload_received);
+
+               ret_code = lttng_channels_create_and_flatten_from_buffer(
+                               &events_view, cmd_header->count, channels);
+               if (ret_code != LTTNG_OK) {
+                       ret = -ret_code;
+                       goto end;
+               }
        }
 
-       ret = (int) channel_count;
+       ret = (int) cmd_header->count;
 end:
+       free(cmd_header);
+       free(reception_buffer);
        return ret;
 }
 
@@ -2698,6 +2718,7 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                return;
        }
 
+       /* Save the pointer for later use */
        extended = (struct lttng_channel_extended *) attr->extended.ptr;
        memset(attr, 0, sizeof(struct lttng_channel_attr));
 
@@ -2714,12 +2735,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                attr->subbuf_size = default_get_kernel_channel_subbuf_size();
                attr->num_subbuf = DEFAULT_KERNEL_CHANNEL_SUBBUF_NUM;
                attr->output = DEFAULT_KERNEL_CHANNEL_OUTPUT;
-               if (extended) {
-                       extended->monitor_timer_interval =
-                                       DEFAULT_KERNEL_CHANNEL_MONITOR_TIMER;
-                       extended->blocking_timeout =
-                                       DEFAULT_KERNEL_CHANNEL_BLOCKING_TIMEOUT;
-               }
                break;
        case LTTNG_DOMAIN_UST:
                switch (domain->buf_type) {
@@ -2731,12 +2746,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                                        DEFAULT_UST_UID_CHANNEL_SWITCH_TIMER;
                        attr->read_timer_interval =
                                        DEFAULT_UST_UID_CHANNEL_READ_TIMER;
-                       if (extended) {
-                               extended->monitor_timer_interval =
-                                               DEFAULT_UST_UID_CHANNEL_MONITOR_TIMER;
-                               extended->blocking_timeout =
-                                               DEFAULT_UST_UID_CHANNEL_BLOCKING_TIMEOUT;
-                       }
                        break;
                case LTTNG_BUFFER_PER_PID:
                default:
@@ -2747,12 +2756,6 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                                        DEFAULT_UST_PID_CHANNEL_SWITCH_TIMER;
                        attr->read_timer_interval =
                                        DEFAULT_UST_PID_CHANNEL_READ_TIMER;
-                       if (extended) {
-                               extended->monitor_timer_interval =
-                                               DEFAULT_UST_PID_CHANNEL_MONITOR_TIMER;
-                               extended->blocking_timeout =
-                                               DEFAULT_UST_PID_CHANNEL_BLOCKING_TIMEOUT;
-                       }
                        break;
                }
        default:
@@ -2760,6 +2763,11 @@ void lttng_channel_set_default_attr(struct lttng_domain *domain,
                break;
        }
 
+       if (extended) {
+               lttng_channel_set_default_extended_attr(domain, extended);
+       }
+
+       /* Reassign the extended pointer. */
        attr->extended.ptr = extended;
 }
 
This page took 0.046415 seconds and 4 git commands to generate.