Asterisk - The Open Source Telephony Project GIT-master-2de1a68
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 1059 of file res_pjsip_exten_state.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1059 of file res_pjsip_exten_state.c.

◆ add_datastore()

static int add_datastore ( struct exten_state_subscription exten_state_sub)
static

Definition at line 380 of file res_pjsip_exten_state.c.

381{
382 RAII_VAR(struct ast_datastore *, datastore,
384
385 if (!datastore) {
386 return -1;
387 }
388
389 datastore->data = exten_state_sub;
390 ast_sip_subscription_add_datastore(exten_state_sub->sip_sub, datastore);
391 ao2_ref(exten_state_sub, +1);
392 return 0;
393}
#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:941

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{
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;
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
#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_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 1059 of file res_pjsip_exten_state.c.

◆ build_regex()

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

Definition at line 854 of file res_pjsip_exten_state.c.

855{
856 int res;
857
858 if ((res = regcomp(regex, text, REG_EXTENDED | REG_ICASE | REG_NOSUB))) {
859 size_t len = regerror(res, regex, NULL, 0);
860 char buf[len];
861 regerror(res, regex, buf, len);
862 ast_log(LOG_ERROR, "Could not compile regex '%s': %s\n", text, buf);
863 return -1;
864 }
865
866 return 0;
867}
char * text
Definition: app_queue.c:1639
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 514 of file res_pjsip_exten_state.c.

516{
517 struct ast_sip_exten_state_data *exten_state_data;
518 char *subtype = NULL;
519 char *message = NULL;
520 int presence_state;
521
522 exten_state_data = ao2_alloc(sizeof(*exten_state_data), exten_state_data_destructor);
523 if (!exten_state_data) {
524 return NULL;
525 }
526
527 exten_state_data->exten = exten_state_sub->exten;
528 presence_state = ast_hint_presence_state(NULL, exten_state_sub->context, exten_state_sub->exten, &subtype, &message);
530 ao2_cleanup(exten_state_data);
531 return NULL;
532 }
533 exten_state_data->presence_state = presence_state;
534 exten_state_data->presence_subtype = subtype;
535 exten_state_data->presence_message = message;
536 exten_state_data->user_agent = exten_state_sub->user_agent;
537 ast_sip_subscription_get_local_uri(sip_sub, exten_state_data->local,
538 sizeof(exten_state_data->local));
539 ast_sip_subscription_get_remote_uri(sip_sub, exten_state_data->remote,
540 sizeof(exten_state_data->remote));
541 exten_state_data->sub = sip_sub;
542 exten_state_data->datastores = ast_sip_subscription_get_datastores(sip_sub);
543
544 exten_state_data->exten_state = ast_extension_state_extended(
545 NULL, exten_state_sub->context, exten_state_sub->exten,
546 &exten_state_data->device_state_info);
547 if (exten_state_data->exten_state < 0) {
548 ao2_cleanup(exten_state_data);
549 return NULL;
550 }
551
552 exten_state_data->pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
553 "exten_state", 1024, 1024);
554 if (!exten_state_data->pool) {
555 ao2_cleanup(exten_state_data);
556 return NULL;
557 }
558
559 return exten_state_data;
560}
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:3226
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:3176
@ 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:520
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 502 of file res_pjsip_exten_state.c.

503{
504 struct ast_sip_exten_state_data *exten_state_data = obj;
505
506 ao2_cleanup(exten_state_data->device_state_info);
507 ast_free(exten_state_data->presence_subtype);
508 ast_free(exten_state_data->presence_message);
509 if (exten_state_data->pool) {
510 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), exten_state_data->pool);
511 }
512}
#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 614 of file res_pjsip_exten_state.c.

615{
616 struct exten_state_pub_data *pub_data;
617
618 pub_data = ast_calloc(1, sizeof(*pub_data));
619 if (!pub_data) {
620 return NULL;
621 }
622
625 return NULL;
626 }
627
628 /* Save off currently known information for the body generators. */
629 pub_data->exten_state_data.exten = ast_strdup(exten);
630 pub_data->exten_state_data.exten_state = info->exten_state;
631 pub_data->exten_state_data.presence_state = info->presence_state;
632 pub_data->exten_state_data.presence_subtype = ast_strdup(info->presence_subtype);
633 pub_data->exten_state_data.presence_message = ast_strdup(info->presence_message);
634 pub_data->exten_state_data.device_state_info = ao2_bump(info->device_state_info);
635 if (!pub_data->exten_state_data.exten
637 || !pub_data->exten_state_data.presence_message) {
639 return NULL;
640 }
641 return pub_data;
642}
#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, 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 597 of file res_pjsip_exten_state.c.

598{
599 if (!doomed) {
600 return;
601 }
602
603 ast_free((void *) doomed->exten_state_data.exten);
607
609 AST_VECTOR_FREE(&doomed->pubs);
610
611 ast_free(doomed);
612}
#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 651 of file res_pjsip_exten_state.c.

652{
653 struct exten_state_pub_data *pub_data = data;
654 struct exten_state_publisher *publisher;
655 size_t idx;
656 struct ast_str *body_text;
657 pj_pool_t *pool;
658 struct ast_sip_body_data gen_data = {
660 .body_data = &pub_data->exten_state_data,
661 };
662 struct ast_sip_body body;
663
665 if (!body_text) {
667 return 0;
668 }
669
670 /* Need a PJSIP memory pool to generate the bodies. */
671 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "pub_state_body",
672 1024, 1024);
673 if (!pool) {
674 ast_log(LOG_WARNING, "Exten state publishing unable to create memory pool\n");
677 return 0;
678 }
679 pub_data->exten_state_data.pool = pool;
680
681 for (idx = 0; idx < AST_VECTOR_SIZE(&pub_data->pubs); ++idx) {
682 const char *uri;
683 int res;
684
685 publisher = AST_VECTOR_GET(&pub_data->pubs, idx);
686
688 pub_data->exten_state_data.local, sizeof(pub_data->exten_state_data.local));
689 if (ast_strlen_zero(uri)) {
690 ast_log(LOG_WARNING, "PUBLISH client '%s' has no from_uri or server_uri defined.\n",
691 publisher->name);
692 continue;
693 }
694
696 pub_data->exten_state_data.remote, sizeof(pub_data->exten_state_data.remote));
697 if (ast_strlen_zero(uri)) {
698 ast_log(LOG_WARNING, "PUBLISH client '%s' has no to_uri or server_uri defined.\n",
699 publisher->name);
700 continue;
701 }
702
703 pub_data->exten_state_data.datastores = publisher->datastores;
704
706 publisher->body_subtype, &gen_data, &body_text);
707 pj_pool_reset(pool);
708 if (res) {
710 "PUBLISH client '%s' unable to generate %s/%s PUBLISH body.\n",
711 publisher->name, publisher->body_type, publisher->body_subtype);
712 continue;
713 }
714
715 body.type = publisher->body_type;
716 body.subtype = publisher->body_subtype;
717 body.body_text = ast_str_buffer(body_text);
719 }
720
721 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
722
725 return 0;
726}
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.
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.
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:761
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:659
Data used to create bodies for NOTIFY/PUBLISH requests.
const char * body_type
SIP body description.
Definition: res_pjsip.h:2313
const char * body_text
Definition: res_pjsip.h:2319
Support for dynamic strings.
Definition: strings.h:623
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 807 of file res_pjsip_exten_state.c.

808{
809 const struct exten_state_publisher *object_left = obj;
810 const struct exten_state_publisher *object_right = arg;
811 const char *right_key = arg;
812 int cmp;
813
814 switch (flags & OBJ_SEARCH_MASK) {
816 right_key = object_right->name;
817 /* Fall through */
818 case OBJ_SEARCH_KEY:
819 cmp = strcmp(object_left->name, right_key);
820 break;
822 /* Not supported by container. */
823 ast_assert(0);
824 return 0;
825 default:
826 cmp = 0;
827 break;
828 }
829 if (cmp) {
830 return 0;
831 }
832 return CMP_MATCH;
833}
@ 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:739

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

Referenced by load_module().

◆ exten_state_publisher_destroy()

static void exten_state_publisher_destroy ( void *  obj)
static

Destructor for extension state publisher.

Definition at line 838 of file res_pjsip_exten_state.c.

839{
840 struct exten_state_publisher *publisher = obj;
841
842 if (publisher->context_filter) {
843 regfree(&publisher->context_regex);
844 }
845
846 if (publisher->exten_filter) {
847 regfree(&publisher->exten_regex);
848 }
849
850 ao2_cleanup(publisher->client);
851 ao2_cleanup(publisher->datastores);
852}

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 784 of file res_pjsip_exten_state.c.

785{
786 const struct exten_state_publisher *object;
787 const char *key;
788
789 switch (flags & OBJ_SEARCH_MASK) {
790 case OBJ_SEARCH_KEY:
791 key = obj;
792 break;
794 object = obj;
795 key = object->name;
796 break;
797 default:
798 ast_assert(0);
799 return 0;
800 }
801 return ast_str_hash(key);
802}
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
Definition: strings.h:1259

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

Referenced by load_module().

◆ 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 731 of file res_pjsip_exten_state.c.

732{
733 struct ao2_iterator publisher_iter;
734 struct exten_state_publisher *publisher;
735 struct exten_state_pub_data *pub_data = NULL;
736
737 ast_debug(5, "Exten state publisher: %s@%s Reason:%s State:%s Presence:%s Subtype:'%s' Message:'%s'\n",
738 exten, context,
740 ? "Device"
741 : info->reason == AST_HINT_UPDATE_PRESENCE
742 ? "Presence"
743 : "Unknown",
744 ast_extension_state2str(info->exten_state),
745 ast_presence_state2str(info->presence_state),
746 S_OR(info->presence_subtype, ""),
747 S_OR(info->presence_message, ""));
748 publisher_iter = ao2_iterator_init(publishers, 0);
749 for (; (publisher = ao2_iterator_next(&publisher_iter)); ao2_ref(publisher, -1)) {
750 if ((publisher->context_filter && regexec(&publisher->context_regex, context, 0, NULL, 0)) ||
751 (publisher->exten_filter && regexec(&publisher->exten_regex, exten, 0, NULL, 0))) {
752 continue;
753 }
754
755 if (!pub_data) {
756 pub_data = exten_state_pub_data_alloc(exten, info);
757 if (!pub_data) {
758 ao2_ref(publisher, -1);
759 break;
760 }
761 }
762
763 ao2_ref(publisher, +1);
764 if (AST_VECTOR_APPEND(&pub_data->pubs, publisher)) {
765 ao2_ref(publisher, -1);
766 } else {
767 ast_debug(5, "'%s' will publish exten state\n", publisher->name);
768 }
769 }
770 ao2_iterator_destroy(&publisher_iter);
771
772 if (pub_data
774 pub_data)) {
776 }
777
778 return 0;
779}
#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.
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:2099
#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:3126
@ 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, voicemailpwcheck::context, exten_state_publisher::context_filter, exten_state_publisher::context_regex, 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 */
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);
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 400 of file res_pjsip_exten_state.c.

402{
403 RAII_VAR(struct ast_datastore *, datastore,
405
406 return datastore ? datastore->data : NULL;
407}
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 562 of file res_pjsip_exten_state.c.

563{
564 struct exten_state_subscription *exten_state_sub;
565
566 exten_state_sub = get_exten_state_sub(sub);
567 if (!exten_state_sub) {
568 return NULL;
569 }
570
571 return exten_state_data_alloc(sub, exten_state_sub);
572}
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 438 of file res_pjsip_exten_state.c.

440{
441 const char *context;
442
443 if (!endpoint || ast_strlen_zero(resource) || !display_name || display_name_size <= 0) {
444 return -1;
445 }
446
447 context = S_OR(endpoint->subscription.context, endpoint->context);
448
449 if (!ast_get_hint(NULL, 0, display_name, display_name_size, NULL, context, resource)) {
450 ast_log(LOG_NOTICE, "Endpoint '%s': "
451 "Extension '%s' does not exist in context '%s' or has no associated hint\n",
452 ast_sorcery_object_get_id(endpoint), resource, context);
453 return -1;
454 }
455
456 return 0;
457}
#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:4137
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:980
struct ast_sip_endpoint_subscription_configuration subscription
Definition: res_pjsip.h:986

References ast_get_hint(), ast_log, ast_sorcery_object_get_id(), ast_strlen_zero(), voicemailpwcheck::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:2201
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:1321

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 1007 of file res_pjsip_exten_state.c.

1008{
1011 if (!publishers) {
1012 ast_log(LOG_WARNING, "Unable to create container to store extension state publishers\n");
1014 }
1015
1018 unload_module();
1020 }
1021
1023 ast_log(LOG_WARNING, "Unable to register subscription handler %s\n",
1025 unload_module();
1027 }
1028
1030 ast_log(LOG_WARNING, "Unable to register presence publisher %s\n",
1032 unload_module();
1034 }
1035
1037 ast_log(LOG_WARNING, "Unable to register subscription handler %s\n",
1039 unload_module();
1041 }
1042
1044 ast_log(LOG_WARNING, "Unable to register presence publisher %s\n",
1046 unload_module();
1048 }
1049
1051}
@ 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:2094
@ 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.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_container_alloc_hash, ast_log, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_sip_create_serializer(), ast_sip_register_event_publisher_handler(), ast_sip_register_subscription_handler(), dialog_handler, dialog_publisher, ast_sip_event_publisher_handler::event_name, ast_sip_subscription_handler::event_name, exten_state_publisher_cmp(), exten_state_publisher_hash(), LOG_WARNING, NULL, presence_handler, presence_publisher, publish_exten_state_serializer, PUBLISHER_BUCKETS, and unload_module().

◆ new_subscribe()

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

Definition at line 423 of file res_pjsip_exten_state.c.

425{
426 const char *context = S_OR(endpoint->subscription.context, endpoint->context);
427
429 ast_log(LOG_NOTICE, "Endpoint '%s' state subscription failed: "
430 "Extension '%s' does not exist in context '%s' or has no associated hint\n",
431 ast_sorcery_object_get_id(endpoint), resource, context);
432 return 404;
433 }
434
435 return 200;
436}
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:4175
#define PRIORITY_HINT
Definition: pbx.h:54

References ast_exists_extension(), ast_log, ast_sorcery_object_get_id(), voicemailpwcheck::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 /* The subscription was terminated while notify_task was in queue.
300 Terminated subscriptions are no longer associated with a valid tree, and sending
301 * NOTIFY messages on a subscription which has already been terminated won't work.
302 */
303 if (ast_sip_subscription_is_terminated(task_data->exten_state_sub->sip_sub)) {
304 return 0;
305 }
306
307 /* All access to the subscription must occur within a task executed within its serializer */
308 ast_sip_subscription_get_local_uri(task_data->exten_state_sub->sip_sub,
309 task_data->exten_state_data.local, sizeof(task_data->exten_state_data.local));
310 ast_sip_subscription_get_remote_uri(task_data->exten_state_sub->sip_sub,
311 task_data->exten_state_data.remote, sizeof(task_data->exten_state_data.remote));
312
313 /* Pool allocation has to happen here so that we allocate within a PJLIB thread */
314 task_data->exten_state_data.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
315 "exten_state", 1024, 1024);
316 if (!task_data->exten_state_data.pool) {
317 return -1;
318 }
319
320 task_data->exten_state_data.sub = task_data->exten_state_sub->sip_sub;
321 task_data->exten_state_data.datastores = ast_sip_subscription_get_datastores(task_data->exten_state_sub->sip_sub);
322
323 ast_sip_subscription_notify(task_data->exten_state_sub->sip_sub, &data,
324 task_data->terminate);
325
326 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(),
327 task_data->exten_state_data.pool);
328 return 0;
329}
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 869 of file res_pjsip_exten_state.c.

870{
871 struct exten_state_publisher *publisher;
872 size_t name_size;
873 size_t body_type_size;
874 size_t body_subtype_size;
875 char *body_subtype;
876 const char *body_full;
877 const char *body_type;
878 const char *name;
879 const char *context;
880 const char *exten;
881
882 name = ast_sorcery_object_get_id(configuration);
883
884 body_full = ast_sorcery_object_get_extended(configuration, "body");
885 if (ast_strlen_zero(body_full)) {
886 ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Body not set\n",
887 name);
888 return -1;
889 }
890
891 body_subtype = ast_strdupa(body_full);
894 ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Body '%s' missing type or subtype\n",
895 name, body_full);
896 return -1;
897 }
898
900 ast_log(LOG_ERROR, "Outbound extension state publisher '%s': '%s' body generator not registered\n",
901 name, body_full);
902 return -1;
903 }
904
905 name_size = strlen(name) + 1;
906 body_type_size = strlen(body_type) + 1;
907 body_subtype_size = strlen(body_subtype) + 1;
908
909 publisher = ao2_alloc_options(
910 sizeof(*publisher) + name_size + body_type_size + body_subtype_size,
912 if (!publisher) {
913 return -1;
914 }
915
916 ast_copy_string(publisher->name, name, name_size);
917 publisher->body_type = publisher->name + name_size;
918 ast_copy_string(publisher->body_type, body_type, body_type_size);
919 publisher->body_subtype = publisher->body_type + body_type_size;
920 ast_copy_string(publisher->body_subtype, body_subtype, body_subtype_size);
921
922 context = ast_sorcery_object_get_extended(configuration, "context");
923 if (!ast_strlen_zero(context)) {
924 if (build_regex(&publisher->context_regex, context)) {
925 ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not build context filter '%s'\n",
926 name, context);
927 ao2_ref(publisher, -1);
928 return -1;
929 }
930
931 publisher->context_filter = 1;
932 }
933
934 exten = ast_sorcery_object_get_extended(configuration, "exten");
935 if (!ast_strlen_zero(exten)) {
936 if (build_regex(&publisher->exten_regex, exten)) {
937 ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not build exten filter '%s'\n",
938 name, exten);
939 ao2_ref(publisher, -1);
940 return -1;
941 }
942
943 publisher->exten_filter = 1;
944 }
945
946 publisher->datastores = ast_datastores_alloc();
947 if (!publisher->datastores) {
948 ast_log(LOG_ERROR, "Outbound extension state publisher '%s': Could not create datastores container\n",
949 name);
950 ao2_ref(publisher, -1);
951 return -1;
952 }
953
954 publisher->client = ao2_bump(client);
955
959 }
962
963 ao2_ref(publisher, -1);
964
965 return 0;
966}
#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:99
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:3823
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:425

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, voicemailpwcheck::context, exten_state_publisher::context_filter, exten_state_publisher::context_regex, exten_state_publisher::datastores, 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 968 of file res_pjsip_exten_state.c.

969{
971 return 0;
972}
#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 337 of file res_pjsip_exten_state.c.

339{
341 struct exten_state_subscription *exten_state_sub = data;
342
343 /* Terminated subscriptions are no longer associated with a valid tree.
344 * Do not queue notify_task.
345 */
346 if (ast_sip_subscription_is_terminated(exten_state_sub->sip_sub)) {
347 return 0;
348 }
349
350 if (!(task_data = alloc_notify_task_data(exten, exten_state_sub, info))) {
351 return -1;
352 }
353
354 /* safe to push this async since we copy the data from info and
355 add a ref for the device state info */
356 if (ast_sip_push_task(task_data->exten_state_sub->serializer, notify_task,
357 task_data)) {
359 return -1;
360 }
361 return 0;
362}
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(), ast_sip_subscription_is_terminated(), exten_state_subscription::exten, sip_to_pjsip::info(), notify_task(), and exten_state_subscription::sip_sub.

Referenced by subscription_established(), and subscription_shutdown().

◆ state_changed_destroy()

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

Definition at line 364 of file res_pjsip_exten_state.c.

365{
366 struct exten_state_subscription *exten_state_sub = data;
367 ao2_cleanup(exten_state_sub);
368}

References ao2_cleanup.

Referenced by subscription_established().

◆ subscription_established()

static int subscription_established ( struct ast_sip_subscription sub)
static

Definition at line 459 of file res_pjsip_exten_state.c.

460{
461 struct ast_sip_endpoint *endpoint = ast_sip_subscription_get_endpoint(sip_sub);
462 const char *resource = ast_sip_subscription_get_resource_name(sip_sub);
463 struct exten_state_subscription *exten_state_sub;
464
465 if (!(exten_state_sub = exten_state_subscription_alloc(sip_sub, endpoint))) {
466 ao2_cleanup(endpoint);
467 return -1;
468 }
469
470 ast_copy_string(exten_state_sub->context,
471 S_OR(endpoint->subscription.context, endpoint->context),
472 sizeof(exten_state_sub->context));
473 ast_copy_string(exten_state_sub->exten, resource, sizeof(exten_state_sub->exten));
474
475 if ((exten_state_sub->id = ast_extension_state_add_destroy_extended(
476 exten_state_sub->context, exten_state_sub->exten,
477 state_changed, state_changed_destroy, exten_state_sub)) < 0) {
478 ast_log(LOG_WARNING, "Unable to subscribe endpoint '%s' to extension '%s@%s'\n",
479 ast_sorcery_object_get_id(endpoint), exten_state_sub->exten,
480 exten_state_sub->context);
481 ao2_cleanup(endpoint);
482 ao2_cleanup(exten_state_sub);
483 return -1;
484 }
485
486 /* Go ahead and cleanup the endpoint since we don't need it anymore */
487 ao2_cleanup(endpoint);
488
489 /* bump the ref since ast_extension_state_add holds a reference */
490 ao2_ref(exten_state_sub, +1);
491
492 if (add_datastore(exten_state_sub)) {
493 ast_log(LOG_WARNING, "Unable to add to subscription datastore.\n");
494 ao2_cleanup(exten_state_sub);
495 return -1;
496 }
497
498 ao2_cleanup(exten_state_sub);
499 return 0;
500}
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:3829
static struct exten_state_subscription * exten_state_subscription_alloc(struct ast_sip_subscription *sip_sub, struct ast_sip_endpoint *endpoint)
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 add_datastore(struct exten_state_subscription *exten_state_sub)
struct ast_sip_endpoint * ast_sip_subscription_get_endpoint(struct ast_sip_subscription *sub)
Get the endpoint that is associated with this subscription.
const char * ast_sip_subscription_get_resource_name(struct ast_sip_subscription *sub)
Get the name of the subscribed resource.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:951

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 409 of file res_pjsip_exten_state.c.

410{
411 struct exten_state_subscription *exten_state_sub = get_exten_state_sub(sub);
412
413 if (!exten_state_sub) {
414 return;
415 }
416
417 ast_extension_state_del(exten_state_sub->id, state_changed);
419 /* remove data store reference */
420 ao2_cleanup(exten_state_sub);
421}
int ast_extension_state_del(int id, ast_state_cb_type change_cb)
Deletes a state change watcher by ID.
Definition: pbx.c:3856
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 574 of file res_pjsip_exten_state.c.

576{
577 struct exten_state_subscription *exten_state_sub =
579
580 if (!exten_state_sub) {
581 return;
582 }
583
584 ast_str_append(buf, 0, "SubscriptionType: extension_state\r\n"
585 "Extension: %s\r\nExtensionStates: %s\r\n",
586 exten_state_sub->exten, ast_extension_state2str(
587 exten_state_sub->last_exten_state));
588}
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:1139

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 load_module(), stasis_message_can_be_ami(), stasis_message_to_ami(), and unload_module().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 974 of file res_pjsip_exten_state.c.

975{
976 /*
977 * pjsip_evsub_register_pkg is called by ast_sip_register_subscription_handler
978 * but there is no corresponding unregister function, so unloading
979 * a module does not remove the event package. If this module is ever
980 * loaded again, then pjproject will assert and cause a crash.
981 * For that reason, we must only be allowed to unload when
982 * asterisk is shutting down. If a pjsip_evsub_unregister_pkg
983 * API is added in the future then we should go back to unloading
984 * the module as intended.
985 */
986
987 if (ast_shutdown_final()) {
992
994
997
1000
1001 return 0;
1002 } else {
1003 return -1;
1004 }
1005}
int ast_shutdown_final(void)
Definition: asterisk.c:1867
void ast_sip_unregister_event_publisher_handler(struct ast_sip_event_publisher_handler *handler)
Unregister a publish handler.
void ast_sip_unregister_subscription_handler(struct ast_sip_subscription_handler *handler)
Unregister a subscription handler.

References ao2_cleanup, ast_extension_state_del(), ast_shutdown_final(), ast_sip_unregister_event_publisher_handler(), ast_sip_unregister_subscription_handler(), ast_taskprocessor_unreference(), dialog_handler, dialog_publisher, exten_state_publisher_state_cb(), NULL, presence_handler, presence_publisher, and publish_exten_state_serializer.

Referenced by load_module().

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 1059 of file res_pjsip_exten_state.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1059 of file res_pjsip_exten_state.c.

◆ dialog_handler

struct ast_sip_subscription_handler dialog_handler

Definition at line 158 of file res_pjsip_exten_state.c.

Referenced by load_module(), and unload_module().

◆ dialog_notifier

struct ast_sip_notifier dialog_notifier

Definition at line 135 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 167 of file res_pjsip_exten_state.c.

Referenced by load_module(), and unload_module().

◆ ds_info

struct ast_datastore_info ds_info = { }
static

Definition at line 370 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 143 of file res_pjsip_exten_state.c.

Referenced by load_module(), and unload_module().

◆ presence_notifier

struct ast_sip_notifier presence_notifier

Definition at line 127 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 152 of file res_pjsip_exten_state.c.

Referenced by load_module(), and 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(), load_module(), 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.