Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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. 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_add_unreachable (void *obj, void *arg, int flags)
 Internal callback function which adds any contact which is unreachable. 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, 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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 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 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:1907
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 * 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
void * arg
Definition: res_pjsip.h:3208
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:941

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:2028
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:2064
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
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:2317
@ 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:1897
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:1262
#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 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:592

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:1853
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:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

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:2391
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

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)
pjsip_tx_data * tdata

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:2464
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
Definition: sorcery.c:1778
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521
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
int qualify_2xx_only
Definition: res_pjsip.h:428
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.
#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:2282
#define MAX(a, b)
Definition: utils.h:233

References NULL.

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

◆ 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:531

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

◆ 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.

◆ 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[]
Definition: chan_ooh323.c:109
#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_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().

◆ 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}
pj_pool_t * pool
Pool used for parsing URI.
pjsip_sip_uri * uri
URI being looked for.

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.

◆ 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.

◆ 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 NULL, and registrar_contact_details::pool.

◆ 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.

◆ 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:739
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113

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

◆ 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:7697
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:2423

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:617
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition: vector.h:371

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 = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 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.

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.

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

◆ pjsip_max_url_size

int pjsip_max_url_size = PJSIP_MAX_URL_SIZE
static

Definition at line 153 of file res_pjsip_registrar.c.

Referenced by load_module().

◆ registrar_module

pjsip_module registrar_module
static

Definition at line 1399 of file res_pjsip_registrar.c.

Referenced by load_module(), and unload_module().