summaryrefslogtreecommitdiff
path: root/res/res_pjsip_pubsub.c
diff options
context:
space:
mode:
authorMark Michelson <mmichelson@digium.com>2015-10-02 15:32:09 -0500
committerRichard Mudgett <rmudgett@digium.com>2015-10-22 16:18:08 -0500
commit7f9823ff57df31fbc266dbb0229bb215eb7a3640 (patch)
tree99c9e48ab0479d4665e96b02959d4eee3bd393bd /res/res_pjsip_pubsub.c
parente9e4bc9ecec8a0bafc9db6f0cd700fbb9c97ace1 (diff)
res_pjsip_pubsub: Prevent sending NOTIFY on destroyed dialog.
A certain situation can result in our attempting to send a NOTIFY on a destroyed dialog. Say we attempt to send a NOTIFY to a subscriber, but that subscriber has dropped off the network. We end up retransmitting that NOTIFY until the appropriate SIP timer says to destroy the NOTIFY transaction. When the pjsip evsub code is told that the transaction has been terminated, it responds in kind by alerting us that the subscription has been terminated, destroying the subscription, and then removing its reference to the dialog, thus destroying the dialog. The problem is that when we get told that the subscription is being terminated, we detect that we have not sent a terminating NOTIFY request, so we queue up such a NOTIFY to be sent out. By the time that queued NOTIFY gets sent, the dialog has been destroyed, so attempting to send that NOTIFY can result in a crash. The fix being introduced here is actually a reintroduction of something the pubsub code used to employ. We hold a reference to the dialog and wait to decrement our reference to the dialog until our subscription tree object is destroyed. This way, we can send messages on the dialog even if the PJSIP evsub code wants to terminate earlier than we would like. In doing this, some NULL checks for subscription tree dialogs have been removed since NULL dialogs are no longer actually possible. Change-Id: I013f43cddd9408bb2a31b77f5db87a7972bfe1e5
Diffstat (limited to 'res/res_pjsip_pubsub.c')
-rw-r--r--res/res_pjsip_pubsub.c45
1 files changed, 20 insertions, 25 deletions
diff --git a/res/res_pjsip_pubsub.c b/res/res_pjsip_pubsub.c
index cf3b1ba6f..697f3a4d2 100644
--- a/res/res_pjsip_pubsub.c
+++ b/res/res_pjsip_pubsub.c
@@ -1177,6 +1177,24 @@ static void shutdown_subscriptions(struct ast_sip_subscription *sub)
sub->handler->subscription_shutdown(sub);
}
}
+static int subscription_unreference_dialog(void *obj)
+{
+ struct sip_subscription_tree *sub_tree = obj;
+
+ /* This is why we keep the dialog on the subscription. When the subscription
+ * is destroyed, there is no guarantee that the underlying dialog is ready
+ * to be destroyed. Furthermore, there's no guarantee in the opposite direction
+ * either. The dialog could be destroyed before our subscription is. We fix
+ * this problem by keeping a reference to the dialog until it is time to
+ * destroy the subscription. We need to have the dialog available when the
+ * subscription is destroyed so that we can guarantee that our attempt to
+ * remove the serializer will be successful.
+ */
+ pjsip_dlg_dec_session(sub_tree->dlg, &pubsub_module);
+ sub_tree->dlg = NULL;
+
+ return 0;
+}
static void subscription_tree_destructor(void *obj)
{
@@ -1190,6 +1208,7 @@ static void subscription_tree_destructor(void *obj)
destroy_subscriptions(sub_tree->root);
+ ast_sip_push_task_synchronous(sub_tree->serializer, subscription_unreference_dialog, sub_tree);
ast_taskprocessor_unreference(sub_tree->serializer);
ast_module_unref(ast_module_info->self);
}
@@ -1206,6 +1225,7 @@ static void subscription_setup_dialog(struct sip_subscription_tree *sub_tree, pj
ast_sip_dialog_set_serializer(dlg, sub_tree->serializer);
ast_sip_dialog_set_endpoint(dlg, sub_tree->endpoint);
pjsip_evsub_set_mod_data(sub_tree->evsub, pubsub_module.id, sub_tree);
+ pjsip_dlg_inc_session(dlg, &pubsub_module);
}
static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_endpoint *endpoint)
@@ -1526,10 +1546,6 @@ void *ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, co
pj_str_t name;
dlg = sub->tree->dlg;
- if (!dlg) {
- return NULL;
- }
-
msg = ast_sip_mod_data_get(dlg->mod_data, pubsub_module.id, MOD_DATA_MSG);
pj_cstr(&name, header);
@@ -2136,10 +2152,6 @@ static int serialized_send_notify(void *userdata)
struct sip_subscription_tree *sub_tree = userdata;
pjsip_dialog *dlg = sub_tree->dlg;
- if (!dlg) {
- return 0;
- }
-
pjsip_dlg_inc_lock(dlg);
/* It's possible that between when the notification was scheduled
* and now, that a new SUBSCRIBE arrived, requiring full state to be
@@ -2193,10 +2205,6 @@ int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip
int res;
pjsip_dialog *dlg = sub->tree->dlg;
- if (!dlg) {
- return 0;
- }
-
pjsip_dlg_inc_lock(dlg);
if (!sub->tree->evsub) {
@@ -2241,10 +2249,6 @@ void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char
pjsip_dialog *dlg;
dlg = sub->tree->dlg;
- if (!dlg) {
- *buf = '\0';
- return;
- }
ast_copy_pj_str(buf, &dlg->remote.info_str, size);
}
@@ -3199,10 +3203,6 @@ static int serialized_pubsub_on_server_timeout(void *userdata)
struct sip_subscription_tree *sub_tree = userdata;
pjsip_dialog *dlg = sub_tree->dlg;
- if (!dlg) {
- return 0;
- }
-
pjsip_dlg_inc_lock(dlg);
if (!sub_tree->evsub) {
pjsip_dlg_dec_lock(dlg);
@@ -3291,7 +3291,6 @@ static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
sub_tree->evsub = NULL;
ast_sip_dialog_set_serializer(sub_tree->dlg, NULL);
ast_sip_dialog_set_endpoint(sub_tree->dlg, NULL);
- sub_tree->dlg = NULL;
subscription_persistence_remove(sub_tree);
shutdown_subscriptions(sub_tree->root);
@@ -3304,10 +3303,6 @@ static int serialized_pubsub_on_rx_refresh(void *userdata)
struct sip_subscription_tree *sub_tree = userdata;
pjsip_dialog *dlg = sub_tree->dlg;
- if (!dlg) {
- return 0;
- }
-
pjsip_dlg_inc_lock(dlg);
if (!sub_tree->evsub) {
pjsip_dlg_dec_lock(dlg);