res_pjsip_pubsub: Ensure dialog manipulation happens on proper thread.
authorJoshua Colp <jcolp@digium.com>
Tue, 24 Dec 2013 02:20:18 +0000 (02:20 +0000)
committerJoshua Colp <jcolp@digium.com>
Tue, 24 Dec 2013 02:20:18 +0000 (02:20 +0000)
When destroying a subscription we remove the serializer from its dialog
and decrease its reference count. Depending on which thread dropped the
subscription reference count to 0 it was possible for this to occur in
a thread where it is not possible.

(closes issue ASTERISK-22952)
Reported by: Matt Jordan
........

Merged revisions 404553 from http://svn.asterisk.org/svn/asterisk/branches/12

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@404554 65c4cc65-6c06-0410-ace0-fbb531ad65f3

res/res_pjsip_pubsub.c

index 5bcfd07..2dcfaf6 100644 (file)
@@ -303,6 +303,25 @@ static int datastore_cmp(void *obj, void *arg, int flags)
        return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
 }
 
+static int subscription_remove_serializer(void *obj)
+{
+       struct ast_sip_subscription *sub = 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.
+        */
+       ast_sip_dialog_set_serializer(sub->dlg, NULL);
+       pjsip_dlg_dec_session(sub->dlg, &pubsub_module);
+
+       return 0;
+}
+
 static void subscription_destructor(void *obj)
 {
        struct ast_sip_subscription *sub = obj;
@@ -314,17 +333,7 @@ static void subscription_destructor(void *obj)
        ao2_cleanup(sub->endpoint);
 
        if (sub->dlg) {
-               /* 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.
-                */
-               ast_sip_dialog_set_serializer(sub->dlg, NULL);
-               pjsip_dlg_dec_session(sub->dlg, &pubsub_module);
+               ast_sip_push_task_synchronous(NULL, subscription_remove_serializer, sub);
        }
        ast_taskprocessor_unreference(sub->serializer);
 }