SIP - prevent race condition when writing contact header

The contact header field was stored in a member varialbe of Jami/SIP
accounts. There was a condition in which the contact header could
be concurrently accessed by multiple threads. This typically happens
when terminating calls in batch (when calling hangupCalls() for
instance).
Managment of SIP contact header in Jami and SIP accounts was
reworked to prevent such race.

Gitlab: #633

Change-Id: Ib9295070a5295969bf114ec29e66e36b1c5c5e03
This commit is contained in:
Mohamed Chibani
2021-10-12 15:14:31 -04:00
parent 1cff5df877
commit 0ae5d6681f
13 changed files with 151 additions and 160 deletions

View File

@ -430,11 +430,8 @@ Call::onTextMessage(std::map<std::string, std::string>&& messages)
#ifdef ENABLE_PLUGIN
auto& pluginChatManager = Manager::instance().getJamiPluginManager().getChatServicesManager();
if (pluginChatManager.hasHandlers()) {
pluginChatManager.publishMessage(std::make_shared<JamiMessage>(getAccountId(),
getPeerNumber(),
true,
messages,
false));
pluginChatManager.publishMessage(
std::make_shared<JamiMessage>(getAccountId(), getPeerNumber(), true, messages, false));
}
#endif
Manager::instance().incomingMessage(getCallId(), getPeerNumber(), messages);
@ -474,8 +471,9 @@ Call::addSubCall(Call& subcall)
subcall.sendTextMessage(msg.first, msg.second);
subcall.addStateListener(
[sub = subcall.weak(),
parent = weak()](Call::CallState new_state, Call::ConnectionState new_cstate, int code) {
[sub = subcall.weak(), parent = weak()](Call::CallState new_state,
Call::ConnectionState new_cstate,
int /* code */) {
runOnMainThread([sub, parent, new_state, new_cstate]() {
if (auto p = parent.lock()) {
if (auto s = sub.lock()) {

View File

@ -794,19 +794,14 @@ JamiAccount::SIPStartCall(SIPCall& call, const IpAddr& target)
std::string targetStr = getToUri(target.toString(true));
pj_str_t pjTarget = sip_utils::CONST_PJ_STR(targetStr);
pj_str_t pjContact;
{
auto transport = call.getTransport();
pjContact = getContactHeader(transport ? transport->get() : nullptr);
}
auto contact = getContactHeader(call.getTransport());
auto pjContact = sip_utils::CONST_PJ_STR(contact);
JAMI_DBG("contact header: %.*s / %s -> %s / %.*s",
(int) pjContact.slen,
pjContact.ptr,
JAMI_DBG("contact header: %s / %s -> %s / %s",
contact.c_str(),
from.c_str(),
toUri.c_str(),
(int) pjTarget.slen,
pjTarget.ptr);
targetStr.c_str());
auto local_sdp = call.getSDP().getLocalSdpSession();
pjsip_dialog* dialog {nullptr};
@ -3058,32 +3053,26 @@ JamiAccount::setMessageDisplayed(const std::string& conversationUri,
return true;
}
pj_str_t
JamiAccount::getContactHeader(pjsip_transport* t)
std::string
JamiAccount::getContactHeader(SipTransport* sipTransport)
{
std::string quotedDisplayName = "\"" + displayName_ + "\" " + (displayName_.empty() ? "" : " ");
if (t) {
auto* td = reinterpret_cast<tls::AbstractSIPTransport::TransportData*>(t);
auto address = td->self->getLocalAddress().toString(true);
bool reliable = t->flag & PJSIP_TRANSPORT_RELIABLE;
std::ostringstream contact;
contact_.slen = pj_ansi_snprintf(contact_.ptr,
PJSIP_MAX_URL_SIZE,
"%s<sips:%s%s%s;transport=%s>",
quotedDisplayName.c_str(),
id_.second->getId().toString().c_str(),
(address.empty() ? "" : "@"),
address.c_str(),
reliable ? "tls" : "dtls");
if (auto transport = sipTransport->get()) {
auto* td = reinterpret_cast<tls::AbstractSIPTransport::TransportData*>(transport);
auto address = td->self->getLocalAddress().toString(true);
bool reliable = transport->flag & PJSIP_TRANSPORT_RELIABLE;
contact << quotedDisplayName << "<sips:" << id_.second->getId().toString()
<< (address.empty() ? "" : "@") << address
<< (reliable ? ";transport=tls>" : ";transport=dtls");
} else {
JAMI_ERR("getContactHeader: no SIP transport provided");
contact_.slen = pj_ansi_snprintf(contact_.ptr,
PJSIP_MAX_URL_SIZE,
"%s<sips:%s@ring.dht>",
quotedDisplayName.c_str(),
id_.second->getId().toString().c_str());
contact << quotedDisplayName << "<sips:" << id_.second->getId().toString() << "@ring.dht>";
}
return contact_;
return contact.str();
}
/* contacts */

View File

@ -251,9 +251,9 @@ public:
/**
* Get the contact header for
* @return pj_str_t The contact header based on account information
* @return The contact header based on account information
*/
pj_str_t getContactHeader(pjsip_transport* = nullptr) override;
std::string getContactHeader(SipTransport* transport = nullptr) override;
/* Returns true if the username and/or hostname match this account */
MatchRank matches(std::string_view username, std::string_view hostname) const override;
@ -804,8 +804,6 @@ private:
*/
pjsip_host_port via_addr_ {};
char contactBuffer_[PJSIP_MAX_URL_SIZE] {};
pj_str_t contact_ {contactBuffer_, 0};
pjsip_transport* via_tp_ {nullptr};
std::unique_ptr<DhtPeerConnector> dhtPeerConnector_;

View File

@ -50,7 +50,7 @@ SyncChannelHandler::connect(const DeviceId& deviceId, const std::string&, Connec
}
bool
SyncChannelHandler::onRequest(const DeviceId& deviceId, const std::string& name)
SyncChannelHandler::onRequest(const DeviceId& deviceId, const std::string& /* name */)
{
auto cert = tls::CertificateStore::instance().getCertificate(deviceId.toString());
auto acc = account_.lock();

View File

@ -174,12 +174,17 @@ getHostFromUri(std::string_view uri)
}
void
addContactHeader(pj_str_t contact_str, pjsip_tx_data* tdata)
addContactHeader(const std::string& contactHdr, pjsip_tx_data* tdata)
{
if (contactHdr.empty()) {
JAMI_WARN("Contact header won't be added (empty string)");
return;
}
auto pjContact = sip_utils::CONST_PJ_STR(contactHdr);
pjsip_contact_hdr* contact = pjsip_contact_hdr_create(tdata->pool);
contact->uri = pjsip_parse_uri(tdata->pool,
contact_str.ptr,
contact_str.slen,
pjContact.ptr,
pjContact.slen,
PJSIP_PARSE_URI_AS_NAMEADDR);
// remove old contact header (if present)
pjsip_msg_find_remove_hdr(tdata->msg, PJSIP_H_CONTACT, NULL);
@ -189,7 +194,7 @@ addContactHeader(pj_str_t contact_str, pjsip_tx_data* tdata)
void
addUserAgentHeader(const std::string& userAgent, pjsip_tx_data* tdata)
{
if (tdata == nullptr)
if (tdata == nullptr or userAgent.empty())
return;
auto pjUserAgent = CONST_PJ_STR(userAgent);
@ -224,8 +229,8 @@ getPeerUserAgent(const pjsip_rx_data* rdata)
constexpr auto USER_AGENT_STR = CONST_PJ_STR("User-Agent");
if (auto uaHdr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
&USER_AGENT_STR,
nullptr)) {
&USER_AGENT_STR,
nullptr)) {
return as_view(uaHdr->hvalue);
}
return {};

View File

@ -96,7 +96,7 @@ std::string parseDisplayName(const pjsip_contact_hdr* header);
std::string_view getHostFromUri(std::string_view sipUri);
void addContactHeader(pj_str_t contactStr, pjsip_tx_data* tdata);
void addContactHeader(const std::string& contact, pjsip_tx_data* tdata);
void addUserAgentHeader(const std::string& userAgent, pjsip_tx_data* tdata);
std::string_view getPeerUserAgent(const pjsip_rx_data* rdata);
void logMessageHeaders(const pjsip_hdr* hdr_list);

View File

@ -146,8 +146,6 @@ SIPAccount::SIPAccount(const std::string& accountID, bool presenceEnabled)
, receivedParameter_("")
, rPort_(-1)
, via_addr_()
, contactBuffer_()
, contact_ {contactBuffer_, 0}
, contactRewriteMethod_(2)
, allowIPAutoRewrite_(true)
, contactOverwritten_(false)
@ -451,13 +449,10 @@ SIPAccount::SIPStartCall(std::shared_ptr<SIPCall>& call)
return false;
}
pj_str_t pjContact = getContactHeader(transport->get());
JAMI_DBG("contact header: %.*s / %s -> %s",
(int) pjContact.slen,
pjContact.ptr,
from.c_str(),
toUri.c_str());
std::string contact = getContactHeader(transport);
JAMI_DBG("contact header: %s / %s -> %s", contact.c_str(), from.c_str(), toUri.c_str());
pj_str_t pjContact = sip_utils::CONST_PJ_STR(contact);
auto local_sdp = isEmptyOffersEnabled() ? nullptr : call->getSDP().getLocalSdpSession();
pjsip_dialog* dialog {nullptr};
@ -881,8 +876,7 @@ SIPAccount::setPushNotificationToken(const std::string& pushDeviceToken)
return;
deviceKey_ = pushDeviceToken;
pj_bzero(contact_.ptr, sizeof(contact_));
contact_.slen = 0;
contact_.clear();
if (enabled_)
doUnregister([&](bool /* transport_free */) { doRegister(); });
@ -890,7 +884,7 @@ SIPAccount::setPushNotificationToken(const std::string& pushDeviceToken)
void
SIPAccount::pushNotificationReceived(const std::string& from,
const std::map<std::string, std::string>& data)
const std::map<std::string, std::string>&)
{
JAMI_WARN("[SIP Account %s] pushNotificationReceived: %s", getAccountID().c_str(), from.c_str());
@ -1099,7 +1093,8 @@ SIPAccount::sendRegister()
const std::string& received(getReceivedParameter());
// Get the contact header
const pj_str_t pjContact(getContactHeader());
std::string contact = getContactHeader();
pj_str_t pjContact = sip_utils::CONST_PJ_STR(contact);
JAMI_DBG("Using contact header %.*s in registration", (int) pjContact.slen, pjContact.ptr);
@ -1568,17 +1563,17 @@ SIPAccount::getServerUri() const
return "<" + scheme + host + transport + ">";
}
pj_str_t
SIPAccount::getContactHeader(pjsip_transport* t)
std::string
SIPAccount::getContactHeader(SipTransport* sipTransport)
{
if (contact_.slen and contactOverwritten_)
if (not contact_.empty() and contactOverwritten_)
return contact_;
if (!t && transport_)
t = transport_->get();
if (!t) {
if (not sipTransport && transport_)
sipTransport = transport_.get();
if (not sipTransport) {
JAMI_ERR("Transport not created yet");
return {nullptr, 0};
return {};
}
// The transport type must be specified, in our case START_OTHER refers to stun transport
@ -1591,7 +1586,7 @@ SIPAccount::getContactHeader(pjsip_transport* t)
std::string address;
pj_uint16_t port;
link_.findLocalAddressFromTransport(t, transportType, hostname_, address, port);
link_.findLocalAddressFromTransport(sipTransport->get(), transportType, hostname_, address, port);
if (getUPnPActive() and getUPnPIpAddress()) {
address = getUPnPIpAddress().toString();
@ -1603,7 +1598,11 @@ SIPAccount::getContactHeader(pjsip_transport* t)
port = publishedPort_;
JAMI_DBG("Using published address %s and port %d", address.c_str(), port);
} else if (stunEnabled_) {
auto success = link_.findLocalAddressFromSTUN(t, &stunServerName_, stunPort_, address, port);
auto success = link_.findLocalAddressFromSTUN(sipTransport->get(),
&stunServerName_,
stunPort_,
address,
port);
if (not success)
emitSignal<DRing::ConfigurationSignal::StunStatusFailed>(getAccountID());
setPublishedAddress({address});
@ -1628,55 +1627,48 @@ SIPAccount::getContactHeader(pjsip_transport* t)
const char* scheme = "sip";
const char* transport = "";
if (PJSIP_TRANSPORT_IS_SECURE(t)) {
if (PJSIP_TRANSPORT_IS_SECURE(sipTransport->get())) {
scheme = "sips";
transport = ";transport=tls";
}
std::string quotedDisplayName = displayName_.empty() ? "" : "\"" + displayName_ + "\" ";
contact_.slen
= printContactHeader(contact_.ptr, quotedDisplayName, scheme, address, port, transport);
contact_ = printContactHeader(quotedDisplayName, scheme, address, port, transport);
return contact_;
}
int
SIPAccount::printContactHeader(char* data,
const std::string& displayName,
std::string
SIPAccount::printContactHeader(const std::string& displayName,
const char* scheme,
const std::string& address,
pj_uint16_t port,
const char* transport)
{
if (deviceKey_.empty()) {
return pj_ansi_snprintf(data,
PJSIP_MAX_URL_SIZE,
CONTACT_HEADER_WITHOUT_PN,
displayName.c_str(),
scheme,
username_.c_str(),
(username_.empty() ? "" : "@"),
address.c_str(),
port,
transport);
} else {
return pj_ansi_snprintf(data,
PJSIP_MAX_URL_SIZE,
CONTACT_HEADER_WITH_PN,
displayName.c_str(),
scheme,
username_.c_str(),
(username_.empty() ? "" : "@"),
address.c_str(),
port,
transport,
// This method generates SIP contact header field, with push
// notification parameters if any.
// Example without push notification:
// John Doe<sips:jdoe@10.10.10.10:5060;transport=tls>
// Example with push notification:
// John Doe<sips:jdoe@10.10.10.10:5060;transport=tls;pn-provider=XXX;pn-param=YYY;pn-prid=ZZZ>
std::ostringstream contact;
contact << displayName << "<" << scheme << ":" << username_ << (username_.empty() ? "" : "@")
<< address << ":" << port << transport;
if (not deviceKey_.empty()) {
contact
#if defined(__ANDROID__) || defined(ANDROID)
PN_FCM,
<< "pn-provider=" << PN_FCM
#elif defined(__Apple__)
PN_APNS,
<< "pn-provider=" << PN_APNS
#endif
"",
deviceKey_.c_str());
<< "pn-param=;"
<< "pn-prid=" << deviceKey_;
}
contact << ">";
return contact.str();
}
pjsip_host_port
@ -2007,9 +1999,10 @@ SIPAccount::checkNATAddress(pjsip_regc_cbparam* param, pj_pool_t* pool)
setPublishedAddress(IpAddr(via_addrstr));
/* Compare received and rport with the URI in our registration */
auto pjContact = sip_utils::CONST_PJ_STR(getContactHeader());
const pj_str_t STR_CONTACT = {(char*) "Contact", 7};
pjsip_contact_hdr* contact_hdr = (pjsip_contact_hdr*)
pjsip_parse_hdr(pool, &STR_CONTACT, contact_.ptr, contact_.slen, nullptr);
pjsip_parse_hdr(pool, &STR_CONTACT, pjContact.ptr, pjContact.slen, nullptr);
pj_assert(contact_hdr != nullptr);
pjsip_sip_uri* uri = (pjsip_sip_uri*) contact_hdr->uri;
pj_assert(uri != nullptr);
@ -2106,21 +2099,21 @@ SIPAccount::checkNATAddress(pjsip_regc_cbparam* param, pj_pool_t* pool)
transport_param = ";transport=tls";
}
char* tmp = (char*) pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
int len = printContactHeader(tmp, "", scheme, via_addrstr, rport, transport_param);
auto tmp = printContactHeader("", scheme, via_addrstr, rport, transport_param);
if (len < 1) {
JAMI_ERR("URI too long");
if (tmp.empty()) {
JAMI_ERR("Invalid contact header");
return false;
}
pj_str_t tmp_str = {tmp, len};
pj_strncpy_with_null(&contact_, &tmp_str, PJSIP_MAX_URL_SIZE);
// Update
contact_ = std::move(tmp);
pjContact = sip_utils::CONST_PJ_STR(contact_);
}
if (contactRewriteMethod_ == 2 && regc_ != nullptr) {
contactOverwritten_ = true;
pjsip_regc_update_contact(regc_, 1, &contact_);
pjsip_regc_update_contact(regc_, 1, &pjContact);
/* Perform new registration at the next registration cycle */
}

View File

@ -69,9 +69,6 @@ class SIPAccount : public SIPAccountBase
{
public:
constexpr static const char* const ACCOUNT_TYPE = "SIP";
constexpr static const char* const CONTACT_HEADER_WITH_PN
= "%s<%s:%s%s%s:%d%s;pn-provider=%s;pn-param=%s;pn-prid=%s>";
constexpr static const char* const CONTACT_HEADER_WITHOUT_PN = "%s<%s:%s%s%s:%d%s>";
constexpr static const char* const PN_FCM = "fcm";
constexpr static const char* const PN_APNS = "apns";
@ -348,9 +345,9 @@ public:
/**
* Get the contact header for
* @return pj_str_t The contact header based on account information
* @return The contact header based on account information
*/
pj_str_t getContactHeader(pjsip_transport* = nullptr) override;
std::string getContactHeader(SipTransport* transport = nullptr) override;
std::string getServiceRoute() const { return serviceRoute_; }
@ -613,12 +610,11 @@ private:
/**
* Print contact header in certain format
*/
int printContactHeader(char* data,
const std::string& displayName,
const char* scheme,
const std::string& address,
pj_uint16_t port,
const char* transport);
std::string printContactHeader(const std::string& displayName,
const char* scheme,
const std::string& address,
pj_uint16_t port,
const char* transport);
/**
* Resolved IP of hostname_ (for registration)
@ -750,8 +746,7 @@ private:
*/
std::string upnpIpAddr_;
char contactBuffer_[PJSIP_MAX_URL_SIZE];
pj_str_t contact_;
std::string contact_;
int contactRewriteMethod_;
bool allowIPAutoRewrite_;
/* Undocumented feature in pjsip, this can == 2 */

View File

@ -458,7 +458,7 @@ SIPAccountBase::getIceOptions() const noexcept
void
SIPAccountBase::onTextMessage(const std::string& id,
const std::string& from,
const std::string& deviceId,
const std::string& /* deviceId */,
const std::map<std::string, std::string>& payloads)
{
JAMI_DBG("Text message received from %s, %zu part(s)", from.c_str(), payloads.size());
@ -476,7 +476,8 @@ SIPAccountBase::onTextMessage(const std::string& id,
#ifdef ENABLE_PLUGIN
auto& pluginChatManager = Manager::instance().getJamiPluginManager().getChatServicesManager();
if (pluginChatManager.hasHandlers()) {
pluginChatManager.publishMessage(std::make_shared<JamiMessage>(accountID_, from, true, payloads, false));
pluginChatManager.publishMessage(
std::make_shared<JamiMessage>(accountID_, from, true, payloads, false));
}
#endif
emitSignal<DRing::ConfigurationSignal::IncomingAccountMessage>(accountID_, from, id, payloads);

View File

@ -216,9 +216,9 @@ public:
/**
* Get the contact header for
* @return pj_str_t The contact header based on account information
* @return The contact header based on account information
*/
virtual pj_str_t getContactHeader(pjsip_transport* = nullptr) = 0;
virtual std::string getContactHeader(SipTransport* transport = nullptr) = 0;
virtual std::string getToUri(const std::string& username) const = 0;

View File

@ -420,9 +420,15 @@ SIPCall::generateMediaPorts()
}
void
SIPCall::setContactHeader(pj_str_t contact)
SIPCall::setContactHeader(const std::string& contact)
{
pj_strcpy(&contactHeader_, &contact);
contactHeader_ = contact;
}
const std::string&
SIPCall::getContactHeader() const
{
return contactHeader_;
}
void
@ -437,6 +443,12 @@ SIPCall::setTransport(const std::shared_ptr<SipTransport>& t)
if (not t) {
return;
}
auto account = getSIPAccount();
if (not account) {
JAMI_ERR("[call:%s] No account detected", getCallId().c_str());
}
setContactHeader(account->getContactHeader(transport_.get()));
if (isSrtpEnabled() and not transport_->isSecure()) {
JAMI_WARN("[call:%s] Crypto (SRTP) is negotiated over an un-encrypted signaling channel",
@ -701,9 +713,7 @@ SIPCall::terminateSipSession(int status)
if (tdata) {
auto account = getSIPAccount();
if (account) {
sip_utils::addContactHeader(account->getContactHeader(
transport_ ? transport_->get() : nullptr),
tdata);
sip_utils::addContactHeader(contactHeader_, tdata);
// Add user-agent header
sip_utils::addUserAgentHeader(account->getUserAgentName(), tdata);
} else {
@ -750,8 +760,6 @@ SIPCall::answer()
Manager::instance().sipVoIPLink().createSDPOffer(inviteSession_.get());
}
setContactHeader(account->getContactHeader(transport_ ? transport_->get() : nullptr));
pjsip_tx_data* tdata;
if (!inviteSession_->last_answer)
throw std::runtime_error("Should only be called for initial answer");
@ -765,15 +773,16 @@ SIPCall::answer()
!= PJ_SUCCESS)
throw std::runtime_error("Could not init invite request answer (200 OK)");
// contactStr must stay in scope as long as tdata
if (contactHeader_.slen) {
JAMI_DBG("[call:%s] Answering with contact header: %.*s",
getCallId().c_str(),
(int) contactHeader_.slen,
contactHeader_.ptr);
sip_utils::addContactHeader(contactHeader_, tdata);
if (contactHeader_.empty()) {
throw std::runtime_error("Cant answer with an invalid contact header");
}
JAMI_DBG("[call:%s] Answering with contact header: %s",
getCallId().c_str(),
contactHeader_.c_str());
sip_utils::addContactHeader(contactHeader_, tdata);
// Add user-agent header
sip_utils::addUserAgentHeader(account->getUserAgentName(), tdata);
@ -879,8 +888,6 @@ SIPCall::answer(const std::vector<DRing::MediaMap>& mediaList)
}
}
setContactHeader(account->getContactHeader(transport_ ? transport_->get() : nullptr));
if (!inviteSession_->last_answer)
throw std::runtime_error("Should only be called for initial answer");
@ -896,14 +903,16 @@ SIPCall::answer(const std::vector<DRing::MediaMap>& mediaList)
!= PJ_SUCCESS)
throw std::runtime_error("Could not init invite request answer (200 OK)");
if (contactHeader_.slen) {
JAMI_DBG("[call:%s] Answering with contact header: %.*s",
getCallId().c_str(),
(int) contactHeader_.slen,
contactHeader_.ptr);
sip_utils::addContactHeader(contactHeader_, tdata);
if (contactHeader_.empty()) {
throw std::runtime_error("Cant answer with an invalid contact header");
}
JAMI_DBG("[call:%s] Answering with contact header: %s",
getCallId().c_str(),
contactHeader_.c_str());
sip_utils::addContactHeader(contactHeader_, tdata);
// Add user-agent header
sip_utils::addUserAgentHeader(account->getUserAgentName(), tdata);
@ -990,7 +999,7 @@ SIPCall::answerMediaChangeRequest(const std::vector<DRing::MediaMap>& mediaList)
return;
}
if (contactHeader_.slen) {
if (not contactHeader_.empty()) {
sip_utils::addContactHeader(contactHeader_, tdata);
}
@ -2501,7 +2510,7 @@ SIPCall::onReceiveOffer(const pjmedia_sdp_session* offer, const pjsip_rx_data* r
NULL,
&tdata)
!= PJ_SUCCESS) {
JAMI_ERR("Could not create initial answer OK");
JAMI_ERR("[call:%s] Could not create initial answer OK", getCallId().c_str());
return !PJ_SUCCESS;
}
@ -2514,11 +2523,15 @@ SIPCall::onReceiveOffer(const pjmedia_sdp_session* offer, const pjsip_rx_data* r
return !PJ_SUCCESS;
}
// ContactStr must stay in scope as long as tdata
sip_utils::addContactHeader(getSIPAccount()->getContactHeader(getTransport()->get()), tdata);
if (contactHeader_.empty()) {
JAMI_ERR("[call:%s] Contact header is empty!", getCallId().c_str());
return !PJ_SUCCESS;
}
sip_utils::addContactHeader(contactHeader_, tdata);
if (pjsip_inv_send_msg(inviteSession_.get(), tdata) != PJ_SUCCESS) {
JAMI_ERR("Could not send msg OK");
JAMI_ERR("[call:%s] Could not send msg OK", getCallId().c_str());
return !PJ_SUCCESS;
}
@ -3029,8 +3042,7 @@ SIPCall::merge(Call& call)
sdp_ = std::move(subcall.sdp_);
peerHolding_ = subcall.peerHolding_;
upnp_ = std::move(subcall.upnp_);
std::copy_n(subcall.contactBuffer_, PJSIP_MAX_URL_SIZE, contactBuffer_);
pj_strcpy(&contactHeader_, &subcall.contactHeader_);
contactHeader_ = std::move(subcall.contactHeader_);
localAudioPort_ = subcall.localAudioPort_;
localVideoPort_ = subcall.localVideoPort_;
peerUserAgent_ = subcall.peerUserAgent_;

View File

@ -219,7 +219,8 @@ public:
void onMediaNegotiationComplete();
// End fo SiPVoipLink events
void setContactHeader(pj_str_t contact);
void setContactHeader(const std::string& contact);
const std::string& getContactHeader() const;
void setTransport(const std::shared_ptr<SipTransport>& t);
@ -432,8 +433,7 @@ private:
std::string peerRegisteredName_ {};
char contactBuffer_[PJSIP_MAX_URL_SIZE] {};
pj_str_t contactHeader_ {contactBuffer_, 0};
std::string contactHeader_ {};
std::shared_ptr<jami::upnp::Controller> upnp_;

View File

@ -560,7 +560,7 @@ transaction_request_cb(pjsip_rx_data* rdata)
return PJ_FALSE;
}
sip_utils::addContactHeader(account->getContactHeader(transport->get()), tdata);
sip_utils::addContactHeader(call->getContactHeader(), tdata);
if (pjsip_inv_send_msg(call->inviteSession_.get(), tdata) != PJ_SUCCESS) {
JAMI_ERR("Could not send msg RINGING");
return PJ_FALSE;