29 #include <pjsip_simple.h>
31 #include "asterisk/res_pjproject.h"
32 #include "asterisk/res_pjsip.h"
33 #include "asterisk/res_pjsip_outbound_publish.h"
36 #include "asterisk/threadpool.h"
38 #include "res_pjsip/include/res_pjsip_private.h"
124 static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
220 unsigned int destroy;
255 AST_RWLOCK_DEFINE_STATIC(load_lock);
257 #define DEFAULT_PUBLISHER_BUCKETS 119
262 #define MAX_UNLOAD_TIMEOUT_TIME 35
268 #define DEFAULT_STATE_BUCKETS 31
274 static int outbound_publish_state_hash(
const void *obj,
const int flags)
295 static int outbound_publish_state_cmp(
void *obj,
void *arg,
int flags)
299 const char *right_key = arg;
304 right_key = object_right->id;
307 cmp = strcmp(object_left->id, right_key);
323 static struct ao2_container *get_publishes_and_update_state(
void)
329 ast_sip_get_sorcery(),
"outbound-publish",
337 ao2_cleanup(new_states);
365 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
366 &publisher->
timer, 0)) {
376 pj_time_val delay = { .sec = 0, };
378 cancel_publish_refresh(publisher);
380 if (expiration > 0) {
381 delay.sec = expiration - PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH;
386 if (delay.sec < PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH) {
387 delay.sec = PJSIP_PUBLISHC_DELAY_BEFORE_REFRESH;
391 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &publisher->
timer, &delay) != PJ_SUCCESS) {
392 ast_log(LOG_WARNING,
"Failed to pass timed publish refresh to scheduler\n");
398 static int publisher_client_send(
void *obj,
void *arg,
void *data,
int flags);
401 static void sip_outbound_publish_timer_cb(pj_timer_heap_t *
timer_heap,
struct pj_timer_entry *
entry)
409 publisher_client_send(publisher, NULL, &res, 0);
411 ao2_unlock(publisher);
417 static int cancel_refresh_timer_task(
void *data)
421 cancel_publish_refresh(publisher);
430 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
432 ast_sip_set_tpselector_from_transport_name(
434 pjsip_tx_data_set_transport(tdata, &selector);
435 ast_sip_tpselector_unref(&selector);
440 static int send_unpublish_task(
void *data)
443 pjsip_tx_data *tdata;
445 if (pjsip_publishc_unpublish(publisher->
client, &tdata) == PJ_SUCCESS) {
446 set_transport(publisher, tdata);
447 pjsip_publishc_send(publisher->
client, tdata);
459 handler = find_publisher_handler_for_event_name(client->
publish->
event);
467 static int cancel_and_unpublish(
void *obj,
void *arg,
int flags);
487 while ((state = ao2_iterator_next(&i))) {
494 ast_debug(2,
"Could not find handler for event '%s' for outbound publish client '%s'\n",
497 ast_log(LOG_ERROR,
"Failed to start outbound publish with event '%s' for client '%s'\n",
562 ast_rwlock_wrlock(&load_lock);
565 if (!(publisher = sip_outbound_publish_client_add_publisher(client, user))) {
566 ast_rwlock_unlock(&load_lock);
570 ast_rwlock_unlock(&load_lock);
576 char *uri,
size_t size)
580 publisher = sip_outbound_publish_client_get_publisher(client, user);
599 char *uri,
size_t size)
603 publisher = sip_outbound_publish_client_get_publisher(client, user);
620 ast_log(LOG_ERROR,
"Handler does not implement required callbacks. Cannot register\n");
622 }
else if (ast_strlen_zero(handler->
event_name)) {
623 ast_log(LOG_ERROR,
"No event package specified for event publisher handler. Cannot register\n");
627 existing = find_publisher_handler_for_event_name(handler->
event_name);
629 ast_log(LOG_ERROR,
"Unable to register event publisher handler for event %s. "
630 "A handler is already registered\n", handler->
event_name);
634 sub_add_handler(handler);
636 sip_outbound_publish_synchronize(NULL);
646 if (handler == iter) {
647 AST_RWLIST_REMOVE_CURRENT(next);
651 AST_RWLIST_TRAVERSE_SAFE_END;
653 sip_outbound_publish_synchronize(handler);
657 static void sip_outbound_publish_destroy(
void *obj)
667 static void *sip_outbound_publish_alloc(
const char *name)
670 sip_outbound_publish_destroy);
673 ao2_cleanup(publish);
680 static void sip_outbound_publish_datastore_destroy(
void *obj)
687 datastore->
data = NULL;
690 ast_free((
void *) datastore->
uid);
691 datastore->
uid = NULL;
697 const char *uid_ptr =
uid;
698 char uuid_buf[AST_UUID_STR_LEN];
704 datastore = ao2_alloc(
sizeof(*datastore), sip_outbound_publish_datastore_destroy);
710 if (ast_strlen_zero(uid)) {
716 if (!datastore->
uid) {
727 ast_assert(datastore != NULL);
728 ast_assert(datastore->
info != NULL);
729 ast_assert(!ast_strlen_zero(datastore->
uid));
749 static int sip_publisher_service_queue(
void *data)
754 pjsip_tx_data *tdata;
761 if (pjsip_publishc_publish(publisher->
client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
766 ast_sip_add_body(tdata, &message->
body)) {
767 pjsip_tx_data_dec_ref(tdata);
771 set_transport(publisher, tdata);
773 status = pjsip_publishc_send(publisher->
client, tdata);
774 if (status == PJ_EBUSY) {
777 }
else if (status != PJ_SUCCESS) {
796 static int publisher_client_send(
void *obj,
void *arg,
void *data,
int flags)
801 size_t type_len = 0, subtype_len = 0, body_text_len = 0;
812 type_len = strlen(body->
type) + 1;
813 subtype_len = strlen(body->
subtype) + 1;
814 body_text_len = strlen(body->
body_text) + 1;
817 message =
ast_calloc(1,
sizeof(*message) + type_len + subtype_len + body_text_len);
849 publisher_client_send, (
void *)body, &res);
853 static int sip_outbound_publisher_set_uri(
854 pj_pool_t *
pool,
const char *uri,
const char *user, pj_str_t *res_uri)
858 pjsip_sip_uri *parsed_uri;
861 pj_strdup2_with_null(pool, &tmp, uri);
862 if (!(parsed = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0))) {
866 if (!(parsed_uri = pjsip_uri_get_uri(parsed))) {
870 if (!ast_strlen_zero(user)) {
871 pj_strdup2(pool, &parsed_uri->user, user);
874 res_uri->ptr = (
char*) pj_pool_alloc(pool, pjsip_max_url_size);
879 if ((size = pjsip_uri_print(PJSIP_URI_IN_OTHER, parsed_uri, res_uri->ptr,
880 pjsip_max_url_size - 1)) <= 0) {
883 res_uri->ptr[size] =
'\0';
884 res_uri->slen = size;
889 static int sip_outbound_publisher_set_uris(
891 pj_str_t *server_uri, pj_str_t *to_uri, pj_str_t *from_uri)
895 if (sip_outbound_publisher_set_uri(pool, publish->
server_uri, publisher->
user, server_uri)) {
896 ast_log(LOG_ERROR,
"Invalid server URI '%s' specified on outbound publish '%s'\n",
901 if (ast_strlen_zero(publish->
to_uri)) {
902 to_uri->ptr = server_uri->ptr;
903 to_uri->slen = server_uri->slen;
904 }
else if (sip_outbound_publisher_set_uri(pool, publish->
to_uri, publisher->
user, to_uri)) {
905 ast_log(LOG_ERROR,
"Invalid to URI '%s' specified on outbound publish '%s'\n",
915 if (ast_strlen_zero(publish->
from_uri)) {
916 from_uri->ptr = server_uri->ptr;
917 from_uri->slen = server_uri->slen;
918 }
else if (sip_outbound_publisher_set_uri(pool, publish->
from_uri, publisher->
user, from_uri)) {
919 ast_log(LOG_ERROR,
"Invalid from URI '%s' specified on outbound publish '%s'\n",
932 static void sip_outbound_publish_callback(
struct pjsip_publishc_cbparam *param);
935 static int sip_outbound_publisher_init(
void *data)
939 pjsip_publishc_opt opt = {
940 .queue_request = PJ_FALSE,
949 if (pjsip_publishc_create(ast_sip_get_pjsip_endpoint(), &opt,
950 ao2_bump(publisher), sip_outbound_publish_callback,
951 &publisher->
client) != PJ_SUCCESS) {
959 pjsip_route_hdr route_set, *route;
960 static const pj_str_t ROUTE_HNAME = {
"Route", 5 };
962 pj_list_init(&route_set);
964 if (!(route = pjsip_parse_hdr(pjsip_publishc_get_pool(publisher->
client), &ROUTE_HNAME,
966 pjsip_publishc_destroy(publisher->
client);
969 pj_list_insert_nodes_before(&route_set, route);
971 pjsip_publishc_set_route_set(publisher->
client, &route_set);
974 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
"URI Validation",
975 pjsip_max_url_size, pjsip_max_url_size);
977 ast_log(LOG_ERROR,
"Could not create pool for URI validation on outbound publish '%s'\n",
979 pjsip_publishc_destroy(publisher->
client);
983 if (sip_outbound_publisher_set_uris(pool, publisher, &server_uri, &from_uri, &to_uri)) {
984 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
985 pjsip_publishc_destroy(publisher->
client);
989 pj_cstr(&event, publish->
event);
990 if (pjsip_publishc_init(publisher->
client, &event, &server_uri, &from_uri, &to_uri,
992 ast_log(LOG_ERROR,
"Failed to initialize publishing client on outbound publish '%s'\n",
994 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
995 pjsip_publishc_destroy(publisher->
client);
999 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1003 static int sip_outbound_publisher_reinit(
void *obj,
void *arg,
int flags)
1005 return sip_outbound_publisher_init(obj);
1008 static int sip_outbound_publisher_reinit_all(
void *data)
1015 static void sip_outbound_publisher_destroy(
void *obj)
1026 ao2_cleanup(publisher->
owner);
1028 ast_free(publisher->
to_uri);
1039 publisher = ao2_alloc(
sizeof(*publisher) + (user ? strlen(user) : 0) + 1,
1040 sip_outbound_publisher_destroy);
1057 publisher->
timer.user_data = publisher;
1058 publisher->
timer.cb = sip_outbound_publish_timer_cb;
1060 strcpy(publisher->
user, user);
1062 *publisher->
user =
'\0';
1076 ast_log(LOG_ERROR,
"Unable to create publisher for outbound publish '%s'\n",
1089 sip_outbound_publisher_alloc(client, user);
1115 publisher = sip_outbound_publish_client_get_publisher(client, user);
1120 publisher_client_send(publisher, (
void *)body, &res, 0);
1132 static int explicit_publish_destroy(
void *data)
1142 pjsip_publishc_destroy(publisher->
client);
1152 static int cancel_and_unpublish(
void *obj,
void *arg,
int flags)
1170 ast_log(LOG_WARNING,
"Could not stop refresh timer on outbound publish '%s'\n",
1178 ast_log(LOG_WARNING,
"Could not send unpublish message on outbound publish '%s'\n",
1188 static void sip_outbound_publish_client_destroy(
void *obj)
1204 static void sip_outbound_publish_state_destroy(
void *obj)
1208 stop_publishing(state->
client, NULL);
1226 ao2_cleanup(state->
client);
1260 static void sip_outbound_publish_callback(
struct pjsip_publishc_cbparam *param)
1262 #define DESTROY_CLIENT() do { \
1263 pjsip_publishc_destroy(publisher->client); \
1264 publisher->client = NULL; \
1265 ao2_ref(publisher, -1); } while (0)
1270 pjsip_tx_data *tdata;
1279 ast_log(LOG_WARNING,
"Could not send unpublish message on outbound publish '%s'\n",
1288 if (param->code == 401 || param->code == 407) {
1289 pjsip_transaction *tsx = pjsip_rdata_get_tsx(param->rdata);
1292 param->rdata, tsx->last_tx, &tdata)) {
1293 set_transport(publisher, tdata);
1294 pjsip_publishc_send(publisher->
client, tdata);
1300 ast_log(LOG_ERROR,
"Reached maximum number of PUBLISH authentication attempts on outbound publish '%s'\n",
1310 if (param->code == 412) {
1312 if (sip_outbound_publisher_init(publisher)) {
1313 ast_log(LOG_ERROR,
"Failed to create a new outbound publish client for '%s' on 412 response\n",
1320 }
else if (param->code == 423) {
1322 pjsip_expires_hdr *expires;
1324 expires = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_MIN_EXPIRES, NULL);
1325 if (!expires || !expires->ivalue) {
1327 ast_log(LOG_ERROR,
"Received 423 response on outbound publish '%s' without a Min-Expires header\n",
1332 pjsip_publishc_update_expires(publisher->
client, expires->ivalue);
1334 }
else if (publisher->
sending) {
1339 if (!param->rdata) {
1340 ast_log(LOG_NOTICE,
"No response received for outbound publish '%s'\n",
1346 schedule_publish_refresh(publisher, param->expiration);
1350 if (!publisher->
client) {
1363 #define DATASTORE_BUCKETS 53
1365 static int datastore_hash(
const void *obj,
int flags)
1370 switch (flags & OBJ_SEARCH_MASK) {
1376 uid = datastore->
uid;
1387 static int datastore_cmp(
void *obj,
void *arg,
int flags)
1391 const char *right_key = arg;
1394 switch (flags & OBJ_SEARCH_MASK) {
1396 right_key = object_right->
uid;
1399 cmp = strcmp(object_left->
uid, right_key);
1402 cmp = strncmp(object_left->
uid, right_key, strlen(right_key));
1428 ao2_alloc(
sizeof(*state) + strlen(
id) + 1, sip_outbound_publish_state_destroy);
1434 state->
client = ao2_alloc(
sizeof(*state->
client), sip_outbound_publish_client_destroy);
1449 sip_outbound_publisher_hash_fn, NULL, sip_outbound_publisher_cmp_fn);
1457 strcpy(state->id,
id);
1464 ast_log(LOG_ERROR,
"No server URI specified on outbound publish '%s'\n",
1467 }
else if (ast_sip_validate_uri_length(publish->
server_uri)) {
1468 ast_log(LOG_ERROR,
"Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s' on outbound publish '%s'\n",
1472 }
else if (ast_strlen_zero(publish->
event)) {
1473 ast_log(LOG_ERROR,
"No event type specified for outbound publish '%s'\n",
1476 }
else if (!ast_strlen_zero(publish->
from_uri)
1477 && ast_sip_validate_uri_length(publish->
from_uri)) {
1478 ast_log(LOG_ERROR,
"From URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s' on outbound publish '%s'\n",
1482 }
else if (!ast_strlen_zero(publish->
to_uri)
1483 && ast_sip_validate_uri_length(publish->
to_uri)) {
1484 ast_log(LOG_ERROR,
"To URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s' on outbound publish '%s'\n",
1506 if (!can_reuse_publish(current_state->
client->
publish, publish)) {
1528 ast_log(LOG_ERROR,
"Unable to reinitialize client(s) for outbound publish '%s'\n",
1538 ao2_cleanup(old_publish);
1545 static int sip_outbound_publish_apply(
const struct ast_sorcery *sorcery,
void *obj)
1547 #define ADD_TO_NEW_STATES(__obj) \
1549 ao2_link(new_states, __obj); \
1550 ao2_ref(__obj, -1); } } while (0)
1564 outbound_publish_state_hash, NULL, outbound_publish_state_cmp);
1567 ast_log(LOG_ERROR,
"Unable to allocate new states container\n");
1575 if ((res = validate_publish_config(applied))) {
1576 ADD_TO_NEW_STATES(current_state);
1580 if (current_state && (res = current_state_reusable(applied, current_state))) {
1585 ADD_TO_NEW_STATES(current_state);
1586 return res == 1 ? 0 : -1;
1593 new_state = sip_outbound_publish_state_alloc(applied);
1595 ast_log(LOG_ERROR,
"Unable to create state for outbound publish '%s'\n",
1597 ADD_TO_NEW_STATES(current_state);
1602 !(publisher = sip_outbound_publish_client_add_publisher(new_state->
client, NULL))) {
1603 ADD_TO_NEW_STATES(current_state);
1607 ao2_cleanup(publisher);
1609 ADD_TO_NEW_STATES(new_state);
1610 ao2_cleanup(current_state);
1622 static int unload_module(
void)
1631 ast_debug(2,
"Waiting for publication to complete for unload.\n");
1632 remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME);
1634 ast_log(LOG_WARNING,
"Unload incomplete. Could not stop %d outbound publications. Try again later.\n",
1641 ao2_cleanup(shutdown_group);
1642 shutdown_group = NULL;
1647 static int load_module(
void)
1652 shutdown_group = ast_serializer_shutdown_group_alloc();
1653 if (!shutdown_group) {
1657 ast_sorcery_apply_config(ast_sip_get_sorcery(),
"res_pjsip_outbound_publish");
1658 ast_sorcery_apply_default(ast_sip_get_sorcery(),
"outbound-publish",
"config",
"pjsip.conf,criteria=type=outbound-publish");
1661 sip_outbound_publish_apply)) {
1662 ast_log(LOG_ERROR,
"Unable to register 'outbound-publish' type with sorcery\n");
1682 sip_outbound_publish_synchronize(NULL);
1685 pjsip_publishc_init_module(ast_sip_get_pjsip_endpoint());
1690 static int reload_module(
void)
1695 sip_outbound_publish_synchronize(NULL);
1700 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER,
"PJSIP Outbound Publish Support",
1701 .support_level = AST_MODULE_SUPPORT_CORE,
1702 .load = load_module,
1703 .reload = reload_module,
1704 .unload = unload_module,
1706 .requires =
"res_pjproject,res_pjsip",
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
AO2_STRING_FIELD_HASH_FN(transport_monitor, key)
Hashing function for struct transport_monitor.
unsigned int started
Publishing has been fully started and event type informed.
#define SCOPED_WRLOCK(varname, lock)
scoped lock specialization for write locks
The arg parameter is a search key, but is not an object.
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
int(* start_publishing)(struct ast_sip_outbound_publish *configuration, struct ast_sip_outbound_publish_client *client)
Called when a publisher should start publishing.
const ast_string_field outbound_proxy
Outbound proxy to use.
Structure for variables, used for configurations and for channel variables.
static pj_pool_t * pool
Global memory pool for configuration and timers.
char user[0]
User, if any, associated with the publisher.
Perform no matching, return all objects.
Full structure for sorcery.
Type for a default handler that should do nothing.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Structure for a data store type.
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
#define SORCERY_OBJECT(details)
Macro which must be used at the beginning of each sorcery capable object.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Return all matching objects.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
struct ast_sip_outbound_publish_client * client
Outbound publish client.
#define ast_strdup(str)
A wrapper for strdup()
Structure for a data store object.
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
struct ast_sip_body body
Optional body.
Outbound publish state information (persists for lifetime of a publish)
char * to_uri
The To URI for this specific publisher.
unsigned int multi_user
The publishing client is used for multiple users when true.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
Asterisk datastore objects.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
int(* stop_publishing)(struct ast_sip_outbound_publish_client *client)
Called when a publisher should stop publishing.
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
char body_contents[0]
Extra space for body contents.
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
Outbound publish client state information (persists for lifetime of a publish)
int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Type for default option handler for unsigned integers.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Callbacks that event publisher handlers will define.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
const char * event_name
The name of the event this handler deals with.
#define AST_STRING_FIELD(name)
Declare a string field.
const struct ast_datastore_info * info
void(* destroy)(void *data)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
struct ao2_container * container
struct ast_taskprocessor * ast_sip_create_serializer_group(const char *name, struct ast_serializer_shutdown_group *shutdown_group)
Create a new serializer for SIP tasks.
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
struct ao2_container * datastores
Publisher datastores set up by handlers.
struct sip_outbound_publisher::@468 queue
Queue of outgoing publish messages to send.
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
pj_timer_entry timer
Timer entry for refreshing publish.
struct ast_taskprocessor * serializer
Serializer for stuff and things.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
char * from_uri
The From URI for this specific publisher.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
struct ast_sip_outbound_publish_client * owner
The client object that 'owns' this client.
#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.
const ast_string_field transport
Explicit transport to use for publish.
pjsip_publishc * client
Underlying publish client.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
unsigned int max_auth_attempts
Maximum number of auth attempts before stopping the publish client.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Type for default option handler for bools (ast_true/ast_false)
unsigned int auth_attempts
The number of auth attempts done.
Outbound publish information.
const ast_string_field server_uri
URI for the entity and server.
Queued outbound publish message.
struct ast_sip_outbound_publish * publish
Outbound publish information.
#define DATASTORE_BUCKETS
Number of buckets for datastore container.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define SCOPED_AO2LOCK(varname, obj)
scoped lock specialization for ao2 mutexes.
#define ast_calloc(num, len)
A wrapper for calloc()
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
Module has failed to load, may be in an inconsistent state.
An API for managing task processing threads that can be shared across modules.
structure to hold users read from users.conf
void * ast_sorcery_retrieve_by_fields(const struct ast_sorcery *sorcery, const char *type, unsigned int flags, struct ast_variable *fields)
Retrieve an object or multiple objects using specific fields.
#define ast_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
const ast_string_field event
The event type to publish.
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
struct ao2_container * publishers
Container of all the client publishing objects.
The arg parameter is an object of the same type.
struct sip_outbound_publish_message * sending
The message currently being sent.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
A ast_taskprocessor structure is a singleton by name.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
const ast_string_field from_uri
URI for the From header.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
Type for default option handler for stringfields.
unsigned int expiration
Requested expiration time.
unsigned int destroy
Publish client should be destroyed.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
const ast_string_field to_uri
URI for the To header.
Search option field mask.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
static pj_timer_heap_t * timer_heap
Global timer heap.
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
#define ao2_link(container, obj)
Add an object to a container.