diff --git a/core/libs/prx/libwebrtc/CMakeLists.txt b/core/libs/prx/libwebrtc/CMakeLists.txt index d8773bec69..190029c626 100644 --- a/core/libs/prx/libwebrtc/CMakeLists.txt +++ b/core/libs/prx/libwebrtc/CMakeLists.txt @@ -3,6 +3,7 @@ target_include_directories(libwebrtc PRIVATE ${LIBS_INCLUDE_DIR}) configure_windows_unwind(libwebrtc) target_sources(libwebrtc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/ExpFilter.cpp) +target_sources(libwebrtc PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/RtcpCommonHeader.cpp) if(BUILD_TESTING) add_test_executable(guest_webrtc_fast_int_to_buffer_tests ${CMAKE_CURRENT_SOURCE_DIR}/tests/FastIntToBuffer.cpp) @@ -25,4 +26,14 @@ if(BUILD_TESTING) set_tests_properties(guest_webrtc_exp_filter PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_test_executable(guest_webrtc_rtcp_common_header_tests ${CMAKE_CURRENT_SOURCE_DIR}/tests/RtcpCommonHeader.cpp) + target_include_directories(guest_webrtc_rtcp_common_header_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_webrtc_rtcp_common_header_tests PRIVATE libwebrtc libc) + configure_windows_unwind(guest_webrtc_rtcp_common_header_tests) + add_test(NAME guest_webrtc_rtcp_common_header COMMAND guest_webrtc_rtcp_common_header_tests) + set_tests_properties(guest_webrtc_rtcp_common_header PROPERTIES TIMEOUT 20) + if(WIN32) + set_tests_properties(guest_webrtc_rtcp_common_header PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() endif() diff --git a/core/libs/prx/libwebrtc/Export.cpp b/core/libs/prx/libwebrtc/Export.cpp index c84988b995..0fe15a48b2 100644 --- a/core/libs/prx/libwebrtc/Export.cpp +++ b/core/libs/prx/libwebrtc/Export.cpp @@ -1128,11 +1128,6 @@ int APS5_VABI _ZN6webrtc4rtcp3AppD1Ev_nid_postfix(void) { return 0; } -int APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(void) { - NotImplemented_nid_no_patch(__func__); - return 0; -} - APS5_EXPORT("PEV9t77ljzc", libwebrtcUnknown34); int APS5_VABI libwebrtcUnknown34(void) { NotImplemented_nid_no_patch("PEV9t77ljzc"); diff --git a/core/libs/prx/libwebrtc/include/Api.hpp b/core/libs/prx/libwebrtc/include/Api.hpp index 40b0b30044..9ce5d377dc 100644 --- a/core/libs/prx/libwebrtc/include/Api.hpp +++ b/core/libs/prx/libwebrtc/include/Api.hpp @@ -2,6 +2,7 @@ #include "SceTypes.hpp" #include "prx/libwebrtc/include/ExpFilter.hpp" +#include "prx/libwebrtc/include/RtcpCommonHeader.hpp" extern "C" { @@ -222,7 +223,7 @@ int APS5_VABI _ZNK6webrtc4rtcp10RtcpPacket5BuildEv_nid_postfix(void); int APS5_VABI _ZN6webrtc4rtcp3App5ParseERKNS0_12CommonHeaderE_nid_postfix(void); int APS5_VABI _ZN6webrtc4rtcp3AppC1Ev_nid_postfix(void); int APS5_VABI _ZN6webrtc4rtcp3AppD1Ev_nid_postfix(void); -int APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(void); +bool APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(WebRtcRtcpCommonHeader* header, const std::uint8_t* buffer, std::size_t size); int APS5_VABI libwebrtcUnknown34(void); int APS5_VABI _ZN6webrtc4rtcp14CompoundPacketC1Ev_nid_postfix(void); int APS5_VABI _ZN6webrtc4rtcp14CompoundPacketD1Ev_nid_postfix(void); diff --git a/core/libs/prx/libwebrtc/include/RtcpCommonHeader.hpp b/core/libs/prx/libwebrtc/include/RtcpCommonHeader.hpp new file mode 100644 index 0000000000..15e9280434 --- /dev/null +++ b/core/libs/prx/libwebrtc/include/RtcpCommonHeader.hpp @@ -0,0 +1,19 @@ +#pragma once + +#include +#include + +constexpr std::size_t WebRtcRtcpCommonHeaderSize = 4; + +struct WebRtcRtcpCommonHeader { + std::uint8_t packetType; + std::uint8_t countOrFormat; + std::uint8_t paddingSize; + std::uint32_t payloadSize; + const std::uint8_t* payload; +}; + +static_assert(sizeof(WebRtcRtcpCommonHeader) == 16); +static_assert(offsetof(WebRtcRtcpCommonHeader, paddingSize) == 2); +static_assert(offsetof(WebRtcRtcpCommonHeader, payloadSize) == 4); +static_assert(offsetof(WebRtcRtcpCommonHeader, payload) == 8); diff --git a/core/libs/prx/libwebrtc/src/RtcpCommonHeader.cpp b/core/libs/prx/libwebrtc/src/RtcpCommonHeader.cpp new file mode 100644 index 0000000000..e4f85d3ce1 --- /dev/null +++ b/core/libs/prx/libwebrtc/src/RtcpCommonHeader.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +/* + * Copyright (c) 2011, The WebRTC project authors. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * * Neither the name of Google nor the names of its contributors may + * be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "prx/libwebrtc/libwebrtc.hpp" + +#include +#include +#include + +extern "C" { + +bool APS5_VABI _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(WebRtcRtcpCommonHeader* header, const std::uint8_t* buffer, std::size_t size) { + if (!header) + throw std::invalid_argument("CommonHeader::Parse requires a header"); + if (size < WebRtcRtcpCommonHeaderSize) + return false; + if (!buffer) + throw std::invalid_argument("CommonHeader::Parse requires a buffer"); + if ((buffer[0] >> 6) != 2) + return false; + bool hasPadding = (buffer[0] & 0x20) != 0; + header->countOrFormat = buffer[0] & 0x1F; + header->packetType = buffer[1]; + header->payloadSize = ((static_cast(buffer[2]) << 8) | buffer[3]) * 4u; + header->payload = buffer + WebRtcRtcpCommonHeaderSize; + header->paddingSize = 0; + if (size < WebRtcRtcpCommonHeaderSize + header->payloadSize) + return false; + if (hasPadding) { + if (header->payloadSize == 0) + return false; + header->paddingSize = header->payload[header->payloadSize - 1]; + if (header->paddingSize == 0) + return false; + if (header->paddingSize > header->payloadSize) + return false; + header->payloadSize -= header->paddingSize; + } + return true; +} + +} diff --git a/core/libs/prx/libwebrtc/tests/RtcpCommonHeader.cpp b/core/libs/prx/libwebrtc/tests/RtcpCommonHeader.cpp new file mode 100644 index 0000000000..d7c331b9e9 --- /dev/null +++ b/core/libs/prx/libwebrtc/tests/RtcpCommonHeader.cpp @@ -0,0 +1,144 @@ +#include "prx/libwebrtc/libwebrtc.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + +void Require(bool condition, std::source_location location = std::source_location::current()) { + if (condition) return; + std::fprintf(stderr, "libwebrtc rtcp::CommonHeader check failed at line %u\n", location.line()); + std::abort(); +} + +template void RequireInvalidArgument(TAction action, std::source_location location = std::source_location::current()) { + try { + action(); + } catch (const std::invalid_argument&) { + return; + } + Require(false, location); +} + +WebRtcRtcpCommonHeader Filled() { + WebRtcRtcpCommonHeader header; + std::memset(&header, 0xA5, sizeof(header)); + return header; +} + +bool Parse(WebRtcRtcpCommonHeader& header, const std::vector& packet, std::size_t size) { + return _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(&header, packet.data(), size); +} + +bool Unchanged(const WebRtcRtcpCommonHeader& header) { + WebRtcRtcpCommonHeader filled = Filled(); + return header.packetType == filled.packetType && header.countOrFormat == filled.countOrFormat && header.paddingSize == filled.paddingSize && + header.payloadSize == filled.payloadSize && header.payload == filled.payload; +} + +void TestReceiverReport() { + std::vector packet {0x81, 201, 0x00, 0x07}; + packet.resize(32, 0x11); + WebRtcRtcpCommonHeader header = Filled(); + Require(Parse(header, packet, packet.size())); + Require(header.countOrFormat == 1); + Require(header.packetType == 201); + Require(header.payloadSize == 28); + Require(header.paddingSize == 0); + Require(header.payload == packet.data() + 4); +} + +void TestFeedbackFormatAndEmptyPayload() { + std::vector packet {0x9F, 206, 0x00, 0x00}; + WebRtcRtcpCommonHeader header = Filled(); + Require(Parse(header, packet, packet.size())); + Require(header.countOrFormat == 31); + Require(header.packetType == 206); + Require(header.payloadSize == 0); + Require(header.paddingSize == 0); +} + +void TestPadding() { + std::vector packet {0xA0, 200, 0x00, 0x02, 1, 2, 3, 4, 5, 0, 0, 3}; + WebRtcRtcpCommonHeader header = Filled(); + Require(Parse(header, packet, packet.size())); + Require(header.countOrFormat == 0); + Require(header.paddingSize == 3); + Require(header.payloadSize == 5); + Require(header.payload == packet.data() + 4); + + packet[11] = 8; + header = Filled(); + Require(Parse(header, packet, packet.size())); + Require(header.paddingSize == 8); + Require(header.payloadSize == 0); +} + +void TestRejectsBeforeReading() { + std::vector packet {0x80, 200, 0x00, 0x00}; + WebRtcRtcpCommonHeader header = Filled(); + Require(!Parse(header, packet, 3)); + Require(Unchanged(header)); + Require(!_ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(&header, nullptr, 3)); + Require(Unchanged(header)); + for (std::uint8_t first : {0x00, 0x41, 0xC1}) { + packet[0] = first; + Require(!Parse(header, packet, packet.size())); + Require(Unchanged(header)); + } +} + +void TestRejectsAfterReading() { + std::vector packet {0x81, 201, 0x00, 0x02, 1, 2, 3, 4, 5, 6, 7}; + WebRtcRtcpCommonHeader header = Filled(); + Require(!Parse(header, packet, packet.size())); + Require(header.countOrFormat == 1); + Require(header.packetType == 201); + Require(header.payloadSize == 8); + Require(header.paddingSize == 0); + Require(header.payload == packet.data() + 4); + + std::vector empty {0xA0, 200, 0x00, 0x00}; + header = Filled(); + Require(!Parse(header, empty, empty.size())); + Require(header.payloadSize == 0); + Require(header.paddingSize == 0); + + std::vector zeroPadding {0xA0, 200, 0x00, 0x01, 1, 2, 3, 0}; + header = Filled(); + Require(!Parse(header, zeroPadding, zeroPadding.size())); + Require(header.payloadSize == 4); + Require(header.paddingSize == 0); + + std::vector tooMuchPadding {0xA0, 200, 0x00, 0x01, 1, 2, 3, 5}; + header = Filled(); + Require(!Parse(header, tooMuchPadding, tooMuchPadding.size())); + Require(header.payloadSize == 4); + Require(header.paddingSize == 5); +} + +void TestNullArguments() { + std::array packet {0x80, 200, 0x00, 0x00}; + RequireInvalidArgument([&] { _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(nullptr, packet.data(), packet.size()); }); + WebRtcRtcpCommonHeader header = Filled(); + RequireInvalidArgument([&] { _ZN6webrtc4rtcp12CommonHeader5ParseEPKhm_nid_postfix(&header, nullptr, 4); }); + Require(Unchanged(header)); +} + +} + +int main() { + TestReceiverReport(); + TestFeedbackFormatAndEmptyPayload(); + TestPadding(); + TestRejectsBeforeReading(); + TestRejectsAfterReading(); + TestNullArguments(); + std::puts("libwebrtc rtcp::CommonHeader tests passed"); +} diff --git a/docs/dev/debt/libwebrtc.md b/docs/dev/debt/libwebrtc.md index b361a7cce4..868ffaca0a 100644 --- a/docs/dev/debt/libwebrtc.md +++ b/docs/dev/debt/libwebrtc.md @@ -2,7 +2,7 @@ ### Unknown function info -- [409 exports (60 without a known name, bound by NID)](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - every function export of `libwebrtc.sprx` from the firmware 13.60 export table that the next section does not implement, names from aerolib.csv only where `tools/nid_names.py` `compute_nid` reproduces the NID. Signatures, parameter layouts and behaviour are unknown; every export throws through `NotImplemented_nid_no_patch` +- [408 exports (60 without a known name, bound by NID)](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - every function export of `libwebrtc.sprx` from the firmware 13.60 export table that the next section does not implement, names from aerolib.csv only where `tools/nid_names.py` `compute_nid` reproduces the NID. Signatures, parameter layouts and behaviour are unknown; every export throws through `NotImplemented_nid_no_patch` - [31 data exports](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - the module also exports 31 data objects (+qcl2IzxTzg, -ix-knPYqWA, 00mefEErs+Y, 5FM0YOa3NWc, 67nsSkXmJ7E, 7I2xDnqfDV4, 8Dzy4JayJSU, CVCDyAzGrhI, HpbtuVdvO-w, PGIpx6NnFLE, Q+xnDp4KI-s, QXDv9OpZNvM, aOOjLmup+u4, g5USRJNh3bU, hvpHGXjlpbk, iU6+qODNSjU, jpkYoOv34AM, lHLJlq3NEqE, lQJvoyxHov4, nUaORqH85DQ, o6LS+08kOUs, oh8srl3AcNE, oslHzys1vV0, sp5NqvqDdHw, t66Gw3OIpSo, tr8vseK8-ro, uSis0q+bv6k, uTz5pEKL+hM, uxkudCJIYJA, whHm70jlRXw, yW0sV3sCdPA); they are not defined, so imports of them stay unresolved until their layout is known ### Public source implementations @@ -10,3 +10,4 @@ - [Source revision](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - the module's exact WebRTC revision is not identified. Its `rtc::` names and `InterleavedView` resampler overloads place it between M127 ([branch-heads/6533](https://webrtc.googlesource.com/src/+/e0b28a6a81a989c1f5c89e30fcd247870047390d)) and M134 ([branch-heads/6998](https://webrtc.googlesource.com/src/+/8d78f5de6c27b2c793039989ea381f1428fb0100)), so the exports below follow code that is the same at both. Nothing is checked on the console. Closes when: the revision is identified and the exports are compared with the console. - [absl::numbers_internal::FastIntToBuffer(int, char*)](../../../core/libs/prx/libwebrtc/Export.cpp) (libwebrtc) - follows the abseil both branches pin, [65ef38d368](https://chromium.googlesource.com/chromium/src/third_party/+/65ef38d36813d1ad9d4cbf8a18b32ac3691f418b/abseil-cpp/absl/strings/numbers.cc) and [d212a71416](https://chromium.googlesource.com/chromium/src/third_party/+/d212a71416ad7c6ceca04d6d27dfdd84fd00c04c/abseil-cpp/absl/strings/numbers.cc): the decimal text and a NUL, returning a pointer to the NUL. For magnitudes from 10 to 99999999 its 8-byte store also zeroes the bytes after the digits up to 8 from the first digit. A null buffer, which abseil writes through, throws. Closes when: compared with the console. - [rtc::ExpFilter::Reset and Apply](../../../core/libs/prx/libwebrtc/src/ExpFilter.cpp) (libwebrtc) - adapted from [exp_filter.cc](https://webrtc.googlesource.com/src/+/8d78f5de6c27b2c793039989ea381f1428fb0100/rtc_base/numerics/exp_filter.cc), with its WebRTC copyright notice and BSD licence at the top of the file, on the 12-byte `alpha_`, `filtered_` and `max_` layout of `exp_filter.h`. -1 marks both an unset output and no maximum, so an output that lands on exactly -1 restarts the filter on the next sample, as upstream does. The last bit of a result can differ if the console build fuses the multiply-adds. A null filter throws. Closes when: compared with the console. +- [webrtc::rtcp::CommonHeader::Parse](../../../core/libs/prx/libwebrtc/src/RtcpCommonHeader.cpp) (libwebrtc) - adapted from [common_header.cc](https://webrtc.googlesource.com/src/+/8d78f5de6c27b2c793039989ea381f1428fb0100/modules/rtp_rtcp/source/rtcp_packet/common_header.cc), with its WebRTC copyright notice and BSD licence at the top of the file, on the 16-byte layout of `common_header.h`: packet type, count or format and padding size at 0 to 2, payload size at 4 and payload pointer at 8. Its checks run in the same order, so a short buffer or a wrong version leaves the header untouched and the later failures leave the fields already parsed. The `RTC_LOG(LS_WARNING)` message each failure logs upstream is not emitted. A null header, or a null buffer of 4 bytes or more, which upstream reads, throws. Closes when: the warnings are logged through libwebrtc's logging and the parse is compared with the console.