#define LTTNG_TRACE_FORMAT_DESCRIPTOR_H
#include <inttypes.h>
+#include <lttng/domain.h>
+#include <lttng/lttng-error.h>
#include <lttng/lttng-export.h>
#ifdef __cplusplus
#endif
struct lttng_trace_format_descriptor;
+enum lttng_domain_type;
enum lttng_trace_format_descriptor_status {
LTTNG_TRACE_FORMAT_DESCRIPTOR_STATUS_INVALID = -1,
LTTNG_EXPORT void lttng_trace_format_descriptor_destroy(
struct lttng_trace_format_descriptor *descriptor);
+/*
+ * Check if the passed trace format is supported for the passed domain.
+ */
+LTTNG_EXPORT extern enum lttng_error_code lttng_domain_supports_trace_format(
+ const struct lttng_endpoint *session_daemon_endpoint,
+ enum lttng_domain_type domain_type,
+ const struct lttng_trace_format_descriptor *trace_format_descriptor);
+
+/*
+ * For network destinations targeting a relay daemon, the session daemon will
+ * establish a connection to check for the capability at the time of the call.
+ * Note that the relay daemon at the destination address may be replaced by
+ * the time tracing starts.
+ *
+ * When destination url is a network destination (relayd), the following
+ * URL format is expected:
+ * NETPROTO://(HOST | IPADDR)[:CTRLPORT[:DATAPORT]][/TRACEPATH]
+ *
+ * Always returns LTTNG_OK for local destinations.
+ */
+LTTNG_EXPORT extern enum lttng_error_code lttng_destination_supports_trace_format(
+ const struct lttng_endpoint *session_daemon_endpoint,
+ const char *destination_url,
+ const struct lttng_trace_format_descriptor *trace_format_descriptor);
#ifdef __cplusplus
}
case LTTNG_EXECUTE_ERROR_QUERY:
need_domain = false;
break;
+ case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY:
+ need_domain = cmd_ctx->lsm.u.trace_format_support_query.query_type == 0;
+ break;
default:
need_domain = true;
}
case LTTNG_REGISTER_TRIGGER:
case LTTNG_UNREGISTER_TRIGGER:
case LTTNG_EXECUTE_ERROR_QUERY:
+ case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY:
need_consumerd = false;
break;
default:
case LTTNG_UNREGISTER_TRIGGER:
case LTTNG_LIST_TRIGGERS:
case LTTNG_EXECUTE_ERROR_QUERY:
+ case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY:
need_tracing_session = false;
break;
default:
break;
}
+ case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY:
+ {
+ ret = cmd_execute_trace_format_support_query(*cmd_ctx, *sock, *sock_error);
+ break;
+ }
default:
ret = LTTNG_ERR_UND;
break;
consumer->relay_major_version = control_sock->major;
consumer->relay_minor_version = control_sock->minor;
- ret = relayd_get_configuration(control_sock, 0, result_flags, nullptr);
+ ret = relayd_get_configuration(control_sock,
+ LTTCOMM_RELAYD_CONFIGURATION_QUERY_FLAG_SUPPORTED_TRACE_FORMAT,
+ result_flags, &supported_trace_format);
if (ret < 0) {
ERR("Unable to get relayd configuration");
status = LTTNG_ERR_RELAYD_CONNECT_FAIL;
return ret;
}
+enum lttng_error_code cmd_execute_trace_format_support_query(
+ struct command_ctx& cmd_ctx, int sock, int& sock_error)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ struct lttng_payload query_payload;
+ size_t payload_len, offset = 0;
+ ssize_t sock_recv_len, consumed;
+
+ lttng::trace_format_descriptor::uptr trace_format;
+
+ lttng_payload_init(&query_payload);
+
+ /* Receive the payload */
+ payload_len = (size_t) cmd_ctx.lsm.u.trace_format_support_query.trace_format_length +
+ cmd_ctx.lsm.u.trace_format_support_query.type_payload_length;
+ ret = lttng_dynamic_buffer_set_size(&query_payload.buffer, payload_len);
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ }
+
+ sock_recv_len = lttcomm_recv_unix_sock(sock, query_payload.buffer.data, payload_len);
+ if (sock_recv_len < 0 || sock_recv_len != payload_len) {
+ ERR("Failed to receive error query in command payload");
+ sock_error = 1;
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+
+ /* Receive fds, if any. */
+ if (cmd_ctx.lsm.fd_count > 0) {
+ sock_recv_len = lttcomm_recv_payload_fds_unix_sock(
+ sock, cmd_ctx.lsm.fd_count, &query_payload);
+ if (sock_recv_len > 0 && sock_recv_len != cmd_ctx.lsm.fd_count * sizeof(int)) {
+ ERR("Failed to receive all file descriptors for error query in command payload: expected fd count = %u, ret = %d",
+ cmd_ctx.lsm.fd_count, (int) ret);
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ sock_error = 1;
+ goto end;
+ } else if (sock_recv_len <= 0) {
+ ERR("Failed to receive file descriptors for error query in command payload: expected fd count = %u, ret = %d",
+ cmd_ctx.lsm.fd_count, (int) ret);
+ ret_code = LTTNG_ERR_FATAL;
+ sock_error = 1;
+ goto end;
+ }
+ }
+
+ /* Deserialize trace_format_descriptor. */
+ {
+ struct lttng_payload_view view =
+ lttng_payload_view_from_payload(&query_payload, offset, -1);
+ if (!lttng_payload_view_is_valid(&view)) {
+ ret = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+
+ consumed = lttng::trace_format_descriptor::create_from_payload(&view, trace_format);
+
+ if (consumed != cmd_ctx.lsm.u.trace_format_support_query.trace_format_length) {
+ ERR("Invalid trace format descriptor received as part of command payload");
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+ offset += consumed;
+ }
+
+ switch (cmd_ctx.lsm.u.trace_format_support_query.query_type) {
+ case 0:
+ {
+ if (cmd_ctx.lsm.domain.type != LTTNG_DOMAIN_KERNEL) {
+ /* UST supports all trace format*/
+ ret_code = LTTNG_OK;
+ goto end;
+ }
+ ret_code = kernel_domain_check_trace_format_requirements(*trace_format);
+ break;
+ }
+ case 1:
+ {
+ struct lttcomm_relayd_sock *relay_sock = nullptr;
+ struct lttng_uri uri;
+ uint64_t result_flags = 0;
+ uint64_t supported_trace_format = 0;
+ struct lttng_payload_view view = lttng_payload_view_from_payload(&query_payload,
+ offset,
+ cmd_ctx.lsm.u.trace_format_support_query.type_payload_length);
+ if (!lttng_payload_view_is_valid(&view)) {
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+
+ memcpy(&uri, view.buffer.data, sizeof(uri));
+ ret_code = create_connect_relayd(&uri, &relay_sock);
+ if (ret_code != LTTNG_OK) {
+ goto end;
+ }
+ LTTNG_ASSERT(sock);
+
+ ret_code = relayd_get_configuration(relay_sock,
+ LTTCOMM_RELAYD_CONFIGURATION_QUERY_FLAG_SUPPORTED_TRACE_FORMAT,
+ result_flags, &supported_trace_format);
+ if (ret_code != LTTNG_OK) {
+ goto end;
+ }
+
+ if (!(supported_trace_format & trace_format->relayd_type())) {
+ ERR("Relayd does not support the requested trace format");
+ ret_code = LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_RELAY_DAEMON;
+ goto end;
+ }
+
+ ret_code = LTTNG_OK;
+ break;
+ }
+ default:
+ {
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ break;
+ }
+ }
+end:
+ lttng_payload_reset(&query_payload);
+ return ret_code;
+}
+
/* Wait for a given path to be removed before continuing. */
static enum lttng_error_code wait_on_path(void *path_data)
{
struct lttng_error_query_results **_results,
struct notification_thread_handle *notification_thread);
+enum lttng_error_code cmd_execute_trace_format_support_query(
+ struct command_ctx& cmd_ctx, int sock, int& sock_error);
+
int cmd_rotate_session(struct ltt_session *session,
struct lttng_rotate_session_return *rotate_return,
bool quiet_rotation,
}
}
+ ret = (int) session->trace_format->config_serialize(writer);
+ if (ret != LTTNG_OK) {
+ goto end;
+ }
+
ret = save_domains(writer, session);
if (ret != LTTNG_OK) {
goto end;
goto error;
}
}
+
end:
free(uris);
return descriptor;
goto end;
}
+static int trace_format_check(struct lttng_session_descriptor& descriptor)
+{
+ int ret = 0;
+ enum lttng_error_code ret_code;
+ const lttng_trace_format_descriptor *trace_format_descriptor = nullptr;
+ enum lttng_session_descriptor_status status;
+ std::string destination;
+
+ status = lttng_session_descriptor_get_trace_format_descriptor(
+ &descriptor, &trace_format_descriptor);
+ if (status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ /*
+ * Only check kernel domain since only the kernel tracer can lag behind
+ * in term of feature.
+ */
+
+ ret_code = lttng_domain_supports_trace_format(lttng_session_daemon_command_endpoint,
+ LTTNG_DOMAIN_KERNEL, trace_format_descriptor);
+ if (ret_code == LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_KERNEL_TRACER) {
+ WARN("%s", lttng_strerror(ret_code));
+ } else if (ret_code == LTTNG_ERR_KERN_NA || ret_code == LTTNG_ERR_NEED_ROOT_SESSIOND) {
+ /*
+ * Not an error, kernel tracers is simply not available at that
+ * time. Next operation will fail as necessary.
+ */
+ DBG("Kernel tracer not available for trace format support check");
+ } else if (ret_code != LTTNG_OK) {
+ ERR("Failed to validate trace format support: %s", lttng_strerror(ret_code));
+ ret = -1;
+ goto end;
+ }
+
+ if (opt_output_path) {
+ char *tmp = utils_expand_path(opt_output_path);
+ if (!tmp) {
+ ret = -1;
+ goto end;
+ }
+ destination = tmp;
+ free(tmp);
+ } else if (opt_url || opt_ctrl_url) {
+ destination = opt_ctrl_url ? opt_ctrl_url : opt_url;
+ } else if (opt_live_timer) {
+ destination = "tcp://127.0.0.1";
+ }
+
+ if (!destination.empty()) {
+ ret_code = lttng_destination_supports_trace_format(
+ lttng_session_daemon_command_endpoint, destination.c_str(),
+ trace_format_descriptor);
+ if (ret_code == LTTNG_ERR_TRACE_FORMAT_UNSUPPORTED_RELAY_DAEMON) {
+ WARN("%s", lttng_strerror(ret_code));
+ } else if (ret_code == LTTNG_ERR_RELAYD_CONNECT_FAIL) {
+ DBG("Could not validate trace format support: %s",
+ lttng_strerror(ret_code));
+ } else if (ret_code != LTTNG_OK) {
+ ERR("Failed to validate trace format support: %s",
+ lttng_strerror(ret_code));
+ ret = -1;
+ goto end;
+ }
+ }
+
+end:
+ return ret;
+}
+
/*
* Create a tracing session.
* If no name is specified, a default name is generated.
ret = CMD_ERROR;
goto error;
}
+
ret_code = lttng_create_session_ext(session_descriptor);
if (ret_code != LTTNG_OK) {
ERR("%s", lttng_strerror(-ret_code));
goto error;
}
+ ret = trace_format_check(*session_descriptor);
+ if (ret < 0) {
+ ret = CMD_ERROR;
+ goto error;
+ }
+
descriptor_status = lttng_session_descriptor_get_session_name(
- session_descriptor, &created_session_name);
+ session_descriptor, &created_session_name);
if (descriptor_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) {
ERR("Failed to obtain created session name");
ret = CMD_ERROR;
*/
#define _LGPL_SOURCE
-#include <stdlib.h>
+#include <arpa/inet.h>
#include <ctype.h>
+#include <inttypes.h>
#include <limits.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <signal.h>
#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <inttypes.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <common/error.hpp>
* Spawn session daemon and tell
* it to signal us when ready.
*/
- execlp(pathname, "lttng-relayd", "-L", url, NULL);
+ execlp(pathname, "lttng-relayd", "-L", url, "--daemonize", NULL);
/* execlp only returns if error happened */
if (errno == ENOENT) {
ERR("No relayd found. Use --relayd-path.");
} else {
PERROR("execlp");
}
- kill(getppid(), SIGTERM); /* wake parent */
+ kill(getppid(), SIGTERM); /* wake parent */
exit(EXIT_FAILURE);
} else if (pid > 0) {
+ /*
+ * In daemon mode (--daemonize), lttng-relayd only exits when
+ * it's ready to accept commands.
+ */
+ for (;;) {
+ int status;
+ pid_t wait_pid_ret = waitpid(pid, &status, 0);
+
+ if (wait_pid_ret < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ PERROR("waitpid");
+ ret = -errno;
+ goto end;
+ }
+
+ if (WIFSIGNALED(status)) {
+ ERR("Relay daemon was killed by signal %d", WTERMSIG(status));
+ ret = -1;
+ goto end;
+ } else if (WIFEXITED(status)) {
+ DBG("Relay daemon terminated normally (exit status: %d)",
+ WEXITSTATUS(status));
+
+ if (WEXITSTATUS(status) != 0) {
+ ERR("Relay daemon terminated with an error (exit status: %d)",
+ WEXITSTATUS(status));
+ ret = -1;
+ goto end;
+ }
+ break;
+ }
+ }
+
goto end;
} else {
PERROR("fork");
return ret;
}
-static
-int create_snapshot_session(const char *session_name, xmlNodePtr output_node,
- const struct config_load_session_override_attr *overrides)
+static int create_snapshot_session(const char *session_name,
+ xmlNodePtr output_node,
+ const struct config_load_session_override_attr *overrides,
+ const struct lttng_trace_format_descriptor *trace_format_descriptor)
{
int ret;
enum lttng_error_code ret_code;
goto end;
}
+ if (trace_format_descriptor != nullptr) {
+ enum lttng_session_descriptor_status s_status;
+ s_status = lttng_session_descriptor_set_trace_format_descriptor(
+ session_descriptor, trace_format_descriptor);
+ if (s_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+ }
+
ret_code = lttng_create_session_ext(session_descriptor);
if (ret_code != LTTNG_OK) {
ret = -ret_code;
return ret;
}
-static
-int create_session(const char *name,
- xmlNodePtr output_node,
- uint64_t live_timer_interval,
- const struct config_load_session_override_attr *overrides)
+static int create_session(const char *name,
+ xmlNodePtr output_node,
+ uint64_t live_timer_interval,
+ const struct config_load_session_override_attr *overrides,
+ const struct lttng_trace_format_descriptor *trace_format_descriptor)
{
int ret = 0;
enum lttng_error_code ret_code;
goto end;
}
+ if (trace_format_descriptor != nullptr) {
+ enum lttng_session_descriptor_status s_status;
+ s_status = lttng_session_descriptor_set_trace_format_descriptor(
+ session_descriptor, trace_format_descriptor);
+ if (s_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+ }
+
ret_code = lttng_create_session_ext(session_descriptor);
if (ret_code != LTTNG_OK) {
ret = -ret_code;
return ret;
}
+/* TODO: this could most probably be moved to a similar scheme to create_from_buffer/payload for the
+ * lttng::trace_format_descriptor object */
+static int process_trace_format_descriptor_node(xmlNodePtr trace_format_descriptor_node,
+ struct lttng_trace_format_descriptor **descriptor)
+{
+ int ret;
+ xmlNodePtr node;
+ struct lttng_trace_format_descriptor *local_descriptor = nullptr;
+ struct lttng_trace_format_descriptor *(*constructor)(void) = nullptr;
+
+ for (node = xmlFirstElementChild(trace_format_descriptor_node); node;
+ node = xmlNextElementSibling(node)) {
+ if (!strcmp((const char *) node->name, config_element_session_trace_format_ctf1)) {
+ constructor = lttng_trace_format_ctf_1_descriptor_create;
+ break;
+ } else if (!strcmp((const char *) node->name,
+ config_element_session_trace_format_ctf2)) {
+ constructor = lttng_trace_format_ctf_2_descriptor_create;
+ break;
+ }
+ }
+
+ if (constructor == nullptr) {
+ ret = -LTTNG_ERR_LOAD_INVALID_CONFIG;
+ goto end;
+ }
+
+ local_descriptor = constructor();
+
+ if (local_descriptor == nullptr) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ *descriptor = local_descriptor;
+ local_descriptor = nullptr;
+ ret = 0;
+
+end:
+ lttng_trace_format_descriptor_destroy(local_descriptor);
+ return ret;
+}
+
static
int process_session_node(xmlNodePtr session_node, const char *session_name,
int overwrite,
struct lttng_domain *jul_domain = NULL;
struct lttng_domain *log4j_domain = NULL;
struct lttng_domain *python_domain = NULL;
+ struct lttng_trace_format_descriptor *trace_format_descriptor = nullptr;
for (node = xmlFirstElementChild(session_node); node;
node = xmlNextElementSibling(node)) {
}
shm_path = node_content;
+ } else if (!trace_format_descriptor &&
+ !strcmp((const char *) node->name,
+ config_element_session_trace_format)) {
+ ret = process_trace_format_descriptor_node(node, &trace_format_descriptor);
+ if (ret) {
+ goto error;
+ }
} else {
/*
* attributes, snapshot_mode, live_timer_interval, rotation_size,
/* Create session type depending on output type */
if (snapshot_mode && snapshot_mode != -1) {
- ret = create_snapshot_session((const char *) name, output_node,
- overrides);
+ ret = create_snapshot_session((const char *) name, output_node, overrides,
+ trace_format_descriptor);
} else if (live_timer_interval &&
live_timer_interval != UINT64_MAX) {
- ret = create_session((const char *) name,
- output_node, live_timer_interval, overrides);
+ ret = create_session((const char *) name, output_node, live_timer_interval,
+ overrides, trace_format_descriptor);
} else {
/* regular session */
- ret = create_session((const char *) name,
- output_node, UINT64_MAX, overrides);
+ ret = create_session((const char *) name, output_node, UINT64_MAX, overrides,
+ trace_format_descriptor);
}
if (ret) {
goto error;
}
error:
+ lttng_trace_format_descriptor_destroy(trace_format_descriptor);
free(kernel_domain);
free(ust_domain);
free(jul_domain);
if (ret < 0) {
PERROR("Failed to send command %s of size %" PRIu64,
lttcomm_relayd_command_str(cmd), buf_size);
- ret = rsock->sock.ops->sendmsg(&rsock->sock, buf, buf_size, flags);
ret = -errno;
goto error;
}
</xs:choice>
</xs:complexType>
+ <!-- Maps to a lttng_event_rule. -->
+ <xs:complexType name="trace_format_descriptor_type">
+ <xs:all>
+ <xs:element ref="trace_format_descriptor_sub_type" minOccurs="1" />
+ </xs:all>
+ </xs:complexType>
+
+ <!-- Maps to a lttng_trace_format_descriptor subtypes -->
+ <xs:element name="trace_format_descriptor_sub_type" abstract="true"/>
+ <xs:element name="ctf1" type="trace_format_descriptor_ctf1_type" substitutionGroup="trace_format_descriptor_sub_type" />
+ <xs:element name="ctf2" type="trace_format_descriptor_ctf2_type" substitutionGroup="trace_format_descriptor_sub_type" />
+
+ <!-- Maps to a lttng_trace_format_ctf1_descriptor. -->
+ <xs:complexType name="trace_format_descriptor_ctf1_type">
+ <xs:all>
+ </xs:all>
+ </xs:complexType>
+
+ <!-- Maps to a lttng_trace_format_ctf2_descriptor. -->
+ <xs:complexType name="trace_format_descriptor_ctf2_type">
+ <xs:all>
+ </xs:all>
+ </xs:complexType>
+
<xs:complexType name="session_type">
<xs:all>
<xs:element name="name" type="name_type"/>
<xs:element name="started" type="xs:boolean" default="0" minOccurs="0"/>
<xs:element name="attributes" type="session_attributes_type" minOccurs="0"/>
<xs:element name="output" type="session_output_type" minOccurs="0"/>
+ <xs:element name="trace_format" type="trace_format_descriptor_type" minOccurs="0" />
</xs:all>
</xs:complexType>
#include <common/optional.hpp>
#define RELAYD_VERSION_COMM_MAJOR VERSION_MAJOR
-#define RELAYD_VERSION_COMM_MINOR VERSION_MINOR
+/* FIXME: remove, SPOOFING VERSION as 2.15 */
+//#define RELAYD_VERSION_COMM_MINOR VERSION_MINOR
+#define RELAYD_VERSION_COMM_MINOR 15
#define RELAYD_COMM_LTTNG_HOST_NAME_MAX_2_4 64
#define RELAYD_COMM_LTTNG_NAME_MAX_2_4 255
LTTNG_CLEAR_SESSION = 50,
LTTNG_LIST_TRIGGERS = 51,
LTTNG_EXECUTE_ERROR_QUERY = 52,
+ LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY = 53,
};
static inline
return "LTTNG_LIST_TRIGGERS";
case LTTNG_EXECUTE_ERROR_QUERY:
return "LTTNG_EXECUTE_ERROR_QUERY";
+ case LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY:
+ return "LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY";
default:
abort();
}
uint64_t session_descriptor_size;
/* An lttng_session_descriptor follows. */
} LTTNG_PACKED create_session;
+ struct {
+ uint32_t query_type;
+ uint32_t type_payload_length;
+ uint32_t trace_format_length;
+ } LTTNG_PACKED trace_format_support_query;
+
} u;
/* Count of fds sent. */
uint32_t fd_count;
lttng_create_session_live
lttng_create_session_snapshot
lttng_data_pending
+lttng_destination_supports_trace_format
lttng_destroy_handle
lttng_destroy_session
lttng_destroy_session_ext
lttng_disable_consumer
lttng_disable_event
lttng_disable_event_ext
+lttng_domain_supports_trace_format
lttng_elf_get_sdt_probe_offsets
lttng_elf_get_symbol_offset
lttng_enable_channel
{
free(tracing_group);
}
+
+LTTNG_EXPORT enum lttng_error_code lttng_domain_supports_trace_format(
+ const struct lttng_endpoint *session_daemon_endpoint,
+ enum lttng_domain_type domain_type,
+ const struct lttng_trace_format_descriptor *trace_format_descriptor)
+{
+ int ret;
+ enum lttng_error_code ret_code;
+ struct lttcomm_session_msg lsm = {
+ .cmd_type = LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY,
+ .session = {},
+ .domain = {},
+ .u = {},
+ .fd_count = 0,
+ };
+ struct lttng_payload message;
+ struct lttng_payload reply;
+ struct lttcomm_session_msg *message_lsm;
+
+ lttng_payload_init(&message);
+ lttng_payload_init(&reply);
+
+ if (!session_daemon_endpoint || !trace_format_descriptor) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ lsm.domain.type = domain_type;
+ lsm.u.trace_format_support_query.query_type = 0;
+ lsm.u.trace_format_support_query.type_payload_length = 0;
+
+ if (session_daemon_endpoint != lttng_session_daemon_command_endpoint) {
+ ret_code = LTTNG_ERR_INVALID_ERROR_QUERY_TARGET;
+ goto end;
+ }
+
+ ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ ret = reinterpret_cast<const lttng::trace_format_descriptor *>(trace_format_descriptor)
+ ->serialize(&message);
+ if (ret) {
+ ret_code = LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+ message_lsm->u.trace_format_support_query.trace_format_length =
+ (uint32_t) message.buffer.size - sizeof(lsm);
+
+ {
+ struct lttng_payload_view message_view =
+ lttng_payload_view_from_payload(&message, 0, -1);
+
+ message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(&message_view);
+ ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
+ if (ret < 0) {
+ ret_code = (lttng_error_code) -ret;
+ goto end;
+ }
+ if (ret != 0) {
+ /* No payload expected */
+ ret = LTTNG_ERR_INVALID_PROTOCOL;
+ }
+ }
+
+ ret_code = LTTNG_OK;
+end:
+ lttng_payload_reset(&message);
+ lttng_payload_reset(&reply);
+ return ret_code;
+}
+
+LTTNG_EXPORT extern enum lttng_error_code lttng_destination_supports_trace_format(
+ const struct lttng_endpoint *session_daemon_endpoint,
+ const char *destination_url,
+ const struct lttng_trace_format_descriptor *trace_format_descriptor)
+{
+ int ret;
+ ssize_t size;
+ enum lttng_error_code ret_code;
+ struct lttcomm_session_msg lsm = {
+ .cmd_type = LTTNG_EXECUTE_TRACE_FORMAT_SUPPORT_QUERY,
+ .session = {},
+ .domain = {},
+ .u = {},
+ .fd_count = 0,
+ };
+ struct lttng_payload message;
+ struct lttng_payload reply;
+ struct lttcomm_session_msg *message_lsm;
+ struct lttng_uri *uris = NULL;
+ size_t size_before_payload = 0;
+
+ lttng_payload_init(&message);
+ lttng_payload_init(&reply);
+
+ if (!session_daemon_endpoint || !trace_format_descriptor) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ size = uri_parse_str_urls(destination_url, NULL, &uris);
+ if (size < 1) {
+ ret_code = LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (uris[0].dtype == LTTNG_DST_PATH) {
+ /* Local output */
+ ret_code = LTTNG_OK;
+ goto end;
+ }
+
+ lsm.u.trace_format_support_query.query_type = 1;
+
+ if (session_daemon_endpoint != lttng_session_daemon_command_endpoint) {
+ ret_code = LTTNG_ERR_INVALID_ERROR_QUERY_TARGET;
+ goto end;
+ }
+
+ ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ size_before_payload = message.buffer.size;
+
+ ret = reinterpret_cast<const lttng::trace_format_descriptor *>(trace_format_descriptor)
+ ->serialize(&message);
+ if (ret) {
+ ret_code = LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+ message_lsm->u.trace_format_support_query.trace_format_length =
+ (uint32_t) message.buffer.size - size_before_payload;
+
+ /* FIXME replace all this with good old serialization of sub query type
+ * object. (internal) */
+ size_before_payload = message.buffer.size;
+ ret = lttng_dynamic_buffer_append(&message.buffer, &uris[0], sizeof(*uris));
+ if (ret) {
+ ret_code = LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+ message_lsm->u.trace_format_support_query.type_payload_length =
+ (uint32_t) message.buffer.size - size_before_payload;
+
+ {
+ struct lttng_payload_view message_view =
+ lttng_payload_view_from_payload(&message, 0, -1);
+
+ message_lsm->fd_count = lttng_payload_view_get_fd_handle_count(&message_view);
+ ret = lttng_ctl_ask_sessiond_payload(&message_view, &reply);
+ if (ret < 0) {
+ ret_code = (lttng_error_code) -ret;
+ goto end;
+ }
+ if (ret != 0) {
+ /* No payload expected */
+ ret_code = LTTNG_ERR_INVALID_PROTOCOL;
+ goto end;
+ }
+ }
+
+ ret_code = LTTNG_OK;
+end:
+ lttng_payload_reset(&message);
+ lttng_payload_reset(&reply);
+ return ret_code;
+}