From 0376af95192b0e902e52c33f9230dc5ecc90be42 Mon Sep 17 00:00:00 2001 From: Joshua Colp <jcolp@digium.com> Date: Wed, 14 Sep 2016 07:53:36 -0400 Subject: [PATCH] rtp: Only accept the first payload for a format in SDP. When receiving an SDP offer with multiple payloads for the same format we would generate an answer with the first payload, but during the payload crossover operation (to set the payloads for receiving) we would remove all payloads but the last. This would result in incoming traffic being matched against the wrong format and outgoing traffic being sent using the wrong payload. This change makes it so that once a format has a payload number put into the mapping all subsequent ones are ignored. This ensures there is only ever one payload in the mapping and that it is the payload placed into the answer SDP. ASTERISK-26365 #close Change-Id: I1e8150860a3518cab36d00b1fab50f9352b64e60 --- main/rtp_engine.c | 95 +++++++++++++++++++++++++++++------------------ 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/main/rtp_engine.c b/main/rtp_engine.c index 0671374ef5..b91bc41157 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -753,18 +753,18 @@ static void rtp_codecs_payloads_copy_rx(struct ast_rtp_codecs *src, struct ast_r /*! * \internal - * \brief Remove other matching payload mappings. + * \brief Determine if a type of payload is already present in mappings. * \since 14.0.0 * - * \param codecs Codecs that need tx mappings removed. - * \param instance RTP instance to notify of any payloads removed. + * \param codecs Codecs to be checked for mappings. * \param to_match Payload type object to compare against. * * \note It is assumed that codecs is write locked before calling. * - * \return Nothing + * \retval 0 not found + * \retval 1 found */ -static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *codecs, struct ast_rtp_instance *instance, struct ast_rtp_payload_type *to_match) +static int payload_mapping_tx_is_present(const struct ast_rtp_codecs *codecs, const struct ast_rtp_payload_type *to_match) { int idx; struct ast_rtp_payload_type *current; @@ -772,12 +772,18 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code for (idx = 0; idx < AST_VECTOR_SIZE(&codecs->payload_mapping_tx); ++idx) { current = AST_VECTOR_GET(&codecs->payload_mapping_tx, idx); - if (!current || current == to_match) { + if (!current) { continue; } + if (current == to_match) { + /* The exact object is already in the mapping. */ + return 1; + } if (current->asterisk_format && to_match->asterisk_format) { - if (ast_format_cmp(current->format, to_match->format) == AST_FORMAT_CMP_NOT_EQUAL) { + if (ast_format_get_codec_id(current->format) != ast_format_get_codec_id(to_match->format)) { continue; + } else if (current->payload == to_match->payload) { + return 0; } } else if (!current->asterisk_format && !to_match->asterisk_format) { if (current->rtp_code != to_match->rtp_code) { @@ -787,13 +793,10 @@ static void payload_mapping_tx_remove_other_mappings(struct ast_rtp_codecs *code continue; } - /* Remove other mapping */ - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, idx, NULL); - ao2_ref(current, -1); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, idx, 0, NULL, 0); - } + return 1; } + + return 0; } /*! @@ -833,13 +836,14 @@ static void rtp_codecs_payloads_copy_tx(struct ast_rtp_codecs *src, struct ast_r if (instance && instance->engine && instance->engine->payload_set) { instance->engine->payload_set(instance, idx, type->asterisk_format, type->format, type->rtp_code); } - - payload_mapping_tx_remove_other_mappings(dest, instance, type); } } void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_codecs *dest, struct ast_rtp_instance *instance) { + int idx; + struct ast_rtp_payload_type *type; + ast_rwlock_wrlock(&dest->codecs_lock); /* Deadlock avoidance because of held write lock. */ @@ -849,6 +853,17 @@ void ast_rtp_codecs_payloads_copy(struct ast_rtp_codecs *src, struct ast_rtp_cod ast_rwlock_wrlock(&dest->codecs_lock); } + /* + * This represents a completely new mapping of what the remote party is + * expecting for payloads, so we clear out the entire tx payload mapping + * vector and replace it. + */ + for (idx = 0; idx < AST_VECTOR_SIZE(&dest->payload_mapping_tx); ++idx) { + type = AST_VECTOR_GET(&dest->payload_mapping_tx, idx); + ao2_t_cleanup(type, "destroying ast_rtp_codec tx mapping"); + AST_VECTOR_REPLACE(&dest->payload_mapping_tx, idx, NULL); + } + rtp_codecs_payloads_copy_rx(src, dest, instance); rtp_codecs_payloads_copy_tx(src, dest, instance); dest->framing = src->framing; @@ -921,18 +936,20 @@ void ast_rtp_codecs_payloads_set_m_type(struct ast_rtp_codecs *codecs, struct as ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload), - "cleaning up replaced tx payload type"); - } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); + if (!payload_mapping_tx_is_present(codecs, new_type)) { + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload), + "cleaning up replaced tx payload type"); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, new_type); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); + if (instance && instance->engine && instance->engine->payload_set) { + instance->engine->payload_set(instance, payload, new_type->asterisk_format, new_type->format, new_type->rtp_code); + } + } else { + ao2_ref(new_type, -1); } - payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); - ast_rwlock_unlock(&codecs->codecs_lock); } @@ -995,17 +1012,20 @@ int ast_rtp_codecs_payloads_set_rtpmap_type_rate(struct ast_rtp_codecs *codecs, new_type->format = ast_format_parse_sdp_fmtp(new_type->format, ""); } - if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt), - "cleaning up replaced tx payload type"); - } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); + if (!payload_mapping_tx_is_present(codecs, new_type)) { + if (pt < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_t_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, pt), + "cleaning up replaced tx payload type"); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, pt, new_type); - if (instance && instance->engine && instance->engine->payload_set) { - instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); + if (instance && instance->engine && instance->engine->payload_set) { + instance->engine->payload_set(instance, pt, new_type->asterisk_format, new_type->format, new_type->rtp_code); + } + } else { + ao2_ref(new_type, -1); } - payload_mapping_tx_remove_other_mappings(codecs, instance, new_type); break; } @@ -1088,11 +1108,14 @@ int ast_rtp_codecs_payload_replace_format(struct ast_rtp_codecs *codecs, int pay type->primary_mapping = 1; ast_rwlock_wrlock(&codecs->codecs_lock); - if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { - ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); + if (!payload_mapping_tx_is_present(codecs, type)) { + if (payload < AST_VECTOR_SIZE(&codecs->payload_mapping_tx)) { + ao2_cleanup(AST_VECTOR_GET(&codecs->payload_mapping_tx, payload)); + } + AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type); + } else { + ao2_ref(type, -1); } - AST_VECTOR_REPLACE(&codecs->payload_mapping_tx, payload, type); - payload_mapping_tx_remove_other_mappings(codecs, NULL, type); ast_rwlock_unlock(&codecs->codecs_lock); return 0; -- GitLab