Generate session name and default output on sessiond's end
[lttng-tools.git] / src / common / session-descriptor.c
diff --git a/src/common/session-descriptor.c b/src/common/session-descriptor.c
new file mode 100644 (file)
index 0000000..6f0a357
--- /dev/null
@@ -0,0 +1,1180 @@
+/*
+ * Copyright (C) 2019 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License, version 2.1 only,
+ * as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <lttng/session-descriptor-internal.h>
+#include <common/macros.h>
+#include <common/uri.h>
+#include <common/defaults.h>
+#include <common/error.h>
+#include <time.h>
+#include <assert.h>
+#include <stdio.h>
+
+struct lttng_session_descriptor_network_location {
+       struct lttng_uri *control;
+       struct lttng_uri *data;
+};
+
+struct lttng_session_descriptor {
+       enum lttng_session_descriptor_type type;
+       /*
+        * If an output type that is not OUTPUT_TYPE_NONE is specified,
+        * it means that an output of that type must be generated at
+        * session-creation time.
+        */
+       enum lttng_session_descriptor_output_type output_type;
+       char *name;
+       union {
+               struct lttng_session_descriptor_network_location network;
+               struct lttng_uri *local;
+       } output;
+};
+
+struct lttng_session_descriptor_snapshot {
+       struct lttng_session_descriptor base;
+       /*
+        * Assumes at-most one snapshot output is supported. Uses
+        * the output field of the base class.
+        */
+};
+
+struct lttng_session_descriptor_live {
+       struct lttng_session_descriptor base;
+       unsigned long long live_timer_us;
+};
+
+struct lttng_session_descriptor_comm {
+       /* enum lttng_session_descriptor_type */
+       uint8_t type;
+       /* enum lttng_session_descriptor_output_type */
+       uint8_t output_type;
+       /* Includes trailing null. */
+       uint32_t name_len;
+       /* Name follows, followed by URIs */
+       uint8_t uri_count;
+} LTTNG_PACKED;
+
+struct lttng_session_descriptor_live_comm {
+       struct lttng_session_descriptor_comm base;
+       /* Live-specific parameters. */
+       uint64_t live_timer_us;
+} LTTNG_PACKED;
+
+static
+struct lttng_uri *uri_copy(const struct lttng_uri *uri)
+{
+       struct lttng_uri *new_uri = NULL;
+
+       if (!uri) {
+               goto end;
+       }
+
+       new_uri = zmalloc(sizeof(*new_uri));
+       if (!new_uri) {
+               goto end;
+       }
+       memcpy(new_uri, uri, sizeof(*new_uri));
+end:
+       return new_uri;
+}
+
+static
+struct lttng_uri *uri_from_path(const char *path)
+{
+       struct lttng_uri *uris = NULL;
+       ssize_t uri_count;
+       char local_protocol_string[LTTNG_PATH_MAX + sizeof("file://")] =
+                       "file://";
+
+       if (strlen(path) >= LTTNG_PATH_MAX) {
+               goto end;
+       }
+
+       if (path[0] != '/') {
+               /* Not an absolute path. */
+               goto end;
+       }
+
+       strncat(local_protocol_string, path, LTTNG_PATH_MAX);
+       uri_count = uri_parse(local_protocol_string, &uris);
+       if (uri_count != 1) {
+               goto error;
+       }
+       if (uris[0].dtype != LTTNG_DST_PATH) {
+               goto error;
+       }
+
+end:
+       return uris;
+error:
+       free(uris);
+       return NULL;
+}
+
+static
+void network_location_fini(
+               struct lttng_session_descriptor_network_location *location)
+{
+       free(location->control);
+       free(location->data);
+}
+
+/* Assumes ownership of control and data. */
+static
+int network_location_set_from_lttng_uris(
+               struct lttng_session_descriptor_network_location *location,
+               struct lttng_uri *control, struct lttng_uri *data)
+{
+       int ret = 0;
+
+       if (!control && !data) {
+               goto end;
+       }
+
+       if (!(control && data)) {
+               /* None or both must be set. */
+               ret = -1;
+               goto end;
+       }
+
+       if (control->stype != LTTNG_STREAM_CONTROL ||
+                       data->stype != LTTNG_STREAM_DATA) {
+               ret = -1;
+               goto end;
+       }
+
+       free(location->control);
+       free(location->data);
+       location->control = control;
+       location->data = data;
+       control = NULL;
+       data = NULL;
+end:
+       free(control);
+       free(data);
+       return ret;
+}
+
+static
+int network_location_set_from_uri_strings(
+               struct lttng_session_descriptor_network_location *location,
+               const char *control, const char *data)
+{
+       int ret = 0;
+       ssize_t uri_count;
+       struct lttng_uri *parsed_uris = NULL;
+       struct lttng_uri *control_uri = NULL;
+       struct lttng_uri *data_uri = NULL;
+
+       uri_count = uri_parse_str_urls(control, data, &parsed_uris);
+       if (uri_count != 2 && uri_count != 0) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * uri_parse_str_urls returns a contiguous array of lttng_uris whereas
+        * session descriptors expect individually allocated lttng_uris.
+        */
+       if (uri_count == 2) {
+               control_uri = zmalloc(sizeof(*control_uri));
+               data_uri = zmalloc(sizeof(*data_uri));
+               if (!control_uri || !data_uri) {
+                       ret = -1;
+                       goto end;
+               }
+               memcpy(control_uri, &parsed_uris[0], sizeof(*control_uri));
+               memcpy(data_uri, &parsed_uris[1], sizeof(*data_uri));
+       }
+
+       /* Ownership of control and data uris is transferred. */
+       ret = network_location_set_from_lttng_uris(
+                       location,
+                       control_uri,
+                       data_uri);
+       control_uri = NULL;
+       data_uri = NULL;
+end:
+       free(parsed_uris);
+       free(control_uri);
+       free(data_uri);
+       return ret;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_create(const char *name)
+{
+       struct lttng_session_descriptor *descriptor;
+
+       descriptor = zmalloc(sizeof(*descriptor));
+       if (!descriptor) {
+               goto error;
+       }
+
+       descriptor->type = LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR;
+       descriptor->output_type =
+                       LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE;
+       if (lttng_session_descriptor_set_session_name(descriptor, name)) {
+               goto error;
+       }
+       return descriptor;
+error:
+       lttng_session_descriptor_destroy(descriptor);
+       return NULL;
+}
+
+/* Ownership of uri is transferred. */
+static
+struct lttng_session_descriptor *
+_lttng_session_descriptor_local_create(const char *name,
+               struct lttng_uri *uri)
+{
+       struct lttng_session_descriptor *descriptor;
+
+       descriptor = lttng_session_descriptor_create(name);
+       if (!descriptor) {
+               goto error;
+       }
+       descriptor->type = LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR;
+       descriptor->output_type =
+                       LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL;
+       if (uri) {
+               if (uri->dtype != LTTNG_DST_PATH) {
+                       goto error;
+               }
+               descriptor->output.local = uri;
+               uri = NULL;
+       }
+       return descriptor;
+error:
+       free(uri);
+       lttng_session_descriptor_destroy(descriptor);
+       return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_local_create(const char *name, const char *path)
+{
+       struct lttng_uri *uri = NULL;
+       struct lttng_session_descriptor *descriptor;
+
+       if (path) {
+               uri = uri_from_path(path);
+               if (!uri) {
+                       goto error;
+               }
+       }
+       descriptor = _lttng_session_descriptor_local_create(name, uri);
+       return descriptor;
+error:
+       return NULL;
+}
+
+/* Assumes the ownership of both uris. */
+static
+struct lttng_session_descriptor *
+_lttng_session_descriptor_network_create(const char *name,
+               struct lttng_uri *control, struct lttng_uri *data)
+{
+       int ret;
+       struct lttng_session_descriptor *descriptor;
+
+       descriptor = lttng_session_descriptor_create(name);
+       if (!descriptor) {
+               goto error;
+       }
+
+       descriptor->type = LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR;
+       descriptor->output_type = LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK;
+       /* Assumes the ownership of both uris. */
+       ret = network_location_set_from_lttng_uris(&descriptor->output.network,
+                       control, data);
+       control = NULL;
+       data = NULL;
+       if (ret) {
+               goto error;
+       }
+       return descriptor;
+error:
+       lttng_session_descriptor_destroy(descriptor);
+       free(control);
+       free(data);
+       return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_network_create(const char *name,
+               const char *control_url, const char *data_url)
+{
+       int ret;
+       struct lttng_session_descriptor *descriptor;
+
+       descriptor = _lttng_session_descriptor_network_create(name,
+                       NULL, NULL);
+       if (!descriptor) {
+               goto error;
+       }
+
+       ret = network_location_set_from_uri_strings(&descriptor->output.network,
+                       control_url, data_url);
+       if (ret) {
+               goto error;
+       }
+       return descriptor;
+error:
+       lttng_session_descriptor_destroy(descriptor);
+       return NULL;
+}
+
+static
+struct lttng_session_descriptor_snapshot *
+_lttng_session_descriptor_snapshot_create(const char *name)
+{
+       struct lttng_session_descriptor_snapshot *descriptor;
+
+       descriptor = zmalloc(sizeof(*descriptor));
+       if (!descriptor) {
+               goto error;
+       }
+
+       descriptor->base.type = LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT;
+       descriptor->base.output_type =
+                       LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE;
+       if (lttng_session_descriptor_set_session_name(&descriptor->base,
+                       name)) {
+               goto error;
+       }
+       return descriptor;
+error:
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+/* Ownership of control and data is transferred. */
+static
+struct lttng_session_descriptor_snapshot *
+_lttng_session_descriptor_snapshot_network_create(const char *name,
+               struct lttng_uri *control, struct lttng_uri *data)
+{
+       int ret;
+       struct lttng_session_descriptor_snapshot *descriptor;
+
+       descriptor = _lttng_session_descriptor_snapshot_create(name);
+       if (!descriptor) {
+               goto error;
+       }
+
+       descriptor->base.output_type =
+                       LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK;
+       /* Ownership of control and data is transferred. */
+       ret = network_location_set_from_lttng_uris(
+                       &descriptor->base.output.network,
+                       control, data);
+       control = NULL;
+       data = NULL;
+       if (ret) {
+               goto error;
+       }
+       return descriptor;
+error:
+       free(control);
+       free(data);
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_create(const char *name)
+{
+       struct lttng_session_descriptor_snapshot *descriptor;
+
+       descriptor = _lttng_session_descriptor_snapshot_create(name);
+       return descriptor ? &descriptor->base : NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_network_create(const char *name,
+               const char *control_url, const char *data_url)
+{
+       int ret;
+       struct lttng_session_descriptor_snapshot *descriptor;
+
+       descriptor = _lttng_session_descriptor_snapshot_network_create(name,
+                       NULL, NULL);
+       if (!descriptor) {
+               goto error;
+       }
+
+       ret = network_location_set_from_uri_strings(
+                       &descriptor->base.output.network,
+                       control_url, data_url);
+       if (ret) {
+               goto error;
+       }
+       return &descriptor->base;
+error:
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+/* Ownership of uri is transferred. */
+static
+struct lttng_session_descriptor_snapshot *
+_lttng_session_descriptor_snapshot_local_create(const char *name,
+               struct lttng_uri *uri)
+{
+       struct lttng_session_descriptor_snapshot *descriptor;
+
+       descriptor = _lttng_session_descriptor_snapshot_create(name);
+       if (!descriptor) {
+               goto error;
+       }
+       descriptor->base.output_type =
+                       LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL;
+       if (uri) {
+               if (uri->dtype != LTTNG_DST_PATH) {
+                       goto error;
+               }
+               descriptor->base.output.local = uri;
+               uri = NULL;
+       }
+       return descriptor;
+error:
+       free(uri);
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_snapshot_local_create(const char *name,
+               const char *path)
+{
+       struct lttng_uri *path_uri = NULL;
+       struct lttng_session_descriptor_snapshot *descriptor;
+
+       if (path) {
+               path_uri = uri_from_path(path);
+               if (!path_uri) {
+                       goto error;
+               }
+       }
+       descriptor = _lttng_session_descriptor_snapshot_local_create(name,
+                       path_uri);
+       return descriptor ? &descriptor->base : NULL;
+error:
+       return NULL;
+}
+
+static
+struct lttng_session_descriptor_live *
+_lttng_session_descriptor_live_create(const char *name,
+               unsigned long long live_timer_interval_us)
+{
+       struct lttng_session_descriptor_live *descriptor = NULL;
+
+       if (live_timer_interval_us == 0) {
+               goto error;
+       }
+       descriptor = zmalloc(sizeof(*descriptor));
+       if (!descriptor) {
+               goto error;
+       }
+
+       descriptor->base.type = LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE;
+       descriptor->base.output_type =
+                       LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE;
+       descriptor->live_timer_us = live_timer_interval_us;
+       if (lttng_session_descriptor_set_session_name(&descriptor->base,
+                       name)) {
+               goto error;
+       }
+
+       return descriptor;
+error:
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+/* Ownership of control and data is transferred. */
+static
+struct lttng_session_descriptor_live *
+_lttng_session_descriptor_live_network_create(
+               const char *name,
+               struct lttng_uri *control, struct lttng_uri *data,
+               unsigned long long live_timer_interval_us)
+{
+       int ret;
+       struct lttng_session_descriptor_live *descriptor;
+
+       descriptor = _lttng_session_descriptor_live_create(name,
+                       live_timer_interval_us);
+       descriptor->base.output_type =
+                       LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK;
+
+       /* Ownerwhip of control and data is transferred. */
+       ret = network_location_set_from_lttng_uris(
+                       &descriptor->base.output.network,
+                       control, data);
+       control = NULL;
+       data = NULL;
+       if (ret) {
+               goto error;
+       }
+       return descriptor;
+error:
+       free(control);
+       free(data);
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_live_create(
+               const char *name,
+               unsigned long long live_timer_us)
+{
+       struct lttng_session_descriptor_live *descriptor;
+
+       descriptor = _lttng_session_descriptor_live_create(name, live_timer_us);
+       if (!descriptor) {
+               goto error;
+       }
+
+       return descriptor ? &descriptor->base : NULL;
+error:
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+struct lttng_session_descriptor *
+lttng_session_descriptor_live_network_create(
+               const char *name,
+               const char *control_url, const char *data_url,
+               unsigned long long live_timer_us)
+{
+       int ret;
+       struct lttng_session_descriptor_live *descriptor;
+
+       descriptor = _lttng_session_descriptor_live_network_create(name,
+                       NULL, NULL, live_timer_us);
+       if (!descriptor) {
+               goto error;
+       }
+
+       ret = network_location_set_from_uri_strings(
+                       &descriptor->base.output.network,
+                       control_url, data_url);
+       if (ret) {
+               goto error;
+       }
+       return &descriptor->base;
+error:
+       lttng_session_descriptor_destroy(descriptor ? &descriptor->base : NULL);
+       return NULL;
+}
+
+void lttng_session_descriptor_destroy(
+               struct lttng_session_descriptor *descriptor)
+{
+       if (!descriptor) {
+               return;
+       }
+
+       switch (descriptor->output_type) {
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+               free(descriptor->output.local);
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+               network_location_fini(&descriptor->output.network);
+               break;
+       default:
+               abort();
+       }
+
+       free(descriptor->name);
+       free(descriptor);
+}
+
+LTTNG_HIDDEN
+ssize_t lttng_session_descriptor_create_from_buffer(
+               const struct lttng_buffer_view *payload,
+               struct lttng_session_descriptor **descriptor)
+{
+       int i;
+       ssize_t offset = 0, ret;
+       struct lttng_buffer_view current_view;
+       const char *name = NULL;
+       const struct lttng_session_descriptor_comm *base_header;
+       size_t max_expected_uri_count;
+       uint64_t live_timer_us = 0;
+       struct lttng_uri *uris[2] = {};
+       enum lttng_session_descriptor_type type;
+       enum lttng_session_descriptor_output_type output_type;
+
+       current_view = lttng_buffer_view_from_view(payload, offset,
+                       sizeof(*base_header));
+       base_header = (typeof(base_header)) current_view.data;
+       if (!base_header) {
+               ret = -1;
+               goto end;
+       }
+
+       switch (base_header->type) {
+       case LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR:
+       case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
+       {
+               const struct lttng_session_descriptor_live_comm *live_header;
+
+               current_view = lttng_buffer_view_from_view(payload, offset,
+                               sizeof(*live_header));
+               live_header = (typeof(live_header)) current_view.data;
+               if (!live_header) {
+                       ret = -1;
+                       goto end;
+               }
+
+               live_timer_us = live_header->live_timer_us;
+               break;
+       }
+       default:
+               ret = -1;
+               goto end;
+       }
+       /* type has been validated. */
+       type = base_header->type;
+
+       switch (base_header->output_type) {
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+               max_expected_uri_count = 0;
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+               max_expected_uri_count = 1;
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+               max_expected_uri_count = 2;
+               break;
+       default:
+               ret = -1;
+               goto end;
+       }
+       /* output_type has been validated. */
+       output_type = base_header->output_type;
+
+       /* Skip after header. */
+       offset += current_view.size;
+       if (!base_header->name_len) {
+               goto skip_name;
+       }
+
+       /* Map the name. */
+       current_view = lttng_buffer_view_from_view(payload, offset,
+                       base_header->name_len);
+       name = current_view.data;
+       if (!name) {
+               ret = -1;
+               goto end;
+       }
+
+       if (base_header->name_len == 1 ||
+                       name[base_header->name_len - 1] ||
+                       strlen(name) != base_header->name_len - 1) {
+               /*
+                * Check that the name is not NULL, is NULL-terminated, and
+                * does not contain a NULL before the last byte.
+                */
+               ret = -1;
+               goto end;
+       }
+
+       /* Skip after the name. */
+       offset += base_header->name_len;
+skip_name:
+       if (base_header->uri_count > max_expected_uri_count) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < base_header->uri_count; i++) {
+               struct lttng_uri *uri;
+
+               /* Map a URI. */
+               current_view = lttng_buffer_view_from_view(payload,
+                               offset, sizeof(*uri));
+               uri = (typeof(uri)) current_view.data;
+               if (!uri) {
+                       ret = -1;
+                       goto end;
+               }
+               uris[i] = zmalloc(sizeof(*uri));
+               if (!uris[i]) {
+                       ret = -1;
+                       goto end;
+               }
+               memcpy(uris[i], uri, sizeof(*uri));
+               offset += sizeof(*uri);
+       }
+
+       switch (type) {
+       case LTTNG_SESSION_DESCRIPTOR_TYPE_REGULAR:
+               switch (output_type) {
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+                       *descriptor = lttng_session_descriptor_create(name);
+                       break;
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+                       *descriptor = _lttng_session_descriptor_local_create(
+                                       name, uris[0]);
+                       break;
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+                       *descriptor = _lttng_session_descriptor_network_create(
+                                       name, uris[0], uris[1]);
+                       break;
+               default:
+                       /* Already checked. */
+                       abort();
+               }
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_TYPE_SNAPSHOT:
+       {
+               struct lttng_session_descriptor_snapshot *snapshot;
+               switch (output_type) {
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+                       snapshot = _lttng_session_descriptor_snapshot_create(
+                                       name);
+                       break;
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+                       snapshot = _lttng_session_descriptor_snapshot_local_create(
+                                       name, uris[0]);
+                       break;
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+                       snapshot = _lttng_session_descriptor_snapshot_network_create(
+                                       name, uris[0], uris[1]);
+                       break;
+               default:
+                       /* Already checked. */
+                       abort();
+               }
+               *descriptor = snapshot ? &snapshot->base : NULL;
+               break;
+       }
+       case LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE:
+       {
+               struct lttng_session_descriptor_live *live;
+
+               switch (output_type) {
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+                       live = _lttng_session_descriptor_live_create(
+                                       name, live_timer_us);
+                       break;
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+                       live = _lttng_session_descriptor_live_network_create(
+                                       name, uris[0], uris[1],
+                                       live_timer_us);
+                       break;
+               case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+                       ret = -1;
+                       goto end;
+               default:
+                       /* Already checked. */
+                       abort();
+               }
+               *descriptor = live ? &live->base : NULL;
+               break;
+       }
+       default:
+               /* Already checked. */
+               abort();
+       }
+       memset(uris, 0, sizeof(uris));
+       if (!*descriptor) {
+               ret = -1;
+               goto end;
+       }
+
+       ret = offset;
+end:
+       free(uris[0]);
+       free(uris[1]);
+       return ret;
+}
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_serialize(
+               const struct lttng_session_descriptor *descriptor,
+               struct lttng_dynamic_buffer *buffer)
+{
+       int ret, i;
+       /* There are, at most, two URIs to serialize. */
+       struct lttng_uri *uris[2] = {};
+       size_t uri_count = 0;
+       /* The live header is a superset of all headers. */
+       struct lttng_session_descriptor_live_comm header = {
+               .base.type = (uint8_t) descriptor->type,
+               .base.output_type = (uint8_t) descriptor->output_type,
+               .base.name_len = descriptor->name ?
+                               strlen(descriptor->name) + 1 : 0,
+       };
+       const void *header_ptr = NULL;
+       size_t header_size;
+
+       switch (descriptor->output_type) {
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+               uris[0] = descriptor->output.local;
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+               uris[0] = descriptor->output.network.control;
+               uris[1] = descriptor->output.network.data;
+               break;
+       default:
+               ret = -1;
+               goto end;
+       }
+       uri_count += !!uris[0];
+       uri_count += !!uris[1];
+
+       header.base.uri_count = uri_count;
+       if (descriptor->type == LTTNG_SESSION_DESCRIPTOR_TYPE_LIVE) {
+               const struct lttng_session_descriptor_live *live =
+                               container_of(descriptor, typeof(*live),
+                               base);
+
+               header.live_timer_us = live->live_timer_us;
+               header_ptr = &header;
+               header_size = sizeof(header);
+       } else {
+               header_ptr = &header.base;
+               header_size = sizeof(header.base);
+       }
+
+       ret = lttng_dynamic_buffer_append(buffer, header_ptr, header_size);
+       if (ret) {
+               goto end;
+       }
+       if (header.base.name_len) {
+               ret = lttng_dynamic_buffer_append(buffer, descriptor->name,
+                               header.base.name_len);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < uri_count; i++) {
+               ret = lttng_dynamic_buffer_append(buffer, uris[i],
+                               sizeof(struct lttng_uri));
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+enum lttng_session_descriptor_type
+lttng_session_descriptor_get_type(
+               const struct lttng_session_descriptor *descriptor)
+{
+       return descriptor->type;
+}
+
+LTTNG_HIDDEN
+enum lttng_session_descriptor_output_type
+lttng_session_descriptor_get_output_type(
+               const struct lttng_session_descriptor *descriptor)
+{
+       return descriptor->output_type;
+}
+
+LTTNG_HIDDEN
+void lttng_session_descriptor_get_local_output_uri(
+               const struct lttng_session_descriptor *descriptor,
+               struct lttng_uri *local_uri)
+{
+       memcpy(local_uri, descriptor->output.local, sizeof(*local_uri));
+}
+
+LTTNG_HIDDEN
+void lttng_session_descriptor_get_network_output_uris(
+               const struct lttng_session_descriptor *descriptor,
+               struct lttng_uri *control,
+               struct lttng_uri *data)
+{
+       memcpy(control, descriptor->output.network.control, sizeof(*control));
+       memcpy(data, descriptor->output.network.data, sizeof(*data));
+}
+
+LTTNG_HIDDEN
+unsigned long long
+lttng_session_descriptor_live_get_timer_interval(
+               const struct lttng_session_descriptor *descriptor)
+{
+       struct lttng_session_descriptor_live *live;
+
+       live = container_of(descriptor, typeof(*live), base);
+       return live->live_timer_us;
+}
+
+enum lttng_session_descriptor_status
+lttng_session_descriptor_get_session_name(
+               const struct lttng_session_descriptor *descriptor,
+               const char **session_name)
+{
+       enum lttng_session_descriptor_status status;
+
+       if (!descriptor || !session_name) {
+               status = LTTNG_SESSION_DESCRIPTOR_STATUS_INVALID;
+               goto end;
+       }
+
+       *session_name = descriptor->name;
+       status = descriptor->name ?
+                       LTTNG_SESSION_DESCRIPTOR_STATUS_OK :
+                       LTTNG_SESSION_DESCRIPTOR_STATUS_UNSET;
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+int lttng_session_descriptor_set_session_name(
+               struct lttng_session_descriptor *descriptor,
+               const char *name)
+{
+       int ret = 0;
+       char *new_name;
+
+       if (!name) {
+               goto end;
+       }
+       if (strlen(name) >= LTTNG_NAME_MAX) {
+               ret = -1;
+               goto end;
+       }
+       new_name = strdup(name);
+       if (!new_name) {
+               ret = -1;
+               goto end;
+       }
+       free(descriptor->name);
+       descriptor->name = new_name;
+end:
+       return ret;
+}
+
+LTTNG_HIDDEN
+bool lttng_session_descriptor_is_output_destination_initialized(
+               const struct lttng_session_descriptor *descriptor)
+{
+       switch (descriptor->output_type) {
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+               return true;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+               return descriptor->output.local;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+               return descriptor->output.network.control;
+       default:
+               abort();
+       }
+}
+
+LTTNG_HIDDEN
+bool lttng_session_descriptor_has_output_directory(
+               const struct lttng_session_descriptor *descriptor)
+{
+       switch (descriptor->output_type) {
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+               if (descriptor->output.local) {
+                       return *descriptor->output.local->dst.path;
+               }
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+               if (descriptor->output.network.control) {
+                       return *descriptor->output.network.control->subdir;
+               }
+               break;
+       default:
+               abort();
+       }
+       return false;
+}
+
+LTTNG_HIDDEN
+enum lttng_error_code lttng_session_descriptor_set_default_output(
+               struct lttng_session_descriptor *descriptor,
+               time_t *session_creation_time,
+               const char *absolute_home_path)
+{
+       enum lttng_error_code ret_code = LTTNG_OK;
+       struct lttng_uri *uris = NULL;
+
+       switch (descriptor->output_type) {
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+               goto end;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+       {
+               int ret;
+               ssize_t uri_ret;
+               char local_uri[LTTNG_PATH_MAX];
+               char creation_datetime_suffix[17] = {};
+
+               if (session_creation_time) {
+                       size_t strftime_ret;
+                       struct tm *timeinfo;
+
+                       timeinfo = localtime(session_creation_time);
+                       if (!timeinfo) {
+                               ret_code = LTTNG_ERR_FATAL;
+                               goto end;
+                       }
+                       strftime_ret = strftime(creation_datetime_suffix,
+                                       sizeof(creation_datetime_suffix),
+                                       "-%Y%m%d-%H%M%S", timeinfo);
+                       if (strftime_ret == 0) {
+                               ERR("Failed to format session creation timestamp while setting default local output destination");
+                               ret_code = LTTNG_ERR_FATAL;
+                               goto end;
+                       }
+               }
+               assert(descriptor->name);
+               ret = snprintf(local_uri, sizeof(local_uri),
+                               "file://%s/%s/%s%s",
+                               absolute_home_path,
+                               DEFAULT_TRACE_DIR_NAME, descriptor->name,
+                               creation_datetime_suffix);
+               if (ret >= sizeof(local_uri)) {
+                       ERR("Truncation occurred while setting default local output destination");
+                       ret_code = LTTNG_ERR_SET_URL;
+                       goto end;
+               } else if (ret < 0) {
+                       PERROR("Failed to format default local output URI");
+                       ret_code = LTTNG_ERR_SET_URL;
+                       goto end;
+               }
+
+               uri_ret = uri_parse(local_uri, &uris);
+               if (uri_ret != 1) {
+                       ret_code = LTTNG_ERR_SET_URL;
+                       goto end;
+               }
+               free(descriptor->output.local);
+               descriptor->output.local = &uris[0];
+               uris = NULL;
+               break;
+       }
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+       {
+               int ret;
+               ssize_t uri_ret;
+               struct lttng_uri *control = NULL, *data = NULL;
+
+               uri_ret = uri_parse_str_urls("net://127.0.0.1", NULL, &uris);
+               if (uri_ret != 2) {
+                       ret_code = LTTNG_ERR_SET_URL;
+                       goto end;
+               }
+
+               control = uri_copy(&uris[0]);
+               data = uri_copy(&uris[1]);
+               if (!control || !data) {
+                       free(control);
+                       free(data);
+                       ret_code = LTTNG_ERR_SET_URL;
+                       goto end;
+               }
+
+               /* Ownership of uris is transferred. */
+               ret = network_location_set_from_lttng_uris(
+                               &descriptor->output.network,
+                               control, data);
+               if (ret) {
+                       abort();
+                       ret_code = LTTNG_ERR_SET_URL;
+                       goto end;
+               }
+               break;
+       }
+       default:
+               abort();
+       }
+end:
+       free(uris);
+       return ret_code;
+}
+
+/*
+ * Note that only properties that can be populated by the session daemon
+ * (output destination and name) are assigned.
+ */
+LTTNG_HIDDEN
+int lttng_session_descriptor_assign(
+               struct lttng_session_descriptor *dst,
+               const struct lttng_session_descriptor *src)
+{
+       int ret = 0;
+
+       if (dst->type != src->type) {
+               ret = -1;
+               goto end;
+       }
+       if (dst->output_type != src->output_type) {
+               ret = -1;
+               goto end;
+       }
+       ret = lttng_session_descriptor_set_session_name(dst, src->name);
+       if (ret) {
+               goto end;
+       }
+       switch (dst->output_type) {
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_LOCAL:
+               free(dst->output.local);
+               dst->output.local = uri_copy(src->output.local);
+               if (!dst->output.local) {
+                       ret = -1;
+                       goto end;
+               }
+               break;
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NETWORK:
+       {
+               struct lttng_uri *control_copy = NULL, *data_copy = NULL;
+
+               control_copy = uri_copy(dst->output.network.control);
+               if (!control_copy && dst->output.network.control) {
+                       ret = -1;
+                       goto end;
+               }
+               data_copy = uri_copy(dst->output.network.data);
+               if (!data_copy && dst->output.network.data) {
+                       free(control_copy);
+                       ret = -1;
+                       goto end;
+               }
+               ret = network_location_set_from_lttng_uris(&dst->output.network,
+                               control_copy, data_copy);
+               break;
+       }
+       case LTTNG_SESSION_DESCRIPTOR_OUTPUT_TYPE_NONE:
+               goto end;
+       }
+end:
+       return ret;
+}
This page took 0.035817 seconds and 5 git commands to generate.