Asterisk - The Open Source Telephony Project  18.5.0
Data Structures | Macros | Enumerations | Functions | Variables
res_pjsip_registrar.c File Reference
#include "asterisk.h"
#include <signal.h>
#include <pjsip.h>
#include <pjsip_ua.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/module.h"
#include "asterisk/paths.h"
#include "asterisk/test.h"
#include "asterisk/taskprocessor.h"
#include "asterisk/manager.h"
#include "asterisk/named_locks.h"
#include "asterisk/res_pjproject.h"
#include "res_pjsip/include/res_pjsip_private.h"
Include dependency graph for res_pjsip_registrar.c:

Go to the source code of this file.

Data Structures

struct  aor_core_response
 
struct  contact_transport_monitor
 
struct  registrar_contact_details
 Structure used for finding contact. More...
 

Macros

#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES   "PJSIPShowRegistrationInboundContactStatuses"
 
#define AMI_SHOW_REGISTRATIONS   "PJSIPShowRegistrationsInbound"
 

Enumerations

enum  contact_delete_type {
  CONTACT_DELETE_ERROR, CONTACT_DELETE_EXISTING, CONTACT_DELETE_EXPIRE, CONTACT_DELETE_REQUEST,
  CONTACT_DELETE_SHUTDOWN
}
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static int ami_registrations_aor (void *obj, void *arg, int flags)
 
static int ami_registrations_endpoint (void *obj, void *arg, int flags)
 
static int ami_registrations_endpoints (void *arg)
 
static int ami_show_registration_contact_statuses (struct mansession *s, const struct message *m)
 
static int ami_show_registrations (struct mansession *s, const struct message *m)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
 AST_VECTOR (excess_contact_vector, struct ast_sip_contact *)
 
static int build_path_data (pjsip_rx_data *rdata, struct ast_str **path_str)
 
static void * check_expiration_thread (void *data)
 
static int contact_transport_monitor_matcher (void *a, void *b)
 
static void expiration_global_loaded (const char *object_type)
 
static int expire_contact (void *obj, void *arg, int flags)
 Callback function which deletes a contact. More...
 
static char * find_aor_name (const pj_str_t *pj_username, const pj_str_t *pj_domain, const char *aors)
 
static struct ast_sip_aorfind_registrar_aor (struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
 
static int load_module (void)
 
static int match_aor (const char *aor_name, const char *id)
 
static int register_aor (pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name)
 
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 int register_contact_transport_remove_cb (void *data)
 
static void register_contact_transport_shutdown_cb (void *data)
 
static int registrar_add_contact (void *obj, void *arg, int flags)
 Internal function which adds a contact to a response. More...
 
static int registrar_add_non_permanent (void *obj, void *arg, int flags)
 Callback function which adds non-permanent contacts to a container. More...
 
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_delete_contact (void *obj, void *arg, int flags)
 Internal function used to delete a contact from an AOR. More...
 
static int registrar_find_contact (void *obj, void *arg, int flags)
 Callback function for finding a contact. More...
 
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. More...
 
static pj_bool_t registrar_on_rx_request (struct pjsip_rx_data *rdata)
 
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, and returns number of contacts. More...
 
static int registrar_validate_path (pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
 
static void remove_excess_contacts (struct ao2_container *contacts, struct ao2_container *response_contacts, unsigned int to_remove)
 
static int sip_contact_to_str (void *acp, void *arg, int flags)
 
static int unload_module (void)
 
static int vec_contact_add (void *obj, void *arg, int flags)
 
static int vec_contact_cmp (struct ast_sip_contact *left, struct ast_sip_contact *right)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Registrar Support" , .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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3, .requires = "res_pjproject,res_pjsip", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static unsigned int check_interval
 The global interval at which to check for contact expiration. More...
 
static pthread_t check_thread = AST_PTHREADT_NULL
 Thread keeping things alive. More...
 
static struct ast_sorcery_observer expiration_global_observer
 Observer which is used to update our interval when the global setting changes. More...
 
static const pj_str_t path_hdr_name = { "Path", 4 }
 
static int pj_max_hostname = PJ_MAX_HOSTNAME
 
static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE
 
static pjsip_module registrar_module
 

Macro Definition Documentation

◆ AMI_SHOW_REGISTRATION_CONTACT_STATUSES

#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES   "PJSIPShowRegistrationInboundContactStatuses"

Definition at line 1225 of file res_pjsip_registrar.c.

Referenced by load_module(), and unload_module().

◆ AMI_SHOW_REGISTRATIONS

#define AMI_SHOW_REGISTRATIONS   "PJSIPShowRegistrationsInbound"

Definition at line 1226 of file res_pjsip_registrar.c.

Referenced by load_module(), and unload_module().

Enumeration Type Documentation

◆ contact_delete_type

Enumerator
CONTACT_DELETE_ERROR 
CONTACT_DELETE_EXISTING 
CONTACT_DELETE_EXPIRE 
CONTACT_DELETE_REQUEST 
CONTACT_DELETE_SHUTDOWN 

Definition at line 204 of file res_pjsip_registrar.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1375 of file res_pjsip_registrar.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1375 of file res_pjsip_registrar.c.

◆ ami_registrations_aor()

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

Definition at line 1133 of file res_pjsip_registrar.c.

References ast_sip_ami::arg, ast_free, ast_sip_create_ami_event(), ast_sip_for_each_contact(), ast_sip_sorcery_object_to_ami(), ast_str_append(), ast_str_buffer(), astman_append(), buf, ast_sip_ami::count, RAII_VAR, ast_sip_ami::s, and sip_contact_to_str().

Referenced by ami_registrations_endpoint().

1134 {
1135  struct ast_sip_aor *aor = obj;
1136  struct ast_sip_ami *ami = arg;
1137  int *count = ami->arg;
1138  RAII_VAR(struct ast_str *, buf,
1139  ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
1140 
1141  if (!buf) {
1142  return -1;
1143  }
1144 
1146  ast_str_append(&buf, 0, "Contacts: ");
1148  ast_str_append(&buf, 0, "\r\n");
1149 
1150  astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1151  (*count)++;
1152  return 0;
1153 }
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:3080
A SIP address of record.
Definition: res_pjsip.h:361
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
void * arg
Definition: res_pjsip.h:2745
AMI variable container.
Definition: res_pjsip.h:2737
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:1091
#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:911
struct mansession * s
Definition: res_pjsip.h:2739
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ast_free(a)
Definition: astmm.h:182
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.
static int sip_contact_to_str(void *acp, void *arg, int flags)
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
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 &#39;on_contact&#39; handler.
Definition: location.c:719

◆ ami_registrations_endpoint()

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

Definition at line 1155 of file res_pjsip_registrar.c.

References ami_registrations_aor(), ast_sip_endpoint::aors, and ast_sip_for_each_aor().

Referenced by ami_registrations_endpoints().

1156 {
1157  struct ast_sip_endpoint *endpoint = obj;
1158  return ast_sip_for_each_aor(
1159  endpoint->aors, ami_registrations_aor, arg);
1160 }
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 &#39;on_aor&#39; handler. ...
Definition: location.c:684
static int ami_registrations_aor(void *obj, void *arg, int flags)
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
const ast_string_field aors
Definition: res_pjsip.h:821

◆ ami_registrations_endpoints()

static int ami_registrations_endpoints ( void *  arg)
static

Definition at line 1162 of file res_pjsip_registrar.c.

References ami_registrations_endpoint(), ao2_callback, ao2_cleanup, ast_sip_get_endpoints(), endpoints, OBJ_NODATA, and RAII_VAR.

Referenced by ami_show_registrations().

1163 {
1164  RAII_VAR(struct ao2_container *, endpoints,
1166 
1167  if (!endpoints) {
1168  return 0;
1169  }
1170 
1172  return 0;
1173 }
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#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:911
static struct ao2_container * endpoints
static int ami_registrations_endpoint(void *obj, void *arg, int flags)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
struct ao2_container * ast_sip_get_endpoints(void)
Retrieve any endpoints available to sorcery.
Generic container type.

◆ ami_show_registration_contact_statuses()

static int ami_show_registration_contact_statuses ( struct mansession s,
const struct message m 
)
static

Definition at line 1190 of file res_pjsip_registrar.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, ast_sip_contact::aor, ast_sip_contact_wrapper::aor_id, AST_RETRIEVE_FLAG_ALL, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_format_contact_ami(), ast_sip_get_sorcery(), ast_sorcery_object_get_id(), ast_sorcery_retrieve_by_fields(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_sip_contact_wrapper::contact, ast_sip_contact_wrapper::contact_id, ast_sip_ami::count, ast_sip_ami::m, NULL, and ast_sip_ami::s.

Referenced by load_module().

1191 {
1192  int count = 0;
1193  struct ast_sip_ami ami = { .s = s, .m = m, .arg = NULL, .action_id = astman_get_header(m, "ActionID"), };
1194  struct ao2_container *contacts = ast_sorcery_retrieve_by_fields(
1196  struct ao2_iterator i;
1197  struct ast_sip_contact *contact;
1198 
1199  astman_send_listack(s, m, "Following are ContactStatusEvents for each Inbound "
1200  "registration", "start");
1201 
1202  if (contacts) {
1203  i = ao2_iterator_init(contacts, 0);
1204  while ((contact = ao2_iterator_next(&i))) {
1205  struct ast_sip_contact_wrapper wrapper;
1206 
1207  wrapper.aor_id = (char *)contact->aor;
1208  wrapper.contact = contact;
1209  wrapper.contact_id = (char *)ast_sorcery_object_get_id(contact);
1210 
1211  ast_sip_format_contact_ami(&wrapper, &ami, 0);
1212  count++;
1213 
1214  ao2_ref(contact, -1);
1215  }
1217  ao2_ref(contacts, -1);
1218  }
1219 
1220  astman_send_list_complete_start(s, m, "ContactStatusDetailComplete", count);
1222  return 0;
1223 }
const struct message * m
Definition: res_pjsip.h:2741
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
AMI variable container.
Definition: res_pjsip.h:2737
Perform no matching, return all objects.
Definition: sorcery.h:123
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
Return all matching objects.
Definition: sorcery.h:120
#define NULL
Definition: resample.c:96
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
A wrapper for contact that adds the aor_id and a consistent contact id. Used by ast_sip_for_each_cont...
Definition: res_pjsip.h:396
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct mansession * s
Definition: res_pjsip.h:2739
Contact associated with an address of record.
Definition: res_pjsip.h:281
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
Formats the contact and sends over AMI.
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.
Definition: sorcery.c:1897
const ast_string_field aor
Definition: res_pjsip.h:303
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
Generic container type.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201

◆ ami_show_registrations()

static int ami_show_registrations ( struct mansession s,
const struct message m 
)
static

Definition at line 1175 of file res_pjsip_registrar.c.

References ami_registrations_endpoints(), astman_get_header(), astman_send_list_complete_end(), astman_send_list_complete_start(), astman_send_listack(), ast_sip_ami::count, ast_sip_ami::m, and ast_sip_ami::s.

Referenced by load_module().

1176 {
1177  int count = 0;
1178  struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };
1179 
1180  astman_send_listack(s, m, "Following are Events for each Inbound registration",
1181  "start");
1182 
1184 
1185  astman_send_list_complete_start(s, m, "InboundRegistrationDetailComplete", count);
1187  return 0;
1188 }
const struct message * m
Definition: res_pjsip.h:2741
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:3237
AMI variable container.
Definition: res_pjsip.h:2737
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
Definition: manager.c:2820
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:3245
struct mansession * s
Definition: res_pjsip.h:2739
static int ami_registrations_endpoints(void *arg)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:3201

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 1375 of file res_pjsip_registrar.c.

◆ AST_VECTOR()

AST_VECTOR ( excess_contact_vector  ,
struct ast_sip_contact  
)

◆ build_path_data()

static int build_path_data ( pjsip_rx_data *  rdata,
struct ast_str **  path_str 
)
static

Definition at line 252 of file res_pjsip_registrar.c.

References ast_str_append(), ast_str_create, ast_str_set(), and NULL.

Referenced by registrar_validate_path().

253 {
254  pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL);
255 
256  if (!path_hdr) {
257  return 0;
258  }
259 
260  *path_str = ast_str_create(64);
261  if (!*path_str) {
262  return -1;
263  }
264 
265  ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
266 
267  while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
268  ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
269  }
270 
271  return 0;
272 }
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:1091
#define NULL
Definition: resample.c:96
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
Definition: strings.h:1065
static const pj_str_t path_hdr_name
#define ast_str_create(init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:620

◆ check_expiration_thread()

static void* check_expiration_thread ( void *  data)
static

Definition at line 1266 of file res_pjsip_registrar.c.

References ao2_callback, ao2_container_count(), ao2_ref, ast_debug, AST_RETRIEVE_FLAG_MULTIPLE, ast_sip_get_sorcery(), ast_sorcery_retrieve_by_fields(), ast_tvnow(), ast_variable_new, ast_variables_destroy(), expire_contact(), NULL, OBJ_NODATA, and var.

Referenced by expiration_global_loaded().

1267 {
1268  struct ao2_container *contacts;
1269  struct ast_variable *var;
1270  char *time = alloca(64);
1271 
1272  while (check_interval) {
1273  sleep(check_interval);
1274 
1275  sprintf(time, "%ld", ast_tvnow().tv_sec);
1276  var = ast_variable_new("expiration_time <=", time, "");
1277 
1278  ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval);
1279 
1280  contacts = ast_sorcery_retrieve_by_fields(ast_sip_get_sorcery(), "contact",
1282 
1283  ast_variables_destroy(var);
1284  if (contacts) {
1285  ast_debug(3, "Expiring %d contacts\n", ao2_container_count(contacts));
1287  ao2_ref(contacts, -1);
1288  }
1289  }
1290 
1291  return NULL;
1292 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
Return all matching objects.
Definition: sorcery.h:120
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_variable_new(name, value, filename)
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.
Definition: sorcery.c:1897
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
Generic container type.
static unsigned int check_interval
The global interval at which to check for contact expiration.
static int expire_contact(void *obj, void *arg, int flags)
Callback function which deletes a contact.

◆ contact_transport_monitor_matcher()

static int contact_transport_monitor_matcher ( void *  a,
void *  b 
)
static

Definition at line 321 of file res_pjsip_registrar.c.

References a, contact_transport_monitor::aor_name, b, and contact_transport_monitor::contact_name.

Referenced by register_aor_core(), and registrar_contact_delete().

322 {
323  struct contact_transport_monitor *ma = a;
324  struct contact_transport_monitor *mb = b;
325 
326  return strcmp(ma->aor_name, mb->aor_name) == 0
327  && strcmp(ma->contact_name, mb->contact_name) == 0;
328 }
char * contact_name
Sorcery contact name to remove on transport shutdown.
static struct test_val b
static struct test_val a

◆ expiration_global_loaded()

static void expiration_global_loaded ( const char *  object_type)
static

Definition at line 1294 of file res_pjsip_registrar.c.

References ast_debug, ast_log, ast_pthread_create_background, AST_PTHREADT_NULL, ast_sip_get_contact_expiration_check_interval(), check_expiration_thread(), LOG_ERROR, and NULL.

1295 {
1297 
1298  /* Observer calls are serialized so this is safe without it's own lock */
1299  if (check_interval) {
1302  ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n");
1303  return;
1304  }
1305  ast_debug(3, "Interval = %d, starting thread\n", check_interval);
1306  }
1307  } else {
1309  pthread_kill(check_thread, SIGURG);
1310  pthread_join(check_thread, NULL);
1312  ast_debug(3, "Interval = 0, shutting thread down\n");
1313  }
1314  }
1315 }
static pthread_t check_thread
Thread keeping things alive.
#define NULL
Definition: resample.c:96
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:567
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define AST_PTHREADT_NULL
Definition: lock.h:66
#define LOG_ERROR
Definition: logger.h:285
unsigned int ast_sip_get_contact_expiration_check_interval(void)
Retrieve the system contact expiration check interval setting.
static void * check_expiration_thread(void *data)
static unsigned int check_interval
The global interval at which to check for contact expiration.

◆ expire_contact()

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

Callback function which deletes a contact.

Definition at line 1242 of file res_pjsip_registrar.c.

References ao2_lock, ao2_unlock, ast_sip_contact::aor, ast_named_lock_get, ast_named_lock_put, AST_NAMED_LOCK_TYPE_MUTEX, ast_tvdiff_ms(), ast_tvnow(), CONTACT_DELETE_EXPIRE, ast_sip_contact::expiration_time, lock, NULL, and registrar_contact_delete().

Referenced by check_expiration_thread().

1243 {
1244  struct ast_sip_contact *contact = obj;
1245  struct ast_named_lock *lock;
1246 
1247  lock = ast_named_lock_get(AST_NAMED_LOCK_TYPE_MUTEX, "aor", contact->aor);
1248  if (!lock) {
1249  return 0;
1250  }
1251 
1252  /*
1253  * We need to check the expiration again with the aor lock held
1254  * in case another thread is attempting to renew the contact.
1255  */
1256  ao2_lock(lock);
1257  if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) {
1259  }
1260  ao2_unlock(lock);
1261  ast_named_lock_put(lock);
1262 
1263  return 0;
1264 }
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define ao2_unlock(a)
Definition: astobj2.h:730
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define NULL
Definition: resample.c:96
ast_mutex_t lock
Definition: app_meetme.c:1091
#define ao2_lock(a)
Definition: astobj2.h:718
Contact associated with an address of record.
Definition: res_pjsip.h:281
struct timeval expiration_time
Definition: res_pjsip.h:305
const ast_string_field aor
Definition: res_pjsip.h:303
static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport, struct ast_sip_contact *contact, const char *aor_name)
#define ast_named_lock_get(lock_type, keyspace, key)
Geta named lock handle.
Definition: named_locks.h:83
#define ast_named_lock_put(lock)
Put a named lock handle away.
Definition: named_locks.h:93

◆ find_aor_name()

static char* find_aor_name ( const pj_str_t *  pj_username,
const pj_str_t *  pj_domain,
const char *  aors 
)
static

Definition at line 947 of file res_pjsip_registrar.c.

References ao2_cleanup, ast_alloca, ast_copy_pj_str(), ast_sip_get_sorcery(), ast_sorcery_retrieve_by_id(), ast_strdup, ast_strdupa, ast_strip(), ast_strlen_zero, ast_sip_domain_alias::domain, match_aor(), NULL, and strsep().

Referenced by find_registrar_aor().

948 {
949  char *configured_aors;
950  char *aors_buf;
951  char *aor_name;
952  char *id_domain;
953  char *username, *domain;
954  struct ast_sip_domain_alias *alias;
955 
956  /* Turn these into C style strings for convenience */
957  username = ast_alloca(pj_strlen(pj_username) + 1);
958  ast_copy_pj_str(username, pj_username, pj_strlen(pj_username) + 1);
959  domain = ast_alloca(pj_strlen(pj_domain) + 1);
960  ast_copy_pj_str(domain, pj_domain, pj_strlen(pj_domain) + 1);
961 
962  id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
963  sprintf(id_domain, "%s@%s", username, domain);
964 
965  aors_buf = ast_strdupa(aors);
966 
967  /* Look for exact match on username@domain */
968  configured_aors = aors_buf;
969  while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
970  if (match_aor(aor_name, id_domain)) {
971  return ast_strdup(aor_name);
972  }
973  }
974 
975  /* If there's a domain alias, look for exact match on username@domain_alias */
976  alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
977  if (alias) {
978  char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);
979 
980  sprintf(id_domain_alias, "%s@%s", username, alias->domain);
981  ao2_cleanup(alias);
982 
983  configured_aors = strcpy(aors_buf, aors);/* Safe */
984  while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
985  if (match_aor(aor_name, id_domain_alias)) {
986  return ast_strdup(aor_name);
987  }
988  }
989  }
990 
991  if (ast_strlen_zero(username)) {
992  /* No username, no match */
993  return NULL;
994  }
995 
996  /* Look for exact match on username only */
997  configured_aors = strcpy(aors_buf, aors);/* Safe */
998  while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
999  if (match_aor(aor_name, username)) {
1000  return ast_strdup(aor_name);
1001  }
1002  }
1003 
1004  return NULL;
1005 }
static int match_aor(const char *aor_name, const char *id)
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
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:5240
#define NULL
Definition: resample.c:96
Domain data structure.
Definition: sip.h:888
#define ast_strlen_zero(foo)
Definition: strings.h:52
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
char * strsep(char **str, const char *delims)
const ast_string_field domain
Definition: res_pjsip.h:265
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ find_registrar_aor()

static struct ast_sip_aor* find_registrar_aor ( struct pjsip_rx_data *  rdata,
struct ast_sip_endpoint endpoint 
)
static

Definition at line 1007 of file res_pjsip_registrar.c.

References ast_sip_endpoint::aors, ast_debug, ast_free, ast_log, AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME, AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME, ast_sip_get_ignore_uri_user_options(), ast_sip_get_pjsip_endpoint(), ast_sip_location_retrieve_aor(), ast_sip_report_req_no_support(), ast_sorcery_object_get_id(), ast_strlen_zero, AST_VECTOR_GET, AST_VECTOR_SIZE, find_aor_name(), ast_sip_endpoint::ident_method_order, LOG_WARNING, NULL, and registrar_contact_details::uri.

Referenced by registrar_on_rx_request().

1008 {
1009  struct ast_sip_aor *aor = NULL;
1010  char *aor_name = NULL;
1011  int i;
1012 
1013  for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) {
1014  pj_str_t username;
1015  pjsip_sip_uri *uri;
1016  pjsip_authorization_hdr *header = NULL;
1017 
1018  switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) {
1020  uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
1021 
1022  pj_strassign(&username, &uri->user);
1023 
1024  /*
1025  * We may want to match without any user options getting
1026  * in the way.
1027  *
1028  * Logic adapted from AST_SIP_USER_OPTIONS_TRUNCATE_CHECK for pj_str_t.
1029  */
1031  pj_ssize_t semi = pj_strcspn2(&username, ";");
1032  if (semi < pj_strlen(&username)) {
1033  username.slen = semi;
1034  }
1035  }
1036 
1037  aor_name = find_aor_name(&username, &uri->host, endpoint->aors);
1038  if (aor_name) {
1039  ast_debug(3, "Matched aor '%s' by To username\n", aor_name);
1040  }
1041  break;
1043  while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION,
1044  header ? header->next : NULL))) {
1045  if (header && !pj_stricmp2(&header->scheme, "digest")) {
1046  aor_name = find_aor_name(&header->credential.digest.username,
1047  &header->credential.digest.realm, endpoint->aors);
1048  if (aor_name) {
1049  ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name);
1050  break;
1051  }
1052  }
1053  }
1054  break;
1055  default:
1056  continue;
1057  }
1058 
1059  if (aor_name) {
1060  break;
1061  }
1062  }
1063 
1064  if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
1065  /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
1066  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
1067  ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
1068  ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s' (%s:%d)\n",
1069  aor_name ?: "", ast_sorcery_object_get_id(endpoint),
1070  rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1071  }
1072  ast_free(aor_name);
1073  return aor;
1074 }
A SIP address of record.
Definition: res_pjsip.h:361
#define LOG_WARNING
Definition: logger.h:274
static char * find_aor_name(const pj_str_t *pj_username, const pj_str_t *pj_domain, const char *aors)
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
struct ast_sip_identify_by_vector ident_method_order
Definition: res_pjsip.h:861
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.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition: location.c:147
#define ast_free(a)
Definition: astmm.h:182
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
const ast_string_field aors
Definition: res_pjsip.h:821
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
unsigned int ast_sip_get_ignore_uri_user_options(void)
Retrieve the global setting &#39;ignore_uri_user_options&#39;.

◆ load_module()

static int load_module ( void  )
static

Definition at line 1322 of file res_pjsip_registrar.c.

References ami_show_registration_contact_statuses(), AMI_SHOW_REGISTRATION_CONTACT_STATUSES, ami_show_registrations(), AMI_SHOW_REGISTRATIONS, ast_manager_register_xml, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_pjproject_get_buildopt(), ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_register_service(), ast_sip_unregister_service(), ast_sorcery_observer_add(), ast_sorcery_reload_object(), EVENT_FLAG_SYSTEM, NULL, pj_max_hostname, and pjsip_max_url_size.

Referenced by unload_module().

1323 {
1324  const pj_str_t STR_REGISTER = { "REGISTER", 8 };
1325 
1326  ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
1327  /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
1328  ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
1329 
1331  return AST_MODULE_LOAD_DECLINE;
1332  }
1333 
1334  if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
1336  return AST_MODULE_LOAD_DECLINE;
1337  }
1338 
1343 
1346 
1347  return AST_MODULE_LOAD_SUCCESS;
1348 }
static int pjsip_max_url_size
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
#define NULL
Definition: resample.c:96
static int ami_show_registration_contact_statuses(struct mansession *s, const struct message *m)
#define EVENT_FLAG_SYSTEM
Definition: manager.h:71
static int ami_show_registrations(struct mansession *s, const struct message *m)
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:3315
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.
Definition: sorcery.c:2386
#define AMI_SHOW_REGISTRATIONS
static int pj_max_hostname
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static pjsip_module registrar_module
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:186
static struct ast_sorcery_observer expiration_global_observer
Observer which is used to update our interval when the global setting changes.
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.
Definition: sorcery.c:1442

◆ match_aor()

static int match_aor ( const char *  aor_name,
const char *  id 
)
static

Definition at line 933 of file res_pjsip_registrar.c.

References ast_debug, and ast_strlen_zero.

Referenced by find_aor_name().

934 {
935  if (ast_strlen_zero(aor_name)) {
936  return 0;
937  }
938 
939  if (!strcmp(aor_name, id)) {
940  ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name);
941  return 1;
942  }
943 
944  return 0;
945 }
#define ast_strlen_zero(foo)
Definition: strings.h:52
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452

◆ register_aor()

static int register_aor ( pjsip_rx_data *  rdata,
struct ast_sip_endpoint endpoint,
struct ast_sip_aor aor,
const char *  aor_name 
)
static

Definition at line 900 of file res_pjsip_registrar.c.

References ao2_cleanup, ao2_lock, ao2_unlock, ast_sip_get_pjsip_endpoint(), ast_sip_location_retrieve_aor_contacts_nolock(), ast_sip_send_stateful_response(), aor_core_response::code, NULL, register_aor_core(), and aor_core_response::tdata.

Referenced by registrar_on_rx_request().

904 {
905  struct aor_core_response response = {
906  .code = 500,
907  };
908  struct ao2_container *contacts = NULL;
909 
910  ao2_lock(aor);
912  if (!contacts) {
913  ao2_unlock(aor);
914  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
915  rdata, response.code, NULL, NULL, NULL);
916  return PJ_TRUE;
917  }
918 
919  register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
920  ao2_cleanup(contacts);
921  ao2_unlock(aor);
922 
923  /* Now send the REGISTER response to the peer */
924  if (response.tdata) {
925  ast_sip_send_stateful_response(rdata, response.tdata, endpoint);
926  } else {
927  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
928  rdata, response.code, NULL, NULL, NULL);
929  }
930  return PJ_TRUE;
931 }
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.
Definition: location.c:214
pjsip_tx_data * tdata
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
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)
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.
Definition: res_pjsip.c:5420
#define ao2_lock(a)
Definition: astobj2.h:718
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Generic container type.

◆ register_aor_core()

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

Definition at line 584 of file res_pjsip_registrar.c.

References ao2_alloc, AO2_ALLOC_OPT_LOCK_NOLOCK, ao2_callback, ao2_cleanup, ao2_container_alloc_list, ao2_container_count(), ao2_link, ao2_ref, ao2_unlink, ast_sip_contact::aor, contact_transport_monitor::aor_name, ast_alloca, ast_config_AST_SYSTEM_NAME, ast_copy_pj_str(), ast_copy_string(), ast_debug, ast_free, ast_log, ast_samp2tv(), ast_sip_add_date_header(), ast_sip_create_response(), ast_sip_get_pjsip_endpoint(), ast_sip_get_sorcery(), ast_sip_location_create_contact(), ast_sip_location_update_contact(), ast_sip_report_failed_acl(), ast_sip_transport_monitor_register_replace(), ast_sip_will_uri_survive_restart(), ast_sorcery_copy(), ast_sorcery_object_get_id(), ast_sorcery_object_id_compare(), ast_str_buffer(), ast_string_field_set, ast_strlen_zero, ast_test_suite_event_notify, ast_tvadd(), ast_tvnow(), ast_verb, ast_sip_contact::authenticate_qualify, ast_sip_contact::call_id, CONTACT_DELETE_ERROR, CONTACT_DELETE_REQUEST, contact_transport_monitor::contact_name, contact_transport_monitor_matcher(), ast_sip_contact::endpoint, ast_sip_contact::expiration_time, LOG_ERROR, LOG_WARNING, MAX, monitor, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_sip_contact::path, pjsip_max_url_size, ast_sip_contact::prune_on_boot, ast_sip_contact::qualify_frequency, RAII_VAR, ast_sip_contact::reg_server, register_contact_transport_shutdown_cb(), registrar_add_contact(), registrar_add_non_permanent(), registrar_contact_delete(), registrar_delete_contact(), registrar_find_contact(), registrar_get_expiration(), registrar_validate_contacts(), registrar_validate_path(), remove_excess_contacts(), ast_sip_contact::user_agent, ast_sip_contact::via_addr, and ast_sip_contact::via_port.

Referenced by register_aor().

590 {
591  static const pj_str_t USER_AGENT = { "User-Agent", 10 };
592 
593  int added = 0;
594  int updated = 0;
595  int deleted = 0;
596  int permanent = 0;
597  int contact_count;
598  struct ao2_container *existing_contacts = NULL;
599  pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
600  struct registrar_contact_details details = { 0, };
601  pjsip_tx_data *tdata;
602  RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
603  struct ast_sip_contact *response_contact;
604  char *user_agent = NULL;
605  pjsip_user_agent_hdr *user_agent_hdr;
606  pjsip_expires_hdr *expires_hdr;
607  pjsip_via_hdr *via_hdr;
608  pjsip_via_hdr *via_hdr_last;
609  char *via_addr = NULL;
610  int via_port = 0;
611  pjsip_cid_hdr *call_id_hdr;
612  char *call_id = NULL;
613  size_t alloc_size;
614 
615  /* We create a single pool and use it throughout this function where we need one */
616  details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
617  "Contact Comparison", 1024, 256);
618  if (!details.pool) {
619  response->code = 500;
620  return;
621  }
622 
623  /* If there are any permanent contacts configured on the AOR we need to take them
624  * into account when counting contacts.
625  */
626  if (aor->permanent_contacts) {
627  permanent = ao2_container_count(aor->permanent_contacts);
628  }
629 
630  if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) {
631  /* The provided Contact headers do not conform to the specification */
632  ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
633  ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
634  ast_sorcery_object_get_id(endpoint));
635  response->code = 400;
636  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
637  return;
638  }
639 
640  if (registrar_validate_path(rdata, aor, &path_str)) {
641  /* Ensure that intervening proxies did not make invalid modifications to the request */
642  ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
643  ast_sorcery_object_get_id(endpoint));
644  response->code = 420;
645  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
646  return;
647  }
648 
649  if (aor->remove_existing) {
650  /* Cumulative number of contacts affected by this registration */
651  contact_count = MAX(updated + added - deleted, 0);
652 
653  /* We need to keep track of only existing contacts so we can later
654  * remove them if need be.
655  */
658  if (!existing_contacts) {
659  response->code = 500;
660  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
661  return;
662  }
663 
664  ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts);
665  } else {
666  /* Total contacts after this registration */
667  contact_count = ao2_container_count(contacts) - permanent + added - deleted;
668  }
669  if (contact_count > aor->max_contacts) {
670  /* Enforce the maximum number of contacts */
671  ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
672  ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' (%s:%d) to AOR '%s' will exceed max contacts of %u\n",
673  ast_sorcery_object_get_id(endpoint), rdata->pkt_info.src_name, rdata->pkt_info.src_port,
674  aor_name, aor->max_contacts);
675  response->code = 403;
676  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
677  ao2_cleanup(existing_contacts);
678  return;
679  }
680 
681  user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
682  if (user_agent_hdr) {
683  alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
684  user_agent = ast_alloca(alloc_size);
685  ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
686  }
687 
688  /* Find the first Via header */
689  via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
690  if (via_hdr) {
691  /* Find the last Via header */
692  while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
693  PJSIP_H_VIA, via_hdr->next)) != NULL) {
694  via_hdr_last = via_hdr;
695  }
696  alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
697  via_addr = ast_alloca(alloc_size);
698  ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
699  via_port=via_hdr_last->sent_by.port;
700  }
701 
702  call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
703  if (call_id_hdr) {
704  alloc_size = pj_strlen(&call_id_hdr->id) + 1;
705  call_id = ast_alloca(alloc_size);
706  ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
707  }
708 
709  /* Iterate each provided Contact header and add, update, or delete */
710  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)) {
711  int expiration;
712  char contact_uri[pjsip_max_url_size];
714 
715  if (contact_hdr->star) {
716  /* A star means to unregister everything, so do so for the possible contacts */
718  registrar_delete_contact, (void *)aor_name);
719  /* If we are keeping track of existing contacts for removal then, well, there is
720  * absolutely nothing left so no need to try to remove any.
721  */
722  if (existing_contacts) {
723  ao2_ref(existing_contacts, -1);
724  existing_contacts = NULL;
725  }
726  break;
727  }
728 
729  if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
730  /* This registrar only currently supports sip: and sips: URI schemes */
731  continue;
732  }
733 
734  expiration = registrar_get_expiration(aor, contact_hdr, rdata);
735  details.uri = pjsip_uri_get_uri(contact_hdr->uri);
736  pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
737 
738  contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
739 
740  /* If a contact was returned and we need to keep track of existing contacts then it
741  * should be removed.
742  */
743  if (contact && existing_contacts) {
744  ao2_unlink(existing_contacts, contact);
745  }
746 
747  if (!contact) {
748  int prune_on_boot;
749 
750  /* If they are actually trying to delete a contact that does not exist... be forgiving */
751  if (!expiration) {
752  ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
753  contact_uri, aor_name);
754  continue;
755  }
756 
757  prune_on_boot = !ast_sip_will_uri_survive_restart(details.uri, endpoint, rdata);
758 
759  contact = ast_sip_location_create_contact(aor, contact_uri,
760  ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)),
761  path_str ? ast_str_buffer(path_str) : NULL,
762  user_agent, via_addr, via_port, call_id, prune_on_boot, endpoint);
763  if (!contact) {
764  ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
765  contact_uri, aor_name);
766  continue;
767  }
768 
769  if (prune_on_boot) {
770  size_t contact_name_len;
771  const char *contact_name;
773 
774  /*
775  * Monitor the transport in case it gets disconnected because
776  * the contact won't be valid anymore if that happens.
777  */
778  contact_name = ast_sorcery_object_get_id(contact);
779  contact_name_len = strlen(contact_name) + 1;
780  monitor = ao2_alloc(sizeof(*monitor) + 1 + strlen(aor_name)
781  + contact_name_len, NULL);
782  if (monitor) {
783  strcpy(monitor->aor_name, aor_name);/* Safe */
784  monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1;
785  ast_copy_string(monitor->contact_name, contact_name, contact_name_len);/* Safe */
786 
787  ast_sip_transport_monitor_register_replace(rdata->tp_info.transport,
789  ao2_ref(monitor, -1);
790  }
791  }
792 
793  ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
794  contact_uri, aor_name, expiration);
795  ast_test_suite_event_notify("AOR_CONTACT_ADDED",
796  "Contact: %s\r\n"
797  "AOR: %s\r\n"
798  "Expiration: %d\r\n"
799  "UserAgent: %s",
800  contact_uri,
801  aor_name,
802  expiration,
803  user_agent);
804 
805  ao2_link(contacts, contact);
806  } else if (expiration) {
807  struct ast_sip_contact *contact_update;
808 
809  contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
810  if (!contact_update) {
811  ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
812  contact->uri, expiration);
813  continue;
814  }
815 
816  contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
817  contact_update->qualify_frequency = aor->qualify_frequency;
818  contact_update->authenticate_qualify = aor->authenticate_qualify;
819  if (path_str) {
820  ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
821  }
822  if (user_agent) {
823  ast_string_field_set(contact_update, user_agent, user_agent);
824  }
827  }
828 
829  if (ast_sip_location_update_contact(contact_update)) {
830  ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
831  contact->uri, expiration);
832  registrar_contact_delete(CONTACT_DELETE_ERROR, rdata->tp_info.transport,
833  contact, aor_name);
834  continue;
835  }
836  ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
837  contact_uri, aor_name, expiration);
838  ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
839  "Contact: %s\r\n"
840  "AOR: %s\r\n"
841  "Expiration: %d\r\n"
842  "UserAgent: %s",
843  contact_uri,
844  aor_name,
845  expiration,
846  contact_update->user_agent);
847  ao2_link(contacts, contact_update);
848  ao2_cleanup(contact_update);
849  } else {
850  registrar_contact_delete(CONTACT_DELETE_REQUEST, rdata->tp_info.transport,
851  contact, aor_name);
852  }
853  }
854 
855  pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
856 
857  /*
858  * If the AOR is configured to remove any contacts over max_contacts
859  * that have not been updated/added/deleted as a result of this
860  * REGISTER do so.
861  *
862  * The existing contacts container holds all contacts that were not
863  * involved in this REGISTER.
864  * The contacts container holds the current contacts of the AOR.
865  */
866  if (aor->remove_existing && existing_contacts) {
867  /* Total contacts after this registration */
868  contact_count = ao2_container_count(existing_contacts) + updated + added;
869  if (contact_count > aor->max_contacts) {
870  /* Remove excess existing contacts that expire the soonest */
871  remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts);
872  }
873  ao2_ref(existing_contacts, -1);
874  }
875 
876  response_contact = ao2_callback(contacts, 0, NULL, NULL);
877 
878  /* Send a response containing all of the contacts (including static) that are present on this AOR */
879  if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
880  ao2_cleanup(response_contact);
881  ao2_cleanup(contacts);
882  response->code = 500;
883  return;
884  }
885  ao2_cleanup(response_contact);
886 
887  /* Add the date header to the response, some UAs use this to set their date and time */
889 
890  ao2_callback(contacts, 0, registrar_add_contact, tdata);
891 
892  if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
893  expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
894  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
895  }
896 
897  response->tdata = tdata;
898 }
int authenticate_qualify
Definition: res_pjsip.h:309
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static int registrar_delete_contact(void *obj, void *arg, int flags)
Internal function used to delete a contact from an AOR.
const ast_string_field call_id
Definition: res_pjsip.h:303
const ast_string_field user_agent
Definition: res_pjsip.h:303
const ast_string_field path
Definition: res_pjsip.h:303
unsigned int remove_existing
Definition: res_pjsip.h:381
static int registrar_add_non_permanent(void *obj, void *arg, int flags)
Callback function which adds non-permanent contacts to a container.
unsigned int max_contacts
Definition: res_pjsip.h:379
#define LOG_WARNING
Definition: logger.h:274
const ast_string_field via_addr
Definition: res_pjsip.h:303
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
pjsip_tx_data * tdata
static int pjsip_max_url_size
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1335
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition: sorcery.c:2459
static int registrar_find_contact(void *obj, void *arg, int flags)
Callback function for finding a contact.
unsigned int qualify_frequency
Definition: res_pjsip.h:307
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.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
static int contact_transport_monitor_matcher(void *a, void *b)
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:5240
static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts, unsigned int to_remove)
const ast_string_field reg_server
Definition: res_pjsip.h:303
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:463
#define ast_strlen_zero(foo)
Definition: strings.h:52
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
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.
Definition: res_pjsip.c:5448
unsigned int qualify_frequency
Definition: res_pjsip.h:375
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
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.
#define ast_log
Definition: astobj2.c:42
#define MAX(a, b)
Definition: utils.h:228
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.
Definition: location.c:355
#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:911
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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 ...
Definition: time.h:238
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
char * contact_name
Sorcery contact name to remove on transport shutdown.
static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
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.
#define LOG_ERROR
Definition: logger.h:285
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
static void register_contact_transport_shutdown_cb(void *data)
static unsigned int monitor
Definition: chan_phone.c:116
Contact associated with an address of record.
Definition: res_pjsip.h:281
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
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.
Definition: res_pjsip.c:3288
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...
struct timeval expiration_time
Definition: res_pjsip.h:305
#define ast_free(a)
Definition: astmm.h:182
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Definition: res_pjsip.c:3723
struct ao2_container * permanent_contacts
Definition: res_pjsip.h:383
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport, struct ast_sip_contact *contact, const char *aor_name)
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1778
Structure used for finding contact.
int authenticate_qualify
Definition: res_pjsip.h:377
Generic container type.
int ast_sip_location_update_contact(struct ast_sip_contact *contact)
Update a contact.
Definition: location.c:445
static int registrar_add_contact(void *obj, void *arg, int flags)
Internal function which adds a contact to a response.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:514
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ register_contact_transport_remove_cb()

static int register_contact_transport_remove_cb ( void *  data)
static

Definition at line 330 of file res_pjsip_registrar.c.

References ao2_lock, ao2_ref, ao2_unlock, contact_transport_monitor::aor_name, ast_sip_location_retrieve_aor(), ast_sip_location_retrieve_contact(), CONTACT_DELETE_SHUTDOWN, contact_transport_monitor::contact_name, monitor, NULL, registrar_contact_delete(), and contact_transport_monitor::removing.

Referenced by register_contact_transport_shutdown_cb().

331 {
332  struct contact_transport_monitor *monitor = data;
333  struct ast_sip_contact *contact;
334  struct ast_sip_aor *aor;
335 
336  aor = ast_sip_location_retrieve_aor(monitor->aor_name);
337  if (!aor) {
338  ao2_lock(monitor);
339  monitor->removing = 0;
340  ao2_unlock(monitor);
341  ao2_ref(monitor, -1);
342  return 0;
343  }
344 
345  ao2_lock(aor);
346 
348  if (contact) {
350  ao2_ref(contact, -1);
351  }
352  ao2_unlock(aor);
353  ao2_ref(aor, -1);
354 
355  ao2_ref(monitor, -1);
356  return 0;
357 }
A SIP address of record.
Definition: res_pjsip.h:361
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
char * contact_name
Sorcery contact name to remove on transport shutdown.
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition: location.c:147
static unsigned int monitor
Definition: chan_phone.c:116
Contact associated with an address of record.
Definition: res_pjsip.h:281
static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport, struct ast_sip_contact *contact, const char *aor_name)
struct ast_sip_contact * ast_sip_location_retrieve_contact(const char *contact_name)
Retrieve a named contact.
Definition: location.c:350

◆ register_contact_transport_shutdown_cb()

static void register_contact_transport_shutdown_cb ( void *  data)
static

Definition at line 369 of file res_pjsip_registrar.c.

References ao2_lock, ao2_ref, ao2_unlock, ast_sip_push_task(), monitor, NULL, register_contact_transport_remove_cb(), and contact_transport_monitor::removing.

Referenced by register_aor_core(), registrar_contact_delete(), and unload_module().

370 {
371  struct contact_transport_monitor *monitor = data;
372 
373  /*
374  * It's possible for this shutdown handler to get called multiple times for the
375  * same monitor from different threads. Only one of the calls needs to do the
376  * actual removing of the contact, so if one is currently removing then any
377  * subsequent calls can skip.
378  */
379  ao2_lock(monitor);
380  if (monitor->removing) {
381  ao2_unlock(monitor);
382  return;
383  }
384 
385  monitor->removing = 1;
386 
387  /*
388  * Push off to a default serializer. This is in case sorcery
389  * does database accesses for contacts. Database accesses may
390  * not be on this machine. We don't want to tie up the pjsip
391  * monitor thread with potentially long access times.
392  */
393  ao2_ref(monitor, +1);
395  monitor->removing = 0;
396  ao2_ref(monitor, -1);
397  }
398 
399  ao2_unlock(monitor);
400 }
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_lock(a)
Definition: astobj2.h:718
static int register_contact_transport_remove_cb(void *data)
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:5138
static unsigned int monitor
Definition: chan_phone.c:116

◆ registrar_add_contact()

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

Internal function which adds a contact to a response.

Definition at line 223 of file res_pjsip_registrar.c.

References ast_sip_contact::aor, ast_log, ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), ast_sip_contact::expiration_time, LOG_WARNING, PJSIP_EXPIRES_NOT_SPECIFIED, registrar_contact_details::uri, and ast_sip_contact::uri.

Referenced by register_aor_core().

224 {
225  struct ast_sip_contact *contact = obj;
226  pjsip_tx_data *tdata = arg;
227  pj_str_t uri;
228  pjsip_uri *parsed;
229 
230  pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
231  parsed = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
232 
233  if (parsed && (PJSIP_URI_SCHEME_IS_SIP(parsed) || PJSIP_URI_SCHEME_IS_SIPS(parsed))) {
234  pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
235  hdr->uri = parsed;
236  if (!ast_tvzero(contact->expiration_time)) {
237  hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
238  } else {
239  hdr->expires = PJSIP_EXPIRES_NOT_SPECIFIED;
240  }
241  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
242  } else {
243  ast_log(LOG_WARNING, "Skipping invalid Contact URI \"%.*s\" for AOR %s\n",
244  (int) uri.slen, uri.ptr, contact->aor);
245  }
246 
247  return 0;
248 }
#define LOG_WARNING
Definition: logger.h:274
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define ast_log
Definition: astobj2.c:42
Contact associated with an address of record.
Definition: res_pjsip.h:281
struct timeval expiration_time
Definition: res_pjsip.h:305
const ast_string_field aor
Definition: res_pjsip.h:303
const ast_string_field uri
Definition: res_pjsip.h:303
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:63

◆ registrar_add_non_permanent()

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

Callback function which adds non-permanent contacts to a container.

Definition at line 563 of file res_pjsip_registrar.c.

References ao2_link, ast_tvzero(), container, and ast_sip_contact::expiration_time.

Referenced by register_aor_core().

564 {
565  struct ast_sip_contact *contact = obj;
566  struct ao2_container *container = arg;
567 
568  if (ast_tvzero(contact->expiration_time)) {
569  return 0;
570  }
571 
572  ao2_link(container, contact);
573 
574  return 0;
575 }
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
struct ao2_container * container
Definition: res_fax.c:502
Contact associated with an address of record.
Definition: res_pjsip.h:281
struct timeval expiration_time
Definition: res_pjsip.h:305
Generic container type.
#define ao2_link(container, obj)
Definition: astobj2.h:1549

◆ registrar_contact_delete()

static int registrar_contact_delete ( enum contact_delete_type  type,
pjsip_transport *  transport,
struct ast_sip_contact contact,
const char *  aor_name 
)
static

Definition at line 403 of file res_pjsip_registrar.c.

References contact_transport_monitor::aor_name, ast_alloca, ast_copy_string(), ast_sip_location_delete_contact(), ast_sip_transport_monitor_unregister(), ast_sip_transport_monitor_unregister_all(), ast_sorcery_object_get_id(), ast_test_suite_event_notify, ast_tvzero(), AST_VECTOR(), ast_verb, CONTACT_DELETE_ERROR, CONTACT_DELETE_EXISTING, CONTACT_DELETE_EXPIRE, CONTACT_DELETE_REQUEST, CONTACT_DELETE_SHUTDOWN, contact_transport_monitor::contact_name, contact_transport_monitor_matcher(), ast_sip_contact::expiration_time, monitor, ast_sip_contact::prune_on_boot, register_contact_transport_shutdown_cb(), ast_sip_contact::uri, ast_sip_contact::user_agent, and VERBOSITY_ATLEAST.

Referenced by expire_contact(), register_aor_core(), register_contact_transport_remove_cb(), registrar_delete_contact(), and remove_excess_contacts().

405 {
406  int aor_size;
407 
408  /* Permanent contacts can't be deleted */
409  if (ast_tvzero(contact->expiration_time)) {
410  return -1;
411  }
412 
413  aor_size = aor_name ? strlen(aor_name) : 0;
414  if (contact->prune_on_boot && type != CONTACT_DELETE_SHUTDOWN && aor_size) {
415  const char *contact_name = ast_sorcery_object_get_id(contact);
416  size_t contact_name_len = strlen(contact_name) + 1;
418  sizeof(*monitor) + 1 + aor_size + contact_name_len);
419 
420  strcpy(monitor->aor_name, aor_name); /* Safe */
421  monitor->contact_name = monitor->aor_name + aor_size + 1;
422  ast_copy_string(monitor->contact_name, contact_name, contact_name_len); /* Safe */
423 
424  if (transport) {
428  } else {
429  /*
430  * If a specific transport is not supplied then unregister the matching
431  * monitor from all reliable transports.
432  */
435  }
436  }
437 
439 
440  if (aor_size) {
441  if (VERBOSITY_ATLEAST(3)) {
442  const char *reason = "none";
443 
444  switch (type) {
446  reason = "registration failure";
447  break;
449  reason = "remove existing";
450  break;
452  reason = "expiration";
453  break;
455  reason = "request";
456  break;
458  reason = "shutdown";
459  break;
460  }
461 
462  ast_verb(3, "Removed contact '%s' from AOR '%s' due to %s\n",
463  contact->uri, aor_name, reason);
464  }
465 
466  ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
467  "Contact: %s\r\n"
468  "AOR: %s\r\n"
469  "UserAgent: %s",
470  contact->uri,
471  aor_name,
472  contact->user_agent);
473  }
474 
475  return 0;
476 }
static const char type[]
Definition: chan_ooh323.c:109
const ast_string_field user_agent
Definition: res_pjsip.h:303
#define VERBOSITY_ATLEAST(level)
Definition: logger.h:461
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
static int contact_transport_monitor_matcher(void *a, void *b)
#define ast_verb(level,...)
Definition: logger.h:463
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
char * contact_name
Sorcery contact name to remove on transport shutdown.
int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
Delete a contact.
Definition: location.c:450
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.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
static void register_contact_transport_shutdown_cb(void *data)
static unsigned int monitor
Definition: chan_phone.c:116
struct timeval expiration_time
Definition: res_pjsip.h:305
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const ast_string_field uri
Definition: res_pjsip.h:303
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.

◆ registrar_delete_contact()

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

Internal function used to delete a contact from an AOR.

Definition at line 216 of file res_pjsip_registrar.c.

References CMP_MATCH, CONTACT_DELETE_REQUEST, NULL, and registrar_contact_delete().

Referenced by register_aor_core().

217 {
219  CONTACT_DELETE_REQUEST, NULL, obj, arg) ? 0 : CMP_MATCH;
220 }
#define NULL
Definition: resample.c:96
static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport, struct ast_sip_contact *contact, const char *aor_name)

◆ registrar_find_contact()

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

Callback function for finding a contact.

Definition at line 121 of file res_pjsip_registrar.c.

References ast_log, ast_tvzero(), CMP_MATCH, ast_sip_contact::expiration_time, LOG_WARNING, registrar_contact_details::pool, registrar_contact_details::uri, and ast_sip_contact::uri.

Referenced by register_aor_core().

122 {
123  struct ast_sip_contact *contact = obj;
124  const struct registrar_contact_details *details = arg;
125  pjsip_uri *contact_uri;
126 
127  if (ast_tvzero(contact->expiration_time)) {
128  return 0;
129  }
130 
131  contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
132  if (!contact_uri) {
133  ast_log(LOG_WARNING, "Unable to parse contact URI from '%s'.\n", contact->uri);
134  return 0;
135  }
136 
137  return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
138 }
#define LOG_WARNING
Definition: logger.h:274
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
pjsip_sip_uri * uri
URI being looked for.
#define ast_log
Definition: astobj2.c:42
pj_pool_t * pool
Pool used for parsing URI.
Contact associated with an address of record.
Definition: res_pjsip.h:281
struct timeval expiration_time
Definition: res_pjsip.h:305
Structure used for finding contact.
const ast_string_field uri
Definition: res_pjsip.h:303

◆ registrar_get_expiration()

static unsigned int registrar_get_expiration ( const struct ast_sip_aor aor,
const pjsip_contact_hdr *  contact,
const pjsip_rx_data *  rdata 
)
static

Internal function which returns the expiration time for a contact.

Definition at line 84 of file res_pjsip_registrar.c.

References ast_sip_aor::default_expiration, ast_sip_aor::maximum_expiration, ast_sip_aor::minimum_expiration, NULL, and PJSIP_EXPIRES_NOT_SPECIFIED.

Referenced by register_aor_core().

85 {
86  pjsip_expires_hdr *expires;
87  unsigned int expiration = aor->default_expiration;
88 
90  /* Expiration was provided with the contact itself */
91  expiration = contact->expires;
92  } else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
93  /* Expiration was provided using the Expires header */
94  expiration = expires->ivalue;
95  }
96 
97  /* If the value has explicitly been set to 0, do not enforce */
98  if (!expiration) {
99  return expiration;
100  }
101 
102  /* Enforce the range that we will allow for expiration */
103  if (expiration < aor->minimum_expiration) {
104  expiration = aor->minimum_expiration;
105  } else if (expiration > aor->maximum_expiration) {
106  expiration = aor->maximum_expiration;
107  }
108 
109  return expiration;
110 }
char * expires
#define NULL
Definition: resample.c:96
unsigned int minimum_expiration
Definition: res_pjsip.h:369
unsigned int default_expiration
Definition: res_pjsip.h:373
unsigned int maximum_expiration
Definition: res_pjsip.h:371
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:63

◆ registrar_on_rx_request()

static pj_bool_t registrar_on_rx_request ( struct pjsip_rx_data *  rdata)
static

Definition at line 1076 of file res_pjsip_registrar.c.

References ao2_cleanup, ao2_ref, ast_log, ast_pjsip_rdata_get_endpoint(), ast_sip_get_pjsip_endpoint(), ast_sip_report_failed_acl(), ast_sip_report_req_no_support(), ast_sorcery_object_get_id(), ast_strlen_zero, find_registrar_aor(), LOG_WARNING, ast_sip_aor::max_contacts, NULL, RAII_VAR, and register_aor().

1077 {
1078  RAII_VAR(struct ast_sip_endpoint *, endpoint,
1080  struct ast_sip_aor *aor;
1081  const char *aor_name;
1082 
1083  if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
1084  return PJ_FALSE;
1085  }
1086 
1087  if (ast_strlen_zero(endpoint->aors)) {
1088  /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
1089  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1090  ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
1091  ast_log(LOG_WARNING, "Endpoint '%s' (%s:%d) has no configured AORs\n", ast_sorcery_object_get_id(endpoint),
1092  rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1093  return PJ_TRUE;
1094  }
1095 
1096  if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
1097  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
1098  ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
1099  ast_log(LOG_WARNING, "Endpoint '%s' (%s:%d) attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint),
1100  rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1101  return PJ_TRUE;
1102  }
1103 
1104  aor = find_registrar_aor(rdata, endpoint);
1105  if (!aor) {
1106  /* We've already responded about not finding an AOR. */
1107  return PJ_TRUE;
1108  }
1109 
1110  aor_name = ast_sorcery_object_get_id(aor);
1111 
1112  if (!aor->max_contacts) {
1113  /* Registration is not permitted for this AOR */
1114  pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1115  ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
1116  ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' (%s:%d) unable to register\n",
1117  aor_name, ast_sorcery_object_get_id(endpoint),
1118  rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1119  } else {
1120  register_aor(rdata, endpoint, aor, aor_name);
1121  }
1122  ao2_ref(aor, -1);
1123  return PJ_TRUE;
1124 }
A SIP address of record.
Definition: res_pjsip.h:361
static int register_aor(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name)
unsigned int max_contacts
Definition: res_pjsip.h:379
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
#define ast_strlen_zero(foo)
Definition: strings.h:52
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_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.
#define ast_log
Definition: astobj2.c:42
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.
#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:911
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
static struct ast_sip_aor * find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:3718
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ registrar_validate_contacts()

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 
)
static

Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts.

Definition at line 141 of file res_pjsip_registrar.c.

References NULL, and registrar_contact_details::pool.

Referenced by register_aor_core().

143 {
144  pjsip_contact_hdr *previous = NULL;
145  pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
147  .pool = pool,
148  };
149 
150  for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(pool)) {
151  unsigned int expiration = registrar_get_expiration(aor, contact, rdata);
152  struct ast_sip_contact *existing;
153  char contact_uri[pjsip_max_url_size];
154 
155  if (contact->star) {
156  /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
157  if (expiration != 0 || previous) {
158  return -1;
159  }
160  /* Count all contacts to delete */
161  *deleted = ao2_container_count(contacts) - permanent;
162  previous = contact;
163  continue;
164  } else if (previous && previous->star) {
165  /* If there is a previous contact and it is a '*' this is a deal breaker */
166  return -1;
167  }
168  previous = contact;
169 
170  if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
171  continue;
172  }
173 
174  details.uri = pjsip_uri_get_uri(contact->uri);
175 
176  /* pjsip_uri_print returns -1 if there's not enough room in the buffer */
177  if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
178  /* If the total length of the uri is greater than pjproject can handle, go no further */
179  return -1;
180  }
181 
182  if (details.uri->host.slen >= pj_max_hostname) {
183  /* If the length of the hostname is greater than pjproject can handle, go no further */
184  return -1;
185  }
186 
187  /* Determine if this is an add, update, or delete for policy enforcement purposes */
188  existing = ao2_callback(contacts, 0, registrar_find_contact, &details);
189  ao2_cleanup(existing);
190  if (!existing) {
191  if (expiration) {
192  ++*added;
193  }
194  } else if (expiration) {
195  ++*updated;
196  } else {
197  ++*deleted;
198  }
199  }
200 
201  return 0;
202 }
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct ast_sorcery_object_details details
Definition: res_pjsip.h:363
static int pjsip_max_url_size
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
static pj_pool_t * pool
Global memory pool for configuration and timers.
static int registrar_find_contact(void *obj, void *arg, int flags)
Callback function for finding a contact.
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.
#define NULL
Definition: resample.c:96
Contact associated with an address of record.
Definition: res_pjsip.h:281
static int pj_max_hostname
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Structure used for finding contact.

◆ registrar_validate_path()

static int registrar_validate_path ( pjsip_rx_data *  rdata,
struct ast_sip_aor aor,
struct ast_str **  path_str 
)
static

Definition at line 274 of file res_pjsip_registrar.c.

References build_path_data(), NULL, and ast_sip_aor::support_path.

Referenced by register_aor_core().

275 {
276  const pj_str_t path_supported_name = { "path", 4 };
277  pjsip_supported_hdr *supported_hdr;
278  int i;
279 
280  if (!aor->support_path) {
281  return 0;
282  }
283 
284  if (build_path_data(rdata, path_str)) {
285  return -1;
286  }
287 
288  if (!*path_str) {
289  return 0;
290  }
291 
292  supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
293  if (!supported_hdr) {
294  return -1;
295  }
296 
297  /* Find advertised path support */
298  for (i = 0; i < supported_hdr->count; i++) {
299  if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
300  return 0;
301  }
302  }
303 
304  /* Path header present, but support not advertised */
305  return -1;
306 }
static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
#define NULL
Definition: resample.c:96
unsigned int support_path
Definition: res_pjsip.h:385

◆ remove_excess_contacts()

static void remove_excess_contacts ( struct ao2_container contacts,
struct ao2_container response_contacts,
unsigned int  to_remove 
)
static

Definition at line 523 of file res_pjsip_registrar.c.

References ao2_callback, ao2_unlink, ast_sip_contact::aor, ast_assert, AST_VECTOR_FREE, AST_VECTOR_GET, AST_VECTOR_INIT, AST_VECTOR_SIZE, CONTACT_DELETE_EXISTING, NULL, OBJ_MULTIPLE, OBJ_NODATA, registrar_contact_delete(), and vec_contact_add().

Referenced by register_aor_core().

525 {
526  struct excess_contact_vector contact_vec;
527 
528  /*
529  * Create a sorted vector to hold the to_remove soonest to
530  * expire contacts. The vector has an extra space to
531  * temporarily hold the longest to expire contact that we
532  * won't remove.
533  */
534  if (AST_VECTOR_INIT(&contact_vec, to_remove + 1)) {
535  return;
536  }
537  ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, vec_contact_add, &contact_vec);
538 
539  /*
540  * The vector should always be populated with the number
541  * of contacts we need to remove. Just in case, we will
542  * remove all contacts in the vector even if the contacts
543  * container had fewer contacts than there should be.
544  */
545  ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove);
546  to_remove = AST_VECTOR_SIZE(&contact_vec);
547 
548  /* Remove the excess contacts that expire the soonest */
549  while (to_remove--) {
550  struct ast_sip_contact *contact;
551 
552  contact = AST_VECTOR_GET(&contact_vec, to_remove);
553 
555 
556  ao2_unlink(response_contacts, contact);
557  }
558 
559  AST_VECTOR_FREE(&contact_vec);
560 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
#define ast_assert(a)
Definition: utils.h:695
#define NULL
Definition: resample.c:96
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
static int vec_contact_add(void *obj, void *arg, int flags)
#define ao2_unlink(container, obj)
Definition: astobj2.h:1598
Contact associated with an address of record.
Definition: res_pjsip.h:281
const ast_string_field aor
Definition: res_pjsip.h:303
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:682
static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport, struct ast_sip_contact *contact, const char *aor_name)
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ sip_contact_to_str()

static int sip_contact_to_str ( void *  acp,
void *  arg,
int  flags 
)
static

Definition at line 1128 of file res_pjsip_registrar.c.

References ast_sip_contact_to_str().

Referenced by ami_registrations_aor().

1129 {
1130  return ast_sip_contact_to_str(acp, arg, flags);
1131 }
int ast_sip_contact_to_str(void *object, void *arg, int flags)
Handler used to convert a contact to a string.
Definition: location.c:767

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1350 of file res_pjsip_registrar.c.

References AMI_SHOW_REGISTRATION_CONTACT_STATUSES, AMI_SHOW_REGISTRATIONS, ast_manager_unregister(), AST_MODFLAG_LOAD_ORDER, AST_MODPRI_CHANNEL_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, AST_PTHREADT_NULL, ast_sip_get_sorcery(), ast_sip_transport_monitor_unregister_all(), ast_sip_unregister_service(), ast_sorcery_observer_remove(), ASTERISK_GPL_KEY, load_module(), NULL, and register_contact_transport_shutdown_cb().

1351 {
1353  check_interval = 0;
1354  pthread_kill(check_thread, SIGURG);
1355  pthread_join(check_thread, NULL);
1356 
1358  }
1359 
1361 
1366  return 0;
1367 }
static pthread_t check_thread
Thread keeping things alive.
#define NULL
Definition: resample.c:96
#define AST_PTHREADT_NULL
Definition: lock.h:66
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7258
#define AMI_SHOW_REGISTRATIONS
static void register_contact_transport_shutdown_cb(void *data)
static pjsip_module registrar_module
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.
Definition: sorcery.c:2418
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:3331
#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES
static unsigned int check_interval
The global interval at which to check for contact expiration.
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.
static struct ast_sorcery_observer expiration_global_observer
Observer which is used to update our interval when the global setting changes.

◆ vec_contact_add()

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

Definition at line 489 of file res_pjsip_registrar.c.

References AST_VECTOR_ADD_SORTED, AST_VECTOR_MAX_SIZE, AST_VECTOR_SIZE, and vec_contact_cmp().

Referenced by remove_excess_contacts().

490 {
491  struct ast_sip_contact *contact = obj;
492  struct excess_contact_vector *contact_vec = arg;
493 
494  /*
495  * Performance wise, an insertion sort is fine because we
496  * shouldn't need to remove more than a handful of contacts.
497  * I expect we'll typically be removing only one contact.
498  */
499  AST_VECTOR_ADD_SORTED(contact_vec, contact, vec_contact_cmp);
500  if (AST_VECTOR_SIZE(contact_vec) == AST_VECTOR_MAX_SIZE(contact_vec)) {
501  /*
502  * We added a contact over the number we need to remove.
503  * Remove the longest to expire contact from the vector
504  * which is the last element in the vector. It may be
505  * the one we just added or the one we just added pushed
506  * out an earlier contact from removal consideration.
507  */
508  --AST_VECTOR_SIZE(contact_vec);
509  }
510  return 0;
511 }
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition: vector.h:371
static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact *right)
Contact associated with an address of record.
Definition: res_pjsip.h:281
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define AST_VECTOR_MAX_SIZE(vec)
Get the maximum number of elements the vector can currently hold.
Definition: vector.h:619

◆ vec_contact_cmp()

static int vec_contact_cmp ( struct ast_sip_contact left,
struct ast_sip_contact right 
)
static

Definition at line 480 of file res_pjsip_registrar.c.

References ast_tvcmp(), and ast_sip_contact::expiration_time.

Referenced by vec_contact_add().

481 {
482  struct ast_sip_contact *left_contact = left;
483  struct ast_sip_contact *right_contact = right;
484 
485  /* Sort from soonest to expire to last to expire */
486  return ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time);
487 }
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compres two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
Definition: time.h:128
Contact associated with an address of record.
Definition: res_pjsip.h:281
struct timeval expiration_time
Definition: res_pjsip.h:305

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Registrar Support" , .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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3, .requires = "res_pjproject,res_pjsip", }
static

Definition at line 1375 of file res_pjsip_registrar.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1375 of file res_pjsip_registrar.c.

◆ check_interval

unsigned int check_interval
static

The global interval at which to check for contact expiration.

Definition at line 1239 of file res_pjsip_registrar.c.

◆ check_thread

pthread_t check_thread = AST_PTHREADT_NULL
static

Thread keeping things alive.

Definition at line 1236 of file res_pjsip_registrar.c.

◆ expiration_global_observer

struct ast_sorcery_observer expiration_global_observer
static
Initial value:
= {
}
static void expiration_global_loaded(const char *object_type)

Observer which is used to update our interval when the global setting changes.

Definition at line 1318 of file res_pjsip_registrar.c.

◆ path_hdr_name

const pj_str_t path_hdr_name = { "Path", 4 }
static

Definition at line 250 of file res_pjsip_registrar.c.

◆ pj_max_hostname

int pj_max_hostname = PJ_MAX_HOSTNAME
static

Definition at line 80 of file res_pjsip_registrar.c.

Referenced by load_module().

◆ pjsip_max_url_size

int pjsip_max_url_size = PJSIP_MAX_URL_SIZE
static

Definition at line 81 of file res_pjsip_registrar.c.

Referenced by load_module(), and register_aor_core().

◆ registrar_module

pjsip_module registrar_module
static

Definition at line 1228 of file res_pjsip_registrar.c.