|
|
|
@ -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 */
|
|
|
|
@ -1220,6 +1230,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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1271,6 +1282,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);
|
|
|
|
@ -1469,11 +1488,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) {
|
|
|
|
@ -1514,6 +1532,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;
|
|
|
|
@ -1635,7 +1656,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",
|
|
|
|
@ -1653,7 +1674,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 */
|
|
|
|
@ -2710,6 +2730,28 @@ void ast_sip_publication_remove_datastore(struct ast_sip_publication *publicatio
|
|
|
|
|
ao2_callback(publication->datastores, OBJ_KEY | OBJ_UNLINK | OBJ_NODATA, NULL, (void *) name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
@ -3076,7 +3118,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);
|
|
|
|
@ -4725,6 +4767,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;
|
|
|
|
@ -5599,6 +5674,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);
|
|
|
|
|