mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-12 15:45:18 +00:00
res_pjsip_pubsub: Add ability to persist generator state information.
Some body generators, such as dialog-info+xml, require storing state information which is then conveyed in the NOTIFY request itself. Up until now there was no way for such body generators to persist this information. Two new API calls have been added to allow body generators to set and get persisted data. This data is persisted out alongside the normal persistence information and allows the body generator to restore state information or to simply use this for normal storage of state. State is stored in the form of JSON and it is up to the body generator to interpret this as needed. The dialog-info+xml body generator has been updated to take advantage of this to persist the version number. ASTERISK-27759 Change-Id: I5fda56c624fd13c17b3c48e0319b77079e9e27de
This commit is contained in:
committed by
Joshua Colp
parent
e89c8bc0d2
commit
4e7adbd8f4
@@ -132,6 +132,11 @@
|
||||
and therefore the subscription must be deleted after an asterisk restart.
|
||||
</synopsis>
|
||||
</configOption>
|
||||
<configOption name="generator_data">
|
||||
<synopsis>If set, contains persistence data for all generators of content
|
||||
for the subscription.
|
||||
</synopsis>
|
||||
</configOption>
|
||||
</configObject>
|
||||
<configObject name="resource_list">
|
||||
<synopsis>Resource list configuration parameters.</synopsis>
|
||||
@@ -389,6 +394,8 @@ struct subscription_persistence {
|
||||
char contact_uri[PJSIP_MAX_URL_SIZE];
|
||||
/*! Prune subscription on restart */
|
||||
int prune_on_boot;
|
||||
/*! Body generator specific persistence data */
|
||||
struct ast_json *generator_data;
|
||||
};
|
||||
|
||||
/*!
|
||||
@@ -490,6 +497,8 @@ struct ast_sip_subscription {
|
||||
unsigned int full_state;
|
||||
/*! URI associated with the subscription */
|
||||
pjsip_sip_uri *uri;
|
||||
/*! Data to be persisted with the subscription */
|
||||
struct ast_json *persistence_data;
|
||||
/*! Name of resource being subscribed to */
|
||||
char resource[0];
|
||||
};
|
||||
@@ -615,6 +624,7 @@ static void subscription_persistence_destroy(void *obj)
|
||||
|
||||
ast_free(persistence->endpoint);
|
||||
ast_free(persistence->tag);
|
||||
ast_json_unref(persistence->generator_data);
|
||||
}
|
||||
|
||||
/*! \brief Allocator for subscription persistence */
|
||||
@@ -1198,6 +1208,7 @@ static void destroy_subscription(struct ast_sip_subscription *sub)
|
||||
|
||||
AST_VECTOR_FREE(&sub->children);
|
||||
ao2_cleanup(sub->datastores);
|
||||
ast_json_unref(sub->persistence_data);
|
||||
ast_free(sub);
|
||||
}
|
||||
|
||||
@@ -1248,6 +1259,14 @@ static struct ast_sip_subscription *allocate_subscription(const struct ast_sip_s
|
||||
pjsip_sip_uri_assign(tree->dlg->pool, sub->uri, contact_uri);
|
||||
pj_strdup2(tree->dlg->pool, &sub->uri->user, resource);
|
||||
|
||||
/* If there is any persistence information available for this subscription that was persisted
|
||||
* then make it available so that the NOTIFY has the correct state.
|
||||
*/
|
||||
|
||||
if (tree->persistence && tree->persistence->generator_data) {
|
||||
sub->persistence_data = ast_json_object_get(tree->persistence->generator_data, resource);
|
||||
}
|
||||
|
||||
sub->handler = handler;
|
||||
sub->subscription_state = PJSIP_EVSUB_STATE_ACTIVE;
|
||||
sub->tree = ao2_bump(tree);
|
||||
@@ -1446,11 +1465,10 @@ static struct sip_subscription_tree *allocate_subscription_tree(struct ast_sip_e
|
||||
static struct sip_subscription_tree *create_subscription_tree(const struct ast_sip_subscription_handler *handler,
|
||||
struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *resource,
|
||||
struct ast_sip_pubsub_body_generator *generator, struct resource_tree *tree,
|
||||
pj_status_t *dlg_status)
|
||||
pj_status_t *dlg_status, struct subscription_persistence *persistence)
|
||||
{
|
||||
struct sip_subscription_tree *sub_tree;
|
||||
pjsip_dialog *dlg;
|
||||
struct subscription_persistence *persistence;
|
||||
|
||||
sub_tree = allocate_subscription_tree(endpoint, rdata);
|
||||
if (!sub_tree) {
|
||||
@@ -1491,6 +1509,9 @@ static struct sip_subscription_tree *create_subscription_tree(const struct ast_s
|
||||
|
||||
sub_tree->notification_batch_interval = tree->notification_batch_interval;
|
||||
|
||||
/* Persistence information needs to be available for all the subscriptions */
|
||||
sub_tree->persistence = ao2_bump(persistence);
|
||||
|
||||
sub_tree->root = create_virtual_subscriptions(handler, resource, generator, sub_tree, tree->root);
|
||||
if (AST_VECTOR_SIZE(&sub_tree->root->children) > 0) {
|
||||
sub_tree->is_list = 1;
|
||||
@@ -1612,7 +1633,7 @@ static int sub_persistence_recreate(void *obj)
|
||||
pj_status_t dlg_status;
|
||||
|
||||
sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator,
|
||||
&tree, &dlg_status);
|
||||
&tree, &dlg_status, persistence);
|
||||
if (!sub_tree) {
|
||||
if (dlg_status != PJ_EEXISTS) {
|
||||
ast_log(LOG_WARNING, "Failed recreating '%s' subscription: Could not create subscription tree.\n",
|
||||
@@ -1630,7 +1651,6 @@ static int sub_persistence_recreate(void *obj)
|
||||
ind->sub_tree = ao2_bump(sub_tree);
|
||||
ind->expires = expires_header->ivalue;
|
||||
|
||||
sub_tree->persistence = ao2_bump(persistence);
|
||||
subscription_persistence_update(sub_tree, rdata, SUBSCRIPTION_PERSISTENCE_RECREATED);
|
||||
if (ast_sip_push_task(sub_tree->serializer, initial_notify_task, ind)) {
|
||||
/* Could not send initial subscribe NOTIFY */
|
||||
@@ -2644,6 +2664,28 @@ struct ao2_container *ast_sip_publication_get_datastores(const struct ast_sip_pu
|
||||
return publication->datastores;
|
||||
}
|
||||
|
||||
void ast_sip_subscription_set_persistence_data(struct ast_sip_subscription *subscription, struct ast_json *persistence_data)
|
||||
{
|
||||
ast_json_unref(subscription->persistence_data);
|
||||
subscription->persistence_data = persistence_data;
|
||||
|
||||
if (subscription->tree->persistence) {
|
||||
if (!subscription->tree->persistence->generator_data) {
|
||||
subscription->tree->persistence->generator_data = ast_json_object_create();
|
||||
if (!subscription->tree->persistence->generator_data) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
ast_json_object_set(subscription->tree->persistence->generator_data, subscription->resource,
|
||||
ast_json_ref(persistence_data));
|
||||
}
|
||||
}
|
||||
|
||||
const struct ast_json *ast_sip_subscription_get_persistence_data(const struct ast_sip_subscription *subscription)
|
||||
{
|
||||
return subscription->persistence_data;
|
||||
}
|
||||
|
||||
AST_RWLIST_HEAD_STATIC(publish_handlers, ast_sip_publish_handler);
|
||||
|
||||
static int publication_hash_fn(const void *obj, const int flags)
|
||||
@@ -3005,7 +3047,7 @@ static pj_bool_t pubsub_on_rx_subscribe_request(pjsip_rx_data *rdata)
|
||||
return PJ_TRUE;
|
||||
}
|
||||
|
||||
sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status);
|
||||
sub_tree = create_subscription_tree(handler, endpoint, rdata, resource, generator, &tree, &dlg_status, NULL);
|
||||
if (!sub_tree) {
|
||||
if (dlg_status != PJ_EEXISTS) {
|
||||
pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL);
|
||||
@@ -4657,6 +4699,39 @@ static int persistence_tag_struct2str(const void *obj, const intptr_t *args, cha
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int persistence_generator_data_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||
{
|
||||
struct subscription_persistence *persistence = obj;
|
||||
struct ast_json_error error;
|
||||
|
||||
/* We tolerate a failure of the JSON to load and instead start fresh, since this field
|
||||
* originates from the persistence code and not a user.
|
||||
*/
|
||||
persistence->generator_data = ast_json_load_string(var->value, &error);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int persistence_generator_data_struct2str(const void *obj, const intptr_t *args, char **buf)
|
||||
{
|
||||
const struct subscription_persistence *persistence = obj;
|
||||
char *value;
|
||||
|
||||
if (!persistence->generator_data) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
value = ast_json_dump_string(persistence->generator_data);
|
||||
if (!value) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
*buf = ast_strdup(value);
|
||||
ast_json_free(value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int persistence_expires_str2struct(const struct aco_option *opt, struct ast_variable *var, void *obj)
|
||||
{
|
||||
struct subscription_persistence *persistence = obj;
|
||||
@@ -5529,6 +5604,8 @@ static int load_module(void)
|
||||
CHARFLDSET(struct subscription_persistence, contact_uri));
|
||||
ast_sorcery_object_field_register(sorcery, "subscription_persistence", "prune_on_boot", "no", OPT_YESNO_T, 1,
|
||||
FLDSET(struct subscription_persistence, prune_on_boot));
|
||||
ast_sorcery_object_field_register_custom(sorcery, "subscription_persistence", "generator_data", "",
|
||||
persistence_generator_data_str2struct, persistence_generator_data_struct2str, NULL, 0, 0);
|
||||
|
||||
if (apply_list_configuration(sorcery)) {
|
||||
ast_sched_context_destroy(sched);
|
||||
|
Reference in New Issue
Block a user