[asterisk-commits] mmichelson: branch mmichelson/pub_sub r386158 - in /team/mmichelson/pub_sub: ...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Fri Apr 19 16:59:06 CDT 2013


Author: mmichelson
Date: Fri Apr 19 16:59:05 2013
New Revision: 386158

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=386158
Log:
Address Josh's review feedback

* Get rid of ast_sip_dialog_remove_serializer
* Fix the lifetime of the ast_sip_subscription_response_data
* Note that refcount is increased on ast_sip_subscription_get_endpoint
* Send unsolicited MWI NOTIFY to all endpoint contacts
* Change subscription destructor not to push a synchronous task.
  Instead, ensure all unrefs are done in a servant thread.
* Document the inbuilt use of specialized PJSIP APIs for MWI and presence
* Do not allow for duplicate events when registering subscription handlers.


Modified:
    team/mmichelson/pub_sub/include/asterisk/res_sip.h
    team/mmichelson/pub_sub/include/asterisk/res_sip_pubsub.h
    team/mmichelson/pub_sub/res/res_sip.exports.in
    team/mmichelson/pub_sub/res/res_sip/sip_distributor.c
    team/mmichelson/pub_sub/res/res_sip_mwi.c
    team/mmichelson/pub_sub/res/res_sip_pubsub.c

Modified: team/mmichelson/pub_sub/include/asterisk/res_sip.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pub_sub/include/asterisk/res_sip.h?view=diff&rev=386158&r1=386157&r2=386158
==============================================================================
--- team/mmichelson/pub_sub/include/asterisk/res_sip.h (original)
+++ team/mmichelson/pub_sub/include/asterisk/res_sip.h Fri Apr 19 16:59:05 2013
@@ -787,21 +787,12 @@
 /*!
  * \brief Set a serializer on a SIP dialog so requests and responses are automatically serialized
  *
+ * Passing a NULL serializer is a way to remove a serializer from a dialog.
+ *
  * \param dlg The SIP dialog itself
  * \param serializer The serializer to use
  */
 void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer);
-
-/*!
- * \brief Remove a serializer on a SIP dialog
- *
- * This is useful for a case where the user of the serializer dies before the SIP dialog
- * does. This way, any further requests/responses that arrive on the dialog do not try
- * to use the serializer any more
- *
- * \param Dialog from which to remove the serializer
- */
-void ast_sip_dialog_remove_serializer(pjsip_dialog *dlg);
 
 /*!
  * \brief Set an endpoint on a SIP dialog so in-dialog requests do not undergo endpoint lookup.

Modified: team/mmichelson/pub_sub/include/asterisk/res_sip_pubsub.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pub_sub/include/asterisk/res_sip_pubsub.h?view=diff&rev=386158&r1=386157&r2=386158
==============================================================================
--- team/mmichelson/pub_sub/include/asterisk/res_sip_pubsub.h (original)
+++ team/mmichelson/pub_sub/include/asterisk/res_sip_pubsub.h Fri Apr 19 16:59:05 2013
@@ -44,247 +44,6 @@
     AST_SIP_NOTIFIER,
 };
 
-#define AST_SIP_MAX_ACCEPT 32
-
-struct ast_sip_subscription_handler {
-    /*! The name of the event this handler deals with */
-    const char *event_name;
-    /*! The types of body this handler accepts */
-    const char *accept[AST_SIP_MAX_ACCEPT];
- 
-    /*!
-     * \brief Called when a subscription is to be destroyed
-     *
-     * This is a subscriber and notifier callback.
-     *
-     * The handler is not expected to send any sort of requests or responses
-     * during this callback. The handler MUST, however, begin the destruction
-	 * process for the subscription during this callback.
-     */
-   void (*subscription_shutdown)(struct ast_sip_subscription *subscription);
- 
-    /*!
-     * \brief Called when a SUBSCRIBE arrives in order to create a new subscription
-     *
-     * This is a notifier callback.
-     *
-     * If the notifier wishes to accept the subscription, then it can create
-     * a new ast_sip_subscription to do so. 
-     *
-     * If the notifier chooses to create a new subscription, then it must accept
-     * the incoming subscription using pjsip_evsub_accept() and it must also
-     * send an initial NOTIFY with the current subscription state.
-     *
-     * \param endpoint The endpoint from which we received the SUBSCRIBE
-     * \param rdata The SUBSCRIBE request
-     * \retval NULL The SUBSCRIBE has not been accepted
-     * \retval non-NULL The newly-created subscription
-     */
-    struct ast_sip_subscription *(*new_subscribe)(struct ast_sip_endpoint *endpoint,
-            pjsip_rx_data *rdata);
- 
-    /*!
-     * \brief Called when an endpoint renews a subscription.
-     *
-     * This is a notifier callback.
-     *
-     * Because of the way that the PJSIP evsub framework works, it will automatically
-     * send a response to the SUBSCRIBE. However, the subscription handler must send
-	 * a NOTIFY with the current subscription state when this callback is called.
-     *
-     * \param sub The subscription that is being renewed
-     * \param rdata The SUBSCRIBE request in question
-     * \retval NULL Allow the default 200 OK response to be sent
-     * \retval non-NULL Send a response with the specified data present
-     */
-    struct ast_sip_subscription_response_data *(*resubscribe)(struct ast_sip_subscription *sub,
-            pjsip_rx_data *rdata);
- 
-    /*!
-     * \brief Called when a subscription times out.
-     *
-     * This is a notifier callback
-     *
-     * This indicates that the subscription has timed out. The subscription handler is
-     * expected to send a NOTIFY that terminates the subscription.
-     *
-     * \param sub The subscription that has timed out
-     */
-    void (*subscription_timeout)(struct ast_sip_subscription *sub);
- 
-    /*!
-     * \brief Called when a subscription is terminated via a SUBSCRIBE or NOTIFY request
-     *
-     * This is a notifier and subscriber callback.
-     *
-     * The PJSIP subscription framework will automatically send the response to the
-     * request. If a notifier receives this callback, then the subscription handler
-	 * is expected to send a final NOTIFY to terminate the subscription.
-     *
-     * \param sub The subscription being terminated
-     * \param rdata The request that terminated the subscription
-     */
-    void (*subscription_terminated)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
- 
-    /*!
-     * \brief Called when a subscription handler's outbound NOTIFY receives a response
-     *
-     * This is a notifier callback.
-     *
-     * \param sub The subscription
-     * \param rdata The NOTIFY response
-     */
-    void (*notify_response)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
- 
-    /*!
-     * \brief Called when a subscription handler receives an inbound NOTIFY
-     *
-     * This is a subscriber callback.
-     *
-     * Because of the way that the PJSIP evsub framework works, it will automatically
-     * send a response to the NOTIFY. By default this will be a 200 OK response, but
-     * this callback can change details of the response by returning response data
-     * to use.
-     *
-     * \param sub The subscription
-     * \param rdata The NOTIFY request
-     * \retval NULL Have the framework send the default 200 OK response
-     * \retval non-NULL Send a response with the specified data
-     */
-    struct ast_sip_subscription_response_data *(*notify_request)(struct ast_sip_subscription *sub,
-            pjsip_rx_data *rdata);
- 
-    /*!
-     * \brief Called when it is time for a subscriber to resubscribe
-     *
-     * This is a subscriber callback.
-     *
-     * The subscriber can reresh the subscription using the pjsip_evsub_initiate()
-     * function.
-     *
-     * \param sub The subscription to refresh
-     * \retval 0 Success
-     * \retval non-zero Failure
-     */
-    int (*refresh_subscription)(struct ast_sip_subscription *sub);
-	AST_LIST_ENTRY(ast_sip_subscription_handler) next;
-};
-
-/*!
- * \brief Create a new ast_sip_subscription structure
- *
- * \param handler The subsription handler for this subscription
- * \param role Whether we are acting as subscriber or notifier for this subscription
- * \param endpoint The endpoint involved in this subscription
- * \param rdata If acting as a notifier, the SUBSCRIBE request that triggered subscription creation
- */
-struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
-        enum ast_sip_subscription_role role, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
- 
- 
-/*!
- * \brief Get the endpoint that is associated with this subscription
- *
- * \retval NULL Could not get endpoint
- * \retval non-NULL The endpoint
- */
-struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub);
- 
-/*!
- * \brief Get the serializer for the subscription
- *
- * Tasks that originate outside of a SIP servant thread should get the serializer
- * and push the task to the serializer.
- *
- * \param sub The subscription
- * \retval NULL Failure
- * \retval non-NULL The subscription's serializer
- */
-struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub);
- 
-/*!
- * \brief Get the underlying PJSIP evsub structure
- *
- * This is useful when wishing to call PJSIP's API calls in order to
- * create SUBSCRIBEs, NOTIFIES, etc. as well as get subscription state
- *
- * This function, as well as all methods called on the pjsip_evsub should
- * be done in a SIP servant thread.
- *
- * \param sub The subscription
- * \retval NULL Failure
- * \retval non-NULL The underlying pjsip_evsub
- */
-pjsip_evsub *ast_sip_subscription_get_evsub(struct ast_sip_subscription *sub);
- 
-/*!
- * \brief Send a request created via a PJSIP evsub method
- *
- * Callers of this function should take care to do so within a SIP servant
- * thread.
- *
- * \param sub The subscription on which to send the request
- * \param tdata The request to send
- * \retval 0 Success
- * \retval non-zero Failure
- */
-int ast_sip_subscription_send_request(struct ast_sip_subscription *sub, pjsip_tx_data *tdata);
- 
-/*!
- * \brief Alternative for ast_datastore_alloc()
- *
- * There are two major differences between this and ast_datastore_alloc()
- * 1) This allocates a refcounted object
- * 2) This will fill in a uid if one is not provided
- *
- * DO NOT call ast_datastore_free() on a datastore allocated in this
- * way since that function will attempt to free the datastore rather
- * than play nicely with its refcount.
- *
- * \param info Callbacks for datastore
- * \param uid Identifier for datastore
- * \retval NULL Failed to allocate datastore
- * \retval non-NULL Newly allocated datastore
- */
-struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid);
- 
-/*!
- * \brief Add a datastore to a SIP subscription
- *
- * Note that SIP uses reference counted datastores. The datastore passed into this function
- * must have been allocated using ao2_alloc() or there will be serious problems.
- *
- * \param subscription The ssubscription to add the datastore to
- * \param datastore The datastore to be added to the subscription
- * \retval 0 Success
- * \retval -1 Failure
- */
-int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore);
- 
-/*!
- * \brief Retrieve a subscription datastore
- *
- * The datastore retrieved will have its reference count incremented. When the caller is done
- * with the datastore, the reference counted needs to be decremented using ao2_ref().
- *
- * \param subscription The subscription from which to retrieve the datastore
- * \param name The name of the datastore to retrieve
- * \retval NULL Failed to find the specified datastore
- * \retval non-NULL The specified datastore
- */
-struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name);
- 
-/*!
- * \brief Remove a subscription datastore from the subscription
- *
- * This operation may cause the datastore's free() callback to be called if the reference
- * count reaches zero.
- *
- * \param subscription The subscription to remove the datastore from
- * \param name The name of the datastore to remove
- */
-void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name);
-
 /*!
  * \brief Data for responses to SUBSCRIBEs and NOTIFIEs
  *
@@ -292,9 +51,9 @@
  * with data so that they can craft a response rather than have
  * us create our own response.
  *
- * The entire structure is itself optional, since the framework
+ * Filling in the structure is optional, since the framework
  * will automatically respond with a 200 OK response if we do
- * not provide it with any data.
+ * not provide it with any additional data.
  */
 struct ast_sip_subscription_response_data {
     /*! Status code of the response */
@@ -306,7 +65,270 @@
     /*! Optional body to add to the response */
     struct ast_sip_body *body;
 };
- 
+
+#define AST_SIP_MAX_ACCEPT 32
+
+struct ast_sip_subscription_handler {
+    /*! The name of the event this handler deals with */
+    const char *event_name;
+    /*! The types of body this handler accepts */
+    const char *accept[AST_SIP_MAX_ACCEPT];
+ 
+    /*!
+     * \brief Called when a subscription is to be destroyed
+     *
+     * This is a subscriber and notifier callback.
+     *
+     * The handler is not expected to send any sort of requests or responses
+     * during this callback. The handler MUST, however, begin the destruction
+	 * process for the subscription during this callback.
+     */
+   void (*subscription_shutdown)(struct ast_sip_subscription *subscription);
+ 
+    /*!
+     * \brief Called when a SUBSCRIBE arrives in order to create a new subscription
+     *
+     * This is a notifier callback.
+     *
+     * If the notifier wishes to accept the subscription, then it can create
+     * a new ast_sip_subscription to do so. 
+     *
+     * If the notifier chooses to create a new subscription, then it must accept
+     * the incoming subscription using pjsip_evsub_accept() and it must also
+     * send an initial NOTIFY with the current subscription state.
+     *
+     * \param endpoint The endpoint from which we received the SUBSCRIBE
+     * \param rdata The SUBSCRIBE request
+     * \retval NULL The SUBSCRIBE has not been accepted
+     * \retval non-NULL The newly-created subscription
+     */
+    struct ast_sip_subscription *(*new_subscribe)(struct ast_sip_endpoint *endpoint,
+            pjsip_rx_data *rdata);
+ 
+    /*!
+     * \brief Called when an endpoint renews a subscription.
+     *
+     * This is a notifier callback.
+     *
+     * Because of the way that the PJSIP evsub framework works, it will automatically
+     * send a response to the SUBSCRIBE. However, the subscription handler must send
+	 * a NOTIFY with the current subscription state when this callback is called.
+	 *
+	 * The response_data that is passed into this callback is used to craft what should
+	 * be in the response to the incoming SUBSCRIBE. It is initialized with a 200 status
+	 * code and all other parameters are empty.
+     *
+     * \param sub The subscription that is being renewed
+     * \param rdata The SUBSCRIBE request in question
+	 * \param[out] response_data Data pertaining to the SIP response that should be
+	 * sent to the SUBSCRIBE
+     */
+    void (*resubscribe)(struct ast_sip_subscription *sub,
+            pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data);
+ 
+    /*!
+     * \brief Called when a subscription times out.
+     *
+     * This is a notifier callback
+     *
+     * This indicates that the subscription has timed out. The subscription handler is
+     * expected to send a NOTIFY that terminates the subscription.
+     *
+     * \param sub The subscription that has timed out
+     */
+    void (*subscription_timeout)(struct ast_sip_subscription *sub);
+ 
+    /*!
+     * \brief Called when a subscription is terminated via a SUBSCRIBE or NOTIFY request
+     *
+     * This is a notifier and subscriber callback.
+     *
+     * The PJSIP subscription framework will automatically send the response to the
+     * request. If a notifier receives this callback, then the subscription handler
+	 * is expected to send a final NOTIFY to terminate the subscription.
+     *
+     * \param sub The subscription being terminated
+     * \param rdata The request that terminated the subscription
+     */
+    void (*subscription_terminated)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
+ 
+    /*!
+     * \brief Called when a subscription handler's outbound NOTIFY receives a response
+     *
+     * This is a notifier callback.
+     *
+     * \param sub The subscription
+     * \param rdata The NOTIFY response
+     */
+    void (*notify_response)(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
+ 
+    /*!
+     * \brief Called when a subscription handler receives an inbound NOTIFY
+     *
+     * This is a subscriber callback.
+     *
+     * Because of the way that the PJSIP evsub framework works, it will automatically
+     * send a response to the NOTIFY. By default this will be a 200 OK response, but
+     * this callback can change details of the response by returning response data
+     * to use.
+	 *
+	 * The response_data that is passed into this callback is used to craft what should
+	 * be in the response to the incoming SUBSCRIBE. It is initialized with a 200 status
+	 * code and all other parameters are empty.
+     *
+     * \param sub The subscription
+     * \param rdata The NOTIFY request
+	 * \param[out] response_data Data pertaining to the SIP response that should be
+	 * sent to the SUBSCRIBE
+     */
+    void (*notify_request)(struct ast_sip_subscription *sub,
+            pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data);
+ 
+    /*!
+     * \brief Called when it is time for a subscriber to resubscribe
+     *
+     * This is a subscriber callback.
+     *
+     * The subscriber can reresh the subscription using the pjsip_evsub_initiate()
+     * function.
+     *
+     * \param sub The subscription to refresh
+     * \retval 0 Success
+     * \retval non-zero Failure
+     */
+    int (*refresh_subscription)(struct ast_sip_subscription *sub);
+	AST_LIST_ENTRY(ast_sip_subscription_handler) next;
+};
+
+/*!
+ * \brief Create a new ast_sip_subscription structure
+ *
+ * In most cases the pubsub core will create a general purpose subscription
+ * within PJSIP. However, PJSIP provides enhanced support for the following
+ * event packages:
+ *
+ * presence
+ * message-summary
+ *
+ * If either of these events are handled by the subscription handler, then
+ * the special-purpose event subscriptions will be created within PJSIP,
+ * and it will be expected that your subscription handler make use of the
+ * special PJSIP APIs.
+ *
+ * \param handler The subsription handler for this subscription
+ * \param role Whether we are acting as subscriber or notifier for this subscription
+ * \param endpoint The endpoint involved in this subscription
+ * \param rdata If acting as a notifier, the SUBSCRIBE request that triggered subscription creation
+ */
+struct ast_sip_subscription *ast_sip_create_subscription(const struct ast_sip_subscription_handler *handler,
+        enum ast_sip_subscription_role role, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata);
+ 
+ 
+/*!
+ * \brief Get the endpoint that is associated with this subscription
+ *
+ * This function will increase the reference count of the endpoint. Be sure to
+ * release the reference to it when you are finished with the endpoint.
+ *
+ * \retval NULL Could not get endpoint
+ * \retval non-NULL The endpoint
+ */
+struct ast_sip_endpoint *ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub);
+ 
+/*!
+ * \brief Get the serializer for the subscription
+ *
+ * Tasks that originate outside of a SIP servant thread should get the serializer
+ * and push the task to the serializer.
+ *
+ * \param sub The subscription
+ * \retval NULL Failure
+ * \retval non-NULL The subscription's serializer
+ */
+struct ast_taskprocessor *ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub);
+ 
+/*!
+ * \brief Get the underlying PJSIP evsub structure
+ *
+ * This is useful when wishing to call PJSIP's API calls in order to
+ * create SUBSCRIBEs, NOTIFIES, etc. as well as get subscription state
+ *
+ * This function, as well as all methods called on the pjsip_evsub should
+ * be done in a SIP servant thread.
+ *
+ * \param sub The subscription
+ * \retval NULL Failure
+ * \retval non-NULL The underlying pjsip_evsub
+ */
+pjsip_evsub *ast_sip_subscription_get_evsub(struct ast_sip_subscription *sub);
+ 
+/*!
+ * \brief Send a request created via a PJSIP evsub method
+ *
+ * Callers of this function should take care to do so within a SIP servant
+ * thread.
+ *
+ * \param sub The subscription on which to send the request
+ * \param tdata The request to send
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+int ast_sip_subscription_send_request(struct ast_sip_subscription *sub, pjsip_tx_data *tdata);
+ 
+/*!
+ * \brief Alternative for ast_datastore_alloc()
+ *
+ * There are two major differences between this and ast_datastore_alloc()
+ * 1) This allocates a refcounted object
+ * 2) This will fill in a uid if one is not provided
+ *
+ * DO NOT call ast_datastore_free() on a datastore allocated in this
+ * way since that function will attempt to free the datastore rather
+ * than play nicely with its refcount.
+ *
+ * \param info Callbacks for datastore
+ * \param uid Identifier for datastore
+ * \retval NULL Failed to allocate datastore
+ * \retval non-NULL Newly allocated datastore
+ */
+struct ast_datastore *ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid);
+ 
+/*!
+ * \brief Add a datastore to a SIP subscription
+ *
+ * Note that SIP uses reference counted datastores. The datastore passed into this function
+ * must have been allocated using ao2_alloc() or there will be serious problems.
+ *
+ * \param subscription The ssubscription to add the datastore to
+ * \param datastore The datastore to be added to the subscription
+ * \retval 0 Success
+ * \retval -1 Failure
+ */
+int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore);
+ 
+/*!
+ * \brief Retrieve a subscription datastore
+ *
+ * The datastore retrieved will have its reference count incremented. When the caller is done
+ * with the datastore, the reference counted needs to be decremented using ao2_ref().
+ *
+ * \param subscription The subscription from which to retrieve the datastore
+ * \param name The name of the datastore to retrieve
+ * \retval NULL Failed to find the specified datastore
+ * \retval non-NULL The specified datastore
+ */
+struct ast_datastore *ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name);
+ 
+/*!
+ * \brief Remove a subscription datastore from the subscription
+ *
+ * This operation may cause the datastore's free() callback to be called if the reference
+ * count reaches zero.
+ *
+ * \param subscription The subscription to remove the datastore from
+ * \param name The name of the datastore to remove
+ */
+void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name);
  
 /*!
  * \brief Register a subscription handler

Modified: team/mmichelson/pub_sub/res/res_sip.exports.in
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pub_sub/res/res_sip.exports.in?view=diff&rev=386158&r1=386157&r2=386158
==============================================================================
--- team/mmichelson/pub_sub/res/res_sip.exports.in (original)
+++ team/mmichelson/pub_sub/res/res_sip.exports.in Fri Apr 19 16:59:05 2013
@@ -43,7 +43,6 @@
 		LINKER_SYMBOL_PREFIXast_pjsip_rdata_get_endpoint;
 		LINKER_SYMBOL_PREFIXast_sip_thread_is_servant;
 		LINKER_SYMBOL_PREFIXast_sip_dialog_set_serializer;
-		LINKER_SYMBOL_PREFIXast_sip_dialog_remove_serializer;
 		LINKER_SYMBOL_PREFIXast_sip_dialog_set_endpoint;
 		LINKER_SYMBOL_PREFIXast_sip_dialog_get_endpoint;
 		LINKER_SYMBOL_PREFIXast_sip_retrieve_auths;

Modified: team/mmichelson/pub_sub/res/res_sip/sip_distributor.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pub_sub/res/res_sip/sip_distributor.c?view=diff&rev=386158&r1=386157&r2=386158
==============================================================================
--- team/mmichelson/pub_sub/res/res_sip/sip_distributor.c (original)
+++ team/mmichelson/pub_sub/res/res_sip/sip_distributor.c Fri Apr 19 16:59:05 2013
@@ -40,41 +40,39 @@
 	struct ast_sip_endpoint *endpoint;
 };
 
+/*!
+ * \internal
+ *
+ * \note Call this with the dialog locked
+ */
 static struct distributor_dialog_data *distributor_dialog_data_alloc(pjsip_dialog *dlg)
 {
 	struct distributor_dialog_data *dist;
 
-	pjsip_dlg_inc_lock(dlg);
 	dist = PJ_POOL_ZALLOC_T(dlg->pool, struct distributor_dialog_data);
 	pjsip_dlg_set_mod_data(dlg, distributor_mod.id, dist);
-	pjsip_dlg_dec_lock(dlg);
 
 	return dist;
 }
 
 void ast_sip_dialog_set_serializer(pjsip_dialog *dlg, struct ast_taskprocessor *serializer)
 {
-	struct distributor_dialog_data *dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
+	struct distributor_dialog_data *dist;
+	SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
+	
+	dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
 	if (!dist) {
 		dist = distributor_dialog_data_alloc(dlg);
 	}
 	dist->serializer = serializer;
 }
 
-void ast_sip_dialog_remove_serializer(pjsip_dialog *dlg)
+void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
 {
 	struct distributor_dialog_data *dist;
 	SCOPED_LOCK(lock, dlg, pjsip_dlg_inc_lock, pjsip_dlg_dec_lock);
-
+	
 	dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
-	if (dist) {
-		dist->serializer = NULL;
-	}
-}
-
-void ast_sip_dialog_set_endpoint(pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint)
-{
-	struct distributor_dialog_data *dist = pjsip_dlg_get_mod_data(dlg, distributor_mod.id);
 	if (!dist) {
 		dist = distributor_dialog_data_alloc(dlg);
 	}

Modified: team/mmichelson/pub_sub/res/res_sip_mwi.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pub_sub/res/res_sip_mwi.c?view=diff&rev=386158&r1=386157&r2=386158
==============================================================================
--- team/mmichelson/pub_sub/res/res_sip_mwi.c (original)
+++ team/mmichelson/pub_sub/res/res_sip_mwi.c Fri Apr 19 16:59:05 2013
@@ -46,13 +46,13 @@
 static void mwi_subscription_shutdown(struct ast_sip_subscription *sub);
 static struct ast_sip_subscription *mwi_new_subscribe(struct ast_sip_endpoint *endpoint,
 		pjsip_rx_data *rdata);
-static struct ast_sip_subscription_response_data *mwi_resubscribe(struct ast_sip_subscription *sub,
-		pjsip_rx_data *rdata);
+static void mwi_resubscribe(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+		struct ast_sip_subscription_response_data *response_data);
 static void mwi_subscription_timeout(struct ast_sip_subscription *sub);
 static void mwi_subscription_terminated(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
 static void mwi_notify_response(struct ast_sip_subscription *sub, pjsip_rx_data *rdata);
-static struct ast_sip_subscription_response_data *mwi_notify_request(struct ast_sip_subscription *sub,
-		pjsip_rx_data *rdata);
+static void mwi_notify_request(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+		struct ast_sip_subscription_response_data *response_data);
 static int mwi_refresh_subscription(struct ast_sip_subscription *sub);
 
 static struct ast_sip_subscription_handler mwi_handler = {
@@ -223,6 +223,7 @@
 struct message_accumulator {
 	int old_msgs;
 	int new_msgs;
+	const char *reason;
 };
 
 static int get_message_count(void *obj, void *arg, int flags)
@@ -243,27 +244,37 @@
 	return 0;
 }
 
-static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, pjsip_evsub_state state, const char *reason,
-		const pjsip_media_type *mwi_type, const pj_str_t *body_text)
-{
-	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
-				"endpoint", sub->id), ao2_cleanup);
+struct unsolicited_mwi_data {
+	struct mwi_subscription *sub;
+	struct ast_sip_endpoint *endpoint;
+	pjsip_evsub_state state;
+	const char *reason;
+	const pjsip_media_type *mwi_type;
+	const pj_str_t *body_text;
+};
+
+static int send_unsolicited_mwi_notify_to_contact(void *obj, void *arg, int flags)
+{
+	struct unsolicited_mwi_data *mwi_data = arg;
+	struct mwi_subscription *sub = mwi_data->sub;
+	struct ast_sip_endpoint *endpoint = mwi_data->endpoint;
+	pjsip_evsub_state state = mwi_data->state;
+	const char *reason = mwi_data->reason;
+	const pjsip_media_type *mwi_type = mwi_data->mwi_type;
+	const pj_str_t *body_text = mwi_data->body_text;
+	struct ast_sip_contact *contact = obj;
 	const char *state_name;
+	pjsip_tx_data *tdata;
 	pjsip_msg_body *msg_body;
 	pjsip_sub_state_hdr *sub_state;
 	pjsip_event_hdr *event;
-	pjsip_tx_data *tdata;
 	const pjsip_hdr *allow_events = pjsip_evsub_get_allow_events_hdr(NULL);
 
-	if (!endpoint) {
-		ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because endpoint does not exist\n",
-				sub->id);
-		return;
-	}
-	if (ast_sip_create_request("NOTIFY", NULL, endpoint, NULL, &tdata)) {
-		ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s\n", sub->id);
-		return;
-	}
+	if (ast_sip_create_request("NOTIFY", NULL, endpoint, contact->uri, &tdata)) {
+		ast_log(LOG_WARNING, "Unable to create unsolicited NOTIFY request to endpoint %s URI %s\n", sub->id, contact->uri);
+		return 0;
+	}
+
 	switch (state) {
 	case PJSIP_EVSUB_STATE_ACTIVE:
 		state_name = "active";
@@ -289,6 +300,56 @@
 	msg_body = pjsip_msg_body_create(tdata->pool, &mwi_type->type, &mwi_type->subtype, body_text);
 	tdata->msg->body = msg_body;
 	ast_sip_send_request(tdata, NULL, endpoint);
+
+	return 0;
+}
+
+static void send_unsolicited_mwi_notify(struct mwi_subscription *sub, pjsip_evsub_state state, const char *reason,
+		const pjsip_media_type *mwi_type, const pj_str_t *body_text)
+{
+	RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(),
+				"endpoint", sub->id), ao2_cleanup);
+	char *endpoint_aors;
+	char *aor_name;
+
+	if (!endpoint) {
+		ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because endpoint does not exist\n",
+				sub->id);
+		return;
+	}
+	if (ast_strlen_zero(endpoint->aors)) {
+		ast_log(LOG_WARNING, "Unable to send unsolicited MWI to %s because the endpoint has no"
+				" configured AORs\n", sub->id);
+		return;
+	}
+
+	endpoint_aors = ast_strdupa(endpoint->aors);
+
+	while ((aor_name = strsep(&endpoint_aors, ","))) {
+		RAII_VAR(struct ast_sip_aor *, aor, ast_sip_location_retrieve_aor(aor_name), ao2_cleanup);
+		RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup);
+		struct unsolicited_mwi_data mwi_data = {
+			.sub = sub,
+			.endpoint = endpoint,
+			.state = state,
+			.reason = reason,
+			.mwi_type = mwi_type,
+			.body_text = body_text,
+		};
+
+		if (!aor) {
+			ast_log(LOG_WARNING, "Unable to locate AOR %s for unsolicited MWI\n", aor_name);
+			continue;
+		}
+
+		contacts = ast_sip_location_retrieve_aor_contacts(aor);
+		if (!contacts || (ao2_container_count(contacts) == 0)) {
+			ast_log(LOG_WARNING, "No contacts bound to AOR %s. Cannot send unsolicited MWI.\n", aor_name);
+			continue;
+		}
+
+		ao2_callback(contacts, OBJ_NODATA, send_unsolicited_mwi_notify_to_contact, &mwi_data);
+	}
 }
 
 static void send_mwi_notify(struct mwi_subscription *sub, pjsip_evsub_state state, const char *reason)
@@ -441,14 +502,13 @@
 	return sub->sip_sub;
 }
 
-static struct ast_sip_subscription_response_data *mwi_resubscribe(struct ast_sip_subscription *sub,
-		pjsip_rx_data *rdata)
+static void mwi_resubscribe(struct ast_sip_subscription *sub,
+		pjsip_rx_data *rdata, struct ast_sip_subscription_response_data *response_data)
 {
 	pjsip_tx_data *tdata;
 
 	pjsip_mwi_current_notify(ast_sip_subscription_get_evsub(sub), &tdata);
 	ast_sip_subscription_send_request(sub, tdata);
-	return NULL;
 }
 
 static void mwi_subscription_timeout(struct ast_sip_subscription *sub)
@@ -491,11 +551,10 @@
 	/* We don't really care about NOTIFY responses for the moment */
 }
 
-static struct ast_sip_subscription_response_data *mwi_notify_request(struct ast_sip_subscription *sub,
-		pjsip_rx_data *rdata)
+static void mwi_notify_request(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+		struct ast_sip_subscription_response_data *response_data)
 {
 	ast_log(LOG_WARNING, "Received an MWI NOTIFY request? This should not happen\n");
-	return NULL;
 }
 
 static int mwi_refresh_subscription(struct ast_sip_subscription *sub)
@@ -513,13 +572,29 @@
 	return 0;
 }
 
+static int serialized_cleanup(void *userdata)
+{
+	struct mwi_subscription *mwi_sub = userdata;
+
+	/* This is getting rid of the reference that was added
+	 * just before this serialized task was pushed.
+	 */
+	ao2_cleanup(mwi_sub);
+	/* This is getting rid of the reference held by the
+	 * stasis subscription
+	 */
+	ao2_cleanup(mwi_sub);
+	return 0;
+}
+
 static void mwi_stasis_cb(void *userdata, struct stasis_subscription *sub,
 		struct stasis_topic *topic, struct stasis_message *msg)
 {
 	struct mwi_subscription *mwi_sub = userdata;
 
 	if (stasis_subscription_final_message(sub, msg)) {
-		ao2_cleanup(mwi_sub);
+		ao2_ref(mwi_sub, +1);
+		ast_sip_push_task(NULL, serialized_cleanup, mwi_sub);
 		return;
 	}
 

Modified: team/mmichelson/pub_sub/res/res_sip_pubsub.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pub_sub/res/res_sip_pubsub.c?view=diff&rev=386158&r1=386157&r2=386158
==============================================================================
--- team/mmichelson/pub_sub/res/res_sip_pubsub.c (original)
+++ team/mmichelson/pub_sub/res/res_sip_pubsub.c Fri Apr 19 16:59:05 2013
@@ -88,25 +88,6 @@
 	return strcmp(datastore1->uid, uid2) ? 0 : CMP_MATCH | CMP_STOP;
 }
 
-static int remove_serializer(void *user_data)
-{
-	pjsip_dialog *dlg = user_data;
-
-	/* 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_remove_serializer(dlg);
-	pjsip_dlg_dec_session(dlg, &sub_module);
-
-	return 0;
-}
-
 static void subscription_destructor(void *obj)
 {
 	struct ast_sip_subscription *sub = obj;
@@ -116,11 +97,18 @@
 	ao2_cleanup(sub->datastores);
 	ao2_cleanup(sub->endpoint);
 
-	/* This is pushed into the threadpool since there is no guarantee
-	 * what thread this destructor will get called from
-	 */
 	if (sub->dlg) {
-		ast_sip_push_task_synchronous(NULL, remove_serializer, 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, &sub_module);
 	}
 	ast_taskprocessor_unreference(sub->serializer);
 }
@@ -331,9 +319,21 @@
 	ast_module_ref(ast_module_info->self);
 }
 
+static int handler_exists_for_event_name(const char *event_name)
+{
+	struct ast_sip_subscription_handler *iter;
+	SCOPED_LOCK(lock, &subscription_handlers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
+
+	AST_RWLIST_TRAVERSE(&subscription_handlers, iter, next) {
+		if (!strcmp(iter->event_name, event_name)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
 int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
 {
-	/* TODO Ensure duplicate events can't get registered */
 	pj_str_t event;
 	pj_str_t accept[AST_SIP_MAX_ACCEPT];
 	int i;
@@ -345,6 +345,12 @@
 
 	if (ast_strlen_zero(handler->accept[0])) {
 		ast_log(LOG_ERROR, "Subscription handler must supply at least one 'Accept' format\n");
+		return -1;
+	}
+
+	if (handler_exists_for_event_name(handler->event_name)) {
+		ast_log(LOG_ERROR, "A subscription handler for event %s already exists. Not registering "
+				"new subscription handler\n", handler->event_name);
 		return -1;
 	}
 
@@ -546,44 +552,59 @@
 	}
 }
 
+static int response_data_changed(struct ast_sip_subscription_response_data *response_data)
+{
+	if (response_data->status_code != 200 ||
+			!ast_strlen_zero(response_data->status_text) ||
+			response_data->headers ||
+			response_data->body) {
+		return 1;
+	}
+	return 0;
+}
+
 static void pubsub_on_rx_refresh(pjsip_evsub *evsub, pjsip_rx_data *rdata,
 		int *p_st_code, pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 {
 	struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
-	struct ast_sip_subscription_response_data *response_data;
+	struct ast_sip_subscription_response_data response_data = {
+		.status_code = 200,
+	};
 
 	if (!sub) {
 		return;
 	}
 
-	response_data = sub->handler->resubscribe(sub, rdata);
-
-	if (!response_data) {
+	sub->handler->resubscribe(sub, rdata, &response_data);
+
+	if (!response_data_changed(&response_data)) {
 		return;
 	}
 
 	set_parameters_from_response_data(rdata->tp_info.pool, p_st_code, p_st_text,
-			res_hdr, p_body, response_data);
+			res_hdr, p_body, &response_data);
 }
 
 static void pubsub_on_rx_notify(pjsip_evsub *evsub, pjsip_rx_data *rdata, int *p_st_code,
 		pj_str_t **p_st_text, pjsip_hdr *res_hdr, pjsip_msg_body **p_body)
 {
 	struct ast_sip_subscription *sub = pjsip_evsub_get_mod_data(evsub, sub_module.id);
-	struct ast_sip_subscription_response_data *response_data;
+	struct ast_sip_subscription_response_data response_data = {
+		.status_code = 200,
+	};
 
 	if (!sub|| !sub->handler->notify_request) {
 		return;
 	}
 
-	response_data = sub->handler->notify_request(sub, rdata);
-
-	if (!response_data) {
+	sub->handler->notify_request(sub, rdata, &response_data);
+
+	if (!response_data_changed(&response_data)) {
 		return;
 	}
 
 	set_parameters_from_response_data(rdata->tp_info.pool, p_st_code, p_st_text,
-			res_hdr, p_body, response_data);
+			res_hdr, p_body, &response_data);
 }
 
 static int serialized_pubsub_on_client_refresh(void *userdata)




More information about the asterisk-commits mailing list