From be82f937f4540b6d0370c7f6fe2ae4040c3efdd2 Mon Sep 17 00:00:00 2001 From: Simon Morlat <simon.morlat@linphone.org> Date: Mon, 24 Jul 2023 16:53:03 +0200 Subject: [PATCH] Remove rtcp_rewind()/rtcp_next() that are error-prone, and replace by a new RtcpParserContext object. This fixes an issue with RTCP packets received via TURN not decoded properly. --- coreapi/quality_reporting.c | 32 +++++++++++++++------------ src/c-wrapper/api/c-call-stats.cpp | 26 ++++++++++------------ src/conference/session/ms2-stream.cpp | 12 +++++----- tester/tester.c | 17 ++++++++------ 4 files changed, 47 insertions(+), 40 deletions(-) diff --git a/coreapi/quality_reporting.c b/coreapi/quality_reporting.c index 7d9d3651ab..44b85ed0a8 100644 --- a/coreapi/quality_reporting.c +++ b/coreapi/quality_reporting.c @@ -677,35 +677,38 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_t metrics = &report->local_metrics; block = _linphone_call_stats_get_sent_rtcp(stats); } + RtcpParserContext rtcpctx; + const mblk_t *rtcpMessage = rtcp_parser_context_init(&rtcpctx, block); + do { - if (rtcp_is_XR(block) && (rtcp_XR_get_block_type(block) == RTCP_XR_VOIP_METRICS)) { + if (rtcp_is_XR(rtcpMessage) && (rtcp_XR_get_block_type(rtcpMessage) == RTCP_XR_VOIP_METRICS)) { - uint8_t config = rtcp_XR_voip_metrics_get_rx_config(block); + uint8_t config = rtcp_XR_voip_metrics_get_rx_config(rtcpMessage); metrics->rtcp_xr_count++; // for local mos rating, we'll use the quality indicator directly // because rtcp XR might not be enabled if (_linphone_call_stats_get_updated(stats) == LINPHONE_CALL_STATS_RECEIVED_RTCP_UPDATE) { - metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(block) == 127) + metrics->quality_estimates.moslq = (rtcp_XR_voip_metrics_get_mos_lq(rtcpMessage) == 127) ? 127 - : rtcp_XR_voip_metrics_get_mos_lq(block) / 10.f; - metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(block) == 127) + : rtcp_XR_voip_metrics_get_mos_lq(rtcpMessage) / 10.f; + metrics->quality_estimates.moscq = (rtcp_XR_voip_metrics_get_mos_cq(rtcpMessage) == 127) ? 127 - : rtcp_XR_voip_metrics_get_mos_cq(block) / 10.f; + : rtcp_XR_voip_metrics_get_mos_cq(rtcpMessage) / 10.f; } - metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(block); - metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(block); - metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(block); + metrics->jitter_buffer.nominal += rtcp_XR_voip_metrics_get_jb_nominal(rtcpMessage); + metrics->jitter_buffer.max += rtcp_XR_voip_metrics_get_jb_maximum(rtcpMessage); + metrics->jitter_buffer.abs_max = rtcp_XR_voip_metrics_get_jb_abs_max(rtcpMessage); metrics->jitter_buffer.adaptive = (config >> 4) & 0x3; - metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(block); - metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(block); + metrics->packet_loss.network_packet_loss_rate = rtcp_XR_voip_metrics_get_loss_rate(rtcpMessage); + metrics->packet_loss.jitter_buffer_discard_rate = rtcp_XR_voip_metrics_get_discard_rate(rtcpMessage); metrics->session_description.packet_loss_concealment = (config >> 6) & 0x3; - metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(block); - } else if (rtcp_is_SR(block)) { + metrics->delay.round_trip_delay += rtcp_XR_voip_metrics_get_round_trip_delay(rtcpMessage); + } else if (rtcp_is_SR(rtcpMessage)) { MediaStream *ms = (stats_type == 0) ? Call::toCpp(call)->getMediaStream(LinphoneStreamTypeAudio) : ((stats_type == 1) ? Call::toCpp(call)->getMediaStream(LinphoneStreamTypeVideo) @@ -717,7 +720,8 @@ void linphone_reporting_on_rtcp_update(LinphoneCall *call, SalStreamType stats_t metrics->delay.round_trip_delay += (int)(1000 * rtt); } } - } while (rtcp_next_packet(block)); + } while ((rtcpMessage = rtcp_parser_context_next_packet(&rtcpctx)) != nullptr); + rtcp_parser_context_uninit(&rtcpctx); /* check if we should send an interval report - use a random sending time to dispatch reports and avoid sending them too close from each other */ diff --git a/src/c-wrapper/api/c-call-stats.cpp b/src/c-wrapper/api/c-call-stats.cpp index ad1c2c283a..8dd9f387e5 100644 --- a/src/c-wrapper/api/c-call-stats.cpp +++ b/src/c-wrapper/api/c-call-stats.cpp @@ -304,16 +304,15 @@ float linphone_call_stats_get_sender_loss_rate(const LinphoneCallStats *stats) { ms_warning("linphone_call_stats_get_sender_loss_rate(): there is no RTCP packet sent."); return 0.0; } - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several - * mblk_t structure */ - if (stats->sent_rtcp->b_cont != NULL) msgpullup(stats->sent_rtcp, (size_t)-1); + RtcpParserContext parserCtx; + const mblk_t *rtcpMessage = rtcp_parser_context_init(&parserCtx, stats->sent_rtcp); do { - if (rtcp_is_SR(stats->sent_rtcp)) srb = rtcp_SR_get_report_block(stats->sent_rtcp, 0); - else if (rtcp_is_RR(stats->sent_rtcp)) srb = rtcp_RR_get_report_block(stats->sent_rtcp, 0); + if (rtcp_is_SR(rtcpMessage)) srb = rtcp_SR_get_report_block(rtcpMessage, 0); + else if (rtcp_is_RR(rtcpMessage)) srb = rtcp_RR_get_report_block(rtcpMessage, 0); if (srb) break; - } while (rtcp_next_packet(stats->sent_rtcp)); - rtcp_rewind(stats->sent_rtcp); + } while ((rtcpMessage = rtcp_parser_context_next_packet(&parserCtx)) != nullptr); + rtcp_parser_context_uninit(&parserCtx); if (!srb) return 0.0; return 100.0f * (float)report_block_get_fraction_lost(srb) / 256.0f; } @@ -325,16 +324,15 @@ float linphone_call_stats_get_receiver_loss_rate(const LinphoneCallStats *stats) ms_warning("linphone_call_stats_get_receiver_loss_rate(): there is no RTCP packet received."); return 0.0; } - /* Perform msgpullup() to prevent crashes in rtcp_is_SR() or rtcp_is_RR() if the RTCP packet is composed of several - * mblk_t structure */ - if (stats->received_rtcp->b_cont != NULL) msgpullup(stats->received_rtcp, (size_t)-1); + RtcpParserContext parserCtx; + const mblk_t *rtcpMessage = rtcp_parser_context_init(&parserCtx, stats->received_rtcp); do { - if (rtcp_is_RR(stats->received_rtcp)) rrb = rtcp_RR_get_report_block(stats->received_rtcp, 0); - else if (rtcp_is_SR(stats->received_rtcp)) rrb = rtcp_SR_get_report_block(stats->received_rtcp, 0); + if (rtcp_is_RR(rtcpMessage)) rrb = rtcp_RR_get_report_block(rtcpMessage, 0); + else if (rtcp_is_SR(rtcpMessage)) rrb = rtcp_SR_get_report_block(rtcpMessage, 0); if (rrb) break; - } while (rtcp_next_packet(stats->received_rtcp)); - rtcp_rewind(stats->received_rtcp); + } while ((rtcpMessage = rtcp_parser_context_next_packet(&parserCtx)) != nullptr); + rtcp_parser_context_uninit(&parserCtx); if (!rrb) return 0.0; return 100.0f * (float)report_block_get_fraction_lost(rrb) / 256.0f; } diff --git a/src/conference/session/ms2-stream.cpp b/src/conference/session/ms2-stream.cpp index ba5277b71f..d419b099e1 100644 --- a/src/conference/session/ms2-stream.cpp +++ b/src/conference/session/ms2-stream.cpp @@ -1375,16 +1375,18 @@ void MS2Stream::handleEvents() { /*This MUST be done before any call to "linphone_call_stats_fill" since it has ownership over evd->packet*/ if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) { + RtcpParserContext rtcpctx; + const mblk_t *rtcpMessage = rtcp_parser_context_init(&rtcpctx, evd->packet); do { - if (evd->packet && rtcp_is_RTPFB(evd->packet)) { - if (rtcp_RTPFB_get_type(evd->packet) == RTCP_RTPFB_TMMBR) { + if (rtcpMessage && rtcp_is_RTPFB(rtcpMessage)) { + if (rtcp_RTPFB_get_type(rtcpMessage) == RTCP_RTPFB_TMMBR) { CallSessionListener *listener = getMediaSessionPrivate().getCallSessionListener(); listener->onTmmbrReceived(getMediaSession().getSharedFromThis(), (int)getIndex(), - (int)rtcp_RTPFB_tmmbr_get_max_bitrate(evd->packet)); + (int)rtcp_RTPFB_tmmbr_get_max_bitrate(rtcpMessage)); } } - } while (rtcp_next_packet(evd->packet)); - rtcp_rewind(evd->packet); + } while ((rtcpMessage = rtcp_parser_context_next_packet(&rtcpctx)) != nullptr); + rtcp_parser_context_uninit(&rtcpctx); } if (ms) linphone_call_stats_fill(mStats, ms, ev); bool isIceEvent = false; diff --git a/tester/tester.c b/tester/tester.c index 9aa49e6837..185d7fe089 100644 --- a/tester/tester.c +++ b/tester/tester.c @@ -3753,21 +3753,24 @@ void dtmf_received(LinphoneCore *lc, BCTBX_UNUSED(LinphoneCall *call), int dtmf) counters->dtmf_count++; } -bool_t rtcp_is_type(const mblk_t *m, rtcp_type_t type) { +static bool_t rtcp_is_type(const mblk_t *m, rtcp_type_t type) { const rtcp_common_header_t *ch = rtcp_get_common_header(m); return (ch != NULL && rtcp_common_header_get_packet_type(ch) == type); } -void rtcp_received(stats *counters, mblk_t *packet) { +static void rtcp_received(stats *counters, mblk_t *packet) { + RtcpParserContext rtcpParser; + + const mblk_t *rtcpMessage = rtcp_parser_context_init(&rtcpParser, packet); do { - if (rtcp_is_type(packet, RTCP_RTPFB)) { - if (rtcp_RTPFB_get_type(packet) == RTCP_RTPFB_TMMBR) { + if (rtcp_is_type(rtcpMessage, RTCP_RTPFB)) { + if (rtcp_RTPFB_get_type(rtcpMessage) == RTCP_RTPFB_TMMBR) { counters->number_of_tmmbr_received++; - counters->last_tmmbr_value_received = (int)rtcp_RTPFB_tmmbr_get_max_bitrate(packet); + counters->last_tmmbr_value_received = (int)rtcp_RTPFB_tmmbr_get_max_bitrate(rtcpMessage); } } - } while (rtcp_next_packet(packet)); - rtcp_rewind(packet); + } while ((rtcpMessage = rtcp_parser_context_next_packet(&rtcpParser)) != NULL); + rtcp_parser_context_uninit(&rtcpParser); } void call_stats_updated(LinphoneCore *lc, LinphoneCall *call, const LinphoneCallStats *lstats) { -- GitLab