mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-07 22:02:12 +08:00
multi-stream: check peer's Daemon version
Check peer's Daemon version and ignore media change request action from the client if the the peer does not support the feature. Also bump Daemon version to 10.0.2 Gitlab: #551 Change-Id: Ifd105d2fe2706b4667f5bafabcb3d91e771e7299
This commit is contained in:

committed by
agsantos

parent
8f7e050f12
commit
53d0ae39d1
@ -1026,7 +1026,15 @@
|
||||
<p>Report mediation negotation status.</p>
|
||||
</tp:docstring>
|
||||
<arg type="s" name="callID" />
|
||||
<arg type="s" name="event" />
|
||||
<arg type="s" name="event" >
|
||||
<tp:docstring>
|
||||
The acceptable states are:
|
||||
<ul>
|
||||
<li>NEGOTIATION_SUCCESS: Medias are ready</li>
|
||||
<li>NEGOTIATION_FAIL: Medias negotion failed</li>
|
||||
</ul>
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</signal>
|
||||
</interface>
|
||||
</node>
|
||||
|
@ -152,10 +152,10 @@ systems. This function is required for `alloca.c' support on those systems.
|
||||
#define PACKAGE_BUGREPORT "jami@lists.savoirfairelinux.net"
|
||||
|
||||
/* Define to the full name of this package. */
|
||||
#define PACKAGE_NAME "Jami"
|
||||
#define PACKAGE_NAME "Jami Daemon"
|
||||
|
||||
/* Define to the full name and version of this package. */
|
||||
#define PACKAGE_STRING "Jami"
|
||||
#define PACKAGE_STRING "Jami Daemon 10.0.2"
|
||||
|
||||
/* Define to the one symbol short name of this package. */
|
||||
#define PACKAGE_TARNAME "jami"
|
||||
@ -164,7 +164,7 @@ systems. This function is required for `alloca.c' support on those systems.
|
||||
#define PACKAGE_URL ""
|
||||
|
||||
/* Define to the version of this package. */
|
||||
#define PACKAGE_VERSION "2.3.0"
|
||||
#define PACKAGE_VERSION "10.0.2"
|
||||
|
||||
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||
your system. */
|
||||
@ -201,7 +201,7 @@ STACK_DIRECTION = 0 => direction of growth unknown */
|
||||
#undef _MBCS
|
||||
|
||||
/* Version number of package */
|
||||
#define VERSION "2.3.0"
|
||||
#define VERSION "10.0.2"
|
||||
|
||||
// UWP compatibility
|
||||
#define PROGSHAREDIR ""
|
||||
|
@ -2,7 +2,7 @@ dnl Jami - configure.ac
|
||||
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([Jami Daemon],[10.0.1],[jami@gnu.org],[jami])
|
||||
AC_INIT([Jami Daemon],[10.0.2],[jami@gnu.org],[jami])
|
||||
|
||||
dnl Clear the implicit flags that default to '-g -O2', otherwise they
|
||||
dnl take precedence over the values we set via the
|
||||
|
@ -1,5 +1,5 @@
|
||||
project('jami-daemon', ['c', 'cpp'],
|
||||
version: '10.0.1',
|
||||
version: '10.0.2',
|
||||
license: 'GPL3+',
|
||||
default_options: ['cpp_std=gnu++17', 'buildtype=debugoptimized'],
|
||||
meson_version:'>= 0.54'
|
||||
|
@ -709,4 +709,18 @@ Account::removeDefaultModerator(const std::string& uri)
|
||||
defaultModerators_.erase(uri);
|
||||
}
|
||||
|
||||
bool
|
||||
Account::meetMinimumRequiredVersion(const std::vector<unsigned>& jamiVersion,
|
||||
const std::vector<unsigned>& minRequiredVersion)
|
||||
{
|
||||
if (jamiVersion.size() != 3 or minRequiredVersion.size() != 3) {
|
||||
JAMI_ERR("Unexpected vector size");
|
||||
return false;
|
||||
}
|
||||
|
||||
return jamiVersion[0] > minRequiredVersion[0]
|
||||
or (jamiVersion[0] == minRequiredVersion[0] and jamiVersion[1] > minRequiredVersion[1])
|
||||
or (jamiVersion[0] == minRequiredVersion[0] and jamiVersion[1] == minRequiredVersion[1]
|
||||
and jamiVersion[2] >= minRequiredVersion[2]);
|
||||
}
|
||||
} // namespace jami
|
||||
|
@ -353,6 +353,11 @@ public:
|
||||
// should be removed once the multi-stream feature is fully supported.
|
||||
bool isMultiStreamEnabled() const { return multiStreamEnabled_; }
|
||||
void enableMultiStream(bool enable) { multiStreamEnabled_ = enable; }
|
||||
// Check if a Daemon version (typically peer's version) satisfies the
|
||||
// minimum required version. This check is typically used to disable a
|
||||
// feature if it's not backward compatible with the peer's version.
|
||||
static bool meetMinimumRequiredVersion(const std::vector<unsigned>& jamiVersion,
|
||||
const std::vector<unsigned>& minRequiredVersion);
|
||||
|
||||
// Enable/disable compliancy with RFC-5245 for component IDs format.
|
||||
// The ICE component IDs are enumerated relative to the SDP session,
|
||||
|
@ -205,20 +205,47 @@ addUserAgentHeader(const std::string& userAgent, pjsip_tx_data* tdata)
|
||||
pjsip_user_agent_hdr_create(tdata->pool, &STR_USER_AGENT, &pjUserAgent));
|
||||
|
||||
if (hdr != nullptr) {
|
||||
JAMI_DBG("Add header to SIP message: \"%.*s: %.*s\"", (int) hdr->name.slen, hdr->name.ptr,
|
||||
(int) pjUserAgent.slen, pjUserAgent.ptr);
|
||||
JAMI_DBG("Add header to SIP message: \"%.*s: %.*s\"",
|
||||
(int) hdr->name.slen,
|
||||
hdr->name.ptr,
|
||||
(int) pjUserAgent.slen,
|
||||
pjUserAgent.ptr);
|
||||
pjsip_msg_add_hdr(tdata->msg, hdr);
|
||||
}
|
||||
}
|
||||
|
||||
void logMessageHeaders(const pjsip_hdr* hdr_list)
|
||||
std::string
|
||||
getPeerUserAgent(const pjsip_rx_data* rdata)
|
||||
{
|
||||
if (rdata == nullptr or rdata->msg_info.msg == nullptr) {
|
||||
JAMI_ERR("Unexpected null poiter!");
|
||||
return {};
|
||||
}
|
||||
|
||||
std::string peerUa {};
|
||||
pjsip_generic_string_hdr* uaHdr {nullptr};
|
||||
constexpr auto USER_AGENT_STR = CONST_PJ_STR("User-Agent");
|
||||
|
||||
uaHdr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg,
|
||||
&USER_AGENT_STR,
|
||||
nullptr);
|
||||
|
||||
if (uaHdr) {
|
||||
peerUa = {uaHdr->hvalue.ptr, static_cast<size_t>(uaHdr->hvalue.slen)};
|
||||
}
|
||||
|
||||
return peerUa;
|
||||
}
|
||||
|
||||
void
|
||||
logMessageHeaders(const pjsip_hdr* hdr_list)
|
||||
{
|
||||
const pjsip_hdr* hdr = hdr_list->next;
|
||||
const pjsip_hdr* end = hdr_list;
|
||||
std::string msgHdrStr("Message headers:\n");
|
||||
for (; hdr != end; hdr = hdr->next) {
|
||||
char buf[1024];
|
||||
int size = pjsip_hdr_print_on((void*)hdr, buf, sizeof(buf));
|
||||
int size = pjsip_hdr_print_on((void*) hdr, buf, sizeof(buf));
|
||||
if (size > 0) {
|
||||
msgHdrStr.append(buf, size);
|
||||
msgHdrStr.push_back('\n');
|
||||
@ -233,7 +260,7 @@ sip_strerror(pj_status_t code)
|
||||
{
|
||||
char err_msg[PJ_ERR_MSG_SIZE];
|
||||
auto ret = pj_strerror(code, err_msg, sizeof err_msg);
|
||||
return std::string {ret.ptr, ret.ptr+ret.slen};
|
||||
return std::string {ret.ptr, ret.ptr + ret.slen};
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -98,6 +98,7 @@ std::string_view getHostFromUri(std::string_view sipUri);
|
||||
|
||||
void addContactHeader(const pj_str_t* contactStr, pjsip_tx_data* tdata);
|
||||
void addUserAgentHeader(const std::string& userAgent, pjsip_tx_data* tdata);
|
||||
std::string getPeerUserAgent(const pjsip_rx_data* rdata);
|
||||
void logMessageHeaders(const pjsip_hdr* hdr_list);
|
||||
|
||||
std::string sip_strerror(pj_status_t code);
|
||||
|
@ -118,6 +118,7 @@ SIPCall::SIPCall(const std::shared_ptr<SIPAccountBase>& account,
|
||||
Call::CallType type,
|
||||
const std::vector<MediaAttribute>& mediaAttrList)
|
||||
: Call(account, callId, type)
|
||||
, peerSupportMultiStream_(false)
|
||||
, sdp_(new Sdp(callId))
|
||||
{
|
||||
if (account->getUPnPActive())
|
||||
@ -1454,6 +1455,77 @@ SIPCall::sendKeyframe()
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
SIPCall::setPeerUaVersion(const std::string& ua)
|
||||
{
|
||||
if (peerUserAgent_ == ua or ua.empty()) {
|
||||
// Silently ignore if it did not change or empty.
|
||||
return;
|
||||
}
|
||||
|
||||
if (peerUserAgent_.empty()) {
|
||||
JAMI_DBG("[call:%s] Set peer's User-Agent to [%s]", getCallId().c_str(), ua.c_str());
|
||||
} else if (not peerUserAgent_.empty()) {
|
||||
// Unlikely, but should be handled since we dont have control over the peer.
|
||||
// Even if it's unexpected, we still try to parse the UA version.
|
||||
JAMI_WARN("[call:%s] Peer's User-Agent unexpectedely changed from [%s] to [%s]",
|
||||
getCallId().c_str(),
|
||||
peerUserAgent_.c_str(),
|
||||
ua.c_str());
|
||||
}
|
||||
|
||||
peerUserAgent_ = ua;
|
||||
|
||||
// User-agent parsing
|
||||
constexpr std::string_view PACK_NAME(PACKAGE_NAME " ");
|
||||
std::string_view s {peerUserAgent_};
|
||||
std::string version;
|
||||
|
||||
auto pos = s.find(PACK_NAME);
|
||||
if (pos == std::string::npos) {
|
||||
// Must have the expected package name.
|
||||
JAMI_WARN("Could not find the expected package name in peer's User-Agent");
|
||||
return;
|
||||
}
|
||||
|
||||
s = s.substr(pos + PACK_NAME.length());
|
||||
|
||||
// Unstable (un-released) versions has a hiphen + commit Id after
|
||||
// the version number. Find the commit Id if any, and ignore it.
|
||||
pos = s.find("-");
|
||||
if (pos != std::string::npos) {
|
||||
// Get the version and ignore the commit ID.
|
||||
version = s.substr(0, pos);
|
||||
} else {
|
||||
// Extract the version number.
|
||||
pos = s.find(" ");
|
||||
if (pos != std::string::npos) {
|
||||
version = s.substr(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
if (version.empty()) {
|
||||
JAMI_DBG("[call:%s] Could not parse peer's Jami version", getCallId().c_str());
|
||||
}
|
||||
|
||||
auto peerJamiVersion = split_string_to_unsigned(version, '.');
|
||||
if (peerJamiVersion.size() != 3) {
|
||||
JAMI_WARN("Could not parse peer's Jami version");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if peer's version is at least 10.0.2 to enable multi-stream.
|
||||
peerSupportMultiStream_ = Account::meetMinimumRequiredVersion(peerJamiVersion, {10, 0, 2});
|
||||
|
||||
if (not peerSupportMultiStream_) {
|
||||
JAMI_DBG("Peer's version [%u.%u.%u] does not support multi-stream. Min required version: "
|
||||
"[10.0.2]",
|
||||
peerJamiVersion[0],
|
||||
peerJamiVersion[1],
|
||||
peerJamiVersion[2]);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SIPCall::onPeerRinging()
|
||||
{
|
||||
@ -1970,6 +2042,15 @@ SIPCall::isReinviteRequired(const std::vector<MediaAttribute>& mediaAttrList)
|
||||
bool
|
||||
SIPCall::requestMediaChange(const std::vector<MediaAttribute>& mediaAttrList)
|
||||
{
|
||||
// If the peer does not support multi-stream and the size of the new
|
||||
// media list is different from the current media list, the media
|
||||
// change request will be ignored.
|
||||
if (not peerSupportMultiStream_ and rtpStreams_.size() != mediaAttrList.size()) {
|
||||
JAMI_WARN("[call:%s] Peer does not support multi-stream. Media change request ignored",
|
||||
getCallId().c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
JAMI_DBG("[call:%s] Requesting media change. List of new media:", getCallId().c_str());
|
||||
|
||||
unsigned idx = 0;
|
||||
@ -2611,6 +2692,9 @@ SIPCall::merge(Call& call)
|
||||
tmpMediaTransport_ = std::move(subcall.tmpMediaTransport_);
|
||||
}
|
||||
|
||||
peerUserAgent_ = subcall.peerUserAgent_;
|
||||
peerSupportMultiStream_ = subcall.peerSupportMultiStream_;
|
||||
|
||||
Call::merge(subcall);
|
||||
startIceMedia();
|
||||
}
|
||||
|
@ -165,6 +165,11 @@ public:
|
||||
|
||||
void monitor() const override;
|
||||
|
||||
/**
|
||||
* Set peer's User-Agent found in the message header
|
||||
*/
|
||||
void setPeerUaVersion(const std::string& ua);
|
||||
|
||||
/**
|
||||
* Return the SDP's manager of this call
|
||||
*/
|
||||
@ -382,6 +387,11 @@ private:
|
||||
}
|
||||
inline std::weak_ptr<SIPCall> weak() { return std::weak_ptr<SIPCall>(shared()); }
|
||||
|
||||
// Peer's User-Agent.
|
||||
std::string peerUserAgent_ {};
|
||||
// Flag to indicate the the peer's Daemon version support multi-stream.
|
||||
bool peerSupportMultiStream_ {false};
|
||||
|
||||
// Vector holding the current RTP sessions.
|
||||
std::vector<RtpStream> rtpStreams_;
|
||||
|
||||
|
@ -397,6 +397,9 @@ transaction_request_cb(pjsip_rx_data* rdata)
|
||||
if (!call) {
|
||||
return PJ_FALSE;
|
||||
}
|
||||
|
||||
call->setPeerUaVersion(sip_utils::getPeerUserAgent(rdata));
|
||||
|
||||
call->setTransport(transport);
|
||||
|
||||
// JAMI_DBG("transaction_request_cb viaHostname %s toUsername %s addrToUse %s addrSdp %s
|
||||
@ -866,6 +869,10 @@ getCallFromInvite(pjsip_inv_session* inv)
|
||||
static void
|
||||
invite_session_state_changed_cb(pjsip_inv_session* inv, pjsip_event* ev)
|
||||
{
|
||||
if (inv == nullptr or ev == nullptr) {
|
||||
throw VoipLinkException("unexpected null pointer");
|
||||
}
|
||||
|
||||
auto call = getCallFromInvite(inv);
|
||||
if (not call)
|
||||
return;
|
||||
@ -907,6 +914,12 @@ invite_session_state_changed_cb(pjsip_inv_session* inv, pjsip_event* ev)
|
||||
inv->cause);
|
||||
}
|
||||
|
||||
if (ev->type == PJSIP_EVENT_RX_MSG) {
|
||||
call->setPeerUaVersion(sip_utils::getPeerUserAgent(ev->body.rx_msg.rdata));
|
||||
} else if (ev->type == PJSIP_EVENT_TSX_STATE and ev->body.tsx_state.type == PJSIP_EVENT_RX_MSG) {
|
||||
call->setPeerUaVersion(sip_utils::getPeerUserAgent(ev->body.tsx_state.src.rdata));
|
||||
}
|
||||
|
||||
switch (inv->state) {
|
||||
case PJSIP_INV_STATE_EARLY:
|
||||
if (status_code == PJSIP_SC_RINGING)
|
||||
|
Reference in New Issue
Block a user