common: Remove memory leaks shown by Valgrind with tests
This commit is contained in:
parent
fef90f154c
commit
1e751e051f
|
@ -117,7 +117,7 @@ namespace uvgrtp {
|
||||||
struct rtcp_sdes_item {
|
struct rtcp_sdes_item {
|
||||||
uint8_t type = 0;
|
uint8_t type = 0;
|
||||||
uint8_t length = 0;
|
uint8_t length = 0;
|
||||||
void *data = nullptr;
|
uint8_t *data = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rtcp_sdes_chunk {
|
struct rtcp_sdes_chunk {
|
||||||
|
|
|
@ -176,7 +176,7 @@ namespace uvgrtp {
|
||||||
uvgrtp::frame::rtcp_app_packet *get_app_packet(uint32_t ssrc);
|
uvgrtp::frame::rtcp_app_packet *get_app_packet(uint32_t ssrc);
|
||||||
|
|
||||||
/* Return a reference to vector that contains the sockets of all participants */
|
/* 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
|
/* 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
|
* Add it to RTCP participant list so we can start listening for reports
|
||||||
|
@ -388,7 +388,9 @@ namespace uvgrtp {
|
||||||
/* Takes ownership of the frame */
|
/* Takes ownership of the frame */
|
||||||
rtp_error_t send_rtcp_packet_to_participants(uint8_t* frame, uint32_t frame_size, bool encrypt);
|
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 */
|
/* Secure RTCP context */
|
||||||
std::shared_ptr<uvgrtp::srtcp> srtcp_;
|
std::shared_ptr<uvgrtp::srtcp> srtcp_;
|
||||||
|
@ -451,7 +453,7 @@ namespace uvgrtp {
|
||||||
/* The first value of RTP timestamp (aka t = 0) */
|
/* The first value of RTP timestamp (aka t = 0) */
|
||||||
uint32_t rtp_ts_start_;
|
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)
|
uint8_t num_receivers_; // maximum is 32 at the moment (5 bits)
|
||||||
|
|
||||||
/* statistics for RTCP Sender and Receiver Reports */
|
/* 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,
|
/* 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_ */
|
* 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
|
/* Vector of sockets the RTCP runner is listening to
|
||||||
*
|
*
|
||||||
* The socket are also stored here (in addition to participants_ map) so they're easier
|
* 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 */
|
* 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 (*sender_hook_)(uvgrtp::frame::rtcp_sender_report *);
|
||||||
void (*receiver_hook_)(uvgrtp::frame::rtcp_receiver_report *);
|
void (*receiver_hook_)(uvgrtp::frame::rtcp_receiver_report *);
|
||||||
|
|
|
@ -104,10 +104,20 @@ uvgrtp::formats::h26x::~h26x()
|
||||||
{
|
{
|
||||||
for (auto& frame : queued_)
|
for (auto& frame : queued_)
|
||||||
{
|
{
|
||||||
delete[] frame;
|
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
queued_.clear();
|
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
|
/* 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()) {
|
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",
|
UVG_LOG_DEBUG("Received an RTP packet belonging to a dropped frame! Timestamp: %lu, seq: %u",
|
||||||
frame->header.timestamp, frame->header.seq);
|
frame->header.timestamp, frame->header.seq);
|
||||||
|
(void)uvgrtp::frame::dealloc_frame(frame); // free fragment memory
|
||||||
return RTP_GENERIC_ERROR;
|
return RTP_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (completed_ts_.find(frame->header.timestamp) != completed_ts_.end()) {
|
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",
|
UVG_LOG_DEBUG("Received an RTP packet belonging to a completed frame! Timestamp: %lu, seq: %u",
|
||||||
frame->header.timestamp, frame->header.seq);
|
frame->header.timestamp, frame->header.seq);
|
||||||
|
(void)uvgrtp::frame::dealloc_frame(frame); // free fragment memory
|
||||||
return RTP_GENERIC_ERROR;
|
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)
|
if (frames_[fragment_ts].nal_type != nal_type)
|
||||||
{
|
{
|
||||||
UVG_LOG_ERROR("The fragment has different NAL type fragments before!");
|
UVG_LOG_ERROR("The fragment has different NAL type fragments before!");
|
||||||
|
(void)uvgrtp::frame::dealloc_frame(frame); // free fragment memory
|
||||||
return RTP_GENERIC_ERROR;
|
return RTP_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
/* If SRTP with proper encryption has been enabled but
|
||||||
* RCE_SRTP_INPLACE_ENCRYPTION has **not** been enabled, make a copy of the memory block*/
|
* 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)
|
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 });
|
tmp.push_back({ message_len, message });
|
||||||
|
|
||||||
|
|
10
src/poll.cc
10
src/poll.cc
|
@ -53,7 +53,7 @@ rtp_error_t uvgrtp::poll::blocked_recv(std::shared_ptr<uvgrtp::socket> socket, u
|
||||||
return rtp_ret;
|
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)
|
if (buf == nullptr || buf_len == 0)
|
||||||
return RTP_INVALID_VALUE;
|
return RTP_INVALID_VALUE;
|
||||||
|
@ -68,7 +68,7 @@ rtp_error_t uvgrtp::poll::poll(std::vector<uvgrtp::socket>& sockets, uint8_t *bu
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
for (size_t i = 0; i < sockets.size(); ++i) {
|
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;
|
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) {
|
for (size_t i = 0; i < sockets.size(); ++i) {
|
||||||
if (fds[i].revents & POLLIN) {
|
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) {
|
if (rtp_ret != RTP_OK) {
|
||||||
UVG_LOG_ERROR("recv() for socket %d failed: %s", fds[i].fd, strerror(errno));
|
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);
|
FD_ZERO(&read_fds);
|
||||||
|
|
||||||
for (size_t i = 0; i < sockets.size(); ++i) {
|
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);
|
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) {
|
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 (rtp_ret != RTP_OK) {
|
||||||
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
if (WSAGetLastError() == WSAEWOULDBLOCK)
|
||||||
|
|
|
@ -17,7 +17,7 @@ namespace uvgrtp {
|
||||||
*
|
*
|
||||||
* If some actions happens with the socket, return status
|
* If some actions happens with the socket, return status
|
||||||
* If the timeout is exceeded, return RTP_INTERRUPTED */
|
* 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: */
|
/* TODO: */
|
||||||
rtp_error_t blocked_recv(std::shared_ptr<uvgrtp::socket> socket, uint8_t *buf, size_t buf_len, int timeout, int *bytes_read);
|
rtp_error_t blocked_recv(std::shared_ptr<uvgrtp::socket> socket, uint8_t *buf, size_t buf_len, int timeout, int *bytes_read);
|
||||||
|
|
|
@ -48,7 +48,7 @@ void uvgrtp::reception_flow::clear_frames()
|
||||||
frames_mtx_.lock();
|
frames_mtx_.lock();
|
||||||
for (auto& frame : frames_)
|
for (auto& frame : frames_)
|
||||||
{
|
{
|
||||||
delete[] frame;
|
(void)uvgrtp::frame::dealloc_frame(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
frames_.clear();
|
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:
|
case RTP_MULTIPLE_PKTS_READY:
|
||||||
{
|
{
|
||||||
while ((*aux.getter)(aux.arg, frame) == RTP_PKT_READY)
|
while ((*aux.getter)(aux.arg, frame) == RTP_PKT_READY)
|
||||||
this->return_frame(*frame);
|
return_frame(*frame);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RTP_PKT_READY:
|
case RTP_PKT_READY:
|
||||||
this->return_frame(*frame);
|
return_frame(*frame);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* packet was not handled or only partially handled by the handler
|
/* 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:
|
case RTP_MULTIPLE_PKTS_READY:
|
||||||
{
|
{
|
||||||
while (aux.getter(frame) == RTP_PKT_READY)
|
while (aux.getter(frame) == RTP_PKT_READY)
|
||||||
this->return_frame(*frame);
|
return_frame(*frame);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RTP_PKT_READY:
|
case RTP_PKT_READY:
|
||||||
{
|
{
|
||||||
this->return_frame(*frame);
|
return_frame(*frame);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,7 +461,7 @@ void uvgrtp::reception_flow::process_packet(int rce_flags)
|
||||||
}
|
}
|
||||||
case RTP_PKT_MODIFIED:
|
case RTP_PKT_MODIFIED:
|
||||||
{
|
{
|
||||||
this->call_aux_handlers(handler.first, rce_flags, &frame);
|
call_aux_handlers(handler.first, rce_flags, &frame);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case RTP_GENERIC_ERROR:
|
case RTP_GENERIC_ERROR:
|
||||||
|
|
163
src/rtcp.cc
163
src/rtcp.cc
|
@ -81,7 +81,7 @@ uvgrtp::rtcp::rtcp(std::shared_ptr<uvgrtp::rtp> rtp, std::string cname, int rce_
|
||||||
memcpy(cname_, c, cname.length());
|
memcpy(cname_, c, cname.length());
|
||||||
uint8_t length = (uint8_t)cname.length();
|
uint8_t length = (uint8_t)cname.length();
|
||||||
|
|
||||||
cnameItem_ = { 1, length, (void*)cname_ };
|
cnameItem_ = { 1, length, (uint8_t*)cname_ };
|
||||||
ourItems_.push_back(cnameItem_);
|
ourItems_.push_back(cnameItem_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,28 @@ uvgrtp::rtcp::~rtcp()
|
||||||
stop();
|
stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup_participants();
|
||||||
|
|
||||||
ourItems_.clear();
|
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)
|
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;
|
delete[] payload;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uvgrtp::rtcp::free_participant(rtcp_participant* participant)
|
void uvgrtp::rtcp::free_participant(std::unique_ptr<rtcp_participant> participant)
|
||||||
{
|
{
|
||||||
participant->socket = nullptr;
|
participant->socket = nullptr;
|
||||||
|
|
||||||
|
@ -136,14 +157,27 @@ void uvgrtp::rtcp::free_participant(rtcp_participant* participant)
|
||||||
}
|
}
|
||||||
if (participant->sdes_frame)
|
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;
|
delete participant->sdes_frame;
|
||||||
}
|
}
|
||||||
if (participant->app_frame)
|
if (participant->app_frame)
|
||||||
{
|
{
|
||||||
|
if (participant->app_frame->payload != nullptr)
|
||||||
|
{
|
||||||
|
delete[] participant->app_frame->payload;
|
||||||
|
}
|
||||||
delete participant->app_frame;
|
delete participant->app_frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete participant;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rtp_error_t uvgrtp::rtcp::start()
|
rtp_error_t uvgrtp::rtcp::start()
|
||||||
|
@ -163,23 +197,11 @@ rtp_error_t uvgrtp::rtcp::start()
|
||||||
rtp_error_t uvgrtp::rtcp::stop()
|
rtp_error_t uvgrtp::rtcp::stop()
|
||||||
{
|
{
|
||||||
UVG_LOG_DEBUG("Stopping RTCP");
|
UVG_LOG_DEBUG("Stopping RTCP");
|
||||||
|
|
||||||
// TODO: Make thread safe. I think this kind of works, but not in a flexible way
|
// TODO: Make thread safe. I think this kind of works, but not in a flexible way
|
||||||
if (!active_)
|
if (!active_)
|
||||||
{
|
{
|
||||||
UVG_LOG_DEBUG("Removing all participants");
|
cleanup_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();
|
|
||||||
|
|
||||||
return RTP_OK;
|
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;
|
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);
|
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)
|
if ((ret = p->socket->init(AF_INET, SOCK_DGRAM, 0)) != RTP_OK)
|
||||||
{
|
{
|
||||||
delete p;
|
free_participant(std::move(p));
|
||||||
return ret;
|
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)
|
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;
|
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)
|
if ((ret = p->socket->setsockopt(SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))) != RTP_OK)
|
||||||
{
|
{
|
||||||
delete p;
|
free_participant(std::move(p));
|
||||||
return ret;
|
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)
|
if ((ret = p->socket->bind(AF_INET, INADDR_ANY, src_port)) != RTP_OK)
|
||||||
{
|
{
|
||||||
delete p;
|
free_participant(std::move(p));
|
||||||
return ret;
|
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->address = p->socket->create_sockaddr(AF_INET, dst_addr, dst_port);
|
||||||
p->stats.clock_rate = clock_rate;
|
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;
|
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 */
|
* create a "fake" participant that is only used for storing statistics information */
|
||||||
if (initial_participants_.empty())
|
if (initial_participants_.empty())
|
||||||
{
|
{
|
||||||
participants_[ssrc] = new rtcp_participant();
|
participants_[ssrc] = std::unique_ptr<rtcp_participant> (new rtcp_participant());
|
||||||
zero_stats(&participants_[ssrc]->stats);
|
zero_stats(&participants_[ssrc]->stats);
|
||||||
} else {
|
} else {
|
||||||
participants_[ssrc] = initial_participants_.back();
|
participants_[ssrc] = std::move(initial_participants_.back());
|
||||||
initial_participants_.pop_back();
|
initial_participants_.pop_back();
|
||||||
}
|
}
|
||||||
num_receivers_++;
|
num_receivers_++;
|
||||||
|
@ -691,7 +713,7 @@ uvgrtp::frame::rtcp_app_packet* uvgrtp::rtcp::get_app_packet(uint32_t ssrc)
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uvgrtp::socket>& uvgrtp::rtcp::get_sockets()
|
std::vector<std::shared_ptr<uvgrtp::socket>>& uvgrtp::rtcp::get_sockets()
|
||||||
{
|
{
|
||||||
return 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;
|
return RTP_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto p = participants_[ssrc];
|
uint16_t udelta = seq - participants_[ssrc]->stats.max_seq;
|
||||||
uint16_t udelta = seq - p->stats.max_seq;
|
|
||||||
|
|
||||||
/* Source is not valid until MIN_SEQUENTIAL packets with
|
/* Source is not valid until MIN_SEQUENTIAL packets with
|
||||||
* sequential sequence numbers have been received. */
|
* sequential sequence numbers have been received. */
|
||||||
if (p->probation)
|
if (participants_[ssrc]->probation)
|
||||||
{
|
{
|
||||||
/* packet is in sequence */
|
/* packet is in sequence */
|
||||||
if (seq == p->stats.max_seq + 1)
|
if (seq == participants_[ssrc]->stats.max_seq + 1)
|
||||||
{
|
{
|
||||||
p->probation--;
|
participants_[ssrc]->probation--;
|
||||||
p->stats.max_seq = seq;
|
participants_[ssrc]->stats.max_seq = seq;
|
||||||
if (!p->probation)
|
if (!participants_[ssrc]->probation)
|
||||||
{
|
{
|
||||||
uvgrtp::rtcp::init_participant_seq(ssrc, seq);
|
uvgrtp::rtcp::init_participant_seq(ssrc, seq);
|
||||||
return RTP_OK;
|
return RTP_OK;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
p->probation = MIN_SEQUENTIAL - 1;
|
participants_[ssrc]->probation = MIN_SEQUENTIAL - 1;
|
||||||
p->stats.max_seq = seq;
|
participants_[ssrc]->stats.max_seq = seq;
|
||||||
}
|
}
|
||||||
|
|
||||||
return RTP_NOT_READY;
|
return RTP_NOT_READY;
|
||||||
} else if (udelta < MAX_DROPOUT) {
|
} else if (udelta < MAX_DROPOUT) {
|
||||||
/* in order, with permissible gap */
|
/* 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. */
|
/* 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) {
|
} else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
|
||||||
/* the sequence number made a very large jump */
|
/* 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
|
/* Two sequential packets -- assume that the other side
|
||||||
* restarted without telling us so just re-sync
|
* restarted without telling us so just re-sync
|
||||||
* (i.e., pretend this was the first packet). */
|
* (i.e., pretend this was the first packet). */
|
||||||
uvgrtp::rtcp::init_participant_seq(ssrc, seq);
|
uvgrtp::rtcp::init_participant_seq(ssrc, seq);
|
||||||
} else {
|
} else {
|
||||||
p->stats.bad_seq = (seq + 1) & (RTP_SEQ_MOD - 1);
|
participants_[ssrc]->stats.bad_seq = (seq + 1) & (RTP_SEQ_MOD - 1);
|
||||||
UVG_LOG_ERROR("Invalid sequence number. Seq jump: %u -> %u", p->stats.max_seq, seq);
|
UVG_LOG_ERROR("Invalid sequence number. Seq jump: %u -> %u", participants_[ssrc]->stats.max_seq, seq);
|
||||||
return RTP_GENERIC_ERROR;
|
return RTP_GENERIC_ERROR;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -917,10 +938,8 @@ bool uvgrtp::rtcp::collision_detected(uint32_t ssrc, const sockaddr_in& src_addr
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto sender = participants_.at(ssrc);
|
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)
|
||||||
if (src_addr.sin_port != sender->address.sin_port &&
|
|
||||||
src_addr.sin_addr.s_addr != sender->address.sin_addr.s_addr)
|
|
||||||
{
|
{
|
||||||
return true;
|
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)
|
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;
|
participants_[frame->header.ssrc]->stats.received_pkts += 1;
|
||||||
|
participants_[frame->header.ssrc]->stats.received_bytes += (uint32_t)frame->payload_len;
|
||||||
p->stats.received_pkts += 1;
|
|
||||||
p->stats.received_bytes += (uint32_t)frame->payload_len;
|
|
||||||
|
|
||||||
/* calculate number of dropped packets */
|
/* calculate number of dropped packets */
|
||||||
int extended_max = (static_cast<int>(p->stats.cycles) << 16) + p->stats.max_seq;
|
int extended_max = (static_cast<int>(participants_[frame->header.ssrc]->stats.cycles) << 16) +
|
||||||
int expected = extended_max - p->stats.base_seq + 1;
|
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;
|
int dropped = expected - participants_[frame->header.ssrc]->stats.received_pkts;
|
||||||
p->stats.dropped_pkts = dropped >= 0 ? dropped : 0;
|
participants_[frame->header.ssrc]->stats.dropped_pkts = dropped >= 0 ? dropped : 0;
|
||||||
|
|
||||||
// the arrival time expressed as an RTP timestamp
|
// the arrival time expressed as an RTP timestamp
|
||||||
uint32_t arrival = p->stats.initial_rtp +
|
uint32_t arrival = participants_[frame->header.ssrc]->stats.initial_rtp +
|
||||||
(uint32_t)uvgrtp::clock::ntp::diff_now(p->stats.initial_ntp)*(p->stats.clock_rate / 1000);
|
(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
|
// calculate interarrival jitter. See RFC 3550 A.8
|
||||||
uint32_t transit = arrival - frame->header.timestamp; // A.8: int transit = arrival - r->ts
|
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
|
// update statistics
|
||||||
p->stats.transit = transit;
|
participants_[frame->header.ssrc]->stats.transit = transit;
|
||||||
p->stats.jitter += (1.f / 16.f) * ((double)trans_difference - p->stats.jitter);
|
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:
|
/* 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;
|
auto frame = new uvgrtp::frame::rtcp_sdes_packet;
|
||||||
frame->header = header;
|
frame->header = header;
|
||||||
|
|
||||||
// TODO: The SDES parsing is incorrect at the moment
|
|
||||||
|
|
||||||
// Read SDES chunks
|
// Read SDES chunks
|
||||||
while (read_ptr + SSRC_CSRC_SIZE <= packet_end)
|
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)
|
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);
|
memcpy(item.data, &packet[read_ptr], item.length);
|
||||||
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);
|
frame->chunks.push_back(chunk);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sdes_mutex_.lock();
|
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");
|
UVG_LOG_DEBUG("Destroying participant with BYE");
|
||||||
participants_[ssrc]->socket = nullptr;
|
free_participant(std::move(participants_[ssrc]));
|
||||||
delete participants_[ssrc];
|
|
||||||
participants_.erase(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;
|
size_t application_data_size = packet_end - read_ptr;
|
||||||
|
|
||||||
// application data is saved to payload
|
if (application_data_size > 0)
|
||||||
frame->payload = new uint8_t[application_data_size];
|
{
|
||||||
memcpy(frame->payload, &packet[read_ptr], application_data_size);
|
// 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();
|
app_mutex_.lock();
|
||||||
if (app_hook_) {
|
if (app_hook_) {
|
||||||
|
|
|
@ -170,6 +170,8 @@ std::string uvgrtp::socket::sockaddr_to_string(const sockaddr_in& addr) const
|
||||||
|
|
||||||
std::string string(c_string);
|
std::string string(c_string);
|
||||||
string.append(":" + std::to_string(ntohs(addr.sin_port)));
|
string.append(":" + std::to_string(ntohs(addr.sin_port)));
|
||||||
|
|
||||||
|
delete[] c_string;
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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");
|
"to select which streams should not perform DH");
|
||||||
}
|
}
|
||||||
|
|
||||||
// perform Diffie-Helmann (DH)
|
// perform Diffie-Hellman (DH)
|
||||||
ret = init_dhm(ssrc, socket, addr);
|
ret = init_dhm(ssrc, socket, addr);
|
||||||
zrtp_mtx_.unlock();
|
zrtp_mtx_.unlock();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
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 */
|
/* RTCP frames can be deallocated using delete */
|
||||||
delete frame;
|
delete frame;
|
||||||
}
|
}
|
||||||
|
@ -258,6 +269,10 @@ void app_hook(uvgrtp::frame::rtcp_app_packet* frame)
|
||||||
std::cout << "ssrc: " << frame->ssrc << std::endl;
|
std::cout << "ssrc: " << frame->ssrc << std::endl;
|
||||||
std::cout << "Name: " << name << std::endl;
|
std::cout << "Name: " << name << std::endl;
|
||||||
std::cout << "Payload length " << payload_len << " and content: " << payload << std::endl;
|
std::cout << "Payload length " << payload_len << " and content: " << payload << std::endl;
|
||||||
|
if (payload_len > 0)
|
||||||
|
{
|
||||||
|
delete[] frame->payload;
|
||||||
|
}
|
||||||
delete frame;
|
delete frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -188,6 +188,9 @@ TEST(EncryptionTests, zrtp)
|
||||||
{
|
{
|
||||||
receiver_thread->join();
|
receiver_thread->join();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cleanup_sess(ctx, sender_session);
|
||||||
|
cleanup_sess(ctx, receiver_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(EncryptionTests, zrtp_multistream)
|
TEST(EncryptionTests, zrtp_multistream)
|
||||||
|
|
Loading…
Reference in New Issue