Asterisk - The Open Source Telephony Project GIT-master-b023714
Loading...
Searching...
No Matches
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  excess_contact_vector
 
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_UNAVAILABLE , 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)
 
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.
 
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.
 
static int registrar_add_non_permanent (void *obj, void *arg, int flags)
 Callback function which adds non-permanent contacts to a container.
 
static int registrar_add_unreachable (void *obj, void *arg, int flags)
 Internal callback function which adds any contact which is unreachable.
 
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.
 
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.
 
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.
 
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, unsigned int remove_existing)
 
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 = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .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.
 
static pthread_t check_thread = AST_PTHREADT_NULL
 Thread keeping things alive.
 
static struct ast_sorcery_observer expiration_global_observer
 Observer which is used to update our interval when the global setting changes.
 
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 1396 of file res_pjsip_registrar.c.

◆ AMI_SHOW_REGISTRATIONS

#define AMI_SHOW_REGISTRATIONS   "PJSIPShowRegistrationsInbound"

Definition at line 1397 of file res_pjsip_registrar.c.

Enumeration Type Documentation

◆ contact_delete_type

Enumerator
CONTACT_DELETE_ERROR 
CONTACT_DELETE_EXISTING 
CONTACT_DELETE_UNAVAILABLE 
CONTACT_DELETE_EXPIRE 
CONTACT_DELETE_REQUEST 
CONTACT_DELETE_SHUTDOWN 

Definition at line 276 of file res_pjsip_registrar.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1547 of file res_pjsip_registrar.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1547 of file res_pjsip_registrar.c.

◆ ami_registrations_aor()

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

Definition at line 1304 of file res_pjsip_registrar.c.

1305{
1306 struct ast_sip_aor *aor = obj;
1307 struct ast_sip_ami *ami = arg;
1308 int *count = ami->arg;
1309 RAII_VAR(struct ast_str *, buf,
1310 ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
1311
1312 if (!buf) {
1313 return -1;
1314 }
1315
1317 ast_str_append(&buf, 0, "Contacts: ");
1319 ast_str_append(&buf, 0, "\r\n");
1320
1321 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1322 (*count)++;
1323 return 0;
1324}
#define ast_free(a)
Definition astmm.h:180
char buf[BUFSIZE]
Definition eagi_proxy.c:66
void astman_append(struct mansession *s, const char *fmt,...)
Definition manager.c:1903
int ast_sip_for_each_contact(const struct ast_sip_aor *aor, ao2_callback_fn on_contact, void *arg)
For every contact on an AOR call the given 'on_contact' handler.
Definition location.c:723
int ast_sip_sorcery_object_to_ami(const void *obj, struct ast_str **buf)
Converts a sorcery object to a string of object properties.
struct ast_str * ast_sip_create_ami_event(const char *event, struct ast_sip_ami *ami)
Creates a string to store AMI event data in.
static int sip_contact_to_str(void *acp, void *arg, int flags)
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
AMI variable container.
Definition res_pjsip.h:3200
struct mansession * s
Definition res_pjsip.h:3202
A SIP address of record.
Definition res_pjsip.h:478
Support for dynamic strings.
Definition strings.h:623
#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:978

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().

◆ ami_registrations_endpoint()

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

Definition at line 1326 of file res_pjsip_registrar.c.

1327{
1328 struct ast_sip_endpoint *endpoint = obj;
1329 return ast_sip_for_each_aor(
1330 endpoint->aors, ami_registrations_aor, arg);
1331}
int ast_sip_for_each_aor(const char *aors, ao2_callback_fn on_aor, void *arg)
For every aor in the comma separated aors string call the given 'on_aor' handler.
Definition location.c:688
static int ami_registrations_aor(void *obj, void *arg, int flags)
An entity with which Asterisk communicates.
Definition res_pjsip.h:1051
const ast_string_field aors
Definition res_pjsip.h:1080

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

Referenced by ami_registrations_endpoints().

◆ ami_registrations_endpoints()

static int ami_registrations_endpoints ( void *  arg)
static

Definition at line 1333 of file res_pjsip_registrar.c.

1334{
1337
1338 if (!endpoints) {
1339 return 0;
1340 }
1341
1343 return 0;
1344}
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition astobj2.h:1693
#define ao2_cleanup(obj)
Definition astobj2.h:1934
@ OBJ_NODATA
Definition astobj2.h:1044
static struct ao2_container * endpoints
struct ao2_container * ast_sip_get_endpoints(void)
Retrieve any endpoints available to sorcery.
static int ami_registrations_endpoint(void *obj, void *arg, int flags)
Generic container type.

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

Referenced by ami_show_registrations().

◆ ami_show_registration_contact_statuses()

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

Definition at line 1361 of file res_pjsip_registrar.c.

1362{
1363 int count = 0;
1364 struct ast_sip_ami ami = { .s = s, .m = m, .arg = NULL, .action_id = astman_get_header(m, "ActionID"), };
1367 struct ao2_iterator i;
1368 struct ast_sip_contact *contact;
1369
1370 astman_send_listack(s, m, "Following are ContactStatusEvents for each Inbound "
1371 "registration", "start");
1372
1373 if (contacts) {
1374 i = ao2_iterator_init(contacts, 0);
1375 while ((contact = ao2_iterator_next(&i))) {
1376 struct ast_sip_contact_wrapper wrapper;
1377
1378 wrapper.aor_id = (char *)contact->aor;
1379 wrapper.contact = contact;
1380 wrapper.contact_id = (char *)ast_sorcery_object_get_id(contact);
1381
1382 ast_sip_format_contact_ami(&wrapper, &ami, 0);
1383 count++;
1384
1385 ao2_ref(contact, -1);
1386 }
1388 ao2_ref(contacts, -1);
1389 }
1390
1391 astman_send_list_complete_start(s, m, "ContactStatusDetailComplete", count);
1393 return 0;
1394}
#define ao2_iterator_next(iter)
Definition astobj2.h:1911
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
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:2024
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:2060
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition manager.c:1643
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition manager.c:2068
int ast_sip_format_contact_ami(void *obj, void *arg, int flags)
Formats the contact and sends over AMI.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define NULL
Definition resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition sorcery.c:2381
@ AST_RETRIEVE_FLAG_MULTIPLE
Return all matching objects.
Definition sorcery.h:120
@ AST_RETRIEVE_FLAG_ALL
Perform no matching, return all objects.
Definition sorcery.h:123
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:1961
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition astobj2.h:1821
const struct message * m
Definition res_pjsip.h:3204
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:519
struct ast_sip_contact * contact
Definition res_pjsip.h:525
Contact associated with an address of record.
Definition res_pjsip.h:390
const ast_string_field aor
Definition res_pjsip.h:412

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().

◆ ami_show_registrations()

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

Definition at line 1346 of file res_pjsip_registrar.c.

1347{
1348 int count = 0;
1349 struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };
1350
1351 astman_send_listack(s, m, "Following are Events for each Inbound registration",
1352 "start");
1353
1355
1356 astman_send_list_complete_start(s, m, "InboundRegistrationDetailComplete", count);
1358 return 0;
1359}
static int ami_registrations_endpoints(void *arg)

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().

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 1547 of file res_pjsip_registrar.c.

◆ build_path_data()

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

Definition at line 325 of file res_pjsip_registrar.c.

326{
327 pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL);
328
329 if (!path_hdr) {
330 return 0;
331 }
332
333 *path_str = ast_str_create(64);
334 if (!*path_str) {
335 return -1;
336 }
337
338 ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
339
340 while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
341 ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
342 }
343
344 return 0;
345}
static const pj_str_t path_hdr_name
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659
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:1113

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

Referenced by registrar_validate_path().

◆ check_expiration_thread()

static void * check_expiration_thread ( void *  data)
static

Definition at line 1437 of file res_pjsip_registrar.c.

1438{
1439 struct ao2_container *contacts;
1440 struct ast_variable *var;
1441 char time[AST_TIME_T_LEN];
1442
1443 while (check_interval) {
1444 sleep(check_interval);
1445
1446 ast_time_t_to_string(ast_tvnow().tv_sec, time, sizeof(time));
1447
1448 var = ast_variable_new("expiration_time <=", time, "");
1449
1450 ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval);
1451
1454
1456 if (contacts) {
1457 ast_debug(3, "Expiring %d contacts\n", ao2_container_count(contacts));
1459 ao2_ref(contacts, -1);
1460 }
1461 }
1462
1463 return NULL;
1464}
#define var
Definition ast_expr2f.c:605
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ast_variable_new(name, value, filename)
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
#define ast_debug(level,...)
Log a DEBUG message.
static int expire_contact(void *obj, void *arg, int flags)
Callback function which deletes a contact.
static unsigned int check_interval
The global interval at which to check for contact expiration.
Structure for variables, used for configurations and for channel variables.
int ast_time_t_to_string(time_t time, char *buf, size_t length)
Converts to a string representation of a time_t as decimal seconds since the epoch....
Definition time.c:152
#define AST_TIME_T_LEN
Definition time.h:45
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition time.h:159

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

Referenced by expiration_global_loaded().

◆ contact_transport_monitor_matcher()

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

Definition at line 394 of file res_pjsip_registrar.c.

395{
396 struct contact_transport_monitor *ma = a;
397 struct contact_transport_monitor *mb = b;
398
399 return strcmp(ma->aor_name, mb->aor_name) == 0
400 && strcmp(ma->contact_name, mb->contact_name) == 0;
401}
char * contact_name
Sorcery contact name to remove on transport shutdown.
static struct test_val b
static struct test_val a

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

Referenced by register_aor_core(), and registrar_contact_delete().

◆ expiration_global_loaded()

static void expiration_global_loaded ( const char *  object_type)
static

Definition at line 1466 of file res_pjsip_registrar.c.

1467{
1469
1470 /* Observer calls are serialized so this is safe without it's own lock */
1471 if (check_interval) {
1474 ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n");
1475 return;
1476 }
1477 ast_debug(3, "Interval = %d, starting thread\n", check_interval);
1478 }
1479 } else {
1481 pthread_kill(check_thread, SIGURG);
1482 pthread_join(check_thread, NULL);
1484 ast_debug(3, "Interval = 0, shutting thread down\n");
1485 }
1486 }
1487}
#define ast_log
Definition astobj2.c:42
#define LOG_ERROR
#define AST_PTHREADT_NULL
Definition lock.h:73
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 pthread_t check_thread
Thread keeping things alive.
#define ast_pthread_create_background(a, b, c, d)
Definition utils.h:629

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

◆ expire_contact()

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

Callback function which deletes a contact.

Definition at line 1413 of file res_pjsip_registrar.c.

1414{
1415 struct ast_sip_contact *contact = obj;
1416 struct ast_named_lock *lock;
1417
1419 if (!lock) {
1420 return 0;
1421 }
1422
1423 /*
1424 * We need to check the expiration again with the aor lock held
1425 * in case another thread is attempting to renew the contact.
1426 */
1427 ao2_lock(lock);
1428 if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) {
1430 }
1433
1434 return 0;
1435}
ast_mutex_t lock
Definition app_sla.c:337
#define ao2_unlock(a)
Definition astobj2.h:729
#define ao2_lock(a)
Definition astobj2.h:717
#define ast_named_lock_put(lock)
Put a named lock handle away.
Definition named_locks.h:93
#define ast_named_lock_get(lock_type, keyspace, key)
Geta named lock handle.
Definition named_locks.h:83
@ AST_NAMED_LOCK_TYPE_MUTEX
Definition named_locks.h:59
static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport, struct ast_sip_contact *contact, const char *aor_name)
struct timeval expiration_time
Definition res_pjsip.h:414
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition time.h:107

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().

◆ 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 1118 of file res_pjsip_registrar.c.

1119{
1120 char *configured_aors;
1121 char *aors_buf;
1122 char *aor_name;
1123 char *id_domain;
1124 char *username, *domain;
1125 struct ast_sip_domain_alias *alias;
1126
1127 /* Turn these into C style strings for convenience */
1128 username = ast_alloca(pj_strlen(pj_username) + 1);
1129 ast_copy_pj_str(username, pj_username, pj_strlen(pj_username) + 1);
1130 domain = ast_alloca(pj_strlen(pj_domain) + 1);
1131 ast_copy_pj_str(domain, pj_domain, pj_strlen(pj_domain) + 1);
1132
1133 id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
1134 sprintf(id_domain, "%s@%s", username, domain);
1135
1136 aors_buf = ast_strdupa(aors);
1137
1138 /* Look for exact match on username@domain */
1139 configured_aors = aors_buf;
1140 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1141 if (match_aor(aor_name, id_domain)) {
1142 return ast_strdup(aor_name);
1143 }
1144 }
1145
1146 /* If there's a domain alias, look for exact match on username@domain_alias */
1147 alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
1148 if (alias) {
1149 char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);
1150
1151 sprintf(id_domain_alias, "%s@%s", username, alias->domain);
1152 ao2_cleanup(alias);
1153
1154 configured_aors = strcpy(aors_buf, aors);/* Safe */
1155 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1156 if (match_aor(aor_name, id_domain_alias)) {
1157 return ast_strdup(aor_name);
1158 }
1159 }
1160 }
1161
1162 if (ast_strlen_zero(username)) {
1163 /* No username, no match */
1164 return NULL;
1165 }
1166
1167 /* Look for exact match on username only */
1168 configured_aors = strcpy(aors_buf, aors);/* Safe */
1169 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1170 if (match_aor(aor_name, username)) {
1171 return ast_strdup(aor_name);
1172 }
1173 }
1174
1175 return NULL;
1176}
char * strsep(char **str, const char *delims)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition astmm.h:288
#define ast_strdup(str)
A wrapper for strdup()
Definition astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition res_pjsip.c:2201
static int match_aor(const char *aor_name, const char *id)
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:1917
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
const ast_string_field domain
Definition res_pjsip.h:321

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().

◆ 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 1178 of file res_pjsip_registrar.c.

1179{
1180 struct ast_sip_aor *aor = NULL;
1181 char *aor_name = NULL;
1182 int i;
1183
1184 for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) {
1185 pj_str_t username;
1186 pjsip_sip_uri *uri;
1187 pjsip_authorization_hdr *header = NULL;
1188
1189 switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) {
1191 uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
1192
1193 pj_strassign(&username, &uri->user);
1194
1195 /*
1196 * We may want to match without any user options getting
1197 * in the way.
1198 *
1199 * Logic adapted from AST_SIP_USER_OPTIONS_TRUNCATE_CHECK for pj_str_t.
1200 */
1202 pj_ssize_t semi = pj_strcspn2(&username, ";");
1203 if (semi < pj_strlen(&username)) {
1204 username.slen = semi;
1205 }
1206 }
1207
1208 aor_name = find_aor_name(&username, &uri->host, endpoint->aors);
1209 if (aor_name) {
1210 ast_debug(3, "Matched aor '%s' by To username\n", aor_name);
1211 }
1212 break;
1214 while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION,
1215 header ? header->next : NULL))) {
1216 if (header && !pj_stricmp2(&header->scheme, "digest")) {
1217 aor_name = find_aor_name(&header->credential.digest.username,
1218 &header->credential.digest.realm, endpoint->aors);
1219 if (aor_name) {
1220 ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name);
1221 break;
1222 }
1223 }
1224 }
1225 break;
1226 default:
1227 continue;
1228 }
1229
1230 if (aor_name) {
1231 break;
1232 }
1233 }
1234
1235 if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
1236 /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
1237 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
1238 ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
1239 ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s' (%s:%d)\n",
1240 aor_name ?: "", ast_sorcery_object_get_id(endpoint),
1241 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1242 }
1243 ast_free(aor_name);
1244 return aor;
1245}
#define LOG_WARNING
@ AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME
Definition res_pjsip.h:701
@ AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME
Definition res_pjsip.h:703
void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *req_type)
Send a security event notification for when a request is not supported.
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition location.c:147
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition res_pjsip.c:520
unsigned int ast_sip_get_ignore_uri_user_options(void)
Retrieve the global setting 'ignore_uri_user_options'.
static char * find_aor_name(const pj_str_t *pj_username, const pj_str_t *pj_domain, const char *aors)
struct ast_sip_identify_by_vector ident_method_order
Definition res_pjsip.h:1104
struct header * next
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition vector.h:620
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition vector.h:691

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, header::next, and NULL.

Referenced by registrar_on_rx_request().

◆ load_module()

static int load_module ( void  )
static

Definition at line 1494 of file res_pjsip_registrar.c.

1495{
1496 const pj_str_t STR_REGISTER = { "REGISTER", 8 };
1497
1498 ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
1499 /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
1500 ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
1501
1504 }
1505
1506 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
1509 }
1510
1515
1518
1520}
#define EVENT_FLAG_SYSTEM
Definition manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition manager.h:192
@ AST_MODULE_LOAD_SUCCESS
Definition module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition module.h:78
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
void ast_sip_unregister_service(pjsip_module *module)
Definition res_pjsip.c:133
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition res_pjsip.c:117
#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES
static int pjsip_max_url_size
static int ami_show_registration_contact_statuses(struct mansession *s, const struct message *m)
static struct ast_sorcery_observer expiration_global_observer
Observer which is used to update our interval when the global setting changes.
static int pj_max_hostname
static pjsip_module registrar_module
#define AMI_SHOW_REGISTRATIONS
static int ami_show_registrations(struct mansession *s, const struct message *m)
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:2455
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:1506

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, expiration_global_observer, NULL, pj_max_hostname, pjsip_max_url_size, and registrar_module.

◆ match_aor()

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

Definition at line 1104 of file res_pjsip_registrar.c.

1105{
1106 if (ast_strlen_zero(aor_name)) {
1107 return 0;
1108 }
1109
1110 if (!strcmp(aor_name, id)) {
1111 ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name);
1112 return 1;
1113 }
1114
1115 return 0;
1116}

References ast_debug, and ast_strlen_zero().

Referenced by find_aor_name().

◆ 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 1071 of file res_pjsip_registrar.c.

1075{
1076 struct aor_core_response response = {
1077 .code = 500,
1078 };
1079 struct ao2_container *contacts = NULL;
1080
1081 ao2_lock(aor);
1083 if (!contacts) {
1084 ao2_unlock(aor);
1085 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1086 rdata, response.code, NULL, NULL, NULL);
1087 return PJ_TRUE;
1088 }
1089
1090 register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
1091 ao2_cleanup(contacts);
1092 ao2_unlock(aor);
1093
1094 /* Now send the REGISTER response to the peer */
1095 if (response.tdata) {
1096 ast_sip_send_stateful_response(rdata, response.tdata, endpoint);
1097 } else {
1098 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1099 rdata, response.code, NULL, NULL, NULL);
1100 }
1101 return PJ_TRUE;
1102}
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
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:2424
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)

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().

◆ 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 725 of file res_pjsip_registrar.c.

731{
732 static const pj_str_t USER_AGENT = { "User-Agent", 10 };
733
734 int added = 0;
735 int updated = 0;
736 int deleted = 0;
737 int permanent = 0;
738 int contact_count;
739 struct ao2_container *existing_contacts = NULL;
740 struct ao2_container *unavail_contacts = NULL;
741 pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
742 struct registrar_contact_details details = { 0, };
743 pjsip_tx_data *tdata;
744 RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
745 struct ast_sip_contact *response_contact;
746 char *user_agent = NULL;
747 pjsip_user_agent_hdr *user_agent_hdr;
748 pjsip_expires_hdr *expires_hdr;
749 pjsip_via_hdr *via_hdr;
750 pjsip_via_hdr *via_hdr_last;
751 char *via_addr = NULL;
752 int via_port = 0;
753 pjsip_cid_hdr *call_id_hdr;
754 char *call_id = NULL;
755 size_t alloc_size;
756
757 /* We create a single pool and use it throughout this function where we need one */
758 details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
759 "Contact Comparison", 1024, 256);
760 if (!details.pool) {
761 response->code = 500;
762 return;
763 }
764
765 /* If there are any permanent contacts configured on the AOR we need to take them
766 * into account when counting contacts.
767 */
768 if (aor->permanent_contacts) {
769 permanent = ao2_container_count(aor->permanent_contacts);
770 }
771
772 if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) {
773 /* The provided Contact headers do not conform to the specification */
774 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
775 ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
777 response->code = 400;
778 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
779 return;
780 }
781
782 if (registrar_validate_path(rdata, aor, &path_str)) {
783 /* Ensure that intervening proxies did not make invalid modifications to the request */
784 ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
786 response->code = 420;
787 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
788 return;
789 }
790
791 if (aor->remove_existing) {
792 /* Cumulative number of contacts affected by this registration */
793 contact_count = MAX(updated + added - deleted, 0);
794
795 /* We need to keep track of only existing contacts so we can later
796 * remove them if need be.
797 */
800 if (!existing_contacts) {
801 response->code = 500;
802 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
803 return;
804 }
805
806 ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts);
807 } else {
808 /* Total contacts after this registration */
809 contact_count = ao2_container_count(contacts) - permanent + added - deleted;
810 }
811
812 if (contact_count > aor->max_contacts && aor->remove_unavailable) {
813 /* Get unavailable contact total */
814 int unavail_count = 0;
815
818 if (!unavail_contacts) {
819 response->code = 500;
820 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
821 return;
822 }
823 ao2_callback(contacts, OBJ_NODATA, registrar_add_unreachable, unavail_contacts);
824 if (unavail_contacts) {
825 unavail_count = ao2_container_count(unavail_contacts);
826 }
827
828 /* Check to see if removing unavailable contacts will help */
829 if (contact_count - unavail_count <= aor->max_contacts) {
830 /* Remove any unavailable contacts */
831 remove_excess_contacts(unavail_contacts, contacts, contact_count - aor->max_contacts, aor->remove_existing);
832 ao2_cleanup(unavail_contacts);
833 /* We're only here if !aor->remove_existing so this count is correct */
834 contact_count = ao2_container_count(contacts) - permanent + added - deleted;
835 }
836 }
837
838 if (contact_count > aor->max_contacts) {
839 /* Enforce the maximum number of contacts */
840 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
841 ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' (%s:%d) to AOR '%s' will exceed max contacts of %u\n",
842 ast_sorcery_object_get_id(endpoint), rdata->pkt_info.src_name, rdata->pkt_info.src_port,
843 aor_name, aor->max_contacts);
844 response->code = 403;
845 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
846 ao2_cleanup(existing_contacts);
847 return;
848 }
849
850 user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
851 if (user_agent_hdr) {
852 alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
853 user_agent = ast_alloca(alloc_size);
854 ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
855 }
856
857 /* Find the first Via header */
858 via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
859 if (via_hdr) {
860 /* Find the last Via header */
861 while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
862 PJSIP_H_VIA, via_hdr->next)) != NULL) {
863 via_hdr_last = via_hdr;
864 }
865 alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
866 via_addr = ast_alloca(alloc_size);
867 ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
868 via_port=via_hdr_last->sent_by.port;
869 }
870
871 call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
872 if (call_id_hdr) {
873 alloc_size = pj_strlen(&call_id_hdr->id) + 1;
874 call_id = ast_alloca(alloc_size);
875 ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
876 }
877
878 /* Iterate each provided Contact header and add, update, or delete */
879 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)) {
880 int expiration;
881 char contact_uri[pjsip_max_url_size];
882 RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
883
884 if (contact_hdr->star) {
885 /* A star means to unregister everything, so do so for the possible contacts */
887 registrar_delete_contact, (void *)aor_name);
888 /* If we are keeping track of existing contacts for removal then, well, there is
889 * absolutely nothing left so no need to try to remove any.
890 */
891 if (existing_contacts) {
892 ao2_ref(existing_contacts, -1);
893 existing_contacts = NULL;
894 }
895 break;
896 }
897
898 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
899 /* This registrar only currently supports sip: and sips: URI schemes */
900 continue;
901 }
902
903 expiration = registrar_get_expiration(aor, contact_hdr, rdata);
904 details.uri = pjsip_uri_get_uri(contact_hdr->uri);
905 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
906
907 contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
908
909 /* If a contact was returned and we need to keep track of existing contacts then it
910 * should be removed.
911 */
912 if (contact && existing_contacts) {
913 ao2_unlink(existing_contacts, contact);
914 }
915
916 if (!contact) {
917 int prune_on_boot;
918
919 /* If they are actually trying to delete a contact that does not exist... be forgiving */
920 if (!expiration) {
921 ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
922 contact_uri, aor_name);
923 continue;
924 }
925
927
928 contact = ast_sip_location_create_contact(aor, contact_uri,
929 ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)),
930 path_str ? ast_str_buffer(path_str) : NULL,
932 if (!contact) {
933 ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
934 contact_uri, aor_name);
935 continue;
936 }
937
938 if (prune_on_boot) {
939 size_t contact_name_len;
940 const char *contact_name;
941 struct contact_transport_monitor *monitor;
942
943 /*
944 * Monitor the transport in case it gets disconnected because
945 * the contact won't be valid anymore if that happens.
946 */
948 contact_name_len = strlen(contact_name) + 1;
949 monitor = ao2_alloc(sizeof(*monitor) + 1 + strlen(aor_name)
950 + contact_name_len, NULL);
951 if (monitor) {
952 strcpy(monitor->aor_name, aor_name);/* Safe */
953 monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1;
954 ast_copy_string(monitor->contact_name, contact_name, contact_name_len);/* Safe */
955
956 ast_sip_transport_monitor_register_replace(rdata->tp_info.transport,
958 ao2_ref(monitor, -1);
959 }
960 }
961
962 ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
963 contact_uri, aor_name, expiration);
964 ast_test_suite_event_notify("AOR_CONTACT_ADDED",
965 "Contact: %s\r\n"
966 "AOR: %s\r\n"
967 "Expiration: %d\r\n"
968 "UserAgent: %s",
969 contact_uri,
970 aor_name,
971 expiration,
972 user_agent);
973
974 ao2_link(contacts, contact);
975 } else if (expiration) {
976 struct ast_sip_contact *contact_update;
977
978 contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
979 if (!contact_update) {
980 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
981 contact->uri, expiration);
982 continue;
983 }
984
985 contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
986 contact_update->qualify_frequency = aor->qualify_frequency;
987 contact_update->authenticate_qualify = aor->authenticate_qualify;
988 contact_update->qualify_2xx_only = aor->qualify_2xx_only;
989 if (path_str) {
990 ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
991 }
992 if (user_agent) {
994 }
997 }
998
999 if (ast_sip_location_update_contact(contact_update)) {
1000 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
1001 contact->uri, expiration);
1002 registrar_contact_delete(CONTACT_DELETE_ERROR, rdata->tp_info.transport,
1003 contact, aor_name);
1004 continue;
1005 }
1006 ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
1007 contact_uri, aor_name, expiration);
1008 ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
1009 "Contact: %s\r\n"
1010 "AOR: %s\r\n"
1011 "Expiration: %d\r\n"
1012 "UserAgent: %s",
1013 contact_uri,
1014 aor_name,
1015 expiration,
1016 contact_update->user_agent);
1017 ao2_link(contacts, contact_update);
1018 ao2_cleanup(contact_update);
1019 } else {
1020 registrar_contact_delete(CONTACT_DELETE_REQUEST, rdata->tp_info.transport,
1021 contact, aor_name);
1022 }
1023 }
1024
1025 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
1026
1027 /*
1028 * If the AOR is configured to remove any contacts over max_contacts
1029 * that have not been updated/added/deleted as a result of this
1030 * REGISTER do so.
1031 *
1032 * The existing contacts container holds all contacts that were not
1033 * involved in this REGISTER.
1034 * The contacts container holds the current contacts of the AOR.
1035 */
1036 if (aor->remove_existing && existing_contacts) {
1037 /* Total contacts after this registration */
1038 contact_count = ao2_container_count(existing_contacts) + updated + added;
1039 if (contact_count > aor->max_contacts) {
1040 /* Remove excess existing contacts that are unavailable or expire soonest */
1041 remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts,
1042 aor->remove_existing);
1043 }
1044 ao2_ref(existing_contacts, -1);
1045 }
1046
1047 response_contact = ao2_callback(contacts, 0, NULL, NULL);
1048
1049 /* Send a response containing all of the contacts (including static) that are present on this AOR */
1050 if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
1051 ao2_cleanup(response_contact);
1052 ao2_cleanup(contacts);
1053 response->code = 500;
1054 return;
1055 }
1056 ao2_cleanup(response_contact);
1057
1058 /* Add the date header to the response, some UAs use this to set their date and time */
1060
1061 ao2_callback(contacts, 0, registrar_add_contact, tdata);
1062
1063 if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
1064 expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
1065 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
1066 }
1067
1068 response->tdata = tdata;
1069}
#define ao2_link(container, obj)
Add an object to a container.
Definition astobj2.h:1532
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition astobj2.h:367
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition astobj2.h:1578
@ OBJ_MULTIPLE
Definition astobj2.h:1049
@ OBJ_UNLINK
Definition astobj2.h:1039
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Definition astobj2.h:1327
#define ao2_alloc(data_size, destructor_fn)
Definition astobj2.h:409
#define ast_verb(level,...)
const char * ast_config_AST_SYSTEM_NAME
Definition options.c:171
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Definition res_pjsip.c:525
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:2468
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:90
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.
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
int ast_sip_location_update_contact(struct ast_sip_contact *contact)
Update a contact.
Definition location.c:446
void ast_sip_report_failed_acl(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *name)
Send a security event notification for when an ACL check fails.
static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
static int registrar_add_unreachable(void *obj, void *arg, int flags)
Internal callback function which adds any contact which is unreachable.
static int registrar_find_contact(void *obj, void *arg, int flags)
Callback function for finding a contact.
static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts, unsigned int to_remove, unsigned int remove_existing)
static int registrar_add_contact(void *obj, void *arg, int flags)
Internal function which adds a contact to a response.
static unsigned int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
Internal function which returns the expiration time for a contact.
static int registrar_validate_contacts(const pjsip_rx_data *rdata, pj_pool_t *pool, struct ao2_container *contacts, struct ast_sip_aor *aor, int permanent, int *added, int *updated, int *deleted)
Internal function which validates provided Contact headers to confirm that they are acceptable,...
static int registrar_add_non_permanent(void *obj, void *arg, int flags)
Callback function which adds non-permanent contacts to a container.
static void register_contact_transport_shutdown_cb(void *data)
static int contact_transport_monitor_matcher(void *a, void *b)
static int registrar_delete_contact(void *obj, void *arg, int flags)
Internal function used to delete a contact from an AOR.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
Definition sorcery.c:2528
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition sorcery.c:1842
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
struct ast_sip_endpoint * endpoint
Definition res_pjsip.h:422
const ast_string_field via_addr
Definition res_pjsip.h:412
const ast_string_field call_id
Definition res_pjsip.h:412
const ast_string_field path
Definition res_pjsip.h:412
int authenticate_qualify
Definition res_pjsip.h:418
const ast_string_field reg_server
Definition res_pjsip.h:412
const ast_string_field user_agent
Definition res_pjsip.h:412
unsigned int qualify_frequency
Definition res_pjsip.h:416
Structure used for finding contact.
pj_pool_t * pool
Pool used for parsing URI.
pjsip_sip_uri * uri
URI being looked for.
#define ast_test_suite_event_notify(s, f,...)
Definition test.h:189
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:282
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition extconf.c:2280
#define MAX(a, b)
Definition utils.h:251

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, aor_core_response::code, 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, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_sip_contact::path, pjsip_max_url_size, registrar_contact_details::pool, ast_sip_contact::prune_on_boot, ast_sip_contact::qualify_2xx_only, 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_add_unreachable(), registrar_contact_delete(), registrar_delete_contact(), registrar_find_contact(), registrar_get_expiration(), registrar_validate_contacts(), registrar_validate_path(), remove_excess_contacts(), aor_core_response::tdata, registrar_contact_details::uri, ast_sip_contact::user_agent, ast_sip_contact::via_addr, and ast_sip_contact::via_port.

Referenced by register_aor().

◆ register_contact_transport_remove_cb()

static int register_contact_transport_remove_cb ( void *  data)
static

Definition at line 403 of file res_pjsip_registrar.c.

404{
405 struct contact_transport_monitor *monitor = data;
406 struct ast_sip_contact *contact;
407 struct ast_sip_aor *aor;
408
410 if (!aor) {
411 ao2_lock(monitor);
412 monitor->removing = 0;
413 ao2_unlock(monitor);
414 ao2_ref(monitor, -1);
415 return 0;
416 }
417
418 ao2_lock(aor);
419
421 if (contact) {
423 ao2_ref(contact, -1);
424 }
425 ao2_unlock(aor);
426 ao2_ref(aor, -1);
427
428 ao2_ref(monitor, -1);
429 return 0;
430}
struct ast_sip_contact * ast_sip_location_retrieve_contact(const char *contact_name)
Retrieve a named contact.
Definition location.c:350

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, NULL, registrar_contact_delete(), and contact_transport_monitor::removing.

Referenced by register_contact_transport_shutdown_cb().

◆ register_contact_transport_shutdown_cb()

static void register_contact_transport_shutdown_cb ( void *  data)
static

Definition at line 440 of file res_pjsip_registrar.c.

441{
442 struct contact_transport_monitor *monitor = data;
443
444 /*
445 * It's possible for this shutdown handler to get called multiple times for the
446 * same monitor from different threads. Only one of the calls needs to do the
447 * actual removing of the contact, so if one is currently removing then any
448 * subsequent calls can skip.
449 */
450 ao2_lock(monitor);
451 if (monitor->removing) {
452 ao2_unlock(monitor);
453 return;
454 }
455
456 monitor->removing = 1;
457
458 /*
459 * Push off to a default serializer. This is in case sorcery
460 * does database accesses for contacts. Database accesses may
461 * not be on this machine. We don't want to tie up the pjsip
462 * monitor thread with potentially long access times.
463 */
464 ao2_ref(monitor, +1);
466 monitor->removing = 0;
467 ao2_ref(monitor, -1);
468 }
469
470 ao2_unlock(monitor);
471}
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Definition res_pjsip.c:2099
static int register_contact_transport_remove_cb(void *data)

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

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

◆ 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 296 of file res_pjsip_registrar.c.

297{
298 struct ast_sip_contact *contact = obj;
299 pjsip_tx_data *tdata = arg;
300 pj_str_t uri;
301 pjsip_uri *parsed;
302
303 pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
304 parsed = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
305
306 if (parsed && (PJSIP_URI_SCHEME_IS_SIP(parsed) || PJSIP_URI_SCHEME_IS_SIPS(parsed))) {
307 pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
308 hdr->uri = parsed;
309 if (!ast_tvzero(contact->expiration_time)) {
310 hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
311 } else {
312 hdr->expires = PJSIP_EXPIRES_NOT_SPECIFIED;
313 }
314 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
315 } else {
316 ast_log(LOG_WARNING, "Skipping invalid Contact URI \"%.*s\" for AOR %s\n",
317 (int) uri.slen, uri.ptr, contact->aor);
318 }
319
320 return 0;
321}
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition res_pjsip.h:68
const ast_string_field uri
Definition res_pjsip.h:412
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition time.h:117

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, and ast_sip_contact::uri.

Referenced by register_aor_core().

◆ 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 681 of file res_pjsip_registrar.c.

682{
683 struct ast_sip_contact *contact = obj;
684 struct ao2_container *container = arg;
685
686 if (ast_tvzero(contact->expiration_time)) {
687 return 0;
688 }
689
690 ao2_link(container, contact);
691
692 return 0;
693}
struct ao2_container * container
Definition res_fax.c:603

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

Referenced by register_aor_core().

◆ registrar_add_unreachable()

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

Internal callback function which adds any contact which is unreachable.

Definition at line 696 of file res_pjsip_registrar.c.

697{
698 struct ast_sip_contact *contact = obj;
699 struct ao2_container *container = arg;
701 int unreachable;
702
704 if (!status) {
705 return 0;
706 }
707
708 unreachable = (status->status == UNAVAILABLE);
709 ao2_ref(status, -1);
710
711 if (unreachable) {
712 ao2_link(container, contact);
713 }
714
715 return 0;
716}
jack_status_t status
Definition app_jack.c:149
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
@ UNAVAILABLE
Definition res_pjsip.h:436
A contact's status.
Definition res_pjsip.h:451

References ao2_link, ao2_ref, ast_sip_get_contact_status(), container, status, and UNAVAILABLE.

Referenced by register_aor_core().

◆ 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 474 of file res_pjsip_registrar.c.

476{
477 int aor_size;
478
479 /* Permanent contacts can't be deleted */
480 if (ast_tvzero(contact->expiration_time)) {
481 return -1;
482 }
483
484 aor_size = aor_name ? strlen(aor_name) : 0;
485 if (contact->prune_on_boot && type != CONTACT_DELETE_SHUTDOWN && aor_size) {
486 const char *contact_name = ast_sorcery_object_get_id(contact);
487 size_t contact_name_len = strlen(contact_name) + 1;
488 struct contact_transport_monitor *monitor = ast_alloca(
489 sizeof(*monitor) + 1 + aor_size + contact_name_len);
490
491 strcpy(monitor->aor_name, aor_name); /* Safe */
492 monitor->contact_name = monitor->aor_name + aor_size + 1;
493 ast_copy_string(monitor->contact_name, contact_name, contact_name_len); /* Safe */
494
495 if (transport) {
499 } else {
500 /*
501 * If a specific transport is not supplied then unregister the matching
502 * monitor from all reliable transports.
503 */
506 }
507 }
508
510
511 if (aor_size) {
512 if (VERBOSITY_ATLEAST(3)) {
513 const char *reason = "none";
514
515 switch (type) {
517 reason = "registration failure";
518 break;
520 reason = "remove existing";
521 break;
523 reason = "remove unavailable";
524 break;
526 reason = "expiration";
527 break;
529 reason = "request";
530 break;
532 reason = "shutdown";
533 break;
534 }
535
536 ast_verb(3, "Removed contact '%s' from AOR '%s' due to %s\n",
537 contact->uri, aor_name, reason);
538 }
539
540 ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
541 "Contact: %s\r\n"
542 "AOR: %s\r\n"
543 "UserAgent: %s",
544 contact->uri,
545 aor_name,
546 contact->user_agent);
547 }
548
549 return 0;
550}
static const char type[]
#define VERBOSITY_ATLEAST(level)
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.
void ast_sip_transport_monitor_unregister_all(ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a transport shutdown monitor from all reliable transports.
int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
Delete a contact.
Definition location.c:451

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_verb, CONTACT_DELETE_ERROR, CONTACT_DELETE_EXISTING, CONTACT_DELETE_EXPIRE, CONTACT_DELETE_REQUEST, CONTACT_DELETE_SHUTDOWN, CONTACT_DELETE_UNAVAILABLE, contact_transport_monitor::contact_name, contact_transport_monitor_matcher(), ast_sip_contact::expiration_time, ast_sip_contact::prune_on_boot, register_contact_transport_shutdown_cb(), type, 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().

◆ 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 289 of file res_pjsip_registrar.c.

290{
292 CONTACT_DELETE_REQUEST, NULL, obj, arg) ? 0 : CMP_MATCH;
293}
@ CMP_MATCH
Definition astobj2.h:1027

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

Referenced by register_aor_core().

◆ registrar_find_contact()

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

Callback function for finding a contact.

Definition at line 193 of file res_pjsip_registrar.c.

194{
195 struct ast_sip_contact *contact = obj;
196 const struct registrar_contact_details *details = arg;
197 pjsip_uri *contact_uri;
198
199 if (ast_tvzero(contact->expiration_time)) {
200 return 0;
201 }
202
203 contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
204 if (!contact_uri) {
205 ast_log(LOG_WARNING, "Unable to parse contact URI from '%s'.\n", contact->uri);
206 return 0;
207 }
208
209 return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
210}

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

Referenced by register_aor_core(), and registrar_validate_contacts().

◆ 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 156 of file res_pjsip_registrar.c.

157{
158 pjsip_expires_hdr *expires;
159 unsigned int expiration = aor->default_expiration;
160
161 if (contact && contact->expires != PJSIP_EXPIRES_NOT_SPECIFIED) {
162 /* Expiration was provided with the contact itself */
163 expiration = contact->expires;
164 } else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
165 /* Expiration was provided using the Expires header */
166 expiration = expires->ivalue;
167 }
168
169 /* If the value has explicitly been set to 0, do not enforce */
170 if (!expiration) {
171 return expiration;
172 }
173
174 /* Enforce the range that we will allow for expiration */
175 if (expiration < aor->minimum_expiration) {
176 expiration = aor->minimum_expiration;
177 } else if (expiration > aor->maximum_expiration) {
178 expiration = aor->maximum_expiration;
179 }
180
181 return expiration;
182}
unsigned int minimum_expiration
Definition res_pjsip.h:488
unsigned int maximum_expiration
Definition res_pjsip.h:490
unsigned int default_expiration
Definition res_pjsip.h:492

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(), and registrar_validate_contacts().

◆ registrar_on_rx_request()

static pj_bool_t registrar_on_rx_request ( struct pjsip_rx_data *  rdata)
static

Definition at line 1247 of file res_pjsip_registrar.c.

1248{
1249 RAII_VAR(struct ast_sip_endpoint *, endpoint,
1251 struct ast_sip_aor *aor;
1252 const char *aor_name;
1253
1254 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
1255 return PJ_FALSE;
1256 }
1257
1258 if (ast_strlen_zero(endpoint->aors)) {
1259 /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
1260 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1261 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
1262 ast_log(LOG_WARNING, "Endpoint '%s' (%s:%d) has no configured AORs\n", ast_sorcery_object_get_id(endpoint),
1263 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1264 return PJ_TRUE;
1265 }
1266
1267 if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
1268 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
1269 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
1270 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),
1271 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1272 return PJ_TRUE;
1273 }
1274
1275 aor = find_registrar_aor(rdata, endpoint);
1276 if (!aor) {
1277 /* We've already responded about not finding an AOR. */
1278 return PJ_TRUE;
1279 }
1280
1281 aor_name = ast_sorcery_object_get_id(aor);
1282
1283 if (!aor->max_contacts) {
1284 /* Registration is not permitted for this AOR */
1285 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1286 ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
1287 ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' (%s:%d) unable to register\n",
1288 aor_name, ast_sorcery_object_get_id(endpoint),
1289 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1290 } else {
1291 register_aor(rdata, endpoint, aor, aor_name);
1292 }
1293 ao2_ref(aor, -1);
1294 return PJ_TRUE;
1295}
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.
static struct ast_sip_aor * find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
static int register_aor(pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint, struct ast_sip_aor *aor, const char *aor_name)
unsigned int max_contacts
Definition res_pjsip.h:498

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().

◆ 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 213 of file res_pjsip_registrar.c.

215{
216 pjsip_contact_hdr *previous = NULL;
217 pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
218 struct registrar_contact_details details = {
219 .pool = pool,
220 };
221
222 for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(pool)) {
223 unsigned int expiration = registrar_get_expiration(aor, contact, rdata);
224 struct ast_sip_contact *existing;
225 char contact_uri[pjsip_max_url_size];
226
227 if (contact->star) {
228 /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
229 if (expiration != 0 || previous) {
230 return -1;
231 }
232 /* Count all contacts to delete */
233 *deleted = ao2_container_count(contacts) - permanent;
234 previous = contact;
235 continue;
236 } else if (previous && previous->star) {
237 /* If there is a previous contact and it is a '*' this is a deal breaker */
238 return -1;
239 }
240 previous = contact;
241
242 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
243 continue;
244 }
245
246 details.uri = pjsip_uri_get_uri(contact->uri);
247
248 /* pjsip_uri_print returns -1 if there's not enough room in the buffer */
249 if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
250 /* If the total length of the uri is greater than pjproject can handle, go no further */
251 return -1;
252 }
253
254 if (details.uri->host.slen >= pj_max_hostname) {
255 /* If the length of the hostname is greater than pjproject can handle, go no further */
256 return -1;
257 }
258
259 /* Determine if this is an add, update, or delete for policy enforcement purposes */
260 existing = ao2_callback(contacts, 0, registrar_find_contact, &details);
261 ao2_cleanup(existing);
262 if (!existing) {
263 if (expiration) {
264 ++*added;
265 }
266 } else if (expiration) {
267 ++*updated;
268 } else {
269 ++*deleted;
270 }
271 }
272
273 return 0;
274}

References ao2_callback, ao2_cleanup, ao2_container_count(), NULL, pj_max_hostname, pjsip_max_url_size, registrar_contact_details::pool, registrar_find_contact(), registrar_get_expiration(), and registrar_contact_details::uri.

Referenced by register_aor_core().

◆ 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 347 of file res_pjsip_registrar.c.

348{
349 const pj_str_t path_supported_name = { "path", 4 };
350 pjsip_supported_hdr *supported_hdr;
351 int i;
352
353 if (!aor->support_path) {
354 return 0;
355 }
356
357 if (build_path_data(rdata, path_str)) {
358 return -1;
359 }
360
361 if (!*path_str) {
362 return 0;
363 }
364
365 supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
366 if (!supported_hdr) {
367 return -1;
368 }
369
370 /* Find advertised path support */
371 for (i = 0; i < supported_hdr->count; i++) {
372 if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
373 return 0;
374 }
375 }
376
377 /* Path header present, but support not advertised */
378 return -1;
379}
static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
unsigned int support_path
Definition res_pjsip.h:504

References ast_sip_contact::aor, build_path_data(), and NULL.

Referenced by register_aor_core().

◆ remove_excess_contacts()

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

Definition at line 637 of file res_pjsip_registrar.c.

639{
640 struct excess_contact_vector contact_vec;
641
642 /*
643 * Create a sorted vector to hold the to_remove soonest to
644 * expire contacts. The vector has an extra space to
645 * temporarily hold the longest to expire contact that we
646 * won't remove.
647 */
648 if (AST_VECTOR_INIT(&contact_vec, to_remove + 1)) {
649 return;
650 }
651 ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, vec_contact_add, &contact_vec);
652
653 /*
654 * The vector should always be populated with the number
655 * of contacts we need to remove. Just in case, we will
656 * remove all contacts in the vector even if the contacts
657 * container had fewer contacts than there should be.
658 */
659 ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove);
660 to_remove = AST_VECTOR_SIZE(&contact_vec);
661
662 /* Remove the excess contacts that are unavailable or expire the soonest */
663 while (to_remove--) {
664 struct ast_sip_contact *contact;
665
666 contact = AST_VECTOR_GET(&contact_vec, to_remove);
667
668 if (!remove_existing) {
670 } else {
672 }
673
674 ao2_unlink(response_contacts, contact);
675 }
676
677 AST_VECTOR_FREE(&contact_vec);
678}
static int vec_contact_add(void *obj, void *arg, int flags)
#define ast_assert(a)
Definition utils.h:776
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition vector.h:185
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition vector.h:124

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, CONTACT_DELETE_UNAVAILABLE, NULL, OBJ_MULTIPLE, OBJ_NODATA, registrar_contact_delete(), and vec_contact_add().

Referenced by register_aor_core().

◆ sip_contact_to_str()

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

Definition at line 1299 of file res_pjsip_registrar.c.

1300{
1301 return ast_sip_contact_to_str(acp, arg, flags);
1302}
int ast_sip_contact_to_str(void *object, void *arg, int flags)
Handler used to convert a contact to a string.
Definition location.c:771

References ast_sip_contact_to_str().

Referenced by ami_registrations_aor().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1522 of file res_pjsip_registrar.c.

1523{
1525 check_interval = 0;
1526 pthread_kill(check_thread, SIGURG);
1527 pthread_join(check_thread, NULL);
1528
1530 }
1531
1533
1538 return 0;
1539}
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition manager.c:7698
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:2487

References AMI_SHOW_REGISTRATION_CONTACT_STATUSES, AMI_SHOW_REGISTRATIONS, ast_manager_unregister(), AST_PTHREADT_NULL, ast_sip_get_sorcery(), ast_sip_transport_monitor_unregister_all(), ast_sip_unregister_service(), ast_sorcery_observer_remove(), check_interval, check_thread, expiration_global_observer, NULL, register_contact_transport_shutdown_cb(), and registrar_module.

◆ vec_contact_add()

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

Definition at line 604 of file res_pjsip_registrar.c.

605{
606 struct ast_sip_contact *contact = obj;
607 struct excess_contact_vector *contact_vec = arg;
608
609 /*
610 * Performance wise, an insertion sort is fine because we
611 * shouldn't need to remove more than a handful of contacts.
612 * I expect we'll typically be removing only one contact.
613 */
614 AST_VECTOR_ADD_SORTED(contact_vec, contact, vec_contact_cmp);
615 if (AST_VECTOR_SIZE(contact_vec) == AST_VECTOR_MAX_SIZE(contact_vec)) {
616 /*
617 * We added a contact over the number we need to remove.
618 * Remove the longest to expire contact from the vector
619 * which is the last element in the vector. It may be
620 * the one we just added or the one we just added pushed
621 * out an earlier contact from removal consideration.
622 */
623 --AST_VECTOR_SIZE(contact_vec);
624 }
625 return 0;
626}
static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact *right)
#define AST_VECTOR_MAX_SIZE(vec)
Get the maximum number of elements the vector can currently hold.
Definition vector.h:628
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition vector.h:382

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

Referenced by remove_excess_contacts().

◆ vec_contact_cmp()

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

Definition at line 554 of file res_pjsip_registrar.c.

555{
556 struct ast_sip_contact *left_contact = left;
557 struct ast_sip_contact *right_contact = right;
558
559 /* Sort from soonest to expire to last to expire */
560 int time_sorted = ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time);
561
562 struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(left_contact->aor);
563 struct ast_sip_contact_status *left_status;
564 struct ast_sip_contact_status *right_status;
565 int remove_unavailable = 0;
566 int left_unreachable;
567 int right_unreachable;
568
569 if (aor) {
570 remove_unavailable = aor->remove_unavailable;
571 ao2_ref(aor, -1);
572 }
573
574 if (!remove_unavailable) {
575 return time_sorted;
576 }
577
578 /* Get contact status if available */
579 left_status = ast_sip_get_contact_status(left_contact);
580 if (!left_status) {
581 return time_sorted;
582 }
583
584 right_status = ast_sip_get_contact_status(right_contact);
585 if (!right_status) {
586 ao2_ref(left_status, -1);
587 return time_sorted;
588 }
589
590 left_unreachable = (left_status->status == UNAVAILABLE);
591 right_unreachable = (right_status->status == UNAVAILABLE);
592 ao2_ref(left_status, -1);
593 ao2_ref(right_status, -1);
594 if (left_unreachable != right_unreachable) {
595 /* Set unavailable contact to top of vector */
596 if (left_unreachable) return -1;
597 if (right_unreachable) return 1;
598 }
599
600 /* Either both available or both unavailable */
601 return time_sorted;
602}
enum ast_sip_contact_status_type status
Definition res_pjsip.h:468
const ast_string_field aor
Definition res_pjsip.h:457
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller,...
Definition time.h:137

References ao2_ref, ast_sip_contact::aor, ast_sip_contact_status::aor, ast_sip_get_contact_status(), ast_sip_location_retrieve_aor(), ast_tvcmp(), ast_sip_contact::expiration_time, ast_sip_contact_status::status, and UNAVAILABLE.

Referenced by vec_contact_add().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP Registrar Support" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .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 1547 of file res_pjsip_registrar.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1547 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 1410 of file res_pjsip_registrar.c.

Referenced by check_expiration_thread(), expiration_global_loaded(), and unload_module().

◆ check_thread

pthread_t check_thread = AST_PTHREADT_NULL
static

Thread keeping things alive.

Definition at line 1407 of file res_pjsip_registrar.c.

Referenced by expiration_global_loaded(), and unload_module().

◆ 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 1490 of file res_pjsip_registrar.c.

1490 {
1491 .loaded = expiration_global_loaded,
1492};

Referenced by load_module(), and unload_module().

◆ path_hdr_name

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

Definition at line 323 of file res_pjsip_registrar.c.

323{ "Path", 4 };

Referenced by build_path_data().

◆ pj_max_hostname

int pj_max_hostname = PJ_MAX_HOSTNAME
static

Definition at line 152 of file res_pjsip_registrar.c.

Referenced by load_module(), and registrar_validate_contacts().

◆ pjsip_max_url_size

int pjsip_max_url_size = PJSIP_MAX_URL_SIZE
static

◆ registrar_module

pjsip_module registrar_module
static

Definition at line 1399 of file res_pjsip_registrar.c.

1399 {
1400 .name = { "Registrar", 9 },
1401 .id = -1,
1402 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
1403 .on_rx_request = registrar_on_rx_request,
1404};
static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)

Referenced by load_module(), and unload_module().