tweak handling of data on unassigned channels

*   Call `note_stale_live555_data` when this happens in playing state.
    This makes it more consistent with what happens while waiting for
    a response in the described state, or in playing state on an
    assigned channel.
*   Print a hex dump of some initial bytes, enough to analyze it to
    see if it looks like RTP or RTCP, what the ssrc is, etc. And do the
    same for other places we log (parts of) packets.
This commit is contained in:
Scott Lamb 2022-04-05 13:09:05 -07:00
parent 1e733ab0c4
commit 1ee6d95cc3
7 changed files with 77 additions and 18 deletions

View File

@ -1803,11 +1803,19 @@ impl Session<Playing> {
}); });
let m = match conn.channels.lookup(channel_id) { let m = match conn.channels.lookup(channel_id) {
Some(m) => m, Some(m) => m,
None => bail!(ErrorInt::RtspUnassignedChannelError { None => {
conn_ctx: *conn.inner.ctx(), note_stale_live555_data(
msg_ctx: *msg_ctx, tokio::runtime::Handle::try_current().ok(),
channel_id, inner.presentation.tool.as_ref(),
}), inner.options,
);
bail!(ErrorInt::RtspUnassignedChannelError {
conn_ctx: *conn.inner.ctx(),
msg_ctx: *msg_ctx,
channel_id,
data: data.into_body(),
});
}
}; };
let stream = &mut inner.presentation.streams[m.stream_i]; let stream = &mut inner.presentation.streams[m.stream_i];
let (timeline, rtp_handler) = match &mut stream.state { let (timeline, rtp_handler) = match &mut stream.state {

View File

@ -5,7 +5,6 @@
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use log::{debug, trace}; use log::{debug, trace};
use pretty_hex::PrettyHex;
use crate::client::PacketItem; use crate::client::PacketItem;
use crate::{ConnectionContext, Error, ErrorInt, PacketContext}; use crate::{ConnectionContext, Error, ErrorInt, PacketContext};
@ -44,7 +43,7 @@ impl std::fmt::Debug for Packet {
.field("sequence_number", &self.sequence_number) .field("sequence_number", &self.sequence_number)
.field("loss", &self.loss) .field("loss", &self.loss)
.field("mark", &self.mark) .field("mark", &self.mark)
.field("payload", &self.payload.hex_dump()) .field("payload", &crate::hex::LimitedHex::new(&self.payload, 64))
.finish() .finish()
} }
} }
@ -109,7 +108,7 @@ impl InorderParser {
"corrupt RTP header while expecting seq={:04x?}: {:?}\n{:#?}", "corrupt RTP header while expecting seq={:04x?}: {:?}\n{:#?}",
&self.next_seq, &self.next_seq,
e, e,
data.hex_dump(), crate::hex::LimitedHex::new(&data, 64),
), ),
}) })
})?; })?;

View File

@ -6,7 +6,6 @@
use std::num::NonZeroU32; use std::num::NonZeroU32;
use bytes::Bytes; use bytes::Bytes;
use pretty_hex::PrettyHex;
const FIXED_CLOCK_RATE: u32 = 8_000; const FIXED_CLOCK_RATE: u32 = 8_000;
@ -53,7 +52,7 @@ impl Depacketizer {
if !Self::validate(&pkt) { if !Self::validate(&pkt) {
return Err(format!( return Err(format!(
"Invalid G.723 packet: {:#?}", "Invalid G.723 packet: {:#?}",
pkt.payload.hex_dump() crate::hex::LimitedHex::new(&pkt.payload, 64),
)); ));
} }
self.pending = Some(super::AudioFrame { self.pending = Some(super::AudioFrame {

View File

@ -13,7 +13,6 @@ use crate::client::rtp;
use crate::ConnectionContext; use crate::ConnectionContext;
use crate::Error; use crate::Error;
use bytes::{Buf, Bytes}; use bytes::{Buf, Bytes};
use pretty_hex::PrettyHex;
pub(crate) mod aac; pub(crate) mod aac;
pub(crate) mod g723; pub(crate) mod g723;
@ -123,7 +122,10 @@ impl std::fmt::Debug for VideoParameters {
.field("pixel_dimensions", &self.pixel_dimensions) .field("pixel_dimensions", &self.pixel_dimensions)
.field("pixel_aspect_ratio", &self.pixel_aspect_ratio) .field("pixel_aspect_ratio", &self.pixel_aspect_ratio)
.field("frame_rate", &self.frame_rate) .field("frame_rate", &self.frame_rate)
.field("extra_data", &self.extra_data.hex_dump()) .field(
"extra_data",
&crate::hex::LimitedHex::new(&self.extra_data, 256),
)
.finish() .finish()
} }
} }
@ -143,7 +145,10 @@ impl std::fmt::Debug for AudioParameters {
f.debug_struct("AudioParameters") f.debug_struct("AudioParameters")
.field("rfc6381_codec", &self.rfc6381_codec) .field("rfc6381_codec", &self.rfc6381_codec)
.field("frame_length", &self.frame_length) .field("frame_length", &self.frame_length)
.field("extra_data", &self.extra_data.hex_dump()) .field(
"extra_data",
&crate::hex::LimitedHex::new(&self.extra_data, 256),
)
.finish() .finish()
} }
} }
@ -201,7 +206,7 @@ impl std::fmt::Debug for AudioFrame {
.field("loss", &self.loss) .field("loss", &self.loss)
.field("timestamp", &self.timestamp) .field("timestamp", &self.timestamp)
.field("frame_length", &self.frame_length) .field("frame_length", &self.frame_length)
.field("data", &self.data.hex_dump()) .field("data", &crate::hex::LimitedHex::new(&self.data, 64))
.finish() .finish()
} }
} }
@ -245,7 +250,7 @@ impl std::fmt::Debug for MessageFrame {
.field("stream_id", &self.stream_id) .field("stream_id", &self.stream_id)
.field("loss", &self.loss) .field("loss", &self.loss)
.field("timestamp", &self.timestamp) .field("timestamp", &self.timestamp)
.field("data", &self.data.hex_dump()) .field("data", &crate::hex::LimitedHex::new(&self.data, 64))
.finish() .finish()
} }
} }
@ -334,8 +339,7 @@ impl std::fmt::Debug for VideoFrame {
.field("new_parameters", &self.new_parameters) .field("new_parameters", &self.new_parameters)
.field("is_random_access_point", &self.is_random_access_point) .field("is_random_access_point", &self.is_random_access_point)
.field("is_disposable", &self.is_disposable) .field("is_disposable", &self.is_disposable)
.field("data_len", &self.data.len()) .field("data", &crate::hex::LimitedHex::new(&self.data, 64))
//.field("data", &self.data.hex_dump())
.finish() .finish()
} }
} }

View File

@ -4,6 +4,7 @@
use std::{fmt::Display, sync::Arc}; use std::{fmt::Display, sync::Arc};
use crate::{ConnectionContext, PacketContext, RtspMessageContext}; use crate::{ConnectionContext, PacketContext, RtspMessageContext};
use bytes::Bytes;
use thiserror::Error; use thiserror::Error;
/// An opaque `std::error::Error + Send + Sync + 'static` implementation. /// An opaque `std::error::Error + Send + Sync + 'static` implementation.
@ -58,12 +59,15 @@ pub(crate) enum ErrorInt {
}, },
#[error( #[error(
"[{conn_ctx}, {msg_ctx}] Received interleaved data on unassigned channel {channel_id}" "[{conn_ctx}, {msg_ctx}] Received interleaved data on unassigned channel {channel_id}: \n\
{:?}",
crate::hex::LimitedHex::new(data, 64)
)] )]
RtspUnassignedChannelError { RtspUnassignedChannelError {
conn_ctx: ConnectionContext, conn_ctx: ConnectionContext,
msg_ctx: RtspMessageContext, msg_ctx: RtspMessageContext,
channel_id: u8, channel_id: u8,
data: Bytes,
}, },
#[error("[{conn_ctx}, {pkt_ctx} stream {stream_id}]: {description}")] #[error("[{conn_ctx}, {pkt_ctx} stream {stream_id}]: {description}")]

44
src/hex.rs Normal file
View File

@ -0,0 +1,44 @@
// Copyright (C) 2022 Scott Lamb <slamb@slamb.org>
// SPDX-License-Identifier: MIT OR Apache-2.0
//! Quick wrapper around `pretty-hex` to limit output.
//!
//! TODO: remove this if [wolandr/pretty-hex#9](https://github.com/wolandr/pretty-hex/pull/9)
//! is merged.
use pretty_hex::PrettyHex;
pub struct LimitedHex<'a> {
inner: &'a [u8],
max_bytes: usize,
}
impl<'a> LimitedHex<'a> {
pub fn new(inner: &'a [u8], max_bytes: usize) -> Self {
Self { inner, max_bytes }
}
}
impl<'a> std::fmt::Debug for LimitedHex<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let omitted = self.inner.len().checked_sub(self.max_bytes);
let print = if omitted.is_some() {
&self.inner[..self.max_bytes]
} else {
self.inner
};
writeln!(f, "Length: {0} (0x{0:x}) bytes", self.inner.len())?;
writeln!(
f,
"{:#?}",
print.hex_conf(pretty_hex::HexConfig {
title: false,
..Default::default()
})
)?;
if let Some(o) = omitted {
write!(f, "\n...{0} (0x{0:x}) bytes not shown...", o)?;
}
Ok(())
}
}

View File

@ -24,6 +24,7 @@ use std::ops::Range;
mod error; mod error;
mod rtcp; mod rtcp;
mod hex;
#[cfg(test)] #[cfg(test)]
mod testutil; mod testutil;