res_pjsip_session: Fix issue with COLP and 491

The recent 491 changes introduced a check to determine if the active
and pending topologies were equal and to suppress the re-invite if they
were. When a re-invite is sent for a COLP-only change, the pending
topology is NULL so that check doesn't happen and the re-invite is
correctly sent. Of course, sending the re-invite sets the pending
topology.  If a 491 is received, when we resend the re-invite, the
pending topology is set and since we didn't request a change to the
topology in the first place, pending and active topologies are equal so
the topologies-equal check causes the re-invite to be erroneously
suppressed.

This change checks if the topologies are equal before we run the media
state resolver (which recreates the pending topology) so that when we
do the final topologies-equal check we know if this was a topology
change request.  If it wasn't a change request, we don't suppress
the re-invite even though the topologies are equal.

ASTERISK-29014

Change-Id: Iffd7dd0500301156a566119ebde528d1a9573314
This commit is contained in:
George Joseph 2020-09-11 10:09:55 -06:00
parent ad4f2a8c99
commit cc71be0078
1 changed files with 29 additions and 17 deletions

View File

@ -1596,11 +1596,12 @@ static int delay_request(struct ast_sip_session *session,
struct ast_sip_session_delayed_request *delay = delayed_request_alloc(method,
on_request, on_sdp_creation, on_response, generate_new_sdp, pending_media_state,
active_media_state);
SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
if (!delay) {
ast_sip_session_media_state_free(pending_media_state);
ast_sip_session_media_state_free(active_media_state);
return -1;
SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_ERROR, "Unable to allocate delay request\n");
}
if (method == DELAYED_METHOD_BYE || queue_head) {
@ -1609,14 +1610,14 @@ static int delay_request(struct ast_sip_session *session,
} else {
AST_LIST_INSERT_TAIL(&session->delayed_requests, delay, next);
}
return 0;
SCOPE_EXIT_RTN_VALUE(0);
}
static pjmedia_sdp_session *generate_session_refresh_sdp(struct ast_sip_session *session)
{
pjsip_inv_session *inv_session = session->inv_session;
const pjmedia_sdp_session *previous_sdp = NULL;
SCOPE_ENTER(1, "%s\n", ast_sip_session_get_name(session));
SCOPE_ENTER(3, "%s\n", ast_sip_session_get_name(session));
if (inv_session->neg) {
if (pjmedia_sdp_neg_was_answer_remote(inv_session->neg)) {
@ -2258,6 +2259,7 @@ static int sip_session_refresh(struct ast_sip_session *session,
if (pending_media_state) {
int index;
int type_streams[AST_MEDIA_TYPE_END] = {0};
int topology_change_request = 0;
ast_trace(-1, "%s: Pending media state exists\n", ast_sip_session_get_name(session));
@ -2278,8 +2280,16 @@ static int sip_session_refresh(struct ast_sip_session *session,
if (active_media_state) {
struct ast_sip_session_media_state *new_pending_state;
/*
* We need to check if the passed in active and pending states are equal
* before we run the media states resolver. We'll use the flag later
* to signal whether this was topology change or some other change such
* as a connected line change.
*/
topology_change_request = !ast_stream_topology_equal(active_media_state->topology, pending_media_state->topology);
ast_trace(-1, "%s: Active media state exists\n", ast_sip_session_get_name(session));
ast_trace(-1, "%s: Active media state exists and is%s equal to pending\n", ast_sip_session_get_name(session),
topology_change_request ? " not" : "");
ast_trace(-1, "%s: DP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));
ast_trace(-1, "%s: DA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(active_media_state->topology, &STR_TMP)));
ast_trace(-1, "%s: CP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->pending_media_state->topology, &STR_TMP)));
@ -2437,8 +2447,13 @@ static int sip_session_refresh(struct ast_sip_session *session,
ast_sip_session_get_name(session), position);
}
/* If the resulting media state matches the existing active state don't bother doing a session refresh */
if (ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {
/*
* We can suppress this re-invite if the pending topology is equal to the currently
* active topology but only if this re-invite was the result of a requested topology
* change. If it was the result of some other change, like connected line, then
* we don't want to suppress it even though the topologies are equal.
*/
if (topology_change_request && ast_stream_topology_equal(session->active_media_state->topology, pending_media_state->topology)) {
ast_trace(-1, "%s: CA: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(session->active_media_state->topology, &STR_TMP)));
ast_trace(-1, "%s: NP: %s\n", ast_sip_session_get_name(session), ast_str_tmp(256, ast_stream_topology_to_str(pending_media_state->topology, &STR_TMP)));
ast_sip_session_media_state_free(pending_media_state);
@ -4185,34 +4200,29 @@ static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session
struct ast_sip_session_media_state *pending_media_state;
struct ast_sip_session_media_state *active_media_state;
const char *session_name = ast_sip_session_get_name(session);
ast_debug(3, "%s re-INVITE collision.\n", session_name);
SCOPE_ENTER(3, "%s\n", session_name);
pending_media_state = ast_sip_session_media_state_clone(session->pending_media_state);
if (!pending_media_state) {
ast_log(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);
return;
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone pending media state\n", session_name);
}
active_media_state = ast_sip_session_media_state_clone(session->active_media_state);
if (!active_media_state) {
ast_sip_session_media_state_free(pending_media_state);
ast_log(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);
return;
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to clone active media state\n", session_name);
}
if (delay_request(session, NULL, NULL, on_response, 1, DELAYED_METHOD_INVITE, pending_media_state,
active_media_state, 1)) {
ast_sip_session_media_state_free(pending_media_state);
ast_sip_session_media_state_free(active_media_state);
ast_log(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);
return;
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Failed to add delayed request\n", session_name);
}
if (pj_timer_entry_running(&session->rescheduled_reinvite)) {
/* Timer already running. Something weird is going on. */
ast_log(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);
return;
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: re-INVITE collision while timer running!!!\n", session_name);
}
tv.sec = 0;
@ -4227,8 +4237,10 @@ static void reschedule_reinvite(struct ast_sip_session *session, ast_sip_session
if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(),
&session->rescheduled_reinvite, &tv) != PJ_SUCCESS) {
ao2_ref(session, -1);
ast_log(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);
SCOPE_EXIT_LOG_RTN(LOG_ERROR, "%s: Couldn't schedule timer\n", session_name);
}
SCOPE_EXIT_RTN();
}
static void __print_debug_details(const char *function, pjsip_inv_session *inv, pjsip_transaction *tsx, pjsip_event *e)