Asterisk - The Open Source Telephony Project GIT-master-3dee037
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 1324 of file res_pjsip_registrar.c.

◆ AMI_SHOW_REGISTRATIONS

#define AMI_SHOW_REGISTRATIONS   "PJSIPShowRegistrationsInbound"

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

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 1475 of file res_pjsip_registrar.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1475 of file res_pjsip_registrar.c.

◆ ami_registrations_aor()

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

Definition at line 1232 of file res_pjsip_registrar.c.

1233{
1234 struct ast_sip_aor *aor = obj;
1235 struct ast_sip_ami *ami = arg;
1236 int *count = ami->arg;
1237 RAII_VAR(struct ast_str *, buf,
1238 ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
1239
1240 if (!buf) {
1241 return -1;
1242 }
1243
1245 ast_str_append(&buf, 0, "Contacts: ");
1247 ast_str_append(&buf, 0, "\r\n");
1248
1249 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1250 (*count)++;
1251 return 0;
1252}
#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:1890
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:3050
struct mansession * s
Definition: res_pjsip.h:3052
void * arg
Definition: res_pjsip.h:3058
A SIP address of record.
Definition: res_pjsip.h:477
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 1254 of file res_pjsip_registrar.c.

1255{
1256 struct ast_sip_endpoint *endpoint = obj;
1257 return ast_sip_for_each_aor(
1258 endpoint->aors, ami_registrations_aor, arg);
1259}
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:962
const ast_string_field aors
Definition: res_pjsip.h:991

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

1262{
1265
1266 if (!endpoints) {
1267 return 0;
1268 }
1269
1271 return 0;
1272}
#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 1289 of file res_pjsip_registrar.c.

1290{
1291 int count = 0;
1292 struct ast_sip_ami ami = { .s = s, .m = m, .arg = NULL, .action_id = astman_get_header(m, "ActionID"), };
1295 struct ao2_iterator i;
1296 struct ast_sip_contact *contact;
1297
1298 astman_send_listack(s, m, "Following are ContactStatusEvents for each Inbound "
1299 "registration", "start");
1300
1301 if (contacts) {
1302 i = ao2_iterator_init(contacts, 0);
1303 while ((contact = ao2_iterator_next(&i))) {
1304 struct ast_sip_contact_wrapper wrapper;
1305
1306 wrapper.aor_id = (char *)contact->aor;
1307 wrapper.contact = contact;
1308 wrapper.contact_id = (char *)ast_sorcery_object_get_id(contact);
1309
1310 ast_sip_format_contact_ami(&wrapper, &ami, 0);
1311 count++;
1312
1313 ao2_ref(contact, -1);
1314 }
1316 ao2_ref(contacts, -1);
1317 }
1318
1319 astman_send_list_complete_start(s, m, "ContactStatusDetailComplete", count);
1321 return 0;
1322}
#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:2011
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:2047
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1630
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2055
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:3054
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:518
struct ast_sip_contact * contact
Definition: res_pjsip.h:524
Contact associated with an address of record.
Definition: res_pjsip.h:389
const ast_string_field aor
Definition: res_pjsip.h:411

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

1275{
1276 int count = 0;
1277 struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };
1278
1279 astman_send_listack(s, m, "Following are Events for each Inbound registration",
1280 "start");
1281
1283
1284 astman_send_list_complete_start(s, m, "InboundRegistrationDetailComplete", count);
1286 return 0;
1287}
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 1475 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 253 of file res_pjsip_registrar.c.

254{
255 pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL);
256
257 if (!path_hdr) {
258 return 0;
259 }
260
261 *path_str = ast_str_create(64);
262 if (!*path_str) {
263 return -1;
264 }
265
266 ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
267
268 while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
269 ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
270 }
271
272 return 0;
273}
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 1365 of file res_pjsip_registrar.c.

1366{
1367 struct ao2_container *contacts;
1368 struct ast_variable *var;
1369 char time[AST_TIME_T_LEN];
1370
1371 while (check_interval) {
1372 sleep(check_interval);
1373
1374 ast_time_t_to_string(ast_tvnow().tv_sec, time, sizeof(time));
1375
1376 var = ast_variable_new("expiration_time <=", time, "");
1377
1378 ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval);
1379
1382
1384 if (contacts) {
1385 ast_debug(3, "Expiring %d contacts\n", ao2_container_count(contacts));
1387 ao2_ref(contacts, -1);
1388 }
1389 }
1390
1391 return NULL;
1392}
#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 322 of file res_pjsip_registrar.c.

323{
324 struct contact_transport_monitor *ma = a;
325 struct contact_transport_monitor *mb = b;
326
327 return strcmp(ma->aor_name, mb->aor_name) == 0
328 && strcmp(ma->contact_name, mb->contact_name) == 0;
329}
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 1394 of file res_pjsip_registrar.c.

1395{
1397
1398 /* Observer calls are serialized so this is safe without it's own lock */
1399 if (check_interval) {
1402 ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n");
1403 return;
1404 }
1405 ast_debug(3, "Interval = %d, starting thread\n", check_interval);
1406 }
1407 } else {
1409 pthread_kill(check_thread, SIGURG);
1410 pthread_join(check_thread, NULL);
1412 ast_debug(3, "Interval = 0, shutting thread down\n");
1413 }
1414 }
1415}
#define ast_log
Definition: astobj2.c:42
#define LOG_ERROR
#define AST_PTHREADT_NULL
Definition: lock.h:66
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 1341 of file res_pjsip_registrar.c.

1342{
1343 struct ast_sip_contact *contact = obj;
1344 struct ast_named_lock *lock;
1345
1347 if (!lock) {
1348 return 0;
1349 }
1350
1351 /*
1352 * We need to check the expiration again with the aor lock held
1353 * in case another thread is attempting to renew the contact.
1354 */
1355 ao2_lock(lock);
1356 if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) {
1358 }
1361
1362 return 0;
1363}
ast_mutex_t lock
Definition: app_sla.c:331
#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:413
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 1046 of file res_pjsip_registrar.c.

1047{
1048 char *configured_aors;
1049 char *aors_buf;
1050 char *aor_name;
1051 char *id_domain;
1052 char *username, *domain;
1053 struct ast_sip_domain_alias *alias;
1054
1055 /* Turn these into C style strings for convenience */
1056 username = ast_alloca(pj_strlen(pj_username) + 1);
1057 ast_copy_pj_str(username, pj_username, pj_strlen(pj_username) + 1);
1058 domain = ast_alloca(pj_strlen(pj_domain) + 1);
1059 ast_copy_pj_str(domain, pj_domain, pj_strlen(pj_domain) + 1);
1060
1061 id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
1062 sprintf(id_domain, "%s@%s", username, domain);
1063
1064 aors_buf = ast_strdupa(aors);
1065
1066 /* Look for exact match on username@domain */
1067 configured_aors = aors_buf;
1068 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1069 if (match_aor(aor_name, id_domain)) {
1070 return ast_strdup(aor_name);
1071 }
1072 }
1073
1074 /* If there's a domain alias, look for exact match on username@domain_alias */
1075 alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
1076 if (alias) {
1077 char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);
1078
1079 sprintf(id_domain_alias, "%s@%s", username, alias->domain);
1080 ao2_cleanup(alias);
1081
1082 configured_aors = strcpy(aors_buf, aors);/* Safe */
1083 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1084 if (match_aor(aor_name, id_domain_alias)) {
1085 return ast_strdup(aor_name);
1086 }
1087 }
1088 }
1089
1090 if (ast_strlen_zero(username)) {
1091 /* No username, no match */
1092 return NULL;
1093 }
1094
1095 /* Look for exact match on username only */
1096 configured_aors = strcpy(aors_buf, aors);/* Safe */
1097 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1098 if (match_aor(aor_name, username)) {
1099 return ast_strdup(aor_name);
1100 }
1101 }
1102
1103 return NULL;
1104}
#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
char * strsep(char **str, const char *delims)
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:320

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

1107{
1108 struct ast_sip_aor *aor = NULL;
1109 char *aor_name = NULL;
1110 int i;
1111
1112 for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) {
1113 pj_str_t username;
1114 pjsip_sip_uri *uri;
1115 pjsip_authorization_hdr *header = NULL;
1116
1117 switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) {
1119 uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
1120
1121 pj_strassign(&username, &uri->user);
1122
1123 /*
1124 * We may want to match without any user options getting
1125 * in the way.
1126 *
1127 * Logic adapted from AST_SIP_USER_OPTIONS_TRUNCATE_CHECK for pj_str_t.
1128 */
1130 pj_ssize_t semi = pj_strcspn2(&username, ";");
1131 if (semi < pj_strlen(&username)) {
1132 username.slen = semi;
1133 }
1134 }
1135
1136 aor_name = find_aor_name(&username, &uri->host, endpoint->aors);
1137 if (aor_name) {
1138 ast_debug(3, "Matched aor '%s' by To username\n", aor_name);
1139 }
1140 break;
1142 while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION,
1143 header ? header->next : NULL))) {
1144 if (header && !pj_stricmp2(&header->scheme, "digest")) {
1145 aor_name = find_aor_name(&header->credential.digest.username,
1146 &header->credential.digest.realm, endpoint->aors);
1147 if (aor_name) {
1148 ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name);
1149 break;
1150 }
1151 }
1152 }
1153 break;
1154 default:
1155 continue;
1156 }
1157
1158 if (aor_name) {
1159 break;
1160 }
1161 }
1162
1163 if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
1164 /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
1165 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
1166 ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
1167 ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s' (%s:%d)\n",
1168 aor_name ?: "", ast_sorcery_object_get_id(endpoint),
1169 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1170 }
1171 ast_free(aor_name);
1172 return aor;
1173}
#define LOG_WARNING
@ AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME
Definition: res_pjsip.h:612
@ AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME
Definition: res_pjsip.h:614
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:1015
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 1422 of file res_pjsip_registrar.c.

1423{
1424 const pj_str_t STR_REGISTER = { "REGISTER", 8 };
1425
1426 ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
1427 /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
1428 ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
1429
1432 }
1433
1434 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
1437 }
1438
1443
1446
1448}
#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:191
@ 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 1032 of file res_pjsip_registrar.c.

1033{
1034 if (ast_strlen_zero(aor_name)) {
1035 return 0;
1036 }
1037
1038 if (!strcmp(aor_name, id)) {
1039 ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name);
1040 return 1;
1041 }
1042
1043 return 0;
1044}

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

1003{
1004 struct aor_core_response response = {
1005 .code = 500,
1006 };
1007 struct ao2_container *contacts = NULL;
1008
1009 ao2_lock(aor);
1011 if (!contacts) {
1012 ao2_unlock(aor);
1013 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1014 rdata, response.code, NULL, NULL, NULL);
1015 return PJ_TRUE;
1016 }
1017
1018 register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
1019 ao2_cleanup(contacts);
1020 ao2_unlock(aor);
1021
1022 /* Now send the REGISTER response to the peer */
1023 if (response.tdata) {
1024 ast_sip_send_stateful_response(rdata, response.tdata, endpoint);
1025 } else {
1026 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1027 rdata, response.code, NULL, NULL, NULL);
1028 }
1029 return PJ_TRUE;
1030}
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 653 of file res_pjsip_registrar.c.

659{
660 static const pj_str_t USER_AGENT = { "User-Agent", 10 };
661
662 int added = 0;
663 int updated = 0;
664 int deleted = 0;
665 int permanent = 0;
666 int contact_count;
667 struct ao2_container *existing_contacts = NULL;
668 struct ao2_container *unavail_contacts = NULL;
669 pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
670 struct registrar_contact_details details = { 0, };
671 pjsip_tx_data *tdata;
672 RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
673 struct ast_sip_contact *response_contact;
674 char *user_agent = NULL;
675 pjsip_user_agent_hdr *user_agent_hdr;
676 pjsip_expires_hdr *expires_hdr;
677 pjsip_via_hdr *via_hdr;
678 pjsip_via_hdr *via_hdr_last;
679 char *via_addr = NULL;
680 int via_port = 0;
681 pjsip_cid_hdr *call_id_hdr;
682 char *call_id = NULL;
683 size_t alloc_size;
684
685 /* We create a single pool and use it throughout this function where we need one */
686 details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
687 "Contact Comparison", 1024, 256);
688 if (!details.pool) {
689 response->code = 500;
690 return;
691 }
692
693 /* If there are any permanent contacts configured on the AOR we need to take them
694 * into account when counting contacts.
695 */
696 if (aor->permanent_contacts) {
697 permanent = ao2_container_count(aor->permanent_contacts);
698 }
699
700 if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) {
701 /* The provided Contact headers do not conform to the specification */
702 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
703 ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
705 response->code = 400;
706 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
707 return;
708 }
709
710 if (registrar_validate_path(rdata, aor, &path_str)) {
711 /* Ensure that intervening proxies did not make invalid modifications to the request */
712 ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
714 response->code = 420;
715 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
716 return;
717 }
718
719 if (aor->remove_existing) {
720 /* Cumulative number of contacts affected by this registration */
721 contact_count = MAX(updated + added - deleted, 0);
722
723 /* We need to keep track of only existing contacts so we can later
724 * remove them if need be.
725 */
728 if (!existing_contacts) {
729 response->code = 500;
730 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
731 return;
732 }
733
734 ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts);
735 } else {
736 /* Total contacts after this registration */
737 contact_count = ao2_container_count(contacts) - permanent + added - deleted;
738 }
739
740 if (contact_count > aor->max_contacts && aor->remove_unavailable) {
741 /* Get unavailable contact total */
742 int unavail_count = 0;
743
746 if (!unavail_contacts) {
747 response->code = 500;
748 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
749 return;
750 }
751 ao2_callback(contacts, OBJ_NODATA, registrar_add_unreachable, unavail_contacts);
752 if (unavail_contacts) {
753 unavail_count = ao2_container_count(unavail_contacts);
754 }
755
756 /* Check to see if removing unavailable contacts will help */
757 if (contact_count - unavail_count <= aor->max_contacts) {
758 /* Remove any unavailable contacts */
759 remove_excess_contacts(unavail_contacts, contacts, contact_count - aor->max_contacts, aor->remove_existing);
760 ao2_cleanup(unavail_contacts);
761 /* We're only here if !aor->remove_existing so this count is correct */
762 contact_count = ao2_container_count(contacts) - permanent + added - deleted;
763 }
764 }
765
766 if (contact_count > aor->max_contacts) {
767 /* Enforce the maximum number of contacts */
768 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
769 ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' (%s:%d) to AOR '%s' will exceed max contacts of %u\n",
770 ast_sorcery_object_get_id(endpoint), rdata->pkt_info.src_name, rdata->pkt_info.src_port,
771 aor_name, aor->max_contacts);
772 response->code = 403;
773 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
774 ao2_cleanup(existing_contacts);
775 return;
776 }
777
778 user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
779 if (user_agent_hdr) {
780 alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
781 user_agent = ast_alloca(alloc_size);
782 ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
783 }
784
785 /* Find the first Via header */
786 via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
787 if (via_hdr) {
788 /* Find the last Via header */
789 while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
790 PJSIP_H_VIA, via_hdr->next)) != NULL) {
791 via_hdr_last = via_hdr;
792 }
793 alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
794 via_addr = ast_alloca(alloc_size);
795 ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
796 via_port=via_hdr_last->sent_by.port;
797 }
798
799 call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
800 if (call_id_hdr) {
801 alloc_size = pj_strlen(&call_id_hdr->id) + 1;
802 call_id = ast_alloca(alloc_size);
803 ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
804 }
805
806 /* Iterate each provided Contact header and add, update, or delete */
807 for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) {
808 int expiration;
809 char contact_uri[pjsip_max_url_size];
810 RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
811
812 if (contact_hdr->star) {
813 /* A star means to unregister everything, so do so for the possible contacts */
815 registrar_delete_contact, (void *)aor_name);
816 /* If we are keeping track of existing contacts for removal then, well, there is
817 * absolutely nothing left so no need to try to remove any.
818 */
819 if (existing_contacts) {
820 ao2_ref(existing_contacts, -1);
821 existing_contacts = NULL;
822 }
823 break;
824 }
825
826 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
827 /* This registrar only currently supports sip: and sips: URI schemes */
828 continue;
829 }
830
831 expiration = registrar_get_expiration(aor, contact_hdr, rdata);
832 details.uri = pjsip_uri_get_uri(contact_hdr->uri);
833 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
834
835 contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
836
837 /* If a contact was returned and we need to keep track of existing contacts then it
838 * should be removed.
839 */
840 if (contact && existing_contacts) {
841 ao2_unlink(existing_contacts, contact);
842 }
843
844 if (!contact) {
845 int prune_on_boot;
846
847 /* If they are actually trying to delete a contact that does not exist... be forgiving */
848 if (!expiration) {
849 ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
850 contact_uri, aor_name);
851 continue;
852 }
853
855
856 contact = ast_sip_location_create_contact(aor, contact_uri,
857 ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)),
858 path_str ? ast_str_buffer(path_str) : NULL,
860 if (!contact) {
861 ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
862 contact_uri, aor_name);
863 continue;
864 }
865
866 if (prune_on_boot) {
867 size_t contact_name_len;
868 const char *contact_name;
869 struct contact_transport_monitor *monitor;
870
871 /*
872 * Monitor the transport in case it gets disconnected because
873 * the contact won't be valid anymore if that happens.
874 */
876 contact_name_len = strlen(contact_name) + 1;
877 monitor = ao2_alloc(sizeof(*monitor) + 1 + strlen(aor_name)
878 + contact_name_len, NULL);
879 if (monitor) {
880 strcpy(monitor->aor_name, aor_name);/* Safe */
881 monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1;
882 ast_copy_string(monitor->contact_name, contact_name, contact_name_len);/* Safe */
883
884 ast_sip_transport_monitor_register_replace(rdata->tp_info.transport,
886 ao2_ref(monitor, -1);
887 }
888 }
889
890 ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
891 contact_uri, aor_name, expiration);
892 ast_test_suite_event_notify("AOR_CONTACT_ADDED",
893 "Contact: %s\r\n"
894 "AOR: %s\r\n"
895 "Expiration: %d\r\n"
896 "UserAgent: %s",
897 contact_uri,
898 aor_name,
899 expiration,
900 user_agent);
901
902 ao2_link(contacts, contact);
903 } else if (expiration) {
904 struct ast_sip_contact *contact_update;
905
906 contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
907 if (!contact_update) {
908 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
909 contact->uri, expiration);
910 continue;
911 }
912
913 contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
914 contact_update->qualify_frequency = aor->qualify_frequency;
915 contact_update->authenticate_qualify = aor->authenticate_qualify;
916 contact_update->qualify_2xx_only = aor->qualify_2xx_only;
917 if (path_str) {
918 ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
919 }
920 if (user_agent) {
922 }
925 }
926
927 if (ast_sip_location_update_contact(contact_update)) {
928 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
929 contact->uri, expiration);
930 registrar_contact_delete(CONTACT_DELETE_ERROR, rdata->tp_info.transport,
931 contact, aor_name);
932 continue;
933 }
934 ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
935 contact_uri, aor_name, expiration);
936 ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
937 "Contact: %s\r\n"
938 "AOR: %s\r\n"
939 "Expiration: %d\r\n"
940 "UserAgent: %s",
941 contact_uri,
942 aor_name,
943 expiration,
944 contact_update->user_agent);
945 ao2_link(contacts, contact_update);
946 ao2_cleanup(contact_update);
947 } else {
948 registrar_contact_delete(CONTACT_DELETE_REQUEST, rdata->tp_info.transport,
949 contact, aor_name);
950 }
951 }
952
953 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
954
955 /*
956 * If the AOR is configured to remove any contacts over max_contacts
957 * that have not been updated/added/deleted as a result of this
958 * REGISTER do so.
959 *
960 * The existing contacts container holds all contacts that were not
961 * involved in this REGISTER.
962 * The contacts container holds the current contacts of the AOR.
963 */
964 if (aor->remove_existing && existing_contacts) {
965 /* Total contacts after this registration */
966 contact_count = ao2_container_count(existing_contacts) + updated + added;
967 if (contact_count > aor->max_contacts) {
968 /* Remove excess existing contacts that are unavailable or expire soonest */
969 remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts,
970 aor->remove_existing);
971 }
972 ao2_ref(existing_contacts, -1);
973 }
974
975 response_contact = ao2_callback(contacts, 0, NULL, NULL);
976
977 /* Send a response containing all of the contacts (including static) that are present on this AOR */
978 if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
979 ao2_cleanup(response_contact);
980 ao2_cleanup(contacts);
981 response->code = 500;
982 return;
983 }
984 ao2_cleanup(response_contact);
985
986 /* Add the date header to the response, some UAs use this to set their date and time */
988
989 ao2_callback(contacts, 0, registrar_add_contact, tdata);
990
991 if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
992 expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
993 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
994 }
995
996 response->tdata = tdata;
997}
#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:170
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:421
const ast_string_field via_addr
Definition: res_pjsip.h:411
int qualify_2xx_only
Definition: res_pjsip.h:427
const ast_string_field call_id
Definition: res_pjsip.h:411
const ast_string_field path
Definition: res_pjsip.h:411
int authenticate_qualify
Definition: res_pjsip.h:417
const ast_string_field reg_server
Definition: res_pjsip.h:411
const ast_string_field user_agent
Definition: res_pjsip.h:411
unsigned int qualify_frequency
Definition: res_pjsip.h:415
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 331 of file res_pjsip_registrar.c.

332{
333 struct contact_transport_monitor *monitor = data;
334 struct ast_sip_contact *contact;
335 struct ast_sip_aor *aor;
336
338 if (!aor) {
339 ao2_lock(monitor);
340 monitor->removing = 0;
341 ao2_unlock(monitor);
342 ao2_ref(monitor, -1);
343 return 0;
344 }
345
346 ao2_lock(aor);
347
349 if (contact) {
351 ao2_ref(contact, -1);
352 }
353 ao2_unlock(aor);
354 ao2_ref(aor, -1);
355
356 ao2_ref(monitor, -1);
357 return 0;
358}
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 368 of file res_pjsip_registrar.c.

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

225{
226 struct ast_sip_contact *contact = obj;
227 pjsip_tx_data *tdata = arg;
228 pj_str_t uri;
229 pjsip_uri *parsed;
230
231 pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
232 parsed = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
233
234 if (parsed && (PJSIP_URI_SCHEME_IS_SIP(parsed) || PJSIP_URI_SCHEME_IS_SIPS(parsed))) {
235 pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
236 hdr->uri = parsed;
237 if (!ast_tvzero(contact->expiration_time)) {
238 hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
239 } else {
240 hdr->expires = PJSIP_EXPIRES_NOT_SPECIFIED;
241 }
242 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
243 } else {
244 ast_log(LOG_WARNING, "Skipping invalid Contact URI \"%.*s\" for AOR %s\n",
245 (int) uri.slen, uri.ptr, contact->aor);
246 }
247
248 return 0;
249}
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:68
const ast_string_field uri
Definition: res_pjsip.h:411
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 609 of file res_pjsip_registrar.c.

610{
611 struct ast_sip_contact *contact = obj;
612 struct ao2_container *container = arg;
613
614 if (ast_tvzero(contact->expiration_time)) {
615 return 0;
616 }
617
618 ao2_link(container, contact);
619
620 return 0;
621}
struct ao2_container * container
Definition: res_fax.c:501

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

625{
626 struct ast_sip_contact *contact = obj;
627 struct ao2_container *container = arg;
629 int unreachable;
630
632 if (!status) {
633 return 0;
634 }
635
636 unreachable = (status->status == UNAVAILABLE);
637 ao2_ref(status, -1);
638
639 if (unreachable) {
640 ao2_link(container, contact);
641 }
642
643 return 0;
644}
jack_status_t status
Definition: app_jack.c:146
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:435
A contact's status.
Definition: res_pjsip.h:450

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

404{
405 int aor_size;
406
407 /* Permanent contacts can't be deleted */
408 if (ast_tvzero(contact->expiration_time)) {
409 return -1;
410 }
411
412 aor_size = aor_name ? strlen(aor_name) : 0;
413 if (contact->prune_on_boot && type != CONTACT_DELETE_SHUTDOWN && aor_size) {
414 const char *contact_name = ast_sorcery_object_get_id(contact);
415 size_t contact_name_len = strlen(contact_name) + 1;
416 struct contact_transport_monitor *monitor = ast_alloca(
417 sizeof(*monitor) + 1 + aor_size + contact_name_len);
418
419 strcpy(monitor->aor_name, aor_name); /* Safe */
420 monitor->contact_name = monitor->aor_name + aor_size + 1;
421 ast_copy_string(monitor->contact_name, contact_name, contact_name_len); /* Safe */
422
423 if (transport) {
427 } else {
428 /*
429 * If a specific transport is not supplied then unregister the matching
430 * monitor from all reliable transports.
431 */
434 }
435 }
436
438
439 if (aor_size) {
440 if (VERBOSITY_ATLEAST(3)) {
441 const char *reason = "none";
442
443 switch (type) {
445 reason = "registration failure";
446 break;
448 reason = "remove existing";
449 break;
451 reason = "remove unavailable";
452 break;
454 reason = "expiration";
455 break;
457 reason = "request";
458 break;
460 reason = "shutdown";
461 break;
462 }
463
464 ast_verb(3, "Removed contact '%s' from AOR '%s' due to %s\n",
465 contact->uri, aor_name, reason);
466 }
467
468 ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
469 "Contact: %s\r\n"
470 "AOR: %s\r\n"
471 "UserAgent: %s",
472 contact->uri,
473 aor_name,
474 contact->user_agent);
475 }
476
477 return 0;
478}
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 217 of file res_pjsip_registrar.c.

218{
220 CONTACT_DELETE_REQUEST, NULL, obj, arg) ? 0 : CMP_MATCH;
221}
@ 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 121 of file res_pjsip_registrar.c.

122{
123 struct ast_sip_contact *contact = obj;
124 const struct registrar_contact_details *details = arg;
125 pjsip_uri *contact_uri;
126
127 if (ast_tvzero(contact->expiration_time)) {
128 return 0;
129 }
130
131 contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
132 if (!contact_uri) {
133 ast_log(LOG_WARNING, "Unable to parse contact URI from '%s'.\n", contact->uri);
134 return 0;
135 }
136
137 return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
138}
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 84 of file res_pjsip_registrar.c.

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

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

1176{
1177 RAII_VAR(struct ast_sip_endpoint *, endpoint,
1179 struct ast_sip_aor *aor;
1180 const char *aor_name;
1181
1182 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
1183 return PJ_FALSE;
1184 }
1185
1186 if (ast_strlen_zero(endpoint->aors)) {
1187 /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
1188 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1189 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
1190 ast_log(LOG_WARNING, "Endpoint '%s' (%s:%d) has no configured AORs\n", ast_sorcery_object_get_id(endpoint),
1191 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1192 return PJ_TRUE;
1193 }
1194
1195 if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
1196 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
1197 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
1198 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),
1199 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1200 return PJ_TRUE;
1201 }
1202
1203 aor = find_registrar_aor(rdata, endpoint);
1204 if (!aor) {
1205 /* We've already responded about not finding an AOR. */
1206 return PJ_TRUE;
1207 }
1208
1209 aor_name = ast_sorcery_object_get_id(aor);
1210
1211 if (!aor->max_contacts) {
1212 /* Registration is not permitted for this AOR */
1213 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1214 ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
1215 ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' (%s:%d) unable to register\n",
1216 aor_name, ast_sorcery_object_get_id(endpoint),
1217 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1218 } else {
1219 register_aor(rdata, endpoint, aor, aor_name);
1220 }
1221 ao2_ref(aor, -1);
1222 return PJ_TRUE;
1223}
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:497

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

143{
144 pjsip_contact_hdr *previous = NULL;
145 pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
146 struct registrar_contact_details details = {
147 .pool = pool,
148 };
149
150 for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(pool)) {
151 unsigned int expiration = registrar_get_expiration(aor, contact, rdata);
152 struct ast_sip_contact *existing;
153 char contact_uri[pjsip_max_url_size];
154
155 if (contact->star) {
156 /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
157 if (expiration != 0 || previous) {
158 return -1;
159 }
160 /* Count all contacts to delete */
161 *deleted = ao2_container_count(contacts) - permanent;
162 previous = contact;
163 continue;
164 } else if (previous && previous->star) {
165 /* If there is a previous contact and it is a '*' this is a deal breaker */
166 return -1;
167 }
168 previous = contact;
169
170 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
171 continue;
172 }
173
174 details.uri = pjsip_uri_get_uri(contact->uri);
175
176 /* pjsip_uri_print returns -1 if there's not enough room in the buffer */
177 if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
178 /* If the total length of the uri is greater than pjproject can handle, go no further */
179 return -1;
180 }
181
182 if (details.uri->host.slen >= pj_max_hostname) {
183 /* If the length of the hostname is greater than pjproject can handle, go no further */
184 return -1;
185 }
186
187 /* Determine if this is an add, update, or delete for policy enforcement purposes */
188 existing = ao2_callback(contacts, 0, registrar_find_contact, &details);
189 ao2_cleanup(existing);
190 if (!existing) {
191 if (expiration) {
192 ++*added;
193 }
194 } else if (expiration) {
195 ++*updated;
196 } else {
197 ++*deleted;
198 }
199 }
200
201 return 0;
202}

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

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

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

567{
568 struct excess_contact_vector contact_vec;
569
570 /*
571 * Create a sorted vector to hold the to_remove soonest to
572 * expire contacts. The vector has an extra space to
573 * temporarily hold the longest to expire contact that we
574 * won't remove.
575 */
576 if (AST_VECTOR_INIT(&contact_vec, to_remove + 1)) {
577 return;
578 }
579 ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, vec_contact_add, &contact_vec);
580
581 /*
582 * The vector should always be populated with the number
583 * of contacts we need to remove. Just in case, we will
584 * remove all contacts in the vector even if the contacts
585 * container had fewer contacts than there should be.
586 */
587 ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove);
588 to_remove = AST_VECTOR_SIZE(&contact_vec);
589
590 /* Remove the excess contacts that are unavailable or expire the soonest */
591 while (to_remove--) {
592 struct ast_sip_contact *contact;
593
594 contact = AST_VECTOR_GET(&contact_vec, to_remove);
595
596 if (!remove_existing) {
598 } else {
600 }
601
602 ao2_unlink(response_contacts, contact);
603 }
604
605 AST_VECTOR_FREE(&contact_vec);
606}
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 1227 of file res_pjsip_registrar.c.

1228{
1229 return ast_sip_contact_to_str(acp, arg, flags);
1230}
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 1450 of file res_pjsip_registrar.c.

1451{
1453 check_interval = 0;
1454 pthread_kill(check_thread, SIGURG);
1455 pthread_join(check_thread, NULL);
1456
1458 }
1459
1461
1466 return 0;
1467}
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7608
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 532 of file res_pjsip_registrar.c.

533{
534 struct ast_sip_contact *contact = obj;
535 struct excess_contact_vector *contact_vec = arg;
536
537 /*
538 * Performance wise, an insertion sort is fine because we
539 * shouldn't need to remove more than a handful of contacts.
540 * I expect we'll typically be removing only one contact.
541 */
542 AST_VECTOR_ADD_SORTED(contact_vec, contact, vec_contact_cmp);
543 if (AST_VECTOR_SIZE(contact_vec) == AST_VECTOR_MAX_SIZE(contact_vec)) {
544 /*
545 * We added a contact over the number we need to remove.
546 * Remove the longest to expire contact from the vector
547 * which is the last element in the vector. It may be
548 * the one we just added or the one we just added pushed
549 * out an earlier contact from removal consideration.
550 */
551 --AST_VECTOR_SIZE(contact_vec);
552 }
553 return 0;
554}
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 482 of file res_pjsip_registrar.c.

483{
484 struct ast_sip_contact *left_contact = left;
485 struct ast_sip_contact *right_contact = right;
486
487 /* Sort from soonest to expire to last to expire */
488 int time_sorted = ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time);
489
490 struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(left_contact->aor);
491 struct ast_sip_contact_status *left_status;
492 struct ast_sip_contact_status *right_status;
493 int remove_unavailable = 0;
494 int left_unreachable;
495 int right_unreachable;
496
497 if (aor) {
498 remove_unavailable = aor->remove_unavailable;
499 ao2_ref(aor, -1);
500 }
501
502 if (!remove_unavailable) {
503 return time_sorted;
504 }
505
506 /* Get contact status if available */
507 left_status = ast_sip_get_contact_status(left_contact);
508 if (!left_status) {
509 return time_sorted;
510 }
511
512 right_status = ast_sip_get_contact_status(right_contact);
513 if (!right_status) {
514 ao2_ref(left_status, -1);
515 return time_sorted;
516 }
517
518 left_unreachable = (left_status->status == UNAVAILABLE);
519 right_unreachable = (right_status->status == UNAVAILABLE);
520 ao2_ref(left_status, -1);
521 ao2_ref(right_status, -1);
522 if (left_unreachable != right_unreachable) {
523 /* Set unavailable contact to top of vector */
524 if (left_unreachable) return -1;
525 if (right_unreachable) return 1;
526 }
527
528 /* Either both available or both unavailable */
529 return time_sorted;
530}
enum ast_sip_contact_status_type status
Definition: res_pjsip.h:467
const ast_string_field aor
Definition: res_pjsip.h:456
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 1475 of file res_pjsip_registrar.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1475 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 1338 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 1335 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 1418 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 251 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 80 of file res_pjsip_registrar.c.

Referenced by load_module().

◆ pjsip_max_url_size

int pjsip_max_url_size = PJSIP_MAX_URL_SIZE
static

Definition at line 81 of file res_pjsip_registrar.c.

Referenced by load_module().

◆ registrar_module

pjsip_module registrar_module
static

Definition at line 1327 of file res_pjsip_registrar.c.

Referenced by load_module(), and unload_module().