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

◆ AMI_SHOW_REGISTRATIONS

#define AMI_SHOW_REGISTRATIONS   "PJSIPShowRegistrationsInbound"

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

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 1474 of file res_pjsip_registrar.c.

◆ ami_registrations_aor()

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

Definition at line 1231 of file res_pjsip_registrar.c.

1232{
1233 struct ast_sip_aor *aor = obj;
1234 struct ast_sip_ami *ami = arg;
1235 int *count = ami->arg;
1236 RAII_VAR(struct ast_str *, buf,
1237 ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
1238
1239 if (!buf) {
1240 return -1;
1241 }
1242
1244 ast_str_append(&buf, 0, "Contacts: ");
1246 ast_str_append(&buf, 0, "\r\n");
1247
1248 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1249 (*count)++;
1250 return 0;
1251}
#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:3302
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:722
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:3047
struct mansession * s
Definition: res_pjsip.h:3049
void * arg
Definition: res_pjsip.h:3055
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 1253 of file res_pjsip_registrar.c.

1254{
1255 struct ast_sip_endpoint *endpoint = obj;
1256 return ast_sip_for_each_aor(
1257 endpoint->aors, ami_registrations_aor, arg);
1258}
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:687
static int ami_registrations_aor(void *obj, void *arg, int flags)
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
const ast_string_field aors
Definition: res_pjsip.h:992

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

1261{
1264
1265 if (!endpoints) {
1266 return 0;
1267 }
1268
1270 return 0;
1271}
#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 1288 of file res_pjsip_registrar.c.

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

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

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

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

1394{
1396
1397 /* Observer calls are serialized so this is safe without it's own lock */
1398 if (check_interval) {
1401 ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n");
1402 return;
1403 }
1404 ast_debug(3, "Interval = %d, starting thread\n", check_interval);
1405 }
1406 } else {
1408 pthread_kill(check_thread, SIGURG);
1409 pthread_join(check_thread, NULL);
1411 ast_debug(3, "Interval = 0, shutting thread down\n");
1412 }
1413 }
1414}
#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 1340 of file res_pjsip_registrar.c.

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

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

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

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

1422{
1423 const pj_str_t STR_REGISTER = { "REGISTER", 8 };
1424
1425 ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
1426 /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
1427 ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
1428
1431 }
1432
1433 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
1436 }
1437
1442
1445
1447}
#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 1031 of file res_pjsip_registrar.c.

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

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

1002{
1003 struct aor_core_response response = {
1004 .code = 500,
1005 };
1006 struct ao2_container *contacts = NULL;
1007
1008 ao2_lock(aor);
1010 if (!contacts) {
1011 ao2_unlock(aor);
1012 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1013 rdata, response.code, NULL, NULL, NULL);
1014 return PJ_TRUE;
1015 }
1016
1017 register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
1018 ao2_cleanup(contacts);
1019 ao2_unlock(aor);
1020
1021 /* Now send the REGISTER response to the peer */
1022 if (response.tdata) {
1023 ast_sip_send_stateful_response(rdata, response.tdata, endpoint);
1024 } else {
1025 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1026 rdata, response.code, NULL, NULL, NULL);
1027 }
1028 return PJ_TRUE;
1029}
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 if (path_str) {
917 ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
918 }
919 if (user_agent) {
921 }
924 }
925
926 if (ast_sip_location_update_contact(contact_update)) {
927 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
928 contact->uri, expiration);
929 registrar_contact_delete(CONTACT_DELETE_ERROR, rdata->tp_info.transport,
930 contact, aor_name);
931 continue;
932 }
933 ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
934 contact_uri, aor_name, expiration);
935 ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
936 "Contact: %s\r\n"
937 "AOR: %s\r\n"
938 "Expiration: %d\r\n"
939 "UserAgent: %s",
940 contact_uri,
941 aor_name,
942 expiration,
943 contact_update->user_agent);
944 ao2_link(contacts, contact_update);
945 ao2_cleanup(contact_update);
946 } else {
947 registrar_contact_delete(CONTACT_DELETE_REQUEST, rdata->tp_info.transport,
948 contact, aor_name);
949 }
950 }
951
952 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
953
954 /*
955 * If the AOR is configured to remove any contacts over max_contacts
956 * that have not been updated/added/deleted as a result of this
957 * REGISTER do so.
958 *
959 * The existing contacts container holds all contacts that were not
960 * involved in this REGISTER.
961 * The contacts container holds the current contacts of the AOR.
962 */
963 if (aor->remove_existing && existing_contacts) {
964 /* Total contacts after this registration */
965 contact_count = ao2_container_count(existing_contacts) + updated + added;
966 if (contact_count > aor->max_contacts) {
967 /* Remove excess existing contacts that are unavailable or expire soonest */
968 remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts,
969 aor->remove_existing);
970 }
971 ao2_ref(existing_contacts, -1);
972 }
973
974 response_contact = ao2_callback(contacts, 0, NULL, NULL);
975
976 /* Send a response containing all of the contacts (including static) that are present on this AOR */
977 if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
978 ao2_cleanup(response_contact);
979 ao2_cleanup(contacts);
980 response->code = 500;
981 return;
982 }
983 ao2_cleanup(response_contact);
984
985 /* Add the date header to the response, some UAs use this to set their date and time */
987
988 ao2_callback(contacts, 0, registrar_add_contact, tdata);
989
990 if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
991 expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
992 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
993 }
994
995 response->tdata = tdata;
996}
#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:445
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:424
const ast_string_field via_addr
Definition: res_pjsip.h:414
const ast_string_field call_id
Definition: res_pjsip.h:414
const ast_string_field path
Definition: res_pjsip.h:414
int authenticate_qualify
Definition: res_pjsip.h:420
const ast_string_field reg_server
Definition: res_pjsip.h:414
const ast_string_field user_agent
Definition: res_pjsip.h:414
unsigned int qualify_frequency
Definition: res_pjsip.h:418
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:414
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: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 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:450

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

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

1227{
1228 return ast_sip_contact_to_str(acp, arg, flags);
1229}
int ast_sip_contact_to_str(void *object, void *arg, int flags)
Handler used to convert a contact to a string.
Definition: location.c:770

References ast_sip_contact_to_str().

Referenced by ami_registrations_aor().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 1449 of file res_pjsip_registrar.c.

1450{
1452 check_interval = 0;
1453 pthread_kill(check_thread, SIGURG);
1454 pthread_join(check_thread, NULL);
1455
1457 }
1458
1460
1465 return 0;
1466}
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:8041
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: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 1474 of file res_pjsip_registrar.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 1474 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 1337 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 1334 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 1417 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 1326 of file res_pjsip_registrar.c.

Referenced by load_module(), and unload_module().