len = vstream->stream->metadata_received - vstream->metadata_sent;
if (len == 0) {
+ /*
+ * The live viewers expect to receive a NO_NEW_METADATA
+ * status before a stream disappears, otherwise they abort the
+ * entire live connection when receiving an error status.
+ */
reply.status = htobe32(LTTNG_VIEWER_NO_NEW_METADATA);
+ /*
+ * The live viewer considers a closed 0 byte metadata stream as
+ * an error.
+ */
+ if (vstream->metadata_sent > 0) {
+ vstream->stream->no_new_metadata_notified = true;
+ if (vstream->stream->closed) {
+ /* Release ownership for the viewer metadata stream. */
+ viewer_stream_put(vstream);
+ }
+ }
goto send_reply;
}
goto error;
}
vstream->metadata_sent += read_len;
- if (vstream->metadata_sent == vstream->stream->metadata_received
- && vstream->stream->closed) {
- /* Release ownership for the viewer metadata stream. */
- viewer_stream_put(vstream);
- }
-
reply.status = htobe32(LTTNG_VIEWER_METADATA_OK);
goto send_reply;
vstream = viewer_stream_get_by_id(stream->stream_handle);
if (vstream) {
- if (vstream->metadata_sent == stream->metadata_received) {
+ if (stream->no_new_metadata_notified) {
/*
* Since all the metadata has been sent to the
* viewer and that we have a request to close
}
if (stream->is_metadata) {
- stream->metadata_received += packet ? packet->size : 0;
- stream->metadata_received += padding_len;
+ size_t recv_len;
+
+ recv_len = packet ? packet->size : 0;
+ recv_len += padding_len;
+ stream->metadata_received += recv_len;
+ if (recv_len) {
+ stream->no_new_metadata_notified = false;
+ }
}
DBG("Wrote to %sstream %" PRIu64 ": data_length = %zu, padding_length = %zu",
struct cds_list_head recv_node;
/* Protected by session lock. */
bool published;
+ /* Notified viewer that no new metadata is available. */
+ bool no_new_metadata_notified;
/*
* Node of stream within global stream hash table.
*/