From 84bf8c9e4ca12fbb6742395900479395c145d3d7 Mon Sep 17 00:00:00 2001 From: Heikki Tampio Date: Mon, 6 Mar 2023 10:21:56 +0200 Subject: [PATCH 1/4] ipv6: add ipv6 support ipv6 support for rtp, rtcp, srtp+zrtp, no context flags needed # Conflicts: # src/media_stream.cc # src/rtcp.cc # src/socket.cc --- include/uvgrtp/media_stream.hh | 5 + include/uvgrtp/rtcp.hh | 13 +- src/media_stream.cc | 95 ++++++++-- src/rtcp.cc | 71 +++++-- src/session.cc | 2 +- src/socket.cc | 337 +++++++++++++++++++++++++++------ src/socket.hh | 46 ++++- src/zrtp.cc | 44 +++-- src/zrtp.hh | 11 +- src/zrtp/zrtp_message.cc | 11 +- src/zrtp/zrtp_message.hh | 8 +- 11 files changed, 521 insertions(+), 122 deletions(-) diff --git a/include/uvgrtp/media_stream.hh b/include/uvgrtp/media_stream.hh index 4e62d40..97187e8 100644 --- a/include/uvgrtp/media_stream.hh +++ b/include/uvgrtp/media_stream.hh @@ -11,6 +11,7 @@ #include #include #endif +#include namespace uvgrtp { @@ -348,6 +349,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 @@ -381,10 +384,12 @@ namespace uvgrtp { std::shared_ptr 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 */ diff --git a/include/uvgrtp/rtcp.hh b/include/uvgrtp/rtcp.hh index 3eeb7ac..6776186 100644 --- a/include/uvgrtp/rtcp.hh +++ b/include/uvgrtp/rtcp.hh @@ -4,6 +4,13 @@ #include "util.hh" #include "frame.hh" +#ifdef _WIN32 +#include +#else +#include +#include +#endif + #include #include #include @@ -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> 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 diff --git a/src/media_stream.cc b/src/media_stream.cc index 148677a..76e50cd 100644 --- a/src/media_stream.cc +++ b/src/media_stream.cc @@ -17,13 +17,21 @@ #include "srtp/srtp.hh" #include "formats/media.hh" #include "global.hh" +#ifdef _WIN32 +#include +#else +#include +#include +#include +#include +#endif #include #include -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,34 @@ 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 + int ret1; + struct addrinfo hint; + struct addrinfo* res = NULL; + memset(&hint, '\0', sizeof(hint)); + hint.ai_family = PF_UNSPEC; + hint.ai_flags = AI_NUMERICHOST; + + if ((ret1 = getaddrinfo(local_address_.c_str(), NULL, &hint, &res)) != 0) { + if ((ret1 = 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_INFO("Using an IPv6 address"); + } + else { + UVG_LOG_INFO("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 */ @@ -81,14 +116,19 @@ rtp_error_t uvgrtp::media_stream::init_connection() if (::ioctlsocket(socket_->get_raw_socket(), FIONBIO, (u_long *)&enabled) < 0) UVG_LOG_ERROR("Failed to make the socket non-blocking!"); #endif - - short int family = AF_INET; + //TODO FIX THIS 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 +138,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 +155,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 +304,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 (new uvgrtp::reception_flow()); rtp_ = std::shared_ptr (new uvgrtp::rtp(fmt_, ssrc_)); rtcp_ = std::shared_ptr (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 +351,7 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr 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 +367,9 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr 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 (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 +762,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 +807,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 srtp, std::shared_ptr zrtp) { diff --git a/src/rtcp.cc b/src/rtcp.cc index 295ebd0..f128c76 100644 --- a/src/rtcp.cc +++ b/src/rtcp.cc @@ -16,6 +16,10 @@ #ifndef _WIN32 #include +#include +#include +#else +#include #endif #include @@ -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 rtp, std::shared_ptr 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), + rtcp_pkt_sent_count_(0), initial_(true), ssrc_(rtp->get_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(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)); @@ -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!"); } @@ -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) { diff --git a/src/session.cc b/src/session.cc index b458e35..ef57e23 100644 --- a/src/session.cc +++ b/src/session.cc @@ -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); diff --git a/src/socket.cc b/src/socket.cc index 5d5556e..8561cf2 100644 --- a/src/socket.cc +++ b/src/socket.cc @@ -8,13 +8,17 @@ #include #ifdef _WIN32 +#include #include #include #include +#include #else #include #include #include +#include +#include #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) { @@ -100,7 +112,12 @@ rtp_error_t uvgrtp::socket::bind(sockaddr_in& local_address) { local_address_ = local_address; - UVG_LOG_DEBUG("Binding to address %s", sockaddr_to_string(local_address_).c_str()); + if (ipv6_) { + UVG_LOG_DEBUG("Binding to address %s", sockaddr_ip6_to_string(local_ip6_address_).c_str()); + } + else { + UVG_LOG_DEBUG("Binding to address %s", sockaddr_to_string(local_address_).c_str()); + } if (::bind(socket_, (struct sockaddr*)&local_address_, sizeof(local_address_)) < 0) { #ifdef _WIN32 @@ -115,6 +132,25 @@ 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_to_string(local_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,14 +181,71 @@ sockaddr_in uvgrtp::socket::create_sockaddr(short family, std::string host, shor return addr; } +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 +{ + + /* + struct addrinfo hints = { 0 }, *addr_i; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + std::string port_str = std::to_string(port); + + int status = getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addr_i); + + // exit?? + if (status != 0) { + UVG_LOG_ERROR("Invalid address"); + }*/ + + 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; + // tyhjennä turhat "ipv6 supportit" pois + char* c_string = new char[INET_ADDRSTRLEN]; + memset(c_string, 0, INET_ADDRSTRLEN); if (addr.sin_family == AF_INET6) { @@ -176,11 +269,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, INET_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,12 +310,18 @@ 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) @@ -219,11 +334,17 @@ 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()); + // FIX THIS + UVG_LOG_ERROR("Failed to send to %s", 1 /*sockaddr_to_string(addr).c_str()*/); if (bytes_sent) *bytes_sent = -1; @@ -244,26 +365,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,14 +400,21 @@ 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 { + // mikä tämä void* on?? + 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; header_.msg_hdr.msg_controllen = 0; + // MIKÄ TÄMÄ SENDMMSG ON??? if (sendmmsg(socket_, &header_, 1, send_flags) < 0) { UVG_LOG_ERROR("Failed to send RTP frame: %s!", strerror(errno)); set_bytes(bytes_sent, -1); @@ -305,12 +435,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 +479,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 +493,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 +506,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 +525,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 +548,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; @@ -420,6 +570,7 @@ rtp_error_t uvgrtp::socket::__sendtov( ssize_t bptr = buffers.size(); while (bptr > npkts) { + // MIKÄ SENDMMSG if (sendmmsg(socket_, hptr, npkts, send_flags) < 0) { log_platform_error("sendmmsg(2) failed"); return_value = RTP_SEND_ERROR; @@ -466,18 +617,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 +657,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 +692,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 +707,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 +722,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 +737,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 +859,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 +921,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); } diff --git a/src/socket.hh b/src/socket.hh index 01452c6..6460725 100644 --- a/src/socket.hh +++ b/src/socket.hh @@ -3,13 +3,18 @@ #include "uvgrtp/util.hh" #ifdef _WIN32 +#include #include #include #include +#include +#include #else #include #include #include +#include +#include #endif #include @@ -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,15 @@ 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); + // mitäs näille tehdään??? + // rtcp käyttää tätä, ei korjattu + rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, uint8_t *buf, size_t buf_len, int send_flags); + // zrtp käyttää tätä, ei korjattu + 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) * @@ -123,6 +133,7 @@ namespace uvgrtp { * Return RTP_INTERRUPTED if the call was interrupted due to timeout and set "bytes_sent" to 0 * Return RTP_GENERIC_ERROR on error and set "bytes_sent" to -1 */ rtp_error_t recv(uint8_t *buf, size_t buf_len, int recv_flags); + // used in poll rtp_error_t recv(uint8_t *buf, size_t buf_len, int recv_flags, int *bytes_read); /* Same as recvfrom(2), receives a message from remote @@ -135,6 +146,7 @@ namespace uvgrtp { * Return RTP_GENERIC_ERROR on error and set "bytes_sent" to -1 */ rtp_error_t recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, sockaddr_in *sender, int *bytes_read); rtp_error_t recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, sockaddr_in *sender); + // used in rec flow 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); @@ -146,9 +158,15 @@ namespace uvgrtp { * NOTE: "family" must be AF_INET */ sockaddr_in create_sockaddr(short family, std::string host, short port) const; + 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 +175,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 +191,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_; + SOCKET 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 */ diff --git a/src/zrtp.cc b/src/zrtp.cc index f6f12f3..05af12c 100644 --- a/src/zrtp.cc +++ b/src/zrtp.cc @@ -11,7 +11,12 @@ #include "crypto.hh" #include "random.hh" #include "debug.hh" - +#ifdef _WIN32 +#include +#else +#include +#include +#endif #include #include @@ -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 socket, sockaddr_in& addr, bool perform_dh) +rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr 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 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 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 socket, sockaddr_in& addr) +rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr 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 socket, sockaddr_in& addr) +rtp_error_t uvgrtp::zrtp::init_msm(uint32_t ssrc, std::shared_ptr 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; diff --git a/src/zrtp.hh b/src/zrtp.hh index 804e29c..5775f40 100644 --- a/src/zrtp.hh +++ b/src/zrtp.hh @@ -8,9 +8,13 @@ #include #include #include +#include + #else #include #include +#include +#include #endif #include @@ -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 socket, sockaddr_in& addr, bool perform_dh); + rtp_error_t init(uint32_t ssrc, std::shared_ptr 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 socket, sockaddr_in& addr); + rtp_error_t init_dhm(uint32_t ssrc, std::shared_ptr 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 socket, sockaddr_in& addr); + rtp_error_t init_msm(uint32_t ssrc, std::shared_ptr 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 local_socket_; sockaddr_in remote_addr_; + sockaddr_in6 remote_ip6_addr_; /* Has the ZRTP connection been initialized using DH */ bool initialized_; diff --git a/src/zrtp/zrtp_message.cc b/src/zrtp/zrtp_message.cc index 4954cee..71f6a64 100644 --- a/src/zrtp/zrtp_message.cc +++ b/src/zrtp/zrtp_message.cc @@ -6,6 +6,12 @@ #include "debug.hh" #include +#ifdef _WIN32 +#include +#else +#include +#include +#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 socket, sockaddr_in& addr) +rtp_error_t uvgrtp::zrtp_msg::zrtp_message::send_msg(std::shared_ptr 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; diff --git a/src/zrtp/zrtp_message.hh b/src/zrtp/zrtp_message.hh index 7baf9fd..78ee7ca 100644 --- a/src/zrtp/zrtp_message.hh +++ b/src/zrtp/zrtp_message.hh @@ -7,6 +7,12 @@ #include "uvgrtp/util.hh" #include +#ifdef _WIN32 +#include +#else +#include +#include +#endif namespace uvgrtp { @@ -19,7 +25,7 @@ namespace uvgrtp { zrtp_message(); ~zrtp_message(); - rtp_error_t send_msg(std::shared_ptr socket, sockaddr_in& addr); + rtp_error_t send_msg(std::shared_ptr socket, sockaddr_in& addr, sockaddr_in6& addr6); virtual rtp_error_t parse_msg(uvgrtp::zrtp_msg::receiver& receiver, zrtp_session_t& session) = 0; From 5c9c5562e25c87cfb8c82afb8c91dbbd4a3456ab Mon Sep 17 00:00:00 2001 From: Heikki Tampio Date: Mon, 13 Mar 2023 10:39:25 +0200 Subject: [PATCH 2/4] ipv6: fix compiler error --- include/uvgrtp/media_stream.hh | 4 ++-- src/rtcp.cc | 2 +- src/socket.cc | 18 ++++++++---------- src/socket.hh | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/include/uvgrtp/media_stream.hh b/include/uvgrtp/media_stream.hh index 97187e8..69f998a 100644 --- a/include/uvgrtp/media_stream.hh +++ b/include/uvgrtp/media_stream.hh @@ -10,9 +10,9 @@ #ifndef _WIN32 #include #include -#endif +#else #include - +#endif namespace uvgrtp { // forward declarations diff --git a/src/rtcp.cc b/src/rtcp.cc index f128c76..fb96196 100644 --- a/src/rtcp.cc +++ b/src/rtcp.cc @@ -49,7 +49,7 @@ uvgrtp::rtcp::rtcp(std::shared_ptr rtp, std::shared_ptrget_ssrc()), + rtcp_pkt_sent_count_(0), initial_(true), ssrc_(ssrc), num_receivers_(0), ipv6_(false), socket_address_({}), diff --git a/src/socket.cc b/src/socket.cc index 8561cf2..472bf64 100644 --- a/src/socket.cc +++ b/src/socket.cc @@ -244,14 +244,10 @@ std::string uvgrtp::socket::get_socket_path_string() const std::string uvgrtp::socket::sockaddr_to_string(const sockaddr_in& addr) const { // tyhjennä turhat "ipv6 supportit" pois + int addr_len = INET6_ADDRSTRLEN; char* c_string = new char[INET_ADDRSTRLEN]; memset(c_string, 0, INET_ADDRSTRLEN); - if (addr.sin_family == AF_INET6) - { - addr_len = INET6_ADDRSTRLEN; - } - char* addr_string = new char[addr_len]; memset(addr_string, 0, addr_len); @@ -316,16 +312,17 @@ rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, sockaddr_in6& addr6, boo #ifndef _WIN32 if (ipv6) { - nsend = ::sendto(socket_, buf, buf_len, send_flags, (const struct sockaddr*)&addr6, sizeof(addr6))); + 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))); + nsend = ::sendto(socket_, buf, buf_len, send_flags, (const struct sockaddr*)&addr, sizeof(addr)); } - if ((nsend == -1) { + 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 @@ -353,8 +350,9 @@ rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, sockaddr_in6& addr6, boo nsend = sent_bytes; #endif - if (bytes_sent) + if (bytes_sent) { *bytes_sent = nsend; + } #ifndef NDEBUG ++sent_packets_; diff --git a/src/socket.hh b/src/socket.hh index 6460725..ef02d27 100644 --- a/src/socket.hh +++ b/src/socket.hh @@ -202,7 +202,7 @@ namespace uvgrtp { 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 socket_; + socket_t socket_; sockaddr_in remote_address_; sockaddr_in local_address_; sockaddr_in6 remote_ip6_address_; From 600aa908a5df805ba0fae146df1f9852bbe17236 Mon Sep 17 00:00:00 2001 From: Heikki Tampio Date: Wed, 15 Mar 2023 12:23:06 +0200 Subject: [PATCH 3/4] ipv6: add automatic tests for ipv6 support --- src/media_stream.cc | 4 +- src/socket.cc | 18 -- test/CMakeLists.txt | 4 + test/test_10_srtp_zrtp_ipv6.cpp | 361 ++++++++++++++++++++++++++ test/test_7_rtp_ipv6.cpp | 201 +++++++++++++++ test/test_8_rtcp_ipv6.cpp | 153 +++++++++++ test/test_9_formats_ipv6.cpp | 443 ++++++++++++++++++++++++++++++++ 7 files changed, 1164 insertions(+), 20 deletions(-) create mode 100644 test/test_10_srtp_zrtp_ipv6.cpp create mode 100644 test/test_7_rtp_ipv6.cpp create mode 100644 test/test_8_rtcp_ipv6.cpp create mode 100644 test/test_9_formats_ipv6.cpp diff --git a/src/media_stream.cc b/src/media_stream.cc index 76e50cd..4860cfd 100644 --- a/src/media_stream.cc +++ b/src/media_stream.cc @@ -98,10 +98,10 @@ rtp_error_t uvgrtp::media_stream::init_connection() } if (res->ai_family == AF_INET6) { ipv6_ = true; - UVG_LOG_INFO("Using an IPv6 address"); + UVG_LOG_DEBUG("Using an IPv6 address"); } else { - UVG_LOG_INFO("Using an IPv4 address"); + UVG_LOG_DEBUG("Using an IPv4 address"); } // Initialize socket diff --git a/src/socket.cc b/src/socket.cc index 472bf64..3ced354 100644 --- a/src/socket.cc +++ b/src/socket.cc @@ -197,21 +197,6 @@ sockaddr_in6 uvgrtp::socket::create_ip6_sockaddr(unsigned host, short port) cons sockaddr_in6 uvgrtp::socket::create_ip6_sockaddr(std::string host, short port) const { - - /* - struct addrinfo hints = { 0 }, *addr_i; - hints.ai_family = AF_INET6; - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = IPPROTO_UDP; - std::string port_str = std::to_string(port); - - int status = getaddrinfo(host.c_str(), port_str.c_str(), &hints, &addr_i); - - // exit?? - if (status != 0) { - UVG_LOG_ERROR("Invalid address"); - }*/ - sockaddr_in6 addr; memset(&addr, 0, sizeof(addr)); @@ -403,7 +388,6 @@ rtp_error_t uvgrtp::socket::__sendtov( header_.msg_hdr.msg_namelen = sizeof(addr6); } else { - // mikä tämä void* on?? header_.msg_hdr.msg_name = (void *)&addr; header_.msg_hdr.msg_namelen = sizeof(addr); } @@ -412,7 +396,6 @@ rtp_error_t uvgrtp::socket::__sendtov( header_.msg_hdr.msg_control = 0; header_.msg_hdr.msg_controllen = 0; - // MIKÄ TÄMÄ SENDMMSG ON??? if (sendmmsg(socket_, &header_, 1, send_flags) < 0) { UVG_LOG_ERROR("Failed to send RTP frame: %s!", strerror(errno)); set_bytes(bytes_sent, -1); @@ -568,7 +551,6 @@ rtp_error_t uvgrtp::socket::__sendtov( ssize_t bptr = buffers.size(); while (bptr > npkts) { - // MIKÄ SENDMMSG if (sendmmsg(socket_, hptr, npkts, send_flags) < 0) { log_platform_error("sendmmsg(2) failed"); return_value = RTP_SEND_ERROR; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index afad76e..11f4fb5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -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 ) diff --git a/test/test_10_srtp_zrtp_ipv6.cpp b/test/test_10_srtp_zrtp_ipv6.cpp new file mode 100644 index 0000000..06071a1 --- /dev/null +++ b/test/test_10_srtp_zrtp_ipv6.cpp @@ -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 sender_thread = std::unique_ptr(new std::thread(user_send_func6, key, salt, len)); + std::unique_ptr receiver_thread = std::unique_ptr(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 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 sender_thread = + std::unique_ptr(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT, RECEIVER_PORT, zrtp_flags)); + + std::unique_ptr receiver_thread = + std::unique_ptr(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 sender_thread = + std::unique_ptr(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT, RECEIVER_PORT, zrtp_flags)); + + std::unique_ptr receiver_thread = + std::unique_ptr(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 sender_thread1 = + std::unique_ptr(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT + 2, RECEIVER_PORT + 2, zrtp_dh_flags)); + + std::unique_ptr receiver_thread1 = + std::unique_ptr(new std::thread(zrtp_receive_func6, receiver_session, SENDER_PORT + 2, RECEIVER_PORT + 2, zrtp_dh_flags)); + + std::unique_ptr sender_thread2 = + std::unique_ptr(new std::thread(zrtp_sender_func6, sender_session, SENDER_PORT + 4, RECEIVER_PORT + 4, zrtp_multistream_flags)); + + std::unique_ptr receiver_thread2 = + std::unique_ptr(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 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); +} \ No newline at end of file diff --git a/test/test_7_rtp_ipv6.cpp b/test/test_7_rtp_ipv6.cpp new file mode 100644 index 0000000..3cc2777 --- /dev/null +++ b/test/test_7_rtp_ipv6.cpp @@ -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 sizes = { 1000, 2000 }; + for (size_t& size : sizes) + { + std::unique_ptr 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 sizes = { 1000, 2000 }; + for (size_t& size : sizes) + { + int rtp_flags = RTP_COPY; + std::unique_ptr 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 sizes = { 1000, 2000 }; + for (size_t& size : sizes) + { + std::unique_ptr 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 sizes = { 1000, 2000 }; + for (size_t& size : sizes) + { + std::unique_ptr 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 sizes = { 1000, 2000 }; + for (size_t& size : sizes) + { + std::unique_ptr 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); +} diff --git a/test/test_8_rtcp_ipv6.cpp b/test/test_8_rtcp_ipv6.cpp new file mode 100644 index 0000000..112ca82 --- /dev/null +++ b/test/test_8_rtcp_ipv6.cpp @@ -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 test_frame = std::unique_ptr(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 test_frame = std::unique_ptr(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(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); +} \ No newline at end of file diff --git a/test/test_9_formats_ipv6.cpp b/test/test_9_formats_ipv6.cpp new file mode 100644 index 0000000..35d5aa3 --- /dev/null +++ b/test/test_9_formats_ipv6.cpp @@ -0,0 +1,443 @@ +#include "test_common.hh" + +#include + +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 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 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 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 test_sizes = std::vector(16); + std::iota(test_sizes.begin(), test_sizes.end(), 4); + + for (auto& size : test_sizes) + { + int nal_type = 8; + std::unique_ptr 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 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 test_sizes = std::vector(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 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 test_sizes = std::vector(16); + std::iota(test_sizes.begin(), test_sizes.end(), 6); + + for (auto& size : test_sizes) + { + int nal_type = 8; + std::unique_ptr 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 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 test_sizes = std::vector(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 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 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 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 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 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 test_sizes = std::vector(16); + std::iota(test_sizes.begin(), test_sizes.end(), 6); + + for (auto& size : test_sizes) + { + int nal_type = 8; + std::unique_ptr 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 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 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 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 test_sizes = std::vector(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 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); +} \ No newline at end of file From 68a5cc920b8b2595a69a443f02d981d940bb7a23 Mon Sep 17 00:00:00 2001 From: Heikki Tampio Date: Wed, 15 Mar 2023 15:05:40 +0200 Subject: [PATCH 4/4] ipv6: clean up some code --- src/media_stream.cc | 9 +++------ src/rtcp.cc | 6 +++--- src/socket.cc | 24 +++++++++++------------- src/socket.hh | 8 ++------ 4 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/media_stream.cc b/src/media_stream.cc index 4860cfd..7988357 100644 --- a/src/media_stream.cc +++ b/src/media_stream.cc @@ -83,15 +83,13 @@ rtp_error_t uvgrtp::media_stream::init_connection() rtp_error_t ret = RTP_GENERIC_ERROR; // Use getaddrinfo() to determine whether we are using ipv4 or ipv6 addresses - int ret1; - struct addrinfo hint; - struct addrinfo* res = NULL; + struct addrinfo hint, *res = NULL; memset(&hint, '\0', sizeof(hint)); hint.ai_family = PF_UNSPEC; hint.ai_flags = AI_NUMERICHOST; - if ((ret1 = getaddrinfo(local_address_.c_str(), NULL, &hint, &res)) != 0) { - if ((ret1 = getaddrinfo(remote_address_.c_str(), NULL, &hint, &res)) != 0) { + 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; } @@ -116,7 +114,6 @@ rtp_error_t uvgrtp::media_stream::init_connection() if (::ioctlsocket(socket_->get_raw_socket(), FIONBIO, (u_long *)&enabled) < 0) UVG_LOG_ERROR("Failed to make the socket non-blocking!"); #endif - //TODO FIX THIS if (!(rce_flags_ & RCE_RECEIVE_ONLY) && remote_address_ != "" && dst_port_ != 0) { diff --git a/src/rtcp.cc b/src/rtcp.cc index fb96196..479cad1 100644 --- a/src/rtcp.cc +++ b/src/rtcp.cc @@ -304,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_) @@ -352,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 @@ -1750,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; } diff --git a/src/socket.cc b/src/socket.cc index 3ced354..5ed4261 100644 --- a/src/socket.cc +++ b/src/socket.cc @@ -112,12 +112,7 @@ rtp_error_t uvgrtp::socket::bind(sockaddr_in& local_address) { local_address_ = local_address; - if (ipv6_) { - UVG_LOG_DEBUG("Binding to address %s", sockaddr_ip6_to_string(local_ip6_address_).c_str()); - } - else { - UVG_LOG_DEBUG("Binding to address %s", sockaddr_to_string(local_address_).c_str()); - } + UVG_LOG_DEBUG("Binding to address %s", sockaddr_to_string(local_address_).c_str()); if (::bind(socket_, (struct sockaddr*)&local_address_, sizeof(local_address_)) < 0) { #ifdef _WIN32 @@ -135,8 +130,7 @@ rtp_error_t uvgrtp::socket::bind(sockaddr_in& local_address) rtp_error_t uvgrtp::socket::bind_ip6(sockaddr_in6& local_address) { local_ip6_address_ = local_address; - - //UVG_LOG_DEBUG("Binding to address %s", sockaddr_to_string(local_address_).c_str()); + 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 @@ -181,6 +175,7 @@ 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 { @@ -228,8 +223,7 @@ std::string uvgrtp::socket::get_socket_path_string() const std::string uvgrtp::socket::sockaddr_to_string(const sockaddr_in& addr) const { - // tyhjennä turhat "ipv6 supportit" pois - int addr_len = INET6_ADDRSTRLEN; + int addr_len = INET_ADDRSTRLEN; char* c_string = new char[INET_ADDRSTRLEN]; memset(c_string, 0, INET_ADDRSTRLEN); @@ -254,7 +248,7 @@ std::string uvgrtp::socket::sockaddr_ip6_to_string(const sockaddr_in6& addr6) co { char* c_string = new char[INET6_ADDRSTRLEN]; memset(c_string, 0, INET6_ADDRSTRLEN); - inet_ntop(AF_INET6, &addr6.sin6_addr, c_string, INET_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; @@ -325,8 +319,12 @@ rtp_error_t uvgrtp::socket::__sendto(sockaddr_in& addr, sockaddr_in6& addr6, boo } if (result == -1) { win_get_last_error(); - // FIX THIS - UVG_LOG_ERROR("Failed to send to %s", 1 /*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; diff --git a/src/socket.hh b/src/socket.hh index ef02d27..61dfaf0 100644 --- a/src/socket.hh +++ b/src/socket.hh @@ -115,10 +115,7 @@ 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 */ - // mitäs näille tehdään??? - // rtcp käyttää tätä, ei korjattu rtp_error_t sendto(sockaddr_in& addr, sockaddr_in6& addr6, uint8_t *buf, size_t buf_len, int send_flags); - // zrtp käyttää tätä, ei korjattu 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); @@ -133,7 +130,6 @@ namespace uvgrtp { * Return RTP_INTERRUPTED if the call was interrupted due to timeout and set "bytes_sent" to 0 * Return RTP_GENERIC_ERROR on error and set "bytes_sent" to -1 */ rtp_error_t recv(uint8_t *buf, size_t buf_len, int recv_flags); - // used in poll rtp_error_t recv(uint8_t *buf, size_t buf_len, int recv_flags, int *bytes_read); /* Same as recvfrom(2), receives a message from remote @@ -146,11 +142,10 @@ namespace uvgrtp { * Return RTP_GENERIC_ERROR on error and set "bytes_sent" to -1 */ rtp_error_t recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, sockaddr_in *sender, int *bytes_read); rtp_error_t recvfrom(uint8_t *buf, size_t buf_len, int recv_flags, sockaddr_in *sender); - // used in rec flow 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; @@ -158,6 +153,7 @@ 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);