31 #include "asterisk/res_pjsip.h"
32 #include "asterisk/res_pjsip_cli.h"
36 #include "asterisk/stasis_system.h"
38 #include "asterisk/threadpool.h"
39 #include "asterisk/statsd.h"
40 #include "res_pjsip/include/res_pjsip_private.h"
269 static int set_outbound_initial_authentication_credentials(pjsip_regc *regc,
276 #define REREGISTER_BUFFER_TIME 10
279 #define LINE_PARAMETER_SIZE 8
282 enum sip_outbound_registration_status {
284 SIP_REGISTRATION_UNREGISTERED = 0,
286 SIP_REGISTRATION_REGISTERED,
288 SIP_REGISTRATION_REJECTED_TEMPORARY,
290 SIP_REGISTRATION_REJECTED_PERMANENT,
292 SIP_REGISTRATION_STOPPING,
294 SIP_REGISTRATION_STOPPED,
306 static const char *sip_outbound_registration_status_str(
enum sip_outbound_registration_status
state)
310 str =
"Unregistered";
312 case SIP_REGISTRATION_STOPPING:
313 case SIP_REGISTRATION_STOPPED:
314 case SIP_REGISTRATION_UNREGISTERED:
316 case SIP_REGISTRATION_REGISTERED:
319 case SIP_REGISTRATION_REJECTED_TEMPORARY:
320 case SIP_REGISTRATION_REJECTED_PERMANENT:
381 enum sip_outbound_registration_status
status;
400 char line[LINE_PARAMETER_SIZE];
454 #define MAX_UNLOAD_TIMEOUT_TIME 35
460 #define DEFAULT_STATE_BUCKETS 53
467 static int registration_state_hash(
const void *obj,
const int flags)
488 static int registration_state_cmp(
void *obj,
void *arg,
int flags)
492 const char *right_key = arg;
532 ast_sip_get_sorcery(),
"registration",
535 return registrations;
539 static int line_identify_relationship(
void *obj,
void *arg,
int flags)
542 pjsip_param *line = arg;
547 static struct pjsip_param *get_uri_option_line(
const void *uri)
549 static const pj_str_t LINE_STR = {
"line", 4 };
551 return ast_sip_pjsip_uri_get_other_param((pjsip_uri *)uri, &LINE_STR);
561 if (!(line = get_uri_option_line(rdata->msg_info.to->uri))
562 && !(line = get_uri_option_line(rdata->msg_info.msg->line.req.uri))) {
571 state =
ao2_callback(states, 0, line_identify_relationship, line);
576 ast_debug(3,
"Determined relationship to outbound registration '%s' based on line '%s', using configured endpoint '%s'\n",
589 if (pj_timer_heap_cancel_if_active(pjsip_endpt_get_timer_heap(ast_sip_get_pjsip_endpoint()),
590 &client_state->
timer, client_state->
timer.id)) {
596 static pj_str_t PATH_NAME = {
"path", 4 };
597 static pj_str_t OUTBOUND_NAME = {
"outbound", 8 };
611 static int contact_has_security_mechanisms(
void *obj,
void *arg,
int flags)
617 if (!contact_status) {
621 ao2_cleanup(contact_status);
624 *ret = contact_status;
628 static int contact_add_security_headers_to_status(
void *obj,
void *arg,
int flags)
634 if (!contact_status) {
641 ao2_lock(contact_status);
643 ao2_unlock(contact_status);
646 ao2_cleanup(contact_status);
652 pjsip_tx_data *tdata)
654 int add_sec_client_header = 0;
660 static const pj_str_t security_verify = {
"Security-Verify", 15 };
661 static const pj_str_t security_client = {
"Security-Client", 15 };
670 && (contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->
aors))) {
674 ao2_callback(contact_container, 0, contact_has_security_mechanisms, &contact_status);
675 if (contact_status) {
676 ao2_lock(contact_status);
679 ao2_cleanup(contact_container);
685 if (client_state->
status == SIP_REGISTRATION_REJECTED_TEMPORARY || client_state->
auth_attempted) {
686 if (sec_mechs != NULL && pjsip_msg_find_hdr_by_name(tdata->msg, &security_verify, NULL) == NULL) {
693 add_sec_client_header = (pjsip_msg_find_hdr_by_name(tdata->msg, &security_client, NULL) == NULL) ? 1 : 0;
699 if (add_sec_client_header) {
704 if (contact_status) {
705 ao2_unlock(contact_status);
706 ao2_cleanup(contact_status);
714 pjsip_tx_data *tdata)
717 int *callback_invoked;
718 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
721 if (!callback_invoked) {
722 pjsip_tx_data_dec_ref(tdata);
725 *callback_invoked = 0;
734 pjsip_tx_data_add_ref(tdata);
737 add_security_headers(client_state, tdata);
742 if (!ast_strlen_zero(client_state->
user_agent)) {
743 static const pj_str_t user_agent_str = {
"User-Agent", 10 };
744 pjsip_generic_string_hdr *default_user_agent_hdr;
745 pjsip_generic_string_hdr *user_agent_hdr;
746 pj_str_t user_agent_val;
747 default_user_agent_hdr = pjsip_msg_find_hdr_by_name(tdata->msg, &user_agent_str, NULL);
748 user_agent_val = pj_str(client_state->
user_agent);
749 user_agent_hdr = pjsip_generic_string_hdr_create(tdata->pool, &user_agent_str, &user_agent_val);
750 if (!user_agent_hdr) {
751 ast_log(LOG_ERROR,
"Could not add custom User-Agent to outbound registration %s, sending REGISTER request with non-custom header\n", client_state->
registration_name);
753 if (default_user_agent_hdr) {
754 pj_list_erase(default_user_agent_hdr);
756 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)user_agent_hdr);
765 ast_sip_set_tpselector_from_transport_name(client_state->
transport_name, &selector);
766 pjsip_regc_set_transport(client_state->
client, &selector);
767 ast_sip_tpselector_unref(&selector);
769 status = pjsip_regc_send(client_state->
client, tdata);
775 if ((status != PJ_SUCCESS) && !(*callback_invoked)) {
776 pjsip_tx_data_dec_ref(tdata);
787 pjsip_tx_data_dec_ref(client_state->
last_tdata);
795 static int add_to_supported_header(pjsip_tx_data *tdata, pj_str_t *name)
797 pjsip_supported_hdr *hdr;
800 hdr = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_SUPPORTED, NULL);
803 hdr = pjsip_supported_hdr_create(tdata->pool);
805 pjsip_tx_data_dec_ref(tdata);
809 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *)hdr);
813 for (i = 0; i < hdr->count; ++i) {
814 if (pj_stricmp(&hdr->values[i], name) == 0) {
819 if (hdr->count >= PJSIP_GENERIC_ARRAY_MAX_COUNT) {
824 pj_strassign(&hdr->values[hdr->count++], name);
833 if (!add_to_supported_header(tdata, &PATH_NAME)) {
839 if (!add_to_supported_header(tdata, &OUTBOUND_NAME)) {
848 static int handle_client_registration(
void *data)
851 pjsip_tx_data *tdata;
853 if (set_outbound_initial_authentication_credentials(client_state->
client, &client_state->
outbound_auths)) {
854 ast_log(LOG_WARNING,
"Failed to set initial authentication credentials\n");
857 if (client_state->
status == SIP_REGISTRATION_STOPPED
858 || pjsip_regc_register(client_state->
client, PJ_FALSE, &tdata) != PJ_SUCCESS) {
862 if (DEBUG_ATLEAST(1)) {
863 pjsip_regc_info info;
865 pjsip_regc_get_info(client_state->
client, &info);
866 ast_log(LOG_DEBUG,
"Outbound REGISTER attempt %u to '%.*s' with client '%.*s'\n",
868 (
int) info.server_uri.slen, info.server_uri.ptr,
869 (
int) info.client_uri.slen, info.client_uri.ptr);
872 if (!add_configured_supported_headers(client_state, tdata)) {
873 ast_log(LOG_WARNING,
"Failed to set supported headers\n");
877 registration_client_send(client_state, tdata);
883 static void sip_outbound_registration_timer_cb(pj_timer_heap_t *
timer_heap,
struct pj_timer_entry *
entry)
895 ast_log(LOG_WARNING,
"Scheduled outbound registration could not be executed.\n");
903 pj_time_val delay = { .sec = seconds, };
904 pjsip_regc_info info;
906 cancel_registration(client_state);
908 pjsip_regc_get_info(client_state->
client, &info);
909 ast_debug(1,
"Scheduling outbound registration to server '%.*s' from client '%.*s' in %d seconds\n",
910 (
int) info.server_uri.slen, info.server_uri.ptr,
911 (
int) info.client_uri.slen, info.client_uri.ptr,
915 if (pjsip_endpt_schedule_timer(ast_sip_get_pjsip_endpoint(), &client_state->
timer, &delay) != PJ_SUCCESS) {
916 ast_log(LOG_WARNING,
"Failed to schedule registration to server '%.*s' from client '%.*s'\n",
917 (
int) info.server_uri.slen, info.server_uri.ptr,
918 (
int) info.client_uri.slen, info.client_uri.ptr);
926 const char *status_old;
927 const char *status_new;
929 if (client_state->
status == status) {
934 status_old = sip_outbound_registration_status_str(client_state->
status);
935 status_new = sip_outbound_registration_status_str(status);
938 if (!strcmp(status_old, status_new)) {
946 ast_statsd_log_string_va(
"PJSIP.registrations.state.%s", AST_STATSD_GAUGE,
"-1", 1.0,
948 ast_statsd_log_string_va(
"PJSIP.registrations.state.%s", AST_STATSD_GAUGE,
"+1", 1.0,
953 static int handle_client_state_destruction(
void *data)
957 cancel_registration(client_state);
959 if (client_state->
client) {
960 pjsip_regc_info info;
961 pjsip_tx_data *tdata;
963 pjsip_regc_get_info(client_state->
client, &info);
965 if (info.is_busy == PJ_TRUE) {
968 "Registration transaction is busy with server '%.*s' from client '%.*s'.\n",
969 (
int) info.server_uri.slen, info.server_uri.ptr,
970 (
int) info.client_uri.slen, info.client_uri.ptr);
976 switch (client_state->
status) {
977 case SIP_REGISTRATION_UNREGISTERED:
979 case SIP_REGISTRATION_REGISTERED:
981 "Trying to unregister with server '%.*s' from client '%.*s' before destruction.\n",
982 (
int) info.server_uri.slen, info.server_uri.ptr,
983 (
int) info.client_uri.slen, info.client_uri.ptr);
985 update_client_state_status(client_state, SIP_REGISTRATION_STOPPING);
987 if (pjsip_regc_unregister(client_state->
client, &tdata) == PJ_SUCCESS
988 && add_configured_supported_headers(client_state, tdata)
989 && registration_client_send(client_state, tdata) == PJ_SUCCESS) {
994 case SIP_REGISTRATION_REJECTED_TEMPORARY:
995 case SIP_REGISTRATION_REJECTED_PERMANENT:
996 case SIP_REGISTRATION_STOPPING:
997 case SIP_REGISTRATION_STOPPED:
1001 pjsip_regc_destroy(client_state->
client);
1002 client_state->
client = NULL;
1005 update_client_state_status(client_state, SIP_REGISTRATION_STOPPED);
1033 static void registration_response_destroy(
void *obj)
1037 if (response->
rdata) {
1038 pjsip_rx_data_free_cloned(response->
rdata);
1049 static int sip_outbound_registration_is_temporal(
unsigned int code,
1053 if (code == PJSIP_SC_REQUEST_TIMEOUT ||
1054 code == PJSIP_SC_INTERNAL_SERVER_ERROR ||
1055 code == PJSIP_SC_BAD_GATEWAY ||
1056 code == PJSIP_SC_SERVICE_UNAVAILABLE ||
1057 code == PJSIP_SC_SERVER_TIMEOUT ||
1058 ((code == PJSIP_SC_UNAUTHORIZED ||
1059 code == PJSIP_SC_PROXY_AUTHENTICATION_REQUIRED) &&
1061 PJSIP_IS_STATUS_IN_CLASS(code, 600)) {
1069 const char *server_uri,
const char *client_uri)
1071 update_client_state_status(response->
client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
1072 schedule_registration(response->
client_state, interval);
1074 if (response->
rdata) {
1075 ast_log(LOG_WARNING,
"Temporal response '%d' received from '%s' on "
1076 "registration attempt to '%s', retrying in '%u'\n",
1077 response->
code, server_uri, client_uri, interval);
1079 ast_log(LOG_WARNING,
"No response received from '%s' on "
1080 "registration attempt to '%s', retrying in '%u'\n",
1081 server_uri, client_uri, interval);
1085 static int reregister_immediately_cb(
void *obj)
1094 if (DEBUG_ATLEAST(1)) {
1095 pjsip_regc_info info;
1099 "Outbound registration transport to server '%.*s' from client '%.*s' shutdown\n",
1100 (
int) info.server_uri.slen, info.server_uri.ptr,
1101 (
int) info.client_uri.slen, info.client_uri.ptr);
1122 static void registration_transport_shutdown_cb(
void *obj)
1124 const char *registration_name = obj;
1127 state = get_state(registration_name);
1137 static int monitor_matcher(
void *a,
void *b)
1142 return strcmp(ma, mb) == 0;
1145 static void registration_transport_monitor_setup(
const char *transport_key,
const char *registration_name)
1149 monitor = ao2_alloc_options(strlen(registration_name) + 1, NULL,
1154 strcpy(monitor, registration_name);
1162 monitor, monitor_matcher);
1168 static const pj_str_t associated_uri_str = {
"P-Associated-URI", 16 };
1169 static const pj_str_t service_route_str = {
"Service-Route", 13 };
1170 pjsip_hdr *
header = NULL;
1171 pjsip_msg *msg = response->
rdata->msg_info.msg;
1181 while ((header = pjsip_msg_find_hdr_by_name(msg, &service_route_str, header ? header->next : NULL))) {
1182 char *service_route;
1189 size = pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1;
1191 if (!service_route) {
1192 if (service_routes) {
1193 ast_sip_service_route_vector_destroy(service_routes);
1194 service_routes = NULL;
1199 ast_copy_pj_str(service_route, &((pjsip_generic_string_hdr*)header)->hvalue, size);
1201 if (!service_routes) {
1202 service_routes = ast_sip_service_route_vector_alloc();
1203 if (!service_routes) {
1204 ast_free(service_route);
1210 ast_free(service_route);
1211 ast_sip_service_route_vector_destroy(service_routes);
1212 service_routes = NULL;
1218 if (service_routes) {
1225 header = pjsip_msg_find_hdr_by_name(msg, &associated_uri_str, NULL);
1227 char value[pj_strlen(&((pjsip_generic_string_hdr*)header)->hvalue) + 1];
1229 ast_copy_pj_str(value, &((pjsip_generic_string_hdr*)header)->hvalue,
sizeof(value));
1236 static int handle_registration_response(
void *data)
1239 pjsip_regc_info info;
1240 char server_uri[PJSIP_MAX_URL_SIZE];
1241 char client_uri[PJSIP_MAX_URL_SIZE];
1249 ast_copy_pj_str(server_uri, &info.server_uri,
sizeof(server_uri));
1250 ast_copy_pj_str(client_uri, &info.client_uri,
sizeof(client_uri));
1253 ast_debug(1,
"Processing REGISTER response %d from server '%s' for client '%s'\n",
1254 response->
code, server_uri, client_uri);
1256 if (response->
code == 408 || response->
code == 503) {
1257 if ((ast_sip_failover_request(response->
old_request))) {
1261 if (res == PJ_SUCCESS) {
1266 }
else if ((response->
code == 401 || response->
code == 407 || response->
code == 494)
1270 pjsip_cseq_hdr *cseq_hdr;
1271 pjsip_tx_data *tdata;
1277 pjsip_generic_string_hdr *header;
1279 static const pj_str_t security_server = {
"Security-Server", 15 };
1285 contact_container = ast_sip_location_retrieve_contacts_from_aor_list(endpt->
aors);
1289 header = pjsip_msg_find_hdr_by_name(response->
rdata->msg_info.msg, &security_server, NULL);
1291 header = pjsip_msg_find_hdr_by_name(response->
rdata->msg_info.msg, &security_server, header->next)) {
1295 if (contact_container) {
1300 ao2_cleanup(contact_container);
1307 if (response->
code == 494) {
1308 update_client_state_status(response->
client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
1316 ast_debug(1,
"Sending authenticated REGISTER to server '%s' from client '%s'\n",
1317 server_uri, client_uri);
1318 pjsip_tx_data_add_ref(tdata);
1320 res = registration_client_send(response->
client_state, tdata);
1323 cseq_hdr = (pjsip_cseq_hdr *) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ,
1326 pjsip_tx_data_dec_ref(tdata);
1327 if (res == PJ_SUCCESS) {
1332 ast_log(LOG_WARNING,
"Failed to create authenticated REGISTER request to server '%s' from client '%s'\n",
1333 server_uri, client_uri);
1340 if (PJSIP_IS_STATUS_IN_CLASS(response->
code, 200)) {
1343 int next_registration_round;
1346 ast_debug(1,
"Outbound registration to '%s' with client '%s' successful\n", server_uri, client_uri);
1347 update_client_state_status(response->
client_state, SIP_REGISTRATION_REGISTERED);
1349 next_registration_round = response->
expiration - REREGISTER_BUFFER_TIME;
1350 if (next_registration_round < 0) {
1352 next_registration_round = 0;
1354 schedule_registration(response->
client_state, next_registration_round);
1357 if (PJSIP_TRANSPORT_IS_RELIABLE(response->
rdata->tp_info.transport)) {
1358 registration_transport_monitor_setup(response->
transport_key,
1362 ast_debug(1,
"Outbound unregistration to '%s' with client '%s' successful\n", server_uri, client_uri);
1363 update_client_state_status(response->
client_state, SIP_REGISTRATION_UNREGISTERED);
1364 if (PJSIP_TRANSPORT_IS_RELIABLE(response->
rdata->tp_info.transport)) {
1371 save_response_fields_to_transport(response);
1376 schedule_retry(response, response->
retry_after, server_uri, client_uri);
1378 && sip_outbound_registration_is_temporal(response->
code, response->
client_state)) {
1381 update_client_state_status(response->
client_state, SIP_REGISTRATION_REJECTED_PERMANENT);
1382 ast_log(LOG_WARNING,
"Maximum retries reached when attempting outbound registration to '%s' with client '%s', stopping registration attempt\n",
1383 server_uri, client_uri);
1390 if (response->
code == 403
1394 update_client_state_status(response->
client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
1397 ast_log(LOG_WARNING,
"403 Forbidden fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1402 update_client_state_status(response->
client_state, SIP_REGISTRATION_REJECTED_TEMPORARY);
1405 ast_log(LOG_WARNING,
"'%d' fatal response received from '%s' on registration attempt to '%s', retrying in '%u' seconds\n",
1409 update_client_state_status(response->
client_state, SIP_REGISTRATION_REJECTED_PERMANENT);
1410 if (response->
rdata) {
1411 ast_log(LOG_WARNING,
"Fatal response '%d' received from '%s' on registration attempt to '%s', stopping outbound registration\n",
1412 response->
code, server_uri, client_uri);
1414 ast_log(LOG_WARNING,
"Fatal registration attempt to '%s', stopping outbound registration\n", client_uri);
1425 handle_client_state_destruction(response->
client_state);
1433 static void sip_outbound_registration_response_cb(
struct pjsip_regc_cbparam *param)
1437 int *callback_invoked;
1441 ast_assert(callback_invoked != NULL);
1442 ast_assert(client_state != NULL);
1444 *callback_invoked = 1;
1446 response = ao2_alloc(
sizeof(*response), registration_response_destroy);
1451 response->
code = param->code;
1460 ast_debug(1,
"Received REGISTER response %d(%.*s)\n",
1461 param->code, (
int) param->reason.slen, param->reason.ptr);
1464 struct pjsip_retry_after_hdr *retry_after;
1465 pjsip_transaction *tsx;
1467 retry_after = pjsip_msg_find_hdr(param->rdata->msg_info.msg, PJSIP_H_RETRY_AFTER,
1469 response->
retry_after = retry_after ? retry_after->ivalue : 0;
1478 pjsip_tx_data_dec_ref(client_state->
last_tdata);
1480 tsx = pjsip_rdata_get_tsx(param->rdata);
1483 pjsip_rx_data_clone(param->rdata, 0, &response->
rdata);
1484 AST_SIP_MAKE_REMOTE_IPADDR_PORT_STR(param->rdata->tp_info.transport,
1499 ast_log(LOG_WARNING,
"Failed to pass incoming registration response to threadpool\n");
1500 ao2_cleanup(response);
1505 static void sip_outbound_registration_state_destroy(
void *obj)
1509 ast_debug(3,
"Destroying registration state for registration to server '%s' from client '%s'\n",
1519 handle_client_state_destruction, state->
client_state)) {
1520 ast_log(LOG_WARNING,
"Failed to pass outbound registration client destruction to threadpool\n");
1526 static void sip_outbound_registration_client_state_destroy(
void *obj)
1530 ast_statsd_log_string(
"PJSIP.registrations.count", AST_STATSD_GAUGE,
"-1", 1.0);
1531 ast_statsd_log_string_va(
"PJSIP.registrations.state.%s", AST_STATSD_GAUGE,
"-1", 1.0,
1532 sip_outbound_registration_status_str(client_state->
status));
1539 pjsip_tx_data_dec_ref(client_state->
last_tdata);
1549 state = ao2_alloc(
sizeof(*state), sip_outbound_registration_state_destroy);
1554 sip_outbound_registration_client_state_destroy);
1562 sip_outbound_registration_timer_cb);
1568 ast_statsd_log_string(
"PJSIP.registrations.count", AST_STATSD_GAUGE,
"+1", 1.0);
1569 ast_statsd_log_string_va(
"PJSIP.registrations.state.%s", AST_STATSD_GAUGE,
"+1", 1.0,
1594 static void sip_outbound_registration_destroy(
void *obj)
1605 static void *sip_outbound_registration_alloc(
const char *name)
1610 sip_outbound_registration_destroy);
1612 ao2_cleanup(registration);
1616 return registration;
1620 static int sip_dialog_create_contact(pj_pool_t *
pool, pj_str_t *contact,
const char *
user,
1621 const pj_str_t *target, pjsip_tpselector *selector,
const char *line,
const char *header_params)
1623 pj_str_t tmp, local_addr;
1625 pjsip_sip_uri *sip_uri;
1626 pjsip_transport_type_e type;
1629 pj_strdup_with_null(pool, &tmp, target);
1631 if (!(uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0)) ||
1632 (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
1636 sip_uri = pjsip_uri_get_uri(uri);
1638 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
1639 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
1640 if (type == PJSIP_TRANSPORT_UNSPECIFIED
1641 || !(pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE)) {
1642 type = PJSIP_TRANSPORT_TLS;
1644 }
else if (!sip_uri->transport_param.slen) {
1645 type = PJSIP_TRANSPORT_UDP;
1646 }
else if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
1650 if (pj_strchr(&sip_uri->host,
':')) {
1651 type |= PJSIP_TRANSPORT_IPV6;
1654 if (pjsip_tpmgr_find_local_addr(pjsip_endpt_get_tpmgr(ast_sip_get_pjsip_endpoint()),
1655 pool, type, selector, &local_addr, &local_port) != PJ_SUCCESS) {
1659 if (!pj_strchr(&sip_uri->host,
':') && pj_strchr(&local_addr,
':')) {
1660 type |= PJSIP_TRANSPORT_IPV6;
1663 contact->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
1664 contact->slen = pj_ansi_snprintf(contact->ptr, PJSIP_MAX_URL_SIZE,
1665 "<%s:%s@%s%.*s%s:%d%s%s%s%s>%s%s",
1666 ((pjsip_transport_get_flag_from_type(type) & PJSIP_TRANSPORT_SECURE) && PJSIP_URI_SCHEME_IS_SIPS(uri)) ?
"sips" :
"sip",
1668 (type & PJSIP_TRANSPORT_IPV6) ?
"[" :
"",
1669 (
int)local_addr.slen,
1671 (type & PJSIP_TRANSPORT_IPV6) ?
"]" :
"",
1673 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ?
";transport=" :
"",
1674 (type != PJSIP_TRANSPORT_UDP && type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(type) :
"",
1675 !ast_strlen_zero(line) ?
";line=" :
"",
1677 !ast_strlen_zero(header_params) ?
";" :
"",
1678 S_OR(header_params,
""));
1697 struct ast_sorcery *sorcery = ast_sip_get_sorcery();
1717 static const char *fetch_google_access_token(
const struct ast_sip_auth *auth)
1721 const char *url =
"https://www.googleapis.com/oauth2/v3/token";
1729 ast_log(LOG_ERROR,
"CURL is unavailable. This is required for Google OAuth 2.0 authentication. Please ensure it is loaded.\n");
1734 "CURL(%s,client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token)",
1740 ast_debug(2,
"Performing Google OAuth 2.0 authentication using command: %s\n", cmd);
1746 ast_log(LOG_ERROR,
"Could not retrieve Google OAuth 2.0 authentication\n");
1750 ast_debug(2,
"Google OAuth 2.0 authentication returned: %s\n", buf);
1754 ast_log(LOG_ERROR,
"Could not parse Google OAuth 2.0 authentication: %d(%d) %s: '%s'\n",
1755 error.line, error.column, error.text, buf);
1761 ast_log(LOG_ERROR,
"Could not find Google OAuth 2.0 access_token in: '%s'\n",
1777 static int set_outbound_initial_authentication_credentials(pjsip_regc *regc,
1782 const char *access_token;
1783 pjsip_cred_info auth_creds[1];
1784 pjsip_auth_clt_pref prefs;
1788 memset(auths, 0,
sizeof(auths));
1789 if (ast_sip_retrieve_auths(auth_vector, auths)) {
1794 for (idx = 0; idx < auth_size; ++idx) {
1795 switch (auths[idx]->type) {
1796 case AST_SIP_AUTH_TYPE_GOOGLE_OAUTH:
1797 pj_cstr(&auth_creds[0].username, auths[idx]->
auth_user);
1798 pj_cstr(&auth_creds[0].scheme,
"Bearer");
1799 pj_cstr(&auth_creds[0].
realm, auths[idx]->realm);
1800 ast_debug(2,
"Obtaining Google OAuth access token\n");
1801 access_token = fetch_google_access_token(auths[idx]);
1802 if (!access_token) {
1803 ast_log(LOG_WARNING,
"Obtaining Google OAuth access token failed\n");
1807 ast_debug(2,
"Setting data to '%s'\n", access_token);
1809 pj_cstr(&auth_creds[0].data, access_token);
1810 auth_creds[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
1812 pjsip_regc_set_credentials(regc, 1, auth_creds);
1815 prefs.initial_auth = PJ_TRUE;
1816 pj_cstr(&prefs.algorithm,
"oauth");
1817 pjsip_regc_set_prefs(regc, &prefs);
1819 if (access_token != auths[idx]->
auth_pass) {
1820 ast_free((
char *) access_token);
1830 ast_sip_cleanup_auths(auths, auth_size);
1835 static int sip_outbound_registration_regc_alloc(
void *data)
1843 pj_str_t server_uri, client_uri, contact_uri;
1844 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
1846 pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(),
"URI Validation", 256, 256);
1848 ast_log(LOG_ERROR,
"Could not create pool for URI validation on outbound registration '%s'\n",
1853 pj_strdup2_with_null(pool, &tmp, registration->
server_uri);
1854 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1856 ast_log(LOG_ERROR,
"Invalid server URI '%s' specified on outbound registration '%s'\n",
1858 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1862 pj_strdup2_with_null(pool, &tmp, registration->
client_uri);
1863 uri = pjsip_parse_uri(pool, tmp.ptr, tmp.slen, 0);
1865 ast_log(LOG_ERROR,
"Invalid client URI '%s' specified on outbound registration '%s'\n",
1867 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1871 pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), pool);
1874 if (pjsip_regc_create(ast_sip_get_pjsip_endpoint(), state->
client_state,
1875 sip_outbound_registration_response_cb,
1880 ast_sip_set_tpselector_from_transport_name(registration->
transport, &selector);
1884 pjsip_route_hdr route_set, *route;
1885 static const pj_str_t ROUTE_HNAME = {
"Route", 5 };
1888 pj_list_init(&route_set);
1893 &ROUTE_HNAME, tmp.ptr, tmp.slen, NULL);
1895 ast_sip_tpselector_unref(&selector);
1898 pj_list_insert_nodes_before(&route_set, route);
1907 pj_cstr(&server_uri, registration->
server_uri);
1910 &contact_uri,
S_OR(registration->
contact_user,
"s"), &server_uri, &selector,
1912 ast_sip_tpselector_unref(&selector);
1916 ast_sip_tpselector_unref(&selector);
1918 pj_cstr(&client_uri, registration->
client_uri);
1920 &client_uri, 1, &contact_uri, registration->
expiration) != PJ_SUCCESS) {
1928 static int sip_outbound_registration_perform(
void *data)
1964 schedule_registration(state->
client_state, (max_delay ? ast_random() % max_delay : 0) + 1);
1972 static int sip_outbound_registration_apply(
const struct ast_sorcery *sorcery,
void *obj)
1988 ast_log(LOG_ERROR,
"No server URI specified on outbound registration '%s'\n",
1991 }
else if (ast_sip_validate_uri_length(applied->
server_uri)) {
1992 ast_log(LOG_ERROR,
"Server URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
1995 }
else if (ast_strlen_zero(applied->
client_uri)) {
1996 ast_log(LOG_ERROR,
"No client URI specified on outbound registration '%s'\n",
1999 }
else if (ast_sip_validate_uri_length(applied->
client_uri)) {
2000 ast_log(LOG_ERROR,
"Client URI or hostname length exceeds pjproject limit or is not a sip(s) uri: '%s'\n",
2003 }
else if (applied->
line && ast_strlen_zero(applied->
endpoint)) {
2004 ast_log(LOG_ERROR,
"Line support has been enabled on outbound registration '%s' without providing an endpoint\n",
2007 }
else if (!ast_strlen_zero(applied->
endpoint) && !applied->
line) {
2008 ast_log(LOG_ERROR,
"An endpoint has been specified on outbound registration '%s' without enabling line support\n",
2013 if (state && can_reuse_registration(state->
registration, applied)) {
2015 "No change between old configuration and new configuration on outbound registration '%s'. Using previous state\n",
2029 if (!(new_state = sip_outbound_registration_state_alloc(applied))) {
2034 sip_outbound_registration_regc_alloc, new_state)) {
2039 sip_outbound_registration_perform,
ao2_bump(new_state))) {
2040 ast_log(LOG_ERROR,
"Failed to perform outbound registration on '%s'\n",
2056 static int security_mechanism_to_str(
const void *obj,
const intptr_t *args,
char **buf)
2063 static const char *security_negotiation_map[] = {
2064 [AST_SIP_SECURITY_NEG_NONE] =
"no",
2065 [AST_SIP_SECURITY_NEG_MEDIASEC] =
"mediasec",
2068 static int security_negotiation_to_str(
const void *obj,
const intptr_t *args,
char **buf)
2077 static int security_mechanisms_handler(
const struct aco_option *opt,
struct ast_variable *var,
void *obj)
2084 static int security_negotiation_handler(
const struct aco_option *opt,
struct ast_variable *var,
void *obj)
2098 static int outbound_auths_to_str(
const void *obj,
const intptr_t *args,
char **buf)
2105 static int outbound_auths_to_var_list(
const void *obj,
struct ast_variable **fields)
2112 ast_variable_list_append(&head, ast_variable_new(
"outbound_auth",
2123 static int unregister_task(
void *obj)
2127 pjsip_tx_data *tdata;
2128 pjsip_regc_info info;
2130 pjsip_regc_get_info(client, &info);
2131 ast_debug(1,
"Unregistering contacts with server '%s' from client '%s'\n",
2136 if (pjsip_regc_unregister(client, &tdata) == PJ_SUCCESS
2137 && add_configured_supported_headers(state->
client_state, tdata)) {
2167 static void unregister_all(
void)
2181 static void reregister_all(
void)
2187 static char *cli_complete_registration(
const char *line,
const char *word,
2190 char *result = NULL;
2201 wordlen = strlen(word);
2202 if (wordlen == 0 && ++which > state) {
2208 if (!registrations) {
2213 while ((registration = ao2_iterator_next(&i))) {
2216 if (!strncasecmp(word, name, wordlen) && ++which > state) {
2234 const char *registration_name;
2238 e->
command =
"pjsip send unregister";
2240 "Usage: pjsip send unregister <registration> | *all\n"
2241 " Unregisters the specified (or all) outbound registration(s) "
2242 "and stops future registration attempts.\n";
2245 return cli_complete_registration(a->line, a->word, a->pos, a->n);
2249 return CLI_SHOWUSAGE;
2252 registration_name = a->argv[3];
2254 if (strcmp(registration_name,
"*all") == 0) {
2256 ast_cli(a->fd,
"Unregister all queued\n");
2260 state = get_state(registration_name);
2262 ast_cli(a->fd,
"Unable to retrieve registration %s\n", registration_name);
2266 if (queue_unregister(state)) {
2267 ast_cli(a->fd,
"Failed to queue unregistration\n");
2277 const char *registration_name;
2281 e->
command =
"pjsip send register";
2283 "Usage: pjsip send register <registration> | *all \n"
2284 " Unregisters the specified (or all) outbound "
2285 "registration(s) then starts registration(s) and schedules re-registrations.\n";
2288 return cli_complete_registration(a->line, a->word, a->pos, a->n);
2292 return CLI_SHOWUSAGE;
2295 registration_name = a->argv[3];
2297 if (strcmp(registration_name,
"*all") == 0) {
2299 ast_cli(a->fd,
"Re-register all queued\n");
2303 state = get_state(registration_name);
2305 ast_cli(a->fd,
"Unable to retrieve registration %s\n", registration_name);
2312 if (queue_unregister(state)) {
2313 ast_cli(a->fd,
"Failed to queue unregistration\n");
2314 }
else if (queue_register(state)) {
2315 ast_cli(a->fd,
"Failed to queue registration\n");
2327 if (ast_strlen_zero(registration_name)) {
2332 if (strcmp(registration_name,
"*all") == 0) {
2338 state = get_state(registration_name);
2344 if (queue_unregister(state)) {
2359 if (ast_strlen_zero(registration_name)) {
2364 if (strcmp(registration_name,
"*all") == 0) {
2370 state = get_state(registration_name);
2379 if (queue_unregister(state)) {
2381 }
else if (queue_register(state)) {
2398 static int ami_outbound_registration_task(
void *obj)
2404 buf = ast_sip_create_ami_event(
"OutboundRegistrationDetail", ami->ami);
2409 ast_sip_sorcery_object_to_ami(ami->registration, &buf);
2412 pjsip_regc_info info;
2417 ++ami->not_registered;
2431 return ast_sip_format_auths_ami(&ami->registration->
outbound_auths, ami->ami);
2434 static int ami_outbound_registration_detail(
void *obj,
void *arg,
int flags)
2438 ami->registration = obj;
2442 static int ami_show_outbound_registrations(
struct mansession *s,
2449 regs = get_registrations();
2452 "outbound registrations\n");
2462 ami_outbound.registered + ami_outbound.not_registered);
2464 "Registered: %d\r\n"
2465 "NotRegistered: %d\r\n",
2466 ami_outbound.registered,
2467 ami_outbound.not_registered);
2474 static struct ao2_container *cli_get_container(
const char *regex)
2505 static void *cli_retrieve_by_id(
const char *
id)
2522 static int cli_print_header(
void *obj,
void *arg,
int flags)
2529 " <Registration/ServerURI..............................> <Auth....................> <Status.......>\n");
2534 static int cli_print_body(
void *obj,
void *arg,
int flags)
2541 #define REGISTRATION_URI_FIELD_LEN 53
2548 (
int) (REGISTRATION_URI_FIELD_LEN - strlen(
id)),
2549 (
int) (REGISTRATION_URI_FIELD_LEN - strlen(
id)),
2554 (state ? sip_outbound_registration_status_str(state->
client_state->
status) :
"Unregistered"),
2555 state ?
" (exp. " :
"", abs(expsecs), state ? (expsecs < 0 ?
"s ago)" :
"s)") :
"");
2561 ast_sip_cli_print_sorcery_objectset(registration, context, 0);
2574 return ast_sip_cli_traverse_objects(e, cmd, a);
2578 AST_CLI_DEFINE(cli_unregister,
"Unregisters outbound registration target"),
2579 AST_CLI_DEFINE(cli_register,
"Registers an outbound registration target"),
2580 AST_CLI_DEFINE(my_cli_traverse_objects,
"List PJSIP Registrations",
2581 .
command =
"pjsip list registrations",
2582 .
usage =
"Usage: pjsip list registrations [ like <pattern> ]\n"
2583 " List the configured PJSIP Registrations\n"
2584 " Optional regular expression pattern is used to filter the list.\n"),
2585 AST_CLI_DEFINE(my_cli_traverse_objects,
"Show PJSIP Registrations",
2586 .
command =
"pjsip show registrations",
2587 .
usage =
"Usage: pjsip show registrations [ like <pattern> ]\n"
2588 " Show the configured PJSIP Registrations\n"
2589 " Optional regular expression pattern is used to filter the list.\n"),
2590 AST_CLI_DEFINE(my_cli_traverse_objects,
"Show PJSIP Registration",
2591 .
command =
"pjsip show registration",
2592 .
usage =
"Usage: pjsip show registration <id>\n"
2593 " Show the configured PJSIP Registration\n"),
2598 static void auth_observer(
const char *type)
2603 const char *registration_id;
2606 ast_debug(4,
"Auths updated. Checking for any outbound registrations that are in permanent rejected state so they can be retried\n");
2616 for (; (registration = ao2_iterator_next(&i));
ao2_ref(registration, -1)) {
2618 state = get_state(registration_id);
2620 ast_debug(4,
"Trying outbound registration '%s' again\n", registration_id);
2623 sip_outbound_registration_perform,
ao2_bump(state))) {
2624 ast_log(LOG_ERROR,
"Failed to perform outbound registration on '%s'\n", registration_id);
2638 static int check_state(
void *obj,
void *arg,
int flags)
2645 if (!registration) {
2663 static void registration_loaded_observer(
const char *name,
const struct ast_sorcery *sorcery,
const char *object_type,
int reloaded)
2667 if (strcmp(object_type,
"registration")) {
2683 ao2_cleanup(get_registrations());
2694 static void registration_deleted_observer(
const void *obj)
2711 .
deleted = registration_deleted_observer,
2720 ast_debug(3,
"Received network change event\n");
2725 static int unload_module(
void)
2736 ast_sip_unregister_cli_formatter(cli_formatter);
2737 cli_formatter = NULL;
2739 ast_sip_unregister_endpoint_identifier(&line_identifier);
2751 ast_debug(2,
"Waiting for registration transactions to complete for unload.\n");
2752 remaining = ast_serializer_shutdown_group_join(shutdown_group, MAX_UNLOAD_TIMEOUT_TIME);
2759 ast_log(LOG_WARNING,
"Unload incomplete. Could not stop %d outbound registrations. Try again later.\n",
2766 ao2_cleanup(shutdown_group);
2767 shutdown_group = NULL;
2772 static int load_module(
void)
2776 shutdown_group = ast_serializer_shutdown_group_alloc();
2777 if (!shutdown_group) {
2783 DEFAULT_STATE_BUCKETS, registration_state_hash, NULL, registration_state_cmp);
2785 ast_log(LOG_ERROR,
"Unable to allocate registration states container\n");
2795 ast_sorcery_apply_config(ast_sip_get_sorcery(),
"res_pjsip_outbound_registration");
2796 ast_sorcery_apply_default(ast_sip_get_sorcery(),
"registration",
"config",
"pjsip.conf,criteria=type=registration");
2798 if (
ast_sorcery_object_register(ast_sip_get_sorcery(),
"registration", sip_outbound_registration_alloc, NULL, sip_outbound_registration_apply)) {
2830 &observer_callbacks_registrations)
2832 &observer_callbacks_auth)
2834 ®istration_observer)) {
2835 ast_log(LOG_ERROR,
"Unable to register observers.\n");
2841 ast_sip_register_endpoint_identifier(&line_identifier);
2845 if (!cli_formatter) {
2846 ast_log(LOG_ERROR,
"Unable to allocate memory for cli formatter\n");
2850 cli_formatter->
name =
"registration";
2854 cli_formatter->
iterate = cli_iterator;
2857 ast_sip_register_cli_formatter(cli_formatter);
2863 ast_manager_register_xml(
"PJSIPShowRegistrationsOutbound", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, ami_show_outbound_registrations);
2866 ast_statsd_log(
"PJSIP.registrations.count", AST_STATSD_GAUGE, 0);
2867 ast_statsd_log(
"PJSIP.registrations.state.Registered", AST_STATSD_GAUGE, 0);
2868 ast_statsd_log(
"PJSIP.registrations.state.Unregistered", AST_STATSD_GAUGE, 0);
2869 ast_statsd_log(
"PJSIP.registrations.state.Rejected", AST_STATSD_GAUGE, 0);
2875 network_change_stasis_cb, NULL);
2882 static int reload_module(
void)
2888 AST_MODULE_INFO(
ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER,
"PJSIP Outbound Registration Support",
2889 .support_level = AST_MODULE_SUPPORT_CORE,
2890 .load = load_module,
2891 .reload = reload_module,
2892 .unload = unload_module,
2894 .requires =
"res_pjsip",
2895 .optional_modules =
"res_statsd",
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
struct ast_str * output_buffer
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
unsigned int support_path
Whether Path support is enabled.
struct ao2_container *(* get_container)(const char *regex)
#define ARRAY_IN_BOUNDS(v, a)
Checks to see if value is within the bounds of the given array.
int last_status_code
Status code of last response if we have tried to register before.
unsigned int auth_attempted
Non-zero if we have attempted sending a REGISTER with authentication.
int ast_func_read(struct ast_channel *chan, const char *function, char *workspace, size_t len)
executes a read operation on a function
void ast_taskprocessor_build_name(char *buf, unsigned int size, const char *format,...)
Build a taskprocessor name with a sequence number on the end.
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
struct ast_sip_security_mechanism_vector security_mechanisms
Client security mechanisms (RFC 3329).
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
struct stasis_topic * ast_system_topic(void)
A Stasis Message Bus API topic which publishes messages regarding system changes. ...
CLI Formatter Registry Entry.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
void(* deleted)(const void *object)
Callback for when an object is deleted.
int( ao2_callback_fn)(void *obj, void *arg, int flags)
Type of a generic callback function.
unsigned int max_retries
Maximum number of retries permitted.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
const ast_string_field oauth_secret
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
int ast_sip_security_mechanism_vector_init(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *value)
Initialize security mechanism vector from string of security mechanisms.
int ast_sorcery_instance_observer_add(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Add an observer to a sorcery instance.
The arg parameter is a search key, but is not an object.
struct ast_sip_security_mechanism_vector server_security_mechanisms
Security mechanisms of the peer (RFC 3329).
unsigned int support_outbound
Determines whether SIP Outbound support should be advertised.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
pjsip_tx_data * old_request
Request for which the response was received.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
descriptor for a cli entry.
enum sip_outbound_registration_status status
Current state of this registration.
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.
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
struct ast_sip_security_mechanism_vector security_mechanisms
Client security mechanisms (RFC 3329).
const ast_string_field client_uri
URI for the AOR.
Perform no matching, return all objects.
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
static struct stasis_subscription * network_change_sub
int ast_sorcery_object_id_compare(void *obj, void *arg, int flags)
ao2 object comparator based on sorcery id.
pj_timer_entry timer
Timer entry for retrying on temporal responses.
Full structure for sorcery.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int(* iterate)(void *container, ao2_callback_fn callback, void *args)
Type for a default handler that should do nothing.
int stasis_subscription_set_filter(struct stasis_subscription *subscription, enum stasis_subscription_message_filter filter)
Set the message type filtering level on a subscription.
const ast_string_field server_uri
URI for the registrar.
Outbound registration state information (persists for lifetime that registration should exist) ...
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
unsigned int expiration
Requested expiration time.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Return all matching objects.
struct ast_json * ast_json_load_string(const char *input, struct ast_json_error *error)
Parse null terminated string into a JSON object or array.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
Outbound registration client state information (persists for lifetime of regc)
char * user_agent
The value for the User-Agent header sent in requests.
char transport_key[IP6ADDR_COLON_PORT_BUFLEN]
Key for the reliable transport in use.
#define ast_strdup(str)
A wrapper for strdup()
struct ast_sip_endpoint *(* identify_endpoint)(pjsip_rx_data *rdata)
Callback used to identify the source of a message. See ast_sip_identify_endpoint for more details...
void ast_sip_transport_monitor_unregister_key(const char *transport_key, ast_transport_monitor_shutdown_cb cb, void *data, ast_transport_monitor_data_matcher matches)
Unregister a reliable transport shutdown monitor.
CLI Formatter Context passed to all formatters.
Definitions to aid in the use of thread local storage.
void ast_sorcery_load_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to load persistent objects.
int ast_sip_security_mechanisms_to_str(const struct ast_sip_security_mechanism_vector *security_mechanisms, int add_qvalue, char **buf)
Writes the security mechanisms of an endpoint into a buffer as a string and returns the buffer...
#define AST_TASKPROCESSOR_MAX_NAME
Suggested maximum taskprocessor name length (less null terminator).
int ast_sip_push_task_wait_servant(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
char line[LINE_PARAMETER_SIZE]
Optional line parameter placed into Contact.
Structure for registration response.
unsigned int max_retries
Maximum number of retries permitted.
JSON parsing error information.
void ast_sip_security_mechanisms_vector_copy(struct ast_sip_security_mechanism_vector *dst, const struct ast_sip_security_mechanism_vector *src)
Duplicate a security mechanism.
unsigned int support_outbound
Whether Outbound support is enabled.
const ast_string_field contact_user
Optional user for contact header.
struct ao2_container * ast_sorcery_retrieve_by_regex(const struct ast_sorcery *sorcery, const char *type, const char *regex)
Retrieve multiple objects using a regular expression on their id.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
const ast_string_field oauth_clientid
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_sip_add_security_headers(struct ast_sip_security_mechanism_vector *security_mechanisms, const char *header_name, int add_qval, pjsip_tx_data *tdata)
Add security headers to transmission data.
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
Type for default option handler for bools (ast_true/ast_false)
struct sip_outbound_registration_client_state * client_state
Client state information.
#define ast_sorcery_object_field_register_custom(sorcery, type, name, default_val, config_handler, sorcery_handler, multiple_handler, flags,...)
Register a field within an object with custom handlers.
static void cleanup(void)
Clean up any old apps that we don't need any more.
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
unsigned int forbidden_retry_interval
Interval at which retries should occur for permanent responses.
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
const ast_string_field outbound_proxy
Outbound proxy to use.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
void ast_sip_remove_headers_by_name_and_value(pjsip_msg *msg, const pj_str_t *hdr_name, const char *value)
Removes all headers of a specific name and value from a pjsip_msg.
int ast_sorcery_object_unregister(struct ast_sorcery *sorcery, const char *type)
Unregister an object type.
Type for default option handler for unsigned integers.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Interface for the sorcery instance observer.
int ast_sip_push_task_wait_serializer(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to the serializer and wait for it to complete.
void ast_system_publish_registry(const char *channeltype, const char *username, const char *domain, const char *status, const char *cause)
Publish a channel driver outgoing registration message.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_STRING_FIELD(name)
Declare a string field.
const ast_string_field user_agent
User-Agent to use when sending the REGISTER.
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.
int ast_sorcery_object_id_sort(const void *obj, const void *arg, int flags)
ao2 object sorter based on sorcery id.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
void *(* retrieve_by_id)(const char *id)
unsigned int support_path
Determines whether SIP Path support should be advertised.
const ast_string_field transport
Explicit transport to use for registration.
const char * ast_json_string_get(const struct ast_json *string)
Get the value of a JSON string.
pjsip_tx_data * last_tdata
Last tdata sent We need the original tdata to resend a request on auth failure or timeout...
#define ast_malloc(len)
A wrapper for malloc()
struct ao2_container * container
struct ast_taskprocessor * ast_sip_create_serializer_group(const char *name, struct ast_serializer_shutdown_group *shutdown_group)
Create a new serializer for SIP tasks.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_VECTOR(name, type)
Define a vector structure.
char * registration_name
The name of the registration sorcery object.
An entity with which Asterisk communicates.
#define ast_sorcery_object_register(sorcery, type, alloc, transform, apply)
Register an object type.
Core PBX routines and definitions.
void ast_sorcery_instance_observer_remove(struct ast_sorcery *sorcery, const struct ast_sorcery_instance_observer *callbacks)
Remove an observer from a sorcery instance.
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.
struct sip_outbound_registration * registration
Outbound registration configuration object.
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
int code
Response code for the registration attempt.
Outbound registration information.
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
int expiration
Expiration time for registration.
Support for dynamic strings.
#define ao2_unlink(container, obj)
Remove an object from a container.
int ao2_container_dup(struct ao2_container *dest, struct ao2_container *src, enum search_flags flags)
Copy all object references in the src container into the dest container.
const ast_string_field realm
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.
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Type for default option handler for bools (ast_true/ast_false)
char * ast_generate_random_string(char *buf, size_t size)
Create a pseudo-random string of a fixed length.
SORCERY_OBJECT(details)
Sorcery object details.
enum ast_transport_monitor_reg ast_sip_transport_monitor_register_replace_key(const char *transport_key, 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.
#define ast_sorcery_objectset_create(sorcery, object)
Create an object set (KVP list) for an object.
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.
struct ast_taskprocessor * serializer
Serializer for stuff and things.
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.
const ast_string_field auth_pass
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
struct stasis_subscription * stasis_unsubscribe_and_join(struct stasis_subscription *subscription)
Cancel a subscription, blocking until the last message is processed.
Module has failed to load, may be in an inconsistent state.
Vector container support.
An API for managing task processing threads that can be shared across modules.
An entity responsible for identifying the source of a SIP message.
const char *(* get_id)(const void *obj)
structure to hold users read from users.conf
const ast_string_field refresh_token
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
unsigned int max_random_initial_delay
Maximum random initial delay interval for initial registrations.
char * transport_name
The name of the transport to be used for the registration.
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_sorcery_object_field_register(sorcery, type, name, default_val, opt_type, flags,...)
Register a field within an object.
enum ast_sip_security_negotiation security_negotiation
Type of security negotiation to use (RFC 3329).
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
unsigned int retry_interval
Interval at which retries should occur for temporal responses.
The arg parameter is an object of the same type.
void(* object_type_loaded)(const char *name, const struct ast_sorcery *sorcery, const char *object_type, int reloaded)
Callback after any object_type is loaded/reloaded.
unsigned int retries
Current number of retries.
#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.
A ast_taskprocessor structure is a singleton by name.
#define ao2_replace(dst, src)
Replace one object reference with another cleaning up the original.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
int ast_sorcery_changeset_create(const struct ast_variable *original, const struct ast_variable *modified, struct ast_variable **changes)
Create a changeset given two object sets.
struct ast_sip_auth_vector outbound_auths
Configured authentication credentials.
const ast_string_field endpoint
Endpoint to use for related incoming calls.
Standard Command Line Interface.
struct ast_json * ast_json_object_get(struct ast_json *object, const char *key)
Get a field from a JSON object.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
struct sip_outbound_registration_client_state * client_state
Outbound registration client state.
unsigned int auth_rejection_permanent
Treat authentication challenges that we cannot handle as permanent failures.
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Abstract JSON element (object, array, string, int, ...).
Type for default option handler for stringfields.
unsigned int registration_expires
Expected time of registration lapse/expiration.
ao2_callback_fn * print_header
int retry_after
Retry-After value.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
unsigned int fatal_retry_interval
Interval at which retries should occur for all permanent responses.
unsigned int destroy
Registration should be destroyed after completion of transaction.
Search option field mask.
void * ast_sorcery_generic_alloc(size_t size, ao2_destructor_fn destructor)
Allocate a generic sorcery capable object.
static pj_timer_heap_t * timer_heap
Global timer heap.
void ast_sip_header_to_security_mechanism(const pjsip_generic_string_hdr *hdr, struct ast_sip_security_mechanism_vector *security_mechanisms)
Append to security mechanism vector from SIP header.
const ast_string_field aors
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
ao2_callback_fn * print_body
void ast_sip_security_mechanisms_vector_destroy(struct ast_sip_security_mechanism_vector *security_mechanisms)
Free contents of a security mechanism vector.
#define AO2_GLOBAL_OBJ_STATIC(name)
Define a global object holder to be used to hold an ao2 object, statically initialized.
#define ASTERISK_GPL_KEY
The text the key() function should return.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
const ast_string_field contact_header_params
Optional header parameters for contact.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
int ast_func_write(struct ast_channel *chan, const char *function, const char *value)
executes a write operation on a function
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
pjsip_rx_data * rdata
The response message.
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
const ast_string_field auth_user
#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_VECTOR_CALLBACK_VOID(vec, callback,...)
Execute a callback on every element in a vector disregarding callback return.
pjsip_regc * client
Outbound registration client.
enum ast_sip_security_negotiation security_negotiation
Type of security negotiation to use (RFC 3329).
static force_inline int attribute_pure ast_str_hash(const char *str)
Compute a hash value on a string.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
unsigned show_details_only_level_0
unsigned int line
Whether to add a line parameter to the outbound Contact or not.
#define ao2_link(container, obj)
Add an object to a container.