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
This commit is contained in:
parent
e6c759f514
commit
84bf8c9e4c
|
@ -11,6 +11,7 @@
|
|||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <ws2ipdef.h>
|
||||
|
||||
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<uvgrtp::rtcp> rtcp_;
|
||||
|
||||
sockaddr_in remote_sockaddr_;
|
||||
sockaddr_in6 remote_sockaddr_ip6_;
|
||||
std::string remote_address_;
|
||||
std::string local_address_;
|
||||
uint16_t src_port_;
|
||||
uint16_t dst_port_;
|
||||
bool ipv6_;
|
||||
rtp_format_t fmt_;
|
||||
|
||||
/* Media context config */
|
||||
|
|
|
@ -4,6 +4,13 @@
|
|||
#include "util.hh"
|
||||
#include "frame.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ws2ipdef.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <bitset>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
|
@ -223,6 +230,8 @@ namespace uvgrtp {
|
|||
/* Getter for interval_ms_, which is calculated by set_session_bandwidth */
|
||||
uint32_t get_rtcp_interval_ms() const;
|
||||
|
||||
void set_ipv6(bool set);
|
||||
|
||||
/* Set RTCP packet transmission interval in milliseconds
|
||||
*
|
||||
* Return RTP_OK if interval was set successfully
|
||||
|
@ -597,9 +606,11 @@ namespace uvgrtp {
|
|||
|
||||
std::map<uint32_t, std::unique_ptr<rtcp_participant>> participants_;
|
||||
uint8_t num_receivers_; // maximum is 32 at the moment (5 bits)
|
||||
bool ipv6_;
|
||||
|
||||
/* Address of the socket that we are sending data to */
|
||||
sockaddr_in socket_address_ = {};
|
||||
sockaddr_in socket_address_;
|
||||
sockaddr_in6 socket_address_ipv6_;
|
||||
|
||||
|
||||
/* Map for keeping track of sources for timeouts
|
||||
|
|
|
@ -17,13 +17,21 @@
|
|||
#include "srtp/srtp.hh"
|
||||
#include "formats/media.hh"
|
||||
#include "global.hh"
|
||||
#ifdef _WIN32
|
||||
#include <Ws2tcpip.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <cstring>
|
||||
#include <errno.h>
|
||||
|
||||
uvgrtp::media_stream::media_stream(std::string cname, std::string remote_addr,
|
||||
std::string local_addr, uint16_t src_port, uint16_t dst_port, rtp_format_t fmt,
|
||||
int rce_flags):
|
||||
uvgrtp::media_stream::media_stream(std::string cname, std::string remote_addr,
|
||||
std::string local_addr, uint16_t src_port, uint16_t dst_port, rtp_format_t fmt,
|
||||
int rce_flags) :
|
||||
key_(uvgrtp::random::generate_32()),
|
||||
srtp_(nullptr),
|
||||
srtcp_(nullptr),
|
||||
|
@ -31,10 +39,12 @@ uvgrtp::media_stream::media_stream(std::string cname, std::string remote_addr,
|
|||
rtp_(nullptr),
|
||||
rtcp_(nullptr),
|
||||
remote_sockaddr_(),
|
||||
remote_sockaddr_ip6_(),
|
||||
remote_address_(remote_addr),
|
||||
local_address_(local_addr),
|
||||
src_port_(src_port),
|
||||
dst_port_(dst_port),
|
||||
ipv6_(false),
|
||||
fmt_(fmt),
|
||||
rce_flags_(rce_flags),
|
||||
initialized_(false),
|
||||
|
@ -70,9 +80,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<uvgrtp::reception_flow> (new uvgrtp::reception_flow());
|
||||
|
||||
rtp_ = std::shared_ptr<uvgrtp::rtp> (new uvgrtp::rtp(fmt_, ssrc_));
|
||||
rtcp_ = std::shared_ptr<uvgrtp::rtcp> (new uvgrtp::rtcp(rtp_, ssrc_, cname_, rce_flags_));
|
||||
if (ipv6_) {
|
||||
rtcp_->set_ipv6(true);
|
||||
}
|
||||
|
||||
socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec);
|
||||
|
||||
|
@ -294,7 +351,7 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr<uvgrtp::zrtp> zrtp)
|
|||
}
|
||||
|
||||
rtp_error_t ret = RTP_OK;
|
||||
if ((ret = zrtp->init(rtp_->get_ssrc(), socket_, remote_sockaddr_, perform_dh)) != RTP_OK) {
|
||||
if ((ret = zrtp->init(rtp_->get_ssrc(), socket_, remote_sockaddr_, remote_sockaddr_ip6_, perform_dh, ipv6_)) != RTP_OK) {
|
||||
UVG_LOG_WARN("Failed to initialize ZRTP for media stream!");
|
||||
return free_resources(ret);
|
||||
}
|
||||
|
@ -310,7 +367,9 @@ rtp_error_t uvgrtp::media_stream::init(std::shared_ptr<uvgrtp::zrtp> zrtp)
|
|||
zrtp->dh_has_finished(); // only after the DH stream has gotten its keys, do we let non-DH stream perform ZRTP
|
||||
|
||||
rtcp_ = std::shared_ptr<uvgrtp::rtcp> (new uvgrtp::rtcp(rtp_, ssrc_, cname_, srtcp_, rce_flags_));
|
||||
|
||||
if (ipv6_) {
|
||||
rtcp_->set_ipv6(true);
|
||||
}
|
||||
socket_->install_handler(rtcp_.get(), rtcp_->send_packet_handler_vec);
|
||||
socket_->install_handler(srtp_.get(), srtp_->send_packet_handler);
|
||||
|
||||
|
@ -703,7 +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<uvgrtp::base_srtp> srtp,
|
||||
std::shared_ptr<uvgrtp::zrtp> zrtp)
|
||||
{
|
||||
|
|
71
src/rtcp.cc
71
src/rtcp.cc
|
@ -16,6 +16,10 @@
|
|||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#else
|
||||
#include <ws2ipdef.h>
|
||||
#endif
|
||||
|
||||
#include <cassert>
|
||||
|
@ -40,13 +44,16 @@ constexpr int ESTIMATED_MAX_RECEPTION_TIME_MS = 10;
|
|||
const uint32_t MAX_SUPPORTED_PARTICIPANTS = 31;
|
||||
|
||||
uvgrtp::rtcp::rtcp(std::shared_ptr<uvgrtp::rtp> rtp, std::shared_ptr<std::atomic_uint> ssrc, std::string cname, int rce_flags):
|
||||
rce_flags_(rce_flags), our_role_(RECEIVER),
|
||||
rce_flags_(rce_flags), our_role_(RECEIVER),
|
||||
tp_(0), tc_(0), tn_(0), pmembers_(0),
|
||||
members_(0), senders_(0), rtcp_bandwidth_(0), reduced_minimum_(0),
|
||||
we_sent_(false), local_addr_(""), remote_addr_(""), local_port_(0), dst_port_(0),
|
||||
avg_rtcp_pkt_pize_(0), avg_rtcp_size_(64), rtcp_pkt_count_(0), rtcp_byte_count_(0),
|
||||
rtcp_pkt_sent_count_(0), initial_(true), ssrc_(ssrc),
|
||||
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<uvgrtp::socket>(new uvgrtp::socket(0));
|
||||
rtp_error_t ret = RTP_OK;
|
||||
|
||||
if ((ret = rtcp_socket_->init(AF_INET, SOCK_DGRAM, 0)) != RTP_OK)
|
||||
{
|
||||
if (ipv6_) {
|
||||
ret = rtcp_socket_->init(AF_INET6, SOCK_DGRAM, 0);
|
||||
}
|
||||
else {
|
||||
ret = rtcp_socket_->init(AF_INET, SOCK_DGRAM, 0);
|
||||
}
|
||||
if (ret != RTP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -233,19 +244,47 @@ rtp_error_t uvgrtp::rtcp::start()
|
|||
if (local_addr_ != "")
|
||||
{
|
||||
UVG_LOG_INFO("Binding RTCP to port %s:%d", local_addr_.c_str(), local_port_);
|
||||
sockaddr_in bind_addr = rtcp_socket_->create_sockaddr(AF_INET, local_addr_, local_port_);
|
||||
if ((ret = rtcp_socket_->bind(bind_addr)) != RTP_OK)
|
||||
{
|
||||
return ret;
|
||||
if (ipv6_) {
|
||||
sockaddr_in6 bind_addr6 = rtcp_socket_->create_ip6_sockaddr(local_addr_, local_port_);
|
||||
if ((ret = rtcp_socket_->bind_ip6(bind_addr6)) != RTP_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sockaddr_in bind_addr = rtcp_socket_->create_sockaddr(AF_INET, local_addr_, local_port_);
|
||||
if ((ret = rtcp_socket_->bind(bind_addr)) != RTP_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UVG_LOG_WARN("No local address provided");
|
||||
return ret;
|
||||
|
||||
UVG_LOG_WARN("No local address provided, binding RTCP to INADDR_ANY");
|
||||
UVG_LOG_INFO("Binding RTCP to port %s:%d", local_addr_.c_str(), local_port_);
|
||||
if (ipv6_) {
|
||||
sockaddr_in6 bind_addr6 = rtcp_socket_->create_ip6_sockaddr_any(local_port_);
|
||||
if ((ret = rtcp_socket_->bind_ip6(bind_addr6)) != RTP_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
else {
|
||||
sockaddr_in bind_addr = rtcp_socket_->create_sockaddr(AF_INET, INADDR_ANY, local_port_);
|
||||
if ((ret = rtcp_socket_->bind(bind_addr)) != RTP_OK)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ipv6_) {
|
||||
socket_address_ipv6_ = rtcp_socket_->create_ip6_sockaddr(remote_addr_, dst_port_);
|
||||
}
|
||||
else {
|
||||
socket_address_ = rtcp_socket_->create_sockaddr(AF_INET, remote_addr_, dst_port_);
|
||||
}
|
||||
|
||||
socket_address_ = rtcp_socket_->create_sockaddr(AF_INET, remote_addr_, dst_port_);
|
||||
report_generator_.reset(new std::thread(rtcp_runner, this));
|
||||
report_reader_.reset(new std::thread(rtcp_report_reader, this));
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
337
src/socket.cc
337
src/socket.cc
|
@ -8,13 +8,17 @@
|
|||
#include <thread>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <Ws2tcpip.h>
|
||||
#include <ws2def.h>
|
||||
#include <ws2ipdef.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#if defined(__MINGW32__) || defined(__MINGW64__)
|
||||
|
@ -29,10 +33,13 @@ using namespace mingw;
|
|||
|
||||
#define WSABUF_SIZE 256
|
||||
|
||||
uvgrtp::socket::socket(int rce_flags):
|
||||
uvgrtp::socket::socket(int rce_flags) :
|
||||
socket_(0),
|
||||
remote_address_(),
|
||||
local_address_(),
|
||||
remote_ip6_address_(),
|
||||
local_ip6_address_(),
|
||||
ipv6_(false),
|
||||
rce_flags_(rce_flags),
|
||||
#ifdef _WIN32
|
||||
buffers_()
|
||||
|
@ -55,7 +62,12 @@ uvgrtp::socket::~socket()
|
|||
|
||||
rtp_error_t uvgrtp::socket::init(short family, int type, int protocol)
|
||||
{
|
||||
assert(family == AF_INET);
|
||||
if (family == AF_INET6) {
|
||||
ipv6_ = true;
|
||||
}
|
||||
else {
|
||||
ipv6_ = false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if ((socket_ = ::socket(family, type, protocol)) == INVALID_SOCKET) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -3,13 +3,18 @@
|
|||
#include "uvgrtp/util.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <Windows.h>
|
||||
#include <winsock2.h>
|
||||
#include <mswsock.h>
|
||||
#include <inaddr.h>
|
||||
#include <ws2ipdef.h>
|
||||
#include <WS2tcpip.h>
|
||||
#else
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
@ -83,6 +88,7 @@ namespace uvgrtp {
|
|||
* Return RTP_BIND_ERROR if the bind failed */
|
||||
rtp_error_t bind(short family, unsigned host, short port);
|
||||
rtp_error_t bind(sockaddr_in& local_address);
|
||||
rtp_error_t bind_ip6(sockaddr_in6& local_address);
|
||||
|
||||
/* Same as setsockopt(2), used to manipulate the underlying socket object
|
||||
*
|
||||
|
@ -100,6 +106,7 @@ namespace uvgrtp {
|
|||
*
|
||||
* Return RTP_OK on success and write the amount of bytes sent to "bytes_sent"
|
||||
* Return RTP_SEND_ERROR on error and set "bytes_sent" to -1 */
|
||||
// nämä done
|
||||
rtp_error_t sendto(uint8_t *buf, size_t buf_len, int send_flags);
|
||||
rtp_error_t sendto(uint8_t *buf, size_t buf_len, int send_flags, int *bytes_sent);
|
||||
rtp_error_t sendto(buf_vec& buffers, int send_flags);
|
||||
|
@ -108,12 +115,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 */
|
||||
|
|
44
src/zrtp.cc
44
src/zrtp.cc
|
@ -11,7 +11,12 @@
|
|||
#include "crypto.hh"
|
||||
#include "random.hh"
|
||||
#include "debug.hh"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <ws2ipdef.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#include <cstring>
|
||||
#include <thread>
|
||||
|
||||
|
@ -27,6 +32,7 @@ using namespace uvgrtp::zrtp_msg;
|
|||
uvgrtp::zrtp::zrtp():
|
||||
ssrc_(0),
|
||||
remote_addr_(),
|
||||
remote_ip6_addr_(),
|
||||
initialized_(false),
|
||||
receiver_(),
|
||||
dh_finished_(false)
|
||||
|
@ -377,7 +383,7 @@ rtp_error_t uvgrtp::zrtp::begin_session()
|
|||
UVG_LOG_DEBUG("Sending ZRTP hello # %i, path: %s", i + 1, path.c_str());
|
||||
int type = 0;
|
||||
|
||||
if (hello.send_msg(local_socket_, remote_addr_) != RTP_OK) {
|
||||
if (hello.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to send Hello message");
|
||||
}
|
||||
else if (receiver_.recv_msg(local_socket_, rto, 0, type) == RTP_OK) {
|
||||
|
@ -388,7 +394,7 @@ rtp_error_t uvgrtp::zrtp::begin_session()
|
|||
/* We received Hello message from remote, parse it and send */
|
||||
if (type == ZRTP_FT_HELLO) {
|
||||
UVG_LOG_DEBUG("Got ZRTP Hello. Sending Hello ACK");
|
||||
hello_ack.send_msg(local_socket_, remote_addr_);
|
||||
hello_ack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
|
||||
|
||||
if (!hello_recv) {
|
||||
hello_recv = true;
|
||||
|
@ -480,7 +486,7 @@ rtp_error_t uvgrtp::zrtp::init_session(int key_agreement)
|
|||
rto = 150;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (commit.send_msg(local_socket_, remote_addr_) != RTP_OK) {
|
||||
if (commit.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to send Commit message!");
|
||||
}
|
||||
else if (receiver_.recv_msg(local_socket_, rto, 0, type) == RTP_OK) {
|
||||
|
@ -519,7 +525,7 @@ rtp_error_t uvgrtp::zrtp::dh_part1()
|
|||
int type = 0;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (dhpart.send_msg(local_socket_, remote_addr_) != RTP_OK) {
|
||||
if (dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to send DHPart1 Message!");
|
||||
}
|
||||
|
||||
|
@ -563,7 +569,7 @@ rtp_error_t uvgrtp::zrtp::dh_part2()
|
|||
generate_shared_secrets_dh();
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if ((ret = dhpart.send_msg(local_socket_, remote_addr_)) != RTP_OK) {
|
||||
if ((ret = dhpart.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to send DHPart2 Message!");
|
||||
return ret;
|
||||
}
|
||||
|
@ -590,7 +596,7 @@ rtp_error_t uvgrtp::zrtp::responder_finalize_session()
|
|||
int type = 0;
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if (confirm.send_msg(local_socket_, remote_addr_) != RTP_OK) {
|
||||
if (confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to send Confirm1 Message!");
|
||||
}
|
||||
|
||||
|
@ -608,7 +614,7 @@ rtp_error_t uvgrtp::zrtp::responder_finalize_session()
|
|||
}
|
||||
|
||||
/* TODO: send in a loop? */
|
||||
confack.send_msg(local_socket_, remote_addr_);
|
||||
confack.send_msg(local_socket_, remote_addr_, remote_ip6_addr_);
|
||||
return RTP_OK;
|
||||
}
|
||||
}
|
||||
|
@ -638,7 +644,7 @@ rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
|
|||
}
|
||||
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
if ((ret = confirm.send_msg(local_socket_, remote_addr_)) != RTP_OK) {
|
||||
if ((ret = confirm.send_msg(local_socket_, remote_addr_, remote_ip6_addr_)) != RTP_OK) {
|
||||
UVG_LOG_ERROR("Failed to send Confirm2 Message!");
|
||||
return ret;
|
||||
}
|
||||
|
@ -657,7 +663,7 @@ rtp_error_t uvgrtp::zrtp::initiator_finalize_session()
|
|||
return RTP_TIMEOUT;
|
||||
}
|
||||
|
||||
rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, bool perform_dh)
|
||||
rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool perform_dh, bool ipv6)
|
||||
{
|
||||
rtp_error_t ret = RTP_OK;
|
||||
|
||||
|
@ -672,7 +678,7 @@ rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> so
|
|||
}
|
||||
|
||||
// perform Diffie-Hellman (DH)
|
||||
ret = init_dhm(ssrc, socket, addr);
|
||||
ret = init_dhm(ssrc, socket, addr, addr6, ipv6);
|
||||
zrtp_mtx_.unlock();
|
||||
}
|
||||
else
|
||||
|
@ -684,17 +690,21 @@ rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> so
|
|||
}
|
||||
|
||||
// multistream mode
|
||||
ret = init_msm(ssrc, socket, addr);
|
||||
ret = init_msm(ssrc, socket, addr, addr6);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr)
|
||||
rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6)
|
||||
{
|
||||
rtp_error_t ret = RTP_OK;
|
||||
|
||||
UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", socket->sockaddr_to_string(addr).c_str());
|
||||
if (ipv6) {
|
||||
UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", socket->sockaddr_ip6_to_string(addr6).c_str());
|
||||
}
|
||||
else {
|
||||
UVG_LOG_DEBUG("Starting ZRTP Diffie-Hellman negotiation with %s", socket->sockaddr_to_string(addr).c_str());
|
||||
}
|
||||
|
||||
/* TODO: set all fields initially to zero */
|
||||
memset(session_.hash_ctx.o_hvi, 0, sizeof(session_.hash_ctx.o_hvi));
|
||||
|
@ -708,6 +718,7 @@ rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
|
|||
|
||||
local_socket_ = socket;
|
||||
remote_addr_ = addr;
|
||||
remote_ip6_addr_ = addr6;
|
||||
|
||||
session_.seq = 0;
|
||||
session_.ssrc = ssrc;
|
||||
|
@ -789,12 +800,13 @@ rtp_error_t uvgrtp::zrtp::init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket
|
|||
return RTP_OK;
|
||||
}
|
||||
|
||||
rtp_error_t uvgrtp::zrtp::init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr)
|
||||
rtp_error_t uvgrtp::zrtp::init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6)
|
||||
{
|
||||
rtp_error_t ret;
|
||||
|
||||
local_socket_ = socket;
|
||||
remote_addr_ = addr;
|
||||
remote_ip6_addr_ = addr6;
|
||||
|
||||
session_.ssrc = ssrc;
|
||||
session_.seq = 0;
|
||||
|
|
11
src/zrtp.hh
11
src/zrtp.hh
|
@ -8,9 +8,13 @@
|
|||
#include <winsock2.h>
|
||||
#include <mswsock.h>
|
||||
#include <inaddr.h>
|
||||
#include <ws2ipdef.h>
|
||||
|
||||
#else
|
||||
#include <netinet/ip.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
#include <mutex>
|
||||
|
@ -42,7 +46,7 @@ namespace uvgrtp {
|
|||
*
|
||||
* Return RTP_OK on success
|
||||
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
|
||||
rtp_error_t init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, bool perform_dh);
|
||||
rtp_error_t init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool perform_dh, bool ipv6);
|
||||
|
||||
/* Get SRTP keys for the session that was just initialized
|
||||
*
|
||||
|
@ -85,13 +89,13 @@ namespace uvgrtp {
|
|||
*
|
||||
* Return RTP_OK on success
|
||||
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
|
||||
rtp_error_t init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr);
|
||||
rtp_error_t init_dhm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6, bool ipv6);
|
||||
|
||||
/* Initialize ZRTP session between us and remote using Multistream mode
|
||||
*
|
||||
* Return RTP_OK on success
|
||||
* Return RTP_TIMEOUT if remote did not send messages in timely manner */
|
||||
rtp_error_t init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr);
|
||||
rtp_error_t init_msm(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6);
|
||||
|
||||
/* Generate zid for this ZRTP instance. ZID is a unique, 96-bit long ID */
|
||||
void generate_zid();
|
||||
|
@ -170,6 +174,7 @@ namespace uvgrtp {
|
|||
uint32_t ssrc_;
|
||||
std::shared_ptr<uvgrtp::socket> local_socket_;
|
||||
sockaddr_in remote_addr_;
|
||||
sockaddr_in6 remote_ip6_addr_;
|
||||
|
||||
/* Has the ZRTP connection been initialized using DH */
|
||||
bool initialized_;
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
#include "debug.hh"
|
||||
|
||||
#include <string>
|
||||
#ifdef _WIN32
|
||||
#include <ws2ipdef.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
uvgrtp::zrtp_msg::zrtp_message::zrtp_message():
|
||||
frame_(nullptr),
|
||||
|
@ -26,11 +32,10 @@ uvgrtp::zrtp_msg::zrtp_message::~zrtp_message()
|
|||
(void)uvgrtp::frame::dealloc_frame((uvgrtp::frame::zrtp_frame*)rframe_);
|
||||
}
|
||||
|
||||
rtp_error_t uvgrtp::zrtp_msg::zrtp_message::send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr)
|
||||
rtp_error_t uvgrtp::zrtp_msg::zrtp_message::send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6)
|
||||
{
|
||||
rtp_error_t ret;
|
||||
|
||||
if ((ret = socket->sendto(addr, (uint8_t *)frame_, len_, 0, nullptr)) != RTP_OK)
|
||||
if ((ret = socket->sendto(addr, addr6, (uint8_t*)frame_, len_, 0, nullptr)) != RTP_OK)
|
||||
log_platform_error("Failed to send ZRTP message");
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -7,6 +7,12 @@
|
|||
#include "uvgrtp/util.hh"
|
||||
|
||||
#include <memory>
|
||||
#ifdef _WIN32
|
||||
#include <ws2ipdef.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
|
||||
namespace uvgrtp {
|
||||
|
||||
|
@ -19,7 +25,7 @@ namespace uvgrtp {
|
|||
zrtp_message();
|
||||
~zrtp_message();
|
||||
|
||||
rtp_error_t send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr);
|
||||
rtp_error_t send_msg(std::shared_ptr<uvgrtp::socket> socket, sockaddr_in& addr, sockaddr_in6& addr6);
|
||||
|
||||
virtual rtp_error_t parse_msg(uvgrtp::zrtp_msg::receiver& receiver,
|
||||
zrtp_session_t& session) = 0;
|
||||
|
|
Loading…
Reference in New Issue