[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