X-Git-Url: https://git.lttng.org/?a=blobdiff_plain;f=src%2Fcommon%2Fsession-descriptor.cpp;fp=src%2Fcommon%2Fsession-descriptor.cpp;h=ec510b0c6e392b1299f27dee414551bc64e7a03d;hb=a6bc4ca9d659caf016ef932fcd944029737ac57c;hp=0000000000000000000000000000000000000000;hpb=97535efaa975ca52bf02c2d5e76351bfd2e3defa;p=lttng-tools.git diff --git a/src/common/session-descriptor.cpp b/src/common/session-descriptor.cpp new file mode 100644 index 000000000..ec510b0c6 --- /dev/null +++ b/src/common/session-descriptor.cpp @@ -0,0 +1,1157 @@ +/* + * Copyright (C) 2019 Jérémie Galarneau + * + * SPDX-License-Identifier: GPL-2.0-only + */ + +#include +#include +#include +#include +#include +#include +#include + +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 = (lttng_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 = (lttng_uri *) zmalloc(sizeof(*control_uri)); + data_uri = (lttng_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 = (lttng_session_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 = (lttng_session_descriptor_snapshot *) 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 = (lttng_session_descriptor_live *) 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); + if (!descriptor) { + goto error; + } + + 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); + + return descriptor ? &descriptor->base : 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); +} + +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)); + if (!lttng_buffer_view_is_valid(¤t_view)) { + ret = -1; + goto end; + } + + base_header = (typeof(base_header)) current_view.data; + 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)); + if (!lttng_buffer_view_is_valid(¤t_view)) { + ret = -1; + goto end; + } + + live_header = (typeof(live_header)) current_view.data; + live_timer_us = live_header->live_timer_us; + break; + } + default: + ret = -1; + goto end; + } + /* type has been validated. */ + type = (lttng_session_descriptor_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 = (lttng_session_descriptor_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); + if (!lttng_buffer_view_is_valid(¤t_view)) { + ret = -1; + goto end; + } + + name = current_view.data; + 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)); + if (!lttng_buffer_view_is_valid(¤t_view)) { + ret = -1; + goto end; + } + + uri = (typeof(uri)) current_view.data; + uris[i] = (lttng_uri *) 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; +} + +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, + .output_type = (uint8_t) descriptor->output_type, + .name_len = (uint32_t) (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; +} + +enum lttng_session_descriptor_type +lttng_session_descriptor_get_type( + const struct lttng_session_descriptor *descriptor) +{ + return descriptor->type; +} + +enum lttng_session_descriptor_output_type +lttng_session_descriptor_get_output_type( + const struct lttng_session_descriptor *descriptor) +{ + return descriptor->output_type; +} + +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)); +} + +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)); +} + +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; +} + +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; +} + +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(); + } +} + +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; +} + +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; + } + } + LTTNG_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. + */ +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; +}