[svn-commits] mmichelson: branch mmichelson/rls-rlmi r420059 - in /team/mmichelson/rls-rlmi...
SVN commits to the Digium repositories
svn-commits at lists.digium.com
Tue Aug 5 13:57:11 CDT 2014
Author: mmichelson
Date: Tue Aug 5 13:57:06 2014
New Revision: 420059
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=420059
Log:
Apply changes from the previous rls-rlmi branch.
This is the changeset that is on review board at /r/3741.
Next is to address the review comments.
Modified:
team/mmichelson/rls-rlmi/include/asterisk/res_pjsip_pubsub.h
team/mmichelson/rls-rlmi/res/res_pjsip_pubsub.c
Modified: team/mmichelson/rls-rlmi/include/asterisk/res_pjsip_pubsub.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/rls-rlmi/include/asterisk/res_pjsip_pubsub.h?view=diff&rev=420059&r1=420058&r2=420059
==============================================================================
--- team/mmichelson/rls-rlmi/include/asterisk/res_pjsip_pubsub.h (original)
+++ team/mmichelson/rls-rlmi/include/asterisk/res_pjsip_pubsub.h Tue Aug 5 13:57:06 2014
@@ -332,10 +332,9 @@
/*!
* \brief Notify a SIP subscription of a state change.
*
- * This will create a NOTIFY body to be sent out for the subscribed resource.
- * On real subscriptions, a NOTIFY request will be generated and sent.
- * On virtual subscriptions, the NOTIFY is saved on the virtual subscription and the
- * parent subscription is alerted.
+ * This tells the pubsub core that the state of a subscribed resource has changed.
+ * The pubsub core will generate an appropriate NOTIFY request to send to the
+ * subscriber.
*
* \param sub The subscription on which a state change is occurring.
* \param notify_data Event package-specific data used to create the NOTIFY body.
@@ -348,7 +347,7 @@
/*!
* \brief Retrieve the local URI for this subscription
*
- * This is the local URI as determined by the underlying SIP dialog.
+ * This is the local URI of the subscribed resource.
*
* \param sub The subscription
* \param[out] buf The buffer into which to store the URI.
Modified: team/mmichelson/rls-rlmi/res/res_pjsip_pubsub.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/rls-rlmi/res/res_pjsip_pubsub.c?view=diff&rev=420059&r1=420058&r2=420059
==============================================================================
--- team/mmichelson/rls-rlmi/res/res_pjsip_pubsub.c (original)
+++ team/mmichelson/rls-rlmi/res/res_pjsip_pubsub.c Tue Aug 5 13:57:06 2014
@@ -44,6 +44,7 @@
#include "asterisk/manager.h"
#include "asterisk/test.h"
#include "res_pjsip/include/res_pjsip_private.h"
+#include "asterisk/res_pjsip_presence_xml.h"
/*** DOCUMENTATION
<manager name="PJSIPShowSubscriptionsInbound" language="en_US">
@@ -409,6 +410,12 @@
int body_changed;
/*! The current state of the subscription */
pjsip_evsub_state subscription_state;
+ /*! For lists, the current version to place in the RLMI body */
+ unsigned int version;
+ /*! For lists, indicates if full state should always be communicated. */
+ unsigned int full_state;
+ /*! URI associated with the subscription */
+ pjsip_sip_uri *uri;
/*! Name of resource being subscribed to */
char resource[0];
};
@@ -593,21 +600,22 @@
static struct ast_sip_pubsub_body_generator *subscription_get_generator_from_rdata(pjsip_rx_data *rdata,
const struct ast_sip_subscription_handler *handler)
{
- pjsip_accept_hdr *accept_header;
+ pjsip_accept_hdr *accept_header = (pjsip_accept_hdr *) &rdata->msg_info.msg->hdr;
char accept[AST_SIP_MAX_ACCEPT][64];
size_t num_accept_headers = 0;
- accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, rdata->msg_info.msg->hdr.next);
- if (accept_header) {
+ while ((accept_header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, accept_header->next))) {
int i;
for (i = 0; i < accept_header->count; ++i) {
if (!exceptional_accept(&accept_header->values[i])) {
- ast_copy_pj_str(accept[i], &accept_header->values[i], sizeof(accept[i]));
+ ast_copy_pj_str(accept[num_accept_headers], &accept_header->values[i], sizeof(accept[num_accept_headers]));
++num_accept_headers;
}
}
- } else {
+ }
+
+ if (num_accept_headers == 0) {
/* If a SUBSCRIBE contains no Accept headers, then we must assume that
* the default accept type for the event package is to be used.
*/
@@ -625,6 +633,7 @@
*/
struct tree_node {
AST_VECTOR(, struct tree_node *) children;
+ unsigned int full_state;
char resource[0];
};
@@ -664,10 +673,11 @@
*
* \param resource The name of the resource for this tree node.
* \param visited The vector of resources that have been visited.
+ * \param if allocating a list, indicate whether full state is requested in notifications.
* \retval NULL Allocation failure.
* \retval non-NULL The newly-allocated tree_node
*/
-static struct tree_node *tree_node_alloc(const char *resource, struct resources *visited)
+static struct tree_node *tree_node_alloc(const char *resource, struct resources *visited, unsigned int full_state)
{
struct tree_node *node;
@@ -681,6 +691,7 @@
ast_free(node);
return NULL;
}
+ node->full_state = full_state;
if (visited) {
AST_VECTOR_APPEND(visited, resource);
@@ -772,7 +783,7 @@
if (!child_list) {
int resp = handler->notifier->new_subscribe(endpoint, resource);
if (PJSIP_IS_STATUS_IN_CLASS(resp, 200)) {
- current = tree_node_alloc(resource, visited);
+ current = tree_node_alloc(resource, visited, 0);
if (!current) {
ast_debug(1, "Subscription to leaf resource %s was successful, but encountered"
"allocation error afterwards\n", resource);
@@ -787,7 +798,7 @@
}
} else {
ast_debug(1, "Resource %s (child of %s) is a list\n", resource, parent->resource);
- current = tree_node_alloc(resource, visited);
+ current = tree_node_alloc(resource, visited, child_list->full_state);
if (!current) {
ast_debug(1, "Cannot build children of resource %s due to allocation failure\n", resource);
continue;
@@ -870,7 +881,7 @@
list = retrieve_resource_list(resource, handler->event_name);
if (!list) {
ast_debug(1, "Subscription to resource %s is not to a list\n", resource);
- tree->root = tree_node_alloc(resource, NULL);
+ tree->root = tree_node_alloc(resource, NULL, 0);
if (!tree->root) {
return 500;
}
@@ -882,7 +893,7 @@
return 500;
}
- tree->root = tree_node_alloc(resource, &visited);
+ tree->root = tree_node_alloc(resource, &visited, list->full_state);
if (!tree->root) {
return 500;
}
@@ -968,7 +979,7 @@
{
struct ast_sip_subscription *sub = obj;
- ast_debug(3, "Destroying SIP subscription\n");
+ ast_debug(3, "Destroying SIP subscription to resource %s\n", sub->resource);
ao2_cleanup(sub->datastores);
}
@@ -977,6 +988,7 @@
const char *resource, struct sip_subscription_tree *tree)
{
struct ast_sip_subscription *sub;
+ pjsip_sip_uri *contact_uri;
sub = ao2_alloc(sizeof(*sub) + strlen(resource) + 1, subscription_destructor);
if (!sub) {
@@ -995,6 +1007,11 @@
ao2_ref(sub, -1);
return NULL;
}
+
+ sub->uri = pjsip_sip_uri_create(tree->dlg->pool, PJ_FALSE);
+ contact_uri = pjsip_uri_get_uri(tree->dlg->local.contact->uri);
+ pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, contact_uri);
+ pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
sub->handler = handler;
sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
@@ -1024,6 +1041,7 @@
return NULL;
}
+ sub->full_state = current->full_state;
sub->body_generator = generator;
for (i = 0; i < AST_VECTOR_SIZE(¤t->children); ++i) {
@@ -1045,6 +1063,23 @@
return sub;
}
+static void shutdown_subscriptions(struct ast_sip_subscription *sub)
+{
+ int i;
+
+ if (AST_VECTOR_SIZE(&sub->children) > 0) {
+ for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
+ shutdown_subscriptions(AST_VECTOR_GET(&sub->children, i));
+ ao2_cleanup(AST_VECTOR_GET(&sub->children, i));
+ }
+ return;
+ }
+
+ if (sub->handler->subscription_shutdown) {
+ sub->handler->subscription_shutdown(sub);
+ }
+}
+
static void subscription_tree_destructor(void *obj)
{
struct sip_subscription_tree *sub_tree = obj;
@@ -1055,6 +1090,9 @@
if (sub_tree->dlg) {
ast_sip_push_task_synchronous(NULL, subscription_remove_serializer, sub_tree);
}
+
+ shutdown_subscriptions(sub_tree->root);
+ ao2_cleanup(sub_tree->root);
ast_taskprocessor_unreference(sub_tree->serializer);
remove_subscription(sub_tree);
@@ -1087,6 +1125,7 @@
}
sub_tree->endpoint = ao2_bump(endpoint);
+ sub_tree->notify_sched_id = -1;
add_subscription(sub_tree);
return sub_tree;
@@ -1452,65 +1491,432 @@
return res;
}
-static int generate_list_body(struct ast_sip_subscription *sub, struct ast_str **str)
-{
- /* XXX This is where a multipart/related body would be created with
- * an RLMI part and the bodies of all child parts of the subscription.
- * The generated multipart/related body is then saved on sub->body_text.
- *
- * This will be added when working on ASTERISK-23867. For now, this is
- * just a STUB.
+/*!
+ * \param Create a pseudo-random string of a fixed length.
+ *
+ * This function is useful for generating a string whose randomness
+ * does not need to be across all time and space.
+ *
+ * This is currently used for boundaries and Content-ID
+ * headers for multipart bodies. This is used instead of a UUID
+ * for two main reasons:
+ *
+ * 1) Since it is possible to generate many Content-IDs in a
+ * single multipart body, this is quicker than creating UUIDs.
+ * 2) Since multipart bodies tend to be large, using a smaller
+ * random string than a UUID can reduce the size of the generated
+ * bodies.
+ *
+ * This function will write a null byte at the final position
+ * in the buffer (buf[size - 1]). So if you pass in a size of
+ * 10, then this will generate a random 9-character string.
+ *
+ * \param buf Buffer to write random string into.
+ * \param size The size of the buffer.
+ * \return A pointer to buf
+ */
+static char *generate_random_string(char *buf, size_t size)
+{
+ int i;
+
+ for (i = 0; i < size - 1; ++i) {
+ buf[i] = 'a' + (ast_random() % 26);
+ }
+ buf[i] = '\0';
+
+ return buf;
+}
+
+/*!
+ * \brief Add a resource XML element to an RLMI body
+ *
+ * Each resource element represents a subscribed resource in the list. This function currently
+ * will unconditionally add an instance element to each created resource element. Instance
+ * elements refer to later parts in the multipart body.
+ *
+ * \param pool PJLIB allocation pool
+ * \param cid Content-ID header of the resource
+ * \param resource_name Name of the resource
+ * \param resource_uri URI of the resource
+ * \param state State of the subscribed resource
+ */
+static void add_rlmi_resource(pj_pool_t *pool, pj_xml_node *rlmi, const pjsip_generic_string_hdr *cid,
+ const char *resource_name, const pjsip_sip_uri *resource_uri, pjsip_evsub_state state)
+{
+ static pj_str_t cid_name = { "cid", 3 };
+ pj_xml_node *resource;
+ pj_xml_node *name;
+ pj_xml_node *instance;
+ pj_xml_attr *cid_attr;
+ char id[6];
+ char uri[PJSIP_MAX_URL_SIZE];
+
+ /* This creates a string representing the Content-ID without the enclosing < > */
+ const pj_str_t cid_stripped = {
+ .ptr = cid->hvalue.ptr + 1,
+ .slen = cid->hvalue.slen - 2,
+ };
+
+ resource = ast_sip_presence_xml_create_node(pool, rlmi, "resource");
+ name = ast_sip_presence_xml_create_node(pool, resource, "name");
+ instance = ast_sip_presence_xml_create_node(pool, resource, "instance");
+
+ pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, resource_uri, uri, sizeof(uri));
+ ast_sip_presence_xml_create_attr(pool, resource, "uri", uri);
+
+ pj_strdup2(pool, &name->content, resource_name);
+
+ generate_random_string(id, sizeof(id));
+
+ ast_sip_presence_xml_create_attr(pool, instance, "id", id);
+ ast_sip_presence_xml_create_attr(pool, instance, "state",
+ state == PJSIP_EVSUB_STATE_TERMINATED ? "terminated" : "active");
+
+ /* Use the PJLIB-util XML library directly here since we are using a
+ * pj_str_t
*/
- return 0;
-}
-
-static int generate_notify_body(struct ast_sip_subscription *root, struct ast_str **body_text)
-{
+
+ cid_attr = pj_xml_attr_new(pool, &cid_name, &cid_stripped);
+ pj_xml_add_attr(instance, cid_attr);
+}
+
+/*!
+ * \brief A multipart body part and meta-information
+ *
+ * When creating a multipart body part, the end result (the
+ * pjsip_multipart_part) is hard to inspect without undoing
+ * a lot of what was done to create it. Therefore, we use this
+ * structure to store meta-information about the body part.
+ *
+ * The main consumer of this is the creator of the RLMI body
+ * part of a multipart resource list body.
+ */
+struct body_part {
+ /*! Content-ID header for the body part */
+ pjsip_generic_string_hdr *cid;
+ /*! Subscribed resource represented in the body part */
+ const char *resource;
+ /*! URI for the subscribed body part */
+ pjsip_sip_uri *uri;
+ /*! Subscription state of the resource represented in the body part */
+ pjsip_evsub_state state;
+ /*! The actual body part that will be present in the multipart body */
+ pjsip_multipart_part *part;
+};
+
+/*!
+ * \brief Type declaration for container of body part structures
+ */
+AST_VECTOR(body_part_list, struct body_part *);
+
+/*!
+ * \brief Create a Content-ID header
+ *
+ * Content-ID headers are required by RFC2387 for multipart/related
+ * bodies. They serve as identifiers for each part of the multipart body.
+ *
+ * \param pool PJLIB allocation pool
+ * \param sub Subscription to a resource
+ */
+static pjsip_generic_string_hdr *generate_content_id_hdr(pj_pool_t *pool,
+ const struct ast_sip_subscription *sub)
+{
+ static const pj_str_t cid_name = { "Content-ID", 10 };
+ pjsip_generic_string_hdr *cid;
+ char id[6];
+ size_t alloc_size;
+ pj_str_t cid_value;
+
+ /* '<' + '@' + '>' = 3. pj_str_t does not require a null-terminator */
+ alloc_size = sizeof(id) + pj_strlen(&sub->uri->host) + 3;
+ cid_value.ptr = pj_pool_alloc(pool, alloc_size);
+ cid_value.slen = sprintf(cid_value.ptr, "<%s@%.*s>",
+ generate_random_string(id, sizeof(id)),
+ (int) pj_strlen(&sub->uri->host), pj_strbuf(&sub->uri->host));
+ cid = pjsip_generic_string_hdr_create(pool, &cid_name, &cid_value);
+
+ return cid;
+}
+
+/*!
+ * \brief Create an RLMI body part for a multipart resource list body
+ *
+ * RLMI (Resource list meta information) is a special body type that lists
+ * the subscribed resources and tells subscribers the number of subscribed
+ * resources and what other body parts are in the multipart body. The
+ * RLMI body also has a version number that a subscriber can use to ensure
+ * that the locally-stored state corresponds to server state.
+ *
+ * \param pool The allocation pool
+ * \param sub The subscription representing the subscribed resource list
+ * \param body_parts A container of body parts that RLMI will refer to
+ * \param full_state Indicates whether this is a full or partial state notification
+ * \return The multipart part representing the RLMI body
+ */
+static pjsip_multipart_part *build_rlmi_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
+ struct body_part_list *body_parts, unsigned int full_state)
+{
+ static const pj_str_t rlmi_type = { "application", 11 };
+ static const pj_str_t rlmi_subtype = { "rlmi+xml", 8 };
+ pj_xml_node *rlmi;
+ pj_xml_node *name;
+ pj_str_t rlmi_text;
+ pjsip_multipart_part *rlmi_part;
+ char version_str[32];
+ char uri[PJSIP_MAX_URL_SIZE];
+ char rlmi_str[2048] = { 0,};
+ pjsip_generic_string_hdr *cid;
+ int i;
+
+ rlmi = ast_sip_presence_xml_create_node(pool, NULL, "list");
+ ast_sip_presence_xml_create_attr(pool, rlmi, "xmlns", "urn:ietf:params:xml:ns:rlmi");
+
+ ast_sip_subscription_get_local_uri(sub, uri, sizeof(uri));
+ ast_sip_presence_xml_create_attr(pool, rlmi, "uri", uri);
+
+ snprintf(version_str, sizeof(version_str), "%u", sub->version++);
+ ast_sip_presence_xml_create_attr(pool, rlmi, "version", version_str);
+ ast_sip_presence_xml_create_attr(pool, rlmi, "fullState", full_state ? "true" : "false");
+
+ name = ast_sip_presence_xml_create_node(pool, rlmi, "name");
+ pj_strdup2(pool, &name->content, ast_sip_subscription_get_resource_name(sub));
+
+ for (i = 0; i < AST_VECTOR_SIZE(body_parts); ++i) {
+ const struct body_part *part = AST_VECTOR_GET(body_parts, i);
+
+ add_rlmi_resource(pool, rlmi, part->cid, part->resource, part->uri, part->state);
+ }
+
+ pj_xml_print(rlmi, rlmi_str, sizeof(rlmi_str) - 1, PJ_TRUE);
+ pj_cstr(&rlmi_text, rlmi_str);
+
+ rlmi_part = pjsip_multipart_create_part(pool);
+ rlmi_part->body = pjsip_msg_body_create(pool, &rlmi_type, &rlmi_subtype, &rlmi_text);
+
+ cid = generate_content_id_hdr(pool, sub);
+ pj_list_insert_before(&rlmi_part->hdr, cid);
+
+ return rlmi_part;
+}
+
+static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
+ unsigned int force_full_state);
+
+/*!
+ * \brief Destroy a list of body parts
+ *
+ * \param parts The container of parts to destroy
+ */
+static void free_body_parts(struct body_part_list *parts)
+{
+ int i;
+
+ for (i = 0; i < AST_VECTOR_SIZE(parts); ++i) {
+ struct body_part *part = AST_VECTOR_GET(parts, i);
+ ast_free(part);
+ }
+
+ AST_VECTOR_FREE(parts);
+}
+
+/*!
+ * \brief Allocate and initialize a body part structure
+ *
+ * \param pool PJLIB allocation pool
+ * \param sub Subscription representing a subscribed resource
+ */
+static struct body_part *allocate_body_part(pj_pool_t *pool, const struct ast_sip_subscription *sub)
+{
+ struct body_part *bp;
+
+ bp = ast_calloc(1, sizeof(*bp));
+ if (!bp) {
+ return NULL;
+ }
+
+ bp->cid = generate_content_id_hdr(pool, sub);
+ bp->resource = sub->resource;
+ bp->state = sub->subscription_state;
+ bp->uri = sub->uri;
+
+ return bp;
+}
+
+/*!
+ * \brief Create a multipart body part for a subscribed resource
+ *
+ * \param pool PJLIB allocation pool
+ * \param sub The subscription representing a subscribed resource
+ * \param parts A vector of parts to append the created part to.
+ * \param use_full_state Unused locally, but may be passed to other functions
+ */
+static void build_body_part(pj_pool_t *pool, struct ast_sip_subscription *sub,
+ struct body_part_list *parts, unsigned int use_full_state)
+{
+ struct body_part *bp;
+ pjsip_msg_body *body;
+
+ bp = allocate_body_part(pool, sub);
+ if (!bp) {
+ return;
+ }
+
+ body = generate_notify_body(pool, sub, use_full_state);
+ if (!body) {
+ /* Partial state was requested and the resource has not changed state */
+ ast_free(bp);
+ return;
+ }
+
+ bp->part = pjsip_multipart_create_part(pool);
+ bp->part->body = body;
+ pj_list_insert_before(&bp->part->hdr, bp->cid);
+
+ AST_VECTOR_APPEND(parts, bp);
+}
+
+/*!
+ * \brief Create and initialize the PJSIP multipart body structure for a resource list subscription
+ *
+ * \param pool
+ * \return The multipart message body
+ */
+static pjsip_msg_body *create_multipart_body(pj_pool_t *pool)
+{
+ pjsip_media_type media_type;
+ pjsip_param *media_type_param;
+ char boundary[6];
+ pj_str_t pj_boundary;
+
+ pjsip_media_type_init2(&media_type, "multipart", "related");
+
+ media_type_param = pj_pool_alloc(pool, sizeof(*media_type_param));
+ pj_list_init(media_type_param);
+
+ pj_strdup2(pool, &media_type_param->name, "type");
+ pj_strdup2(pool, &media_type_param->value, "\"application/rlmi+xml\"");
+
+ pj_list_insert_before(&media_type.param, media_type_param);
+
+ pj_cstr(&pj_boundary, generate_random_string(boundary, sizeof(boundary)));
+ return pjsip_multipart_create(pool, &media_type, &pj_boundary);
+}
+
+/*!
+ * \brief Create a resource list body for NOTIFY requests
+ *
+ * Resource list bodies are multipart/related bodies. The first part of the multipart body
+ * is an RLMI body that describes the rest of the parts to come. The other parts of the body
+ * convey state of individual subscribed resources.
+ *
+ * \param pool PJLIB allocation pool
+ * \param sub Subscription details from which to generate body
+ * \param force_full_state If true, ignore resource list settings and send a full state notification
+ * \return The generated multipart/related body
+ */
+static pjsip_msg_body *generate_list_body(pj_pool_t *pool, struct ast_sip_subscription *sub,
+ unsigned int force_full_state)
+{
+ int i;
+ pjsip_multipart_part *rlmi_part;
+ pjsip_msg_body *multipart;
+ struct body_part_list body_parts;
+ unsigned int use_full_state = force_full_state ? 1 : sub->full_state;
+
+ AST_VECTOR_INIT(&body_parts, AST_VECTOR_SIZE(&sub->children));
+
+ for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
+ build_body_part(pool, AST_VECTOR_GET(&sub->children, i), &body_parts, use_full_state);
+ }
+
+ /* This can happen if issuing partial state and no children of the list have changed state */
+ if (AST_VECTOR_SIZE(&body_parts) == 0) {
+ return NULL;
+ }
+
+ multipart = create_multipart_body(pool);
+
+ rlmi_part = build_rlmi_body(pool, sub, &body_parts, use_full_state);
+ pjsip_multipart_add_part(pool, multipart, rlmi_part);
+
+ for (i = 0; i < AST_VECTOR_SIZE(&body_parts); ++i) {
+ pjsip_multipart_add_part(pool, multipart, AST_VECTOR_GET(&body_parts, i)->part);
+ }
+
+ free_body_parts(&body_parts);
+ return multipart;
+}
+
+/*!
+ * \brief Create the body for a NOTIFY request.
+ *
+ * \param pool The pool used for allocations
+ * \param root The root of the subscription tree
+ * \param force_full_state If true, ignore resource list settings and send a full state notification
+ */
+static pjsip_msg_body *generate_notify_body(pj_pool_t *pool, struct ast_sip_subscription *root,
+ unsigned int force_full_state)
+{
+ pjsip_msg_body *body;
+
if (AST_VECTOR_SIZE(&root->children) == 0) {
- /* Not a list. We've already generated the body and saved it on the subscription.
- * Use that directly.
- */
- ast_str_copy_string(body_text, root->body_text);
- root->body_changed = 0;
- return 0;
- }
-
- return generate_list_body(root, body_text);
-}
-
-static int send_notify(struct sip_subscription_tree *sub_tree)
+ if (force_full_state || root->body_changed) {
+ /* Not a list. We've already generated the body and saved it on the subscription.
+ * Use that directly.
+ */
+ pj_str_t type;
+ pj_str_t subtype;
+ pj_str_t text;
+
+ pj_cstr(&type, ast_sip_subscription_get_body_type(root));
+ pj_cstr(&subtype, ast_sip_subscription_get_body_subtype(root));
+ pj_cstr(&text, ast_str_buffer(root->body_text));
+
+ body = pjsip_msg_body_create(pool, &type, &subtype, &text);
+ root->body_changed = 0;
+ } else {
+ body = NULL;
+ }
+ } else {
+ body = generate_list_body(pool, root, force_full_state);
+ }
+
+ return body;
+}
+
+/*!
+ * \brief Shortcut method to create a Require: eventlist header
+ */
+static pjsip_require_hdr *create_require_eventlist(pj_pool_t *pool)
+{
+ pjsip_require_hdr *require;
+
+ require = pjsip_require_hdr_create(pool);
+ pj_strdup2(pool, &require->values[0], "eventlist");
+ require->count = 1;
+
+ return require;
+}
+
+/*!
+ * \brief Send a NOTIFY request to a subscriber
+ *
+ * \param sub_tree The subscription tree representing the subscription
+ * \param force_full_state If true, ignore resource list settings and send full resource list state.
+ * \retval 0 Success
+ * \retval non-zero Failure
+ */
+static int send_notify(struct sip_subscription_tree *sub_tree, unsigned int force_full_state)
{
pjsip_evsub *evsub = sub_tree->evsub;
pjsip_tx_data *tdata;
- struct ast_sip_body body = {
- .type = ast_sip_subscription_get_body_type(sub_tree->root),
- .subtype = ast_sip_subscription_get_body_subtype(sub_tree->root),
- };
- RAII_VAR(struct ast_str *, body_text, ast_str_create(64), ast_free_ptr);
-
- if (!body_text) {
- return -1;
- }
if (pjsip_evsub_notify(evsub, sub_tree->root->subscription_state,
NULL, NULL, &tdata) != PJ_SUCCESS) {
return -1;
}
- if (generate_notify_body(sub_tree->root, &body_text)) {
- pjsip_tx_data_dec_ref(tdata);
- return -1;
- }
-
- body.body_text = ast_str_buffer(body_text);
-
- if (ast_sip_add_body(tdata, &body)) {
- pjsip_tx_data_dec_ref(tdata);
- return -1;
- }
-
if (sip_subscription_send_request(sub_tree, tdata)) {
- ast_free(body_text);
pjsip_tx_data_dec_ref(tdata);
return -1;
}
@@ -1530,19 +1936,20 @@
* bail out here instead of sending the batched NOTIFY.
*/
if (!sub_tree->send_scheduled_notify) {
+ ao2_cleanup(sub_tree);
return 0;
}
- send_notify(sub_tree);
+ send_notify(sub_tree, 0);
ao2_cleanup(sub_tree);
return 0;
}
static int sched_cb(const void *data)
{
- /* Why the #*(@% does the scheduler give us const data?! */
struct sip_subscription_tree *sub_tree = (struct sip_subscription_tree *) data;
+ /* We don't need to bump the refcount of sub_tree since we bumped it when scheduling this task */
ast_sip_push_task(sub_tree->serializer, serialized_send_notify, sub_tree);
return 0;
}
@@ -1579,14 +1986,13 @@
if (sub->tree->notification_batch_interval) {
return schedule_notification(sub->tree);
} else {
- return send_notify(sub->tree);
+ return send_notify(sub->tree, 0);
}
}
void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
{
- pjsip_dialog *dlg = sub->tree->dlg;
- ast_copy_pj_str(buf, &dlg->local.info_str, size);
+ pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, sub->uri, buf, size);
}
void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
@@ -1598,17 +2004,6 @@
const char *ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
{
return sub->resource;
-}
-
-static pjsip_require_hdr *create_require_eventlist(pj_pool_t *pool)
-{
- pjsip_require_hdr *require;
-
- require = pjsip_require_hdr_create(pool);
- pj_strdup2(pool, &require->values[0], "eventlist");
- require->count = 1;
-
- return require;
}
static int sip_subscription_accept(struct sip_subscription_tree *sub_tree, pjsip_rx_data *rdata, int response)
@@ -2020,7 +2415,7 @@
if (generate_initial_notify(sub_tree->root)) {
pjsip_evsub_terminate(sub_tree->evsub, PJ_TRUE);
}
- send_notify(sub_tree);
+ send_notify(sub_tree, 1);
}
resource_tree_destroy(&tree);
@@ -2460,22 +2855,6 @@
return PJ_FALSE;
}
-static void shutdown_subscriptions(struct ast_sip_subscription *sub)
-{
- int i;
-
- if (AST_VECTOR_SIZE(&sub->children) > 0) {
- for (i = 0; i < AST_VECTOR_SIZE(&sub->children); ++i) {
- shutdown_subscriptions(AST_VECTOR_GET(&sub->children, i));
- }
- return;
- }
-
- if (sub->handler->subscription_shutdown) {
- sub->handler->subscription_shutdown(sub);
- }
-}
-
static void pubsub_on_evsub_state(pjsip_evsub *evsub, pjsip_event *event)
{
struct sip_subscription_tree *sub_tree;
@@ -2489,7 +2868,7 @@
return;
}
- shutdown_subscriptions(sub_tree->root);
+ ao2_cleanup(sub_tree);
pjsip_evsub_set_mod_data(evsub, pubsub_module.id, NULL);
}
@@ -2518,7 +2897,7 @@
set_state_terminated(sub_tree->root);
}
- if (send_notify(sub_tree)) {
+ if (send_notify(sub_tree, 1)) {
*p_st_code = 500;
}
@@ -2568,7 +2947,7 @@
struct sip_subscription_tree *sub_tree = userdata;
set_state_terminated(sub_tree->root);
- send_notify(sub_tree);
+ send_notify(sub_tree, 1);
ao2_cleanup(sub_tree);
return 0;
@@ -2864,8 +3243,8 @@
OPT_NOOP_T, 0, 0);
ast_sorcery_object_field_register(sorcery, "resource_list", "event", "",
OPT_CHAR_ARRAY_T, 1, CHARFLDSET(struct resource_list, event));
- ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "0",
- OPT_BOOL_T, 0, FLDSET(struct resource_list, full_state));
+ ast_sorcery_object_field_register(sorcery, "resource_list", "full_state", "no",
+ OPT_BOOL_T, 1, FLDSET(struct resource_list, full_state));
ast_sorcery_object_field_register(sorcery, "resource_list", "notification_batch_interval",
"0", OPT_UINT_T, 0, FLDSET(struct resource_list, notification_batch_interval));
ast_sorcery_object_field_register_custom(sorcery, "resource_list", "list_item",
More information about the svn-commits
mailing list