+/*
+ * Open the index file if needed for the given vstream.
+ *
+ * If an index file is successfully opened, the vstream index_fd set with
+ * it.
+ *
+ * Return 0 on success, a negative value on error (-ENOENT if not ready yet).
+ *
+ * Called with rstream lock held.
+ */
+static int try_open_index(struct relay_viewer_stream *vstream,
+ struct relay_stream *rstream)
+{
+ int ret = 0;
+
+ if (vstream->index_fd) {
+ goto end;
+ }
+
+ /*
+ * First time, we open the index file and at least one index is ready.
+ */
+ if (rstream->total_index_received == 0) {
+ ret = -ENOENT;
+ goto end;
+ }
+ ret = index_open(vstream->path_name, vstream->channel_name,
+ vstream->stream->tracefile_count,
+ vstream->current_tracefile_id);
+ if (ret >= 0) {
+ vstream->index_fd = stream_fd_create(ret);
+ if (!vstream->index_fd) {
+ if (close(ret)) {
+ PERROR("close");
+ }
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+ goto end;
+ }
+
+end:
+ return ret;
+}
+
+/*
+ * Check the status of the index for the given stream. This function
+ * updates the index structure if needed and can put (close) the vstream
+ * in the HUP situation.
+ *
+ * Return 0 means that we can proceed with the index. A value of 1 means
+ * that the index has been updated and is ready to be sent to the
+ * client. A negative value indicates an error that can't be handled.
+ *
+ * Called with rstream lock held.
+ */
+static int check_index_status(struct relay_viewer_stream *vstream,
+ struct relay_stream *rstream, struct ctf_trace *trace,
+ struct lttng_viewer_index *index)
+{
+ int ret;
+
+ if (trace->session->connection_closed
+ && rstream->total_index_received
+ == vstream->last_sent_index) {
+ /* Last index sent and session connection is closed. */
+ index->status = htobe32(LTTNG_VIEWER_INDEX_HUP);
+ goto hup;
+ } else if (rstream->beacon_ts_end != -1ULL &&
+ rstream->total_index_received
+ == vstream->last_sent_index) {
+ /*
+ * We've received a synchronization beacon and the last index
+ * available has been sent, the index for now is inactive.
+ *
+ * In this case, we have received a beacon which allows us to
+ * inform the client of a time interval during which we can
+ * guarantee that there are no events to read (and never will
+ * be).
+ */
+ index->status = htobe32(LTTNG_VIEWER_INDEX_INACTIVE);
+ index->timestamp_end = htobe64(rstream->beacon_ts_end);
+ index->stream_id = htobe64(rstream->ctf_stream_id);
+ goto index_ready;
+ } else if (rstream->total_index_received <= vstream->last_sent_index) {
+ /*
+ * This actually checks the case where recv == last_sent.
+ * In this case, we have not received a beacon. Therefore, we
+ * can only ask the client to retry later.
+ */
+ index->status = htobe32(LTTNG_VIEWER_INDEX_RETRY);
+ goto index_ready;
+ } else if (!viewer_stream_is_tracefile_seq_readable(vstream,
+ vstream->current_tracefile_seq)) {
+ /*
+ * The producer has overwritten our current file. We
+ * need to rotate.
+ */
+ DBG("Viewer stream %" PRIu64 " rotation due to overwrite",
+ vstream->stream->stream_handle);
+ ret = viewer_stream_rotate(vstream);
+ if (ret < 0) {
+ goto end;
+ } else if (ret == 1) {
+ /* EOF across entire stream. */
+ index->status = htobe32(LTTNG_VIEWER_INDEX_HUP);
+ goto hup;
+ }
+ assert(viewer_stream_is_tracefile_seq_readable(vstream,
+ vstream->current_tracefile_seq));
+ /* ret == 0 means successful so we continue. */
+ ret = 0;
+ } else {
+ ssize_t read_ret;
+ char tmp[1];
+
+ /*
+ * Use EOF on current index file to find out when we
+ * need to rotate.
+ */
+ read_ret = lttng_read(vstream->index_fd->fd, tmp, 1);
+ if (read_ret == 1) {
+ off_t seek_ret;
+
+ /* There is still data to read. Rewind position. */
+ seek_ret = lseek(vstream->index_fd->fd, -1, SEEK_CUR);
+ if (seek_ret < 0) {
+ ret = -1;
+ goto end;
+ }
+ ret = 0;
+ } else if (read_ret == 0) {
+ /* EOF. We need to rotate. */
+ DBG("Viewer stream %" PRIu64 " rotation due to EOF",
+ vstream->stream->stream_handle);
+ ret = viewer_stream_rotate(vstream);
+ if (ret < 0) {
+ goto end;
+ } else if (ret == 1) {
+ /* EOF across entire stream. */
+ index->status = htobe32(LTTNG_VIEWER_INDEX_HUP);
+ goto hup;
+ }
+ assert(viewer_stream_is_tracefile_seq_readable(vstream,
+ vstream->current_tracefile_seq));
+ /* ret == 0 means successful so we continue. */
+ ret = 0;
+ } else {
+ /* Error reading index. */
+ ret = -1;
+ }
+ }
+end:
+ return ret;
+
+hup:
+ viewer_stream_put(vstream);
+index_ready:
+ return 1;
+}
+