86 pjsip_expires_hdr *expires;
91 expiration = contact->expires;
92 }
else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL))) {
94 expiration = expires->ivalue;
103 if (expiration < aor->minimum_expiration) {
125 pjsip_uri *contact_uri;
131 contact_uri = pjsip_parse_uri(details->
pool, (
char*)contact->
uri, strlen(contact->
uri), 0);
137 return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->
uri, contact_uri) == PJ_SUCCESS) ?
CMP_MATCH : 0;
142 struct ast_sip_aor *aor,
int permanent,
int *added,
int *updated,
int *deleted)
144 pjsip_contact_hdr *previous =
NULL;
145 pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
150 for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(
pool)) {
157 if (expiration != 0 || previous) {
164 }
else if (previous && previous->star) {
170 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
174 details.uri = pjsip_uri_get_uri(contact->uri);
177 if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri,
sizeof(contact_uri)) < 0) {
194 }
else if (expiration) {
227 pjsip_tx_data *tdata = arg;
231 pj_strdup2_with_null(tdata->pool, &
uri, contact->
uri);
232 parsed = pjsip_parse_uri(tdata->pool,
uri.ptr,
uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
234 if (parsed && (PJSIP_URI_SCHEME_IS_SIP(parsed) || PJSIP_URI_SCHEME_IS_SIPS(parsed))) {
235 pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
242 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
255 pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
path_hdr_name,
NULL);
266 ast_str_set(path_str, 0,
"%.*s", (
int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
268 while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
path_hdr_name, path_hdr->next))) {
269 ast_str_append(path_str, 0,
",%.*s", (
int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
277 const pj_str_t path_supported_name = {
"path", 4 };
278 pjsip_supported_hdr *supported_hdr;
281 if (!
aor->support_path) {
293 supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED,
NULL);
294 if (!supported_hdr) {
299 for (i = 0; i < supported_hdr->count; i++) {
300 if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
417 sizeof(*monitor) + 1 + aor_size + contact_name_len);
441 const char *reason =
"none";
445 reason =
"registration failure";
448 reason =
"remove existing";
451 reason =
"remove unavailable";
454 reason =
"expiration";
464 ast_verb(3,
"Removed contact '%s' from AOR '%s' due to %s\n",
493 int remove_unavailable = 0;
494 int left_unreachable;
495 int right_unreachable;
498 remove_unavailable =
aor->remove_unavailable;
502 if (!remove_unavailable) {
522 if (left_unreachable != right_unreachable) {
524 if (left_unreachable)
return -1;
525 if (right_unreachable)
return 1;
566 unsigned int to_remove,
unsigned int remove_existing)
591 while (to_remove--) {
596 if (!remove_existing) {
656 const char *aor_name,
660 static const pj_str_t USER_AGENT = {
"User-Agent", 10 };
669 pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
671 pjsip_tx_data *tdata;
675 pjsip_user_agent_hdr *user_agent_hdr;
676 pjsip_expires_hdr *expires_hdr;
677 pjsip_via_hdr *via_hdr;
678 pjsip_via_hdr *via_hdr_last;
681 pjsip_cid_hdr *call_id_hdr;
687 "Contact Comparison", 1024, 256);
689 response->code = 500;
696 if (
aor->permanent_contacts) {
705 response->code = 400;
712 ast_log(
LOG_WARNING,
"Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
714 response->code = 420;
719 if (
aor->remove_existing) {
721 contact_count =
MAX(updated + added - deleted, 0);
728 if (!existing_contacts) {
729 response->code = 500;
740 if (contact_count >
aor->max_contacts &&
aor->remove_unavailable) {
742 int unavail_count = 0;
746 if (!unavail_contacts) {
747 response->code = 500;
752 if (unavail_contacts) {
757 if (contact_count - unavail_count <= aor->max_contacts) {
766 if (contact_count >
aor->max_contacts) {
769 ast_log(
LOG_WARNING,
"Registration attempt from endpoint '%s' (%s:%d) to AOR '%s' will exceed max contacts of %u\n",
771 aor_name,
aor->max_contacts);
772 response->code = 403;
778 user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT,
NULL);
779 if (user_agent_hdr) {
780 alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
786 via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA,
NULL);
789 while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
790 PJSIP_H_VIA, via_hdr->next)) !=
NULL) {
791 via_hdr_last = via_hdr;
793 alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
796 via_port=via_hdr_last->sent_by.port;
799 call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID,
NULL);
801 alloc_size = pj_strlen(&call_id_hdr->id) + 1;
807 for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) {
812 if (contact_hdr->star) {
819 if (existing_contacts) {
820 ao2_ref(existing_contacts, -1);
821 existing_contacts =
NULL;
826 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
832 details.uri = pjsip_uri_get_uri(contact_hdr->uri);
833 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri,
sizeof(contact_uri));
840 if (contact && existing_contacts) {
849 ast_verb(3,
"Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
850 contact_uri, aor_name);
862 contact_uri, aor_name);
867 size_t contact_name_len;
868 const char *contact_name;
878 + contact_name_len,
NULL);
890 ast_verb(3,
"Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
903 }
else if (expiration) {
907 if (!contact_update) {
908 ast_log(
LOG_ERROR,
"Failed to update contact '%s' expiration time to %d seconds.\n",
909 contact->uri, expiration);
927 ast_log(
LOG_ERROR,
"Failed to update contact '%s' expiration time to %d seconds.\n",
928 contact->uri, expiration);
933 ast_debug(3,
"Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
934 contact_uri, aor_name, expiration);
963 if (
aor->remove_existing && existing_contacts) {
966 if (contact_count >
aor->max_contacts) {
969 aor->remove_existing);
971 ao2_ref(existing_contacts, -1);
980 response->code = 500;
990 if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES,
NULL))) {
992 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
995 response->tdata = tdata;
1001 const char *aor_name)
1022 if (response.
tdata) {
1037 if (!strcmp(aor_name,
id)) {
1038 ast_debug(3,
"Matched id '%s' to aor '%s'\n",
id, aor_name);
1045static char *
find_aor_name(
const pj_str_t *pj_username,
const pj_str_t *pj_domain,
const char *aors)
1047 char *configured_aors;
1051 char *username, *domain;
1055 username =
ast_alloca(pj_strlen(pj_username) + 1);
1061 sprintf(id_domain,
"%s@%s", username,
domain);
1066 configured_aors = aors_buf;
1076 char *id_domain_alias =
ast_alloca(strlen(username) + strlen(alias->
domain) + 2);
1078 sprintf(id_domain_alias,
"%s@%s", username, alias->
domain);
1081 configured_aors = strcpy(aors_buf, aors);
1083 if (
match_aor(aor_name, id_domain_alias)) {
1095 configured_aors = strcpy(aors_buf, aors);
1108 char *aor_name =
NULL;
1118 uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
1120 pj_strassign(&username, &uri->user);
1129 pj_ssize_t semi = pj_strcspn2(&username,
";");
1130 if (semi < pj_strlen(&username)) {
1131 username.slen = semi;
1137 ast_debug(3,
"Matched aor '%s' by To username\n", aor_name);
1141 while ((
header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION,
1143 if (
header && !pj_stricmp2(&
header->scheme,
"digest")) {
1145 &
header->credential.digest.realm, endpoint->
aors);
1147 ast_debug(3,
"Matched aor '%s' by Authentication username\n", aor_name);
1168 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1179 const char *aor_name;
1181 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
1190 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1194 if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
1198 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1214 ast_log(
LOG_WARNING,
"AOR '%s' has no configured max_contacts. Endpoint '%s' (%s:%d) unable to register\n",
1216 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1298 "registration",
"start");
1323#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES "PJSIPShowRegistrationInboundContactStatuses"
1324#define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"
1327 .name = {
"Registrar", 9 },
1329 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
1401 ast_log(
LOG_ERROR,
"Could not create thread for checking contact expiration.\n");
1411 ast_debug(3,
"Interval = 0, shutting thread down\n");
1423 const pj_str_t STR_REGISTER = {
"REGISTER", 8 };
1473 .
requires =
"res_pjproject,res_pjsip",
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_iterator_next(iter)
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_NOLOCK
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_unlink(container, obj)
Remove an object from a container.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
#define ao2_alloc(data_size, destructor_fn)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
void astman_append(struct mansession *s, const char *fmt,...)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
#define ast_named_lock_put(lock)
Put a named lock handle away.
#define ast_named_lock_get(lock_type, keyspace, key)
Geta named lock handle.
@ AST_NAMED_LOCK_TYPE_MUTEX
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
char * strsep(char **str, const char *delims)
#define ast_variable_new(name, value, filename)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_debug(level,...)
Log a DEBUG message.
#define VERBOSITY_ATLEAST(level)
#define ast_verb(level,...)
#define AST_PTHREADT_NULL
static struct ao2_container * endpoints
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_CHANNEL_DEPEND
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_SYSTEM_NAME
struct ao2_container * container
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
void ast_sip_unregister_service(pjsip_module *module)
@ AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME
@ AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME
void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *req_type)
Send a security event notification for when a request is not supported.
struct ao2_container * ast_sip_get_endpoints(void)
Retrieve any endpoints available to sorcery.
int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code, struct ast_sip_contact *contact, pjsip_tx_data **p_tdata)
General purpose method for creating a SIP response.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
int ast_sip_for_each_contact(const struct ast_sip_aor *aor, ao2_callback_fn on_contact, void *arg)
For every contact on an AOR call the given 'on_contact' handler.
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
For every aor in the comma separated aors string call the given 'on_aor' handler.
void ast_sip_add_date_header(pjsip_tx_data *tdata)
Adds a Date header to the tdata, formatted like: Date: Wed, 01 Jan 2021 14:53:01 GMT.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *ao2_data, ast_transport_monitor_data_matcher matches)
Register a reliable transport shutdown monitor callback replacing any duplicate.
void ast_sip_transport_monitor_unregister(pjsip_transport *transport, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
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.
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
Formats the contact and sends over AMI.
unsigned int ast_sip_get_contact_expiration_check_interval(void)
Retrieve the system contact expiration check interval setting.
struct ao2_container * ast_sip_location_retrieve_aor_contacts_nolock(const struct ast_sip_aor *aor)
Retrieve all contacts currently available for an AOR without locking the AOR.
unsigned int ast_sip_get_ignore_uri_user_options(void)
Retrieve the global setting 'ignore_uri_user_options'.
struct ast_sip_contact * ast_sip_location_retrieve_contact(const char *contact_name)
Retrieve a named contact.
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
struct ast_sip_contact * ast_sip_location_create_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, const char *via_addr, int via_port, const char *call_id, int prune_on_boot, struct ast_sip_endpoint *endpoint)
Create a new contact for an AOR without locking the AOR.
#define PJSIP_EXPIRES_NOT_SPECIFIED
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
int ast_sip_location_update_contact(struct ast_sip_contact *contact)
Update a contact.
int ast_sip_send_stateful_response(pjsip_rx_data *rdata, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
Send a stateful response to an out of dialog request.
int ast_sip_contact_to_str(void *object, void *arg, int flags)
Handler used to convert a contact to a string.
int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
Delete a contact.
void ast_sip_report_failed_acl(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *name)
Send a security event notification for when an ACL check fails.
static int ami_registrations_endpoint(void *obj, void *arg, int flags)
static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact *right)
static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport, struct ast_sip_contact *contact, const char *aor_name)
static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
static int match_aor(const char *aor_name, const char *id)
static int registrar_add_unreachable(void *obj, void *arg, int flags)
Internal callback function which adds any contact which is unreachable.
static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
static int ami_registrations_endpoints(void *arg)
static int register_contact_transport_remove_cb(void *data)
static void * check_expiration_thread(void *data)
static int sip_contact_to_str(void *acp, void *arg, int flags)
#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES
static int pjsip_max_url_size
static pthread_t check_thread
Thread keeping things alive.
static int registrar_find_contact(void *obj, void *arg, int flags)
Callback function for finding a contact.
static int ami_show_registration_contact_statuses(struct mansession *s, const struct message *m)
static void expiration_global_loaded(const char *object_type)
static void register_aor_core(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name, struct ao2_container *contacts, struct aor_core_response *response)
static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts, unsigned int to_remove, unsigned int remove_existing)
static int registrar_add_contact(void *obj, void *arg, int flags)
Internal function which adds a contact to a response.
static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
static unsigned int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
Internal function which returns the expiration time for a contact.
static int vec_contact_add(void *obj, void *arg, int flags)
static int expire_contact(void *obj, void *arg, int flags)
Callback function which deletes a contact.
static int ami_registrations_aor(void *obj, void *arg, int flags)
static struct ast_sip_aor * find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
static int register_aor(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name)
@ CONTACT_DELETE_EXISTING
@ CONTACT_DELETE_SHUTDOWN
@ CONTACT_DELETE_UNAVAILABLE
static struct ast_sorcery_observer expiration_global_observer
Observer which is used to update our interval when the global setting changes.
static int pj_max_hostname
static unsigned int check_interval
The global interval at which to check for contact expiration.
static int registrar_validate_contacts(const pjsip_rx_data *rdata, pj_pool_t *pool, struct ao2_container *contacts, struct ast_sip_aor *aor, int permanent, int *added, int *updated, int *deleted)
Internal function which validates provided Contact headers to confirm that they are acceptable,...
static pjsip_module registrar_module
#define AMI_SHOW_REGISTRATIONS
static int registrar_add_non_permanent(void *obj, void *arg, int flags)
Callback function which adds non-permanent contacts to a container.
static int load_module(void)
static void register_contact_transport_shutdown_cb(void *data)
static int unload_module(void)
static int contact_transport_monitor_matcher(void *a, void *b)
static const pj_str_t path_hdr_name
static int ami_show_registrations(struct mansession *s, const struct message *m)
static int registrar_delete_contact(void *obj, void *arg, int flags)
Internal function used to delete a contact from an AOR.
static char * find_aor_name(const pj_str_t *pj_username, const pj_str_t *pj_domain, const char *aors)
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
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.
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.
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
unsigned int minimum_expiration
unsigned int max_contacts
unsigned int maximum_expiration
unsigned int default_expiration
const ast_string_field domain
An entity with which Asterisk communicates.
const ast_string_field aors
struct ast_sip_identify_by_vector ident_method_order
Interface for a sorcery object type observer.
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
Support for dynamic strings.
Structure for variables, used for configurations and for channel variables.
In case you didn't read that giant block of text above the mansession_session struct,...
An API for managing task processing threads that can be shared across modules.
#define ast_test_suite_event_notify(s, f,...)
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
#define ast_pthread_create_background(a, b, c, d)
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_MAX_SIZE(vec)
Get the maximum number of elements the vector can currently hold.
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
#define AST_VECTOR(name, type)
Define a vector structure.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.