1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 10:45:57 +01:00

7 Commits
v4.5 ... master

Author SHA1 Message Date
Dave Walker
67c81199fb Update CMake minimum required version to 3.10 (#553)
CMake 4 removed compatibility with CMake versions < 3.5, and versions
between 3.5-3.10 are deprecated.

This change updates the minimum required version to 3.10 to ensure
compatibility with modern CMake versions including CMake 4.x.

This issue is affecting NixOS users (see
https://github.com/NixOS/nixpkgs/issues/450198) and will likely impact
other distributions as they upgrade to CMake 4.x.
2025-12-11 20:53:03 -08:00
James R T
fe22186623 Add RTP support (#530)
This commit adds support for the Real-time Transport Protocol (RTP) as
defined in RFC 3550. Some tests have also been added to ensure that the
RTP PDU class functionality is working as expected.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2024-03-31 07:46:42 -07:00
James R T
bbac2ece52 Replace remaining rfind_pdu calls to find_pdu in src directory (#527)
This commit replaces the remaining `rfind_pdu` calls to `find_pdu` in
the `src` directory. Any existing `rfind_pdu` calls in the `examples`
and `tests` directories are unmodified.

The main motivation is that conditional statements are generally more
performant than exception handling. Since `rfind_pdu` calls `find_pdu`
internally anyway, this eliminates some overhead as well.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2024-03-17 08:18:02 -07:00
James R T
ba9a2155ca Update VXLANTest destination port number (#528)
Based on RFC 7348, the default IANA-assigned destination UDP port number
for VXLAN is 4789, not the source port number. Update the value in the
VXLANTest class to align with the RFC.

The VXLAN implementation still allows for the destination port number to
be configurable to allow interoperability (as specified by the RFC),
such as with the Linux kernel's default value of 8472.

Signed-off-by: James Raphael Tiovalen <jamestiotio@gmail.com>
2024-03-17 08:16:31 -07:00
Cameron Miller
00619e0500 Modify conditional to have Android API version check (#526)
Co-authored-by: Cameron Miller <cameron.miller@homeaware.com>
2024-02-20 15:12:00 -08:00
Yang Bin
64da67ca56 Update tcp.h (#516)
Fix a spelling error
2023-09-19 07:04:43 -07:00
Matias Fontanini
3943700830 Bump version to 4.6 2023-08-20 09:47:49 -07:00
16 changed files with 845 additions and 14 deletions

View File

@@ -1,4 +1,4 @@
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.1)
CMAKE_MINIMUM_REQUIRED(VERSION 3.10)
PROJECT(libtins)
OPTION(LIBTINS_BUILD_EXAMPLES "Build examples" ON)
@@ -46,7 +46,7 @@ ENDIF(LIBTINS_BUILD_SHARED)
# The version number.
SET(TINS_VERSION_MAJOR 4)
SET(TINS_VERSION_MINOR 5)
SET(TINS_VERSION_MINOR 6)
SET(TINS_VERSION_PATCH 0)
SET(LIBTINS_VERSION "${TINS_VERSION_MAJOR}.${TINS_VERSION_MINOR}")

View File

@@ -50,7 +50,7 @@ if (NOT CMAKE_CXX_COMPILER_LOADED)
message(FATAL_ERROR "CheckCXX11Features modules only works if language CXX is enabled")
endif ()
cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.10)
#
### Check for needed compiler flags

View File

@@ -181,6 +181,7 @@ public:
MPLS,
DOT11_CONTROL_TA,
VXLAN,
RTP,
UNKNOWN = 999,
USER_DEFINED_PDU = 1000
};

328
include/tins/rtp.h Normal file
View File

@@ -0,0 +1,328 @@
#ifndef TINS_RTP_H
#define TINS_RTP_H
#include <tins/endianness.h>
#include <tins/pdu.h>
#include <tins/pdu_option.h>
#include <tins/small_uint.h>
namespace Tins {
/**
* \class RTP
* \brief Represents a RTP PDU.
*
* This class represents a RTP PDU.
*
* \sa RawPDU
*/
class TINS_API RTP : public PDU {
public:
/**
* \brief This PDU's flag.
*/
static const PDU::PDUType pdu_flag = PDU::RTP;
/**
* The type used to store CSRC identifiers.
*/
typedef std::vector<uint32_t> csrc_ids_type;
/**
* The type used to store extension header data.
*/
typedef std::vector<uint32_t> extension_header_data_type;
/**
* Default constructor.
*/
RTP();
/**
* \brief Constructs a RTP object from a buffer.
*
* \param data The buffer from which this PDU will be constructed.
* \param size The size of the data buffer.
*/
RTP(const uint8_t* data, uint32_t size);
/**
* \brief Getter for the version.
*/
small_uint<2> version() const { return header_.version; }
/**
* \brief Getter for the padding bit.
*/
small_uint<1> padding_bit() const { return header_.padding; }
/**
* \brief Getter for the extension bit.
*/
small_uint<1> extension_bit() const { return header_.extension; }
/**
* \brief Getter for the CSRC count.
*/
small_uint<4> csrc_count() const { return header_.csrc_count; }
/**
* \brief Getter for the marker bit.
*/
small_uint<1> marker_bit() const { return header_.marker; }
/**
* \brief Getter for the payload type.
*/
small_uint<7> payload_type() const { return header_.payload_type; }
/**
* \brief Getter for the sequence number.
*/
uint16_t sequence_number() const { return Endian::be_to_host(header_.seq_num); }
/**
* \brief Getter for the timestamp.
*/
uint32_t timestamp() const { return Endian::be_to_host(header_.timestamp); }
/**
* \brief Getter for the SSRC identifier.
*/
uint32_t ssrc_id() const { return Endian::be_to_host(header_.ssrc_id); }
/**
* \brief Getter for the CSRC identifiers.
*/
const csrc_ids_type& csrc_ids() const {
return csrc_ids_;
}
/**
* \brief Getter for the padding size.
*/
uint8_t padding_size() const { return padding_size_; }
/**
* \brief Getter for the extension header profile.
*/
uint16_t extension_profile() const { return Endian::be_to_host(ext_header_.profile); }
/**
* \brief Getter for the extension header length.
*/
uint16_t extension_length() const { return Endian::be_to_host(ext_header_.length); }
/**
* \brief Getter for the extension header data.
*/
const extension_header_data_type& extension_data() const {
return ext_data_;
}
/**
* \brief Setter for the version.
* \param version The new version.
*/
void version(small_uint<2> version) { header_.version = version; }
/**
* \brief Setter for the extension bit.
* \param extension The new extension bit.
*/
void extension_bit(small_uint<1> extension) { header_.extension = extension; }
/**
* \brief Setter for the marker bit.
* \param marker The new marker bit.
*/
void marker_bit(small_uint<1> marker) { header_.marker = marker; }
/**
* \brief Setter for the payload type.
* \param payload_type The new payload type.
*/
void payload_type(small_uint<7> payload_type) { header_.payload_type = payload_type; }
/**
* \brief Setter for the sequence number.
* \param seq_num The new sequence number.
*/
void sequence_number(uint16_t seq_num) { header_.seq_num = Endian::host_to_be(seq_num); }
/**
* \brief Setter for the timestamp.
* \param timestamp The new timestamp.
*/
void timestamp(uint32_t timestamp) { header_.timestamp = Endian::host_to_be(timestamp); }
/**
* \brief Setter for the SSRC identifier.
* \param ssrc_id The new SSRC identifier.
*/
void ssrc_id(uint32_t ssrc_id) { header_.ssrc_id = Endian::host_to_be(ssrc_id); }
/**
* \brief Setter for the padding size.
* \param size The new padding size.
*/
void padding_size(uint8_t size) {
padding_bit(size > 0);
padding_size_ = size;
}
/**
* \brief Setter for the extension header profile.
* \param profile The new extension header profile.
*/
void extension_profile(uint16_t profile) { ext_header_.profile = Endian::host_to_be(profile); }
/**
* \brief Adds a word of extension header data.
*
* The word is added after the last word of extension header data.
*
* \param value The value of the extension header data to be added.
*/
void add_extension_data(const uint32_t value);
/**
* \brief Removes a word of extension header data.
*
* If there are multiple words of extension header data of the given value,
* only the first one will be removed.
*
* \param value The value of the extension header data to be removed.
* \return true if the extension header data was removed, false otherwise.
*/
bool remove_extension_data(const uint32_t value);
/**
* \brief Searches for extension header data that matches the given value.
* \param value The extension header data to be searched.
* \return true if the extension header data was found, false otherwise.
*/
bool search_extension_data(const uint32_t value);
/**
* \brief Adds a CSRC identifier.
*
* The CSRC identifier is added after the last CSRC identifier in the extension
* header.
*
* \param csrc_id The CSRC identifier to be added
*/
void add_csrc_id(const uint32_t csrc_id);
/**
* \brief Removes a CSRC identifier.
*
* If there are multiple CSRC identifiers of the given value, only the first one
* will be removed.
*
* \param value The value of the CSRC identifier to be removed.
* \return true if the CSRC identifier was removed, false otherwise.
*/
bool remove_csrc_id(const uint32_t value);
/**
* \brief Searches for a CSRC identifier that matches the given value.
* \param value The CSRC identifier to be searched.
* \return true if the CSRC identifier was found, false otherwise.
*/
bool search_csrc_id(const uint32_t value);
/**
* \brief Returns the RTP packet's header length.
*
* This method overrides PDU::header_size.
*
* \return An uint32_t with the header's size.
* \sa PDU::header_size
*/
uint32_t header_size() const;
/**
* \brief Returns the RTP packet's trailer length.
*
* This method overrides PDU::trailer_size.
*
* \return An uint32_t with the trailer's size.
* \sa PDU::trailer_size
*/
uint32_t trailer_size() const { return static_cast<uint32_t>(padding_size_); }
/**
* \brief Getter for the PDU's type.
* \sa PDU::pdu_type
*/
PDUType pdu_type() const { return pdu_flag; }
/**
* \sa PDU::clone
*/
RTP *clone() const { return new RTP(*this); }
private:
TINS_BEGIN_PACK
struct rtp_header {
#if TINS_IS_BIG_ENDIAN
uint16_t version:2,
padding:1,
extension:1,
csrc_count:4,
marker:1,
payload_type:7;
#elif TINS_IS_LITTLE_ENDIAN
uint16_t csrc_count:4,
extension:1,
padding:1,
version:2,
payload_type:7,
marker:1;
#endif
uint16_t seq_num;
uint32_t timestamp;
uint32_t ssrc_id;
} TINS_END_PACK;
TINS_BEGIN_PACK
struct rtp_extension_header {
uint16_t profile;
uint16_t length;
} TINS_END_PACK;
void write_serialization(uint8_t* buffer, uint32_t size);
csrc_ids_type::const_iterator search_csrc_id_iterator(const uint32_t csrc_id) const;
csrc_ids_type::iterator search_csrc_id_iterator(const uint32_t csrc_id);
extension_header_data_type::const_iterator search_extension_data_iterator(const uint32_t data) const;
extension_header_data_type::iterator search_extension_data_iterator(const uint32_t data);
/**
* \brief Setter for the padding bit.
* \param padding The new padding bit.
*/
void padding_bit(small_uint<1> padding) { header_.padding = padding; }
/**
* \brief Setter for the CSRC count. Hidden from the public interface.
* \param csrc_count The new CSRC count.
*/
void csrc_count(small_uint<4> csrc_count) { header_.csrc_count = csrc_count; }
/**
* \brief Setter for the extension header length. Hidden from the public interface.
* \param length The new extension header length.
*/
void extension_length(uint16_t length) { ext_header_.length = Endian::host_to_be(length); }
rtp_header header_;
csrc_ids_type csrc_ids_;
rtp_extension_header ext_header_;
extension_header_data_type ext_data_;
uint8_t padding_size_;
};
} // Tins
#endif // TINS_RTP_H

View File

@@ -303,7 +303,7 @@ public:
* TCP tcp = ...;
* if(tcp.has_flags(TCP::SYN | TCP::ACK)) {
* // It's a SYN+ACK, but it also possible that other flags are set!
* // it is equivalent to: (tpc.flags() & (TCP::SYN | TCP::ACK)) == (TCP::SYN | TCP::ACK)
* // it is equivalent to: (tcp.flags() & (TCP::SYN | TCP::ACK)) == (TCP::SYN | TCP::ACK)
* }
* \endcode
*

View File

@@ -80,5 +80,6 @@
#include <tins/ip_reassembler.h>
#include <tins/pdu_iterator.h>
#include <tins/vxlan.h>
#include <tins/rtp.h>
#endif // TINS_TINS_H

View File

@@ -54,6 +54,7 @@ set(SOURCES
radiotap.cpp
rawpdu.cpp
rsn_information.cpp
rtp.cpp
sll.cpp
snap.cpp
stp.cpp
@@ -131,6 +132,7 @@ set(HEADERS
${LIBTINS_INCLUDE_DIR}/tins/radiotap.h
${LIBTINS_INCLUDE_DIR}/tins/rawpdu.h
${LIBTINS_INCLUDE_DIR}/tins/rsn_information.h
${LIBTINS_INCLUDE_DIR}/tins/rtp.h
${LIBTINS_INCLUDE_DIR}/tins/sll.h
${LIBTINS_INCLUDE_DIR}/tins/small_uint.h
${LIBTINS_INCLUDE_DIR}/tins/snap.h

View File

@@ -705,8 +705,11 @@ WPA2Decrypter::bssids_map::const_iterator WPA2Decrypter::find_ap(const Dot11Data
bool WPA2Decrypter::decrypt(PDU& pdu) {
if (capturer_.process_packet(pdu)) {
try_add_keys(pdu.rfind_pdu<Dot11Data>(), capturer_.handshakes().front());
capturer_.clear_handshakes();
Dot11Data* data = pdu.find_pdu<Dot11Data>();
if (data) {
try_add_keys(*data, capturer_.handshakes().front());
capturer_.clear_handshakes();
}
}
else if (const Dot11Beacon* beacon = pdu.find_pdu<Dot11Beacon>()) {
if (aps_.count(beacon->addr3()) == 0) {

View File

@@ -169,6 +169,8 @@ Tins::PDU* pdu_from_flag(PDU::PDUType type, const uint8_t* buffer, uint32_t size
return new Tins::IEEE802_3(buffer, size);
case Tins::PDU::PPPOE:
return new Tins::PPPoE(buffer, size);
case Tins::PDU::RAW:
return new Tins::RawPDU(buffer, size);
#ifdef TINS_HAVE_DOT11
case Tins::PDU::RADIOTAP:
return new Tins::RadioTap(buffer, size);

View File

@@ -331,7 +331,7 @@ NetworkInterface::Info NetworkInterface::info() const {
}
#else // _WIN32
#ifndef ANDROID
#if !defined(ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 24)
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;
getifaddrs(&ifaddrs);

195
src/rtp.cpp Normal file
View File

@@ -0,0 +1,195 @@
#include <algorithm>
#include <tins/exceptions.h>
#include <tins/internals.h>
#include <tins/memory_helpers.h>
#include <tins/rtp.h>
using std::logic_error;
using Tins::Memory::InputMemoryStream;
using Tins::Memory::OutputMemoryStream;
namespace Tins {
RTP::RTP()
: header_(), ext_header_(), padding_size_(0) {
version(2);
}
RTP::RTP(const uint8_t* buffer, uint32_t total_sz) {
InputMemoryStream stream(buffer, total_sz);
stream.read(header_);
small_uint<4> csrc_count_ = csrc_count();
for (uint32_t i = 0; i < csrc_count_; ++i) {
uint32_t csrc_id;
stream.read(csrc_id);
csrc_ids_.push_back(csrc_id);
}
if (extension_bit() == 1) {
stream.read(ext_header_);
for (uint32_t i = 0; i < extension_length(); ++i) {
uint32_t data;
stream.read(data);
ext_data_.push_back(data);
}
}
padding_size_ = 0;
const uint8_t* data_ptr = stream.pointer();
const size_t data_size = stream.size();
if (padding_bit() == 1) {
if (data_size > 0) {
stream.skip(data_size - sizeof(uint8_t));
stream.read(padding_size_);
} else {
throw malformed_packet();
}
if (padding_size() == 0) {
throw malformed_packet();
}
}
if (padding_size() > data_size) {
throw malformed_packet();
}
if (data_size > padding_size()) {
inner_pdu(
Internals::pdu_from_flag(
PDU::RAW,
data_ptr,
data_size - padding_size()
)
);
}
}
uint32_t RTP::header_size() const {
uint32_t extension_size = 0;
if (extension_bit() == 1) {
extension_size = sizeof(ext_header_) + (extension_length() * sizeof(uint32_t));
}
return static_cast<uint32_t>(sizeof(header_) + (csrc_ids_.size() * sizeof(uint32_t)) + extension_size);
}
void RTP::add_csrc_id(const uint32_t csrc_id) {
small_uint<4> csrc_count_ = csrc_count();
if (TINS_UNLIKELY(csrc_count_ >= 15)) {
throw logic_error("Maximum number of CSRC IDs reached");
}
csrc_ids_.push_back(Endian::host_to_be(csrc_id));
csrc_count(csrc_count_ + 1);
}
bool RTP::remove_csrc_id(const uint32_t csrc_id) {
small_uint<4> csrc_count_ = csrc_count();
if (csrc_count_ == 0) {
return false;
}
csrc_ids_type::iterator iter = search_csrc_id_iterator(Endian::host_to_be(csrc_id));
if (iter == csrc_ids_.end()) {
return false;
}
csrc_ids_.erase(iter);
csrc_count(csrc_count_ - 1);
return true;
}
bool RTP::search_csrc_id(const uint32_t csrc_id) {
csrc_ids_type::const_iterator iter = search_csrc_id_iterator(Endian::host_to_be(csrc_id));
return (iter != csrc_ids_.cend());
}
RTP::csrc_ids_type::const_iterator RTP::search_csrc_id_iterator(const uint32_t csrc_id) const {
return std::find(csrc_ids_.cbegin(), csrc_ids_.cend(), csrc_id);
}
RTP::csrc_ids_type::iterator RTP::search_csrc_id_iterator(const uint32_t csrc_id) {
return std::find(csrc_ids_.begin(), csrc_ids_.end(), csrc_id);
}
void RTP::add_extension_data(const uint32_t value) {
if (TINS_UNLIKELY(extension_length() >= 65535)) {
throw logic_error("Maximum number of extension data reached");
}
extension_bit(1);
ext_data_.push_back(Endian::host_to_be(value));
extension_length(extension_length() + 1);
}
bool RTP::remove_extension_data(const uint32_t value) {
if (extension_bit() == 0 || extension_length() == 0) {
return false;
}
extension_header_data_type::iterator iter = search_extension_data_iterator(Endian::host_to_be(value));
if (iter == ext_data_.end()) {
return false;
}
ext_data_.erase(iter);
extension_length(extension_length() - 1);
if (extension_length() == 0) {
extension_bit(0);
}
return true;
}
bool RTP::search_extension_data(const uint32_t value) {
if (extension_bit() == 0 || extension_length() == 0) {
return false;
}
extension_header_data_type::const_iterator iter = search_extension_data_iterator(Endian::host_to_be(value));
return (iter != ext_data_.cend());
}
RTP::extension_header_data_type::const_iterator RTP::search_extension_data_iterator(const uint32_t data) const {
return std::find(ext_data_.cbegin(), ext_data_.cend(), data);
}
RTP::extension_header_data_type::iterator RTP::search_extension_data_iterator(const uint32_t data) {
return std::find(ext_data_.begin(), ext_data_.end(), data);
}
void RTP::write_serialization(uint8_t* buffer, uint32_t total_sz) {
OutputMemoryStream stream(buffer, total_sz);
stream.write(header_);
for (auto csrc_id : csrc_ids_) {
stream.write(csrc_id);
}
if (extension_bit() == 1) {
stream.write(ext_header_);
for (auto data : ext_data_) {
stream.write(data);
}
}
if (padding_bit() == 1) {
if (padding_size() > 0) {
if (inner_pdu()) {
stream.skip(inner_pdu()->size());
}
stream.fill(padding_size() - 1, 0);
stream.write(padding_size());
} else {
throw pdu_not_serializable();
}
}
}
} // Tins

View File

@@ -59,9 +59,11 @@ Stream::Stream(PDU& packet, const timestamp_type& ts)
client_hw_addr_ = eth->src_addr();
server_hw_addr_ = eth->dst_addr();
}
const TCP& tcp = packet.rfind_pdu<TCP>();
// If this is not the first packet of a stream (SYN), then it's a partial stream
is_partial_stream_ = !tcp.has_flags(TCP::SYN);
const TCP* tcp = packet.find_pdu<TCP>();
if (tcp) {
// If this is not the first packet of a stream (SYN), then it's a partial stream
is_partial_stream_ = !tcp->has_flags(TCP::SYN);
}
}
void Stream::process_packet(PDU& packet, const timestamp_type& ts) {

View File

@@ -413,7 +413,7 @@ set<string> network_interfaces() {
}
#else
set<string> network_interfaces() {
#ifndef ANDROID
#if !defined(ANDROID) || (defined(__ANDROID_API__) && __ANDROID_API__ >= 24)
set<string> output;
struct ifaddrs* ifaddrs = 0;
struct ifaddrs* if_it = 0;

View File

@@ -63,6 +63,7 @@ CREATE_TEST(pppoe)
CREATE_TEST(raw_pdu)
CREATE_TEST(rc4_eapol)
CREATE_TEST(rsn_eapol)
CREATE_TEST(rtp)
CREATE_TEST(sll)
CREATE_TEST(snap)
CREATE_TEST(stp)

292
tests/src/rtp_test.cpp Normal file
View File

@@ -0,0 +1,292 @@
#include <gtest/gtest.h>
#include <string>
#include <tins/endianness.h>
#include <tins/ethernetII.h>
#include <tins/ip.h>
#include <tins/udp.h>
#include <tins/pdu.h>
#include <tins/rawpdu.h>
#include <tins/small_uint.h>
#include <tins/rtp.h>
#define PACKET_SIZE 60ul
#define CSRC_COUNT 5
#define EXTENSION_LENGTH 2
#define PAYLOAD_SIZE 12
using namespace std;
using namespace Tins;
class RTPTest : public testing::Test {
public:
static const uint8_t expected_packet[PACKET_SIZE];
static const uint8_t invalid_packet_one[];
static const uint8_t invalid_packet_two[];
static const uint8_t packet_with_zero_padding_value[];
static const uint8_t packet_without_data_one[];
static const uint8_t packet_without_data_two[];
static const uint8_t packet_with_zero_extension_length[];
static const small_uint<2> version;
static const small_uint<1> padding;
static const small_uint<1> extension;
static const small_uint<4> csrc_count;
static const small_uint<1> marker;
static const small_uint<7> payload_type;
static const uint16_t sequence_number;
static const uint32_t timestamp;
static const uint32_t ssrc_id;
static const uint32_t csrc_ids[CSRC_COUNT];
static const uint16_t profile;
static const uint16_t extension_length;
static const uint32_t extension_data[EXTENSION_LENGTH];
static const uint8_t padding_size;
static const uint8_t payload[PAYLOAD_SIZE];
static const uint16_t dport, sport;
static const IP::address_type dst_ip, src_ip;
static const EthernetII::address_type dst_addr, src_addr;
};
const uint8_t RTPTest::expected_packet[PACKET_SIZE] = {
0xb5, 0xaa, 0xa4, 0x10,
0xde, 0xad, 0xbe, 0xef,
0xab, 0xcd, 0xad, 0xbc,
0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x02,
0x00, 0x00, 0x00, 0x03,
0x00, 0x00, 0x00, 0x04,
0x00, 0x00, 0x00, 0x05,
0x01, 0x01, 0x00, 0x02,
0x77, 0x00, 0x00, 0x00,
0x88, 0x00, 0x00, 0x00,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x00, 0x00, 0x00, 0x04,
};
const uint8_t RTPTest::invalid_packet_one[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0xff,
};
const uint8_t RTPTest::invalid_packet_two[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
};
const uint8_t RTPTest::packet_with_zero_padding_value[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0,
};
const uint8_t RTPTest::packet_without_data_one[] = {
128, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
};
const uint8_t RTPTest::packet_without_data_two[] = {
160, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 7,
};
const uint8_t RTPTest::packet_with_zero_extension_length[] = {
144, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0x56, 0x97, 0, 0,
};
const small_uint<2> RTPTest::version = 2;
const small_uint<1> RTPTest::padding = 1;
const small_uint<1> RTPTest::extension = 1;
const small_uint<4> RTPTest::csrc_count = CSRC_COUNT;
const small_uint<1> RTPTest::marker = 1;
const small_uint<7> RTPTest::payload_type = 42;
const uint16_t RTPTest::sequence_number = 42000;
const uint32_t RTPTest::timestamp = 0xdeadbeef;
const uint32_t RTPTest::ssrc_id = 0xabcdadbc;
const uint32_t RTPTest::csrc_ids[CSRC_COUNT] = { 1, 2, 3, 4, 5 };
const uint16_t RTPTest::profile = 0x0101;
const uint16_t RTPTest::extension_length = EXTENSION_LENGTH;
const uint32_t RTPTest::extension_data[EXTENSION_LENGTH] = { 0x77000000, 0x88000000 };
const uint8_t RTPTest::padding_size = 4;
const uint8_t RTPTest::payload[PAYLOAD_SIZE] = {
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
0x42, 0x42, 0x42, 0x42,
};
const uint16_t RTPTest::dport = 5004;
const uint16_t RTPTest::sport = 30000;
const IP::address_type RTPTest::dst_ip = IP::address_type{"2.2.2.2"};
const IP::address_type RTPTest::src_ip = IP::address_type{"1.1.1.1"};
const EthernetII::address_type RTPTest::dst_addr = EthernetII::address_type{"aa:bb:cc:dd:ee:ff"};
const EthernetII::address_type RTPTest::src_addr = EthernetII::address_type{"8a:8b:8c:8d:8e:8f"};
TEST_F(RTPTest, DefaultConstructor) {
auto const rtp = RTP{};
EXPECT_EQ(rtp.version(), version);
EXPECT_EQ(rtp.padding_bit(), 0);
EXPECT_EQ(rtp.extension_bit(), 0);
EXPECT_EQ(rtp.csrc_count(), 0);
EXPECT_EQ(rtp.marker_bit(), 0);
EXPECT_EQ(rtp.payload_type(), 0);
EXPECT_EQ(rtp.sequence_number(), 0);
EXPECT_EQ(rtp.timestamp(), 0);
EXPECT_EQ(rtp.ssrc_id(), 0);
EXPECT_EQ(rtp.csrc_ids().size(), 0);
EXPECT_EQ(rtp.extension_profile(), 0);
EXPECT_EQ(rtp.extension_length(), 0);
EXPECT_EQ(rtp.extension_data().size(), 0);
EXPECT_EQ(rtp.padding_size(), 0);
EXPECT_EQ(rtp.header_size(), 12);
EXPECT_EQ(rtp.trailer_size(), 0);
}
TEST_F(RTPTest, Serialize) {
auto rtp = RTP{};
rtp.version(version);
rtp.padding_size(padding_size);
rtp.extension_bit(extension);
rtp.marker_bit(marker);
rtp.payload_type(payload_type);
rtp.sequence_number(sequence_number);
rtp.timestamp(timestamp);
rtp.ssrc_id(ssrc_id);
for (auto csrc_id : csrc_ids) {
rtp.add_csrc_id(csrc_id);
}
rtp.extension_profile(profile);
for (auto data : extension_data) {
rtp.add_extension_data(data);
}
auto raw_pdu = RawPDU(payload, PAYLOAD_SIZE);
rtp.inner_pdu(raw_pdu);
EXPECT_EQ(rtp.header_size(), PACKET_SIZE - PAYLOAD_SIZE - padding_size);
EXPECT_EQ(rtp.trailer_size(), padding_size);
auto serialized = rtp.serialize();
ASSERT_EQ(serialized.size(), PACKET_SIZE);
EXPECT_TRUE(std::equal(serialized.begin(), serialized.end(), expected_packet));
}
TEST_F(RTPTest, ConstructorFromBuffer) {
auto rtp = RTP{expected_packet, PACKET_SIZE};
EXPECT_EQ(rtp.version(), version);
EXPECT_EQ(rtp.padding_bit(), padding);
EXPECT_EQ(rtp.extension_bit(), extension);
EXPECT_EQ(rtp.csrc_count(), csrc_count);
EXPECT_EQ(rtp.marker_bit(), marker);
EXPECT_EQ(rtp.payload_type(), payload_type);
EXPECT_EQ(rtp.sequence_number(), sequence_number);
EXPECT_EQ(rtp.timestamp(), timestamp);
EXPECT_EQ(rtp.ssrc_id(), ssrc_id);
auto csrc_id_values = rtp.csrc_ids();
for (size_t i = 0; i < csrc_count; ++i) {
EXPECT_EQ(csrc_id_values[i], Endian::host_to_be(csrc_ids[i]));
}
EXPECT_EQ(rtp.extension_profile(), profile);
EXPECT_EQ(rtp.extension_length(), extension_length);
auto extension_data_values = rtp.extension_data();
for (size_t i = 0; i < extension_length; ++i) {
EXPECT_EQ(extension_data_values[i], Endian::host_to_be(extension_data[i]));
}
EXPECT_EQ(rtp.padding_size(), padding_size);
EXPECT_EQ(rtp.header_size(), PACKET_SIZE - PAYLOAD_SIZE - padding_size);
auto inner_pdu_payload = rtp.inner_pdu()->serialize();
EXPECT_TRUE(std::equal(inner_pdu_payload.begin(), inner_pdu_payload.end(), payload));
auto raw_pdu = RawPDU(payload, PAYLOAD_SIZE);
auto raw_pdu_payload = raw_pdu.serialize();
EXPECT_EQ(rtp.inner_pdu()->size(), raw_pdu.size());
EXPECT_EQ(inner_pdu_payload, raw_pdu_payload);
}
TEST_F(RTPTest, SearchAndRemoveCSRCID) {
auto rtp = RTP{};
for (auto csrc_id : csrc_ids) {
rtp.add_csrc_id(csrc_id);
}
for (size_t i = 0; i < csrc_count; ++i) {
EXPECT_TRUE(rtp.search_csrc_id(csrc_ids[i]));
}
EXPECT_FALSE(rtp.search_csrc_id(0));
EXPECT_FALSE(rtp.remove_csrc_id(0));
EXPECT_TRUE(rtp.remove_csrc_id(csrc_ids[0]));
EXPECT_FALSE(rtp.search_csrc_id(csrc_ids[0]));
}
TEST_F(RTPTest, SearchAndRemoveExtensionData) {
auto rtp = RTP{};
for (auto data : extension_data) {
rtp.add_extension_data(data);
}
for (size_t i = 0; i < extension_length; ++i) {
EXPECT_TRUE(rtp.search_extension_data(extension_data[i]));
}
EXPECT_FALSE(rtp.search_extension_data(0));
EXPECT_FALSE(rtp.remove_extension_data(0));
EXPECT_TRUE(rtp.remove_extension_data(extension_data[0]));
EXPECT_FALSE(rtp.search_extension_data(extension_data[0]));
}
TEST_F(RTPTest, OuterUDP) {
auto pkt = EthernetII{dst_addr, src_addr} / IP{dst_ip, src_ip} / UDP{dport, sport} / RTP{expected_packet, PACKET_SIZE};
auto udp = pkt.find_pdu<UDP>();
ASSERT_TRUE(udp != nullptr);
EXPECT_EQ(udp->dport(), dport);
EXPECT_EQ(udp->sport(), sport);
auto rtp = udp->find_pdu<RTP>();
ASSERT_TRUE(rtp != nullptr);
EXPECT_EQ(rtp->header_size(), PACKET_SIZE - PAYLOAD_SIZE - padding_size);
EXPECT_EQ(rtp->trailer_size(), padding_size);
EXPECT_EQ(rtp->size(), PACKET_SIZE);
EXPECT_EQ(rtp->inner_pdu()->size(), PAYLOAD_SIZE);
auto inner_pdu_payload = rtp->inner_pdu()->serialize();
EXPECT_TRUE(std::equal(inner_pdu_payload.begin(), inner_pdu_payload.end(), payload));
}
TEST_F(RTPTest, PaddingSizeTooLarge) {
EXPECT_THROW((RTP{invalid_packet_one, sizeof(invalid_packet_one)}), malformed_packet);
}
TEST_F(RTPTest, PaddingBitSetWithoutPadding) {
EXPECT_THROW((RTP{invalid_packet_two, sizeof(invalid_packet_two)}), malformed_packet);
}
TEST_F(RTPTest, PacketWithInvalidZeroPaddingValue) {
EXPECT_THROW((RTP{packet_with_zero_padding_value, sizeof(packet_with_zero_padding_value)}), malformed_packet);
}
TEST_F(RTPTest, PacketWithoutData) {
auto rtp = RTP{packet_without_data_one, sizeof(packet_without_data_one)};
EXPECT_EQ(rtp.size(), sizeof(packet_without_data_one));
EXPECT_EQ(rtp.header_size(), sizeof(packet_without_data_one));
EXPECT_EQ(rtp.inner_pdu(), nullptr);
EXPECT_EQ(rtp.padding_size(), 0);
const uint8_t padding_size_ = 7;
rtp = RTP{packet_without_data_two, sizeof(packet_without_data_two)};
EXPECT_EQ(rtp.size(), sizeof(packet_without_data_two));
EXPECT_EQ(rtp.header_size(), sizeof(packet_without_data_two) - padding_size_);
EXPECT_EQ(rtp.inner_pdu(), nullptr);
EXPECT_EQ(rtp.padding_size(), padding_size_);
}
TEST_F(RTPTest, PacketWithZeroExtensionLength) {
auto rtp = RTP{packet_with_zero_extension_length, sizeof(packet_with_zero_extension_length)};
EXPECT_EQ(rtp.size(), sizeof(packet_with_zero_extension_length));
EXPECT_EQ(rtp.header_size(), sizeof(packet_with_zero_extension_length));
EXPECT_EQ(rtp.extension_profile(), 0x5697);
EXPECT_EQ(rtp.extension_length(), 0);
EXPECT_EQ(rtp.extension_data().size(), 0);
}

View File

@@ -34,8 +34,8 @@ const uint8_t VXLANTest::expected_packet[PACKET_SIZE] = {
};
const uint8_t VXLANTest::flags = 8;
const uint16_t VXLANTest::dport = 19627;
const uint16_t VXLANTest::sport = 4789;
const uint16_t VXLANTest::dport = 4789;
const uint16_t VXLANTest::sport = 19627;
const uint16_t VXLANTest::p_type = 0xd0ab;
const small_uint<24> VXLANTest::vni = 0xffffff;
const IP::address_type VXLANTest::dst_ip = IP::address_type{"2.2.2.2"};
@@ -83,7 +83,11 @@ TEST_F(VXLANTest, ConstructorFromBuffer) {
TEST_F(VXLANTest, OuterUDP) {
auto pkt = IP{dst_ip, src_ip} / UDP{dport, sport} / VXLAN{expected_packet, PACKET_SIZE};
auto const vxlan = pkt.find_pdu<VXLAN>();
auto const udp = pkt.find_pdu<UDP>();
ASSERT_TRUE(udp != nullptr);
EXPECT_EQ(udp->dport(), dport);
EXPECT_EQ(udp->sport(), sport);
auto const vxlan = udp->find_pdu<VXLAN>();
ASSERT_TRUE(vxlan != nullptr);
EXPECT_EQ(vxlan->get_flags(), flags);
EXPECT_EQ(vxlan->get_vni(), vni);