]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Fix a possible race condition where duplicate requests may be handled by separate...
authorMark Michelson <mmichelson@digium.com>
Fri, 14 Nov 2014 14:21:55 +0000 (14:21 +0000)
committerMark Michelson <mmichelson@digium.com>
Fri, 14 Nov 2014 14:21:55 +0000 (14:21 +0000)
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

include/asterisk/res_pjsip.h
res/res_pjsip.c
res/res_pjsip_pubsub.c
res/res_pjsip_session.c

index d15d015cfd7d2801b9fe09bdaf1a3e1108063282..650493797fcb8165c497a54bc8ba4a43e0182885 100644 (file)
@@ -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
index 168fed54f23e12d2792ffb855717e41b47484344..72a942d69da39bb91fbd038045eae9ef6967d2a8 100644 (file)
@@ -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;
index a0e8d49f8544d19a69400b66da31a59e8d0960ea..30467904f21741b07999ee05ca51e4544bddec65 100644 (file)
@@ -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);
index 0fa52eca940d0256bb63a9083b5407c3e5bcdb36..7178732a9dc51d9cfd1cdbc114beaa99053c93a7 100644 (file)
@@ -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) {