Asterisk - The Open Source Telephony Project GIT-master-754dea3
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
res_pjsip_registrar.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * Joshua Colp <jcolp@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*** MODULEINFO
20 <depend>pjproject</depend>
21 <depend>res_pjproject</depend>
22 <depend>res_pjsip</depend>
23 <support_level>core</support_level>
24 ***/
25
26#include "asterisk.h"
27
28#include <signal.h>
29#include <pjsip.h>
30#include <pjsip_ua.h>
31
32#include "asterisk/res_pjsip.h"
33#include "asterisk/module.h"
34#include "asterisk/paths.h"
35#include "asterisk/test.h"
37#include "asterisk/manager.h"
41
42/*** DOCUMENTATION
43 <manager name="PJSIPShowRegistrationsInbound" language="en_US">
44 <since>
45 <version>12.0.0</version>
46 </since>
47 <synopsis>
48 Lists PJSIP inbound registrations.
49 </synopsis>
50 <syntax />
51 <description>
52 <para>
53 In response, <literal>InboundRegistrationDetail</literal> events showing configuration
54 and status information are raised for all contacts, static or dynamic. Once all events
55 are completed an <literal>InboundRegistrationDetailComplete</literal> is issued.
56 </para>
57 <warning><para>
58 This command just dumps all coonfigured AORs with contacts, even if the contact
59 is a permanent one. To really get just inbound registrations, use
60 <literal>PJSIPShowRegistrationInboundContactStatuses</literal>.
61 </para>
62 </warning>
63 </description>
64 <see-also>
65 <ref type="manager" module="res_pjsip_registrar">PJSIPShowRegistrationInboundContactStatuses</ref>
66 </see-also>
67 </manager>
68 <manager name="PJSIPShowRegistrationInboundContactStatuses" language="en_US">
69 <since>
70 <version>14.3.0</version>
71 <version>13.14.0</version>
72 </since>
73 <synopsis>
74 Lists ContactStatuses for PJSIP inbound registrations.
75 </synopsis>
76 <syntax />
77 <description>
78 <para>
79 In response, <literal>ContactStatusDetail</literal> events showing status information
80 are raised for each inbound registration (dynamic contact) object. Once all events
81 are completed a <literal>ContactStatusDetailComplete</literal> event is issued.
82 </para>
83 </description>
84 </manager>
85 <managerEvent language="en_US" name="InboundRegistrationDetail">
86 <managerEventInstance class="EVENT_FLAG_COMMAND">
87 <since>
88 <version>12.0.0</version>
89 </since>
90 <synopsis>Provide details about the Address of Record (AoR) associated
91 with a registration.</synopsis>
92 <syntax>
93 <parameter name="ObjectType">
94 <para>The object's type. This will always be 'aor'.</para>
95 </parameter>
96 <parameter name="ObjectName">
97 <para>The name of this object.</para>
98 </parameter>
99 <parameter name="MinimumExpiration">
100 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='minimum_expiration']/synopsis/node())"/></para>
101 </parameter>
102 <parameter name="DefaultExpiration">
103 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='default_expiration']/synopsis/node())"/></para>
104 </parameter>
105 <parameter name="QualifyTimeout">
106 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='qualify_timeout']/synopsis/node())"/></para>
107 </parameter>
108 <parameter name="Qualify2xxOnly">
109 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='qualify_2xx_only']/synopsis/node())"/></para>
110 </parameter>
111 <parameter name="Mailboxes">
112 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='mailboxes']/synopsis/node())"/></para>
113 </parameter>
114 <parameter name="SupportPath">
115 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='support_path']/synopsis/node())"/></para>
116 </parameter>
117 <parameter name="RemoveUnavailable">
118 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_unavailable']/synopsis/node())"/></para>
119 </parameter>
120 <parameter name="VoicemailExtension">
121 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='voicemail_extension']/synopsis/node())"/></para>
122 </parameter>
123 <parameter name="MaxContacts">
124 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='max_contacts']/synopsis/node())"/></para>
125 </parameter>
126 <parameter name="AuthenticateQualify">
127 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='authenticate_qualify']/synopsis/node())"/></para>
128 </parameter>
129 <parameter name="MaximumExpiration">
130 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='maximum_expiration']/synopsis/node())"/></para>
131 </parameter>
132 <parameter name="QualifyFrequency">
133 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='qualify_frequency']/synopsis/node())"/></para>
134 </parameter>
135 <parameter name="RemoveExisting">
136 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='remove_existing']/synopsis/node())"/></para>
137 </parameter>
138 <parameter name="OutboundProxy">
139 <para><xi:include xpointer="xpointer(/docs/configInfo[@name='res_pjsip']/configFile[@name='pjsip.conf']/configObject[@name='aor']/configOption[@name='outbound_proxy']/synopsis/node())"/></para>
140 </parameter>
141 <parameter name="Contacts">
142 <para>A comma-separated list of contacts associated with this AoR.</para>
143 </parameter>
144 <parameter name="Contact">
145 <para>The specific contact associated with this registration.</para>
146 </parameter>
147 </syntax>
148 </managerEventInstance>
149 </managerEvent>
150 ***/
151
152static int pj_max_hostname = PJ_MAX_HOSTNAME;
153static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
154
155/*! \brief Internal function which returns the expiration time for a contact */
156static unsigned int registrar_get_expiration(const struct ast_sip_aor *aor, const pjsip_contact_hdr *contact, const pjsip_rx_data *rdata)
157{
158 pjsip_expires_hdr *expires;
159 unsigned int expiration = aor->default_expiration;
160
161 if (contact && contact->expires != PJSIP_EXPIRES_NOT_SPECIFIED) {
162 /* Expiration was provided with the contact itself */
163 expiration = contact->expires;
164 } else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
165 /* Expiration was provided using the Expires header */
166 expiration = expires->ivalue;
167 }
168
169 /* If the value has explicitly been set to 0, do not enforce */
170 if (!expiration) {
171 return expiration;
172 }
173
174 /* Enforce the range that we will allow for expiration */
175 if (expiration < aor->minimum_expiration) {
176 expiration = aor->minimum_expiration;
177 } else if (expiration > aor->maximum_expiration) {
178 expiration = aor->maximum_expiration;
179 }
180
181 return expiration;
182}
183
184/*! \brief Structure used for finding contact */
186 /*! \brief Pool used for parsing URI */
187 pj_pool_t *pool;
188 /*! \brief URI being looked for */
189 pjsip_sip_uri *uri;
190};
191
192/*! \brief Callback function for finding a contact */
193static int registrar_find_contact(void *obj, void *arg, int flags)
194{
195 struct ast_sip_contact *contact = obj;
196 const struct registrar_contact_details *details = arg;
197 pjsip_uri *contact_uri;
198
199 if (ast_tvzero(contact->expiration_time)) {
200 return 0;
201 }
202
203 contact_uri = pjsip_parse_uri(details->pool, (char*)contact->uri, strlen(contact->uri), 0);
204 if (!contact_uri) {
205 ast_log(LOG_WARNING, "Unable to parse contact URI from '%s'.\n", contact->uri);
206 return 0;
207 }
208
209 return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->uri, contact_uri) == PJ_SUCCESS) ? CMP_MATCH : 0;
210}
211
212/*! \brief Internal function which validates provided Contact headers to confirm that they are acceptable, and returns number of contacts */
213static int registrar_validate_contacts(const pjsip_rx_data *rdata, pj_pool_t *pool, struct ao2_container *contacts,
214 struct ast_sip_aor *aor, int permanent, int *added, int *updated, int *deleted)
215{
216 pjsip_contact_hdr *previous = NULL;
217 pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
218 struct registrar_contact_details details = {
219 .pool = pool,
220 };
221
222 for (; (contact = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact->next)); pj_pool_reset(pool)) {
223 unsigned int expiration = registrar_get_expiration(aor, contact, rdata);
224 struct ast_sip_contact *existing;
225 char contact_uri[pjsip_max_url_size];
226
227 if (contact->star) {
228 /* The expiration MUST be 0 when a '*' contact is used and there must be no other contact */
229 if (expiration != 0 || previous) {
230 return -1;
231 }
232 /* Count all contacts to delete */
233 *deleted = ao2_container_count(contacts) - permanent;
234 previous = contact;
235 continue;
236 } else if (previous && previous->star) {
237 /* If there is a previous contact and it is a '*' this is a deal breaker */
238 return -1;
239 }
240 previous = contact;
241
242 if (!PJSIP_URI_SCHEME_IS_SIP(contact->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->uri)) {
243 continue;
244 }
245
246 details.uri = pjsip_uri_get_uri(contact->uri);
247
248 /* pjsip_uri_print returns -1 if there's not enough room in the buffer */
249 if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)) < 0) {
250 /* If the total length of the uri is greater than pjproject can handle, go no further */
251 return -1;
252 }
253
254 if (details.uri->host.slen >= pj_max_hostname) {
255 /* If the length of the hostname is greater than pjproject can handle, go no further */
256 return -1;
257 }
258
259 /* Determine if this is an add, update, or delete for policy enforcement purposes */
260 existing = ao2_callback(contacts, 0, registrar_find_contact, &details);
261 ao2_cleanup(existing);
262 if (!existing) {
263 if (expiration) {
264 ++*added;
265 }
266 } else if (expiration) {
267 ++*updated;
268 } else {
269 ++*deleted;
270 }
271 }
272
273 return 0;
274}
275
283};
284
285static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport,
286 struct ast_sip_contact *contact, const char *aor_name);
287
288/*! \brief Internal function used to delete a contact from an AOR */
289static int registrar_delete_contact(void *obj, void *arg, int flags)
290{
292 CONTACT_DELETE_REQUEST, NULL, obj, arg) ? 0 : CMP_MATCH;
293}
294
295/*! \brief Internal function which adds a contact to a response */
296static int registrar_add_contact(void *obj, void *arg, int flags)
297{
298 struct ast_sip_contact *contact = obj;
299 pjsip_tx_data *tdata = arg;
300 pj_str_t uri;
301 pjsip_uri *parsed;
302
303 pj_strdup2_with_null(tdata->pool, &uri, contact->uri);
304 parsed = pjsip_parse_uri(tdata->pool, uri.ptr, uri.slen, PJSIP_PARSE_URI_AS_NAMEADDR);
305
306 if (parsed && (PJSIP_URI_SCHEME_IS_SIP(parsed) || PJSIP_URI_SCHEME_IS_SIPS(parsed))) {
307 pjsip_contact_hdr *hdr = pjsip_contact_hdr_create(tdata->pool);
308 hdr->uri = parsed;
309 if (!ast_tvzero(contact->expiration_time)) {
310 hdr->expires = ast_tvdiff_ms(contact->expiration_time, ast_tvnow()) / 1000;
311 } else {
312 hdr->expires = PJSIP_EXPIRES_NOT_SPECIFIED;
313 }
314 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
315 } else {
316 ast_log(LOG_WARNING, "Skipping invalid Contact URI \"%.*s\" for AOR %s\n",
317 (int) uri.slen, uri.ptr, contact->aor);
318 }
319
320 return 0;
321}
322
323static const pj_str_t path_hdr_name = { "Path", 4 };
324
325static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
326{
327 pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL);
328
329 if (!path_hdr) {
330 return 0;
331 }
332
333 *path_str = ast_str_create(64);
334 if (!*path_str) {
335 return -1;
336 }
337
338 ast_str_set(path_str, 0, "%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
339
340 while ((path_hdr = (pjsip_generic_string_hdr *) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, path_hdr->next))) {
341 ast_str_append(path_str, 0, ",%.*s", (int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
342 }
343
344 return 0;
345}
346
347static int registrar_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
348{
349 const pj_str_t path_supported_name = { "path", 4 };
350 pjsip_supported_hdr *supported_hdr;
351 int i;
352
353 if (!aor->support_path) {
354 return 0;
355 }
356
357 if (build_path_data(rdata, path_str)) {
358 return -1;
359 }
360
361 if (!*path_str) {
362 return 0;
363 }
364
365 supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
366 if (!supported_hdr) {
367 return -1;
368 }
369
370 /* Find advertised path support */
371 for (i = 0; i < supported_hdr->count; i++) {
372 if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
373 return 0;
374 }
375 }
376
377 /* Path header present, but support not advertised */
378 return -1;
379}
380
381/*! Transport monitor for incoming REGISTER contacts */
383 /*!
384 * \brief Sorcery contact name to remove on transport shutdown
385 * \note Stored after aor_name in space reserved when struct allocated.
386 */
388 /*! Indicates that the monitor is in the process of removing a contact */
390 /*! AOR name the contact is associated */
391 char aor_name[0];
392};
393
394static int contact_transport_monitor_matcher(void *a, void *b)
395{
396 struct contact_transport_monitor *ma = a;
397 struct contact_transport_monitor *mb = b;
398
399 return strcmp(ma->aor_name, mb->aor_name) == 0
400 && strcmp(ma->contact_name, mb->contact_name) == 0;
401}
402
404{
405 struct contact_transport_monitor *monitor = data;
406 struct ast_sip_contact *contact;
407 struct ast_sip_aor *aor;
408
410 if (!aor) {
411 ao2_lock(monitor);
412 monitor->removing = 0;
413 ao2_unlock(monitor);
414 ao2_ref(monitor, -1);
415 return 0;
416 }
417
418 ao2_lock(aor);
419
421 if (contact) {
423 ao2_ref(contact, -1);
424 }
425 ao2_unlock(aor);
426 ao2_ref(aor, -1);
427
428 ao2_ref(monitor, -1);
429 return 0;
430}
431
432/*!
433 * \internal
434 * \brief The reliable transport we registered as a contact has shutdown.
435 *
436 * \param data What contact needs to be removed.
437 *
438 * \note Normally executed by the pjsip monitor thread.
439 */
441{
442 struct contact_transport_monitor *monitor = data;
443
444 /*
445 * It's possible for this shutdown handler to get called multiple times for the
446 * same monitor from different threads. Only one of the calls needs to do the
447 * actual removing of the contact, so if one is currently removing then any
448 * subsequent calls can skip.
449 */
450 ao2_lock(monitor);
451 if (monitor->removing) {
452 ao2_unlock(monitor);
453 return;
454 }
455
456 monitor->removing = 1;
457
458 /*
459 * Push off to a default serializer. This is in case sorcery
460 * does database accesses for contacts. Database accesses may
461 * not be on this machine. We don't want to tie up the pjsip
462 * monitor thread with potentially long access times.
463 */
464 ao2_ref(monitor, +1);
466 monitor->removing = 0;
467 ao2_ref(monitor, -1);
468 }
469
470 ao2_unlock(monitor);
471}
472
473
474static int registrar_contact_delete(enum contact_delete_type type, pjsip_transport *transport,
475 struct ast_sip_contact *contact, const char *aor_name)
476{
477 int aor_size;
478
479 /* Permanent contacts can't be deleted */
480 if (ast_tvzero(contact->expiration_time)) {
481 return -1;
482 }
483
484 aor_size = aor_name ? strlen(aor_name) : 0;
485 if (contact->prune_on_boot && type != CONTACT_DELETE_SHUTDOWN && aor_size) {
486 const char *contact_name = ast_sorcery_object_get_id(contact);
487 size_t contact_name_len = strlen(contact_name) + 1;
488 struct contact_transport_monitor *monitor = ast_alloca(
489 sizeof(*monitor) + 1 + aor_size + contact_name_len);
490
491 strcpy(monitor->aor_name, aor_name); /* Safe */
492 monitor->contact_name = monitor->aor_name + aor_size + 1;
493 ast_copy_string(monitor->contact_name, contact_name, contact_name_len); /* Safe */
494
495 if (transport) {
499 } else {
500 /*
501 * If a specific transport is not supplied then unregister the matching
502 * monitor from all reliable transports.
503 */
506 }
507 }
508
510
511 if (aor_size) {
512 if (VERBOSITY_ATLEAST(3)) {
513 const char *reason = "none";
514
515 switch (type) {
517 reason = "registration failure";
518 break;
520 reason = "remove existing";
521 break;
523 reason = "remove unavailable";
524 break;
526 reason = "expiration";
527 break;
529 reason = "request";
530 break;
532 reason = "shutdown";
533 break;
534 }
535
536 ast_verb(3, "Removed contact '%s' from AOR '%s' due to %s\n",
537 contact->uri, aor_name, reason);
538 }
539
540 ast_test_suite_event_notify("AOR_CONTACT_REMOVED",
541 "Contact: %s\r\n"
542 "AOR: %s\r\n"
543 "UserAgent: %s",
544 contact->uri,
545 aor_name,
546 contact->user_agent);
547 }
548
549 return 0;
550}
551
553
554static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact *right)
555{
556 struct ast_sip_contact *left_contact = left;
557 struct ast_sip_contact *right_contact = right;
558
559 /* Sort from soonest to expire to last to expire */
560 int time_sorted = ast_tvcmp(left_contact->expiration_time, right_contact->expiration_time);
561
562 struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(left_contact->aor);
563 struct ast_sip_contact_status *left_status;
564 struct ast_sip_contact_status *right_status;
565 int remove_unavailable = 0;
566 int left_unreachable;
567 int right_unreachable;
568
569 if (aor) {
570 remove_unavailable = aor->remove_unavailable;
571 ao2_ref(aor, -1);
572 }
573
574 if (!remove_unavailable) {
575 return time_sorted;
576 }
577
578 /* Get contact status if available */
579 left_status = ast_sip_get_contact_status(left_contact);
580 if (!left_status) {
581 return time_sorted;
582 }
583
584 right_status = ast_sip_get_contact_status(right_contact);
585 if (!right_status) {
586 ao2_ref(left_status, -1);
587 return time_sorted;
588 }
589
590 left_unreachable = (left_status->status == UNAVAILABLE);
591 right_unreachable = (right_status->status == UNAVAILABLE);
592 ao2_ref(left_status, -1);
593 ao2_ref(right_status, -1);
594 if (left_unreachable != right_unreachable) {
595 /* Set unavailable contact to top of vector */
596 if (left_unreachable) return -1;
597 if (right_unreachable) return 1;
598 }
599
600 /* Either both available or both unavailable */
601 return time_sorted;
602}
603
604static int vec_contact_add(void *obj, void *arg, int flags)
605{
606 struct ast_sip_contact *contact = obj;
607 struct excess_contact_vector *contact_vec = arg;
608
609 /*
610 * Performance wise, an insertion sort is fine because we
611 * shouldn't need to remove more than a handful of contacts.
612 * I expect we'll typically be removing only one contact.
613 */
614 AST_VECTOR_ADD_SORTED(contact_vec, contact, vec_contact_cmp);
615 if (AST_VECTOR_SIZE(contact_vec) == AST_VECTOR_MAX_SIZE(contact_vec)) {
616 /*
617 * We added a contact over the number we need to remove.
618 * Remove the longest to expire contact from the vector
619 * which is the last element in the vector. It may be
620 * the one we just added or the one we just added pushed
621 * out an earlier contact from removal consideration.
622 */
623 --AST_VECTOR_SIZE(contact_vec);
624 }
625 return 0;
626}
627
628/*!
629 * \internal
630 * \brief Remove excess existing contacts that are unavailable or expire soonest.
631 * \since 13.18.0
632 *
633 * \param contacts Container of unmodified contacts that could remove.
634 * \param to_remove Maximum number of contacts to remove.
635 * \param response_contacts, remove_existing
636 */
637static void remove_excess_contacts(struct ao2_container *contacts, struct ao2_container *response_contacts,
638 unsigned int to_remove, unsigned int remove_existing)
639{
640 struct excess_contact_vector contact_vec;
641
642 /*
643 * Create a sorted vector to hold the to_remove soonest to
644 * expire contacts. The vector has an extra space to
645 * temporarily hold the longest to expire contact that we
646 * won't remove.
647 */
648 if (AST_VECTOR_INIT(&contact_vec, to_remove + 1)) {
649 return;
650 }
651 ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, vec_contact_add, &contact_vec);
652
653 /*
654 * The vector should always be populated with the number
655 * of contacts we need to remove. Just in case, we will
656 * remove all contacts in the vector even if the contacts
657 * container had fewer contacts than there should be.
658 */
659 ast_assert(AST_VECTOR_SIZE(&contact_vec) == to_remove);
660 to_remove = AST_VECTOR_SIZE(&contact_vec);
661
662 /* Remove the excess contacts that are unavailable or expire the soonest */
663 while (to_remove--) {
664 struct ast_sip_contact *contact;
665
666 contact = AST_VECTOR_GET(&contact_vec, to_remove);
667
668 if (!remove_existing) {
670 } else {
672 }
673
674 ao2_unlink(response_contacts, contact);
675 }
676
677 AST_VECTOR_FREE(&contact_vec);
678}
679
680/*! \brief Callback function which adds non-permanent contacts to a container */
681static int registrar_add_non_permanent(void *obj, void *arg, int flags)
682{
683 struct ast_sip_contact *contact = obj;
684 struct ao2_container *container = arg;
685
686 if (ast_tvzero(contact->expiration_time)) {
687 return 0;
688 }
689
690 ao2_link(container, contact);
691
692 return 0;
693}
694
695/*! \brief Internal callback function which adds any contact which is unreachable */
696static int registrar_add_unreachable(void *obj, void *arg, int flags)
697{
698 struct ast_sip_contact *contact = obj;
699 struct ao2_container *container = arg;
701 int unreachable;
702
704 if (!status) {
705 return 0;
706 }
707
708 unreachable = (status->status == UNAVAILABLE);
709 ao2_ref(status, -1);
710
711 if (unreachable) {
712 ao2_link(container, contact);
713 }
714
715 return 0;
716}
717
719 /*! Tx data to use for statefull response. NULL for stateless response. */
720 pjsip_tx_data *tdata;
721 /*! SIP response code to send in stateless response */
722 int code;
723};
724
725static void register_aor_core(pjsip_rx_data *rdata,
726 struct ast_sip_endpoint *endpoint,
727 struct ast_sip_aor *aor,
728 const char *aor_name,
729 struct ao2_container *contacts,
730 struct aor_core_response *response)
731{
732 static const pj_str_t USER_AGENT = { "User-Agent", 10 };
733
734 int added = 0;
735 int updated = 0;
736 int deleted = 0;
737 int permanent = 0;
738 int contact_count;
739 struct ao2_container *existing_contacts = NULL;
740 struct ao2_container *unavail_contacts = NULL;
741 pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
742 struct registrar_contact_details details = { 0, };
743 pjsip_tx_data *tdata;
744 RAII_VAR(struct ast_str *, path_str, NULL, ast_free);
745 struct ast_sip_contact *response_contact;
746 char *user_agent = NULL;
747 pjsip_user_agent_hdr *user_agent_hdr;
748 pjsip_expires_hdr *expires_hdr;
749 pjsip_via_hdr *via_hdr;
750 pjsip_via_hdr *via_hdr_last;
751 char *via_addr = NULL;
752 int via_port = 0;
753 pjsip_cid_hdr *call_id_hdr;
754 char *call_id = NULL;
755 size_t alloc_size;
756
757 /* We create a single pool and use it throughout this function where we need one */
758 details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
759 "Contact Comparison", 1024, 256);
760 if (!details.pool) {
761 response->code = 500;
762 return;
763 }
764
765 /* If there are any permanent contacts configured on the AOR we need to take them
766 * into account when counting contacts.
767 */
768 if (aor->permanent_contacts) {
769 permanent = ao2_container_count(aor->permanent_contacts);
770 }
771
772 if (registrar_validate_contacts(rdata, details.pool, contacts, aor, permanent, &added, &updated, &deleted)) {
773 /* The provided Contact headers do not conform to the specification */
774 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_contacts_provided");
775 ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n",
777 response->code = 400;
778 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
779 return;
780 }
781
782 if (registrar_validate_path(rdata, aor, &path_str)) {
783 /* Ensure that intervening proxies did not make invalid modifications to the request */
784 ast_log(LOG_WARNING, "Invalid modifications made to REGISTER request from '%s' by intervening proxy\n",
786 response->code = 420;
787 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
788 return;
789 }
790
791 if (aor->remove_existing) {
792 /* Cumulative number of contacts affected by this registration */
793 contact_count = MAX(updated + added - deleted, 0);
794
795 /* We need to keep track of only existing contacts so we can later
796 * remove them if need be.
797 */
800 if (!existing_contacts) {
801 response->code = 500;
802 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
803 return;
804 }
805
806 ao2_callback(contacts, OBJ_NODATA, registrar_add_non_permanent, existing_contacts);
807 } else {
808 /* Total contacts after this registration */
809 contact_count = ao2_container_count(contacts) - permanent + added - deleted;
810 }
811
812 if (contact_count > aor->max_contacts && aor->remove_unavailable) {
813 /* Get unavailable contact total */
814 int unavail_count = 0;
815
818 if (!unavail_contacts) {
819 response->code = 500;
820 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
821 return;
822 }
823 ao2_callback(contacts, OBJ_NODATA, registrar_add_unreachable, unavail_contacts);
824 if (unavail_contacts) {
825 unavail_count = ao2_container_count(unavail_contacts);
826 }
827
828 /* Check to see if removing unavailable contacts will help */
829 if (contact_count - unavail_count <= aor->max_contacts) {
830 /* Remove any unavailable contacts */
831 remove_excess_contacts(unavail_contacts, contacts, contact_count - aor->max_contacts, aor->remove_existing);
832 ao2_cleanup(unavail_contacts);
833 /* We're only here if !aor->remove_existing so this count is correct */
834 contact_count = ao2_container_count(contacts) - permanent + added - deleted;
835 }
836 }
837
838 if (contact_count > aor->max_contacts) {
839 /* Enforce the maximum number of contacts */
840 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_exceeds_maximum_configured_contacts");
841 ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' (%s:%d) to AOR '%s' will exceed max contacts of %u\n",
842 ast_sorcery_object_get_id(endpoint), rdata->pkt_info.src_name, rdata->pkt_info.src_port,
843 aor_name, aor->max_contacts);
844 response->code = 403;
845 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
846 ao2_cleanup(existing_contacts);
847 return;
848 }
849
850 user_agent_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &USER_AGENT, NULL);
851 if (user_agent_hdr) {
852 alloc_size = pj_strlen(&user_agent_hdr->hvalue) + 1;
853 user_agent = ast_alloca(alloc_size);
854 ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
855 }
856
857 /* Find the first Via header */
858 via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
859 if (via_hdr) {
860 /* Find the last Via header */
861 while ( (via_hdr = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg,
862 PJSIP_H_VIA, via_hdr->next)) != NULL) {
863 via_hdr_last = via_hdr;
864 }
865 alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
866 via_addr = ast_alloca(alloc_size);
867 ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
868 via_port=via_hdr_last->sent_by.port;
869 }
870
871 call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
872 if (call_id_hdr) {
873 alloc_size = pj_strlen(&call_id_hdr->id) + 1;
874 call_id = ast_alloca(alloc_size);
875 ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
876 }
877
878 /* Iterate each provided Contact header and add, update, or delete */
879 for (; (contact_hdr = (pjsip_contact_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr->next)); pj_pool_reset(details.pool)) {
880 int expiration;
881 char contact_uri[pjsip_max_url_size];
882 RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup);
883
884 if (contact_hdr->star) {
885 /* A star means to unregister everything, so do so for the possible contacts */
887 registrar_delete_contact, (void *)aor_name);
888 /* If we are keeping track of existing contacts for removal then, well, there is
889 * absolutely nothing left so no need to try to remove any.
890 */
891 if (existing_contacts) {
892 ao2_ref(existing_contacts, -1);
893 existing_contacts = NULL;
894 }
895 break;
896 }
897
898 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
899 /* This registrar only currently supports sip: and sips: URI schemes */
900 continue;
901 }
902
903 expiration = registrar_get_expiration(aor, contact_hdr, rdata);
904 details.uri = pjsip_uri_get_uri(contact_hdr->uri);
905 pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri));
906
907 contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details);
908
909 /* If a contact was returned and we need to keep track of existing contacts then it
910 * should be removed.
911 */
912 if (contact && existing_contacts) {
913 ao2_unlink(existing_contacts, contact);
914 }
915
916 if (!contact) {
917 int prune_on_boot;
918
919 /* If they are actually trying to delete a contact that does not exist... be forgiving */
920 if (!expiration) {
921 ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
922 contact_uri, aor_name);
923 continue;
924 }
925
927
928 contact = ast_sip_location_create_contact(aor, contact_uri,
929 ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)),
930 path_str ? ast_str_buffer(path_str) : NULL,
932 if (!contact) {
933 ast_log(LOG_ERROR, "Unable to bind contact '%s' to AOR '%s'\n",
934 contact_uri, aor_name);
935 continue;
936 }
937
938 if (prune_on_boot) {
939 size_t contact_name_len;
940 const char *contact_name;
941 struct contact_transport_monitor *monitor;
942
943 /*
944 * Monitor the transport in case it gets disconnected because
945 * the contact won't be valid anymore if that happens.
946 */
948 contact_name_len = strlen(contact_name) + 1;
949 monitor = ao2_alloc(sizeof(*monitor) + 1 + strlen(aor_name)
950 + contact_name_len, NULL);
951 if (monitor) {
952 strcpy(monitor->aor_name, aor_name);/* Safe */
953 monitor->contact_name = monitor->aor_name + strlen(aor_name) + 1;
954 ast_copy_string(monitor->contact_name, contact_name, contact_name_len);/* Safe */
955
956 ast_sip_transport_monitor_register_replace(rdata->tp_info.transport,
958 ao2_ref(monitor, -1);
959 }
960 }
961
962 ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
963 contact_uri, aor_name, expiration);
964 ast_test_suite_event_notify("AOR_CONTACT_ADDED",
965 "Contact: %s\r\n"
966 "AOR: %s\r\n"
967 "Expiration: %d\r\n"
968 "UserAgent: %s",
969 contact_uri,
970 aor_name,
971 expiration,
972 user_agent);
973
974 ao2_link(contacts, contact);
975 } else if (expiration) {
976 struct ast_sip_contact *contact_update;
977
978 contact_update = ast_sorcery_copy(ast_sip_get_sorcery(), contact);
979 if (!contact_update) {
980 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
981 contact->uri, expiration);
982 continue;
983 }
984
985 contact_update->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1));
986 contact_update->qualify_frequency = aor->qualify_frequency;
987 contact_update->authenticate_qualify = aor->authenticate_qualify;
988 contact_update->qualify_2xx_only = aor->qualify_2xx_only;
989 if (path_str) {
990 ast_string_field_set(contact_update, path, ast_str_buffer(path_str));
991 }
992 if (user_agent) {
994 }
997 }
998
999 if (ast_sip_location_update_contact(contact_update)) {
1000 ast_log(LOG_ERROR, "Failed to update contact '%s' expiration time to %d seconds.\n",
1001 contact->uri, expiration);
1002 registrar_contact_delete(CONTACT_DELETE_ERROR, rdata->tp_info.transport,
1003 contact, aor_name);
1004 continue;
1005 }
1006 ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
1007 contact_uri, aor_name, expiration);
1008 ast_test_suite_event_notify("AOR_CONTACT_REFRESHED",
1009 "Contact: %s\r\n"
1010 "AOR: %s\r\n"
1011 "Expiration: %d\r\n"
1012 "UserAgent: %s",
1013 contact_uri,
1014 aor_name,
1015 expiration,
1016 contact_update->user_agent);
1017 ao2_link(contacts, contact_update);
1018 ao2_cleanup(contact_update);
1019 } else {
1020 registrar_contact_delete(CONTACT_DELETE_REQUEST, rdata->tp_info.transport,
1021 contact, aor_name);
1022 }
1023 }
1024
1025 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool);
1026
1027 /*
1028 * If the AOR is configured to remove any contacts over max_contacts
1029 * that have not been updated/added/deleted as a result of this
1030 * REGISTER do so.
1031 *
1032 * The existing contacts container holds all contacts that were not
1033 * involved in this REGISTER.
1034 * The contacts container holds the current contacts of the AOR.
1035 */
1036 if (aor->remove_existing && existing_contacts) {
1037 /* Total contacts after this registration */
1038 contact_count = ao2_container_count(existing_contacts) + updated + added;
1039 if (contact_count > aor->max_contacts) {
1040 /* Remove excess existing contacts that are unavailable or expire soonest */
1041 remove_excess_contacts(existing_contacts, contacts, contact_count - aor->max_contacts,
1042 aor->remove_existing);
1043 }
1044 ao2_ref(existing_contacts, -1);
1045 }
1046
1047 response_contact = ao2_callback(contacts, 0, NULL, NULL);
1048
1049 /* Send a response containing all of the contacts (including static) that are present on this AOR */
1050 if (ast_sip_create_response(rdata, 200, response_contact, &tdata) != PJ_SUCCESS) {
1051 ao2_cleanup(response_contact);
1052 ao2_cleanup(contacts);
1053 response->code = 500;
1054 return;
1055 }
1056 ao2_cleanup(response_contact);
1057
1058 /* Add the date header to the response, some UAs use this to set their date and time */
1060
1061 ao2_callback(contacts, 0, registrar_add_contact, tdata);
1062
1063 if ((expires_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
1064 expires_hdr = pjsip_expires_hdr_create(tdata->pool, registrar_get_expiration(aor, NULL, rdata));
1065 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires_hdr);
1066 }
1067
1068 response->tdata = tdata;
1069}
1070
1071static int register_aor(pjsip_rx_data *rdata,
1072 struct ast_sip_endpoint *endpoint,
1073 struct ast_sip_aor *aor,
1074 const char *aor_name)
1075{
1076 struct aor_core_response response = {
1077 .code = 500,
1078 };
1079 struct ao2_container *contacts = NULL;
1080
1081 ao2_lock(aor);
1083 if (!contacts) {
1084 ao2_unlock(aor);
1085 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1086 rdata, response.code, NULL, NULL, NULL);
1087 return PJ_TRUE;
1088 }
1089
1090 register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
1091 ao2_cleanup(contacts);
1092 ao2_unlock(aor);
1093
1094 /* Now send the REGISTER response to the peer */
1095 if (response.tdata) {
1096 ast_sip_send_stateful_response(rdata, response.tdata, endpoint);
1097 } else {
1098 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1099 rdata, response.code, NULL, NULL, NULL);
1100 }
1101 return PJ_TRUE;
1102}
1103
1104static int match_aor(const char *aor_name, const char *id)
1105{
1106 if (ast_strlen_zero(aor_name)) {
1107 return 0;
1108 }
1109
1110 if (!strcmp(aor_name, id)) {
1111 ast_debug(3, "Matched id '%s' to aor '%s'\n", id, aor_name);
1112 return 1;
1113 }
1114
1115 return 0;
1116}
1117
1118static char *find_aor_name(const pj_str_t *pj_username, const pj_str_t *pj_domain, const char *aors)
1119{
1120 char *configured_aors;
1121 char *aors_buf;
1122 char *aor_name;
1123 char *id_domain;
1124 char *username, *domain;
1125 struct ast_sip_domain_alias *alias;
1126
1127 /* Turn these into C style strings for convenience */
1128 username = ast_alloca(pj_strlen(pj_username) + 1);
1129 ast_copy_pj_str(username, pj_username, pj_strlen(pj_username) + 1);
1130 domain = ast_alloca(pj_strlen(pj_domain) + 1);
1131 ast_copy_pj_str(domain, pj_domain, pj_strlen(pj_domain) + 1);
1132
1133 id_domain = ast_alloca(strlen(username) + strlen(domain) + 2);
1134 sprintf(id_domain, "%s@%s", username, domain);
1135
1136 aors_buf = ast_strdupa(aors);
1137
1138 /* Look for exact match on username@domain */
1139 configured_aors = aors_buf;
1140 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1141 if (match_aor(aor_name, id_domain)) {
1142 return ast_strdup(aor_name);
1143 }
1144 }
1145
1146 /* If there's a domain alias, look for exact match on username@domain_alias */
1147 alias = ast_sorcery_retrieve_by_id(ast_sip_get_sorcery(), "domain_alias", domain);
1148 if (alias) {
1149 char *id_domain_alias = ast_alloca(strlen(username) + strlen(alias->domain) + 2);
1150
1151 sprintf(id_domain_alias, "%s@%s", username, alias->domain);
1152 ao2_cleanup(alias);
1153
1154 configured_aors = strcpy(aors_buf, aors);/* Safe */
1155 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1156 if (match_aor(aor_name, id_domain_alias)) {
1157 return ast_strdup(aor_name);
1158 }
1159 }
1160 }
1161
1162 if (ast_strlen_zero(username)) {
1163 /* No username, no match */
1164 return NULL;
1165 }
1166
1167 /* Look for exact match on username only */
1168 configured_aors = strcpy(aors_buf, aors);/* Safe */
1169 while ((aor_name = ast_strip(strsep(&configured_aors, ",")))) {
1170 if (match_aor(aor_name, username)) {
1171 return ast_strdup(aor_name);
1172 }
1173 }
1174
1175 return NULL;
1176}
1177
1178static struct ast_sip_aor *find_registrar_aor(struct pjsip_rx_data *rdata, struct ast_sip_endpoint *endpoint)
1179{
1180 struct ast_sip_aor *aor = NULL;
1181 char *aor_name = NULL;
1182 int i;
1183
1184 for (i = 0; i < AST_VECTOR_SIZE(&endpoint->ident_method_order); ++i) {
1185 pj_str_t username;
1186 pjsip_sip_uri *uri;
1187 pjsip_authorization_hdr *header = NULL;
1188
1189 switch (AST_VECTOR_GET(&endpoint->ident_method_order, i)) {
1191 uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
1192
1193 pj_strassign(&username, &uri->user);
1194
1195 /*
1196 * We may want to match without any user options getting
1197 * in the way.
1198 *
1199 * Logic adapted from AST_SIP_USER_OPTIONS_TRUNCATE_CHECK for pj_str_t.
1200 */
1202 pj_ssize_t semi = pj_strcspn2(&username, ";");
1203 if (semi < pj_strlen(&username)) {
1204 username.slen = semi;
1205 }
1206 }
1207
1208 aor_name = find_aor_name(&username, &uri->host, endpoint->aors);
1209 if (aor_name) {
1210 ast_debug(3, "Matched aor '%s' by To username\n", aor_name);
1211 }
1212 break;
1214 while ((header = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION,
1215 header ? header->next : NULL))) {
1216 if (header && !pj_stricmp2(&header->scheme, "digest")) {
1217 aor_name = find_aor_name(&header->credential.digest.username,
1218 &header->credential.digest.realm, endpoint->aors);
1219 if (aor_name) {
1220 ast_debug(3, "Matched aor '%s' by Authentication username\n", aor_name);
1221 break;
1222 }
1223 }
1224 }
1225 break;
1226 default:
1227 continue;
1228 }
1229
1230 if (aor_name) {
1231 break;
1232 }
1233 }
1234
1235 if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
1236 /* The provided AOR name was not found (be it within the configuration or sorcery itself) */
1237 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
1238 ast_sip_report_req_no_support(endpoint, rdata, "registrar_requested_aor_not_found");
1239 ast_log(LOG_WARNING, "AOR '%s' not found for endpoint '%s' (%s:%d)\n",
1240 aor_name ?: "", ast_sorcery_object_get_id(endpoint),
1241 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1242 }
1243 ast_free(aor_name);
1244 return aor;
1245}
1246
1247static pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
1248{
1249 RAII_VAR(struct ast_sip_endpoint *, endpoint,
1251 struct ast_sip_aor *aor;
1252 const char *aor_name;
1253
1254 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
1255 return PJ_FALSE;
1256 }
1257
1258 if (ast_strlen_zero(endpoint->aors)) {
1259 /* Short circuit early if the endpoint has no AORs configured on it, which means no registration possible */
1260 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1261 ast_sip_report_failed_acl(endpoint, rdata, "registrar_attempt_without_configured_aors");
1262 ast_log(LOG_WARNING, "Endpoint '%s' (%s:%d) has no configured AORs\n", ast_sorcery_object_get_id(endpoint),
1263 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1264 return PJ_TRUE;
1265 }
1266
1267 if (!PJSIP_URI_SCHEME_IS_SIP(rdata->msg_info.to->uri) && !PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.to->uri)) {
1268 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 416, NULL, NULL, NULL);
1269 ast_sip_report_failed_acl(endpoint, rdata, "registrar_invalid_uri_in_to_received");
1270 ast_log(LOG_WARNING, "Endpoint '%s' (%s:%d) attempted to register to an AOR with a non-SIP URI\n", ast_sorcery_object_get_id(endpoint),
1271 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1272 return PJ_TRUE;
1273 }
1274
1275 aor = find_registrar_aor(rdata, endpoint);
1276 if (!aor) {
1277 /* We've already responded about not finding an AOR. */
1278 return PJ_TRUE;
1279 }
1280
1281 aor_name = ast_sorcery_object_get_id(aor);
1282
1283 if (!aor->max_contacts) {
1284 /* Registration is not permitted for this AOR */
1285 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1286 ast_sip_report_req_no_support(endpoint, rdata, "registrar_attempt_without_registration_permitted");
1287 ast_log(LOG_WARNING, "AOR '%s' has no configured max_contacts. Endpoint '%s' (%s:%d) unable to register\n",
1288 aor_name, ast_sorcery_object_get_id(endpoint),
1289 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1290 } else {
1291 register_aor(rdata, endpoint, aor, aor_name);
1292 }
1293 ao2_ref(aor, -1);
1294 return PJ_TRUE;
1295}
1296
1297/* function pointer to callback needs to be within the module
1298 in order to avoid problems with an undefined symbol */
1299static int sip_contact_to_str(void *acp, void *arg, int flags)
1300{
1301 return ast_sip_contact_to_str(acp, arg, flags);
1302}
1303
1304static int ami_registrations_aor(void *obj, void *arg, int flags)
1305{
1306 struct ast_sip_aor *aor = obj;
1307 struct ast_sip_ami *ami = arg;
1308 int *count = ami->arg;
1309 RAII_VAR(struct ast_str *, buf,
1310 ast_sip_create_ami_event("InboundRegistrationDetail", ami), ast_free);
1311
1312 if (!buf) {
1313 return -1;
1314 }
1315
1317 ast_str_append(&buf, 0, "Contacts: ");
1319 ast_str_append(&buf, 0, "\r\n");
1320
1321 astman_append(ami->s, "%s\r\n", ast_str_buffer(buf));
1322 (*count)++;
1323 return 0;
1324}
1325
1326static int ami_registrations_endpoint(void *obj, void *arg, int flags)
1327{
1328 struct ast_sip_endpoint *endpoint = obj;
1329 return ast_sip_for_each_aor(
1330 endpoint->aors, ami_registrations_aor, arg);
1331}
1332
1333static int ami_registrations_endpoints(void *arg)
1334{
1337
1338 if (!endpoints) {
1339 return 0;
1340 }
1341
1343 return 0;
1344}
1345
1346static int ami_show_registrations(struct mansession *s, const struct message *m)
1347{
1348 int count = 0;
1349 struct ast_sip_ami ami = { .s = s, .m = m, .arg = &count, .action_id = astman_get_header(m, "ActionID"), };
1350
1351 astman_send_listack(s, m, "Following are Events for each Inbound registration",
1352 "start");
1353
1355
1356 astman_send_list_complete_start(s, m, "InboundRegistrationDetailComplete", count);
1358 return 0;
1359}
1360
1362{
1363 int count = 0;
1364 struct ast_sip_ami ami = { .s = s, .m = m, .arg = NULL, .action_id = astman_get_header(m, "ActionID"), };
1367 struct ao2_iterator i;
1368 struct ast_sip_contact *contact;
1369
1370 astman_send_listack(s, m, "Following are ContactStatusEvents for each Inbound "
1371 "registration", "start");
1372
1373 if (contacts) {
1374 i = ao2_iterator_init(contacts, 0);
1375 while ((contact = ao2_iterator_next(&i))) {
1376 struct ast_sip_contact_wrapper wrapper;
1377
1378 wrapper.aor_id = (char *)contact->aor;
1379 wrapper.contact = contact;
1380 wrapper.contact_id = (char *)ast_sorcery_object_get_id(contact);
1381
1382 ast_sip_format_contact_ami(&wrapper, &ami, 0);
1383 count++;
1384
1385 ao2_ref(contact, -1);
1386 }
1388 ao2_ref(contacts, -1);
1389 }
1390
1391 astman_send_list_complete_start(s, m, "ContactStatusDetailComplete", count);
1393 return 0;
1394}
1395
1396#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES "PJSIPShowRegistrationInboundContactStatuses"
1397#define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"
1398
1399static pjsip_module registrar_module = {
1400 .name = { "Registrar", 9 },
1401 .id = -1,
1402 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
1403 .on_rx_request = registrar_on_rx_request,
1404};
1405
1406/*! \brief Thread keeping things alive */
1408
1409/*! \brief The global interval at which to check for contact expiration */
1410static unsigned int check_interval;
1411
1412/*! \brief Callback function which deletes a contact */
1413static int expire_contact(void *obj, void *arg, int flags)
1414{
1415 struct ast_sip_contact *contact = obj;
1416 struct ast_named_lock *lock;
1417
1419 if (!lock) {
1420 return 0;
1421 }
1422
1423 /*
1424 * We need to check the expiration again with the aor lock held
1425 * in case another thread is attempting to renew the contact.
1426 */
1427 ao2_lock(lock);
1428 if (ast_tvdiff_ms(ast_tvnow(), contact->expiration_time) > 0) {
1430 }
1433
1434 return 0;
1435}
1436
1437static void *check_expiration_thread(void *data)
1438{
1439 struct ao2_container *contacts;
1440 struct ast_variable *var;
1441 char time[AST_TIME_T_LEN];
1442
1443 while (check_interval) {
1444 sleep(check_interval);
1445
1446 ast_time_t_to_string(ast_tvnow().tv_sec, time, sizeof(time));
1447
1448 var = ast_variable_new("expiration_time <=", time, "");
1449
1450 ast_debug(4, "Woke up at %s Interval: %d\n", time, check_interval);
1451
1454
1456 if (contacts) {
1457 ast_debug(3, "Expiring %d contacts\n", ao2_container_count(contacts));
1459 ao2_ref(contacts, -1);
1460 }
1461 }
1462
1463 return NULL;
1464}
1465
1466static void expiration_global_loaded(const char *object_type)
1467{
1469
1470 /* Observer calls are serialized so this is safe without it's own lock */
1471 if (check_interval) {
1474 ast_log(LOG_ERROR, "Could not create thread for checking contact expiration.\n");
1475 return;
1476 }
1477 ast_debug(3, "Interval = %d, starting thread\n", check_interval);
1478 }
1479 } else {
1481 pthread_kill(check_thread, SIGURG);
1482 pthread_join(check_thread, NULL);
1484 ast_debug(3, "Interval = 0, shutting thread down\n");
1485 }
1486 }
1487}
1488
1489/*! \brief Observer which is used to update our interval when the global setting changes */
1492};
1493
1494static int load_module(void)
1495{
1496 const pj_str_t STR_REGISTER = { "REGISTER", 8 };
1497
1498 ast_pjproject_get_buildopt("PJ_MAX_HOSTNAME", "%d", &pj_max_hostname);
1499 /* As of pjproject 2.4.5, PJSIP_MAX_URL_SIZE isn't exposed yet but we try anyway. */
1500 ast_pjproject_get_buildopt("PJSIP_MAX_URL_SIZE", "%d", &pjsip_max_url_size);
1501
1504 }
1505
1506 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
1509 }
1510
1515
1518
1520}
1521
1522static int unload_module(void)
1523{
1525 check_interval = 0;
1526 pthread_kill(check_thread, SIGURG);
1527 pthread_join(check_thread, NULL);
1528
1530 }
1531
1533
1538 return 0;
1539}
1540
1541AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Registrar Support",
1542 .support_level = AST_MODULE_SUPPORT_CORE,
1543 .load = load_module,
1544 .unload = unload_module,
1545 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 3,
1546 .requires = "res_pjproject,res_pjsip",
jack_status_t status
Definition: app_jack.c:149
ast_mutex_t lock
Definition: app_sla.c:337
#define var
Definition: ast_expr2f.c:605
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define ast_free(a)
Definition: astmm.h:180
#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
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_link(container, obj)
Add an object to a container.
Definition: astobj2.h:1532
@ CMP_MATCH
Definition: astobj2.h:1027
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#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
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_unlink(container, obj)
Remove an object from a container.
Definition: astobj2.h:1578
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_unlock(a)
Definition: astobj2.h:729
#define ao2_lock(a)
Definition: astobj2.h:717
#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.
@ OBJ_NODATA
Definition: astobj2.h:1044
@ 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
static const char type[]
Definition: chan_ooh323.c:109
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
Definition: manager.c:2028
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
Definition: manager.c:2064
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
Definition: manager.c:1647
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
Definition: manager.c:2072
void astman_append(struct mansession *s, const char *fmt,...)
Definition: manager.c:1907
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
Definition: manager.c:7697
#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
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
#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.
#define VERBOSITY_ATLEAST(level)
#define LOG_ERROR
#define ast_verb(level,...)
#define LOG_WARNING
#define AST_PTHREADT_NULL
Definition: lock.h:70
static struct ao2_container * endpoints
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_SYSTEM
Definition: manager.h:75
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Definition: manager.h:192
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_CHANNEL_DEPEND
Definition: module.h:340
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ 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
Named Locks.
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_SYSTEM_NAME
Definition: options.c:170
struct ao2_container * container
Definition: res_fax.c:531
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
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
void ast_sip_unregister_service(pjsip_module *module)
Definition: res_pjsip.c:133
@ AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME
Definition: res_pjsip.h:701
@ AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME
Definition: res_pjsip.h:703
void ast_sip_report_req_no_support(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, const char *req_type)
Send a security event notification for when a request is not supported.
struct ao2_container * ast_sip_get_endpoints(void)
Retrieve any endpoints available to sorcery.
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
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
Definition: res_pjsip.c:117
struct ast_sip_aor * ast_sip_location_retrieve_aor(const char *aor_name)
Retrieve a named AOR.
Definition: location.c:147
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_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
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.
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.
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
Definition: res_pjsip.c:520
struct ast_sip_endpoint * ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata)
Get the looked-up endpoint on an out-of dialog request or response.
void ast_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
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_format_contact_ami(void *obj, void *arg, int flags)
Formats the contact and sends over AMI.
unsigned int ast_sip_get_contact_expiration_check_interval(void)
Retrieve the system contact expiration check interval setting.
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
unsigned int ast_sip_get_ignore_uri_user_options(void)
Retrieve the global setting 'ignore_uri_user_options'.
struct ast_sip_contact * ast_sip_location_retrieve_contact(const char *contact_name)
Retrieve a named contact.
Definition: location.c:350
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.
struct ast_sip_contact * ast_sip_location_create_contact(struct ast_sip_aor *aor, const char *uri, struct timeval expiration_time, const char *path_info, const char *user_agent, const char *via_addr, int via_port, const char *call_id, int prune_on_boot, struct ast_sip_endpoint *endpoint)
Create a new contact for an AOR without locking the AOR.
Definition: location.c:355
#define PJSIP_EXPIRES_NOT_SPECIFIED
Definition: res_pjsip.h:68
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
struct ast_sip_contact_status * ast_sip_get_contact_status(const struct ast_sip_contact *contact)
Retrieve the current status for a contact.
int ast_sip_location_update_contact(struct ast_sip_contact *contact)
Update a contact.
Definition: location.c:446
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
@ UNAVAILABLE
Definition: res_pjsip.h:436
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
int ast_sip_location_delete_contact(struct ast_sip_contact *contact)
Delete a contact.
Definition: location.c:451
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 ami_registrations_endpoint(void *obj, void *arg, int flags)
static int vec_contact_cmp(struct ast_sip_contact *left, struct ast_sip_contact *right)
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_validate_path(pjsip_rx_data *rdata, struct ast_sip_aor *aor, struct ast_str **path_str)
static int match_aor(const char *aor_name, const char *id)
static int registrar_add_unreachable(void *obj, void *arg, int flags)
Internal callback function which adds any contact which is unreachable.
static int build_path_data(pjsip_rx_data *rdata, struct ast_str **path_str)
static int ami_registrations_endpoints(void *arg)
static int register_contact_transport_remove_cb(void *data)
static void * check_expiration_thread(void *data)
static int sip_contact_to_str(void *acp, void *arg, int flags)
#define AMI_SHOW_REGISTRATION_CONTACT_STATUSES
static int pjsip_max_url_size
static pthread_t check_thread
Thread keeping things alive.
static int registrar_find_contact(void *obj, void *arg, int flags)
Callback function for finding a contact.
static int ami_show_registration_contact_statuses(struct mansession *s, const struct message *m)
static void expiration_global_loaded(const char *object_type)
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 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 pj_bool_t registrar_on_rx_request(struct pjsip_rx_data *rdata)
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 vec_contact_add(void *obj, void *arg, int flags)
static int expire_contact(void *obj, void *arg, int flags)
Callback function which deletes a contact.
static int ami_registrations_aor(void *obj, void *arg, int flags)
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)
contact_delete_type
@ CONTACT_DELETE_EXISTING
@ CONTACT_DELETE_ERROR
@ CONTACT_DELETE_SHUTDOWN
@ CONTACT_DELETE_REQUEST
@ CONTACT_DELETE_EXPIRE
@ CONTACT_DELETE_UNAVAILABLE
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 unsigned int check_interval
The global interval at which to check for contact expiration.
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 pjsip_module registrar_module
#define AMI_SHOW_REGISTRATIONS
static int registrar_add_non_permanent(void *obj, void *arg, int flags)
Callback function which adds non-permanent contacts to a container.
static int load_module(void)
static void register_contact_transport_shutdown_cb(void *data)
static int unload_module(void)
static int contact_transport_monitor_matcher(void *a, void *b)
static const pj_str_t path_hdr_name
static int ami_show_registrations(struct mansession *s, const struct message *m)
static int registrar_delete_contact(void *obj, void *arg, int flags)
Internal function used to delete a contact from an AOR.
static char * find_aor_name(const pj_str_t *pj_username, const pj_str_t *pj_domain, const char *aors)
#define NULL
Definition: resample.c:96
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
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
@ 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_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
Definition: sorcery.c:1853
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
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_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
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
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
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
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
#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
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
pjsip_tx_data * tdata
AMI variable container.
Definition: res_pjsip.h:3200
struct mansession * s
Definition: res_pjsip.h:3202
void * arg
Definition: res_pjsip.h:3208
const struct message * m
Definition: res_pjsip.h:3204
A SIP address of record.
Definition: res_pjsip.h:478
unsigned int minimum_expiration
Definition: res_pjsip.h:488
unsigned int max_contacts
Definition: res_pjsip.h:498
unsigned int maximum_expiration
Definition: res_pjsip.h:490
unsigned int default_expiration
Definition: res_pjsip.h:492
A contact's status.
Definition: res_pjsip.h:451
enum ast_sip_contact_status_type status
Definition: res_pjsip.h:468
const ast_string_field aor
Definition: res_pjsip.h:457
A wrapper for contact that adds the aor_id and a consistent contact id. Used by ast_sip_for_each_cont...
Definition: res_pjsip.h:519
struct ast_sip_contact * contact
Definition: res_pjsip.h:525
Contact associated with an address of record.
Definition: res_pjsip.h:390
const ast_string_field uri
Definition: res_pjsip.h:412
struct ast_sip_endpoint * endpoint
Definition: res_pjsip.h:422
const ast_string_field via_addr
Definition: res_pjsip.h:412
int qualify_2xx_only
Definition: res_pjsip.h:428
const ast_string_field call_id
Definition: res_pjsip.h:412
const ast_string_field aor
Definition: res_pjsip.h:412
struct timeval expiration_time
Definition: res_pjsip.h:414
const ast_string_field path
Definition: res_pjsip.h:412
int authenticate_qualify
Definition: res_pjsip.h:418
const ast_string_field reg_server
Definition: res_pjsip.h:412
const ast_string_field user_agent
Definition: res_pjsip.h:412
unsigned int qualify_frequency
Definition: res_pjsip.h:416
const ast_string_field domain
Definition: res_pjsip.h:321
An entity with which Asterisk communicates.
Definition: res_pjsip.h:1051
const ast_string_field aors
Definition: res_pjsip.h:1080
struct ast_sip_identify_by_vector ident_method_order
Definition: res_pjsip.h:1104
Interface for a sorcery object type observer.
Definition: sorcery.h:332
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
Definition: sorcery.h:343
Support for dynamic strings.
Definition: strings.h:623
Structure for variables, used for configurations and for channel variables.
char * contact_name
Sorcery contact name to remove on transport shutdown.
struct header * next
In case you didn't read that giant block of text above the mansession_session struct,...
Definition: manager.c:327
Structure used for finding contact.
pj_pool_t * pool
Pool used for parsing URI.
pjsip_sip_uri * uri
URI being looked for.
An API for managing task processing threads that can be shared across modules.
Test Framework API.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189
static struct test_val b
static struct test_val a
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
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
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:117
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
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2282
#define AST_TIME_T_LEN
Definition: time.h:45
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
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:159
#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
#define ast_assert(a)
Definition: utils.h:739
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:592
#define MAX(a, b)
Definition: utils.h:233
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
#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
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
#define AST_VECTOR(name, type)
Define a vector structure.
Definition: vector.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680