Asterisk - The Open Source Telephony Project  GIT-master-a24979a
Data Structures | Macros | Functions | Variables
res_pjsip_exten_state.c File Reference
#include "asterisk.h"
#include <regex.h>
#include <pjsip.h>
#include <pjsip_simple.h>
#include <pjlib.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/res_pjsip_outbound_publish.h"
#include "asterisk/res_pjsip_pubsub.h"
#include "asterisk/res_pjsip_body_generator_types.h"
#include "asterisk/module.h"
#include "asterisk/logger.h"
#include "asterisk/astobj2.h"
#include "asterisk/sorcery.h"
#include "asterisk/app.h"
#include "asterisk/taskprocessor.h"
Include dependency graph for res_pjsip_exten_state.c:

Go to the source code of this file.

Data Structures

struct  exten_state_pub_data
 
struct  exten_state_publisher
 An extension state publisher. More...
 
struct  exten_state_subscription
 A subscription for extension state. More...
 
struct  exten_state_pub_data::name
 
struct  notify_task_data
 

Macros

#define BODY_SIZE   1024
 
#define DEFAULT_DIALOG_BODY   "application/dialog-info+xml"
 
#define DEFAULT_PRESENCE_BODY   "application/pidf+xml"
 
#define EVENT_TYPE_SIZE   50
 
#define INITIAL_LAST_EXTEN_STATE   -3
 
#define PUBLISHER_BUCKETS   31
 The number of buckets to use for storing publishers. More...
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int add_datastore (struct exten_state_subscription *exten_state_sub)
 
static struct notify_task_dataalloc_notify_task_data (const char *exten, struct exten_state_subscription *exten_state_sub, struct ast_state_cb_info *info)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static int build_regex (regex_t *regex, const char *text)
 
static struct ast_sip_exten_state_dataexten_state_data_alloc (struct ast_sip_subscription *sip_sub, struct exten_state_subscription *exten_state_sub)
 
static void exten_state_data_destructor (void *obj)
 
static struct exten_state_pub_dataexten_state_pub_data_alloc (const char *exten, struct ast_state_cb_info *info)
 
static void exten_state_pub_data_destroy (struct exten_state_pub_data *doomed)
 
static int exten_state_publisher_cb (void *data)
 
static int exten_state_publisher_cmp (void *obj, void *arg, int flags)
 Comparator function for extension state publisher. More...
 
static void exten_state_publisher_destroy (void *obj)
 Destructor for extension state publisher. More...
 
static int exten_state_publisher_hash (const void *obj, const int flags)
 Hashing function for extension state publisher. More...
 
static int exten_state_publisher_state_cb (const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
 Global extension state callback function. More...
 
static struct exten_state_subscriptionexten_state_subscription_alloc (struct ast_sip_subscription *sip_sub, struct ast_sip_endpoint *endpoint)
 
static void exten_state_subscription_destructor (void *obj)
 
static struct exten_state_subscriptionget_exten_state_sub (struct ast_sip_subscription *sub)
 
static void * get_notify_data (struct ast_sip_subscription *sub)
 
static int get_resource_display_name (struct ast_sip_endpoint *endpoint, const char *resource, char *display_name, int display_name_size)
 
static char * get_user_agent (const struct ast_sip_subscription *sip_sub)
 
static int load_module (void)
 
static int new_subscribe (struct ast_sip_endpoint *endpoint, const char *resource)
 
static int notify_task (void *obj)
 
static void notify_task_data_destructor (void *obj)
 
static int publisher_start (struct ast_sip_outbound_publish *configuration, struct ast_sip_outbound_publish_client *client)
 
static int publisher_stop (struct ast_sip_outbound_publish_client *client)
 
static int state_changed (const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
 
static void state_changed_destroy (int id, void *data)
 
static int subscription_established (struct ast_sip_subscription *sub)
 
static void subscription_shutdown (struct ast_sip_subscription *sub)
 
static void to_ami (struct ast_sip_subscription *sub, struct ast_str **buf)
 
static int unload_module (void)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Extension State Notifications" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, .requires = "res_pjsip,res_pjsip_pubsub,res_pjsip_outbound_publish", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
struct ast_sip_subscription_handler dialog_handler
 
struct ast_sip_notifier dialog_notifier
 
struct ast_sip_event_publisher_handler dialog_publisher
 
static struct ast_datastore_info ds_info = { }
 
static const char ds_name [] = "exten state datastore"
 
struct ast_sip_subscription_handler presence_handler
 
struct ast_sip_notifier presence_notifier
 
struct ast_sip_event_publisher_handler presence_publisher
 
static struct ast_taskprocessorpublish_exten_state_serializer
 
static struct ao2_containerpublishers
 Container of active outbound extension state publishers. More...
 

Macro Definition Documentation

◆ BODY_SIZE

#define BODY_SIZE   1024

Definition at line 46 of file res_pjsip_exten_state.c.

◆ DEFAULT_DIALOG_BODY

#define DEFAULT_DIALOG_BODY   "application/dialog-info+xml"

Definition at line 114 of file res_pjsip_exten_state.c.

◆ DEFAULT_PRESENCE_BODY

#define DEFAULT_PRESENCE_BODY   "application/pidf+xml"

Definition at line 113 of file res_pjsip_exten_state.c.

◆ EVENT_TYPE_SIZE

#define EVENT_TYPE_SIZE   50

Definition at line 47 of file res_pjsip_exten_state.c.

◆ INITIAL_LAST_EXTEN_STATE

#define INITIAL_LAST_EXTEN_STATE   -3

Definition at line 204 of file res_pjsip_exten_state.c.

◆ PUBLISHER_BUCKETS

#define PUBLISHER_BUCKETS   31

The number of buckets to use for storing publishers.

Definition at line 52 of file res_pjsip_exten_state.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1036 of file res_pjsip_exten_state.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1036 of file res_pjsip_exten_state.c.

◆ add_datastore()

static int add_datastore ( struct exten_state_subscription exten_state_sub)
static

Definition at line 372 of file res_pjsip_exten_state.c.

373 {
374  RAII_VAR(struct ast_datastore *, datastore,
376 
377  if (!datastore) {
378  return -1;
379  }
380 
381  datastore->data = exten_state_sub;
382  ast_sip_subscription_add_datastore(exten_state_sub->sip_sub, datastore);
383  ao2_ref(exten_state_sub, +1);
384  return 0;
385 }
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
static const char ds_name[]
static struct ast_datastore_info ds_info
struct ast_datastore * ast_sip_subscription_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
int ast_sip_subscription_add_datastore(struct ast_sip_subscription *subscription, struct ast_datastore *datastore)
Add a datastore to a SIP subscription.
Structure for a data store object.
Definition: datastore.h:64
struct ast_sip_subscription * sip_sub
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:936

References ao2_cleanup, ao2_ref, ast_sip_subscription_add_datastore(), ast_sip_subscription_alloc_datastore(), ds_info, ds_name, RAII_VAR, and exten_state_subscription::sip_sub.

Referenced by subscription_established().

◆ alloc_notify_task_data()

static struct notify_task_data* alloc_notify_task_data ( const char *  exten,
struct exten_state_subscription exten_state_sub,
struct ast_state_cb_info info 
)
static

Definition at line 254 of file res_pjsip_exten_state.c.

257 {
258  struct notify_task_data *task_data =
260 
261  if (!task_data) {
262  ast_log(LOG_WARNING, "Unable to create notify task data\n");
263  return NULL;
264  }
265 
266  task_data->exten_state_sub = exten_state_sub;
267  task_data->exten_state_sub->last_exten_state = info->exten_state;
268  task_data->exten_state_sub->last_presence_state = info->presence_state;
269  ao2_ref(task_data->exten_state_sub, +1);
270 
271  task_data->exten_state_data.exten = exten_state_sub->exten;
272  task_data->exten_state_data.exten_state = info->exten_state;
273  task_data->exten_state_data.presence_state = info->presence_state;
274  task_data->exten_state_data.presence_subtype = ast_strdup(info->presence_subtype);
275  task_data->exten_state_data.presence_message = ast_strdup(info->presence_message);
276  task_data->exten_state_data.user_agent = ast_strdup(exten_state_sub->user_agent);
277  task_data->exten_state_data.device_state_info = ao2_bump(info->device_state_info);
278  task_data->exten_state_data.sub = exten_state_sub->sip_sub;
279  task_data->exten_state_data.datastores = ast_sip_subscription_get_datastores(exten_state_sub->sip_sub);
280 
281  if ((info->exten_state == AST_EXTENSION_DEACTIVATED) ||
282  (info->exten_state == AST_EXTENSION_REMOVED)) {
283  ast_verb(2, "Watcher for hint %s %s\n", exten, info->exten_state
284  == AST_EXTENSION_REMOVED ? "removed" : "deactivated");
285  task_data->terminate = 1;
286  }
287 
288  return task_data;
289 }
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_log
Definition: astobj2.c:42
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
Definition: astobj2.h:480
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
static char exten[AST_MAX_EXTENSION]
Definition: chan_alsa.c:122
#define ast_verb(level,...)
#define LOG_WARNING
def info(msg)
@ AST_EXTENSION_REMOVED
Definition: pbx.h:62
@ AST_EXTENSION_DEACTIVATED
Definition: pbx.h:63
static void notify_task_data_destructor(void *obj)
struct ao2_container * ast_sip_subscription_get_datastores(const struct ast_sip_subscription *subscription)
Get the datastores container for a subscription.
#define NULL
Definition: resample.c:96
char exten[AST_MAX_EXTENSION]
struct exten_state_subscription * exten_state_sub
userdata associated with baseline taskprocessor test

References ao2_alloc, ao2_bump, ao2_ref, AST_EXTENSION_DEACTIVATED, AST_EXTENSION_REMOVED, ast_log, ast_sip_subscription_get_datastores(), ast_strdup, ast_verb, exten, exten_state_subscription::exten, notify_task_data::exten_state_sub, sip_to_pjsip::info(), LOG_WARNING, notify_task_data_destructor(), NULL, exten_state_subscription::sip_sub, and exten_state_subscription::user_agent.

Referenced by state_changed().

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1036 of file res_pjsip_exten_state.c.

◆ build_regex()

static int build_regex ( regex_t *  regex,
const char *  text 
)
static

Definition at line 846 of file res_pjsip_exten_state.c.

847 {
848  int res;
849 
850  if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
851  size_t len = regerror(res, regex, NULL, 0);
852  char buf[len];
853  regerror(res, regex, buf, len);
854  ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
855  return -1;
856  }
857 
858  return 0;
859 }
char * text
Definition: app_queue.c:1641
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int regex(struct ast_channel *chan, const char *cmd, char *parse, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define LOG_ERROR

References ast_log, buf, len(), LOG_ERROR, NULL, regex(), and text.

Referenced by publisher_start().

◆ exten_state_data_alloc()

static struct ast_sip_exten_state_data* exten_state_data_alloc ( struct ast_sip_subscription sip_sub,
struct exten_state_subscription exten_state_sub 
)
static

Definition at line 506 of file res_pjsip_exten_state.c.

508 {
509  struct ast_sip_exten_state_data *exten_state_data;
510  char *subtype = NULL;
511  char *message = NULL;
512  int presence_state;
513 
514  exten_state_data = ao2_alloc(sizeof(*exten_state_data), exten_state_data_destructor);
515  if (!exten_state_data) {
516  return NULL;
517  }
518 
519  exten_state_data->exten = exten_state_sub->exten;
520  presence_state = ast_hint_presence_state(NULL, exten_state_sub->context, exten_state_sub->exten, &subtype, &message);
522  ao2_cleanup(exten_state_data);
523  return NULL;
524  }
525  exten_state_data->presence_state = presence_state;
526  exten_state_data->presence_subtype = subtype;
527  exten_state_data->presence_message = message;
528  exten_state_data->user_agent = exten_state_sub->user_agent;
529  ast_sip_subscription_get_local_uri(sip_sub, exten_state_data->local,
530  sizeof(exten_state_data->local));
531  ast_sip_subscription_get_remote_uri(sip_sub, exten_state_data->remote,
532  sizeof(exten_state_data->remote));
533  exten_state_data->sub = sip_sub;
534  exten_state_data->datastores = ast_sip_subscription_get_datastores(sip_sub);
535 
536  exten_state_data->exten_state = ast_extension_state_extended(
537  NULL, exten_state_sub->context, exten_state_sub->exten,
538  &exten_state_data->device_state_info);
539  if (exten_state_data->exten_state < 0) {
540  ao2_cleanup(exten_state_data);
541  return NULL;
542  }
543 
544  exten_state_data->pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
545  "exten_state", 1024, 1024);
546  if (!exten_state_data->pool) {
547  ao2_cleanup(exten_state_data);
548  return NULL;
549  }
550 
551  return exten_state_data;
552 }
int ast_hint_presence_state(struct ast_channel *c, const char *context, const char *exten, char **subtype, char **message)
Uses hint and presence state callback to get the presence state of an extension.
Definition: pbx.c:3233
int ast_extension_state_extended(struct ast_channel *c, const char *context, const char *exten, struct ao2_container **device_state_info)
Uses hint and devicestate callback to get the extended state of an extension.
Definition: pbx.c:3183
@ AST_PRESENCE_INVALID
Definition: presencestate.h:39
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:513
static void exten_state_data_destructor(void *obj)
void ast_sip_subscription_get_remote_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
Retrive the remote URI for this subscription.
void ast_sip_subscription_get_local_uri(struct ast_sip_subscription *sub, char *buf, size_t size)
Retrieve the local URI for this subscription.
structure used for presence XML bodies
struct ast_sip_subscription * sub
enum ast_extension_states exten_state
struct ao2_container * device_state_info
enum ast_presence_state presence_state
char context[AST_MAX_CONTEXT]

References ao2_alloc, ao2_cleanup, ast_extension_state_extended(), ast_hint_presence_state(), AST_PRESENCE_INVALID, ast_sip_get_pjsip_endpoint(), ast_sip_subscription_get_datastores(), ast_sip_subscription_get_local_uri(), ast_sip_subscription_get_remote_uri(), exten_state_subscription::context, ast_sip_exten_state_data::datastores, ast_sip_exten_state_data::device_state_info, ast_sip_exten_state_data::exten, exten_state_subscription::exten, ast_sip_exten_state_data::exten_state, exten_state_data_destructor(), ast_sip_exten_state_data::local, NULL, ast_sip_exten_state_data::pool, ast_sip_exten_state_data::presence_message, ast_sip_exten_state_data::presence_state, ast_sip_exten_state_data::presence_subtype, ast_sip_exten_state_data::remote, ast_sip_exten_state_data::sub, ast_sip_exten_state_data::user_agent, and exten_state_subscription::user_agent.

Referenced by get_notify_data().

◆ exten_state_data_destructor()

static void exten_state_data_destructor ( void *  obj)
static

Definition at line 494 of file res_pjsip_exten_state.c.

495 {
496  struct ast_sip_exten_state_data *exten_state_data = obj;
497 
498  ao2_cleanup(exten_state_data->device_state_info);
499  ast_free(exten_state_data->presence_subtype);
500  ast_free(exten_state_data->presence_message);
501  if (exten_state_data->pool) {
502  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), exten_state_data->pool);
503  }
504 }
#define ast_free(a)
Definition: astmm.h:180

References ao2_cleanup, ast_free, ast_sip_get_pjsip_endpoint(), ast_sip_exten_state_data::device_state_info, ast_sip_exten_state_data::pool, ast_sip_exten_state_data::presence_message, and ast_sip_exten_state_data::presence_subtype.

Referenced by exten_state_data_alloc().

◆ exten_state_pub_data_alloc()

static struct exten_state_pub_data* exten_state_pub_data_alloc ( const char *  exten,
struct ast_state_cb_info info 
)
static

Definition at line 606 of file res_pjsip_exten_state.c.

607 {
608  struct exten_state_pub_data *pub_data;
609 
610  pub_data = ast_calloc(1, sizeof(*pub_data));
611  if (!pub_data) {
612  return NULL;
613  }
614 
617  return NULL;
618  }
619 
620  /* Save off currently known information for the body generators. */
621  pub_data->exten_state_data.exten = ast_strdup(exten);
622  pub_data->exten_state_data.exten_state = info->exten_state;
623  pub_data->exten_state_data.presence_state = info->presence_state;
624  pub_data->exten_state_data.presence_subtype = ast_strdup(info->presence_subtype);
625  pub_data->exten_state_data.presence_message = ast_strdup(info->presence_message);
626  pub_data->exten_state_data.device_state_info = ao2_bump(info->device_state_info);
627  if (!pub_data->exten_state_data.exten
628  || !pub_data->exten_state_data.presence_subtype
629  || !pub_data->exten_state_data.presence_message) {
631  return NULL;
632  }
633  return pub_data;
634 }
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:202
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void exten_state_pub_data_destroy(struct exten_state_pub_data *doomed)
struct ast_sip_exten_state_data exten_state_data
struct exten_state_pub_data::name pubs
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

References ao2_bump, ao2_container_count(), ast_calloc, ast_strdup, AST_VECTOR_INIT, ast_sip_exten_state_data::device_state_info, exten, ast_sip_exten_state_data::exten, ast_sip_exten_state_data::exten_state, exten_state_pub_data::exten_state_data, exten_state_pub_data_destroy(), sip_to_pjsip::info(), NULL, ast_sip_exten_state_data::presence_message, ast_sip_exten_state_data::presence_state, ast_sip_exten_state_data::presence_subtype, and exten_state_pub_data::pubs.

Referenced by exten_state_publisher_state_cb().

◆ exten_state_pub_data_destroy()

static void exten_state_pub_data_destroy ( struct exten_state_pub_data doomed)
static

Definition at line 589 of file res_pjsip_exten_state.c.

590 {
591  if (!doomed) {
592  return;
593  }
594 
595  ast_free((void *) doomed->exten_state_data.exten);
599 
600  AST_VECTOR_CALLBACK_VOID(&doomed->pubs, ao2_ref, -1);
601  AST_VECTOR_FREE(&doomed->pubs);
602 
603  ast_free(doomed);
604 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
Definition: vector.h:862

References ao2_cleanup, ao2_ref, ast_free, AST_VECTOR_CALLBACK_VOID, AST_VECTOR_FREE, ast_sip_exten_state_data::device_state_info, ast_sip_exten_state_data::exten, exten_state_pub_data::exten_state_data, ast_sip_exten_state_data::presence_message, ast_sip_exten_state_data::presence_subtype, and exten_state_pub_data::pubs.

Referenced by exten_state_pub_data_alloc(), exten_state_publisher_cb(), and exten_state_publisher_state_cb().

◆ exten_state_publisher_cb()

static int exten_state_publisher_cb ( void *  data)
static

Definition at line 643 of file res_pjsip_exten_state.c.

644 {
645  struct exten_state_pub_data *pub_data = data;
646  struct exten_state_publisher *publisher;
647  size_t idx;
648  struct ast_str *body_text;
649  pj_pool_t *pool;
650  struct ast_sip_body_data gen_data = {
652  .body_data = &pub_data->exten_state_data,
653  };
654  struct ast_sip_body body;
655 
657  if (!body_text) {
659  return 0;
660  }
661 
662  /* Need a PJSIP memory pool to generate the bodies. */
663  pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "pub_state_body",
664  1024, 1024);
665  if (!pool) {
666  ast_log(LOG_WARNING, "Exten state publishing unable to create memory pool\n");
669  return 0;
670  }
671  pub_data->exten_state_data.pool = pool;
672 
673  for (idx = 0; idx < AST_VECTOR_SIZE(&pub_data->pubs); ++idx) {
674  const char *uri;
675  int res;
676 
677  publisher = AST_VECTOR_GET(&pub_data->pubs, idx);
678 
680  pub_data->exten_state_data.local, sizeof(pub_data->exten_state_data.local));
681  if (ast_strlen_zero(uri)) {
682  ast_log(LOG_WARNING, "PUBLISH client '%s' has no from_uri or server_uri defined.\n",
683  publisher->name);
684  continue;
685  }
686 
688  pub_data->exten_state_data.remote, sizeof(pub_data->exten_state_data.remote));
689  if (ast_strlen_zero(uri)) {
690  ast_log(LOG_WARNING, "PUBLISH client '%s' has no to_uri or server_uri defined.\n",
691  publisher->name);
692  continue;
693  }
694 
695  pub_data->exten_state_data.datastores = publisher->datastores;
696 
698  publisher->body_subtype, &gen_data, &body_text);
699  pj_pool_reset(pool);
700  if (res) {
702  "PUBLISH client '%s' unable to generate %s/%s PUBLISH body.\n",
703  publisher->name, publisher->body_type, publisher->body_subtype);
704  continue;
705  }
706 
707  body.type = publisher->body_type;
708  body.subtype = publisher->body_subtype;
709  body.body_text = ast_str_buffer(body_text);
710  ast_sip_publish_client_user_send(publisher->client, pub_data->exten_state_data.exten, &body);
711  }
712 
713  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
714 
717  return 0;
718 }
const char * ast_sip_publish_client_get_user_from_uri(struct ast_sip_outbound_publish_client *client, const char *user, char *uri, size_t size)
Get the From URI the client will use for a specific user.
int ast_sip_publish_client_user_send(struct ast_sip_outbound_publish_client *client, const char *user, const struct ast_sip_body *body)
Send an outgoing PUBLISH message based on the user.
const char * ast_sip_publish_client_get_user_to_uri(struct ast_sip_outbound_publish_client *client, const char *user, char *uri, size_t size)
Get the To URI the client will use for a specific user.
int ast_sip_pubsub_generate_body_content(const char *content_type, const char *content_subtype, struct ast_sip_body_data *data, struct ast_str **str)
Generate body content for a PUBLISH or NOTIFY.
#define AST_SIP_EXTEN_STATE_DATA
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:739
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition: strings.h:640
Data used to create bodies for NOTIFY/PUBLISH requests.
const char * body_type
SIP body description.
Definition: res_pjsip.h:2108
const char * body_text
Definition: res_pjsip.h:2114
Support for dynamic strings.
Definition: strings.h:604
An extension state publisher.
struct ast_sip_outbound_publish_client * client
struct ao2_container * datastores
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References ast_free, ast_log, AST_SIP_EXTEN_STATE_DATA, ast_sip_get_pjsip_endpoint(), ast_sip_publish_client_get_user_from_uri(), ast_sip_publish_client_get_user_to_uri(), ast_sip_publish_client_user_send(), ast_sip_pubsub_generate_body_content(), ast_str_buffer(), ast_str_create, ast_strlen_zero(), AST_VECTOR_GET, AST_VECTOR_SIZE, exten_state_publisher::body_subtype, ast_sip_body::body_text, ast_sip_body_data::body_type, exten_state_publisher::body_type, exten_state_publisher::client, ast_sip_exten_state_data::datastores, exten_state_publisher::datastores, ast_sip_exten_state_data::exten, exten_state_pub_data::exten_state_data, exten_state_pub_data_destroy(), ast_sip_exten_state_data::local, LOG_WARNING, exten_state_publisher::name, ast_sip_exten_state_data::pool, exten_state_pub_data::pubs, ast_sip_exten_state_data::remote, ast_sip_body::subtype, and ast_sip_body::type.

Referenced by exten_state_publisher_state_cb().

◆ exten_state_publisher_cmp()

static int exten_state_publisher_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Comparator function for extension state publisher.

Definition at line 799 of file res_pjsip_exten_state.c.

800 {
801  const struct exten_state_publisher *object_left = obj;
802  const struct exten_state_publisher *object_right = arg;
803  const char *right_key = arg;
804  int cmp;
805 
806  switch (flags & OBJ_SEARCH_MASK) {
807  case OBJ_SEARCH_OBJECT:
808  right_key = object_right->name;
809  /* Fall through */
810  case OBJ_SEARCH_KEY:
811  cmp = strcmp(object_left->name, right_key);
812  break;
814  /* Not supported by container. */
815  ast_assert(0);
816  return 0;
817  default:
818  cmp = 0;
819  break;
820  }
821  if (cmp) {
822  return 0;
823  }
824  return CMP_MATCH;
825 }
@ CMP_MATCH
Definition: astobj2.h:1027
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
#define ast_assert(a)
Definition: utils.h:734

References ast_assert, CMP_MATCH, exten_state_publisher::name, OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, OBJ_SEARCH_OBJECT, and OBJ_SEARCH_PARTIAL_KEY.

◆ exten_state_publisher_destroy()

static void exten_state_publisher_destroy ( void *  obj)
static

Destructor for extension state publisher.

Definition at line 830 of file res_pjsip_exten_state.c.

831 {
832  struct exten_state_publisher *publisher = obj;
833 
834  if (publisher->context_filter) {
835  regfree(&publisher->context_regex);
836  }
837 
838  if (publisher->exten_filter) {
839  regfree(&publisher->exten_regex);
840  }
841 
842  ao2_cleanup(publisher->client);
843  ao2_cleanup(publisher->datastores);
844 }

References ao2_cleanup, exten_state_publisher::client, exten_state_publisher::context_filter, exten_state_publisher::context_regex, exten_state_publisher::datastores, exten_state_publisher::exten_filter, and exten_state_publisher::exten_regex.

Referenced by publisher_start().

◆ exten_state_publisher_hash()

static int exten_state_publisher_hash ( const void *  obj,
const int  flags 
)
static

Hashing function for extension state publisher.

Definition at line 776 of file res_pjsip_exten_state.c.

777 {
778  const struct exten_state_publisher *object;
779  const char *key;
780 
781  switch (flags & OBJ_SEARCH_MASK) {
782  case OBJ_SEARCH_KEY:
783  key = obj;
784  break;
785  case OBJ_SEARCH_OBJECT:
786  object = obj;
787  key = object->name;
788  break;
789  default:
790  ast_assert(0);
791  return 0;
792  }
793  return ast_str_hash(key);
794 }
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1237

References ast_assert, ast_str_hash(), OBJ_SEARCH_KEY, OBJ_SEARCH_MASK, and OBJ_SEARCH_OBJECT.

◆ exten_state_publisher_state_cb()

static int exten_state_publisher_state_cb ( const char *  context,
const char *  exten,
struct ast_state_cb_info info,
void *  data 
)
static

Global extension state callback function.

Definition at line 723 of file res_pjsip_exten_state.c.

724 {
725  struct ao2_iterator publisher_iter;
726  struct exten_state_publisher *publisher;
727  struct exten_state_pub_data *pub_data = NULL;
728 
729  ast_debug(5, "Exten state publisher: %s@%s Reason:%s State:%s Presence:%s Subtype:'%s' Message:'%s'\n",
730  exten, context,
731  info->reason == AST_HINT_UPDATE_DEVICE
732  ? "Device"
733  : info->reason == AST_HINT_UPDATE_PRESENCE
734  ? "Presence"
735  : "Unknown",
736  ast_extension_state2str(info->exten_state),
737  ast_presence_state2str(info->presence_state),
738  S_OR(info->presence_subtype, ""),
739  S_OR(info->presence_message, ""));
740  publisher_iter = ao2_iterator_init(publishers, 0);
741  for (; (publisher = ao2_iterator_next(&publisher_iter)); ao2_ref(publisher, -1)) {
742  if ((publisher->context_filter && regexec(&publisher->context_regex, context, 0, NULL, 0)) ||
743  (publisher->exten_filter && regexec(&publisher->exten_regex, exten, 0, NULL, 0))) {
744  continue;
745  }
746 
747  if (!pub_data) {
749  if (!pub_data) {
750  ao2_ref(publisher, -1);
751  break;
752  }
753  }
754 
755  ao2_ref(publisher, +1);
756  if (AST_VECTOR_APPEND(&pub_data->pubs, publisher)) {
757  ao2_ref(publisher, -1);
758  } else {
759  ast_debug(5, "'%s' will publish exten state\n", publisher->name);
760  }
761  }
762  ao2_iterator_destroy(&publisher_iter);
763 
764  if (pub_data
766  pub_data)) {
768  }
769 
770  return 0;
771 }
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static char context[AST_MAX_CONTEXT]
Definition: chan_alsa.c:120
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition: res_pjsip.c:1933
#define ast_debug(level,...)
Log a DEBUG message.
const char * ast_extension_state2str(int extension_state)
Return string representation of the state of an extension.
Definition: pbx.c:3133
@ AST_HINT_UPDATE_DEVICE
Definition: pbx.h:91
@ AST_HINT_UPDATE_PRESENCE
Definition: pbx.h:93
const char * ast_presence_state2str(enum ast_presence_state state)
Convert presence state to text string for output.
static struct exten_state_pub_data * exten_state_pub_data_alloc(const char *exten, struct ast_state_cb_info *info)
static int exten_state_publisher_cb(void *data)
static struct ast_taskprocessor * publish_exten_state_serializer
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_debug, ast_extension_state2str(), AST_HINT_UPDATE_DEVICE, AST_HINT_UPDATE_PRESENCE, ast_presence_state2str(), ast_sip_push_task(), AST_VECTOR_APPEND, context, exten_state_publisher::context_filter, exten_state_publisher::context_regex, exten, exten_state_publisher::exten_filter, exten_state_publisher::exten_regex, exten_state_pub_data_alloc(), exten_state_pub_data_destroy(), exten_state_publisher_cb(), sip_to_pjsip::info(), exten_state_publisher::name, NULL, publish_exten_state_serializer, exten_state_pub_data::pubs, and S_OR.

Referenced by publisher_start(), and unload_module().

◆ exten_state_subscription_alloc()

static struct exten_state_subscription* exten_state_subscription_alloc ( struct ast_sip_subscription sip_sub,
struct ast_sip_endpoint endpoint 
)
static

Definition at line 213 of file res_pjsip_exten_state.c.

215 {
216  struct exten_state_subscription * exten_state_sub;
217 
218  exten_state_sub = ao2_alloc(sizeof(*exten_state_sub), exten_state_subscription_destructor);
219  if (!exten_state_sub) {
220  return NULL;
221  }
222 
223  exten_state_sub->sip_sub = sip_sub;
224 
225  /* We keep our own reference to the serializer as there is no guarantee in state_changed
226  * that the subscription tree is still valid when it is called. This can occur when
227  * the subscription is terminated at around the same time as the state_changed
228  * callback is invoked.
229  */
231  exten_state_sub->last_exten_state = INITIAL_LAST_EXTEN_STATE;
232  exten_state_sub->last_presence_state = AST_PRESENCE_NOT_SET;
233  exten_state_sub->user_agent = get_user_agent(sip_sub);
234  return exten_state_sub;
235 }
@ AST_PRESENCE_NOT_SET
Definition: presencestate.h:27
static void exten_state_subscription_destructor(void *obj)
#define INITIAL_LAST_EXTEN_STATE
static char * get_user_agent(const struct ast_sip_subscription *sip_sub)
struct ast_taskprocessor * ast_sip_subscription_get_serializer(struct ast_sip_subscription *sub)
Get the serializer for the subscription.
A subscription for extension state.
enum ast_presence_state last_presence_state
enum ast_extension_states last_exten_state
struct ast_taskprocessor * serializer

References ao2_alloc, ao2_bump, AST_PRESENCE_NOT_SET, ast_sip_subscription_get_serializer(), exten_state_subscription_destructor(), get_user_agent(), INITIAL_LAST_EXTEN_STATE, exten_state_subscription::last_exten_state, exten_state_subscription::last_presence_state, NULL, exten_state_subscription::serializer, exten_state_subscription::sip_sub, and exten_state_subscription::user_agent.

Referenced by subscription_established().

◆ exten_state_subscription_destructor()

static void exten_state_subscription_destructor ( void *  obj)
static

Definition at line 173 of file res_pjsip_exten_state.c.

174 {
175  struct exten_state_subscription *sub = obj;
176 
177  ast_free(sub->user_agent);
179  ast_taskprocessor_unreference(sub->serializer);
180 }
struct stasis_forward * sub
Definition: res_corosync.c:240
void ast_sip_subscription_destroy(struct ast_sip_subscription *sub)
Alert the pubsub core that the subscription is ready for destruction.
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.

References ast_free, ast_sip_subscription_destroy(), ast_taskprocessor_unreference(), and sub.

Referenced by exten_state_subscription_alloc().

◆ get_exten_state_sub()

static struct exten_state_subscription* get_exten_state_sub ( struct ast_sip_subscription sub)
static

Definition at line 392 of file res_pjsip_exten_state.c.

394 {
395  RAII_VAR(struct ast_datastore *, datastore,
397 
398  return datastore ? datastore->data : NULL;
399 }
struct ast_datastore * ast_sip_subscription_get_datastore(struct ast_sip_subscription *subscription, const char *name)
Retrieve a subscription datastore.

References ao2_cleanup, ast_sip_subscription_get_datastore(), ds_name, NULL, RAII_VAR, and sub.

Referenced by get_notify_data(), subscription_shutdown(), and to_ami().

◆ get_notify_data()

static void * get_notify_data ( struct ast_sip_subscription sub)
static

Definition at line 554 of file res_pjsip_exten_state.c.

555 {
556  struct exten_state_subscription *exten_state_sub;
557 
558  exten_state_sub = get_exten_state_sub(sub);
559  if (!exten_state_sub) {
560  return NULL;
561  }
562 
563  return exten_state_data_alloc(sub, exten_state_sub);
564 }
static struct ast_sip_exten_state_data * exten_state_data_alloc(struct ast_sip_subscription *sip_sub, struct exten_state_subscription *exten_state_sub)
static struct exten_state_subscription * get_exten_state_sub(struct ast_sip_subscription *sub)

References exten_state_data_alloc(), get_exten_state_sub(), NULL, and sub.

◆ get_resource_display_name()

static int get_resource_display_name ( struct ast_sip_endpoint endpoint,
const char *  resource,
char *  display_name,
int  display_name_size 
)
static

Definition at line 430 of file res_pjsip_exten_state.c.

432 {
433  const char *context;
434 
435  if (!endpoint || ast_strlen_zero(resource) || !display_name || display_name_size <= 0) {
436  return -1;
437  }
438 
439  context = S_OR(endpoint->subscription.context, endpoint->context);
440 
441  if (!ast_get_hint(NULL, 0, display_name, display_name_size, NULL, context, resource)) {
442  ast_log(LOG_NOTICE, "Endpoint '%s': "
443  "Extension '%s' does not exist in context '%s' or has no associated hint\n",
444  ast_sorcery_object_get_id(endpoint), resource, context);
445  return -1;
446  }
447 
448  return 0;
449 }
#define LOG_NOTICE
int ast_get_hint(char *hint, int hintsize, char *name, int namesize, struct ast_channel *c, const char *context, const char *exten)
If an extension hint exists, return non-zero.
Definition: pbx.c:4144
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
const ast_string_field context
Definition: res_pjsip.h:883
struct ast_sip_endpoint_subscription_configuration subscription
Definition: res_pjsip.h:889

References ast_get_hint(), ast_log, ast_sorcery_object_get_id(), ast_strlen_zero(), context, ast_sip_endpoint_subscription_configuration::context, ast_sip_endpoint::context, LOG_NOTICE, NULL, S_OR, and ast_sip_endpoint::subscription.

◆ get_user_agent()

static char* get_user_agent ( const struct ast_sip_subscription sip_sub)
static

Definition at line 182 of file res_pjsip_exten_state.c.

183 {
184  size_t size;
185  char *user_agent = NULL;
186  pjsip_user_agent_hdr *user_agent_hdr = ast_sip_subscription_get_header(
187  sip_sub, "User-Agent");
188 
189  if (!user_agent_hdr) {
190  return NULL;
191  }
192 
193  size = pj_strlen(&user_agent_hdr->hvalue) + 1;
194  user_agent = ast_malloc(size);
195  ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, size);
196  return ast_str_to_lower(user_agent);
197 }
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2035
void * ast_sip_subscription_get_header(const struct ast_sip_subscription *sub, const char *header)
Get a header value for a subscription.
static force_inline char * ast_str_to_lower(char *str)
Convert a string to all lower-case.
Definition: strings.h:1299

References ast_copy_pj_str(), ast_malloc, ast_sip_subscription_get_header(), ast_str_to_lower(), NULL, exten_state_subscription::sip_sub, and exten_state_subscription::user_agent.

Referenced by exten_state_subscription_alloc().

◆ load_module()

static int load_module ( void  )
static

Definition at line 984 of file res_pjsip_exten_state.c.

985 {
988  if (!publishers) {
989  ast_log(LOG_WARNING, "Unable to create container to store extension state publishers\n");
991  }
992 
995  unload_module();
997  }
998 
1000  ast_log(LOG_WARNING, "Unable to register subscription handler %s\n",
1002  unload_module();
1003  return AST_MODULE_LOAD_DECLINE;
1004  }
1005 
1007  ast_log(LOG_WARNING, "Unable to register presence publisher %s\n",
1009  unload_module();
1010  return AST_MODULE_LOAD_DECLINE;
1011  }
1012 
1014  ast_log(LOG_WARNING, "Unable to register subscription handler %s\n",
1016  unload_module();
1017  return AST_MODULE_LOAD_DECLINE;
1018  }
1019 
1021  ast_log(LOG_WARNING, "Unable to register presence publisher %s\n",
1023  unload_module();
1024  return AST_MODULE_LOAD_DECLINE;
1025  }
1026 
1027  return AST_MODULE_LOAD_SUCCESS;
1028 }
@ AO2_ALLOC_OPT_LOCK_MUTEX
Definition: astobj2.h:363
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1303
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Definition: res_pjsip.c:1928
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int exten_state_publisher_hash(const void *obj, const int flags)
Hashing function for extension state publisher.
static int exten_state_publisher_cmp(void *obj, void *arg, int flags)
Comparator function for extension state publisher.
struct ast_sip_event_publisher_handler dialog_publisher
#define PUBLISHER_BUCKETS
The number of buckets to use for storing publishers.
static int unload_module(void)
struct ast_sip_subscription_handler presence_handler
struct ast_sip_event_publisher_handler presence_publisher
struct ast_sip_subscription_handler dialog_handler
int ast_sip_register_event_publisher_handler(struct ast_sip_event_publisher_handler *handler)
Register an event publisher handler.
int ast_sip_register_subscription_handler(struct ast_sip_subscription_handler *handler)
Register a subscription handler.
const char * event_name
The name of the event this handler deals with.

◆ new_subscribe()

static int new_subscribe ( struct ast_sip_endpoint endpoint,
const char *  resource 
)
static

Definition at line 415 of file res_pjsip_exten_state.c.

417 {
418  const char *context = S_OR(endpoint->subscription.context, endpoint->context);
419 
420  if (!ast_exists_extension(NULL, context, resource, PRIORITY_HINT, NULL)) {
421  ast_log(LOG_NOTICE, "Endpoint '%s' state subscription failed: "
422  "Extension '%s' does not exist in context '%s' or has no associated hint\n",
423  ast_sorcery_object_get_id(endpoint), resource, context);
424  return 404;
425  }
426 
427  return 200;
428 }
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
Definition: pbx.c:4182
#define PRIORITY_HINT
Definition: pbx.h:54

References ast_exists_extension(), ast_log, ast_sorcery_object_get_id(), context, ast_sip_endpoint_subscription_configuration::context, ast_sip_endpoint::context, LOG_NOTICE, NULL, PRIORITY_HINT, S_OR, and ast_sip_endpoint::subscription.

◆ notify_task()

static int notify_task ( void *  obj)
static

Definition at line 291 of file res_pjsip_exten_state.c.

292 {
294  struct ast_sip_body_data data = {
296  .body_data = &task_data->exten_state_data,
297  };
298 
299  /* Terminated subscriptions are no longer associated with a valid tree, and sending
300  * NOTIFY messages on a subscription which has already been terminated won't work.
301  */
302  if (ast_sip_subscription_is_terminated(task_data->exten_state_sub->sip_sub)) {
303  return 0;
304  }
305 
306  /* All access to the subscription must occur within a task executed within its serializer */
307  ast_sip_subscription_get_local_uri(task_data->exten_state_sub->sip_sub,
308  task_data->exten_state_data.local, sizeof(task_data->exten_state_data.local));
309  ast_sip_subscription_get_remote_uri(task_data->exten_state_sub->sip_sub,
310  task_data->exten_state_data.remote, sizeof(task_data->exten_state_data.remote));
311 
312  /* Pool allocation has to happen here so that we allocate within a PJLIB thread */
313  task_data->exten_state_data.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
314  "exten_state", 1024, 1024);
315  if (!task_data->exten_state_data.pool) {
316  return -1;
317  }
318 
319  task_data->exten_state_data.sub = task_data->exten_state_sub->sip_sub;
320  task_data->exten_state_data.datastores = ast_sip_subscription_get_datastores(task_data->exten_state_sub->sip_sub);
321 
322  ast_sip_subscription_notify(task_data->exten_state_sub->sip_sub, &data,
323  task_data->terminate);
324 
325  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(),
326  task_data->exten_state_data.pool);
327  return 0;
328 }
int ast_sip_subscription_notify(struct ast_sip_subscription *sub, struct ast_sip_body_data *notify_data, int terminate)
Notify a SIP subscription of a state change.
int ast_sip_subscription_is_terminated(const struct ast_sip_subscription *sub)
Get whether the subscription has been terminated or not.

References ao2_cleanup, AST_SIP_EXTEN_STATE_DATA, ast_sip_get_pjsip_endpoint(), ast_sip_subscription_get_datastores(), ast_sip_subscription_get_local_uri(), ast_sip_subscription_get_remote_uri(), ast_sip_subscription_is_terminated(), ast_sip_subscription_notify(), ast_sip_body_data::body_type, and RAII_VAR.

Referenced by state_changed().

◆ notify_task_data_destructor()

static void notify_task_data_destructor ( void *  obj)
static

Definition at line 243 of file res_pjsip_exten_state.c.

244 {
245  struct notify_task_data *task_data = obj;
246 
247  ao2_ref(task_data->exten_state_sub, -1);
248  ao2_cleanup(task_data->exten_state_data.device_state_info);
249  ast_free(task_data->exten_state_data.presence_subtype);
250  ast_free(task_data->exten_state_data.presence_message);
251  ast_free(task_data->exten_state_data.user_agent);
252 }

References ao2_cleanup, ao2_ref, and ast_free.

Referenced by alloc_notify_task_data().

◆ publisher_start()

static int publisher_start ( struct ast_sip_outbound_publish configuration,
struct ast_sip_outbound_publish_client client 
)
static

Definition at line 861 of file res_pjsip_exten_state.c.

862 {
863  struct exten_state_publisher *publisher;
864  size_t name_size;
865  size_t body_type_size;
866  size_t body_subtype_size;
867  char *body_subtype;
868  const char *body_full;
869  const char *body_type;
870  const char *name;
871  const char *context;
872  const char *exten;
873 
874  name = ast_sorcery_object_get_id(configuration);
875 
876  body_full = ast_sorcery_object_get_extended(configuration, "body");
877  if (ast_strlen_zero(body_full)) {
878  ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Body not set\n",
879  name);
880  return -1;
881  }
882 
883  body_subtype = ast_strdupa(body_full);
884  body_type = strsep(&body_subtype, "/");
886  ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Body '%s' missing type or subtype\n",
887  name, body_full);
888  return -1;
889  }
890 
892  ast_log(LOG_ERROR, "Outbound extension state publisher '%s': '%s' body generator not registered\n",
893  name, body_full);
894  return -1;
895  }
896 
897  name_size = strlen(name) + 1;
898  body_type_size = strlen(body_type) + 1;
899  body_subtype_size = strlen(body_subtype) + 1;
900 
901  publisher = ao2_alloc_options(
902  sizeof(*publisher) + name_size + body_type_size + body_subtype_size,
904  if (!publisher) {
905  return -1;
906  }
907 
908  ast_copy_string(publisher->name, name, name_size);
909  publisher->body_type = publisher->name + name_size;
910  ast_copy_string(publisher->body_type, body_type, body_type_size);
911  publisher->body_subtype = publisher->body_type + body_type_size;
912  ast_copy_string(publisher->body_subtype, body_subtype, body_subtype_size);
913 
914  context = ast_sorcery_object_get_extended(configuration, "context");
915  if (!ast_strlen_zero(context)) {
916  if (build_regex(&publisher->context_regex, context)) {
917  ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not build context filter '%s'\n",
918  name, context);
919  ao2_ref(publisher, -1);
920  return -1;
921  }
922 
923  publisher->context_filter = 1;
924  }
925 
926  exten = ast_sorcery_object_get_extended(configuration, "exten");
927  if (!ast_strlen_zero(exten)) {
928  if (build_regex(&publisher->exten_regex, exten)) {
929  ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not build exten filter '%s'\n",
930  name, exten);
931  ao2_ref(publisher, -1);
932  return -1;
933  }
934 
935  publisher->exten_filter = 1;
936  }
937 
938  publisher->datastores = ast_datastores_alloc();
939  if (!publisher->datastores) {
940  ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not create datastores container\n",
941  name);
942  ao2_ref(publisher, -1);
943  return -1;
944  }
945 
946  publisher->client = ao2_bump(client);
947 
951  }
952  ao2_link_flags(publishers, publisher, OBJ_NOLOCK);
954 
955  ao2_ref(publisher, -1);
956 
957  return 0;
958 }
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_link_flags(container, obj, flags)
Add an object to a container.
Definition: astobj2.h:1554
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
@ OBJ_NOLOCK
Assume that the ao2_container is already locked.
Definition: astobj2.h:1063
struct ao2_container * ast_datastores_alloc(void)
Allocate a specialized data stores container.
Definition: datastore.c:95
static const char name[]
Definition: format_mp3.c:68
char * strsep(char **str, const char *delims)
int ast_extension_state_add(const char *context, const char *exten, ast_state_cb_type change_cb, void *data)
Add watcher for extension states.
Definition: pbx.c:3830
static void exten_state_publisher_destroy(void *obj)
Destructor for extension state publisher.
static int build_regex(regex_t *regex, const char *text)
static int exten_state_publisher_state_cb(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
Global extension state callback function.
int ast_sip_pubsub_is_body_generator_registered(const char *type, const char *subtype)
Is a body generator registered for the given type/subtype.
const char * ast_sorcery_object_get_extended(const void *object, const char *name)
Get an extended field value from a sorcery object.
Definition: sorcery.c:2330
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:406

References AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_alloc_options, ao2_bump, ao2_container_count(), ao2_link_flags, ao2_lock, ao2_ref, ao2_unlock, ast_copy_string(), ast_datastores_alloc(), ast_extension_state_add(), ast_log, ast_sip_pubsub_is_body_generator_registered(), ast_sorcery_object_get_extended(), ast_sorcery_object_get_id(), ast_strdupa, ast_strlen_zero(), exten_state_publisher::body_subtype, exten_state_publisher::body_type, build_regex(), exten_state_publisher::client, context, exten_state_publisher::context_filter, exten_state_publisher::context_regex, exten_state_publisher::datastores, exten, exten_state_publisher::exten_filter, exten_state_publisher::exten_regex, exten_state_publisher_destroy(), exten_state_publisher_state_cb(), LOG_ERROR, exten_state_publisher::name, name, NULL, OBJ_NOLOCK, and strsep().

◆ publisher_stop()

static int publisher_stop ( struct ast_sip_outbound_publish_client client)
static

Definition at line 960 of file res_pjsip_exten_state.c.

961 {
963  return 0;
964 }
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_UNLINK
Definition: astobj2.h:1039

References ao2_find, ast_sorcery_object_get_id(), exten_state_publisher::client, OBJ_NODATA, OBJ_SEARCH_KEY, and OBJ_UNLINK.

◆ state_changed()

static int state_changed ( const char *  context,
const char *  exten,
struct ast_state_cb_info info,
void *  data 
)
static

Definition at line 336 of file res_pjsip_exten_state.c.

338 {
339  struct notify_task_data *task_data;
340  struct exten_state_subscription *exten_state_sub = data;
341 
342  if (!(task_data = alloc_notify_task_data(exten, exten_state_sub, info))) {
343  return -1;
344  }
345 
346  /* safe to push this async since we copy the data from info and
347  add a ref for the device state info */
348  if (ast_sip_push_task(task_data->exten_state_sub->serializer, notify_task,
349  task_data)) {
351  return -1;
352  }
353  return 0;
354 }
static struct notify_task_data * alloc_notify_task_data(const char *exten, struct exten_state_subscription *exten_state_sub, struct ast_state_cb_info *info)
static int notify_task(void *obj)

References alloc_notify_task_data(), ao2_cleanup, ast_sip_push_task(), exten, sip_to_pjsip::info(), and notify_task().

Referenced by subscription_established(), and subscription_shutdown().

◆ state_changed_destroy()

static void state_changed_destroy ( int  id,
void *  data 
)
static

Definition at line 356 of file res_pjsip_exten_state.c.

357 {
358  struct exten_state_subscription *exten_state_sub = data;
359  ao2_cleanup(exten_state_sub);
360 }

Referenced by subscription_established().

◆ subscription_established()

static int subscription_established ( struct ast_sip_subscription sub)
static

Definition at line 451 of file res_pjsip_exten_state.c.

452 {
453  struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sip_sub);
454  const char *resource = ast_sip_subscription_get_resource_name(sip_sub);
455  struct exten_state_subscription *exten_state_sub;
456 
457  if (!(exten_state_sub = exten_state_subscription_alloc(sip_sub, endpoint))) {
458  ao2_cleanup(endpoint);
459  return -1;
460  }
461 
462  ast_copy_string(exten_state_sub->context,
463  S_OR(endpoint->subscription.context, endpoint->context),
464  sizeof(exten_state_sub->context));
465  ast_copy_string(exten_state_sub->exten, resource, sizeof(exten_state_sub->exten));
466 
467  if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
468  exten_state_sub->context, exten_state_sub->exten,
469  state_changed, state_changed_destroy, exten_state_sub)) < 0) {
470  ast_log(LOG_WARNING, "Unable to subscribe endpoint '%s' to extension '%s@%s'\n",
471  ast_sorcery_object_get_id(endpoint), exten_state_sub->exten,
472  exten_state_sub->context);
473  ao2_cleanup(endpoint);
474  ao2_cleanup(exten_state_sub);
475  return -1;
476  }
477 
478  /* Go ahead and cleanup the endpoint since we don't need it anymore */
479  ao2_cleanup(endpoint);
480 
481  /* bump the ref since ast_extension_state_add holds a reference */
482  ao2_ref(exten_state_sub, +1);
483 
484  if (add_datastore(exten_state_sub)) {
485  ast_log(LOG_WARNING, "Unable to add to subscription datastore.\n");
486  ao2_cleanup(exten_state_sub);
487  return -1;
488  }
489 
490  ao2_cleanup(exten_state_sub);
491  return 0;
492 }
int ast_extension_state_add_destroy_extended(const char *context, const char *exten, ast_state_cb_type change_cb, ast_state_cb_destroy_type destroy_cb, void *data)
Add watcher for extended extension states with destructor.
Definition: pbx.c:3836
static int state_changed(const char *context, const char *exten, struct ast_state_cb_info *info, void *data)
static struct exten_state_subscription * exten_state_subscription_alloc(struct ast_sip_subscription *sip_sub, struct ast_sip_endpoint *endpoint)
static void state_changed_destroy(int id, void *data)
static int add_datastore(struct exten_state_subscription *exten_state_sub)
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
struct ast_sip_endpoint * ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
Get the endpoint that is associated with this subscription.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:854

References add_datastore(), ao2_cleanup, ao2_ref, ast_copy_string(), ast_extension_state_add_destroy_extended(), ast_log, ast_sip_subscription_get_endpoint(), ast_sip_subscription_get_resource_name(), ast_sorcery_object_get_id(), ast_sip_endpoint_subscription_configuration::context, ast_sip_endpoint::context, exten_state_subscription::context, exten_state_subscription::exten, exten_state_subscription_alloc(), exten_state_subscription::id, LOG_WARNING, S_OR, exten_state_subscription::sip_sub, state_changed(), state_changed_destroy(), and ast_sip_endpoint::subscription.

◆ subscription_shutdown()

static void subscription_shutdown ( struct ast_sip_subscription sub)
static

Definition at line 401 of file res_pjsip_exten_state.c.

402 {
403  struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
404 
405  if (!exten_state_sub) {
406  return;
407  }
408 
409  ast_extension_state_del(exten_state_sub->id, state_changed);
411  /* remove data store reference */
412  ao2_cleanup(exten_state_sub);
413 }
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3863
void ast_sip_subscription_remove_datastore(struct ast_sip_subscription *subscription, const char *name)
Remove a subscription datastore from the subscription.

References ao2_cleanup, ast_extension_state_del(), ast_sip_subscription_remove_datastore(), ds_name, get_exten_state_sub(), exten_state_subscription::id, exten_state_subscription::sip_sub, state_changed(), and sub.

◆ to_ami()

static void to_ami ( struct ast_sip_subscription sub,
struct ast_str **  buf 
)
static

Definition at line 566 of file res_pjsip_exten_state.c.

568 {
569  struct exten_state_subscription *exten_state_sub =
571 
572  if (!exten_state_sub) {
573  return;
574  }
575 
576  ast_str_append(buf, 0, "SubscriptionType: extension_state\r\n"
577  "Extension: %s\r\nExtensionStates: %s\r\n",
578  exten_state_sub->exten, ast_extension_state2str(
579  exten_state_sub->last_exten_state));
580 }
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1117

References ast_extension_state2str(), ast_str_append(), buf, exten_state_subscription::exten, get_exten_state_sub(), exten_state_subscription::last_exten_state, and sub.

Referenced by stasis_message_can_be_ami(), stasis_message_to_ami(), and unload_module().

◆ unload_module()

static int unload_module ( void  )
static

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Extension State Notifications" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND + 5, .requires = "res_pjsip,res_pjsip_pubsub,res_pjsip_outbound_publish", }
static

Definition at line 984 of file res_pjsip_exten_state.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1036 of file res_pjsip_exten_state.c.

◆ dialog_handler

struct ast_sip_subscription_handler dialog_handler

Definition at line 125 of file res_pjsip_exten_state.c.

Referenced by unload_module().

◆ dialog_notifier

struct ast_sip_notifier dialog_notifier

Definition at line 125 of file res_pjsip_exten_state.c.

◆ dialog_publisher

struct ast_sip_event_publisher_handler dialog_publisher
Initial value:
= {
.event_name = "dialog",
.start_publishing = publisher_start,
.stop_publishing = publisher_stop,
}
static int publisher_start(struct ast_sip_outbound_publish *configuration, struct ast_sip_outbound_publish_client *client)
static int publisher_stop(struct ast_sip_outbound_publish_client *client)

Definition at line 125 of file res_pjsip_exten_state.c.

Referenced by unload_module().

◆ ds_info

struct ast_datastore_info ds_info = { }
static

Definition at line 356 of file res_pjsip_exten_state.c.

Referenced by add_datastore().

◆ ds_name

const char ds_name[] = "exten state datastore"
static

◆ presence_handler

struct ast_sip_subscription_handler presence_handler

Definition at line 125 of file res_pjsip_exten_state.c.

Referenced by unload_module().

◆ presence_notifier

struct ast_sip_notifier presence_notifier

Definition at line 125 of file res_pjsip_exten_state.c.

◆ presence_publisher

struct ast_sip_event_publisher_handler presence_publisher
Initial value:
= {
.event_name = "presence",
.start_publishing = publisher_start,
.stop_publishing = publisher_stop,
}

Definition at line 125 of file res_pjsip_exten_state.c.

Referenced by unload_module().

◆ publish_exten_state_serializer

struct ast_taskprocessor* publish_exten_state_serializer
static

Serializer for outbound extension state publishing.

Definition at line 60 of file res_pjsip_exten_state.c.

Referenced by exten_state_publisher_state_cb(), and unload_module().

◆ publishers

struct ao2_container* publishers
static

Container of active outbound extension state publishers.

Definition at line 57 of file res_pjsip_exten_state.c.