32 #include "asterisk/res_pjsip.h"
39 #include "asterisk/res_pjproject.h"
40 #include "res_pjsip/include/res_pjsip_private.h"
80 static int pj_max_hostname = PJ_MAX_HOSTNAME;
81 static int pjsip_max_url_size = PJSIP_MAX_URL_SIZE;
84 static unsigned int registrar_get_expiration(
const struct ast_sip_aor *aor,
const pjsip_contact_hdr *contact,
const pjsip_rx_data *rdata)
86 pjsip_expires_hdr *expires;
89 if (contact && contact->expires != PJSIP_EXPIRES_NOT_SPECIFIED) {
91 expiration = contact->expires;
92 }
else if ((expires = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL))) {
94 expiration = expires->ivalue;
103 if (expiration < aor->minimum_expiration) {
121 static int registrar_find_contact(
void *obj,
void *arg,
int flags)
125 pjsip_uri *contact_uri;
131 contact_uri = pjsip_parse_uri(details->
pool, (
char*)contact->
uri, strlen(contact->
uri), 0);
133 ast_log(LOG_WARNING,
"Unable to parse contact URI from '%s'.\n", contact->
uri);
137 return (pjsip_uri_cmp(PJSIP_URI_IN_CONTACT_HDR, details->
uri, contact_uri) == PJ_SUCCESS) ?
CMP_MATCH : 0;
141 static int registrar_validate_contacts(
const pjsip_rx_data *rdata, pj_pool_t *
pool,
struct ao2_container *contacts,
142 struct ast_sip_aor *aor,
int permanent,
int *added,
int *updated,
int *deleted)
144 pjsip_contact_hdr *previous = NULL;
145 pjsip_contact_hdr *contact = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
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);
153 char contact_uri[pjsip_max_url_size];
157 if (expiration != 0 || previous) {
164 }
else if (previous && previous->star) {
170 if (!PJSIP_URI_SCHEME_IS_SIP(contact->
uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact->
uri)) {
174 details.
uri = pjsip_uri_get_uri(contact->
uri);
177 if (pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.
uri, contact_uri,
sizeof(contact_uri)) < 0) {
182 if (details.
uri->host.slen >= pj_max_hostname) {
188 existing =
ao2_callback(contacts, 0, registrar_find_contact, &details);
189 ao2_cleanup(existing);
194 }
else if (expiration) {
204 enum contact_delete_type {
205 CONTACT_DELETE_ERROR,
206 CONTACT_DELETE_EXISTING,
207 CONTACT_DELETE_UNAVAILABLE,
208 CONTACT_DELETE_EXPIRE,
209 CONTACT_DELETE_REQUEST,
210 CONTACT_DELETE_SHUTDOWN,
213 static int registrar_contact_delete(
enum contact_delete_type type, pjsip_transport *transport,
217 static int registrar_delete_contact(
void *obj,
void *arg,
int flags)
219 return registrar_contact_delete(
220 CONTACT_DELETE_REQUEST, NULL, obj, arg) ? 0 :
CMP_MATCH;
224 static int registrar_add_contact(
void *obj,
void *arg,
int flags)
227 pjsip_tx_data *tdata = arg;
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);
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);
240 hdr->expires = PJSIP_EXPIRES_NOT_SPECIFIED;
242 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
244 ast_log(LOG_WARNING,
"Skipping invalid Contact URI \"%.*s\" for AOR %s\n",
245 (
int) uri.slen, uri.ptr, contact->
aor);
251 static const pj_str_t path_hdr_name = {
"Path", 4 };
253 static int build_path_data(pjsip_rx_data *rdata,
struct ast_str **path_str)
255 pjsip_generic_string_hdr *path_hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &path_hdr_name, NULL);
266 ast_str_set(path_str, 0,
"%.*s", (
int)path_hdr->hvalue.slen, path_hdr->hvalue.ptr);
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);
275 static int registrar_validate_path(pjsip_rx_data *rdata,
struct ast_sip_aor *aor,
struct ast_str **path_str)
277 const pj_str_t path_supported_name = {
"path", 4 };
278 pjsip_supported_hdr *supported_hdr;
285 if (build_path_data(rdata, path_str)) {
293 supported_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_SUPPORTED, NULL);
294 if (!supported_hdr) {
299 for (i = 0; i < supported_hdr->count; i++) {
300 if (!pj_stricmp(&supported_hdr->values[i], &path_supported_name)) {
322 static int contact_transport_monitor_matcher(
void *a,
void *b)
331 static int register_contact_transport_remove_cb(
void *data)
337 aor = ast_sip_location_retrieve_aor(monitor->
aor_name);
348 contact = ast_sip_location_retrieve_contact(monitor->
contact_name);
350 registrar_contact_delete(CONTACT_DELETE_SHUTDOWN, NULL, contact, monitor->
aor_name);
368 static void register_contact_transport_shutdown_cb(
void *data)
402 static int registrar_contact_delete(
enum contact_delete_type type, pjsip_transport *transport,
412 aor_size = aor_name ? strlen(aor_name) : 0;
413 if (contact->
prune_on_boot && type != CONTACT_DELETE_SHUTDOWN && aor_size) {
415 size_t contact_name_len = strlen(contact_name) + 1;
417 sizeof(*monitor) + 1 + aor_size + contact_name_len);
419 strcpy(monitor->
aor_name, aor_name);
425 register_contact_transport_shutdown_cb, monitor,
426 contact_transport_monitor_matcher);
433 monitor, contact_transport_monitor_matcher);
437 ast_sip_location_delete_contact(contact);
440 if (VERBOSITY_ATLEAST(3)) {
441 const char *reason =
"none";
444 case CONTACT_DELETE_ERROR:
445 reason =
"registration failure";
447 case CONTACT_DELETE_EXISTING:
448 reason =
"remove existing";
450 case CONTACT_DELETE_UNAVAILABLE:
451 reason =
"remove unavailable";
453 case CONTACT_DELETE_EXPIRE:
454 reason =
"expiration";
456 case CONTACT_DELETE_REQUEST:
459 case CONTACT_DELETE_SHUTDOWN:
464 ast_verb(3,
"Removed contact '%s' from AOR '%s' due to %s\n",
465 contact->
uri, aor_name, reason);
490 struct ast_sip_aor *aor = ast_sip_location_retrieve_aor(left_contact->
aor);
493 int remove_unavailable = 0;
494 int left_unreachable;
495 int right_unreachable;
502 if (!remove_unavailable) {
507 left_status = ast_sip_get_contact_status(left_contact);
512 right_status = ast_sip_get_contact_status(right_contact);
518 left_unreachable = (left_status->
status == UNAVAILABLE);
519 right_unreachable = (right_status->
status == UNAVAILABLE);
522 if (left_unreachable != right_unreachable) {
524 if (left_unreachable)
return -1;
525 if (right_unreachable)
return 1;
532 static int vec_contact_add(
void *obj,
void *arg,
int flags)
566 unsigned int to_remove,
unsigned int remove_existing)
591 while (to_remove--) {
596 if (!remove_existing) {
597 registrar_contact_delete(CONTACT_DELETE_UNAVAILABLE, NULL, contact, contact->
aor);
599 registrar_contact_delete(CONTACT_DELETE_EXISTING, NULL, contact, contact->
aor);
609 static int registrar_add_non_permanent(
void *obj,
void *arg,
int flags)
624 static int registrar_add_unreachable(
void *obj,
void *arg,
int flags)
631 status = ast_sip_get_contact_status(contact);
636 unreachable = (status->
status == UNAVAILABLE);
653 static void register_aor_core(pjsip_rx_data *rdata,
656 const char *aor_name,
660 static const pj_str_t USER_AGENT = {
"User-Agent", 10 };
669 pjsip_contact_hdr *contact_hdr = (pjsip_contact_hdr *)&rdata->msg_info.msg->hdr;
671 pjsip_tx_data *tdata;
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;
681 pjsip_cid_hdr *call_id_hdr;
686 details.
pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
687 "Contact Comparison", 1024, 256);
689 response->code = 500;
700 if (registrar_validate_contacts(rdata, details.
pool, contacts, aor, permanent, &added, &updated, &deleted)) {
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);
710 if (registrar_validate_path(rdata, aor, &path_str)) {
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);
721 contact_count = MAX(updated + added - deleted, 0);
728 if (!existing_contacts) {
729 response->code = 500;
730 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.
pool);
742 int unavail_count = 0;
746 if (!unavail_contacts) {
747 response->code = 500;
748 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.
pool);
752 if (unavail_contacts) {
757 if (contact_count - unavail_count <= aor->max_contacts) {
760 ao2_cleanup(unavail_contacts);
769 ast_log(LOG_WARNING,
"Registration attempt from endpoint '%s' (%s:%d) to AOR '%s' will exceed max contacts of %u\n",
772 response->code = 403;
773 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.
pool);
774 ao2_cleanup(existing_contacts);
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;
782 ast_copy_pj_str(user_agent, &user_agent_hdr->hvalue, alloc_size);
786 via_hdr = via_hdr_last = (pjsip_via_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_VIA, NULL);
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;
793 alloc_size = pj_strlen(&via_hdr_last->sent_by.host) + 1;
795 ast_copy_pj_str(via_addr, &via_hdr_last->sent_by.host, alloc_size);
796 via_port=via_hdr_last->sent_by.port;
799 call_id_hdr = (pjsip_cid_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CALL_ID, NULL);
801 alloc_size = pj_strlen(&call_id_hdr->id) + 1;
803 ast_copy_pj_str(call_id, &call_id_hdr->id, alloc_size);
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)) {
809 char contact_uri[pjsip_max_url_size];
812 if (contact_hdr->star) {
815 registrar_delete_contact, (
void *)aor_name);
819 if (existing_contacts) {
820 ao2_ref(existing_contacts, -1);
821 existing_contacts = NULL;
826 if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) {
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));
840 if (contact && existing_contacts) {
849 ast_verb(3,
"Attempted to remove non-existent contact '%s' from AOR '%s' by request\n",
850 contact_uri, aor_name);
854 prune_on_boot = !ast_sip_will_uri_survive_restart(details.
uri,
endpoint, rdata);
856 contact = ast_sip_location_create_contact(aor, contact_uri,
859 user_agent, via_addr, via_port, call_id, prune_on_boot,
endpoint);
861 ast_log(LOG_ERROR,
"Unable to bind contact '%s' to AOR '%s'\n",
862 contact_uri, aor_name);
867 size_t contact_name_len;
868 const char *contact_name;
876 contact_name_len = strlen(contact_name) + 1;
877 monitor = ao2_alloc(
sizeof(*monitor) + 1 + strlen(aor_name)
878 + contact_name_len, NULL);
880 strcpy(monitor->
aor_name, aor_name);
885 register_contact_transport_shutdown_cb, monitor, contact_transport_monitor_matcher);
890 ast_verb(3,
"Added contact '%s' to AOR '%s' with expiration of %d seconds\n",
891 contact_uri, aor_name, expiration);
903 }
else if (expiration) {
907 if (!contact_update) {
908 ast_log(LOG_ERROR,
"Failed to update contact '%s' expiration time to %d seconds.\n",
909 contact->
uri, expiration);
922 if (!ast_strlen_zero(ast_config_AST_SYSTEM_NAME)) {
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,
933 ast_debug(3,
"Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n",
934 contact_uri, aor_name, expiration);
945 ao2_cleanup(contact_update);
947 registrar_contact_delete(CONTACT_DELETE_REQUEST, rdata->tp_info.transport,
952 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.
pool);
968 remove_excess_contacts(existing_contacts, contacts, contact_count - aor->
max_contacts,
971 ao2_ref(existing_contacts, -1);
974 response_contact =
ao2_callback(contacts, 0, NULL, NULL);
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;
983 ao2_cleanup(response_contact);
986 ast_sip_add_date_header(tdata);
988 ao2_callback(contacts, 0, registrar_add_contact, tdata);
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);
995 response->tdata = tdata;
998 static int register_aor(pjsip_rx_data *rdata,
1001 const char *aor_name)
1009 contacts = ast_sip_location_retrieve_aor_contacts_nolock(aor);
1012 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1013 rdata, response.
code, NULL, NULL, NULL);
1017 register_aor_core(rdata, endpoint, aor, aor_name, contacts, &response);
1018 ao2_cleanup(contacts);
1022 if (response.
tdata) {
1023 ast_sip_send_stateful_response(rdata, response.
tdata, endpoint);
1025 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(),
1026 rdata, response.
code, NULL, NULL, NULL);
1031 static int match_aor(
const char *aor_name,
const char *
id)
1033 if (ast_strlen_zero(aor_name)) {
1037 if (!strcmp(aor_name,
id)) {
1038 ast_debug(3,
"Matched id '%s' to aor '%s'\n",
id, aor_name);
1045 static char *find_aor_name(
const pj_str_t *pj_username,
const pj_str_t *pj_domain,
const char *aors)
1047 char *configured_aors;
1051 char *username, *domain;
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);
1060 id_domain =
ast_alloca(strlen(username) + strlen(domain) + 2);
1061 sprintf(id_domain,
"%s@%s", username, domain);
1066 configured_aors = aors_buf;
1067 while ((aor_name =
ast_strip(strsep(&configured_aors,
",")))) {
1068 if (match_aor(aor_name, id_domain)) {
1076 char *id_domain_alias =
ast_alloca(strlen(username) + strlen(alias->
domain) + 2);
1078 sprintf(id_domain_alias,
"%s@%s", username, alias->
domain);
1081 configured_aors = strcpy(aors_buf, aors);
1082 while ((aor_name =
ast_strip(strsep(&configured_aors,
",")))) {
1083 if (match_aor(aor_name, id_domain_alias)) {
1089 if (ast_strlen_zero(username)) {
1095 configured_aors = strcpy(aors_buf, aors);
1096 while ((aor_name =
ast_strip(strsep(&configured_aors,
",")))) {
1097 if (match_aor(aor_name, username)) {
1108 char *aor_name = NULL;
1114 pjsip_authorization_hdr *
header = NULL;
1117 case AST_SIP_ENDPOINT_IDENTIFY_BY_USERNAME:
1118 uri = pjsip_uri_get_uri(rdata->msg_info.to->uri);
1120 pj_strassign(&username, &uri->user);
1128 if (ast_sip_get_ignore_uri_user_options()) {
1129 pj_ssize_t semi = pj_strcspn2(&username,
";");
1130 if (semi < pj_strlen(&username)) {
1131 username.slen = semi;
1135 aor_name = find_aor_name(&username, &uri->host, endpoint->
aors);
1137 ast_debug(3,
"Matched aor '%s' by To username\n", aor_name);
1140 case AST_SIP_ENDPOINT_IDENTIFY_BY_AUTH_USERNAME:
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);
1147 ast_debug(3,
"Matched aor '%s' by Authentication username\n", aor_name);
1162 if (ast_strlen_zero(aor_name) || !(aor = ast_sip_location_retrieve_aor(aor_name))) {
1164 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 404, NULL, NULL, NULL);
1166 ast_log(LOG_WARNING,
"AOR '%s' not found for endpoint '%s' (%s:%d)\n",
1168 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1174 static pj_bool_t registrar_on_rx_request(
struct pjsip_rx_data *rdata)
1177 ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup);
1179 const char *aor_name;
1181 if (pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_register_method) || !endpoint) {
1185 if (ast_strlen_zero(endpoint->
aors)) {
1187 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1190 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
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);
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);
1202 aor = find_registrar_aor(rdata, endpoint);
1212 pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 403, NULL, NULL, NULL);
1214 ast_log(LOG_WARNING,
"AOR '%s' has no configured max_contacts. Endpoint '%s' (%s:%d) unable to register\n",
1216 rdata->pkt_info.src_name, rdata->pkt_info.src_port);
1218 register_aor(rdata, endpoint, aor, aor_name);
1226 static int sip_contact_to_str(
void *acp,
void *arg,
int flags)
1228 return ast_sip_contact_to_str(acp, arg, flags);
1231 static int ami_registrations_aor(
void *obj,
void *arg,
int flags)
1237 ast_sip_create_ami_event(
"InboundRegistrationDetail", ami), ast_free);
1243 ast_sip_sorcery_object_to_ami(aor, &buf);
1245 ast_sip_for_each_contact(aor, sip_contact_to_str, &buf);
1253 static int ami_registrations_endpoint(
void *obj,
void *arg,
int flags)
1256 return ast_sip_for_each_aor(
1257 endpoint->
aors, ami_registrations_aor, arg);
1260 static int ami_registrations_endpoints(
void *arg)
1263 ast_sip_get_endpoints(), ao2_cleanup);
1273 static int ami_show_registrations(
struct mansession *s,
const struct message *m)
1281 ami_registrations_endpoints(&ami);
1288 static int ami_show_registration_contact_statuses(
struct mansession *
s,
const struct message *
m)
1298 "registration",
"start");
1302 while ((contact = ao2_iterator_next(&i))) {
1306 wrapper.contact = contact;
1309 ast_sip_format_contact_ami(&wrapper, &ami, 0);
1323 #define AMI_SHOW_REGISTRATION_CONTACT_STATUSES "PJSIPShowRegistrationInboundContactStatuses"
1324 #define AMI_SHOW_REGISTRATIONS "PJSIPShowRegistrationsInbound"
1326 static pjsip_module registrar_module = {
1327 .name = {
"Registrar", 9 },
1329 .priority = PJSIP_MOD_PRIORITY_APPLICATION,
1330 .on_rx_request = registrar_on_rx_request,
1334 static pthread_t check_thread = AST_PTHREADT_NULL;
1337 static unsigned int check_interval;
1340 static int expire_contact(
void *obj,
void *arg,
int flags)
1356 registrar_contact_delete(CONTACT_DELETE_EXPIRE, NULL, contact, contact->
aor);
1364 static void *check_expiration_thread(
void *data)
1368 char time[AST_TIME_T_LEN];
1370 while (check_interval) {
1371 sleep(check_interval);
1375 var = ast_variable_new(
"expiration_time <=", time,
"");
1377 ast_debug(4,
"Woke up at %s Interval: %d\n", time, check_interval);
1393 static void expiration_global_loaded(
const char *object_type)
1395 check_interval = ast_sip_get_contact_expiration_check_interval();
1398 if (check_interval) {
1399 if (check_thread == AST_PTHREADT_NULL) {
1400 if (ast_pthread_create_background(&check_thread, NULL, check_expiration_thread, NULL)) {
1401 ast_log(LOG_ERROR,
"Could not create thread for checking contact expiration.\n");
1404 ast_debug(3,
"Interval = %d, starting thread\n", check_interval);
1407 if (check_thread != AST_PTHREADT_NULL) {
1408 pthread_kill(check_thread, SIGURG);
1409 pthread_join(check_thread, NULL);
1410 check_thread = AST_PTHREADT_NULL;
1411 ast_debug(3,
"Interval = 0, shutting thread down\n");
1418 .
loaded = expiration_global_loaded,
1421 static int load_module(
void)
1423 const pj_str_t STR_REGISTER = {
"REGISTER", 8 };
1429 if (ast_sip_register_service(®istrar_module)) {
1433 if (pjsip_endpt_add_capability(ast_sip_get_pjsip_endpoint(), NULL, PJSIP_H_ALLOW, NULL, 1, &STR_REGISTER) != PJ_SUCCESS) {
1434 ast_sip_unregister_service(®istrar_module);
1439 ami_show_registrations);
1441 ami_show_registration_contact_statuses);
1449 static int unload_module(
void)
1451 if (check_thread != AST_PTHREADT_NULL) {
1453 pthread_kill(check_thread, SIGURG);
1454 pthread_join(check_thread, NULL);
1456 check_thread = AST_PTHREADT_NULL;
1463 ast_sip_unregister_service(®istrar_module);
1468 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP Registrar Support",
1469 .support_level = AST_MODULE_SUPPORT_CORE,
1470 .load = load_module,
1471 .unload = unload_module,
1473 .requires =
"res_pjproject,res_pjsip",
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
unsigned int remove_existing
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. Returns -1 on failure, zero otherwise.
unsigned int max_contacts
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
#define ao2_container_alloc_list(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a list container.
Structure for variables, used for configurations and for channel variables.
static pj_pool_t * pool
Global memory pool for configuration and timers.
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Perform no matching, return all objects.
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Return all matching objects.
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.
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
#define ast_strdup(str)
A wrapper for strdup()
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
unsigned int qualify_frequency
unsigned int remove_unavailable
struct ast_sip_identify_by_vector ident_method_order
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Asterisk file paths, configured in asterisk.conf.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
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 ...
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
struct ao2_container * container
int ast_pjproject_get_buildopt(char *option, char *format_string,...)
Retrieve a pjproject build option.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
An entity with which Asterisk communicates.
unsigned int support_path
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.
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.
#define ast_test_suite_event_notify(s, f,...)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
int ast_tvcmp(struct timeval _a, struct timeval _b)
Compress two struct timeval instances returning -1, 0, 1 if the first arg is smaller, equal or greater to the second.
Support for dynamic strings.
#define ao2_unlink(container, obj)
Remove an object from a container.
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
Interface for a sorcery object type observer.
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
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 struct stasis_rest_handlers endpoints
REST handler for /api-docs/endpoints.json.
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.
struct ao2_container * permanent_contacts
Module has failed to load, may be in an inconsistent state.
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.
An API for managing task processing threads that can be shared across modules.
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
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.
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
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.
const ast_string_field domain
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
void * ast_sorcery_copy(const struct ast_sorcery *sorcery, const void *object)
Create a copy of an object.
const ast_string_field aors
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
unsigned int minimum_expiration
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
unsigned int default_expiration
unsigned int maximum_expiration
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
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.
#define ast_named_lock_get(lock_type, keyspace, key)
Geta named lock handle.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
#define ast_named_lock_put(lock)
Put a named lock handle away.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
#define AST_VECTOR_MAX_SIZE(vec)
Get the maximum number of elements the vector can currently hold.
#define ao2_link(container, obj)
Add an object to a container.