diff --git a/apps/sbc/CallLeg.cpp b/apps/sbc/CallLeg.cpp index 4caf1f75..6d49f2bc 100644 --- a/apps/sbc/CallLeg.cpp +++ b/apps/sbc/CallLeg.cpp @@ -447,18 +447,49 @@ void CallLeg::onB2BEvent(B2BEvent* ev) if (dynamic_cast(ev)) applyPendingUpdate(); break; - - case B2BSipRequest: + case B2BSipRequest: { + B2BSipRequestEvent *req_ev = dynamic_cast(ev); if (!sip_relay_only) { - // disable forwarding of relayed request if we are not connected [yet] - // (only we known that, the B leg has just delayed information about being - // connected to us and thus it can't set) - // Need not to be done if we have only one possible B leg so instead of - // checking call_status we can check if sip_relay_only is set or not - B2BSipRequestEvent *req_ev = dynamic_cast(ev); + /** disable forwarding of relayed request if we are not connected [yet] + * (only we known that, the B leg has just delayed information about being + * connected to us and thus it can't set) + * Need not to be done if we have only one possible B leg so instead of + * checking call_status we can check if sip_relay_only is set or not + */ if (req_ev) req_ev->forward = false; + } else { + if (req_ev && req_ev->forward) { + /* in case of already ongoing negotiation in the other leg */ + if (req_ev->req.method == SIP_METH_INVITE && dlg->getUACInvTransPending()) { + if (AmConfig::send_491_on_pending_session_leg) { + /** do not send right away one more re-INVITE towards it, + * just delay the current leg, which sent us re-INVITE, with with a 491 response. + */ + DBG("Cannot forward INVITE into another leg, already present pending session with it!\n"); + AmB2BSession::relayError(req_ev->req.method, req_ev->req.cseq, true, 491, SIP_REPLY_PENDING); + return; + } else { + /** send a fake 200OK to the one who initiated media re-negotiation, + * in order to let it be sure the re-negotiation is completed, and then + * after a while, when an opposite leg is done with its pending transaction(s), + * propose it new media attributes. This behavior, however, can trigger issues with non + * matched ACK for the faked 200OK, in case B2B establishes other transactions + * within the period till ACK is received (for the fake 200OK). + */ + DBG("Pending UAC INVITE transaction, planning session update (Reinvite) for later.\n"); + pending_updates.push_back(new Reinvite(req_ev->req.hdrs, + req_ev->req.body, /* establishing = */ false, + /* relayed */ false, /* r_cseq */ 0)); + DBG("For now replying with fake 200 OK.\n"); + acceptPendingInviteB2B(req_ev->req); + return; + } + } + } } // continue handling in AmB2bSession + AmB2BSession::onB2BEvent(ev); + } break; default: AmB2BSession::onB2BEvent(ev); diff --git a/core/AmConfig.cpp b/core/AmConfig.cpp index e32b3a18..5c19186f 100644 --- a/core/AmConfig.cpp +++ b/core/AmConfig.cpp @@ -128,7 +128,9 @@ unsigned int AmConfig::ShutdownModeErrCode = 503; string AmConfig::ShutdownModeErrReason = "Server shutting down"; bool AmConfig::skip_cpslimit_emergency = true; - + +bool AmConfig::send_491_on_pending_session_leg = false; + string AmConfig::OptionsTranscoderOutStatsHdr; // empty by default string AmConfig::OptionsTranscoderInStatsHdr; // empty by default string AmConfig::TranscoderOutStatsHdr; // empty by default @@ -466,6 +468,11 @@ int AmConfig::readConfiguration() if (cfg.hasParameter("skip_cpslimit_emergency")) skip_cpslimit_emergency = cfg.getParameter("skip_cpslimit_emergency")=="yes"; + // send_491_on_pending_session_leg = true - generate 491 Pending, on pending transaction + // send_491_on_pending_session_leg = false - generate a fake 200OK, on pending transaction + if (cfg.hasParameter("send_491_on_pending_session_leg")) + send_491_on_pending_session_leg = cfg.getParameter("send_491_on_pending_session_leg")=="yes"; + if(cfg.hasParameter("log_sessions")) LogSessions = cfg.getParameter("log_sessions")=="yes"; diff --git a/core/AmConfig.h b/core/AmConfig.h index 93db08b1..ca9ad1a0 100644 --- a/core/AmConfig.h +++ b/core/AmConfig.h @@ -285,6 +285,19 @@ struct AmConfig /* Global policy for treating emergency calls on CPSLimit triggering */ static bool skip_cpslimit_emergency; + /** Defines whether we send 491 upon receiving re-INVITE in one leg, + * meanwhile in an opposite leg there is still pending transaction. + * Example: ACK hasn't been received in A leg, meanwhile in the B leg + * remote SIP point already sends us re-INVITE to re-negotiate the media. + * - if true, 491 is sent on the re-INVITE, and it's meant, remote point + * re-sends re-INVITE slightly later again. + * - if false, a fake 200OK is generated towards remote side as an answer + * to re-INVITE, and for another leg media updates are scheduled + * for later time (after its handshake is finished for e.g.) + * By default: generate fake 200OK. + */ + static bool send_491_on_pending_session_leg; + /** Read global configuration file and insert values. Maybe overwritten by * command line arguments */ static int readConfiguration();