From 5bb04271c1cdc9f8389a445b830d83741969289a Mon Sep 17 00:00:00 2001 From: Donat Zenichev Date: Fri, 25 Jul 2025 13:09:08 +0200 Subject: [PATCH] MT#62859 AmB2BSession::acceptPendingInviteB2B use local conn/port Don't re-exploit the connection information and port (taken from the coming SDP offer) for creation of faked SDP answer (200OK). This is confusing and can break things in rtpengine monologues handling. Better to create fake SDP answer based on already learned local SDP port and entirely connection information. Change-Id: Id71453022fd6c93f6743f1046588447b52c38c07 --- core/AmB2BSession.cpp | 48 ++++++++++++++++++++++++++++++++++++++++-- core/AmOfferAnswer.cpp | 20 +++++++++++++++++- core/AmOfferAnswer.h | 4 ++++ core/AmSipDialog.h | 1 + 4 files changed, 70 insertions(+), 3 deletions(-) diff --git a/core/AmB2BSession.cpp b/core/AmB2BSession.cpp index 83354eab..58baae92 100644 --- a/core/AmB2BSession.cpp +++ b/core/AmB2BSession.cpp @@ -276,6 +276,15 @@ void AmB2BSession::createFakeReply(const AmMimeBody *sdp, AmMimeBody& reply_bo ILOG_DLG(L_DBG, "created pending INVITE reply body: %s\n", body_str.c_str()); } +static void sdp2body(const AmSdp &sdp, AmMimeBody &body) +{ + string body_str; + sdp.print(body_str); + AmMimeBody *s = body.hasContentType(SIP_APPLICATION_SDP); + if (s) s->parse(SIP_APPLICATION_SDP, (const unsigned char*)body_str.c_str(), body_str.length()); + else body.parse(SIP_APPLICATION_SDP, (const unsigned char*)body_str.c_str(), body_str.length()); +} + void AmB2BSession::acceptPendingInvite(AmSipRequest *invite) { // reply the INVITE with fake 200 reply @@ -292,9 +301,44 @@ void AmB2BSession::acceptPendingInvite(AmSipRequest *invite) void AmB2BSession::acceptPendingInviteB2B(const AmSipRequest& invite) { const AmMimeBody *sdp = invite.body.hasContentType(SIP_APPLICATION_SDP); - AmSipReply n_reply; - createFakeReply(sdp, n_reply.body); + + /* local sdp, which was already learned before */ + AmSdp remote_sdp = dlg->getRemoteSdp(); + + unsigned int remote_port = 0; + + if (dlg->getRemoteMediaPort() > 0) { + ILOG_DLG(L_DBG, "Using remotely seen SDP port for faking this reply: '%d'\n", dlg->getRemoteMediaPort()); + remote_port = dlg->getRemoteMediaPort(); + } + else if (!remote_sdp.media.empty()) { + /* take first possible media and re-use its port */ + SdpMedia remote_sdp_media = remote_sdp.media.front(); + if (remote_sdp_media.port > 0) { + ILOG_DLG(L_DBG, "Using remotely seen SDP port for faking this reply: '%d'\n", remote_sdp_media.port); + remote_port = remote_sdp_media.port; + } + } + + if (remote_port > 0) { + /* create fake AmSdp from AmMimeBody */ + AmSdp fake_sdp; + AmMimeBody fake_mimebody; + fake_sdp.parse((const char *)sdp->getPayload()); + + ILOG_DLG(L_DBG, "Using local SDP port for faking this reply: '%d'\n", remote_port); + for (auto it = fake_sdp.media.begin(); it != fake_sdp.media.end(); ++it) + { + it->port = remote_port; + } + + sdp2body(fake_sdp, fake_mimebody); + createFakeReply(&fake_mimebody, n_reply.body); + } + else { + createFakeReply(sdp, n_reply.body); + } n_reply.code = 200; n_reply.reason = "OK"; diff --git a/core/AmOfferAnswer.cpp b/core/AmOfferAnswer.cpp index 28797b29..e20b2ad1 100644 --- a/core/AmOfferAnswer.cpp +++ b/core/AmOfferAnswer.cpp @@ -58,7 +58,8 @@ AmOfferAnswer::AmOfferAnswer(AmSipDialog* dlg) sdp_remote(), sdp_local(), dlg(dlg), - force_sdp(true) + force_sdp(true), + remote_port_seen(0) { } @@ -85,6 +86,11 @@ const AmSdp& AmOfferAnswer::getRemoteSdp() const return sdp_remote; } +const unsigned int& AmOfferAnswer::getRemoteMediaPort() const +{ + return remote_port_seen; +} + /** State maintenance */ void AmOfferAnswer::saveState() { @@ -225,6 +231,12 @@ int AmOfferAnswer::onReplyIn(const AmSipReply& reply) dlg->onSdpReceived(true); } + if (!sdp_remote.media.empty()) + { + SdpMedia remote = sdp_remote.media.front(); + remote_port_seen = remote.port; + } + } else { bool is_reliable = reply.code >= 200 || key_in_list(getHeader(reply.hdrs, SIP_HDR_REQUIRE), SIP_EXT_100REL); saveState(); @@ -274,6 +286,12 @@ int AmOfferAnswer::onRxSdp(unsigned int m_cseq, const string& m_remote_tag, sdp_remote.clear(); } + if (!sdp_remote.media.empty()) + { + SdpMedia remote = sdp_remote.media.front(); + remote_port_seen = remote.port; + } + if(err_code == 0) { switch(state) { diff --git a/core/AmOfferAnswer.h b/core/AmOfferAnswer.h index f0c19254..eea096a5 100644 --- a/core/AmOfferAnswer.h +++ b/core/AmOfferAnswer.h @@ -53,6 +53,9 @@ private: AmSdp sdp_remote; AmSdp sdp_local; + /* saved remote port */ + unsigned int remote_port_seen; + AmSipDialog* dlg; /** Should SDP generation be forced when not required by standards? */ @@ -79,6 +82,7 @@ public: void setState(OAState n_st); const AmSdp& getLocalSdp() const; const AmSdp& getRemoteSdp() const; + const unsigned int& getRemoteMediaPort() const; void clear(); void clearTransitionalState(); diff --git a/core/AmSipDialog.h b/core/AmSipDialog.h index 16d7c1c9..56e01fa7 100644 --- a/core/AmSipDialog.h +++ b/core/AmSipDialog.h @@ -134,6 +134,7 @@ protected: const AmSdp& getLocalSdp() { return oa.getLocalSdp(); } const AmSdp& getRemoteSdp() { return oa.getRemoteSdp(); } + const unsigned int& getRemoteMediaPort() { return oa.getRemoteMediaPort(); } /** * Reliable provisional replies