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
*
* \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
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,
(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;
#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 };
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;
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);
}
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);
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) {
}
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) {