Merge branch 'IPv6'

This commit is contained in:
Heikki Tampio 2023-03-20 13:26:51 +02:00
commit a9fc7750dc
16 changed files with 1662 additions and 130 deletions

View File

@ -10,8 +10,9 @@
#ifndef _WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#else
#include <ws2ipdef.h>
#endif
namespace uvgrtp {
// forward declarations
@ -351,6 +352,8 @@ namespace uvgrtp {
*/
uint32_t get_ssrc() const;
bool get_ipv6() const;
private:
/* Initialize the connection by initializing the socket
* and binding ourselves to specified interface and creating
@ -384,10 +387,12 @@ namespace uvgrtp {
std::shared_ptr<uvgrtp::rtcp> rtcp_;
sockaddr_in remote_sockaddr_;
sockaddr_in6 remote_sockaddr_ip6_;
std::string remote_address_;
std::string local_address_;
uint16_t src_port_;
uint16_t dst_port_;
bool ipv6_;
rtp_format_t fmt_;
/* Media context config */

View File

@ -4,6 +4,13 @@
#include "util.hh"
#include "frame.hh"
#ifdef _WIN32
#include <ws2ipdef.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <bitset>
#include <map>
#include <thread>
@ -223,6 +230,8 @@ namespace uvgrtp {
/* Getter for interval_ms_, which is calculated by set_session_bandwidth */
uint32_t get_rtcp_interval_ms() const;
void set_ipv6(bool set);
/* Set RTCP packet transmission interval in milliseconds
*
* Return RTP_OK if interval was set successfully
@ -597,9 +606,11 @@ namespace uvgrtp {
std::map<uint32_t, std::unique_ptr<rtcp_participant>> participants_;
uint8_t num_receivers_; // maximum is 32 at the moment (5 bits)
bool ipv6_;
/* Address of the socket that we are sending data to */
sockaddr_in socket_address_ = {};
sockaddr_in socket_address_;
sockaddr_in6 socket_address_ipv6_;
/* Map for keeping track of sources for timeouts

View File

@ -17,13 +17,21 @@
#include "srtp/srtp.hh"
#include "formats/media.hh"
#include "global.hh"
#ifdef _WIN32
#include <Ws2tcpip.h>
#else
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#endif
#include <cstring>
#include <errno.h>
uvgrtp::media_stream::media_stream(std::string cname, std::string remote_addr,
std::string local_addr, uint16_t src_port, uint16_t dst_port, rtp_format_t fmt,
int rce_flags):
uvgrtp::media_stream::media_stream(std::string cname, std::string remote_addr,
std::string local_addr, uint16_t src_port, uint16_t dst_port, rtp_format_t fmt,
int rce_flags) :
key_(uvgrtp::random::generate_32()),
srtp_(nullptr),
srtcp_(nullptr),
@ -31,10 +39,12 @@ uvgrtp::media_stream::media_stream(std::string cname, std::string remote_addr,
rtp_(nullptr),
rtcp_(nullptr),
remote_sockaddr_(),
remote_sockaddr_ip6_(),
remote_address_(remote_addr),
local_address_(local_addr),
src_port_(src_port),
dst_port_(dst_port),
ipv6_(false),
fmt_(fmt),
rce_flags_(rce_flags),
initialized_(false),
@ -70,9 +80,32 @@ uvgrtp::media_stream::~media_stream()
rtp_error_t uvgrtp::media_stream::init_connection()
{
rtp_error_t ret = RTP_OK;
if ((ret = socket_->init(AF_INET, SOCK_DGRAM, 0)) != RTP_OK)
rtp_error_t ret = RTP_GENERIC_ERROR;
// Use getaddrinfo() to determine whether we are using ipv4 or ipv6 addresses
struct addrinfo hint, *res = NULL;
memset(&hint, '\0', sizeof(hint));
hint.ai_family = PF_UNSPEC;
hint.ai_flags = AI_NUMERICHOST;
if (getaddrinfo(local_address_.c_str(), NULL, &hint, &res) != 0) {
if (getaddrinfo(remote_address_.c_str(), NULL, &hint, &res) != 0) {
UVG_LOG_ERROR("Invalid IP address");
return RTP_GENERIC_ERROR;
}
}
if (res->ai_family == AF_INET6) {
ipv6_ = true;
UVG_LOG_DEBUG("Using an IPv6 address");
}
else {
UVG_LOG_DEBUG("Using an IPv4 address");
}
// Initialize socket
if ((ret = socket_->init(res->ai_family, SOCK_DGRAM, 0)) != RTP_OK) {
return ret;
}
#ifdef _WIN32
/* Make the socket non-blocking */
@ -82,13 +115,17 @@ rtp_error_t uvgrtp::media_stream::init_connection()
UVG_LOG_ERROR("Failed to make the socket non-blocking!");
#endif
short int family = AF_INET;
if (!(rce_flags_ & RCE_RECEIVE_ONLY) && remote_address_ != "" && dst_port_ != 0)
{
// no reason to fail sending even if binding fails so we set remote address first
remote_sockaddr_ = socket_->create_sockaddr(family, remote_address_, dst_port_);
socket_->set_sockaddr(remote_sockaddr_);
if (ipv6_) {
remote_sockaddr_ip6_ = socket_->create_ip6_sockaddr(remote_address_, dst_port_);
socket_->set_sockaddr6(remote_sockaddr_ip6_);
}
else {
remote_sockaddr_ = socket_->create_sockaddr(AF_INET, remote_address_, dst_port_);
socket_->set_sockaddr(remote_sockaddr_);
}
}
else
{
@ -98,9 +135,16 @@ rtp_error_t uvgrtp::media_stream::init_connection()
if (!(rce_flags_ & RCE_SEND_ONLY))
{
if (local_address_ != "" && src_port_ != 0) {
sockaddr_in bind_addr = socket_->create_sockaddr(family, local_address_, src_port_);
if (ipv6_) {
sockaddr_in6 bind_addr6 = socket_->create_ip6_sockaddr(local_address_, src_port_);
ret = socket_->bind_ip6(bind_addr6);
}
else {
sockaddr_in bind_addr = socket_->create_sockaddr(AF_INET, local_address_, src_port_);
ret = socket_->bind(bind_addr);
}
if ((ret = socket_->bind(bind_addr)) != RTP_OK)
if (ret != RTP_OK)
{
log_platform_error("bind(2) failed");
return ret;
@ -108,7 +152,14 @@ rtp_error_t uvgrtp::media_stream::init_connection()
}
else if (src_port_ != 0)
{
if ((ret = socket_->bind(family, INADDR_ANY, src_port_)) != RTP_OK)
if (ipv6_) {
sockaddr_in6 ip6_any = socket_->create_ip6_sockaddr_any(src_port_);
ret = socket_->bind_ip6(ip6_any);
}
else {
ret = socket_->bind(AF_INET, INADDR_ANY, src_port_);
}
if (ret != RTP_OK)
{
log_platform_error("bind(2) to any failed");
return ret;
@ -250,11 +301,14 @@ rtp_error_t uvgrtp::media_stream::init()
UVG_LOG_ERROR("Failed to initialize the underlying socket");
return free_resources(RTP_GENERIC_ERROR);
}
reception_flow_ = std::unique_ptr<uvgrtp::reception_flow> (new uvgrtp::reception_flow());
rtp_ = std::shared_ptr<uvgrtp::rtp> (new uvgrtp::rtp(fmt_, ssrc_));
rtcp_ = std::shared_ptr<uvgrtp::rtcp> (new uvgrtp::rtcp(rtp_, ssrc_, cname_, rce_flags_));
if (ipv6_) {
rtcp_->set_ipv6(true);
}
socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec);
@ -294,7 +348,7 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr<uvgrtp::zrtp> zrtp)
}
rtp_error_t ret = RTP_OK;
if ((ret = zrtp->init(rtp_->get_ssrc(), socket_, remote_sockaddr_, perform_dh)) != RTP_OK) {
if ((ret = zrtp->init(rtp_->get_ssrc(), socket_, remote_sockaddr_, remote_sockaddr_ip6_, perform_dh, ipv6_)) != RTP_OK) {
UVG_LOG_WARN("Failed to initialize ZRTP for media stream!");
return free_resources(ret);
}
@ -310,7 +364,9 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr<uvgrtp::zrtp> zrtp)
zrtp->dh_has_finished(); // only after the DH stream has gotten its keys, do we let non-DH stream perform ZRTP
rtcp_ = std::shared_ptr<uvgrtp::rtcp> (new uvgrtp::rtcp(rtp_, ssrc_, cname_, srtcp_, rce_flags_));
if (ipv6_) {
rtcp_->set_ipv6(true);
}
socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec);
socket_->install_handler(srtp_.get(), srtp_->send_packet_handler);
@ -703,7 +759,7 @@ rtp_error_t uvgrtp::media_stream::configure_ctx(int rcc_flag, ssize_t value)
break;
}
case RCC_SESSION_BANDWIDTH: {
bandwidth_ = value;
bandwidth_ = (uint32_t)value;
// TODO: Is there a max value for bandwidth?
if (value <= 0) {
UVG_LOG_WARN("Bandwidth cannot be negative");
@ -748,6 +804,10 @@ uint32_t uvgrtp::media_stream::get_ssrc() const
return *ssrc_.get();
}
bool uvgrtp::media_stream::get_ipv6() const {
return ipv6_;
}
rtp_error_t uvgrtp::media_stream::init_srtp_with_zrtp(int rce_flags, int type, std::shared_ptr<uvgrtp::base_srtp> srtp,
std::shared_ptr<uvgrtp::zrtp> zrtp)
{

View File

@ -16,6 +16,10 @@
#ifndef _WIN32
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#else
#include <ws2ipdef.h>
#endif
#include <cassert>
@ -40,13 +44,16 @@ constexpr int ESTIMATED_MAX_RECEPTION_TIME_MS = 10;
const uint32_t MAX_SUPPORTED_PARTICIPANTS = 31;
uvgrtp::rtcp::rtcp(std::shared_ptr<uvgrtp::rtp> rtp, std::shared_ptr<std::atomic_uint> ssrc, std::string cname, int rce_flags):
rce_flags_(rce_flags), our_role_(RECEIVER),
rce_flags_(rce_flags), our_role_(RECEIVER),
tp_(0), tc_(0), tn_(0), pmembers_(0),
members_(0), senders_(0), rtcp_bandwidth_(0), reduced_minimum_(0),
we_sent_(false), local_addr_(""), remote_addr_(""), local_port_(0), dst_port_(0),
avg_rtcp_pkt_pize_(0), avg_rtcp_size_(64), rtcp_pkt_count_(0), rtcp_byte_count_(0),
rtcp_pkt_sent_count_(0), initial_(true), ssrc_(ssrc),
num_receivers_(0),
ipv6_(false),
socket_address_({}),
socket_address_ipv6_({}),
sender_hook_(nullptr),
receiver_hook_(nullptr),
sdes_hook_(nullptr),
@ -194,9 +201,13 @@ rtp_error_t uvgrtp::rtcp::start()
active_ = true;
rtcp_socket_ = std::unique_ptr<uvgrtp::socket>(new uvgrtp::socket(0));
rtp_error_t ret = RTP_OK;
if ((ret = rtcp_socket_->init(AF_INET, SOCK_DGRAM, 0)) != RTP_OK)
{
if (ipv6_) {
ret = rtcp_socket_->init(AF_INET6, SOCK_DGRAM, 0);
}
else {
ret = rtcp_socket_->init(AF_INET, SOCK_DGRAM, 0);
}
if (ret != RTP_OK) {
return ret;
}
@ -233,19 +244,47 @@ rtp_error_t uvgrtp::rtcp::start()
if (local_addr_ != "")
{
UVG_LOG_INFO("Binding RTCP to port %s:%d", local_addr_.c_str(), local_port_);
sockaddr_in bind_addr = rtcp_socket_->create_sockaddr(AF_INET, local_addr_, local_port_);
if ((ret = rtcp_socket_->bind(bind_addr)) != RTP_OK)
{
return ret;
if (ipv6_) {
sockaddr_in6 bind_addr6 = rtcp_socket_->create_ip6_sockaddr(local_addr_, local_port_);
if ((ret = rtcp_socket_->bind_ip6(bind_addr6)) != RTP_OK)
{
return ret;
}
}
else {
sockaddr_in bind_addr = rtcp_socket_->create_sockaddr(AF_INET, local_addr_, local_port_);
if ((ret = rtcp_socket_->bind(bind_addr)) != RTP_OK)
{
return ret;
}
}
}
else
{
UVG_LOG_WARN("No local address provided");
return ret;
UVG_LOG_WARN("No local address provided, binding RTCP to INADDR_ANY");
UVG_LOG_INFO("Binding RTCP to port %s:%d", local_addr_.c_str(), local_port_);
if (ipv6_) {
sockaddr_in6 bind_addr6 = rtcp_socket_->create_ip6_sockaddr_any(local_port_);
if ((ret = rtcp_socket_->bind_ip6(bind_addr6)) != RTP_OK)
{
return ret;
}
}
else {
sockaddr_in bind_addr = rtcp_socket_->create_sockaddr(AF_INET, INADDR_ANY, local_port_);
if ((ret = rtcp_socket_->bind(bind_addr)) != RTP_OK)
{
return ret;
}
}
}
if (ipv6_) {
socket_address_ipv6_ = rtcp_socket_->create_ip6_sockaddr(remote_addr_, dst_port_);
}
else {
socket_address_ = rtcp_socket_->create_sockaddr(AF_INET, remote_addr_, dst_port_);
}
socket_address_ = rtcp_socket_->create_sockaddr(AF_INET, remote_addr_, dst_port_);
report_generator_.reset(new std::thread(rtcp_runner, this));
report_reader_.reset(new std::thread(rtcp_report_reader, this));
@ -265,7 +304,7 @@ rtp_error_t uvgrtp::rtcp::stop()
uvgrtp::rtcp::send_bye_packet({ *ssrc_.get()});
if ((ret = this->generate_report()) != RTP_OK)
{
UVG_LOG_ERROR("Failed to send RTCP report with BYE packet!");
UVG_LOG_DEBUG("Failed to send RTCP report with BYE packet!");
}
if (!active_)
@ -313,7 +352,7 @@ void uvgrtp::rtcp::rtcp_runner(rtcp* rtcp)
if ((ret = rtcp->generate_report()) != RTP_OK && ret != RTP_NOT_READY)
{
UVG_LOG_ERROR("Failed to send RTCP status report!");
UVG_LOG_INFO("Failed to send RTCP status report!");
}
//Here we check if there are any timed out sources
@ -1623,7 +1662,7 @@ rtp_error_t uvgrtp::rtcp::send_rtcp_packet_to_participants(uint8_t* frame, uint3
if (rtcp_socket_ != nullptr)
{
std::lock_guard prtcp_lock(participants_mutex_);
if ((ret = rtcp_socket_->sendto(socket_address_, frame, frame_size, 0)) != RTP_OK)
if ((ret = rtcp_socket_->sendto(socket_address_, socket_address_ipv6_, frame, frame_size, 0)) != RTP_OK)
{
UVG_LOG_ERROR("Sending rtcp packet with sendto() failed!");
}
@ -1711,7 +1750,7 @@ rtp_error_t uvgrtp::rtcp::generate_report()
{
/* Check the participants_ map. If there is no other participants, don't send report */
if (participants_.empty()) {
UVG_LOG_DEBUG("No other participants in this session. Report not sent.");
UVG_LOG_INFO("No other participants in this session. Report not sent.");
return RTP_GENERIC_ERROR;
}
@ -1997,6 +2036,10 @@ uint32_t uvgrtp::rtcp::get_rtcp_interval_ms() const
return interval_ms_.load();
}
void uvgrtp::rtcp::set_ipv6(bool set) {
ipv6_ = set;
}
rtp_error_t uvgrtp::rtcp::set_network_addresses(std::string local_addr, std::string remote_addr,
uint16_t local_port, uint16_t dst_port)
{

View File

@ -100,7 +100,7 @@ uvgrtp::media_stream* uvgrtp::session::create_stream(uint16_t src_port, uint16_t
rtp_errno = RTP_INVALID_VALUE;
return nullptr;
}
uvgrtp::media_stream* stream =
new uvgrtp::media_stream(cname_, remote_address_, local_address_, src_port, dst_port, fmt, rce_flags);

View File

@ -8,13 +8,17 @@
#include <thread>
#ifdef _WIN32
#include <Windows.h>
#include <winsock2.h>
#include <Ws2tcpip.h>
#include <ws2def.h>
#include <ws2ipdef.h>
#else
#include <unistd.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#if defined(__MINGW32__) || defined(__MINGW64__)
@ -29,10 +33,13 @@ using namespace mingw;
#define WSABUF_SIZE 256
uvgrtp::socket::socket(int rce_flags):
uvgrtp::socket::socket(int rce_flags) :
socket_(0),
remote_address_(),
local_address_(),
remote_ip6_address_(),
local_ip6_address_(),
ipv6_(false),
rce_flags_(rce_flags),
#ifdef _WIN32
buffers_()
@ -55,7 +62,12 @@ uvgrtp::socket::~socket()
rtp_error_t uvgrtp::socket::init(short family, int type, int protocol)
{
assert(family == AF_INET);
if (family == AF_INET6) {
ipv6_ = true;
}
else {
ipv6_ = false;
}
#ifdef _WIN32
if ((socket_ = ::socket(family, type, protocol)) == INVALID_SOCKET) {
@ -115,6 +127,24 @@ rtp_error_t uvgrtp::socket::bind(sockaddr_in& local_address)
return RTP_OK;
}
rtp_error_t uvgrtp::socket::bind_ip6(sockaddr_in6& local_address)
{
local_ip6_address_ = local_address;
UVG_LOG_DEBUG("Binding to address %s", sockaddr_ip6_to_string(local_ip6_address_).c_str());
if (::bind(socket_, (struct sockaddr*)&local_ip6_address_, sizeof(local_ip6_address_)) < 0) {
#ifdef _WIN32
win_get_last_error();
#else
fprintf(stderr, "%s\n", strerror(errno));
#endif
UVG_LOG_ERROR("Binding to port %u failed!", ntohs(local_address_.sin_port));
return RTP_BIND_ERROR;
}
return RTP_OK;
}
sockaddr_in uvgrtp::socket::create_sockaddr(short family, unsigned host, short port) const
{
assert(family == AF_INET);
@ -145,19 +175,57 @@ sockaddr_in uvgrtp::socket::create_sockaddr(short family, std::string host, shor
return addr;
}
// This function seems to not be currently used anywhere
sockaddr_in6 uvgrtp::socket::create_ip6_sockaddr(unsigned host, short port) const
{
sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
std::string host_str = std::to_string(host);
inet_pton(AF_INET6, host_str.c_str(), &addr.sin6_addr);
addr.sin6_port = htons((uint16_t)port);
return addr;
}
sockaddr_in6 uvgrtp::socket::create_ip6_sockaddr(std::string host, short port) const
{
sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, host.c_str(), &addr.sin6_addr);
addr.sin6_port = htons((uint16_t)port);
return addr;
}
sockaddr_in6 uvgrtp::socket::create_ip6_sockaddr_any(short src_port) {
sockaddr_in6 addr;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_any;
addr.sin6_port = htons(src_port);
return addr;
}
std::string uvgrtp::socket::get_socket_path_string() const
{
if (ipv6_) {
return sockaddr_ip6_to_string(local_ip6_address_) + " -> " + sockaddr_ip6_to_string(remote_ip6_address_);
}
return sockaddr_to_string(local_address_) + " -> " + sockaddr_to_string(remote_address_);
}
std::string uvgrtp::socket::sockaddr_to_string(const sockaddr_in& addr) const
{
int addr_len = INET_ADDRSTRLEN;
if (addr.sin_family == AF_INET6)
{
addr_len = INET6_ADDRSTRLEN;
}
char* c_string = new char[INET_ADDRSTRLEN];
memset(c_string, 0, INET_ADDRSTRLEN);
char* addr_string = new char[addr_len];
memset(addr_string, 0, addr_len);
@ -176,11 +244,27 @@ std::string uvgrtp::socket::sockaddr_to_string(const sockaddr_in& addr) const
return string;
}
std::string uvgrtp::socket::sockaddr_ip6_to_string(const sockaddr_in6& addr6) const
{
char* c_string = new char[INET6_ADDRSTRLEN];
memset(c_string, 0, INET6_ADDRSTRLEN);
inet_ntop(AF_INET6, &addr6.sin6_addr, c_string, INET6_ADDRSTRLEN);
std::string string(c_string);
string.append(":" + std::to_string(ntohs(addr6.sin6_port)));
delete[] c_string;
return string;
}
void uvgrtp::socket::set_sockaddr(sockaddr_in addr)
{
remote_address_ = addr;
}
void uvgrtp::socket::set_sockaddr6(sockaddr_in6 addr)
{
remote_ip6_address_ = addr;
}
socket_t& uvgrtp::socket::get_raw_socket()
{
return socket_;
@ -201,16 +285,23 @@ rtp_error_t uvgrtp::socket::install_handler(void *arg, packet_handler_vec handle
return RTP_OK;
}
rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent)
rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent)
{
int nsend = 0;
#ifndef _WIN32
if ((nsend = ::sendto(socket_, buf, buf_len, send_flags, (const struct sockaddr *)&addr, sizeof(addr))) == -1) {
if (ipv6) {
nsend = ::sendto(socket_, buf, buf_len, send_flags, (const struct sockaddr*)&addr6, sizeof(addr6));
}
else {
nsend = ::sendto(socket_, buf, buf_len, send_flags, (const struct sockaddr*)&addr, sizeof(addr));
}
if (nsend == -1) {
UVG_LOG_ERROR("Failed to send data: %s", strerror(errno));
if (bytes_sent)
if (bytes_sent) {
*bytes_sent = -1;
}
return RTP_SEND_ERROR;
}
#else
@ -219,11 +310,21 @@ rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, uint8_t *buf, size_t buf
data_buf.buf = (char *)buf;
data_buf.len = (ULONG)buf_len;
if (WSASendTo(socket_, &data_buf, 1, &sent_bytes, send_flags, (const struct sockaddr *)&addr, sizeof(addr), nullptr, nullptr) == -1) {
int result = -1;
if (ipv6) {
result = WSASendTo(socket_, &data_buf, 1, &sent_bytes, send_flags, (const struct sockaddr*)&addr6, sizeof(addr6), nullptr, nullptr);
}
else {
result = WSASendTo(socket_, &data_buf, 1, &sent_bytes, send_flags, (const struct sockaddr*)&addr, sizeof(addr), nullptr, nullptr);
}
if (result == -1) {
win_get_last_error();
UVG_LOG_ERROR("Failed to send to %s", sockaddr_to_string(addr).c_str());
if (ipv6_) {
UVG_LOG_ERROR("Failed to send to %s", sockaddr_ip6_to_string(addr6).c_str());
}
else {
UVG_LOG_ERROR("Failed to send to %s", sockaddr_to_string(addr).c_str());
}
if (bytes_sent)
*bytes_sent = -1;
@ -232,8 +333,9 @@ rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, uint8_t *buf, size_t buf
nsend = sent_bytes;
#endif
if (bytes_sent)
if (bytes_sent) {
*bytes_sent = nsend;
}
#ifndef NDEBUG
++sent_packets_;
@ -244,26 +346,28 @@ rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, uint8_t *buf, size_t buf
rtp_error_t uvgrtp::socket::sendto(uint8_t *buf, size_t buf_len, int send_flags)
{
return __sendto(remote_address_, buf, buf_len, send_flags, nullptr);
return __sendto(remote_address_, remote_ip6_address_, ipv6_, buf, buf_len, send_flags, nullptr);
}
rtp_error_t uvgrtp::socket::sendto(uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent)
{
return __sendto(remote_address_, buf, buf_len, send_flags, bytes_sent);
return __sendto(remote_address_, remote_ip6_address_, ipv6_, buf, buf_len, send_flags, bytes_sent);
}
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent)
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, sockaddr_in6& addr6, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent)
{
return __sendto(addr, buf, buf_len, send_flags, bytes_sent);
return __sendto(addr, addr6, ipv6_, buf, buf_len, send_flags, bytes_sent);
}
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, uint8_t *buf, size_t buf_len, int send_flags)
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, sockaddr_in6& addr6, uint8_t *buf, size_t buf_len, int send_flags)
{
return __sendto(addr, buf, buf_len, send_flags, nullptr);
return __sendto(addr, addr6, ipv6_, buf, buf_len, send_flags, nullptr);
}
rtp_error_t uvgrtp::socket::__sendtov(
sockaddr_in& addr,
sockaddr_in6& addr6,
bool ipv6,
uvgrtp::buf_vec& buffers,
int send_flags, int *bytes_sent
)
@ -277,9 +381,14 @@ rtp_error_t uvgrtp::socket::__sendtov(
sent_bytes += buffers.at(i).first;
}
header_.msg_hdr.msg_name = (void *)&addr;
header_.msg_hdr.msg_namelen = sizeof(addr);
if (ipv6) {
header_.msg_hdr.msg_name = (void*)&addr6;
header_.msg_hdr.msg_namelen = sizeof(addr6);
}
else {
header_.msg_hdr.msg_name = (void *)&addr;
header_.msg_hdr.msg_namelen = sizeof(addr);
}
header_.msg_hdr.msg_iov = chunks_;
header_.msg_hdr.msg_iovlen = buffers.size();
header_.msg_hdr.msg_control = 0;
@ -305,12 +414,23 @@ rtp_error_t uvgrtp::socket::__sendtov(
buffers_[i].len = (ULONG)buffers.at(i).first;
buffers_[i].buf = (char *)buffers.at(i).second;
}
if (WSASendTo(socket_, buffers_, (DWORD)buffers.size(), &sent_bytes, send_flags,
(SOCKADDR *)&addr, sizeof(addr), nullptr, nullptr) == -1) {
int success = 0;
if (ipv6) {
success = WSASendTo(socket_, buffers_, (DWORD)buffers.size(), &sent_bytes, send_flags,
(SOCKADDR*)&addr6, sizeof(addr6), nullptr, nullptr);
}
else {
success = WSASendTo(socket_, buffers_, (DWORD)buffers.size(), &sent_bytes, send_flags,
(SOCKADDR*)&addr, sizeof(addr), nullptr, nullptr);
}
if (success != 0) {
win_get_last_error();
UVG_LOG_ERROR("Failed to send to %s", sockaddr_to_string(addr).c_str());
if (ipv6_) {
UVG_LOG_ERROR("Failed to send to %s", sockaddr_ip6_to_string(addr6).c_str());
}
else {
UVG_LOG_ERROR("Failed to send to %s", sockaddr_to_string(addr).c_str());
}
set_bytes(bytes_sent, -1);
return RTP_SEND_ERROR;
@ -338,7 +458,7 @@ rtp_error_t uvgrtp::socket::sendto(buf_vec& buffers, int send_flags)
}
}
return __sendtov(remote_address_, buffers, send_flags, nullptr);
return __sendtov(remote_address_, remote_ip6_address_, ipv6_, buffers, send_flags, nullptr);
}
rtp_error_t uvgrtp::socket::sendto(buf_vec& buffers, int send_flags, int *bytes_sent)
@ -352,10 +472,10 @@ rtp_error_t uvgrtp::socket::sendto(buf_vec& buffers, int send_flags, int *bytes_
}
}
return __sendtov(remote_address_, buffers, send_flags, bytes_sent);
return __sendtov(remote_address_, remote_ip6_address_, ipv6_, buffers, send_flags, bytes_sent);
}
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, buf_vec& buffers, int send_flags)
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, sockaddr_in6& addr6, buf_vec& buffers, int send_flags)
{
rtp_error_t ret = RTP_OK;
@ -365,12 +485,13 @@ rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, buf_vec& buffers, int send
return ret;
}
}
return __sendtov(addr, buffers, send_flags, nullptr);
// buf_vec
return __sendtov(addr, addr6, ipv6_, buffers, send_flags, nullptr);
}
rtp_error_t uvgrtp::socket::sendto(
sockaddr_in& addr,
sockaddr_in6 & addr6,
buf_vec& buffers,
int send_flags, int *bytes_sent
)
@ -383,12 +504,14 @@ rtp_error_t uvgrtp::socket::sendto(
return ret;
}
}
return __sendtov(addr, buffers, send_flags, bytes_sent);
// buf_vec
return __sendtov(addr, addr6, ipv6_, buffers, send_flags, bytes_sent);
}
rtp_error_t uvgrtp::socket::__sendtov(
sockaddr_in& addr,
sockaddr_in6& addr6,
bool ipv6,
uvgrtp::pkt_vec& buffers,
int send_flags, int *bytes_sent
)
@ -404,8 +527,14 @@ rtp_error_t uvgrtp::socket::__sendtov(
for (size_t i = 0; i < buffers.size(); ++i) {
headers[i].msg_hdr.msg_iov = new struct iovec[buffers[i].size()];
headers[i].msg_hdr.msg_iovlen = buffers[i].size();
headers[i].msg_hdr.msg_name = (void *)&addr;
headers[i].msg_hdr.msg_namelen = sizeof(addr);
if (ipv6) {
headers[i].msg_hdr.msg_name = (void*)&addr6;
headers[i].msg_hdr.msg_namelen = sizeof(addr6);
}
else {
headers[i].msg_hdr.msg_name = (void *)&addr;
headers[i].msg_hdr.msg_namelen = sizeof(addr);
}
headers[i].msg_hdr.msg_control = 0;
headers[i].msg_hdr.msg_controllen = 0;
@ -466,18 +595,32 @@ rtp_error_t uvgrtp::socket::__sendtov(
send_:
DWORD sent_bytes_dw = 0;
ret = WSASendTo(
socket_,
wsa_bufs,
(DWORD)buffer.size(),
&sent_bytes_dw,
send_flags,
(SOCKADDR *)&addr,
sizeof(addr),
nullptr,
nullptr
);
if (ipv6) {
ret = WSASendTo(
socket_,
wsa_bufs,
(DWORD)buffer.size(),
&sent_bytes_dw,
send_flags,
(SOCKADDR*)&addr6,
sizeof(addr6),
nullptr,
nullptr
);
}
else {
ret = WSASendTo(
socket_,
wsa_bufs,
(DWORD)buffer.size(),
&sent_bytes_dw,
send_flags,
(SOCKADDR*)&addr,
sizeof(addr),
nullptr,
nullptr
);
}
sent_bytes = sent_bytes_dw;
if (ret == SOCKET_ERROR) {
@ -492,8 +635,12 @@ send_:
{
UVG_LOG_DEBUG("WSASendTo failed with error %li", error);
log_platform_error("WSASendTo() failed");
UVG_LOG_ERROR("Failed to send to %s", sockaddr_to_string(addr).c_str());
if (ipv6_) {
UVG_LOG_ERROR("Failed to send to %s", sockaddr_ip6_to_string(addr6).c_str());
}
else {
UVG_LOG_ERROR("Failed to send to %s", sockaddr_to_string(addr).c_str());
}
}
sent_bytes = -1;
@ -523,8 +670,7 @@ rtp_error_t uvgrtp::socket::sendto(pkt_vec& buffers, int send_flags)
}
}
}
return __sendtov(remote_address_, buffers, send_flags, nullptr);
return __sendtov(remote_address_, remote_ip6_address_, ipv6_, buffers, send_flags, nullptr);
}
rtp_error_t uvgrtp::socket::sendto(pkt_vec& buffers, int send_flags, int *bytes_sent)
@ -539,11 +685,10 @@ rtp_error_t uvgrtp::socket::sendto(pkt_vec& buffers, int send_flags, int *bytes_
}
}
}
return __sendtov(remote_address_, buffers, send_flags, bytes_sent);
return __sendtov(remote_address_, remote_ip6_address_, ipv6_, buffers, send_flags, bytes_sent);
}
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, pkt_vec& buffers, int send_flags)
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, sockaddr_in6& addr6, pkt_vec& buffers, int send_flags)
{
rtp_error_t ret = RTP_OK;
@ -555,11 +700,10 @@ rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, pkt_vec& buffers, int send
}
}
}
return __sendtov(addr, buffers, send_flags, nullptr);
return __sendtov(addr, addr6, ipv6_, buffers, send_flags, nullptr);
}
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, pkt_vec& buffers, int send_flags, int *bytes_sent)
rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, sockaddr_in6& addr6, pkt_vec& buffers, int send_flags, int *bytes_sent)
{
rtp_error_t ret = RTP_OK;
@ -571,8 +715,7 @@ rtp_error_t uvgrtp::socket::sendto(sockaddr_in& addr, pkt_vec& buffers, int send
}
}
}
return __sendtov(addr, buffers, send_flags, bytes_sent);
return __sendtov(addr, addr6, ipv6_, buffers, send_flags, bytes_sent);
}
rtp_error_t uvgrtp::socket::__recv(uint8_t *buf, size_t buf_len, int recv_flags, int *bytes_read)
@ -694,6 +837,61 @@ rtp_error_t uvgrtp::socket::__recvfrom(uint8_t *buf, size_t buf_len, int recv_fl
return RTP_OK;
}
rtp_error_t uvgrtp::socket::__recvfrom_ip6(uint8_t* buf, size_t buf_len, int recv_flags, sockaddr_in6* sender, int* bytes_read)
{
socklen_t* len_ptr = nullptr;
socklen_t len = sizeof(sockaddr_in6);
if (sender)
len_ptr = &len;
#ifndef _WIN32
int32_t ret = ::recvfrom(socket_, buf, buf_len, recv_flags, (struct sockaddr*)sender, len_ptr);
if (ret == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
set_bytes(bytes_read, 0);
return RTP_INTERRUPTED;
}
UVG_LOG_ERROR("recvfrom failed: %s", strerror(errno));
set_bytes(bytes_read, -1);
return RTP_GENERIC_ERROR;
}
set_bytes(bytes_read, ret);
#else
(void)recv_flags;
WSABUF DataBuf;
DataBuf.len = (u_long)buf_len;
DataBuf.buf = (char*)buf;
DWORD bytes_received = 0;
DWORD d_recv_flags = 0;
int rc = ::WSARecvFrom(socket_, &DataBuf, 1, &bytes_received, &d_recv_flags, (SOCKADDR*)sender, (int*)len_ptr, NULL, NULL);
if (WSAGetLastError() == WSAEWOULDBLOCK)
return RTP_INTERRUPTED;
int err = 0;
if ((rc == SOCKET_ERROR) && (WSA_IO_PENDING != (err = WSAGetLastError()))) {
/* win_get_last_error(); */
set_bytes(bytes_read, -1);
return RTP_GENERIC_ERROR;
}
set_bytes(bytes_read, bytes_received);
#endif
#ifndef NDEBUG
++received_packets_;
#endif // !NDEBUG
return RTP_OK;
}
rtp_error_t uvgrtp::socket::recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, sockaddr_in *sender, int *bytes_read)
{
return __recvfrom(buf, buf_len, recv_flags, sender, bytes_read);
@ -701,6 +899,9 @@ rtp_error_t uvgrtp::socket::recvfrom(uint8_t *buf, size_t buf_len, int recv_flag
rtp_error_t uvgrtp::socket::recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, int *bytes_read)
{
if (ipv6_) {
return __recvfrom_ip6(buf, buf_len, recv_flags, nullptr, bytes_read);
}
return __recvfrom(buf, buf_len, recv_flags, nullptr, bytes_read);
}

View File

@ -3,13 +3,18 @@
#include "uvgrtp/util.hh"
#ifdef _WIN32
#include <Windows.h>
#include <winsock2.h>
#include <mswsock.h>
#include <inaddr.h>
#include <ws2ipdef.h>
#include <WS2tcpip.h>
#else
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <vector>
@ -83,6 +88,7 @@ namespace uvgrtp {
* Return RTP_BIND_ERROR if the bind failed */
rtp_error_t bind(short family, unsigned host, short port);
rtp_error_t bind(sockaddr_in& local_address);
rtp_error_t bind_ip6(sockaddr_in6& local_address);
/* Same as setsockopt(2), used to manipulate the underlying socket object
*
@ -100,6 +106,7 @@ namespace uvgrtp {
*
* Return RTP_OK on success and write the amount of bytes sent to "bytes_sent"
* Return RTP_SEND_ERROR on error and set "bytes_sent" to -1 */
// nämä done
rtp_error_t sendto(uint8_t *buf, size_t buf_len, int send_flags);
rtp_error_t sendto(uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent);
rtp_error_t sendto(buf_vec& buffers, int send_flags);
@ -108,12 +115,12 @@ namespace uvgrtp {
rtp_error_t sendto(pkt_vec& buffers, int send_flags, int *bytes_sent);
/* Same as sendto() but the remote address given as parameter */
rtp_error_t sendto(sockaddr_in& addr, uint8_t *buf, size_t buf_len, int send_flags);
rtp_error_t sendto(sockaddr_in& addr, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent);
rtp_error_t sendto(sockaddr_in& addr, buf_vec& buffers, int send_flags);
rtp_error_t sendto(sockaddr_in& addr, buf_vec& buffers, int send_flags, int *bytes_sent);
rtp_error_t sendto(sockaddr_in& addr, pkt_vec& buffers, int send_flags);
rtp_error_t sendto(sockaddr_in& addr, pkt_vec& buffers, int send_flags, int *bytes_sent);
rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, uint8_t *buf, size_t buf_len, int send_flags);
rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent);
rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, buf_vec& buffers, int send_flags);
rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, buf_vec& buffers, int send_flags, int *bytes_sent);
rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, pkt_vec& buffers, int send_flags);
rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, pkt_vec& buffers, int send_flags, int *bytes_sent);
/* Same as recv(2), receives a message from socket (remote address not known)
*
@ -138,7 +145,7 @@ namespace uvgrtp {
rtp_error_t recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, int *bytes_read);
rtp_error_t recvfrom(uint8_t *buf, size_t buf_len, int recv_flags);
/* Create sockaddr_in object using the provided information
/* Create sockaddr_in (IPv4) object using the provided information
* NOTE: "family" must be AF_INET */
sockaddr_in create_sockaddr(short family, unsigned host, short port) const;
@ -146,9 +153,16 @@ namespace uvgrtp {
* NOTE: "family" must be AF_INET */
sockaddr_in create_sockaddr(short family, std::string host, short port) const;
/* Create sockaddr_in6 (IPv6) object using the provided information */
sockaddr_in6 create_ip6_sockaddr(unsigned host, short port) const;
sockaddr_in6 create_ip6_sockaddr(std::string host, short port) const;
sockaddr_in6 create_ip6_sockaddr_any(short src_port);
std::string get_socket_path_string() const;
std::string sockaddr_to_string(const sockaddr_in& addr) const;
std::string sockaddr_ip6_to_string(const sockaddr_in6& addr6) const;
/* Get reference to the actual socket object */
socket_t& get_raw_socket();
@ -157,6 +171,7 @@ namespace uvgrtp {
* This is used when calling send() */
void set_sockaddr(sockaddr_in addr);
void set_sockaddr6(sockaddr_in6 addr);
/* Get the out address for the socket if it exists */
sockaddr_in& get_out_address();
@ -172,17 +187,24 @@ namespace uvgrtp {
private:
/* helper function for sending UPD packets, see documentation for sendto() above */
rtp_error_t __sendto(sockaddr_in& addr, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent);
rtp_error_t __sendto(sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6, uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent);
rtp_error_t __recv(uint8_t *buf, size_t buf_len, int recv_flags, int *bytes_read);
rtp_error_t __recvfrom_ip6(uint8_t* buf, size_t buf_len, int recv_flags, sockaddr_in6* sender, int* bytes_read);
rtp_error_t __recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, sockaddr_in *sender, int *bytes_read);
/* __sendtov() does the same as __sendto but it combines multiple buffers into one frame and sends them */
rtp_error_t __sendtov(sockaddr_in& addr, buf_vec& buffers, int send_flags, int *bytes_sent);
rtp_error_t __sendtov(sockaddr_in& addr, uvgrtp::pkt_vec& buffers, int send_flags, int *bytes_sent);
rtp_error_t __sendtov(sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6, buf_vec& buffers, int send_flags, int *bytes_sent);
rtp_error_t __sendtov(sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6, uvgrtp::pkt_vec& buffers, int send_flags, int *bytes_sent);
socket_t socket_;
sockaddr_in remote_address_;
sockaddr_in local_address_;
sockaddr_in6 remote_ip6_address_;
sockaddr_in6 local_ip6_address_;
bool ipv6_;
int rce_flags_;
/* __sendto() calls these handlers in order before sending the packet */

View File

@ -11,7 +11,12 @@
#include "crypto.hh"
#include "random.hh"
#include "debug.hh"
#ifdef _WIN32
#include <ws2ipdef.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <cstring>
#include <thread>
@ -27,6 +32,7 @@ using namespace uvgrtp::zrtp_msg;
uvgrtp::zrtp::zrtp():
ssrc_(0),
remote_addr_(),
remote_ip6_addr_(),
initialized_(false),
receiver_(),
dh_finished_(false)
@ -377,7 +383,7 @@ rtp_error_t uvgrtp::zrtp::begin_session()
UVG_LOG_DEBUG("Sending ZRTP hello # %i, path: %s", i + 1, path.c_str());
int type = 0;
if (hello.send_msg(local_socket_, remote_addr_) != RTP_OK) {
if (hello.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Hello message");
}
else if (receiver_.recv_msg(local_socket_, rto, 0, type) == RTP_OK) {
@ -388,7 +394,7 @@ rtp_error_t uvgrtp::zrtp::begin_session()
/* We received Hello message from remote, parse it and send */
if (type == ZRTP_FT_HELLO) {
UVG_LOG_DEBUG("Got ZRTP Hello. Sending Hello ACK");
hello_ack.send_msg(local_socket_, remote_addr_);
hello_ack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
if (!hello_recv) {
hello_recv = true;
@ -480,7 +486,7 @@ rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
rto = 150;
for (int i = 0; i < 10; ++i) {
if (commit.send_msg(local_socket_, remote_addr_) != RTP_OK) {
if (commit.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Commit message!");
}
else if (receiver_.recv_msg(local_socket_, rto, 0, type) == RTP_OK) {
@ -519,7 +525,7 @@ rtp_error_t uvgrtp::zrtp::dh_part1()
int type = 0;
for (int i = 0; i < 10; ++i) {
if (dhpart.send_msg(local_socket_, remote_addr_) != RTP_OK) {
if (dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send DHPart1 Message!");
}
@ -563,7 +569,7 @@ rtp_error_t uvgrtp::zrtp::dh_part2()
generate_shared_secrets_dh();
for (int i = 0; i < 10; ++i) {
if ((ret = dhpart.send_msg(local_socket_, remote_addr_)) != RTP_OK) {
if ((ret = dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) {
UVG_LOG_ERROR("Failed to send DHPart2 Message!");
return ret;
}
@ -590,7 +596,7 @@ rtp_error_t uvgrtp::zrtp::responder_finalize_session()
int type = 0;
for (int i = 0; i < 10; ++i) {
if (confirm.send_msg(local_socket_, remote_addr_) != RTP_OK) {
if (confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Confirm1 Message!");
}
@ -608,7 +614,7 @@ rtp_error_t uvgrtp::zrtp::responder_finalize_session()
}
/* TODO: send in a loop? */
confack.send_msg(local_socket_, remote_addr_);
confack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
return RTP_OK;
}
}
@ -638,7 +644,7 @@ rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
}
for (int i = 0; i < 10; ++i) {
if ((ret = confirm.send_msg(local_socket_, remote_addr_)) != RTP_OK) {
if ((ret = confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) {
UVG_LOG_ERROR("Failed to send Confirm2 Message!");
return ret;
}
@ -657,7 +663,7 @@ rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
return RTP_TIMEOUT;
}
rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, bool perform_dh)
rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool perform_dh, bool ipv6)
{
rtp_error_t ret = RTP_OK;
@ -672,7 +678,7 @@ rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> so
}
// perform Diffie-Hellman (DH)
ret = init_dhm(ssrc, socket, addr);
ret = init_dhm(ssrc, socket, addr, addr6, ipv6);
zrtp_mtx_.unlock();
}
else
@ -684,17 +690,21 @@ rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> so
}
// multistream mode
ret = init_msm(ssrc, socket, addr);
ret = init_msm(ssrc, socket, addr, addr6);
}
return ret;
}
rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr)
rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6)
{
rtp_error_t ret = RTP_OK;
UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", socket->sockaddr_to_string(addr).c_str());
if (ipv6) {
UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", socket->sockaddr_ip6_to_string(addr6).c_str());
}
else {
UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", socket->sockaddr_to_string(addr).c_str());
}
/* TODO: set all fields initially to zero */
memset(session_.hash_ctx.o_hvi, 0, sizeof(session_.hash_ctx.o_hvi));
@ -708,6 +718,7 @@ rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
local_socket_ = socket;
remote_addr_ = addr;
remote_ip6_addr_ = addr6;
session_.seq = 0;
session_.ssrc = ssrc;
@ -789,12 +800,13 @@ rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
return RTP_OK;
}
rtp_error_t uvgrtp::zrtp::init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr)
rtp_error_t uvgrtp::zrtp::init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6)
{
rtp_error_t ret;
local_socket_ = socket;
remote_addr_ = addr;
remote_ip6_addr_ = addr6;
session_.ssrc = ssrc;
session_.seq = 0;

View File

@ -8,9 +8,13 @@
#include <winsock2.h>
#include <mswsock.h>
#include <inaddr.h>
#include <ws2ipdef.h>
#else
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#endif
#include <mutex>
@ -42,7 +46,7 @@ namespace uvgrtp {
*
* Return RTP_OK on success
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
rtp_error_t init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, bool perform_dh);
rtp_error_t init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool perform_dh, bool ipv6);
/* Get SRTP keys for the session that was just initialized
*
@ -85,13 +89,13 @@ namespace uvgrtp {
*
* Return RTP_OK on success
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
rtp_error_t init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr);
rtp_error_t init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6);
/* Initialize ZRTP session between us and remote using Multistream mode
*
* Return RTP_OK on success
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
rtp_error_t init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr);
rtp_error_t init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6);
/* Generate zid for this ZRTP instance. ZID is a unique, 96-bit long ID */
void generate_zid();
@ -170,6 +174,7 @@ namespace uvgrtp {
uint32_t ssrc_;
std::shared_ptr<uvgrtp::socket> local_socket_;
sockaddr_in remote_addr_;
sockaddr_in6 remote_ip6_addr_;
/* Has the ZRTP connection been initialized using DH */
bool initialized_;

View File

@ -6,6 +6,12 @@
#include "debug.hh"
#include <string>
#ifdef _WIN32
#include <ws2ipdef.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
uvgrtp::zrtp_msg::zrtp_message::zrtp_message():
frame_(nullptr),
@ -26,11 +32,10 @@ uvgrtp::zrtp_msg::zrtp_message::~zrtp_message()
(void)uvgrtp::frame::dealloc_frame((uvgrtp::frame::zrtp_frame*)rframe_);
}
rtp_error_t uvgrtp::zrtp_msg::zrtp_message::send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr)
rtp_error_t uvgrtp::zrtp_msg::zrtp_message::send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6)
{
rtp_error_t ret;
if ((ret = socket->sendto(addr, (uint8_t *)frame_, len_, 0, nullptr)) != RTP_OK)
if ((ret = socket->sendto(addr, addr6, (uint8_t*)frame_, len_, 0, nullptr)) != RTP_OK)
log_platform_error("Failed to send ZRTP message");
return ret;

View File

@ -7,6 +7,12 @@
#include "uvgrtp/util.hh"
#include <memory>
#ifdef _WIN32
#include <ws2ipdef.h>
#else
#include <sys/socket.h>
#include <netinet/in.h>
#endif
namespace uvgrtp {
@ -19,7 +25,7 @@ namespace uvgrtp {
zrtp_message();
~zrtp_message();
rtp_error_t send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr);
rtp_error_t send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6);
virtual rtp_error_t parse_msg(uvgrtp::zrtp_msg::receiver& receiver,
zrtp_session_t& session) = 0;

View File

@ -12,6 +12,10 @@ target_sources(${PROJECT_NAME} PRIVATE
test_4_formats.cpp
test_5_srtp_zrtp.cpp
test_6_scl_unit_test.cpp
test_7_rtp_ipv6.cpp
test_8_rtcp_ipv6.cpp
test_9_formats_ipv6.cpp
test_10_srtp_zrtp_ipv6.cpp
test_common.hh
)

View File

@ -0,0 +1,361 @@
#include "test_common.hh"
// network parameters of example
constexpr char SENDER_ADDRESS[] = "::1";
constexpr uint16_t SENDER_PORT = 9000;
constexpr char RECEIVER_ADDRESS[] = "::1";
constexpr uint16_t RECEIVER_PORT = 9042;
constexpr auto EXAMPLE_DURATION_S = std::chrono::seconds(2);
// encryption parameters of example
enum Key_length { SRTP_128 = 128, SRTP_196 = 196, SRTP_256 = 256 };
constexpr int SALT_SIZE = 112;
constexpr int SALT_SIZE_BYTES = SALT_SIZE / 8;
void user_send_func6(uint8_t* key, uint8_t salt[SALT_SIZE_BYTES], uint8_t key_size);
void user_receive_func6(uint8_t* key, uint8_t salt[SALT_SIZE_BYTES], uint8_t key_size);
void zrtp_sender_func6(uvgrtp::session* sender_session, int sender_port, int receiver_port, unsigned int flags);
void zrtp_receive_func6(uvgrtp::session* receiver_session, int sender_port, int receiver_port, unsigned int flags);
void test_user_key6(Key_length len);
// User key management test
TEST(EncryptionTests_ip6, srtp_user_key_128_ip6)
{
test_user_key6(SRTP_128);
}
TEST(EncryptionTests_ip6, srtp_user_key_196_ip6)
{
test_user_key6(SRTP_196);
}
TEST(EncryptionTests_ip6, srtp_user_key_256_ip6)
{
test_user_key6(SRTP_256);
}
void test_user_key6(Key_length len)
{
std::cout << "Starting ZRTP sender thread" << std::endl;
uvgrtp::context ctx;
if (!ctx.crypto_enabled())
{
std::cout << "Please link crypto to uvgRTP library in order to tests its SRTP user keys!" << std::endl;
FAIL();
return;
}
uint8_t* key = new uint8_t[len];
uint8_t salt[SALT_SIZE_BYTES] = { 0 };
// initialize SRTP key and salt with dummy values
for (int i = 0; i < len; ++i)
key[i] = i;
for (int i = 0; i < SALT_SIZE_BYTES; ++i)
salt[i] = i * 2;
std::unique_ptr<std::thread> sender_thread = std::unique_ptr<std::thread>(new std::thread(user_send_func6, key, salt, len));
std::unique_ptr<std::thread> receiver_thread = std::unique_ptr<std::thread>(new std::thread(user_receive_func6, key, salt, len));
if (sender_thread && sender_thread->joinable())
{
sender_thread->join();
}
if (receiver_thread && receiver_thread->joinable())
{
receiver_thread->join();
}
delete[] key;
}
void user_send_func6(uint8_t* key, uint8_t salt[SALT_SIZE_BYTES], uint8_t key_size)
{
uvgrtp::context ctx;
uvgrtp::session* sender_session = nullptr;
uvgrtp::media_stream* send = nullptr;
sender_session = ctx.create_session(RECEIVER_ADDRESS);
// Enable SRTP and let user manage the keys
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER;
if (key_size == 192)
{
flags |= RCE_SRTP_KEYSIZE_192;
}
else if (key_size == 256)
{
flags |= RCE_SRTP_KEYSIZE_256;
}
if (sender_session)
{
send = sender_session->create_stream(SENDER_PORT, RECEIVER_PORT, RTP_FORMAT_GENERIC, flags);
}
if (send)
send->add_srtp_ctx(key, salt); // add user context
EXPECT_NE(nullptr, sender_session);
EXPECT_NE(nullptr, send);
if (sender_session && send)
{
int test_packets = 10;
size_t frame_size = strlen((char*)"Hello, world!");
std::unique_ptr<uint8_t[]> test_frame = create_test_packet(RTP_FORMAT_GENERIC, 0, false, frame_size, RTP_NO_FLAGS);
send_packets(std::move(test_frame), frame_size, sender_session, send, test_packets, 0, true, RTP_NO_FLAGS);
cleanup_ms(sender_session, send);
cleanup_sess(ctx, sender_session);
}
}
void user_receive_func6(uint8_t* key, uint8_t salt[SALT_SIZE_BYTES], uint8_t key_size)
{
/* See sending.cc for more details */
uvgrtp::context ctx;
uvgrtp::session* receiver_session = ctx.create_session(SENDER_ADDRESS);
/* Enable SRTP and let user manage keys */
unsigned flags = RCE_SRTP | RCE_SRTP_KMNGMNT_USER;
if (key_size == 192)
{
flags |= RCE_SRTP_KEYSIZE_192;
}
else if (key_size == 256)
{
flags |= RCE_SRTP_KEYSIZE_256;
}
/* See sending.cc for more details about create_stream() */
uvgrtp::media_stream* recv = nullptr;
if (receiver_session)
{
recv = receiver_session->create_stream(RECEIVER_PORT, SENDER_PORT, RTP_FORMAT_GENERIC, flags);
}
if (recv)
{
recv->add_srtp_ctx(key, salt);
}
auto start = std::chrono::steady_clock::now();
uvgrtp::frame::rtp_frame* frame = nullptr;
if (recv)
{
while (std::chrono::steady_clock::now() - start < EXAMPLE_DURATION_S)
{
frame = recv->pull_frame(10);
if (frame)
{
process_rtp_frame(frame);
}
}
}
cleanup_ms(receiver_session, recv);
cleanup_sess(ctx, receiver_session);
}
// ZRTP key management tests
TEST(EncryptionTests_ip6, zrtp_ip6)
{
uvgrtp::context ctx;
if (!ctx.crypto_enabled())
{
std::cout << "Please link crypto to uvgRTP library in order to tests its ZRTP feature!" << std::endl;
FAIL();
return;
}
uvgrtp::session* sender_session = ctx.create_session(RECEIVER_ADDRESS, SENDER_ADDRESS);
uvgrtp::session* receiver_session = ctx.create_session(SENDER_ADDRESS, RECEIVER_ADDRESS);
unsigned zrtp_flags = RCE_SRTP | RCE_SRTP_KMNGMNT_ZRTP;
std::unique_ptr<std::thread> sender_thread =
std::unique_ptr<std::thread>(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT, RECEIVER_PORT, zrtp_flags));
std::unique_ptr<std::thread> receiver_thread =
std::unique_ptr<std::thread>(new std::thread(zrtp_receive_func6, receiver_session, SENDER_PORT, RECEIVER_PORT, zrtp_flags));
if (sender_thread && sender_thread->joinable())
{
sender_thread->join();
}
if (receiver_thread && receiver_thread->joinable())
{
receiver_thread->join();
}
cleanup_sess(ctx, sender_session);
cleanup_sess(ctx, receiver_session);
}
TEST(EncryptionTests_ip6, zrtp_authenticate_ip6)
{
uvgrtp::context ctx;
if (!ctx.crypto_enabled())
{
std::cout << "Please link crypto to uvgRTP library in order to tests its ZRTP feature!" << std::endl;
FAIL();
return;
}
uvgrtp::session* sender_session = ctx.create_session(RECEIVER_ADDRESS, SENDER_ADDRESS);
uvgrtp::session* receiver_session = ctx.create_session(SENDER_ADDRESS, RECEIVER_ADDRESS);
unsigned zrtp_flags = RCE_SRTP | RCE_SRTP_KMNGMNT_ZRTP | RCE_SRTP_AUTHENTICATE_RTP;
std::unique_ptr<std::thread> sender_thread =
std::unique_ptr<std::thread>(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT, RECEIVER_PORT, zrtp_flags));
std::unique_ptr<std::thread> receiver_thread =
std::unique_ptr<std::thread>(new std::thread(zrtp_receive_func6, receiver_session, SENDER_PORT, RECEIVER_PORT, zrtp_flags));
if (sender_thread && sender_thread->joinable())
{
sender_thread->join();
}
if (receiver_thread && receiver_thread->joinable())
{
receiver_thread->join();
}
cleanup_sess(ctx, sender_session);
cleanup_sess(ctx, receiver_session);
}
TEST(EncryptionTests_ip6, zrtp_multistream_ip6)
{
uvgrtp::context ctx;
if (!ctx.crypto_enabled())
{
std::cout << "Please link crypto to uvgRTP library in order to tests its ZRTP feature!" << std::endl;
FAIL();
return;
}
/* Enable SRTP and ZRTP */
unsigned zrtp_dh_flags = RCE_SRTP | RCE_SRTP_KMNGMNT_ZRTP | RCE_ZRTP_DIFFIE_HELLMAN_MODE;
// only one of the streams should perform DH
unsigned int zrtp_multistream_flags = RCE_SRTP | RCE_SRTP_KMNGMNT_ZRTP | RCE_ZRTP_MULTISTREAM_MODE;
uvgrtp::session* sender_session = ctx.create_session(RECEIVER_ADDRESS, SENDER_ADDRESS);
uvgrtp::session* receiver_session = ctx.create_session(SENDER_ADDRESS, RECEIVER_ADDRESS);
std::unique_ptr<std::thread> sender_thread1 =
std::unique_ptr<std::thread>(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT + 2, RECEIVER_PORT + 2, zrtp_dh_flags));
std::unique_ptr<std::thread> receiver_thread1 =
std::unique_ptr<std::thread>(new std::thread(zrtp_receive_func6, receiver_session, SENDER_PORT + 2, RECEIVER_PORT + 2, zrtp_dh_flags));
std::unique_ptr<std::thread> sender_thread2 =
std::unique_ptr<std::thread>(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT + 4, RECEIVER_PORT + 4, zrtp_multistream_flags));
std::unique_ptr<std::thread> receiver_thread2 =
std::unique_ptr<std::thread>(new std::thread(zrtp_receive_func6, receiver_session, SENDER_PORT + 4, RECEIVER_PORT + 4, zrtp_multistream_flags));
if (receiver_thread1 && receiver_thread1->joinable())
{
receiver_thread1->join();
}
if (sender_thread1 && sender_thread1->joinable())
{
sender_thread1->join();
}
if (sender_thread2 && sender_thread2->joinable())
{
sender_thread2->join();
}
if (receiver_thread2 && receiver_thread2->joinable())
{
receiver_thread2->join();
}
cleanup_sess(ctx, sender_session);
cleanup_sess(ctx, receiver_session);
}
void zrtp_sender_func6(uvgrtp::session* sender_session, int sender_port, int receiver_port, unsigned int flags)
{
std::cout << "Starting ZRTP sender thread" << std::endl;
/* See sending.cc for more details about create_stream() */
uvgrtp::media_stream* send = nullptr;
if (sender_session)
{
send = sender_session->create_stream(sender_port, receiver_port, RTP_FORMAT_GENERIC, flags);
}
auto start = std::chrono::steady_clock::now();
uvgrtp::frame::rtp_frame* frame = nullptr;
if (send)
{
int test_packets = 10;
size_t packet_size = 1000;
int packet_interval_ms = EXAMPLE_DURATION_S.count() * 1000 / test_packets;
std::unique_ptr<uint8_t[]> test_frame = create_test_packet(RTP_FORMAT_GENERIC, 0, false, packet_size, RTP_NO_FLAGS);
send_packets(std::move(test_frame), packet_size, sender_session, send, test_packets, packet_interval_ms, false, RTP_NO_FLAGS);
}
cleanup_ms(sender_session, send);
}
void zrtp_receive_func6(uvgrtp::session* receiver_session, int sender_port, int receiver_port, unsigned int flags)
{
std::cout << "Starting ZRTP receiver thread" << std::endl;
/* See sending.cc for more details about create_stream() */
uvgrtp::media_stream* recv = nullptr;
if (receiver_session)
{
recv = receiver_session->create_stream(receiver_port, sender_port, RTP_FORMAT_GENERIC, flags);
}
auto start = std::chrono::steady_clock::now();
uvgrtp::frame::rtp_frame* frame = nullptr;
if (recv)
{
while (std::chrono::steady_clock::now() - start < EXAMPLE_DURATION_S)
{
frame = recv->pull_frame(10);
if (frame)
{
process_rtp_frame(frame);
}
}
}
cleanup_ms(receiver_session, recv);
}

201
test/test_7_rtp_ipv6.cpp Normal file
View File

@ -0,0 +1,201 @@
#include "test_common.hh"
/* TODO: 1) Test only sending, 2) test sending with different configuration, 3) test receiving with different configurations, and
* 4) test sending and receiving within same test while checking frame size */
// parameters for this test. You can change these to suit your network environment
constexpr uint16_t SEND_PORT = 9300;
constexpr char REMOTE_ADDRESS[] = "::1";
constexpr uint16_t RECEIVE_PORT = 9302;
void rtp_receive_hook(void* arg, uvgrtp::frame::rtp_frame* frame);
void process_rtp_frame(uvgrtp::frame::rtp_frame* frame);
void test_wait(int time_ms, uvgrtp::media_stream* receiver);
TEST(RTPTests_ip6, rtp_hook_ip6)
{
// Tests installing a hook to uvgRTP
std::cout << "Starting IPv6 RTP hook test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int flags = RCE_FRAGMENT_GENERIC;
if (sess)
{
sender = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_GENERIC, flags);
receiver = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_GENERIC, flags);
}
int test_packets = 10;
std::vector<size_t> sizes = { 1000, 2000 };
for (size_t& size : sizes)
{
std::unique_ptr<uint8_t[]> test_frame = create_test_packet(RTP_FORMAT_GENERIC, 0, false, size, RTP_NO_FLAGS);
test_packet_size(std::move(test_frame), test_packets, size, sess, sender, receiver, RTP_NO_FLAGS);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(RTPTests_ip6, rtp_copy_ip6)
{
// Tests installing a hook to uvgRTP
std::cout << "Starting IPv6 RTP hook test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int flags = RCE_FRAGMENT_GENERIC;
if (sess)
{
sender = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_GENERIC, flags);
receiver = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_GENERIC, flags);
}
int test_packets = 10;
std::vector<size_t> sizes = { 1000, 2000 };
for (size_t& size : sizes)
{
int rtp_flags = RTP_COPY;
std::unique_ptr<uint8_t[]> test_frame = create_test_packet(RTP_FORMAT_GENERIC, 0, false, size, rtp_flags);
test_packet_size(std::move(test_frame), test_packets, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(RTPTests_ip6, rtp_holepuncher_ip6)
{
// Tests installing a hook to uvgRTP
std::cout << "Starting IPv6 RTP holepuncher test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int flags = RCE_FRAGMENT_GENERIC | RCE_HOLEPUNCH_KEEPALIVE;
if (sess)
{
sender = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_GENERIC, flags);
receiver = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_GENERIC, flags);
}
int test_packets = 10;
std::vector<size_t> sizes = { 1000, 2000 };
for (size_t& size : sizes)
{
std::unique_ptr<uint8_t[]> test_frame = create_test_packet(RTP_FORMAT_GENERIC, 0, false, size, RTP_NO_FLAGS);
test_packet_size(std::move(test_frame), test_packets, size, sess, sender, receiver, RTP_NO_FLAGS);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(RTPTests_ip6, rtp_configuration_ip6)
{
// Tests installing a hook to uvgRTP
std::cout << "Starting IPv6 RTP configuration test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int flags = RCE_FRAGMENT_GENERIC;
if (sess)
{
sender = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_GENERIC, flags);
receiver = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_GENERIC, flags);
}
// here we try to break uvgRTP by calling various configure values
if (sender)
{
sender->configure_ctx(RCC_UDP_SND_BUF_SIZE, 40 * 1000 * 1000);
sender->configure_ctx(RCC_UDP_SND_BUF_SIZE, 2 * 1000 * 1000);
sender->configure_ctx(RCC_DYN_PAYLOAD_TYPE, 8);
sender->configure_ctx(RCC_MTU_SIZE, 800);
sender->configure_ctx(RCC_FPS_NUMERATOR, 100);
sender->configure_ctx(RCC_FPS_DENOMINATOR, 1);
}
if (receiver)
{
receiver->configure_ctx(RCC_UDP_RCV_BUF_SIZE, 20 * 1000 * 1000);
receiver->configure_ctx(RCC_UDP_RCV_BUF_SIZE, 2 * 1000 * 1000);
receiver->configure_ctx(RCC_RING_BUFFER_SIZE, 20 * 1000 * 1000);
receiver->configure_ctx(RCC_RING_BUFFER_SIZE, 2 * 1000 * 1000);
receiver->configure_ctx(RCC_PKT_MAX_DELAY, 200);
receiver->configure_ctx(RCC_DYN_PAYLOAD_TYPE, 8);
}
int test_packets = 10;
std::vector<size_t> sizes = { 1000, 2000 };
for (size_t& size : sizes)
{
std::unique_ptr<uint8_t[]> test_frame = create_test_packet(RTP_FORMAT_GENERIC, 0, false, size, RTP_NO_FLAGS);
test_packet_size(std::move(test_frame), test_packets, size, sess, sender, receiver, RTP_NO_FLAGS);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(RTPTests_ip6, rtp_send_receive_only_flags_ip6)
{
// Tests installing a hook to uvgRTP
std::cout << "Starting IPv6 RTP send_receive_only test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* send_sess = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::session* receive_sess = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int send_flags = RCE_FRAGMENT_GENERIC | RCE_SEND_ONLY;
int receive_flags = RCE_FRAGMENT_GENERIC | RCE_RECEIVE_ONLY;
if (send_sess)
{
sender = send_sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_GENERIC, send_flags);
}
if (receive_sess)
{
receiver = receive_sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_GENERIC, receive_flags);
}
int test_packets = 10;
std::vector<size_t> sizes = { 1000, 2000 };
for (size_t& size : sizes)
{
std::unique_ptr<uint8_t[]> test_frame = create_test_packet(RTP_FORMAT_GENERIC, 0, false, size, RTP_NO_FLAGS);
test_packet_size(std::move(test_frame), test_packets, size, send_sess, sender, receiver, RTP_NO_FLAGS);
}
cleanup_ms(send_sess, sender);
cleanup_ms(receive_sess, receiver);
cleanup_sess(ctx, send_sess);
cleanup_sess(ctx, receive_sess);
}

153
test/test_8_rtcp_ipv6.cpp Normal file
View File

@ -0,0 +1,153 @@
#include "test_common.hh"
constexpr char LOCAL_INTERFACE[] = "::1";
constexpr uint16_t LOCAL_PORT = 9200;
constexpr char REMOTE_ADDRESS[] = "::1";
constexpr uint16_t REMOTE_PORT = 9202;
constexpr uint16_t PAYLOAD_LEN = 256;
constexpr uint16_t FRAME_RATE = 30;
constexpr uint32_t EXAMPLE_RUN_TIME_S = 14;
constexpr int SEND_TEST_PACKETS = FRAME_RATE * EXAMPLE_RUN_TIME_S;
constexpr int PACKET_INTERVAL_MS = 1000 / FRAME_RATE;
void receiver_hook(uvgrtp::frame::rtcp_receiver_report* frame);
void sender_hook(uvgrtp::frame::rtcp_sender_report* frame);
void sdes_hook(uvgrtp::frame::rtcp_sdes_packet* frame);
void app_hook(uvgrtp::frame::rtcp_app_packet* frame);
void cleanup(uvgrtp::context& ctx, uvgrtp::session* local_session, uvgrtp::session* remote_session,
uvgrtp::media_stream* send, uvgrtp::media_stream* receive);
TEST(RTCPTests_ip6, rtcp_ip6) {
std::cout << "Starting uvgRTP IPv6 RTCP tests" << std::endl;
// Creation of RTP stream. See sending example for more details
uvgrtp::context ctx;
uvgrtp::session* local_session = ctx.create_session(REMOTE_ADDRESS, LOCAL_INTERFACE);
uvgrtp::session* remote_session = ctx.create_session(LOCAL_INTERFACE, REMOTE_ADDRESS);
int flags = RCE_RTCP;
uvgrtp::media_stream* local_stream = nullptr;
if (local_session)
{
local_stream = local_session->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_GENERIC, flags);
}
uvgrtp::media_stream* remote_stream = nullptr;
if (remote_session)
{
remote_stream = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT, RTP_FORMAT_GENERIC, flags);
}
EXPECT_NE(nullptr, remote_stream);
if (local_stream)
{
EXPECT_EQ(RTP_OK, local_stream->get_rtcp()->install_receiver_hook(receiver_hook));
EXPECT_EQ(RTP_OK, local_stream->get_rtcp()->install_sdes_hook(sdes_hook));
}
if (remote_stream)
{
EXPECT_EQ(RTP_OK, remote_stream->get_rtcp()->install_sender_hook(sender_hook));
EXPECT_EQ(RTP_OK, remote_stream->get_rtcp()->install_sdes_hook(sdes_hook));
}
std::unique_ptr<uint8_t[]> test_frame = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_LEN]);
memset(test_frame.get(), 'b', PAYLOAD_LEN);
send_packets(std::move(test_frame), PAYLOAD_LEN, local_session, local_stream, SEND_TEST_PACKETS, PACKET_INTERVAL_MS, true, RTP_NO_FLAGS);
cleanup(ctx, local_session, remote_session, local_stream, remote_stream);
}
TEST(RTCP_reopen_receiver_ip6, rtcp_ip6) {
std::cout << "Starting uvgRTP IPv6 RTCP reopen receiver test" << std::endl;
// Creation of RTP stream. See sending example for more details
uvgrtp::context ctx;
uvgrtp::session* local_session = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::session* remote_session = ctx.create_session(LOCAL_INTERFACE);
int flags = RCE_RTCP;
uvgrtp::media_stream* local_stream = nullptr;
if (local_session)
{
local_stream = local_session->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_GENERIC, flags);
}
uvgrtp::media_stream* remote_stream = nullptr;
if (remote_session)
{
remote_stream = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT, RTP_FORMAT_GENERIC, flags);
}
EXPECT_NE(nullptr, remote_stream);
if (local_stream)
{
EXPECT_EQ(RTP_OK, local_stream->get_rtcp()->install_receiver_hook(receiver_hook));
EXPECT_EQ(RTP_OK, local_stream->get_rtcp()->install_sdes_hook(sdes_hook));
}
if (remote_stream)
{
EXPECT_EQ(RTP_OK, remote_stream->get_rtcp()->install_sender_hook(sender_hook));
EXPECT_EQ(RTP_OK, remote_stream->get_rtcp()->install_sdes_hook(sdes_hook));
}
if (local_stream)
{
std::unique_ptr<uint8_t[]> test_frame = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_LEN]);
memset(test_frame.get(), 'b', PAYLOAD_LEN);
send_packets(std::move(test_frame), PAYLOAD_LEN, local_session, local_stream, SEND_TEST_PACKETS / 2,
PACKET_INTERVAL_MS, true, RTP_NO_FLAGS);
if (remote_stream)
{
std::cout << "Closing and reopening receiver for testing purposes" << std::endl;
remote_session->destroy_stream(remote_stream);
remote_stream = remote_session->create_stream(REMOTE_PORT, LOCAL_PORT, RTP_FORMAT_GENERIC, flags);
EXPECT_NE(nullptr, remote_stream);
}
test_frame = std::unique_ptr<uint8_t[]>(new uint8_t[PAYLOAD_LEN]);
memset(test_frame.get(), 'b', PAYLOAD_LEN);
send_packets(std::move(test_frame), PAYLOAD_LEN, local_session, local_stream, SEND_TEST_PACKETS / 2,
PACKET_INTERVAL_MS, true, RTP_NO_FLAGS);
}
cleanup(ctx, local_session, remote_session, local_stream, remote_stream);
}
TEST(RTCP_double_bind_test_ip6, rtcp_ip6) {
// Here we test if there are errors when double binding RTCP into the same port
std::cout << "Starting uvgRTP IPv6 RTCP double bind tests" << std::endl;
// Creation of RTP stream. See sending example for more details
uvgrtp::context ctx;
uvgrtp::session* local_session = ctx.create_session(REMOTE_ADDRESS);
uvgrtp::session* remote_session = ctx.create_session(LOCAL_INTERFACE);
int flags = RCE_RTCP;
uvgrtp::media_stream* local_stream = nullptr;
if (local_session)
{
local_stream = local_session->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_GENERIC, flags);
}
uvgrtp::media_stream* remote_stream = nullptr;
if (remote_session)
{
// this is invalid since the ports are the same
remote_stream = remote_session->create_stream(LOCAL_PORT, REMOTE_PORT, RTP_FORMAT_GENERIC, flags);
}
EXPECT_EQ(nullptr, remote_stream);
cleanup(ctx, local_session, remote_session, local_stream, remote_stream);
}

View File

@ -0,0 +1,443 @@
#include "test_common.hh"
#include <numeric>
constexpr uint16_t SEND_PORT = 9100;
constexpr char LOCAL_ADDRESS[] = "::1";
constexpr uint16_t RECEIVE_PORT = 9102;
constexpr int AMOUNT_OF_TEST_PACKETS = 100;
constexpr size_t PAYLOAD_LEN = 100;
// TODO: Use real files
TEST(FormatTests_ip6, h26x_flags_ip6)
{
std::cout << "Starting IPv6 h26x flag test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int sender_rce_flags = RCE_NO_FLAGS;
int receiver_rce_flags = RCE_H26X_DO_NOT_PREPEND_SC;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, sender_rce_flags);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, receiver_rce_flags);
}
std::vector<size_t> test_sizes = { 1443, 1501 };
int rtp_flags = RTP_NO_FLAGS;
int nal_type = 5;
rtp_format_t format = RTP_FORMAT_H264;
int test_runs = 10;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
rtp_flags = RTP_NO_H26X_SCL;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h264_single_nal_unit_ip6)
{
std::cout << "Starting IPv6 h264 Single NAL unit test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H264, RCE_NO_FLAGS);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H264, RCE_NO_FLAGS);
}
int rtp_flags = RTP_NO_FLAGS;
rtp_format_t format = RTP_FORMAT_H264;
int test_runs = 5;
int size = 8;
std::cout << "Testing small NAL unit" << std::endl;
std::vector<size_t> test_sizes = std::vector<size_t>(16);
std::iota(test_sizes.begin(), test_sizes.end(), 4);
for (auto& size : test_sizes)
{
int nal_type = 8;
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
size = 35;
for (unsigned int nal_type = 1; nal_type <= 23; ++nal_type)
{
std::cout << "Testing H264 NAL type " << nal_type << std::endl;
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h264_fragmentation_ip6)
{
std::cout << "Starting IPv6 h264 fragmentation test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H264, RCE_NO_FLAGS);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H264, RCE_NO_FLAGS);
}
// the default packet limit for RTP is 1458 where 12 bytes are dedicated to RTP header
std::vector<size_t> test_sizes = std::vector<size_t>(13);
std::iota(test_sizes.begin(), test_sizes.end(), 1443);
test_sizes.insert(test_sizes.end(), { 1501,
1446 * 2 - 1,
1446 * 2,
1446 * 2 + 1,
5000, 7500, 10000, 25000, 50000 });
int rtp_flags = RTP_NO_FLAGS;
int nal_type = 5;
rtp_format_t format = RTP_FORMAT_H264;
int test_runs = 10;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h265_single_nal_unit_ip6)
{
std::cout << "Starting IPv6 H265 Single NAL unit test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
}
int rtp_flags = RTP_NO_FLAGS;
rtp_format_t format = RTP_FORMAT_H265;
int test_runs = 5;
int size = 8;
std::cout << "Testing small NAL unit" << std::endl;
std::vector<size_t> test_sizes = std::vector<size_t>(16);
std::iota(test_sizes.begin(), test_sizes.end(), 6);
for (auto& size : test_sizes)
{
int nal_type = 8;
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
size = 35;
for (unsigned int nal_type = 0; nal_type <= 47; ++nal_type)
{
std::cout << "Testing H264 NAL type " << nal_type << std::endl;
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h265_fragmentation_ip6)
{
std::cout << "Starting IPv6 h265 fragmentation test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
}
std::vector<size_t> test_sizes = std::vector<size_t>(13);
std::iota(test_sizes.begin(), test_sizes.end(), 1443);
test_sizes.insert(test_sizes.end(), { 1501,
1446 * 2 - 1,
1446 * 2,
1446 * 2 + 1,
5000, 7500, 10000, 25000, 50000 });
// the default packet limit for RTP is 1458 where 12 bytes are dedicated to RTP header
int rtp_flags = RTP_NO_FLAGS;
int nal_type = 5;
rtp_format_t format = RTP_FORMAT_H265;
int test_runs = 10;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h265_fps_ip6)
{
std::cout << "Starting IPv6 h265 test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int framerate = 10;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, RCE_FRAME_RATE);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
if (receiver)
{
sender->configure_ctx(RCC_FPS_NUMERATOR, framerate);
sender->configure_ctx(RCC_FPS_DENOMINATOR, 1);
}
}
std::vector<size_t> test_sizes = { 10000, 20000, 30000, 40000, 50000, 75000, 100000 };
// the default packet limit for RTP is 1458 where 12 bytes are dedicated to RTP header
int rtp_flags = RTP_NO_FLAGS;
int nal_type = 5;
rtp_format_t format = RTP_FORMAT_H265;
int test_runs = 10;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags, framerate);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h265_small_fragment_pacing_fps_ip6)
{
std::cout << "Starting IPv6 h265 test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int framerate = 10;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, RCE_FRAME_RATE | RCE_PACE_FRAGMENT_SENDING);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
if (receiver)
{
sender->configure_ctx(RCC_FPS_NUMERATOR, framerate);
sender->configure_ctx(RCC_FPS_DENOMINATOR, 1);
receiver->configure_ctx(RCC_UDP_RCV_BUF_SIZE, 40 * 1000 * 1000);
receiver->configure_ctx(RCC_RING_BUFFER_SIZE, 40 * 1000 * 1000);
}
}
std::vector<size_t> test_sizes = { 1000, 2000, 3000, 4000, 5000, 7500, 10000 };
// the default packet limit for RTP is 1458 where 12 bytes are dedicated to RTP header
int rtp_flags = RTP_NO_FLAGS;
int nal_type = 5;
rtp_format_t format = RTP_FORMAT_H265;
int test_runs = 10;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags, framerate);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h266_single_nal_unit_ip6)
{
std::cout << "Starting IPv6 H266 Single NAL unit test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H266, RCE_NO_FLAGS);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H266, RCE_NO_FLAGS);
}
int rtp_flags = RTP_NO_FLAGS;
rtp_format_t format = RTP_FORMAT_H266;
int test_runs = 5;
int size = 8;
std::cout << "Testing small NAL unit" << std::endl;
std::vector<size_t> test_sizes = std::vector<size_t>(16);
std::iota(test_sizes.begin(), test_sizes.end(), 6);
for (auto& size : test_sizes)
{
int nal_type = 8;
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
size = 35;
for (unsigned int nal_type = 0; nal_type <= 27; ++nal_type)
{
std::cout << "Testing H264 NAL type " << nal_type << std::endl;
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h265_large_fragment_pacing_ip6)
{
std::cout << "Starting IPv6 h265 test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
int framerate = 10;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H265, RCE_PACE_FRAGMENT_SENDING);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H265, RCE_NO_FLAGS);
if (receiver)
{
sender->configure_ctx(RCC_FPS_NUMERATOR, framerate);
sender->configure_ctx(RCC_FPS_DENOMINATOR, 1);
receiver->configure_ctx(RCC_UDP_RCV_BUF_SIZE, 40 * 1000 * 1000);
receiver->configure_ctx(RCC_RING_BUFFER_SIZE, 40 * 1000 * 1000);
}
}
std::vector<size_t> test_sizes = { 100000, 200000, 300000, 400000, 500000, 750000, 1000000 };
// the default packet limit for RTP is 1458 where 12 bytes are dedicated to RTP header
int rtp_flags = RTP_NO_FLAGS;
int nal_type = 5;
rtp_format_t format = RTP_FORMAT_H265;
int test_runs = 10;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags, framerate);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}
TEST(FormatTests_ip6, h266_fragmentation_ip6)
{
std::cout << "Starting IPv6 h266 fragmentation test" << std::endl;
uvgrtp::context ctx;
uvgrtp::session* sess = ctx.create_session(LOCAL_ADDRESS);
uvgrtp::media_stream* sender = nullptr;
uvgrtp::media_stream* receiver = nullptr;
if (sess)
{
sender = sess->create_stream(SEND_PORT, RECEIVE_PORT, RTP_FORMAT_H266, RCE_NO_FLAGS);
receiver = sess->create_stream(RECEIVE_PORT, SEND_PORT, RTP_FORMAT_H266, RCE_NO_FLAGS);
}
std::vector<size_t> test_sizes = std::vector<size_t>(13);
std::iota(test_sizes.begin(), test_sizes.end(), 1443);
test_sizes.insert(test_sizes.end(), { 1501,
1446 * 2 - 1,
1446 * 2,
1446 * 2 + 1,
5000, 7500, 10000, 25000, 50000 });
// the default packet limit for RTP is 1458 where 12 bytes are dedicated to RTP header
int rtp_flags = RTP_NO_FLAGS;
int nal_type = 5;
rtp_format_t format = RTP_FORMAT_H266;
int test_runs = 10;
for (auto& size : test_sizes)
{
std::unique_ptr<uint8_t[]> intra_frame = create_test_packet(format, nal_type, true, size, rtp_flags);
test_packet_size(std::move(intra_frame), test_runs, size, sess, sender, receiver, rtp_flags);
}
cleanup_ms(sess, sender);
cleanup_ms(sess, receiver);
cleanup_sess(ctx, sess);
}