Commit 428ffdb4 authored by Guillaume Roguez's avatar Guillaume Roguez
Browse files

sip: fix SipTransport class

- use a std::unique_ptr to handle the PJSIP transport (exception-proof).
  Deleter calls pjsip_transport_shutdown() then pjsip_transport_dec_ref().
- prevent a valid construction with invalid PJSIP transport.
- use insert than map [] operator to not cause extra memory allocations.
- minor: postfix private class member with an underscore.
- minor: using-aliases prefered than typedef.
- minor: code indentation fixes.

Refs #64903

Change-Id: I1e78d119ca7291928d5148344be5c0258ca2c02e
parent 2c6b0379
......@@ -72,24 +72,42 @@ SipTransportDescr::toString() const
return ss.str();
}
SipTransport::SipTransport(pjsip_transport* t, const std::shared_ptr<TlsListener>& l) :
transport(t), tlsListener(l)
void
SipTransport::deleteTransport(pjsip_transport* t)
{
pjsip_transport_shutdown(t);
pjsip_transport_dec_ref(t);
}
SipTransport::SipTransport(pjsip_transport* t)
: transport_(nullptr, deleteTransport)
{
if (not t or pjsip_transport_add_ref(t) != PJ_SUCCESS)
throw std::runtime_error("invalid transport");
// Set pointer here, right after the successful pjsip_transport_add_ref
transport_.reset(t);
RING_DBG("SipTransport@%p {tr=%p {rc=%u}}",
this, transport_.get(), pj_atomic_get(transport_->ref_cnt));
}
SipTransport::SipTransport(pjsip_transport* t,
const std::shared_ptr<TlsListener>& l)
: SipTransport(t)
{
pjsip_transport_add_ref(transport);
tlsListener_ = l;
}
SipTransport::~SipTransport()
{
if (transport) {
pjsip_transport_shutdown(transport);
pjsip_transport_dec_ref(transport); // ??
RING_DBG("Destroying transport (refcount: %u)", pj_atomic_get(transport->ref_cnt));
transport = nullptr;
}
RING_DBG("~SipTransport@%p {tr=%p {rc=%u}}",
this, transport_.get(), pj_atomic_get(transport_->ref_cnt));
}
bool
SipTransport::isAlive(UNUSED const std::shared_ptr<SipTransport>& t, pjsip_transport_state state)
SipTransport::isAlive(UNUSED const std::shared_ptr<SipTransport>& t,
pjsip_transport_state state)
{
return state != PJSIP_TP_STATE_DISCONNECTED
#if PJ_VERSION_NUM > (2 << 24 | 1 << 16)
......@@ -110,13 +128,14 @@ SipTransport::stateToStr(pjsip_transport_state state)
}
void
SipTransport::stateCallback(pjsip_transport_state state, const pjsip_transport_state_info *info)
SipTransport::stateCallback(pjsip_transport_state state,
const pjsip_transport_state_info *info)
{
std::vector<SipTransportStateCallback> cbs {};
std::vector<SipTransportStateCallback> cbs;
{
std::lock_guard<std::mutex> lock(stateListenersMutex_);
cbs.reserve(stateListeners.size());
for (auto& l : stateListeners)
cbs.reserve(stateListeners_.size());
for (auto& l : stateListeners_)
cbs.push_back(l.second);
}
for (auto& cb : cbs)
......@@ -127,16 +146,18 @@ void
SipTransport::addStateListener(uintptr_t lid, SipTransportStateCallback cb)
{
std::lock_guard<std::mutex> lock(stateListenersMutex_);
stateListeners[lid] = cb;
auto pair = stateListeners_.insert(std::make_pair(lid, cb));
if (not pair.second)
pair.first->second = cb;
}
bool
SipTransport::removeStateListener(uintptr_t lid)
{
std::lock_guard<std::mutex> lock(stateListenersMutex_);
auto it = stateListeners.find(lid);
if (it != stateListeners.end()) {
stateListeners.erase(it);
auto it = stateListeners_.find(lid);
if (it != stateListeners_.end()) {
stateListeners_.erase(it);
return true;
}
return false;
......
......@@ -103,37 +103,41 @@ private:
pjsip_tpfactory* listener {nullptr};
};
typedef std::function<void(pjsip_transport_state, const pjsip_transport_state_info*)> SipTransportStateCallback;
using SipTransportStateCallback = std::function<void(pjsip_transport_state, const pjsip_transport_state_info*)>;
/**
* SIP transport wraps pjsip_transport.
*/
struct SipTransport
class SipTransport
{
SipTransport() {}
SipTransport(pjsip_transport*, const std::shared_ptr<TlsListener>& l = {});
public:
SipTransport(pjsip_transport*);
SipTransport(pjsip_transport*, const std::shared_ptr<TlsListener>&);
virtual ~SipTransport();
~SipTransport();
static const char* stateToStr(pjsip_transport_state state);
static const char* stateToStr(pjsip_transport_state state);
void stateCallback(pjsip_transport_state state, const pjsip_transport_state_info *info);
void stateCallback(pjsip_transport_state state, const pjsip_transport_state_info *info);
pjsip_transport* get() {
return transport;
}
pjsip_transport* get() {
return transport_.get();
}
void addStateListener(uintptr_t lid, SipTransportStateCallback cb);
bool removeStateListener(uintptr_t lid);
void addStateListener(uintptr_t lid, SipTransportStateCallback cb);
bool removeStateListener(uintptr_t lid);
static bool isAlive(const std::shared_ptr<SipTransport>&, pjsip_transport_state state);
static bool isAlive(const std::shared_ptr<SipTransport>&, pjsip_transport_state state);
private:
NON_COPYABLE(SipTransport);
pjsip_transport* transport {nullptr};
std::shared_ptr<TlsListener> tlsListener {};
std::map<uintptr_t, SipTransportStateCallback> stateListeners {};
std::mutex stateListenersMutex_ {};
private:
NON_COPYABLE(SipTransport);
static void deleteTransport(pjsip_transport* t);
std::unique_ptr<pjsip_transport, decltype(deleteTransport)&> transport_;
std::shared_ptr<TlsListener> tlsListener_;
std::map<uintptr_t, SipTransportStateCallback> stateListeners_;
std::mutex stateListenersMutex_;
};
class IpAddr;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment