MT#56321 Treat 183 as 200OK (other leg), when early media forced

There is a need to add an exception processing for 183 Session Progress,
and the following in-dialog requests/responses, in case the 183
has been previously sent to the B2B with the hf
'P-Early-Announce: force'.

This adds the following behavior.

When 183 is received, and the caller has been updated with the
new media capabilities, according to those needed to embed early
media into the media session with the caller (via re-INVITE), then:
- even though the 183 is treated similarly to 200OK in terms of media
  updates, do not send ACK to the leg going towards DSM,
  becausethe sems-b2b giving the DSM, it's still in stage INVITE/183
- do not re-negotiate the leg going towards the DSM,
  after the caller has been updated with the new media (a usual behavior)
  because the sems-b2b giving the DSM still considers the dialog here
  in the Early stage
- do not set the leg going towards DSM into the Connected state,
  because by the fact, it's still in the Early stage, and setting of
  it into the Connected state, will break processing of BYE / CANCEL.
- upon receiving the BYE from the caller (after the DSM announce is heard),
  answer right away with 200OK, but do not forward BYE to the let going
  towards DSM. Instead initiate the CANCEL towards it, because this leg
  is technically still in the Early stage of the dialog.

Original ticket number: TT#187351

Change-Id: Id6e05202add1bcbd358eecbcd5e2cbda1a995b32
mr11.2.1
Donat Zenichev 3 years ago
parent d36870e5be
commit 91cd45fe7b

@ -504,33 +504,48 @@ void CallLeg::b2bInitial1xx(AmSipReply& reply, bool forward)
void CallLeg::b2bInitial2xx(AmSipReply& reply, bool forward)
{
if (!setOther(reply.from_tag, forward)) {
// ignore reply which comes from non-our-peer leg?
/* ignore reply which comes from non-our-peer leg? */
DBG("2xx reply received from unknown B leg, ignoring\n");
return;
}
DBG("setting call status to connected with leg %s\n", getOtherId().c_str());
// terminate all other legs than the connected one (determined by other_id)
/* terminate all other legs than the connected one (determined by other_id) */
terminateNotConnectedLegs();
// connect media with the other leg if RTP relay is enabled
/* connect media with the other leg if RTP relay is enabled */
if (!other_legs.empty())
other_legs.begin()->releaseMediaSession(); // remove reference hold by OtherLegInfo
other_legs.clear(); // no need to remember the connected leg here
other_legs.begin()->releaseMediaSession(); /* remove reference hold by OtherLegInfo */
other_legs.clear(); /* no need to remember the connected leg here */
onCallConnected(reply);
if (!forward) {
// we need to generate re-INVITE based on received SDP
/* we need to generate re-INVITE based on received SDP
but only if this is not previously faked 183 as 200OK, TT#187351 */
saveSessionDescription(reply.body);
sendEstablishedReInvite();
}
else if (relaySipReply(reply) != 0) {
if (dlg->getFaked183As200()) {
DBG("Re-INVITE will be not send to update the leg, because there was a faked 183 as 200OK.\n");
//dlg->setFaked183As200(false); // should we reset upon media re-negotiation in both legs?
// but then it breaks the BYE -> CANCEL conversion.
} else {
DBG("Re-INVITE will be send to update the leg with the last media capabilities.\n");
sendEstablishedReInvite();
}
} else if (relaySipReply(reply) != 0) {
stopCall(StatusChangeCause::InternalError);
return;
}
updateCallStatus(Connected, &reply);
/* TT#187351, do not set the leg going towards sems DSM applications
* to the connected state, if this has been previously faked (183 considered as 200OK)
* otherwise call cancelation/termination will not work properly for this leg.
*/
if (!dlg->getFaked183As200() && !dlg->getForcedEarlyAnnounce())
updateCallStatus(Connected, &reply);
}
void CallLeg::onInitialReply(B2BSipReplyEvent *e)

@ -143,6 +143,20 @@ void AmB2BSession::finalize()
AmSession::finalize();
}
void AmB2BSession::sl_reply(const string &method, unsigned cseq, bool forward, int sip_code, const char *reason)
{
if (method != SIP_METH_ACK) {
AmSipReply n_reply;
n_reply.code = sip_code;
n_reply.reason = reason;
n_reply.cseq = cseq;
n_reply.cseq_method = method;
n_reply.from_tag = dlg->getLocalTag();
DBG("relaying stateless B2B SIP reply %d %s\n", sip_code, reason);
relayEvent(new B2BSipReplyEvent(n_reply, forward, method, getLocalTag()));
}
}
void AmB2BSession::relayError(const string &method, unsigned cseq,
bool forward, int err_code)
{
@ -212,24 +226,34 @@ void AmB2BSession::onB2BEvent(B2BEvent* ev)
return;
}
int res = relaySip(req_ev->req);
if(res < 0) {
// reply relayed request internally
relayError(req_ev->req.method, req_ev->req.cseq, true, res);
return;
}
/* relay, unless it's a BYE dedicated for other leg with a faked 183 */
int res = 0;
if (req_ev->req.method == SIP_METH_BYE && dlg->getFaked183As200()) {
DBG("This BYE will not forwarded, because other leg is a faked 183 to 200OK. CANCEL required.\n");
/* for now just answer with 200 OK, later on we must send CANCEL to the Early stage leg */
sl_reply(req_ev->req.method, req_ev->req.cseq, true, 200, "OK");
} else {
res = relaySip(req_ev->req); /* most requests get here */
}
if( (req_ev->req.method == SIP_METH_BYE)
// CANCEL is handled differently: other side has already
// sent a terminate event.
//|| (req_ev->req.method == SIP_METH_CANCEL)
) {
onOtherBye(req_ev->req);
if (res < 0) {
/* reply relayed request internally */
relayError(req_ev->req.method, req_ev->req.cseq, true, res);
return;
}
}
return;
if (req_ev->req.method == SIP_METH_BYE) {
/* CANCEL is handled differently: other side has already
sent a terminate event.
|| (req_ev->req.method == SIP_METH_CANCEL) */
if (dlg->getFaked183As200()) onOtherCancel();
else onOtherBye(req_ev->req);
}
}
return;
case B2BSipReply:
{
@ -602,6 +626,15 @@ void AmB2BSession::onOtherBye(const AmSipRequest& req)
terminateLeg();
}
void AmB2BSession::onOtherCancel()
{
DBG("The other leg will be canceled, because still in the Early stage.\n");
setStopped();
clearRtpReceiverRelay();
dlg->cancel();
}
bool AmB2BSession::onOtherReply(const AmSipReply& reply)
{
if(reply.code >= 300)

@ -203,6 +203,7 @@ private:
public:
void sl_reply(const string &method, unsigned cseq, bool forward, int sip_code, const char *reason);
void relayError(const string &method, unsigned cseq, bool forward, int sip_code, const char *reason);
void relayError(const string &method, unsigned cseq, bool forward, int err_code);
@ -254,6 +255,13 @@ private:
/** handle BYE on other leg */
virtual void onOtherBye(const AmSipRequest& req);
/** handle CANCEL on other leg, TT#187351
* This is a convertion of the BYE into the CANCEL for
* the other leg, because previously 183 message processing
* has been faked, and treated as 200OK.
*/
virtual void onOtherCancel();
/**
* Reply received from other leg has been replied
* @return true if reply was processed (should be absorbed)

@ -80,9 +80,8 @@ bool AmBasicSipDialog::getUACTransPending()
void AmBasicSipDialog::setStatus(Status new_status)
{
DBG("setting SIP dialog status: %s->%s\n",
getStatusStr(), getStatusStr(new_status));
DBG("setting SIP dialog status: %s->%s. Local_tag: <%s>\n",
getStatusStr(), getStatusStr(new_status), getLocalTag().c_str());
status = new_status;
}

@ -65,7 +65,7 @@ AmSipDialog::AmSipDialog(AmSipDialogEventHandler* h)
offeranswer_enabled(true),
early_session_started(false),session_started(false),
pending_invites(0),
sdp_local(), sdp_remote(), force_early_announce(false)
sdp_local(), sdp_remote(), faked_183_as_200(false), force_early_announce(false)
{
}
@ -406,7 +406,10 @@ bool AmSipDialog::onRxReplyStatus(const AmSipReply& reply)
/* 100-199 */
if (reply.code < 200) {
DBG("ignoring provisional reply in Early state");
string announce = getHeader(reply.hdrs, SIP_HDR_P_EARLY_ANNOUNCE, true);
setForcedEarlyAnnounce(announce.find("force") != std::string::npos);
/* we should always keep Route set for this leg updated in case
the provisional response updates the list of routes for any reason */
if ((reply.code == 180 || reply.code == 183) && !reply.route.empty()) {
@ -415,11 +418,39 @@ bool AmSipDialog::onRxReplyStatus(const AmSipReply& reply)
setRouteSet(reply.route);
}
/* exceptionally treat 183 with the 'P-Early-Announce: force',
similarly to the 200OK response, this will properly update the caller
with the late SDP capabilities (an early announcement),
which has been put on hold during the transfer
And furthermore will give the possibility to receive and forward BYE.
DSM applications using it:
- early_dbprompt (early_announce)
- pre_announce */
if (reply.code == 183 && !announce.empty() && getForcedEarlyAnnounce()) {
DBG("This is 183 with <P-Early-Announce: force>, treated exceptionally as 200OK.\n");
setStatus(Connected);
setFaked183As200(true); /* remember that this is a faked 200OK, indeed 183 */
if (reply.to_tag.empty()) {
DBG("received 2xx reply without to-tag (callid=%s): sending BYE\n",
reply.callid.c_str());
sendRequest(SIP_METH_BYE);
} else {
setRemoteTag(reply.to_tag);
}
}
/* 200-299 */
} else if(reply.code < 300) {
setStatus(Connected);
setRouteSet(reply.route);
/* reset faked 183, if was previously set and this is 200OK received in this leg */
if (getFaked183As200()) setFaked183As200(false);
if (reply.to_tag.empty()) {
DBG("received 2xx reply without to-tag (callid=%s): sending BYE\n",
reply.callid.c_str());
@ -478,6 +509,10 @@ bool AmSipDialog::onRxReplyStatus(const AmSipReply& reply)
}
bool cont = true;
/* For those exceptional 183 with the 'P-Early-Announce: force'
we don't want to fully imitate 200OK processing, and send ACK
further processing with ACK is only applied to real 200OK responses */
if ( (reply.code >= 200) && (reply.code < 300) &&
(reply.cseq_method == SIP_METH_INVITE) ) {

@ -59,8 +59,12 @@ protected:
// Reliable provisional reply support
Am100rel rel100;
/* dialog variables needed to properly handle 183->200OK faking */
/* Needed to properly handle 183->200OK faking, when 'P-Early-Announce: force'
* is added into 183, and we have to treat 183 similarly to 200OK.
* Means, we have to embed the early media into already established media session.
*/
bool force_early_announce;
bool faked_183_as_200;
int onTxReply(const AmSipRequest& req, AmSipReply& reply, int& flags);
int onTxRequest(AmSipRequest& req, int& flags);
@ -103,6 +107,9 @@ protected:
bool getOAForceSDP() const { return oa.getForceSDP(); }
/* getter/setter for faked 183 as 200OK responses, TT#187351 */
void setFaked183As200(bool value) { faked_183_as_200 = value; }
bool getFaked183As200() { return faked_183_as_200; }
void setForcedEarlyAnnounce(bool value) { force_early_announce = value; }
bool getForcedEarlyAnnounce() { return force_early_announce; }

Loading…
Cancel
Save