common: Remove memory leaks shown by Valgrind with tests

This commit is contained in:
Joni Räsänen 2022-08-31 10:06:37 +03:00
parent fef90f154c
commit 1e751e051f
12 changed files with 152 additions and 91 deletions

View File

@ -117,7 +117,7 @@ namespace uvgrtp {
struct rtcp_sdes_item {
uint8_t type = 0;
uint8_t length = 0;
void *data = nullptr;
uint8_t *data = nullptr;
};
struct rtcp_sdes_chunk {

View File

@ -176,7 +176,7 @@ namespace uvgrtp {
uvgrtp::frame::rtcp_app_packet *get_app_packet(uint32_t ssrc);
/* Return a reference to vector that contains the sockets of all participants */
std::vector<uvgrtp::socket>& get_sockets();
std::vector<std::shared_ptr<uvgrtp::socket>>& get_sockets();
/* Somebody joined the multicast group the owner of this RTCP instance is part of
* Add it to RTCP participant list so we can start listening for reports
@ -388,7 +388,9 @@ namespace uvgrtp {
/* Takes ownership of the frame */
rtp_error_t send_rtcp_packet_to_participants(uint8_t* frame, uint32_t frame_size, bool encrypt);
void free_participant(rtcp_participant* participant);
void free_participant(std::unique_ptr<rtcp_participant> participant);
void cleanup_participants();
/* Secure RTCP context */
std::shared_ptr<uvgrtp::srtcp> srtcp_;
@ -451,7 +453,7 @@ namespace uvgrtp {
/* The first value of RTP timestamp (aka t = 0) */
uint32_t rtp_ts_start_;
std::map<uint32_t, rtcp_participant *> participants_;
std::map<uint32_t, std::unique_ptr<rtcp_participant>> participants_;
uint8_t num_receivers_; // maximum is 32 at the moment (5 bits)
/* statistics for RTCP Sender and Receiver Reports */
@ -459,13 +461,13 @@ namespace uvgrtp {
/* If we expect frames from remote but haven't received anything from remote yet,
* the participant resides in this vector until he's moved to participants_ */
std::vector<rtcp_participant *> initial_participants_;
std::vector<std::unique_ptr<rtcp_participant>> initial_participants_;
/* Vector of sockets the RTCP runner is listening to
*
* The socket are also stored here (in addition to participants_ map) so they're easier
* to pass to poll when RTCP runner is listening to incoming packets */
std::vector<uvgrtp::socket> sockets_;
std::vector<std::shared_ptr<uvgrtp::socket>> sockets_;
void (*sender_hook_)(uvgrtp::frame::rtcp_sender_report *);
void (*receiver_hook_)(uvgrtp::frame::rtcp_receiver_report *);

View File

@ -104,10 +104,20 @@ uvgrtp::formats::h26x::~h26x()
{
for (auto& frame : queued_)
{
delete[] frame;
(void)uvgrtp::frame::dealloc_frame(frame);
}
queued_.clear();
for (auto& fragment : fragments_)
{
if (fragment != nullptr)
{
(void)uvgrtp::frame::dealloc_frame(fragment);
}
}
fragments_.clear();
}
/* NOTE: the area 0 - len (ie data[0] - data[len - 1]) must be addressable
@ -613,12 +623,14 @@ rtp_error_t uvgrtp::formats::h26x::packet_handler(int rce_flags, uvgrtp::frame::
if (dropped_ts_.find(frame->header.timestamp) != dropped_ts_.end()) {
UVG_LOG_DEBUG("Received an RTP packet belonging to a dropped frame! Timestamp: %lu, seq: %u",
frame->header.timestamp, frame->header.seq);
(void)uvgrtp::frame::dealloc_frame(frame); // free fragment memory
return RTP_GENERIC_ERROR;
}
if (completed_ts_.find(frame->header.timestamp) != completed_ts_.end()) {
UVG_LOG_DEBUG("Received an RTP packet belonging to a completed frame! Timestamp: %lu, seq: %u",
frame->header.timestamp, frame->header.seq);
(void)uvgrtp::frame::dealloc_frame(frame); // free fragment memory
return RTP_GENERIC_ERROR;
}
@ -676,6 +688,7 @@ rtp_error_t uvgrtp::formats::h26x::packet_handler(int rce_flags, uvgrtp::frame::
if (frames_[fragment_ts].nal_type != nal_type)
{
UVG_LOG_ERROR("The fragment has different NAL type fragments before!");
(void)uvgrtp::frame::dealloc_frame(frame); // free fragment memory
return RTP_GENERIC_ERROR;
}

View File

@ -210,7 +210,10 @@ rtp_error_t uvgrtp::frame_queue::enqueue_message(uint8_t *message, size_t messag
/* If SRTP with proper encryption has been enabled but
* RCE_SRTP_INPLACE_ENCRYPTION has **not** been enabled, make a copy of the memory block*/
if ((rce_flags_ & (RCE_SRTP | RCE_SRTP_INPLACE_ENCRYPTION | RCE_SRTP_NULL_CIPHER)) == RCE_SRTP)
message = (uint8_t *)memdup(message, message_len);
{
// TODO: This memory is never deleted
message = (uint8_t*)memdup(message, message_len);
}
tmp.push_back({ message_len, message });

View File

@ -53,7 +53,7 @@ rtp_error_t uvgrtp::poll::blocked_recv(std::shared_ptr<uvgrtp::socket> socket, u
return rtp_ret;
}
rtp_error_t uvgrtp::poll::poll(std::vector<uvgrtp::socket>& sockets, uint8_t *buf, size_t buf_len, int timeout, int *bytes_read)
rtp_error_t uvgrtp::poll::poll(std::vector<std::shared_ptr<uvgrtp::socket>>& sockets, uint8_t *buf, size_t buf_len, int timeout, int *bytes_read)
{
if (buf == nullptr || buf_len == 0)
return RTP_INVALID_VALUE;
@ -68,7 +68,7 @@ rtp_error_t uvgrtp::poll::poll(std::vector<uvgrtp::socket>& sockets, uint8_t *bu
int ret;
for (size_t i = 0; i < sockets.size(); ++i) {
fds[i].fd = sockets.at(i).get_raw_socket();
fds[i].fd = sockets.at(i)->get_raw_socket();
fds[i].events = POLLIN | POLLERR;
}
@ -87,7 +87,7 @@ rtp_error_t uvgrtp::poll::poll(std::vector<uvgrtp::socket>& sockets, uint8_t *bu
for (size_t i = 0; i < sockets.size(); ++i) {
if (fds[i].revents & POLLIN) {
auto rtp_ret = sockets.at(i).recv(buf, buf_len, 0, bytes_read);
auto rtp_ret = sockets.at(i)->recv(buf, buf_len, 0, bytes_read);
if (rtp_ret != RTP_OK) {
UVG_LOG_ERROR("recv() for socket %d failed: %s", fds[i].fd, strerror(errno));
@ -107,7 +107,7 @@ rtp_error_t uvgrtp::poll::poll(std::vector<uvgrtp::socket>& sockets, uint8_t *bu
FD_ZERO(&read_fds);
for (size_t i = 0; i < sockets.size(); ++i) {
auto fd = sockets.at(i).get_raw_socket();
auto fd = sockets.at(i)->get_raw_socket();
FD_SET(fd, &read_fds);
}
@ -125,7 +125,7 @@ rtp_error_t uvgrtp::poll::poll(std::vector<uvgrtp::socket>& sockets, uint8_t *bu
}
for (size_t i = 0; i < sockets.size(); ++i) {
auto rtp_ret = sockets.at(i).recv((uint8_t *)buf, (int)buf_len, 0, bytes_read);
auto rtp_ret = sockets.at(i)->recv((uint8_t *)buf, (int)buf_len, 0, bytes_read);
if (rtp_ret != RTP_OK) {
if (WSAGetLastError() == WSAEWOULDBLOCK)

View File

@ -17,7 +17,7 @@ namespace uvgrtp {
*
* If some actions happens with the socket, return status
* If the timeout is exceeded, return RTP_INTERRUPTED */
rtp_error_t poll(std::vector<uvgrtp::socket>& sockets, uint8_t *buf, size_t buf_len, int timeout, int *bytes_read);
rtp_error_t poll(std::vector<std::shared_ptr<uvgrtp::socket>>& sockets, uint8_t *buf, size_t buf_len, int timeout, int *bytes_read);
/* TODO: */
rtp_error_t blocked_recv(std::shared_ptr<uvgrtp::socket> socket, uint8_t *buf, size_t buf_len, int timeout, int *bytes_read);

View File

@ -48,7 +48,7 @@ void uvgrtp::reception_flow::clear_frames()
frames_mtx_.lock();
for (auto& frame : frames_)
{
delete[] frame;
(void)uvgrtp::frame::dealloc_frame(frame);
}
frames_.clear();
@ -256,12 +256,12 @@ void uvgrtp::reception_flow::call_aux_handlers(uint32_t key, int rce_flags, uvgr
case RTP_MULTIPLE_PKTS_READY:
{
while ((*aux.getter)(aux.arg, frame) == RTP_PKT_READY)
this->return_frame(*frame);
return_frame(*frame);
}
break;
case RTP_PKT_READY:
this->return_frame(*frame);
return_frame(*frame);
break;
/* packet was not handled or only partially handled by the handler
@ -291,13 +291,13 @@ void uvgrtp::reception_flow::call_aux_handlers(uint32_t key, int rce_flags, uvgr
case RTP_MULTIPLE_PKTS_READY:
{
while (aux.getter(frame) == RTP_PKT_READY)
this->return_frame(*frame);
return_frame(*frame);
break;
}
case RTP_PKT_READY:
{
this->return_frame(*frame);
return_frame(*frame);
break;
}
@ -461,7 +461,7 @@ void uvgrtp::reception_flow::process_packet(int rce_flags)
}
case RTP_PKT_MODIFIED:
{
this->call_aux_handlers(handler.first, rce_flags, &frame);
call_aux_handlers(handler.first, rce_flags, &frame);
break;
}
case RTP_GENERIC_ERROR:

View File

@ -81,7 +81,7 @@ uvgrtp::rtcp::rtcp(std::shared_ptr<uvgrtp::rtp> rtp, std::string cname, int rce_
memcpy(cname_, c, cname.length());
uint8_t length = (uint8_t)cname.length();
cnameItem_ = { 1, length, (void*)cname_ };
cnameItem_ = { 1, length, (uint8_t*)cname_ };
ourItems_.push_back(cnameItem_);
}
}
@ -100,7 +100,28 @@ uvgrtp::rtcp::~rtcp()
stop();
}
cleanup_participants();
ourItems_.clear();
sockets_.clear();
}
void uvgrtp::rtcp::cleanup_participants()
{
UVG_LOG_DEBUG("Removing all participants");
/* free all receiver statistic structs */
for (auto& participant : participants_)
{
free_participant(std::move(participant.second));
}
participants_.clear();
for (auto& participant : initial_participants_)
{
free_participant(std::move(participant));
}
initial_participants_.clear();
}
uvgrtp::rtcp_app_packet::rtcp_app_packet(const char* name, uint8_t subtype, uint32_t payload_len, const uint8_t* payload)
@ -122,7 +143,7 @@ uvgrtp::rtcp_app_packet::~rtcp_app_packet() {
delete[] payload;
}
void uvgrtp::rtcp::free_participant(rtcp_participant* participant)
void uvgrtp::rtcp::free_participant(std::unique_ptr<rtcp_participant> participant)
{
participant->socket = nullptr;
@ -136,14 +157,27 @@ void uvgrtp::rtcp::free_participant(rtcp_participant* participant)
}
if (participant->sdes_frame)
{
for (auto& chunk : participant->sdes_frame->chunks)
{
for (auto& item : chunk.items)
{
if (item.data != nullptr)
{
delete[] item.data;
}
}
}
delete participant->sdes_frame;
}
if (participant->app_frame)
{
if (participant->app_frame->payload != nullptr)
{
delete[] participant->app_frame->payload;
}
delete participant->app_frame;
}
delete participant;
}
rtp_error_t uvgrtp::rtcp::start()
@ -163,23 +197,11 @@ rtp_error_t uvgrtp::rtcp::start()
rtp_error_t uvgrtp::rtcp::stop()
{
UVG_LOG_DEBUG("Stopping RTCP");
// TODO: Make thread safe. I think this kind of works, but not in a flexible way
if (!active_)
{
UVG_LOG_DEBUG("Removing all participants");
/* free all receiver statistic structs */
for (auto& participant : participants_)
{
free_participant(participant.second);
}
participants_.clear();
for (auto& participant : initial_participants_)
{
free_participant(participant);
}
initial_participants_.clear();
cleanup_participants();
return RTP_OK;
}
@ -320,7 +342,7 @@ rtp_error_t uvgrtp::rtcp::add_participant(std::string dst_addr, uint16_t dst_por
}
rtp_error_t ret;
rtcp_participant *p = new rtcp_participant();
std::unique_ptr<rtcp_participant> p = std::unique_ptr<rtcp_participant>(new rtcp_participant());
zero_stats(&p->stats);
@ -328,7 +350,7 @@ rtp_error_t uvgrtp::rtcp::add_participant(std::string dst_addr, uint16_t dst_por
if ((ret = p->socket->init(AF_INET, SOCK_DGRAM, 0)) != RTP_OK)
{
delete p;
free_participant(std::move(p));
return ret;
}
@ -336,7 +358,7 @@ rtp_error_t uvgrtp::rtcp::add_participant(std::string dst_addr, uint16_t dst_por
if ((ret = p->socket->setsockopt(SOL_SOCKET, SO_REUSEADDR, (const char *)&enable, sizeof(int))) != RTP_OK)
{
delete p;
free_participant(std::move(p));
return ret;
}
@ -360,7 +382,7 @@ rtp_error_t uvgrtp::rtcp::add_participant(std::string dst_addr, uint16_t dst_por
if ((ret = p->socket->setsockopt(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) != RTP_OK)
{
delete p;
free_participant(std::move(p));
return ret;
}
@ -368,7 +390,7 @@ rtp_error_t uvgrtp::rtcp::add_participant(std::string dst_addr, uint16_t dst_por
if ((ret = p->socket->bind(AF_INET, INADDR_ANY, src_port)) != RTP_OK)
{
delete p;
free_participant(std::move(p));
return ret;
}
@ -376,8 +398,8 @@ rtp_error_t uvgrtp::rtcp::add_participant(std::string dst_addr, uint16_t dst_por
p->address = p->socket->create_sockaddr(AF_INET, dst_addr, dst_port);
p->stats.clock_rate = clock_rate;
initial_participants_.push_back(p);
sockets_.push_back(*p->socket);
sockets_.push_back(p->socket);
initial_participants_.push_back(std::move(p));
return RTP_OK;
}
@ -395,10 +417,10 @@ rtp_error_t uvgrtp::rtcp::add_participant(uint32_t ssrc)
* create a "fake" participant that is only used for storing statistics information */
if (initial_participants_.empty())
{
participants_[ssrc] = new rtcp_participant();
participants_[ssrc] = std::unique_ptr<rtcp_participant> (new rtcp_participant());
zero_stats(&participants_[ssrc]->stats);
} else {
participants_[ssrc] = initial_participants_.back();
participants_[ssrc] = std::move(initial_participants_.back());
initial_participants_.pop_back();
}
num_receivers_++;
@ -691,7 +713,7 @@ uvgrtp::frame::rtcp_app_packet* uvgrtp::rtcp::get_app_packet(uint32_t ssrc)
return frame;
}
std::vector<uvgrtp::socket>& uvgrtp::rtcp::get_sockets()
std::vector<std::shared_ptr<uvgrtp::socket>>& uvgrtp::rtcp::get_sockets()
{
return sockets_;
}
@ -847,48 +869,47 @@ rtp_error_t uvgrtp::rtcp::update_participant_seq(uint32_t ssrc, uint16_t seq)
return RTP_GENERIC_ERROR;
}
auto p = participants_[ssrc];
uint16_t udelta = seq - p->stats.max_seq;
uint16_t udelta = seq - participants_[ssrc]->stats.max_seq;
/* Source is not valid until MIN_SEQUENTIAL packets with
* sequential sequence numbers have been received. */
if (p->probation)
if (participants_[ssrc]->probation)
{
/* packet is in sequence */
if (seq == p->stats.max_seq + 1)
if (seq == participants_[ssrc]->stats.max_seq + 1)
{
p->probation--;
p->stats.max_seq = seq;
if (!p->probation)
participants_[ssrc]->probation--;
participants_[ssrc]->stats.max_seq = seq;
if (!participants_[ssrc]->probation)
{
uvgrtp::rtcp::init_participant_seq(ssrc, seq);
return RTP_OK;
}
} else {
p->probation = MIN_SEQUENTIAL - 1;
p->stats.max_seq = seq;
participants_[ssrc]->probation = MIN_SEQUENTIAL - 1;
participants_[ssrc]->stats.max_seq = seq;
}
return RTP_NOT_READY;
} else if (udelta < MAX_DROPOUT) {
/* in order, with permissible gap */
if (seq < p->stats.max_seq)
if (seq < participants_[ssrc]->stats.max_seq)
{
/* Sequence number wrapped - count another 64K cycle. */
p->stats.cycles += 1;
participants_[ssrc]->stats.cycles += 1;
}
p->stats.max_seq = seq;
participants_[ssrc]->stats.max_seq = seq;
} else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
/* the sequence number made a very large jump */
if (seq == p->stats.bad_seq)
if (seq == participants_[ssrc]->stats.bad_seq)
{
/* Two sequential packets -- assume that the other side
* restarted without telling us so just re-sync
* (i.e., pretend this was the first packet). */
uvgrtp::rtcp::init_participant_seq(ssrc, seq);
} else {
p->stats.bad_seq = (seq + 1) & (RTP_SEQ_MOD - 1);
UVG_LOG_ERROR("Invalid sequence number. Seq jump: %u -> %u", p->stats.max_seq, seq);
participants_[ssrc]->stats.bad_seq = (seq + 1) & (RTP_SEQ_MOD - 1);
UVG_LOG_ERROR("Invalid sequence number. Seq jump: %u -> %u", participants_[ssrc]->stats.max_seq, seq);
return RTP_GENERIC_ERROR;
}
} else {
@ -917,10 +938,8 @@ bool uvgrtp::rtcp::collision_detected(uint32_t ssrc, const sockaddr_in& src_addr
return false;
}
auto sender = participants_.at(ssrc);
if (src_addr.sin_port != sender->address.sin_port &&
src_addr.sin_addr.s_addr != sender->address.sin_addr.s_addr)
if (src_addr.sin_port != participants_.at(ssrc)->address.sin_port &&
src_addr.sin_addr.s_addr != participants_.at(ssrc)->address.sin_addr.s_addr)
{
return true;
}
@ -930,31 +949,32 @@ bool uvgrtp::rtcp::collision_detected(uint32_t ssrc, const sockaddr_in& src_addr
void uvgrtp::rtcp::update_session_statistics(const uvgrtp::frame::rtp_frame *frame)
{
auto p = participants_[frame->header.ssrc];
participants_[frame->header.ssrc]->stats.received_rtp_packet = true;
p->stats.received_rtp_packet = true;
p->stats.received_pkts += 1;
p->stats.received_bytes += (uint32_t)frame->payload_len;
participants_[frame->header.ssrc]->stats.received_pkts += 1;
participants_[frame->header.ssrc]->stats.received_bytes += (uint32_t)frame->payload_len;
/* calculate number of dropped packets */
int extended_max = (static_cast<int>(p->stats.cycles) << 16) + p->stats.max_seq;
int expected = extended_max - p->stats.base_seq + 1;
int extended_max = (static_cast<int>(participants_[frame->header.ssrc]->stats.cycles) << 16) +
participants_[frame->header.ssrc]->stats.max_seq;
int expected = extended_max - participants_[frame->header.ssrc]->stats.base_seq + 1;
int dropped = expected - p->stats.received_pkts;
p->stats.dropped_pkts = dropped >= 0 ? dropped : 0;
int dropped = expected - participants_[frame->header.ssrc]->stats.received_pkts;
participants_[frame->header.ssrc]->stats.dropped_pkts = dropped >= 0 ? dropped : 0;
// the arrival time expressed as an RTP timestamp
uint32_t arrival = p->stats.initial_rtp +
(uint32_t)uvgrtp::clock::ntp::diff_now(p->stats.initial_ntp)*(p->stats.clock_rate / 1000);
uint32_t arrival = participants_[frame->header.ssrc]->stats.initial_rtp +
(uint32_t)uvgrtp::clock::ntp::diff_now(participants_[frame->header.ssrc]->stats.initial_ntp)*
(participants_[frame->header.ssrc]->stats.clock_rate / 1000);
// calculate interarrival jitter. See RFC 3550 A.8
uint32_t transit = arrival - frame->header.timestamp; // A.8: int transit = arrival - r->ts
uint32_t trans_difference = std::abs((int)(transit - p->stats.transit));
uint32_t trans_difference = std::abs((int)(transit - participants_[frame->header.ssrc]->stats.transit));
// update statistics
p->stats.transit = transit;
p->stats.jitter += (1.f / 16.f) * ((double)trans_difference - p->stats.jitter);
participants_[frame->header.ssrc]->stats.transit = transit;
participants_[frame->header.ssrc]->stats.jitter += (1.f / 16.f) *
((double)trans_difference - participants_[frame->header.ssrc]->stats.jitter);
}
/* RTCP packet handler is responsible for doing two things:
@ -1330,8 +1350,6 @@ rtp_error_t uvgrtp::rtcp::handle_sdes_packet(uint8_t* packet, size_t& read_ptr,
auto frame = new uvgrtp::frame::rtcp_sdes_packet;
frame->header = header;
// TODO: The SDES parsing is incorrect at the moment
// Read SDES chunks
while (read_ptr + SSRC_CSRC_SIZE <= packet_end)
{
@ -1348,7 +1366,7 @@ rtp_error_t uvgrtp::rtcp::handle_sdes_packet(uint8_t* packet, size_t& read_ptr,
if (read_ptr + item.length <= packet_end)
{
item.data = (void*)new uint8_t[item.length];
item.data = new uint8_t[item.length];
memcpy(item.data, &packet[read_ptr], item.length);
read_ptr += item.length;
@ -1363,7 +1381,6 @@ rtp_error_t uvgrtp::rtcp::handle_sdes_packet(uint8_t* packet, size_t& read_ptr,
}
frame->chunks.push_back(chunk);
}
sdes_mutex_.lock();
@ -1415,8 +1432,7 @@ rtp_error_t uvgrtp::rtcp::handle_bye_packet(uint8_t* packet, size_t& read_ptr,
}
UVG_LOG_DEBUG("Destroying participant with BYE");
participants_[ssrc]->socket = nullptr;
delete participants_[ssrc];
free_participant(std::move(participants_[ssrc]));
participants_.erase(ssrc);
}
@ -1445,9 +1461,16 @@ rtp_error_t uvgrtp::rtcp::handle_app_packet(uint8_t* packet, size_t& read_ptr,
size_t application_data_size = packet_end - read_ptr;
// application data is saved to payload
frame->payload = new uint8_t[application_data_size];
memcpy(frame->payload, &packet[read_ptr], application_data_size);
if (application_data_size > 0)
{
// application data is saved to payload
frame->payload = new uint8_t[application_data_size];
memcpy(frame->payload, &packet[read_ptr], application_data_size);
}
else
{
frame->payload = nullptr;
}
app_mutex_.lock();
if (app_hook_) {

View File

@ -170,6 +170,8 @@ std::string uvgrtp::socket::sockaddr_to_string(const sockaddr_in& addr) const
std::string string(c_string);
string.append(":" + std::to_string(ntohs(addr.sin_port)));
delete[] c_string;
return string;
}

View File

@ -646,7 +646,7 @@ rtp_error_t uvgrtp::zrtp::init(uint32_t ssrc, std::shared_ptr<uvgrtp::socket> so
"to select which streams should not perform DH");
}
// perform Diffie-Helmann (DH)
// perform Diffie-Hellman (DH)
ret = init_dhm(ssrc, socket, addr);
zrtp_mtx_.unlock();
}

View File

@ -244,6 +244,17 @@ void sdes_hook(uvgrtp::frame::rtcp_sdes_packet* frame)
{
std::cout << "Got SDES frame with " << frame->chunks.size() << " chunk" << std::endl;
for (auto& chunk : frame->chunks)
{
for (auto& item : chunk.items)
{
if (item.data != nullptr)
{
delete[] item.data;
}
}
}
/* RTCP frames can be deallocated using delete */
delete frame;
}
@ -258,6 +269,10 @@ void app_hook(uvgrtp::frame::rtcp_app_packet* frame)
std::cout << "ssrc: " << frame->ssrc << std::endl;
std::cout << "Name: " << name << std::endl;
std::cout << "Payload length " << payload_len << " and content: " << payload << std::endl;
if (payload_len > 0)
{
delete[] frame->payload;
}
delete frame;
}

View File

@ -188,6 +188,9 @@ TEST(EncryptionTests, zrtp)
{
receiver_thread->join();
}
cleanup_sess(ctx, sender_session);
cleanup_sess(ctx, receiver_session);
}
TEST(EncryptionTests, zrtp_multistream)