From 1b284a519baab0ce995adcb47b6eb2e027ef2212 Mon Sep 17 00:00:00 2001 From: Andrea Gianarda <andrea.gianarda@belledonne-communications.com> Date: Mon, 24 Mar 2025 11:43:39 +0100 Subject: [PATCH] Do not send further reINVITEs or UPDATEs until the retry function has been executed --- src/conference/client-conference.cpp | 32 +++++++++++++----------- src/conference/session/call-session.cpp | 28 ++++++++++++++++----- src/conference/session/media-session.cpp | 4 +++ src/sal/call-op.cpp | 3 ++- 4 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/conference/client-conference.cpp b/src/conference/client-conference.cpp index 0b1169d2fd..1ec72d9c17 100644 --- a/src/conference/client-conference.cpp +++ b/src/conference/client-conference.cpp @@ -896,13 +896,12 @@ void ClientConference::onFocusCallStateChanged(CallSession::State state, BCTBX_U if (requestStreams() != 0) { lInfo() << "Delaying re-INVITE in order to get streams after joining " << *this << " because the dialog is not available yet to accept this transaction"; - mScheduleUpdate = true; - } else { - // An update has been successfully sent therefore clear the flag mScheduleUpdate to avoid - // sending it twice. - mScheduleUpdate = false; - mFullStateUpdate = false; + session->addPendingAction(requestStreams); } + // An update has been successfully sent therefore clear the flag mScheduleUpdate to avoid sending it + // twice. + mScheduleUpdate = false; + mFullStateUpdate = false; } } BCTBX_NO_BREAK; /* Intentional no break */ @@ -1796,13 +1795,6 @@ void ClientConference::onFullStateReceived() { } #endif // HAVE_ADVANCED_IM - auto requestStreams = [this]() -> LinphoneStatus { - lInfo() << "Sending re-INVITE in order to get streams after receiving a NOTIFY full state for " << *this; - setState(ConferenceInterface::State::Created); - auto ret = updateMainSession(false); - return ret; - }; - auto session = mFocus ? dynamic_pointer_cast<MediaSession>(mFocus->getSession()) : nullptr; // Notify local participant that the microphone is muted when receiving the full state as participants are added // as soon as possible @@ -1812,12 +1804,22 @@ void ClientConference::onFullStateReceived() { if (!getCore()->getCCore()->sal->mediaDisabled()) { if (session && (!session->mediaInProgress() || !session->getPrivate()->isUpdateSentWhenIceCompleted())) { + + auto requestStreams = [this]() -> LinphoneStatus { + lInfo() << "Sending re-INVITE in order to get streams after receiving a NOTIFY full state for " + << *this; + setState(ConferenceInterface::State::Created); + auto ret = updateMainSession(false); + return ret; + }; + if (requestStreams() != 0) { lInfo() << "Delaying re-INVITE in order to get streams after receiving a NOTIFY full state for " << *this << " because it cannot be sent right now"; - mScheduleUpdate = true; - mFullStateUpdate = true; + session->addPendingAction(requestStreams); } + mScheduleUpdate = false; + mFullStateUpdate = false; } else { lInfo() << "Delaying re-INVITE in order to get streams after receiving a NOTIFY full state for " << *this << " because ICE negotiations didn't end yet"; diff --git a/src/conference/session/call-session.cpp b/src/conference/session/call-session.cpp index d08b8cb6cf..adfb24324b 100644 --- a/src/conference/session/call-session.cpp +++ b/src/conference/session/call-session.cpp @@ -443,7 +443,6 @@ bool CallSessionPrivate::failure() { << Utils::toString(lastStableState); setState(lastStableState, "Restore stable state because no retry function has been set"); } - return true; } if (ei->reason != SalReasonNoMatch) { @@ -801,6 +800,15 @@ bool CallSessionPrivate::isReadyForInvite() const { } bool CallSessionPrivate::isUpdateAllowed(CallSession::State &nextState) const { + L_Q(); + if (op->hasRetryFunction()) { + lWarning() << "Unable to send reINVITE or UPDATE request right now because " << *q << " (local address " + << *q->getLocalAddress() << " remote address " + << (q->getRemoteAddress() ? q->getRemoteAddress()->toString() : "Unknown") + << ") needs to execute the request which was replied by a 491 Request Pending first."; + return false; + } + switch (state) { case CallSession::State::IncomingReceived: case CallSession::State::PushIncomingReceived: @@ -826,7 +834,9 @@ bool CallSessionPrivate::isUpdateAllowed(CallSession::State &nextState) const { nextState = state; break; default: - lError() << "Update is not allowed in [" << Utils::toString(state) << "] state"; + lError() << *q << " (local address " << *q->getLocalAddress() << " remote address " + << (q->getRemoteAddress() ? q->getRemoteAddress()->toString() : "Unknown") + << "): Update is not allowed in [" << Utils::toString(state) << "] state"; return false; } return true; @@ -1170,15 +1180,21 @@ std::shared_ptr<Address> CallSessionPrivate::getFixedContact() const { void CallSessionPrivate::reinviteToRecoverFromConnectionLoss() { L_Q(); - lInfo() << "CallSession [" << q << "] is going to be updated (reINVITE) in order to recover from lost connectivity"; + lInfo() << *q << " is going to be updated (reINVITE) in order to recover from lost connectivity"; + if (op) { + // Reset retry function as we need to recover from a network loss + op->resetRetryFunction(); + } q->update(params, CallSession::UpdateMethod::Invite); } void CallSessionPrivate::repairByNewInvite(bool withReplaces) { L_Q(); - lInfo() << "CallSession [" << q - << "] is going to have a new INVITE one in order to recover from lost connectivity; with Replaces header:" - << (withReplaces ? "yes" : "no"); + lInfo() << *q << " is going to have a new INVITE one in order to recover from lost connectivity; " + << (withReplaces ? "with" : "without") << " Replaces header"; + + // Reset retry function as we need to repair the INVITE session + op->resetRetryFunction(); // FIXME: startInvite shall() accept a list of bodies. // Since it is not the case, we can only re-use the first one. diff --git a/src/conference/session/media-session.cpp b/src/conference/session/media-session.cpp index e0c7f8025c..e70087504a 100644 --- a/src/conference/session/media-session.cpp +++ b/src/conference/session/media-session.cpp @@ -4258,6 +4258,10 @@ void MediaSessionPrivate::reinviteToRecoverFromConnectionLoss() { lInfo() << "MediaSession [" << q << "] is going to be updated (reINVITE) in order to recover from lost connectivity"; getStreamsGroup().getIceService().resetSession(); + if (op) { + // Reset retry function as we need to recover from a network loss + op->resetRetryFunction(); + } MediaSessionParams newParams(*getParams()); q->update(&newParams, CallSession::UpdateMethod::Invite, q->isCapabilityNegotiationEnabled()); } diff --git a/src/sal/call-op.cpp b/src/sal/call-op.cpp index 3f2aaadd67..9ab54ebadd 100644 --- a/src/sal/call-op.cpp +++ b/src/sal/call-op.cpp @@ -501,7 +501,8 @@ void SalCallOp::processResponseCb(void *userCtx, const belle_sip_response_event_ auto dialogState = dialog ? belle_sip_dialog_get_state(dialog) : BELLE_SIP_DIALOG_NULL; lInfo() << "Op [" << op << "] receiving call response [" << code << "], dialog is [" << dialog << "] in state [" << belle_sip_dialog_state_to_string(dialogState) << "]"; - op->ref(); // To make sure no cb will destroy op + op->ref(); // To make sure no cb will destroy op + op->resetRetryFunction(); // Retry function has been either executed or not needed anymore auto request = belle_sip_transaction_get_request(BELLE_SIP_TRANSACTION(clientTransaction)); string method = belle_sip_request_get_method(request); -- GitLab