[asterisk-commits] mmichelson: branch mmichelson/pubsub_bodies r405987 - in /team/mmichelson/pub...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Jan 20 17:58:17 CST 2014
Author: mmichelson
Date: Mon Jan 20 17:58:12 2014
New Revision: 405987
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=405987
Log:
Get rid of res_pjsip_exten_state.h.
Since exten state providers were replaced with body
generators, the methods and structures previously
provided in this header are no longer required.
Removed:
team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_exten_state.h
Modified:
team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h
team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c
team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c
team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c
team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c
Modified: team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h (original)
+++ team/mmichelson/pubsub_bodies/include/asterisk/res_pjsip_body_generator_types.h Mon Jan 20 17:58:12 2014
@@ -16,6 +16,11 @@
* at the top of the source tree.
*/
+#ifndef _RES_PJSIP_BODY_GENERATOR_TYPES_H
+#define _RES_PJSIP_BODY_GENERATOR_TYPES_H
+
+#include "asterisk/pbx.h"
+
/*!
* \brief structure used for presence XML bodies
*
@@ -24,13 +29,19 @@
* \li application/xpidf+xml
* \li application/cpim-pidf+xml
*/
-struct exten_state_body_generator_data {
- /*! Extension state data. See res_pjsip_exten_state.h */
- struct ast_sip_exten_state_data *exten_data;
+struct ast_sip_exten_state_data {
+ /*! The extension of the current state change */
+ const char *exten;
+ /*! The extension state of the change */
+ enum ast_extension_states exten_state;
+ /*! The presence state of the change */
+ enum ast_presence_state presence_state;
+ /*! Current device state information */
+ struct ao2_container *device_state_info;
/*! Local dialog URI */
- const char *local;
+ char local[PJSIP_MAX_URL_SIZE];
/*! Remote dialog URI */
- const char *remote;
+ char remote[PJSIP_MAX_URL_SIZE];
/*! Allocation pool */
pj_pool_t *pool;
};
@@ -46,3 +57,5 @@
/*! Number of new messages */
int new_msgs;
};
+
+#endif /* _RES_PJSIP_BODY_GENERATOR_TYPES_H */
Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_exten_state.c Mon Jan 20 17:58:12 2014
@@ -31,7 +31,6 @@
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_pubsub.h"
-#include "asterisk/res_pjsip_exten_state.h"
#include "asterisk/res_pjsip_body_generator_types.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
@@ -41,43 +40,6 @@
#define BODY_SIZE 1024
#define EVENT_TYPE_SIZE 50
-
-AST_RWLIST_HEAD_STATIC(providers, ast_sip_exten_state_provider);
-
-/*!
- * \internal
- * \brief Find a provider based on the given accept body type.
- */
-static struct ast_sip_exten_state_provider *provider_by_type(const char *type)
-{
- struct ast_sip_exten_state_provider *i;
- SCOPED_LOCK(lock, &providers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
- AST_RWLIST_TRAVERSE_SAFE_BEGIN(&providers, i, next) {
- if (!strcmp(i->body_type, type)) {
- return i;
- }
- }
- AST_RWLIST_TRAVERSE_SAFE_END;
- return NULL;
-}
-
-/*!
- * \internal
- * \brief Find a provider based on the given accept body types.
- */
-static struct ast_sip_exten_state_provider *provider_by_types(const char *event_name,
- char **types, int count)
-{
- int i;
- struct ast_sip_exten_state_provider *res;
- for (i = 0; i < count; ++i) {
- if ((res = provider_by_type(types[i])) &&
- !strcmp(event_name, res->event_name)) {
- return res;
- }
- }
- return NULL;
-}
/*!
* \brief A subscription for extension state
@@ -105,454 +67,18 @@
enum ast_extension_states last_exten_state;
};
-static void exten_state_subscription_destructor(void *obj)
-{
- struct exten_state_subscription *sub = obj;
- int i;
-
- for (i = 0; i < sub->body_types_count; ++i) {
- ast_free(sub->body_types[i]);
- }
-
- ast_free(sub->body_types);
- ao2_cleanup(sub->sip_sub);
-}
-
-/*!
- * \internal
- * \brief Copies the body types the message wishes to subscribe to.
- */
-static void copy_body_types(pjsip_rx_data *rdata,
- struct exten_state_subscription *exten_state_sub)
-{
- int i;
- pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)
- pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
-
- exten_state_sub->body_types_count = hdr->count;
- exten_state_sub->body_types = ast_malloc(hdr->count * sizeof(char*));
-
- for (i = 0; i < hdr->count; ++i) {
- exten_state_sub->body_types[i] =
- ast_malloc(hdr->values[i].slen * sizeof(char*) + 1);
-
- ast_copy_string(exten_state_sub->body_types[i],
- pj_strbuf(&hdr->values[i]), hdr->values[i].slen + 1);
- }
-}
-
-/*!
- * \internal
- * \brief Initialize the last extension state to something outside
- * its usual states.
- */
-#define INITIAL_LAST_EXTEN_STATE -3
-
-/*!
- * \internal
- * \brief Allocates an exten_state_subscription object.
- *
- * Creates the underlying SIP subscription for the given request. First makes
- * sure that there are registered handler and provider objects available.
- */
-static struct exten_state_subscription *exten_state_subscription_alloc(
- struct ast_sip_endpoint *endpoint, enum ast_sip_subscription_role role, pjsip_rx_data *rdata)
-{
- static const pj_str_t event_name = { "Event", 5 };
- pjsip_event_hdr *hdr = (pjsip_event_hdr*)pjsip_msg_find_hdr_by_name(
- rdata->msg_info.msg, &event_name, NULL);
-
- struct ast_sip_exten_state_provider *provider;
- RAII_VAR(struct exten_state_subscription *, exten_state_sub,
- ao2_alloc(sizeof(*exten_state_sub), exten_state_subscription_destructor), ao2_cleanup);
-
- if (!exten_state_sub) {
- return NULL;
- }
-
- ast_copy_pj_str(exten_state_sub->event_name, &hdr->event_type,
- sizeof(exten_state_sub->event_name));
-
- copy_body_types(rdata, exten_state_sub);
- if (!(provider = provider_by_types(exten_state_sub->event_name,
- exten_state_sub->body_types,
- exten_state_sub->body_types_count))) {
- ast_log(LOG_WARNING, "Unable to locate subscription handler\n");
- return NULL;
- }
-
- if (!(exten_state_sub->sip_sub = ast_sip_create_subscription(
- provider->handler, role, endpoint, rdata))) {
- ast_log(LOG_WARNING, "Unable to create SIP subscription for endpoint %s\n",
- ast_sorcery_object_get_id(endpoint));
- return NULL;
- }
-
- exten_state_sub->last_exten_state = INITIAL_LAST_EXTEN_STATE;
-
- ao2_ref(exten_state_sub, +1);
- return exten_state_sub;
-}
-
-static int exten_state_body_generator_data_init(struct ast_sip_exten_state_data *exten_data,
- const char *local, const char *remote,
- struct exten_state_body_generator_data *gen_data)
-{
- gen_data->pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
- "pidf", 1024, 1024);
-
- if (!gen_data->pool) {
- return -1;
- }
-
- gen_data->local = local;
- gen_data->remote = remote;
- gen_data->exten_data = exten_data;
-
- return 0;
-}
-
-static void exten_state_body_generator_data_release(struct exten_state_body_generator_data *gen_data)
-{
- pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), gen_data->pool);
-}
-
-/*!
- * \internal
- * \brief Create and send a NOTIFY request to the subscriber.
- */
-static void create_send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
- pjsip_evsub_state evsub_state, struct ast_sip_exten_state_data *exten_state_data)
-{
- RAII_VAR(struct ast_str *, body_text, ast_str_create(BODY_SIZE), ast_free_ptr);
- pj_str_t reason_str;
- const pj_str_t *reason_str_ptr = NULL;
- pjsip_tx_data *tdata;
- pjsip_dialog *dlg;
- char local[PJSIP_MAX_URL_SIZE], remote[PJSIP_MAX_URL_SIZE];
- struct ast_sip_body body;
- struct exten_state_body_generator_data gen_data;
-
- body.type = ast_sip_subscription_get_body_type(exten_state_sub->sip_sub);
- body.subtype = ast_sip_subscription_get_body_subtype(exten_state_sub->sip_sub);
-
- dlg = ast_sip_subscription_get_dlg(exten_state_sub->sip_sub);
- ast_copy_pj_str(local, &dlg->local.info_str, sizeof(local));
- ast_copy_pj_str(remote, &dlg->remote.info_str, sizeof(remote));
-
- if (exten_state_body_generator_data_init(exten_state_data, local, remote, &gen_data)) {
- ast_log(LOG_ERROR, "Unable to allocate resources for sending presence NOTIFY request\n");
- return;
- }
-
- if (ast_sip_pubsub_generate_body_content(body.type, body.subtype,
- &gen_data, &body_text)) {
- ast_log(LOG_ERROR, "Unable to create body on NOTIFY request\n");
- goto end;
- }
-
- body.body_text = ast_str_buffer(body_text);
-
- if (reason) {
- pj_cstr(&reason_str, reason);
- reason_str_ptr = &reason_str;
- }
-
- if (pjsip_evsub_notify(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
- evsub_state, NULL, reason_str_ptr, &tdata) != PJ_SUCCESS) {
- ast_log(LOG_WARNING, "Unable to create NOTIFY request\n");
- goto end;
- }
-
- if (ast_sip_add_body(tdata, &body)) {
- ast_log(LOG_WARNING, "Unable to add body to NOTIFY request\n");
- pjsip_tx_data_dec_ref(tdata);
- goto end;
- }
-
- if (ast_sip_subscription_send_request(exten_state_sub->sip_sub, tdata) != PJ_SUCCESS) {
- ast_log(LOG_WARNING, "Unable to send NOTIFY request\n");
- }
-
-end:
- exten_state_body_generator_data_release(&gen_data);
-}
-
-/*!
- * \internal
- * \brief Get device state information and send notification to the subscriber.
- */
-static void send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
- pjsip_evsub_state evsub_state)
-{
- RAII_VAR(struct ao2_container*, info, NULL, ao2_cleanup);
- char *subtype = NULL, *message = NULL;
-
- struct ast_sip_exten_state_data exten_state_data = {
- .exten = exten_state_sub->exten,
- .presence_state = ast_hint_presence_state(NULL, exten_state_sub->context,
- exten_state_sub->exten, &subtype, &message),
- };
-
- if ((exten_state_data.exten_state = ast_extension_state_extended(
- NULL, exten_state_sub->context, exten_state_sub->exten, &info)) < 0) {
-
- ast_log(LOG_WARNING, "Unable to get device hint/info for extension %s\n",
- exten_state_sub->exten);
- return;
- }
-
- exten_state_data.device_state_info = info;
- create_send_notify(exten_state_sub, reason, evsub_state, &exten_state_data);
-}
-
-struct notify_task_data {
- struct ast_sip_exten_state_data exten_state_data;
- struct exten_state_subscription *exten_state_sub;
- pjsip_evsub_state evsub_state;
-};
-
-static void notify_task_data_destructor(void *obj)
-{
- struct notify_task_data *task_data = obj;
-
- ao2_ref(task_data->exten_state_sub, -1);
- ao2_cleanup(task_data->exten_state_data.device_state_info);
-}
-
-static struct notify_task_data *alloc_notify_task_data(char *exten, struct exten_state_subscription *exten_state_sub,
- struct ast_state_cb_info *info)
-{
- struct notify_task_data *task_data =
- ao2_alloc(sizeof(*task_data), notify_task_data_destructor);
-
- if (!task_data) {
- ast_log(LOG_WARNING, "Unable to create notify task data\n");
- return NULL;
- }
-
- task_data->evsub_state = PJSIP_EVSUB_STATE_ACTIVE;
- task_data->exten_state_sub = exten_state_sub;
- task_data->exten_state_sub->last_exten_state = info->exten_state;
- ao2_ref(task_data->exten_state_sub, +1);
-
- task_data->exten_state_data.exten = exten_state_sub->exten;
- task_data->exten_state_data.exten_state = info->exten_state;
- task_data->exten_state_data.presence_state = info->presence_state;
- task_data->exten_state_data.device_state_info = info->device_state_info;
-
- if (task_data->exten_state_data.device_state_info) {
- ao2_ref(task_data->exten_state_data.device_state_info, +1);
- }
-
- if ((info->exten_state == AST_EXTENSION_DEACTIVATED) ||
- (info->exten_state == AST_EXTENSION_REMOVED)) {
- task_data->evsub_state = PJSIP_EVSUB_STATE_TERMINATED;
- ast_log(LOG_WARNING, "Watcher for hint %s %s\n", exten, info->exten_state
- == AST_EXTENSION_REMOVED ? "removed" : "deactivated");
- }
-
- return task_data;
-}
-
-static int notify_task(void *obj)
-{
- RAII_VAR(struct notify_task_data *, task_data, obj, ao2_cleanup);
-
- create_send_notify(task_data->exten_state_sub, task_data->evsub_state ==
- PJSIP_EVSUB_STATE_TERMINATED ? "noresource" : NULL,
- task_data->evsub_state, &task_data->exten_state_data);
- return 0;
-}
-
-/*!
- * \internal
- * \brief Callback for exten/device state changes.
- *
- * Upon state change, send the appropriate notification to the subscriber.
- */
-static int state_changed(char *context, char *exten,
- struct ast_state_cb_info *info, void *data)
-{
- struct notify_task_data *task_data;
- struct exten_state_subscription *exten_state_sub = data;
-
- if (exten_state_sub->last_exten_state == info->exten_state) {
- return 0;
- }
-
- if (!(task_data = alloc_notify_task_data(exten, exten_state_sub, info))) {
- return -1;
- }
-
- /* safe to push this async since we copy the data from info and
- add a ref for the device state info */
- if (ast_sip_push_task(ast_sip_subscription_get_serializer(task_data->exten_state_sub->sip_sub),
- notify_task, task_data)) {
- ao2_cleanup(task_data);
- return -1;
- }
- return 0;
-}
-
-static void state_changed_destroy(int id, void *data)
-{
- struct exten_state_subscription *exten_state_sub = data;
- ao2_cleanup(exten_state_sub);
-}
-
-static struct ast_datastore_info ds_info = { };
-static const char ds_name[] = "exten state datastore";
-
-/*!
- * \internal
- * \brief Add a datastore for exten exten_state_subscription.
- *
- * Adds the exten_state_subscription wrapper object to a datastore so it can be retrieved
- * later based upon its association with the ast_sip_subscription.
- */
-static int add_datastore(struct exten_state_subscription *exten_state_sub)
-{
- RAII_VAR(struct ast_datastore *, datastore,
- ast_sip_subscription_alloc_datastore(&ds_info, ds_name), ao2_cleanup);
-
- if (!datastore) {
- return -1;
- }
-
- datastore->data = exten_state_sub;
- ast_sip_subscription_add_datastore(exten_state_sub->sip_sub, datastore);
- ao2_ref(exten_state_sub, +1);
- return 0;
-}
-
-/*!
- * \internal
- * \brief Get the exten_state_subscription object associated with the given
- * ast_sip_subscription in the datastore.
- */
-static struct exten_state_subscription *get_exten_state_sub(
- struct ast_sip_subscription *sub)
-{
- RAII_VAR(struct ast_datastore *, datastore,
- ast_sip_subscription_get_datastore(sub, ds_name), ao2_cleanup);
-
- return datastore ? datastore->data : NULL;
-}
-
-static void subscription_shutdown(struct ast_sip_subscription *sub)
-{
- struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
- if (!exten_state_sub) {
- return;
- }
-
- ast_extension_state_del(exten_state_sub->id, state_changed);
- ast_sip_subscription_remove_datastore(exten_state_sub->sip_sub, ds_name);
- /* remove data store reference */
- ao2_cleanup(exten_state_sub);
-}
-
+#define DEFAULT_PRESENCE_BODY "application/pidf+xml"
+
+static void subscription_shutdown(struct ast_sip_subscription *sub);
static struct ast_sip_subscription *new_subscribe(struct ast_sip_endpoint *endpoint,
- pjsip_rx_data *rdata)
-{
- pjsip_uri *uri = rdata->msg_info.msg->line.req.uri;
- pjsip_sip_uri *sip_uri = pjsip_uri_get_uri(uri);
- RAII_VAR(struct exten_state_subscription *, exten_state_sub, NULL, ao2_cleanup);
-
- if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
- ast_log(LOG_WARNING, "Attempt to SUBSCRIBE to a non-SIP URI\n");
- return NULL;
- }
-
- if (!(exten_state_sub = exten_state_subscription_alloc(endpoint, AST_SIP_NOTIFIER, rdata))) {
- return NULL;
- }
-
- ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context));
- ast_copy_pj_str(exten_state_sub->exten, &sip_uri->user, sizeof(exten_state_sub->exten));
-
- if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
- exten_state_sub->context, exten_state_sub->exten,
- state_changed, state_changed_destroy, exten_state_sub)) < 0) {
- ast_log(LOG_WARNING, "Unable to subscribe endpoint '%s' to extension '%s@%s'\n",
- ast_sorcery_object_get_id(endpoint), exten_state_sub->exten,
- exten_state_sub->context);
- pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
- return NULL;
- }
-
- /* bump the ref since ast_extension_state_add holds a reference */
- ao2_ref(exten_state_sub, +1);
-
- if (add_datastore(exten_state_sub)) {
- ast_log(LOG_WARNING, "Unable to add to subscription datastore.\n");
- pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
- return NULL;
- }
-
- if (pjsip_evsub_accept(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
- rdata, 200, NULL) != PJ_SUCCESS) {
- ast_log(LOG_WARNING, "Unable to accept the incoming extension state subscription.\n");
- pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
- return NULL;
- }
-
- send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
- return exten_state_sub->sip_sub;
-}
-
+ pjsip_rx_data *rdata);
static void resubscribe(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
- struct ast_sip_subscription_response_data *response_data)
-{
- struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
- if (!exten_state_sub) {
- return;
- }
-
- send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
-}
-
-static void subscription_timeout(struct ast_sip_subscription *sub)
-{
- struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
- if (!exten_state_sub) {
- return;
- }
-
- ast_verbose(VERBOSE_PREFIX_3 "Subscription has timed out.\n");
- send_notify(exten_state_sub, "timeout", PJSIP_EVSUB_STATE_TERMINATED);
-}
-
+ struct ast_sip_subscription_response_data *response_data);
+static void subscription_timeout(struct ast_sip_subscription *sub);
static void subscription_terminated(struct ast_sip_subscription *sub,
- pjsip_rx_data *rdata)
-{
- struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
-
- if (!exten_state_sub) {
- return;
- }
-
- ast_verbose(VERBOSE_PREFIX_3 "Subscription has been terminated.\n");
- send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_TERMINATED);
-}
-
+ pjsip_rx_data *rdata);
static void to_ami(struct ast_sip_subscription *sub,
- struct ast_str **buf)
-{
- struct exten_state_subscription *exten_state_sub =
- get_exten_state_sub(sub);
-
- ast_str_append(buf, 0, "SubscriptionType: extension_state\r\n"
- "Extension: %s\r\nExtensionStates: %s\r\n",
- exten_state_sub->exten, ast_extension_state2str(
- exten_state_sub->last_exten_state));
-}
-
-#define DEFAULT_PRESENCE_BODY "application/pidf+xml"
+ struct ast_str **buf);
struct ast_sip_subscription_handler presence_handler = {
.event_name = "presence",
@@ -566,6 +92,417 @@
.to_ami = to_ami,
};
+static void exten_state_subscription_destructor(void *obj)
+{
+ struct exten_state_subscription *sub = obj;
+ int i;
+
+ for (i = 0; i < sub->body_types_count; ++i) {
+ ast_free(sub->body_types[i]);
+ }
+
+ ast_free(sub->body_types);
+ ao2_cleanup(sub->sip_sub);
+}
+
+/*!
+ * \internal
+ * \brief Copies the body types the message wishes to subscribe to.
+ */
+static void copy_body_types(pjsip_rx_data *rdata,
+ struct exten_state_subscription *exten_state_sub)
+{
+ int i;
+ pjsip_accept_hdr *hdr = (pjsip_accept_hdr*)
+ pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_ACCEPT, NULL);
+
+ exten_state_sub->body_types_count = hdr->count;
+ exten_state_sub->body_types = ast_malloc(hdr->count * sizeof(char*));
+
+ for (i = 0; i < hdr->count; ++i) {
+ exten_state_sub->body_types[i] =
+ ast_malloc(hdr->values[i].slen * sizeof(char*) + 1);
+
+ ast_copy_string(exten_state_sub->body_types[i],
+ pj_strbuf(&hdr->values[i]), hdr->values[i].slen + 1);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Initialize the last extension state to something outside
+ * its usual states.
+ */
+#define INITIAL_LAST_EXTEN_STATE -3
+
+/*!
+ * \internal
+ * \brief Allocates an exten_state_subscription object.
+ *
+ * Creates the underlying SIP subscription for the given request. First makes
+ * sure that there are registered handler and provider objects available.
+ */
+static struct exten_state_subscription *exten_state_subscription_alloc(
+ struct ast_sip_endpoint *endpoint, enum ast_sip_subscription_role role, pjsip_rx_data *rdata)
+{
+ static const pj_str_t event_name = { "Event", 5 };
+ pjsip_event_hdr *hdr = (pjsip_event_hdr*)pjsip_msg_find_hdr_by_name(
+ rdata->msg_info.msg, &event_name, NULL);
+ RAII_VAR(struct exten_state_subscription *, exten_state_sub,
+ ao2_alloc(sizeof(*exten_state_sub), exten_state_subscription_destructor), ao2_cleanup);
+
+ if (!exten_state_sub) {
+ return NULL;
+ }
+
+ ast_copy_pj_str(exten_state_sub->event_name, &hdr->event_type,
+ sizeof(exten_state_sub->event_name));
+
+ copy_body_types(rdata, exten_state_sub);
+
+ if (!(exten_state_sub->sip_sub = ast_sip_create_subscription(
+ &presence_handler, role, endpoint, rdata))) {
+ ast_log(LOG_WARNING, "Unable to create SIP subscription for endpoint %s\n",
+ ast_sorcery_object_get_id(endpoint));
+ return NULL;
+ }
+
+ exten_state_sub->last_exten_state = INITIAL_LAST_EXTEN_STATE;
+
+ ao2_ref(exten_state_sub, +1);
+ return exten_state_sub;
+}
+
+/*!
+ * \internal
+ * \brief Create and send a NOTIFY request to the subscriber.
+ */
+static void create_send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
+ pjsip_evsub_state evsub_state, struct ast_sip_exten_state_data *exten_state_data)
+{
+ RAII_VAR(struct ast_str *, body_text, ast_str_create(BODY_SIZE), ast_free_ptr);
+ pj_str_t reason_str;
+ const pj_str_t *reason_str_ptr = NULL;
+ pjsip_tx_data *tdata;
+ struct ast_sip_body body;
+
+ body.type = ast_sip_subscription_get_body_type(exten_state_sub->sip_sub);
+ body.subtype = ast_sip_subscription_get_body_subtype(exten_state_sub->sip_sub);
+
+ if (ast_sip_pubsub_generate_body_content(body.type, body.subtype,
+ exten_state_data, &body_text)) {
+ ast_log(LOG_ERROR, "Unable to create body on NOTIFY request\n");
+ return;
+ }
+
+ body.body_text = ast_str_buffer(body_text);
+
+ if (reason) {
+ pj_cstr(&reason_str, reason);
+ reason_str_ptr = &reason_str;
+ }
+
+ if (pjsip_evsub_notify(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
+ evsub_state, NULL, reason_str_ptr, &tdata) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Unable to create NOTIFY request\n");
+ return;
+ }
+
+ if (ast_sip_add_body(tdata, &body)) {
+ ast_log(LOG_WARNING, "Unable to add body to NOTIFY request\n");
+ pjsip_tx_data_dec_ref(tdata);
+ return;
+ }
+
+ if (ast_sip_subscription_send_request(exten_state_sub->sip_sub, tdata) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Unable to send NOTIFY request\n");
+ }
+}
+
+/*!
+ * \internal
+ * \brief Get device state information and send notification to the subscriber.
+ */
+static void send_notify(struct exten_state_subscription *exten_state_sub, const char *reason,
+ pjsip_evsub_state evsub_state)
+{
+ RAII_VAR(struct ao2_container*, info, NULL, ao2_cleanup);
+ char *subtype = NULL, *message = NULL;
+ pjsip_dialog *dlg;
+ struct ast_sip_exten_state_data exten_state_data = {
+ .exten = exten_state_sub->exten,
+ .presence_state = ast_hint_presence_state(NULL, exten_state_sub->context,
+ exten_state_sub->exten, &subtype, &message),
+ };
+
+ dlg = ast_sip_subscription_get_dlg(exten_state_sub->sip_sub);
+ ast_copy_pj_str(exten_state_data.local, &dlg->local.info_str,
+ sizeof(exten_state_data.local));
+ ast_copy_pj_str(exten_state_data.remote, &dlg->remote.info_str,
+ sizeof(exten_state_data.remote));
+
+ if ((exten_state_data.exten_state = ast_extension_state_extended(
+ NULL, exten_state_sub->context, exten_state_sub->exten, &info)) < 0) {
+
+ ast_log(LOG_WARNING, "Unable to get device hint/info for extension %s\n",
+ exten_state_sub->exten);
+ return;
+ }
+
+ exten_state_data.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
+ "exten_state", 1024, 1024);
+
+ exten_state_data.device_state_info = info;
+ create_send_notify(exten_state_sub, reason, evsub_state, &exten_state_data);
+ pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), exten_state_data.pool);
+}
+
+struct notify_task_data {
+ struct ast_sip_exten_state_data exten_state_data;
+ struct exten_state_subscription *exten_state_sub;
+ pjsip_evsub_state evsub_state;
+};
+
+static void notify_task_data_destructor(void *obj)
+{
+ struct notify_task_data *task_data = obj;
+
+ ao2_ref(task_data->exten_state_sub, -1);
+ ao2_cleanup(task_data->exten_state_data.device_state_info);
+}
+
+static struct notify_task_data *alloc_notify_task_data(char *exten, struct exten_state_subscription *exten_state_sub,
+ struct ast_state_cb_info *info)
+{
+ struct notify_task_data *task_data =
+ ao2_alloc(sizeof(*task_data), notify_task_data_destructor);
+
+ if (!task_data) {
+ ast_log(LOG_WARNING, "Unable to create notify task data\n");
+ return NULL;
+ }
+
+ task_data->evsub_state = PJSIP_EVSUB_STATE_ACTIVE;
+ task_data->exten_state_sub = exten_state_sub;
+ task_data->exten_state_sub->last_exten_state = info->exten_state;
+ ao2_ref(task_data->exten_state_sub, +1);
+
+ task_data->exten_state_data.exten = exten_state_sub->exten;
+ task_data->exten_state_data.exten_state = info->exten_state;
+ task_data->exten_state_data.presence_state = info->presence_state;
+ task_data->exten_state_data.device_state_info = info->device_state_info;
+
+ if (task_data->exten_state_data.device_state_info) {
+ ao2_ref(task_data->exten_state_data.device_state_info, +1);
+ }
+
+ if ((info->exten_state == AST_EXTENSION_DEACTIVATED) ||
+ (info->exten_state == AST_EXTENSION_REMOVED)) {
+ task_data->evsub_state = PJSIP_EVSUB_STATE_TERMINATED;
+ ast_log(LOG_WARNING, "Watcher for hint %s %s\n", exten, info->exten_state
+ == AST_EXTENSION_REMOVED ? "removed" : "deactivated");
+ }
+
+ return task_data;
+}
+
+static int notify_task(void *obj)
+{
+ RAII_VAR(struct notify_task_data *, task_data, obj, ao2_cleanup);
+
+ create_send_notify(task_data->exten_state_sub, task_data->evsub_state ==
+ PJSIP_EVSUB_STATE_TERMINATED ? "noresource" : NULL,
+ task_data->evsub_state, &task_data->exten_state_data);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Callback for exten/device state changes.
+ *
+ * Upon state change, send the appropriate notification to the subscriber.
+ */
+static int state_changed(char *context, char *exten,
+ struct ast_state_cb_info *info, void *data)
+{
+ struct notify_task_data *task_data;
+ struct exten_state_subscription *exten_state_sub = data;
+
+ if (exten_state_sub->last_exten_state == info->exten_state) {
+ return 0;
+ }
+
+ if (!(task_data = alloc_notify_task_data(exten, exten_state_sub, info))) {
+ return -1;
+ }
+
+ /* safe to push this async since we copy the data from info and
+ add a ref for the device state info */
+ if (ast_sip_push_task(ast_sip_subscription_get_serializer(task_data->exten_state_sub->sip_sub),
+ notify_task, task_data)) {
+ ao2_cleanup(task_data);
+ return -1;
+ }
+ return 0;
+}
+
+static void state_changed_destroy(int id, void *data)
+{
+ struct exten_state_subscription *exten_state_sub = data;
+ ao2_cleanup(exten_state_sub);
+}
+
+static struct ast_datastore_info ds_info = { };
+static const char ds_name[] = "exten state datastore";
+
+/*!
+ * \internal
+ * \brief Add a datastore for exten exten_state_subscription.
+ *
+ * Adds the exten_state_subscription wrapper object to a datastore so it can be retrieved
+ * later based upon its association with the ast_sip_subscription.
+ */
+static int add_datastore(struct exten_state_subscription *exten_state_sub)
+{
+ RAII_VAR(struct ast_datastore *, datastore,
+ ast_sip_subscription_alloc_datastore(&ds_info, ds_name), ao2_cleanup);
+
+ if (!datastore) {
+ return -1;
+ }
+
+ datastore->data = exten_state_sub;
+ ast_sip_subscription_add_datastore(exten_state_sub->sip_sub, datastore);
+ ao2_ref(exten_state_sub, +1);
+ return 0;
+}
+
+/*!
+ * \internal
+ * \brief Get the exten_state_subscription object associated with the given
+ * ast_sip_subscription in the datastore.
+ */
+static struct exten_state_subscription *get_exten_state_sub(
+ struct ast_sip_subscription *sub)
+{
+ RAII_VAR(struct ast_datastore *, datastore,
+ ast_sip_subscription_get_datastore(sub, ds_name), ao2_cleanup);
+
+ return datastore ? datastore->data : NULL;
+}
+
+static void subscription_shutdown(struct ast_sip_subscription *sub)
+{
+ struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+ if (!exten_state_sub) {
+ return;
+ }
+
+ ast_extension_state_del(exten_state_sub->id, state_changed);
+ ast_sip_subscription_remove_datastore(exten_state_sub->sip_sub, ds_name);
+ /* remove data store reference */
+ ao2_cleanup(exten_state_sub);
+}
+
+static struct ast_sip_subscription *new_subscribe(struct ast_sip_endpoint *endpoint,
+ pjsip_rx_data *rdata)
+{
+ pjsip_uri *uri = rdata->msg_info.msg->line.req.uri;
+ pjsip_sip_uri *sip_uri = pjsip_uri_get_uri(uri);
+ RAII_VAR(struct exten_state_subscription *, exten_state_sub, NULL, ao2_cleanup);
+
+ if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) {
+ ast_log(LOG_WARNING, "Attempt to SUBSCRIBE to a non-SIP URI\n");
+ return NULL;
+ }
+
+ if (!(exten_state_sub = exten_state_subscription_alloc(endpoint, AST_SIP_NOTIFIER, rdata))) {
+ return NULL;
+ }
+
+ ast_copy_string(exten_state_sub->context, endpoint->context, sizeof(exten_state_sub->context));
+ ast_copy_pj_str(exten_state_sub->exten, &sip_uri->user, sizeof(exten_state_sub->exten));
+
+ if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
+ exten_state_sub->context, exten_state_sub->exten,
+ state_changed, state_changed_destroy, exten_state_sub)) < 0) {
+ ast_log(LOG_WARNING, "Unable to subscribe endpoint '%s' to extension '%s@%s'\n",
+ ast_sorcery_object_get_id(endpoint), exten_state_sub->exten,
+ exten_state_sub->context);
+ pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
+ return NULL;
+ }
+
+ /* bump the ref since ast_extension_state_add holds a reference */
+ ao2_ref(exten_state_sub, +1);
+
+ if (add_datastore(exten_state_sub)) {
+ ast_log(LOG_WARNING, "Unable to add to subscription datastore.\n");
+ pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
+ return NULL;
+ }
+
+ if (pjsip_evsub_accept(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub),
+ rdata, 200, NULL) != PJ_SUCCESS) {
+ ast_log(LOG_WARNING, "Unable to accept the incoming extension state subscription.\n");
+ pjsip_evsub_terminate(ast_sip_subscription_get_evsub(exten_state_sub->sip_sub), PJ_FALSE);
+ return NULL;
+ }
+
+ send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
+ return exten_state_sub->sip_sub;
+}
+
+static void resubscribe(struct ast_sip_subscription *sub, pjsip_rx_data *rdata,
+ struct ast_sip_subscription_response_data *response_data)
+{
+ struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+ if (!exten_state_sub) {
+ return;
+ }
+
+ send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_ACTIVE);
+}
+
+static void subscription_timeout(struct ast_sip_subscription *sub)
+{
+ struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+ if (!exten_state_sub) {
+ return;
+ }
+
+ ast_verbose(VERBOSE_PREFIX_3 "Subscription has timed out.\n");
+ send_notify(exten_state_sub, "timeout", PJSIP_EVSUB_STATE_TERMINATED);
+}
+
+static void subscription_terminated(struct ast_sip_subscription *sub,
+ pjsip_rx_data *rdata)
+{
+ struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
+
+ if (!exten_state_sub) {
+ return;
+ }
+
+ ast_verbose(VERBOSE_PREFIX_3 "Subscription has been terminated.\n");
+ send_notify(exten_state_sub, NULL, PJSIP_EVSUB_STATE_TERMINATED);
+}
+
+static void to_ami(struct ast_sip_subscription *sub,
+ struct ast_str **buf)
+{
+ struct exten_state_subscription *exten_state_sub =
+ get_exten_state_sub(sub);
+
+ ast_str_append(buf, 0, "SubscriptionType: extension_state\r\n"
+ "Extension: %s\r\nExtensionStates: %s\r\n",
+ exten_state_sub->exten, ast_extension_state2str(
+ exten_state_sub->last_exten_state));
+}
+
static int load_module(void)
{
if (ast_sip_register_subscription_handler(&presence_handler)) {
Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_pidf.c Mon Jan 20 17:58:12 2014
@@ -32,7 +32,6 @@
#include "asterisk/module.h"
#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_exten_state.h"
#include "asterisk/res_pjsip_pubsub.h"
#include "asterisk/res_pjsip_xml.h"
#include "asterisk/res_pjsip_body_generator_types.h"
Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_pidf_body_generator.c Mon Jan 20 17:58:12 2014
@@ -31,7 +31,6 @@
#include "asterisk/module.h"
#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_exten_state.h"
#include "asterisk/res_pjsip_pubsub.h"
#include "asterisk/res_pjsip_xml.h"
#include "asterisk/res_pjsip_body_generator_types.h"
@@ -111,11 +110,11 @@
static void *pidf_allocate_body(void *data)
{
- struct exten_state_body_generator_data *gen_data = data;
+ struct ast_sip_exten_state_data *state_data = data;
pjpidf_pres *pres;
pj_str_t entity;
- pres = pjpidf_create(gen_data->pool, pj_cstr(&entity, gen_data->local));
+ pres = pjpidf_create(state_data->pool, pj_cstr(&entity, state_data->local));
return pres;
}
@@ -128,27 +127,27 @@
int local_state;
char sanitized[PJSIP_MAX_URL_SIZE];
pjpidf_pres *pres = body;
- struct exten_state_body_generator_data *gen_data = data;
-
- exten_state_to_str(gen_data->exten_data->exten_state, &statestring, &pidfstate,
+ struct ast_sip_exten_state_data *state_data = data;
+
+ exten_state_to_str(state_data->exten_state, &statestring, &pidfstate,
&pidfnote, &local_state);
- add_non_standard(gen_data->pool, pres, pidfstate);
-
- if (!pjpidf_pres_add_note(gen_data->pool, pres, pj_cstr(¬e, pidfnote))) {
+ add_non_standard(state_data->pool, pres, pidfstate);
+
+ if (!pjpidf_pres_add_note(state_data->pool, pres, pj_cstr(¬e, pidfnote))) {
ast_log(LOG_WARNING, "Unable to add note to PIDF presence\n");
return -1;
}
- if (!(tuple = pjpidf_pres_add_tuple(gen_data->pool, pres,
- pj_cstr(&id, gen_data->exten_data->exten)))) {
+ if (!(tuple = pjpidf_pres_add_tuple(state_data->pool, pres,
+ pj_cstr(&id, state_data->exten)))) {
ast_log(LOG_WARNING, "Unable to create PIDF tuple\n");
return -1;
}
- sanitize_xml(gen_data->remote, sanitized, sizeof(sanitized));
- pjpidf_tuple_set_contact(gen_data->pool, tuple, pj_cstr(&contact, sanitized));
- pjpidf_tuple_set_contact_prio(gen_data->pool, tuple, pj_cstr(&priority, "1"));
+ sanitize_xml(state_data->remote, sanitized, sizeof(sanitized));
+ pjpidf_tuple_set_contact(state_data->pool, tuple, pj_cstr(&contact, sanitized));
+ pjpidf_tuple_set_contact_prio(state_data->pool, tuple, pj_cstr(&priority, "1"));
pjpidf_status_set_basic_open(pjpidf_tuple_get_status(tuple),
(pidfstate[0] == 'b') || (local_state != NOTIFY_CLOSED));
Modified: team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c
URL: http://svnview.digium.com/svn/asterisk/team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c?view=diff&rev=405987&r1=405986&r2=405987
==============================================================================
--- team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c (original)
+++ team/mmichelson/pubsub_bodies/res/res_pjsip_xpidf_body_generator.c Mon Jan 20 17:58:12 2014
@@ -32,54 +32,53 @@
#include "asterisk/module.h"
#include "asterisk/res_pjsip.h"
-#include "asterisk/res_pjsip_exten_state.h"
#include "asterisk/res_pjsip_pubsub.h"
#include "asterisk/res_pjsip_xml.h"
#include "asterisk/res_pjsip_body_generator_types.h"
static void *xpidf_allocate_body(void *data)
{
- struct exten_state_body_generator_data *gen_data = data;
+ struct ast_sip_exten_state_data *state_data = data;
pjxpidf_pres *pres;
pj_str_t name;
- pres = pjxpidf_create(gen_data->pool, pj_cstr(&name, gen_data->local));
+ pres = pjxpidf_create(state_data->pool, pj_cstr(&name, state_data->local));
return pres;
}
static int xpidf_generate_body_content(void *body, void *data)
{
pjxpidf_pres *pres = body;
- struct exten_state_body_generator_data *gen_data = data;
+ struct ast_sip_exten_state_data *state_data = data;
static pj_str_t STR_ADDR_PARAM = { ";user=ip", 8 };
char *statestring = NULL, *pidfstate = NULL, *pidfnote = NULL;
pj_xml_attr *attr;
int local_state;
pj_str_t name, uri;
- exten_state_to_str(gen_data->exten_data->exten_state, &statestring, &pidfstate,
+ exten_state_to_str(state_data->exten_state, &statestring, &pidfstate,
&pidfnote, &local_state);
- attr = find_node_attr(gen_data->pool, pres, "atom", "id");
- pj_strdup2(gen_data->pool, &attr->value, gen_data->exten_data->exten);
+ attr = find_node_attr(state_data->pool, pres, "atom", "id");
+ pj_strdup2(state_data->pool, &attr->value, state_data->exten);
- attr = find_node_attr(gen_data->pool, pres, "address", "uri");
+ attr = find_node_attr(state_data->pool, pres, "address", "uri");
- uri.ptr = (char*) pj_pool_alloc(gen_data->pool, strlen(gen_data->remote) + STR_ADDR_PARAM.slen);
- pj_strcpy2( &uri, gen_data->remote);
+ uri.ptr = (char*) pj_pool_alloc(state_data->pool, strlen(state_data->remote) + STR_ADDR_PARAM.slen);
+ pj_strcpy2( &uri, state_data->remote);
pj_strcat( &uri, &STR_ADDR_PARAM);
- pj_strdup(gen_data->pool, &attr->value, &uri);
+ pj_strdup(state_data->pool, &attr->value, &uri);
- create_attr(gen_data->pool, pj_xml_find_node(pres, pj_cstr(&name, "address")),
+ create_attr(state_data->pool, pj_xml_find_node(pres, pj_cstr(&name, "address")),
"priority", "0.80000");
- attr = find_node_attr(gen_data->pool, pres, "status", "status");
- pj_strdup2(gen_data->pool, &attr->value,
+ attr = find_node_attr(state_data->pool, pres, "status", "status");
+ pj_strdup2(state_data->pool, &attr->value,
(local_state == NOTIFY_OPEN) ? "open" :
(local_state == NOTIFY_INUSE) ? "inuse" : "closed");
- attr = find_node_attr(gen_data->pool, pres, "msnsubstatus", "substatus");
- pj_strdup2(gen_data->pool, &attr->value,
+ attr = find_node_attr(state_data->pool, pres, "msnsubstatus", "substatus");
+ pj_strdup2(state_data->pool, &attr->value,
(local_state == NOTIFY_OPEN) ? "online" :
(local_state == NOTIFY_INUSE) ? "onthephone" : "offline");
More information about the asterisk-commits
mailing list