+ ERR("get lost packets");
+ pthread_mutex_unlock(socket->lock);
+ goto end;
+ }
+ pthread_mutex_unlock(socket->lock);
+ *lost += consumer_lost;
+ }
+ ret = 0;
+ DBG("Consumer lost %" PRIu64 " packets in session id %" PRIu64,
+ *lost, session_id);
+
+end:
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Ask the consumer to rotate a channel.
+ *
+ * The new_chunk_id is the session->rotate_count that has been incremented
+ * when the rotation started. On the relay, this allows to keep track in which
+ * chunk each stream is currently writing to (for the rotate_pending operation).
+ */
+int consumer_rotate_channel(struct consumer_socket *socket, uint64_t key,
+ uid_t uid, gid_t gid, struct consumer_output *output,
+ bool is_metadata_channel)
+{
+ int ret;
+ struct lttcomm_consumer_msg msg;
+
+ assert(socket);
+
+ DBG("Consumer rotate channel key %" PRIu64, key);
+
+ pthread_mutex_lock(socket->lock);
+ memset(&msg, 0, sizeof(msg));
+ msg.cmd_type = LTTNG_CONSUMER_ROTATE_CHANNEL;
+ msg.u.rotate_channel.key = key;
+ msg.u.rotate_channel.metadata = !!is_metadata_channel;
+
+ if (output->type == CONSUMER_DST_NET) {
+ msg.u.rotate_channel.relayd_id = output->net_seq_index;
+ } else {
+ msg.u.rotate_channel.relayd_id = (uint64_t) -1ULL;
+ }
+
+ health_code_update();
+ ret = consumer_send_msg(socket, &msg);
+ if (ret < 0) {
+ switch (-ret) {
+ case LTTCOMM_CONSUMERD_CHAN_NOT_FOUND:
+ ret = -LTTNG_ERR_CHAN_NOT_FOUND;
+ break;
+ default:
+ ret = -LTTNG_ERR_ROTATION_FAIL_CONSUMER;
+ break;
+ }
+ goto error;
+ }
+error:
+ pthread_mutex_unlock(socket->lock);
+ health_code_update();
+ return ret;
+}
+
+int consumer_init(struct consumer_socket *socket,
+ const lttng_uuid sessiond_uuid)
+{
+ int ret;
+ struct lttcomm_consumer_msg msg = {
+ .cmd_type = LTTNG_CONSUMER_INIT,
+ };
+
+ assert(socket);
+
+ DBG("Sending consumer initialization command");
+ lttng_uuid_copy(msg.u.init.sessiond_uuid, sessiond_uuid);
+
+ health_code_update();
+ ret = consumer_send_msg(socket, &msg);
+ if (ret < 0) {
+ goto error;
+ }
+
+error:
+ health_code_update();
+ return ret;
+}
+
+/*
+ * Ask the consumer to create a new chunk for a given session.
+ *
+ * Called with the consumer socket lock held.
+ */
+int consumer_create_trace_chunk(struct consumer_socket *socket,
+ uint64_t relayd_id, uint64_t session_id,
+ struct lttng_trace_chunk *chunk)
+{
+ int ret;
+ enum lttng_trace_chunk_status chunk_status;
+ struct lttng_credentials chunk_credentials;
+ const struct lttng_directory_handle *chunk_directory_handle;
+ int chunk_dirfd;
+ const char *chunk_name;
+ bool chunk_name_overridden;
+ uint64_t chunk_id;
+ time_t creation_timestamp;
+ char creation_timestamp_buffer[ISO8601_STR_LEN];
+ const char *creation_timestamp_str = "(none)";
+ const bool chunk_has_local_output = relayd_id == -1ULL;
+ struct lttcomm_consumer_msg msg = {
+ .cmd_type = LTTNG_CONSUMER_CREATE_TRACE_CHUNK,
+ .u.create_trace_chunk.session_id = session_id,
+ };
+
+ assert(socket);
+ assert(chunk);
+
+ if (relayd_id != -1ULL) {
+ LTTNG_OPTIONAL_SET(&msg.u.create_trace_chunk.relayd_id,
+ relayd_id);
+ }
+
+ chunk_status = lttng_trace_chunk_get_name(chunk, &chunk_name,
+ &chunk_name_overridden);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK &&
+ chunk_status != LTTNG_TRACE_CHUNK_STATUS_NONE) {
+ ERR("Failed to get name of trace chunk");
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+ if (chunk_name_overridden) {
+ ret = lttng_strncpy(msg.u.create_trace_chunk.override_name,
+ chunk_name,
+ sizeof(msg.u.create_trace_chunk.override_name));
+ if (ret) {
+ ERR("Trace chunk name \"%s\" exceeds the maximal length allowed by the consumer protocol",
+ chunk_name);
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+ }
+
+ chunk_status = lttng_trace_chunk_get_creation_timestamp(chunk,
+ &creation_timestamp);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+ msg.u.create_trace_chunk.creation_timestamp =
+ (uint64_t) creation_timestamp;
+ /* Only used for logging purposes. */
+ ret = time_to_iso8601_str(creation_timestamp,
+ creation_timestamp_buffer,
+ sizeof(creation_timestamp_buffer));
+ creation_timestamp_str = !ret ? creation_timestamp_buffer :
+ "(formatting error)";
+
+ chunk_status = lttng_trace_chunk_get_id(chunk, &chunk_id);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ /*
+ * Anonymous trace chunks should never be transmitted
+ * to remote peers (consumerd and relayd). They are used
+ * internally for backward-compatibility purposes.
+ */
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+ msg.u.create_trace_chunk.chunk_id = chunk_id;
+
+ if (chunk_has_local_output) {
+ chunk_status = lttng_trace_chunk_get_chunk_directory_handle(
+ chunk, &chunk_directory_handle);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+
+ /*
+ * This will only compile on platforms that support
+ * dirfd (POSIX.2008). This is fine as the session daemon
+ * is only built for such platforms.
+ *
+ * The ownership of the chunk directory handle's is maintained
+ * by the trace chunk.
+ */
+ chunk_dirfd = lttng_directory_handle_get_dirfd(
+ chunk_directory_handle);
+ assert(chunk_dirfd >= 0);
+
+ chunk_status = lttng_trace_chunk_get_credentials(
+ chunk, &chunk_credentials);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ /*
+ * Not associating credentials to a sessiond chunk is a
+ * fatal internal error.
+ */
+ ret = -LTTNG_ERR_FATAL;
+ goto error;