From: Mark Michelson Date: Fri, 14 Nov 2014 14:21:55 +0000 (+0000) Subject: Fix a possible race condition where duplicate requests may be handled by separate... X-Git-Tag: 12.8.0-rc1~47 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c6871f375f1874ed63329ce11608ba3b7b3ebb85;p=thirdparty%2Fasterisk.git Fix a possible race condition where duplicate requests may be handled by separate threads. If an endpoint retransmits a request, it's possible due to temporary load that Asterisk may end up processing both requests at the same time in separate threads. One thread will successfully handle the request, while the other thread fails to handle the request since the first thread already registered the transaction with the PJSIP core. The fix here is to detect the duplicated transaction failure and to silently absorb the request since another thread should be properly handling the request. Review: https://reviewboard.asterisk.org/r/4174 git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/12@427840 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h index d15d015cfd..650493797f 100644 --- a/include/asterisk/res_pjsip.h +++ b/include/asterisk/res_pjsip.h @@ -1228,8 +1228,9 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, * * \param endpoint A pointer to the endpoint * \param rdata The request that is starting the dialog + * \param[out] status On failure, the reason for failure in creating the dialog */ -pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata); +pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status); /*! * \brief General purpose method for creating an rdata structure using specific information diff --git a/res/res_pjsip.c b/res/res_pjsip.c index 168fed54f2..72a942d69d 100644 --- a/res/res_pjsip.c +++ b/res/res_pjsip.c @@ -1646,12 +1646,13 @@ pjsip_dialog *ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, return dlg; } -pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata) +pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status) { pjsip_dialog *dlg; pj_str_t contact; pjsip_transport_type_e type = rdata->tp_info.transport->key.type; - pj_status_t status; + + ast_assert(status != NULL); contact.ptr = pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE); contact.slen = pj_ansi_snprintf(contact.ptr, PJSIP_MAX_URL_SIZE, @@ -1664,11 +1665,11 @@ pjsip_dialog *ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? ";transport=" : "", (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) : ""); - status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); - if (status != PJ_SUCCESS) { + *status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); + if (*status != PJ_SUCCESS) { char err[PJ_ERR_MSG_SIZE]; - pj_strerror(status, err, sizeof(err)); + pj_strerror(*status, err, sizeof(err)); ast_log(LOG_ERROR, "Could not create dialog with endpoint %s. %s\n", ast_sorcery_object_get_id(endpoint), err); return NULL; diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c index a0e8d49f85..30467904f2 100644 --- a/res/res_pjsip_pubsub.c +++ b/res/res_pjsip_pubsub.c @@ -122,6 +122,7 @@ static struct pjsip_module pubsub_module = { #define MOD_DATA_BODY_GENERATOR "sub_body_generator" #define MOD_DATA_PERSISTENCE "sub_persistence" +#define MOD_DATA_DLG_STATUS "dlg_status" static const pj_str_t str_event_name = { "Event", 5 }; @@ -721,6 +722,7 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su struct ast_sip_subscription *sub = ao2_alloc(sizeof(*sub), subscription_destructor); pjsip_dialog *dlg; struct subscription_persistence *persistence; + pj_status_t dlg_status; if (!sub) { return NULL; @@ -739,7 +741,9 @@ struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_su pubsub_module.id, MOD_DATA_BODY_GENERATOR); sub->role = role; if (role == AST_SIP_NOTIFIER) { - dlg = ast_sip_create_dialog_uas(endpoint, rdata); + dlg = ast_sip_create_dialog_uas(endpoint, rdata, &dlg_status); + ast_sip_mod_data_set(rdata->tp_info.pool, rdata->endpt_info.mod_data, + pubsub_module.id, MOD_DATA_DLG_STATUS, (void *) dlg_status); } else { RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); @@ -1173,7 +1177,10 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata) } pjsip_dlg_send_response(dlg, trans, tdata); } else { - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); + long dlg_status = (long) ast_sip_mod_data_get(rdata->endpt_info.mod_data, pubsub_module.id, MOD_DATA_DLG_STATUS); + if (dlg_status != PJ_EEXISTS) { + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); + } } } else { sub->persistence = subscription_persistence_create(sub); diff --git a/res/res_pjsip_session.c b/res/res_pjsip_session.c index 0fa52eca94..7178732a9d 100644 --- a/res/res_pjsip_session.c +++ b/res/res_pjsip_session.c @@ -1406,6 +1406,7 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a pjsip_dialog *dlg; pjsip_inv_session *inv_session; unsigned int options = endpoint->extensions.flags; + pj_status_t dlg_status; if (pjsip_inv_verify_request(rdata, &options, NULL, NULL, ast_sip_get_pjsip_endpoint(), &tdata) != PJ_SUCCESS) { if (tdata) { @@ -1415,9 +1416,11 @@ static pjsip_inv_session *pre_session_setup(pjsip_rx_data *rdata, const struct a } return NULL; } - dlg = ast_sip_create_dialog_uas(endpoint, rdata); + dlg = ast_sip_create_dialog_uas(endpoint, rdata, &dlg_status); if (!dlg) { - pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); + if (dlg_status != PJ_EEXISTS) { + pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); + } return NULL; } if (pjsip_inv_create_uas(dlg, rdata, NULL, options, &inv_session) != PJ_SUCCESS) {