Support custom deleter for SrsUniquePtr. (#4309)

SrsUniquePtr does not support array or object created by malloc, because
we only use delete to dispose the resource. You can use a custom
function to free the memory allocated by malloc or other allocators.
```cpp
      char* p = (char*)malloc(1024);
      SrsUniquePtr<char> ptr(p, your_free_chars);
```

This is used to replace the SrsAutoFreeH. For example:
```cpp
      addrinfo* r = NULL;
      SrsAutoFreeH(addrinfo, r, freeaddrinfo);
      getaddrinfo("127.0.0.1", NULL, &hints, &r);
```

Now, this can be replaced by:
```cpp
      addrinfo* r = NULL;
      getaddrinfo("127.0.0.1", NULL, &hints, &r);
      SrsUniquePtr<addrinfo> r2(r, freeaddrinfo);
```

Please aware that there is a slight difference between SrsAutoFreeH and
SrsUniquePtr. SrsAutoFreeH will track the address of pointer, while
SrsUniquePtr will not.
```cpp
      addrinfo* r = NULL;
      SrsAutoFreeH(addrinfo, r, freeaddrinfo); // r will be freed even r is changed later.
      SrsUniquePtr<addrinfo> ptr(r, freeaddrinfo); // crash because r is an invalid pointer.
```

---------

Co-authored-by: Haibo Chen <495810242@qq.com>
Co-authored-by: john <hondaxiao@tencent.com>
This commit is contained in:
Winlin 2025-04-26 00:01:34 -04:00 committed by GitHub
parent 5881155095
commit 4e55bc83b7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 362 additions and 253 deletions

20
.vscode/settings.json vendored
View File

@ -1,5 +1,23 @@
{
"cmake.sourceDirectory": "${workspaceFolder}/trunk/ide/srs_clion",
"cmake.buildDirectory": "${workspaceFolder}/trunk/ide/vscode-build",
"cmake.configureOnOpen": false
"cmake.configureOnOpen": false,
"files.associations": {
"vector": "cpp",
"__hash_table": "cpp",
"__split_buffer": "cpp",
"__tree": "cpp",
"array": "cpp",
"bitset": "cpp",
"deque": "cpp",
"initializer_list": "cpp",
"list": "cpp",
"map": "cpp",
"queue": "cpp",
"set": "cpp",
"stack": "cpp",
"string": "cpp",
"string_view": "cpp",
"unordered_map": "cpp"
}
}

View File

@ -50,78 +50,5 @@ extern std::ostream& operator<<(std::ostream& out, const ErrorObject* err);
#include <stdlib.h>
// To free the instance in the current scope, for instance, MyClass* ptr,
// which is a ptr and this class will:
// 1. free the ptr.
// 2. set ptr to NULL.
//
// Usage:
// MyClass* po = new MyClass();
// // ...... use po
// SrsAutoFree(MyClass, po);
//
// Usage for array:
// MyClass** pa = new MyClass*[size];
// // ....... use pa
// SrsAutoFreeA(MyClass*, pa);
//
// @remark the MyClass can be basic type, for instance, SrsAutoFreeA(char, pstr),
// where the char* pstr = new char[size].
// To delete object.
#define SrsAutoFree(className, instance) \
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, NULL)
// To delete array.
#define SrsAutoFreeA(className, instance) \
impl_SrsAutoFree<className> _auto_free_array_##instance(&instance, true, false, NULL)
// Use free instead of delete.
#define SrsAutoFreeF(className, instance) \
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, true, NULL)
// Use hook instead of delete.
#define SrsAutoFreeH(className, instance, hook) \
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, hook)
// The template implementation.
template<class T>
class impl_SrsAutoFree
{
private:
T** ptr;
bool is_array;
bool _use_free;
void (*_hook)(T*);
public:
// If use_free, use free(void*) to release the p.
// If specified hook, use hook(p) to release it.
// Use delete to release p, or delete[] if p is an array.
impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) {
ptr = p;
is_array = array;
_use_free = use_free;
_hook = hook;
}
virtual ~impl_SrsAutoFree() {
if (ptr == NULL || *ptr == NULL) {
return;
}
if (_use_free) {
free(*ptr);
} else if (_hook) {
_hook(*ptr);
} else {
if (is_array) {
delete[] *ptr;
} else {
delete *ptr;
}
}
*ptr = NULL;
}
};
// The time unit in ms, for example 100 * SRS_UTIME_MILLISECONDS means 100ms.
#define SRS_UTIME_MILLISECONDS 1000
#endif

View File

@ -360,6 +360,7 @@ function parse_user_option() {
--gmp) SRS_GPERF_MP=$(switch2value $value) ;;
--gcp) SRS_GPERF_CP=$(switch2value $value) ;;
--gprof) SRS_GPROF=$(switch2value $value) ;;
--asan) SRS_SANITIZER=$(switch2value $value) ;;
--sanitizer) SRS_SANITIZER=$(switch2value $value) ;;
--sanitizer-static) SRS_SANITIZER_STATIC=$(switch2value $value) ;;
--sanitizer-log) SRS_SANITIZER_LOG=$(switch2value $value) ;;

View File

@ -1638,41 +1638,15 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket* pkt)
return srs_error_new(ERROR_RTC_RTP_MUXER, "no sps or pps in stap-a rtp. sps: %p, pps:%p", sps, pps);
}
// Reset SPS/PPS cache, ensuring that the next SPS/PPS will be handled when both are received.
// Note that we should use SrsAutoFree to set the ptr to NULL.
SrsAutoFree(SrsRtpPacket, obs_whip_sps_);
SrsAutoFree(SrsRtpPacket, obs_whip_pps_);
// Packet SPS/PPS to RTMP keyframe.
err = packet_sps_pps(pkt, sps, pps);
// h264 raw to h264 packet.
std::string sh;
SrsUniquePtr<SrsRawH264Stream> avc(new SrsRawH264Stream());
if ((err = avc->mux_sequence_header(string(sps->bytes, sps->size), string(pps->bytes, pps->size), sh)) != srs_success) {
return srs_error_wrap(err, "mux sequence header");
}
// h264 packet to flv packet.
char* flv = NULL;
int nb_flv = 0;
if ((err = avc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame, SrsVideoAvcFrameTraitSequenceHeader, pkt->get_avsync_time(),
pkt->get_avsync_time(), &flv, &nb_flv)) != srs_success) {
return srs_error_wrap(err, "avc to flv");
}
SrsMessageHeader header;
header.initialize_video(nb_flv, pkt->get_avsync_time(), 1);
SrsCommonMessage rtmp;
if ((err = rtmp.create(&header, flv, nb_flv)) != srs_success) {
return srs_error_wrap(err, "create rtmp");
}
SrsSharedPtrMessage msg;
if ((err = msg.create(&rtmp)) != srs_success) {
return srs_error_wrap(err, "create message");
}
if ((err = bridge_->on_frame(&msg)) != srs_success) {
return err;
// Always reset the SPS/PPS cache after used it.
srs_freep(obs_whip_sps_);
srs_freep(obs_whip_pps_);
if (err != srs_success) {
return srs_error_wrap(err, "packet sps/pps");
}
}
@ -1729,6 +1703,48 @@ srs_error_t SrsRtcFrameBuilder::packet_video_key_frame(SrsRtpPacket* pkt)
return err;
}
srs_error_t SrsRtcFrameBuilder::packet_sps_pps(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps)
{
srs_error_t err = srs_success;
// h264 raw to h264 packet.
std::string sh;
SrsUniquePtr<SrsRawH264Stream> avc(new SrsRawH264Stream());
string sps2 = string(sps->bytes, sps->size);
string pps2 = string(pps->bytes, pps->size);
if ((err = avc->mux_sequence_header(sps2, pps2, sh)) != srs_success) {
return srs_error_wrap(err, "mux sequence header");
}
// h264 packet to flv packet.
char* flv = NULL;
int nb_flv = 0;
if ((err = avc->mux_avc2flv(sh, SrsVideoAvcFrameTypeKeyFrame,
SrsVideoAvcFrameTraitSequenceHeader, pkt->get_avsync_time(),
pkt->get_avsync_time(), &flv, &nb_flv)) != srs_success) {
return srs_error_wrap(err, "avc to flv");
}
SrsMessageHeader header;
header.initialize_video(nb_flv, pkt->get_avsync_time(), 1);
SrsCommonMessage rtmp;
if ((err = rtmp.create(&header, flv, nb_flv)) != srs_success) {
return srs_error_wrap(err, "create rtmp");
}
SrsSharedPtrMessage msg;
if ((err = msg.create(&rtmp)) != srs_success) {
return srs_error_wrap(err, "create message");
}
if ((err = bridge_->on_frame(&msg)) != srs_success) {
return err;
}
return err;
}
srs_error_t SrsRtcFrameBuilder::packet_video_rtmp(const uint16_t start, const uint16_t end)
{
srs_error_t err = srs_success;

View File

@ -356,6 +356,8 @@ private:
private:
srs_error_t packet_video(SrsRtpPacket* pkt);
srs_error_t packet_video_key_frame(SrsRtpPacket* pkt);
srs_error_t packet_sps_pps(SrsRtpPacket* pkt, SrsSample* sps, SrsSample* pps);
private:
inline uint16_t cache_index(uint16_t current_sn) {
return current_sn % s_cache_size;
}

View File

@ -16,23 +16,36 @@
// SrsUniquePtr<MyClass> ptr(new MyClass());
// ptr->do_something();
//
// Note that the ptr should be initialized before use it, or it will crash if not set, for example:
// Note that the p should be initialized before use it, or it will crash if not set, for example:
// Myclass* p;
// SrsUniquePtr<MyClass> ptr(p); // crash because p is an invalid pointer.
//
// Note that do not support array or object created by malloc, because we only use delete to dispose
// the resource.
// the resource. You can use a custom function to free the memory allocated by malloc or other
// allocators.
// char* p = (char*)malloc(1024);
// SrsUniquePtr<char> ptr(p, your_free_chars);
// Or to free a specific object:
// addrinfo* r = NULL;
// getaddrinfo("127.0.0.1", NULL, &hints, &r);
// SrsUniquePtr<addrinfo> ptr(r, freeaddrinfo);
template<class T>
class SrsUniquePtr
{
private:
T* ptr_;
void (*deleter_)(T*);
public:
SrsUniquePtr(T* ptr = NULL) {
SrsUniquePtr(T* ptr = NULL, void (*deleter)(T*) = NULL) {
ptr_ = ptr;
deleter_ = deleter;
}
virtual ~SrsUniquePtr() {
delete ptr_;
if (!deleter_) {
delete ptr_;
} else {
deleter_(ptr_);
}
}
public:
// Get the object.
@ -68,6 +81,10 @@ private:
// Usage:
// SrsUniquePtr<MyClass[]> ptr(new MyClass[10]);
// ptr[0]->do_something();
//
// Note that the p should be initialized before use it, or it will crash if not set, for example:
// Myclass* p;
// SrsUniquePtr<MyClass[]> ptr(p); // crash because p is an invalid pointer.
template<class T>
class SrsUniquePtr<T[]>
{

View File

@ -11,85 +11,93 @@
#include <stdlib.h>
// Note that the SrsAutoFree is deprecated, please use SrsUniquePtr instead.
// Note that the SrsAutoFree is deprecated, please use SrsUniquePtr instead. For example:
// MyClass* p = new MyClass();
// SrsAutoFree(MyClass, p);
// This can be replaced by:
// SrsUniquePtr<MyClass> p(new MyClass());
//
// Note: Please use SrsUniquePtr if possible. Please aware that there is a slight difference between SrsAutoFree
// and SrsUniquePtr. SrsAutoFree will track the address of pointer, while SrsUniquePtr will not.
// Note: Please aware that there is a slight difference between SrsAutoFree and SrsUniquePtr.
// SrsAutoFree will track the address of pointer, while SrsUniquePtr will not.
// MyClass* p;
// SrsAutoFree(MyClass, p); // p will be freed even p is changed later.
// SrsUniquePtr ptr(p); // crash because p is an invalid pointer.
//
// The auto free helper, which is actually the unique ptr, without the move feature,
// see https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107
//
// To free the instance in the current scope, for instance, MyClass* ptr,
// which is a ptr and this class will:
// 1. free the ptr.
// 2. set ptr to NULL.
//
// Usage:
// MyClass* po = new MyClass();
// // ...... use po
// SrsAutoFree(MyClass, po);
//
// Usage for array:
// See https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107 for more details.
//#define SrsAutoFree(className, instance) \
// impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, NULL)
// To delete array. Please use SrsUniquePtr instead. For example:
// MyClass** pa = new MyClass*[size];
// // ....... use pa
// SrsAutoFreeA(MyClass*, pa);
// This can be replaced by:
// SrsUniquePtr<MyClass[]> pa(new MyClass[10]);
//
// @remark the MyClass can be basic type, for instance, SrsAutoFreeA(char, pstr),
// where the char* pstr = new char[size].
// To delete object.
#define SrsAutoFree(className, instance) \
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, NULL)
// To delete array.
#define SrsAutoFreeA(className, instance) \
impl_SrsAutoFree<className> _auto_free_array_##instance(&instance, true, false, NULL)
// Use free instead of delete.
#define SrsAutoFreeF(className, instance) \
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, true, NULL)
// Use hook instead of delete.
#define SrsAutoFreeH(className, instance, hook) \
impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, hook)
// Note: Please aware that there is a slight difference between SrsAutoFreeA and SrsUniquePtr.
// SrsAutoFreeA will track the address of pointer, while SrsUniquePtr will not.
// MyClass** pa;
// SrsAutoFreeA(MyClass*, pa); // pa will be freed even pa is changed later.
// SrsUniquePtr<MyClass[]> ptr(pa); // crash because pa is an invalid pointer.
//
// See https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107 for more details.
//#define SrsAutoFreeA(className, instance) \
// impl_SrsAutoFree<className> _auto_free_array_##instance(&instance, true, false, NULL)
// Use hook instead of delete. Please use SrsUniquePtr instead. For example:
// addrinfo* r = NULL;
// SrsAutoFreeH(addrinfo, r, freeaddrinfo);
// getaddrinfo("127.0.0.1", NULL, &hints, &r);
// This can be replaced by:
// addrinfo* r = NULL;
// getaddrinfo("127.0.0.1", NULL, &hints, &r);
// SrsUniquePtr<addrinfo> ptr(r, freeaddrinfo);
//
// Note: Please aware that there is a slight difference between SrsAutoFreeH and SrsUniquePtr.
// SrsAutoFreeH will track the address of pointer, while SrsUniquePtr will not.
// addrinfo* r = NULL;
// SrsAutoFreeH(addrinfo, r, freeaddrinfo); // r will be freed even r is changed later.
// SrsUniquePtr<addrinfo> ptr(r, freeaddrinfo); // crash because r is an invalid pointer.
//
// See https://github.com/ossrs/srs/discussions/3667#discussioncomment-8969107 for more details.
//#define SrsAutoFreeH(className, instance, hook) \
// impl_SrsAutoFree<className> _auto_free_##instance(&instance, false, false, hook)
// The template implementation.
template<class T>
class impl_SrsAutoFree
{
private:
T** ptr;
bool is_array;
bool _use_free;
void (*_hook)(T*);
public:
// If use_free, use free(void*) to release the p.
// If specified hook, use hook(p) to release it.
// Use delete to release p, or delete[] if p is an array.
impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) {
ptr = p;
is_array = array;
_use_free = use_free;
_hook = hook;
}
virtual ~impl_SrsAutoFree() {
if (ptr == NULL || *ptr == NULL) {
return;
}
if (_use_free) {
free(*ptr);
} else if (_hook) {
_hook(*ptr);
} else {
if (is_array) {
delete[] *ptr;
} else {
delete *ptr;
}
}
*ptr = NULL;
}
};
//template<class T>
//class impl_SrsAutoFree
//{
//private:
// T** ptr;
// bool is_array;
// bool _use_free;
// void (*_hook)(T*);
//public:
// // If use_free, use free(void*) to release the p.
// // If specified hook, use hook(p) to release it.
// // Use delete to release p, or delete[] if p is an array.
// impl_SrsAutoFree(T** p, bool array, bool use_free, void (*hook)(T*)) {
// ptr = p;
// is_array = array;
// _use_free = use_free;
// _hook = hook;
// }
//
// virtual ~impl_SrsAutoFree() {
// if (ptr == NULL || *ptr == NULL) {
// return;
// }
//
// if (_use_free) {
// free(*ptr);
// } else if (_hook) {
// _hook(*ptr);
// } else {
// if (is_array) {
// delete[] *ptr;
// } else {
// delete *ptr;
// }
// }
//
// *ptr = NULL;
// }
//};
#endif

View File

@ -5315,9 +5315,21 @@ srs_error_t SrsMp4BoxReader::read(SrsSimpleStream* stream, SrsMp4Box** ppbox)
srs_error_t err = srs_success;
SrsMp4Box* box = NULL;
// Note that we should use SrsAutoFree to free the ptr which is set later.
SrsAutoFree(SrsMp4Box, box);
if ((err = do_read(stream, box)) == srs_success) {
*ppbox = box;
return err;
}
// When error, free the created box.
srs_freep(box);
return err;
}
srs_error_t SrsMp4BoxReader::do_read(SrsSimpleStream* stream, SrsMp4Box*& box)
{
srs_error_t err = srs_success;
while (true) {
// For the first time to read the box, maybe it's a basic box which is only 4bytes header.
// When we disconvery the real box, we know the size of the whole box, then read again and decode it.
@ -5357,11 +5369,6 @@ srs_error_t SrsMp4BoxReader::read(SrsSimpleStream* stream, SrsMp4Box** ppbox)
continue;
}
if (err == srs_success) {
*ppbox = box;
box = NULL;
}
break;
}
@ -5651,18 +5658,17 @@ srs_error_t SrsMp4Decoder::load_next_box(SrsMp4Box** ppbox, uint32_t required_bo
while (true) {
SrsMp4Box* box = NULL;
// Note that we should use SrsAutoFree to free the ptr which is set later.
SrsAutoFree(SrsMp4Box, box);
if ((err = do_load_next_box(&box, required_box_type)) != srs_success) {
return srs_error_wrap(err, "load box");
}
if (!required_box_type || (uint32_t)box->type == required_box_type) {
*ppbox = box;
box = NULL;
break;
return err;
}
// Free the box is not matched the required type.
srs_freep(box);
}
return err;

View File

@ -1963,6 +1963,9 @@ public:
public:
// Read a MP4 box to pbox, the stream is fill with the bytes of box to decode.
virtual srs_error_t read(SrsSimpleStream* stream, SrsMp4Box** ppbox);
private:
srs_error_t do_read(SrsSimpleStream* stream, SrsMp4Box*& box);
public:
// Skip the box from stream, and skip in file if need.
virtual srs_error_t skip(SrsMp4Box* box, SrsSimpleStream* stream);
};

View File

@ -156,11 +156,11 @@ string srs_dns_resolve(string host, int& family)
memset(&hints, 0, sizeof(hints));
hints.ai_family = family;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
if(getaddrinfo(host.c_str(), NULL, &hints, &r)) {
addrinfo* r_raw = NULL;
if(getaddrinfo(host.c_str(), NULL, &hints, &r_raw)) {
return "";
}
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
char shost[64];
memset(shost, 0, sizeof(shost));

View File

@ -60,23 +60,23 @@ srs_error_t parse(std::string mp4_file, bool verbose)
fprintf(stderr, "\n%s\n", mp4_file.c_str());
while (true) {
SrsMp4Box* box = NULL;
// Note that we should use SrsAutoFree to free the ptr which is set later.
SrsAutoFree(SrsMp4Box, box);
if ((err = br.read(stream.get(), &box)) != srs_success) {
SrsMp4Box* box_raw = NULL;
if ((err = br.read(stream.get(), &box_raw)) != srs_success) {
if (srs_error_code(err) == ERROR_SYSTEM_FILE_EOF) {
fprintf(stderr, "\n");
}
return srs_error_wrap(err, "read box");
}
// Should use unique pointer after box is created.
SrsUniquePtr box(box_raw);
SrsUniquePtr<SrsBuffer> buffer(new SrsBuffer(stream->bytes(), stream->length()));
if ((err = box->decode(buffer.get())) != srs_success) {
return srs_error_wrap(err, "decode box");
}
if ((err = br.skip(box, stream.get())) != srs_success) {
if ((err = br.skip(box.get(), stream.get())) != srs_success) {
return srs_error_wrap(err, "skip box");
}

View File

@ -198,14 +198,14 @@ srs_error_t srs_srt_listen(srs_srt_t srt_fd, std::string ip, int port)
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) {
addrinfo* r_raw = NULL;
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r_raw)) {
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)",
hints.ai_family, hints.ai_socktype, hints.ai_flags);
}
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
if ((err = do_srs_srt_listen(srt_fd, r)) != srs_success) {
if ((err = do_srs_srt_listen(srt_fd, r.get())) != srs_success) {
srt_close(srt_fd);
return srs_error_wrap(err, "srt_fd=%d", srt_fd);
}

View File

@ -213,11 +213,11 @@ srs_error_t srs_tcp_connect(string server, int port, srs_utime_t tm, srs_netfd_t
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
if(getaddrinfo(server.c_str(), sport, (const addrinfo*)&hints, &r)) {
addrinfo* r_raw = NULL;
if(getaddrinfo(server.c_str(), sport, (const addrinfo*)&hints, &r_raw)) {
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "get address info");
}
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
int sock = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
if(sock == -1){
@ -291,12 +291,12 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd)
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) {
addrinfo* r_raw = NULL;
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r_raw)) {
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)",
hints.ai_family, hints.ai_socktype, hints.ai_flags);
}
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
int fd = 0;
if ((fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) {
@ -304,7 +304,7 @@ srs_error_t srs_tcp_listen(std::string ip, int port, srs_netfd_t* pfd)
r->ai_family, r->ai_socktype, r->ai_protocol);
}
if ((err = do_srs_tcp_listen(fd, r, pfd)) != srs_success) {
if ((err = do_srs_tcp_listen(fd, r.get(), pfd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "fd=%d", fd);
}
@ -353,12 +353,12 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd)
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_NUMERICHOST;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r)) {
addrinfo* r_raw = NULL;
if(getaddrinfo(ip.c_str(), sport, (const addrinfo*)&hints, &r_raw)) {
return srs_error_new(ERROR_SYSTEM_IP_INVALID, "getaddrinfo hints=(%d,%d,%d)",
hints.ai_family, hints.ai_socktype, hints.ai_flags);
}
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
int fd = 0;
if ((fd = socket(r->ai_family, r->ai_socktype, r->ai_protocol)) == -1) {
@ -366,7 +366,7 @@ srs_error_t srs_udp_listen(std::string ip, int port, srs_netfd_t* pfd)
r->ai_family, r->ai_socktype, r->ai_protocol);
}
if ((err = do_srs_udp_listen(fd, r, pfd)) != srs_success) {
if ((err = do_srs_udp_listen(fd, r.get(), pfd)) != srs_success) {
::close(fd);
return srs_error_wrap(err, "fd=%d", fd);
}

View File

@ -17,12 +17,6 @@ VOID TEST(CoreAutoFreeTest, Free)
char* data = new char[32];
srs_freepa(data);
EXPECT_TRUE(data == NULL);
if (true) {
data = new char[32];
SrsAutoFreeA(char, data);
}
EXPECT_TRUE(data == NULL);
}
VOID TEST(CoreMacroseTest, Check)
@ -489,3 +483,120 @@ VOID TEST(CoreSmartPtr, UniquePtrArray)
EXPECT_EQ(100, *ptr);
}
#ifndef _WIN32
#include <netdb.h>
#endif
void mock_free_chars(char* p) {
free(p);
}
VOID TEST(CoreSmartPtr, UniquePtrDeleterExample)
{
if (true) {
char* p = (char*)malloc(1024);
SrsUniquePtr<char> ptr(p, mock_free_chars);
}
if (true) {
addrinfo* r = NULL;
getaddrinfo("127.0.0.1", NULL, NULL, &r);
SrsUniquePtr<addrinfo> ptr(r, freeaddrinfo);
}
}
class MockSlice
{
public:
const char* bytes_;
public:
MockSlice(const char* bytes) {
bytes_ = bytes;
}
virtual ~MockSlice() {
}
public:
static void deleter(MockSlice* p) {
p->bytes_ = NULL;
}
};
VOID TEST(CoreSmartPtr, UniquePtrDeleterSlice)
{
MockSlice p("Hello");
EXPECT_TRUE(p.bytes_ != NULL);
if (true) {
SrsUniquePtr<MockSlice> ptr(&p, MockSlice::deleter);
}
EXPECT_TRUE(p.bytes_ == NULL);
}
class MockSpecialPacket
{
public:
char* bytes_;
int size_;
public:
MockSpecialPacket(char* bytes, int size) {
bytes_ = bytes;
size_ = size;
}
virtual ~MockSpecialPacket() {
srs_freep(bytes_);
}
public:
static void deleter(vector<MockSpecialPacket*>* pkts) {
vector<MockSpecialPacket*>::iterator it;
for (it = pkts->begin(); it != pkts->end(); ++it) {
MockSpecialPacket* pkt = *it;
srs_freep(pkt);
}
pkts->clear();
}
};
VOID TEST(CoreSmartPtr, UniquePtrDeleterVector)
{
vector<MockSpecialPacket*> pkts;
for (int i = 0; i < 10; i++) {
char* bytes = new char[1024];
MockSpecialPacket* pkt = new MockSpecialPacket(bytes, 1024);
pkts.push_back(pkt);
}
EXPECT_EQ(10, (int)pkts.size());
if (true) {
SrsUniquePtr<vector<MockSpecialPacket*>> ptr(&pkts, MockSpecialPacket::deleter);
}
EXPECT_EQ(0, (int)pkts.size());
}
class MockMalloc
{
public:
const char* bytes_;
public:
MockMalloc(int size) {
bytes_ = (char*)malloc(size);
}
virtual ~MockMalloc() {
}
public:
static void deleter(MockMalloc* p) {
free((void*)p->bytes_);
p->bytes_ = NULL;
}
};
VOID TEST(CoreSmartPtr, UniquePtrDeleterMalloc)
{
MockMalloc p(1024);
EXPECT_TRUE(p.bytes_ != NULL);
if (true) {
SrsUniquePtr<MockMalloc> ptr(&p, MockMalloc::deleter);
}
EXPECT_TRUE(p.bytes_ == NULL);
}

View File

@ -626,7 +626,7 @@ VOID TEST(ProtocolMsgArrayTest, MessageArray)
SrsMessageArray arr(3);
SrsMessageArray* parr = &arr;
SrsAutoFreeH(SrsMessageArray, parr, srs_utest_free_message_array);
SrsUniquePtr<SrsMessageArray> parr2(parr, srs_utest_free_message_array);
arr.msgs[0] = msg.copy();
EXPECT_EQ(1, msg.count());
@ -643,7 +643,7 @@ VOID TEST(ProtocolMsgArrayTest, MessageArray)
SrsMessageArray arr(3);
SrsMessageArray* parr = &arr;
SrsAutoFreeH(SrsMessageArray, parr, srs_utest_free_message_array);
SrsUniquePtr<SrsMessageArray> parr2(parr, srs_utest_free_message_array);
arr.msgs[0] = msg.copy();
EXPECT_EQ(1, msg.count());

View File

@ -2999,7 +2999,7 @@ VOID TEST(ProtocolRTMPTest, OthersAll)
SrsMessageArray h(10);
SrsMessageArray* parr = &h;
SrsAutoFreeH(SrsMessageArray, parr, srs_utest_free_message_array);
SrsUniquePtr<SrsMessageArray> parr2(parr, srs_utest_free_message_array);
h.msgs[0] = new SrsSharedPtrMessage();
h.msgs[1] = new SrsSharedPtrMessage();

View File

@ -1118,9 +1118,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("127.0.0.1", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("127.0.0.1", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
@ -1131,9 +1131,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("192.168.0.1", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("192.168.0.1", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
@ -1176,9 +1176,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("2001:da8:6000:291:21f:d0ff:fed4:928c", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("2001:da8:6000:291:21f:d0ff:fed4:928c", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_TRUE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
@ -1187,9 +1187,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("3ffe:dead:beef::1", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("3ffe:dead:beef::1", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_TRUE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
@ -1200,9 +1200,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("::", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("::", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
@ -1213,9 +1213,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("fec0::", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("fec0::", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
@ -1226,9 +1226,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("FE80::", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("FE80::", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}
@ -1239,9 +1239,9 @@ VOID TEST(TCPServerTest, CoverUtility)
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
addrinfo* r = NULL;
SrsAutoFreeH(addrinfo, r, freeaddrinfo);
ASSERT_TRUE(!getaddrinfo("::1", NULL, &hints, &r));
addrinfo* r_raw = NULL;
ASSERT_TRUE(!getaddrinfo("::1", NULL, &hints, &r_raw));
SrsUniquePtr<addrinfo> r(r_raw, freeaddrinfo);
EXPECT_FALSE(srs_net_device_is_internet((sockaddr*)r->ai_addr));
}

View File

@ -111,7 +111,7 @@ VOID TEST(StTest, StUtimePerformance)
EXPECT_LT(gettimeofday_elapsed_time > st_utime_elapsed_time ?
gettimeofday_elapsed_time - st_utime_elapsed_time :
st_utime_elapsed_time - gettimeofday_elapsed_time, 10);
st_utime_elapsed_time - gettimeofday_elapsed_time, 30);
}
}