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:
Joshua C. Colp
2020-01-06 15:02:54 +00:00
committed by Joshua Colp
parent e89c8bc0d2
commit 4e7adbd8f4
3 changed files with 143 additions and 47 deletions

View File

@@ -60,51 +60,15 @@ static void *dialog_info_allocate_body(void *data)
return ast_sip_presence_xml_create_node(state_data->pool, NULL, "dialog-info");
}
static struct ast_datastore *dialog_info_xml_state_find_or_create(struct ao2_container *datastores)
{
struct ast_datastore *datastore = ast_datastores_find(datastores, "dialog-info+xml");
if (datastore) {
return datastore;
}
datastore = ast_datastores_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml");
if (!datastore) {
return NULL;
}
datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state));
if (!datastore->data || ast_datastores_add(datastores, datastore)) {
ao2_ref(datastore, -1);
return NULL;
}
return datastore;
}
static unsigned int dialog_info_xml_get_version(struct ao2_container *datastores, unsigned int *version)
{
struct ast_datastore *datastore = dialog_info_xml_state_find_or_create(datastores);
struct dialog_info_xml_state *state;
if (!datastore) {
return -1;
}
state = datastore->data;
*version = state->version++;
ao2_ref(datastore, -1);
return 0;
}
static int dialog_info_generate_body_content(void *body, void *data)
{
pj_xml_node *dialog_info = body, *dialog, *state;
struct ast_datastore *datastore;
struct dialog_info_xml_state *datastore_state;
struct ast_sip_exten_state_data *state_data = data;
char *local = ast_strdupa(state_data->local), *stripped, *statestring = NULL;
char *pidfstate = NULL, *pidfnote = NULL;
enum ast_sip_pidf_state local_state;
unsigned int version;
char version_str[32], sanitized[PJSIP_MAX_URL_SIZE];
struct ast_sip_endpoint *endpoint = NULL;
unsigned int notify_early_inuse_ringing = 0;
@@ -113,9 +77,35 @@ static int dialog_info_generate_body_content(void *body, void *data)
return -1;
}
if (dialog_info_xml_get_version(state_data->datastores, &version)) {
ast_log(LOG_WARNING, "dialog-info+xml version could not be retrieved from datastore\n");
return -1;
datastore = ast_datastores_find(state_data->datastores, "dialog-info+xml");
if (!datastore) {
const struct ast_json *version_json = NULL;
datastore = ast_datastores_alloc_datastore(&dialog_info_xml_datastore, "dialog-info+xml");
if (!datastore) {
return -1;
}
datastore->data = ast_calloc(1, sizeof(struct dialog_info_xml_state));
if (!datastore->data || ast_datastores_add(state_data->datastores, datastore)) {
ao2_ref(datastore, -1);
return -1;
}
datastore_state = datastore->data;
if (state_data->sub) {
version_json = ast_sip_subscription_get_persistence_data(state_data->sub);
}
if (version_json) {
datastore_state->version = ast_json_integer_get(version_json);
datastore_state->version++;
} else {
datastore_state->version = 0;
}
} else {
datastore_state = datastore->data;
datastore_state->version++;
}
stripped = ast_strip_quoted(local, "<", ">");
@@ -130,9 +120,13 @@ static int dialog_info_generate_body_content(void *body, void *data)
ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "xmlns", "urn:ietf:params:xml:ns:dialog-info");
snprintf(version_str, sizeof(version_str), "%u", version);
snprintf(version_str, sizeof(version_str), "%u", datastore_state->version);
ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "version", version_str);
if (state_data->sub) {
ast_sip_subscription_set_persistence_data(state_data->sub, ast_json_integer_create(datastore_state->version));
}
ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "state", "full");
ast_sip_presence_xml_create_attr(state_data->pool, dialog_info, "entity", sanitized);
@@ -156,6 +150,8 @@ static int dialog_info_generate_body_content(void *body, void *data)
ast_sip_presence_xml_create_attr(state_data->pool, param, "pvalue", "no");
}
ao2_ref(datastore, -1);
return 0;
}