23 #include <pjsip_simple.h>
24 #include <pjsip/sip_transaction.h>
27 #include <pjmedia/errno.h>
59 #define MOD_DATA_CONTACT "contact"
62 #define SERIALIZER_POOL_SIZE 8
87 time_t t = time(
NULL);
90 strftime(date,
sizeof(date),
"%a, %d %b %Y %T GMT", &tm);
97 pjsip_module **module = data;
99 ast_log(
LOG_ERROR,
"There is no PJSIP endpoint. Unable to register services\n");
103 ast_log(
LOG_ERROR,
"Unable to register module %.*s\n", (
int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name));
106 ast_debug(1,
"Registered SIP service %.*s (%p)\n", (
int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name), *module);
117 pjsip_module **module = data;
122 ast_debug(1,
"Unregistered SIP service %.*s\n", (
int) pj_strlen(&(*module)->name), pj_strbuf(&(*module)->name));
140 ast_debug(1,
"Registered SIP authenticator module %p\n", auth);
148 ast_log(
LOG_WARNING,
"Trying to unregister authenticator %p but authenticator %p registered\n",
153 ast_debug(1,
"Unregistered SIP authenticator %p\n", auth);
159 && !pjsip_method_cmp(&rdata->msg_info.msg->line.req.method, &pjsip_options_method)) {
160 ast_debug(3,
"Skipping OPTIONS authentication due to endpoint configuration\n");
165 ast_log(
LOG_WARNING,
"No SIP authenticator registered. Assuming authentication is not required\n");
173 pjsip_rx_data *rdata, pjsip_tx_data *tdata)
176 ast_log(
LOG_WARNING,
"No SIP authenticator registered. Assuming authentication is successful\n");
191 ast_debug(1,
"Registered SIP outbound authenticator module %p\n", auth);
199 ast_log(
LOG_WARNING,
"Trying to unregister outbound authenticator %p but outbound authenticator %p registered\n",
204 ast_debug(1,
"Unregistered SIP outbound authenticator %p\n", auth);
208 pjsip_tx_data *old_request, pjsip_tx_data **new_request)
211 ast_log(
LOG_WARNING,
"No SIP outbound authenticator registered. Cannot respond to authentication challenge\n");
229 char *prev, *
current, *identifier_order;
233 id_list_item =
ast_calloc(1,
sizeof(*id_list_item));
271 if (!strcmp(prev,
name)) {
340 pjsip_generic_string_hdr *hdr;
343 hdr = pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &
str,
NULL);
348 pj_strdup_with_null(rdata->tp_info.pool, &hdr_val, &hdr->hvalue);
369 e->
command =
"pjsip dump endpt [details]";
371 "Usage: pjsip dump endpt [details]\n"
372 " Dump the res_pjsip endpt internals.\n"
374 "Warning: PJPROJECT documents that the function used by this\n"
375 "CLI command may cause a crash when asking for details because\n"
376 "it tries to access all active memory pools.\n";
384 e->
command =
"pjsip dump endpt";
386 "Usage: pjsip dump endpt\n"
387 " Dump the res_pjsip endpt internals.\n";
395 || (
a->argc == 4 && strcasecmp(
a->argv[3],
"details"))) {
406 #define ENDPOINT_IDENTIFIER_FORMAT "%-20.20s\n"
411 e->
command =
"pjsip show identifiers";
412 e->
usage =
"Usage: pjsip show identifiers\n"
413 " List all registered endpoint identifiers\n";
428 iter->
name ? iter->
name :
"name not specified");
432 #undef ENDPOINT_IDENTIFIER_FORMAT
441 e->
command =
"pjsip show settings";
442 e->
usage =
"Usage: pjsip show settings\n"
443 " Show global and system configuration options\n";
451 ast_cli(
a->fd,
"Could not allocate output buffer.\n");
457 ast_cli(
a->fd,
"Error retrieving settings.\n");
519 pjsip_rx_data *rdata)
525 if (uri->port == rdata->pkt_info.src_port
526 && !pj_strcmp(&uri->host,
527 pj_cstr(&host_name, rdata->pkt_info.src_name))
529 && PJSIP_TRANSPORT_IS_RELIABLE(rdata->tp_info.transport)) {
533 if (!strcasecmp(
"WSS", rdata->tp_info.transport->type_name)) {
535 pj_cstr(&type_name,
"ws");
537 pj_cstr(&type_name, rdata->tp_info.transport->type_name);
540 if (!pj_stricmp(&uri->transport_param, &type_name)
543 || !pj_stricmp(&uri->transport_param,
544 pj_cstr(&type_name,
"ws")))) {
558 pjsip_sip_uri *sip_uri,
char *
buf,
size_t buf_len)
562 pjsip_param *x_transport;
569 x_transport = pjsip_param_find(&sip_uri->other_param, &x_name);
587 pjsip_tpselector *selector)
590 pjsip_tpselector sel = { .type = PJSIP_TPSELECTOR_NONE, };
592 uri = pjsip_uri_get_uri(dlg->target);
599 pjsip_dlg_set_transport(dlg, selector);
601 if (selector == &sel) {
609 const char *
domain,
const pj_str_t *target, pjsip_tpselector *selector)
611 pj_str_t
tmp, local_addr;
613 pjsip_sip_uri *sip_uri;
614 pjsip_transport_type_e
type;
616 char default_user[PJSIP_MAX_URL_SIZE];
624 pj_strdup_with_null(pool, &
tmp, target);
626 if (!(uri = pjsip_parse_uri(pool,
tmp.ptr,
tmp.slen, 0)) ||
627 (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
631 sip_uri = pjsip_uri_get_uri(uri);
634 type = pjsip_transport_get_type_from_name(&sip_uri->transport_param);
635 if (PJSIP_URI_SCHEME_IS_SIPS(sip_uri)) {
636 if (
type == PJSIP_TRANSPORT_UNSPECIFIED
637 || !(pjsip_transport_get_flag_from_type(
type) & PJSIP_TRANSPORT_SECURE)) {
638 type = PJSIP_TRANSPORT_TLS;
640 }
else if (!sip_uri->transport_param.slen) {
641 type = PJSIP_TRANSPORT_UDP;
642 }
else if (
type == PJSIP_TRANSPORT_UNSPECIFIED) {
647 if (pj_strchr(&sip_uri->host,
':')) {
648 type |= PJSIP_TRANSPORT_IPV6;
653 from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
654 from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
657 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ?
";transport=" :
"",
658 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(
type) :
"");
663 from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
664 from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
668 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ?
";transport=" :
"",
669 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(
type) :
"");
675 &local_addr, &local_port) != PJ_SUCCESS) {
678 pj_strdup(pool, &local_addr, pj_gethostname());
679 local_port = pjsip_transport_get_default_port_for_type(PJSIP_TRANSPORT_UDP);
683 if (pj_strchr(&local_addr,
':')) {
684 type |= PJSIP_TRANSPORT_IPV6;
687 from->ptr = pj_pool_alloc(pool, PJSIP_MAX_URL_SIZE);
688 from->slen = pj_ansi_snprintf(from->ptr, PJSIP_MAX_URL_SIZE,
689 "<sip:%s@%s%.*s%s:%d%s%s>",
691 (
type & PJSIP_TRANSPORT_IPV6) ?
"[" :
"",
692 (
int)local_addr.slen,
694 (
type & PJSIP_TRANSPORT_IPV6) ?
"]" :
"",
696 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ?
";transport=" :
"",
697 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(
type) :
"");
708 if (!transport_state) {
715 if (transport_state->
flow) {
720 selector->type = PJSIP_TPSELECTOR_TRANSPORT;
721 selector->u.transport = transport_state->
transport;
722 pjsip_transport_add_ref(selector->u.transport);
723 }
else if (transport_state->
factory) {
724 selector->type = PJSIP_TPSELECTOR_LISTENER;
725 selector->u.listener = transport_state->
factory;
733 #ifdef HAVE_PJSIP_TRANSPORT_DISABLE_CONNECTION_REUSE
734 selector->disable_connection_reuse = PJ_TRUE;
736 ast_log(
LOG_WARNING,
"Connection reuse could not be disabled on transport '%s' as support is not available\n",
743 if (transport_state->
flow) {
771 pjsip_sip_uri *sip_uri, pjsip_tpselector *selector)
773 char transport_name[128];
784 if (selector->type == PJSIP_TPSELECTOR_TRANSPORT && selector->u.transport) {
785 pjsip_transport_dec_ref(selector->u.transport);
791 pjsip_sip_uri *sip_uri;
793 static const pj_str_t STR_PHONE = {
"phone", 5 };
795 if (!endpoint || !endpoint->
usereqphone || (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri))) {
799 sip_uri = pjsip_uri_get_uri(uri);
801 if (!pj_strlen(&sip_uri->user)) {
805 if (pj_strbuf(&sip_uri->user)[0] ==
'+') {
810 for (; i < pj_strlen(&sip_uri->user); i++) {
816 if (i < pj_strlen(&sip_uri->user)) {
820 sip_uri->user_param = STR_PHONE;
824 const char *uri,
const char *request_user)
826 char enclosed_uri[PJSIP_MAX_URL_SIZE];
827 pj_str_t local_uri = {
"sip:temp@temp", 13 }, remote_uri, target_uri;
829 pjsip_dialog *dlg =
NULL;
831 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
832 static const pj_str_t HCONTACT = {
"Contact", 7 };
834 snprintf(enclosed_uri,
sizeof(enclosed_uri),
"<%s>", uri);
835 pj_cstr(&remote_uri, enclosed_uri);
837 pj_cstr(&target_uri, uri);
839 res = pjsip_dlg_create_uac(pjsip_ua_instance(), &local_uri,
NULL, &remote_uri, &target_uri, &dlg);
840 if (res == PJ_SUCCESS && !(PJSIP_URI_SCHEME_IS_SIP(dlg->target) || PJSIP_URI_SCHEME_IS_SIPS(dlg->target))) {
843 res = PJSIP_EINVALIDURI;
844 pjsip_dlg_terminate(dlg);
846 if (res != PJ_SUCCESS) {
847 if (res == PJSIP_EINVALIDURI) {
849 "Endpoint '%s': Could not create dialog to invalid URI '%s'. Is endpoint registered and reachable?\n",
862 pjsip_dlg_terminate(dlg);
870 pj_strdup_with_null(dlg->pool, &dlg->local.info_str, &local_uri);
871 dlg->local.info->uri = pjsip_parse_uri(dlg->pool, dlg->local.info_str.ptr, dlg->local.info_str.slen, 0);
872 if (!dlg->local.info->uri) {
874 "Could not parse URI '%s' for endpoint '%s'\n",
877 pjsip_dlg_terminate(dlg);
881 dlg->local.contact = pjsip_parse_hdr(dlg->pool, &HCONTACT, local_uri.ptr, local_uri.slen,
NULL);
884 pjsip_sip_uri *sip_uri;
886 sip_uri = pjsip_uri_get_uri(dlg->local.contact->uri);
887 pj_strdup2(dlg->pool, &sip_uri->user, endpoint->
contact_user);
892 pjsip_sip_uri *sip_uri;
894 if (PJSIP_URI_SCHEME_IS_SIP(dlg->target) || PJSIP_URI_SCHEME_IS_SIPS(dlg->target)) {
895 sip_uri = pjsip_uri_get_uri(dlg->target);
896 pj_strdup2(dlg->pool, &sip_uri->user, request_user);
898 if (PJSIP_URI_SCHEME_IS_SIP(dlg->remote.info->uri) || PJSIP_URI_SCHEME_IS_SIPS(dlg->remote.info->uri)) {
899 sip_uri = pjsip_uri_get_uri(dlg->remote.info->uri);
900 pj_strdup2(dlg->pool, &sip_uri->user, request_user);
909 pjsip_route_hdr route_set, *route;
910 static const pj_str_t ROUTE_HNAME = {
"Route", 5 };
913 pj_list_init(&route_set);
915 pj_strdup2_with_null(dlg->pool, &
tmp, outbound_proxy);
916 if (!(route = pjsip_parse_hdr(dlg->pool, &ROUTE_HNAME,
tmp.ptr,
tmp.slen,
NULL))) {
917 ast_log(
LOG_ERROR,
"Could not create dialog to endpoint '%s' as outbound proxy URI '%s' is not valid\n",
920 pjsip_dlg_terminate(dlg);
923 pj_list_insert_nodes_before(&route_set, route);
925 pjsip_dlg_set_route_set(dlg, &route_set);
945 pjsip_rr_hdr *record_route;
947 if (PJSIP_URI_SCHEME_IS_SIPS(rdata->msg_info.msg->line.req.uri)) {
951 record_route = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_RECORD_ROUTE,
NULL);
953 if (PJSIP_URI_SCHEME_IS_SIPS(&record_route->name_addr)) {
959 contact = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
NULL);
961 if (PJSIP_URI_SCHEME_IS_SIPS(
contact->uri)) {
969 typedef pj_status_t (*
create_dlg_uac)(pjsip_user_agent *ua, pjsip_rx_data *rdata,
970 const pj_str_t *
contact, pjsip_dialog **p_dlg);
977 pjsip_transport_type_e
type = rdata->tp_info.transport->key.type;
978 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
980 pjsip_contact_hdr *contact_hdr;
984 contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
NULL);
991 if (selector.type == PJSIP_TPSELECTOR_TRANSPORT) {
996 contact.ptr = pj_pool_alloc(rdata->tp_info.pool, PJSIP_MAX_URL_SIZE);
998 "<%s:%s%.*s%s:%d%s%s>",
1000 (
type & PJSIP_TRANSPORT_IPV6) ?
"[" :
"",
1003 (
type & PJSIP_TRANSPORT_IPV6) ?
"]" :
"",
1005 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ?
";transport=" :
"",
1006 (
type != PJSIP_TRANSPORT_UDP &&
type != PJSIP_TRANSPORT_UDP6) ? pjsip_transport_get_type_name(
type) :
"");
1008 *
status = create_fun(pjsip_ua_instance(), rdata, &
contact, &dlg);
1009 if (*
status != PJ_SUCCESS) {
1010 char err[PJ_ERR_MSG_SIZE];
1012 pj_strerror(*
status, err,
sizeof(err));
1020 pjsip_dlg_set_transport(dlg, &selector);
1030 #ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
1035 pjsip_dlg_dec_lock(dlg);
1045 pjsip_rx_data *rdata, pj_status_t *
status)
1047 #ifdef HAVE_PJSIP_DLG_CREATE_UAS_AND_INC_LOCK
1059 pjsip_dlg_inc_lock(dlg);
1067 char *transport_type,
const char *local_name,
int local_port,
const char *
contact)
1075 pj_list_init(&rdata->msg_info.parse_err);
1077 rdata->tp_info.transport = PJ_POOL_ZALLOC_T(rdata->tp_info.pool, pjsip_transport);
1078 if (!rdata->tp_info.transport) {
1082 ast_copy_string(rdata->pkt_info.packet, packet,
sizeof(rdata->pkt_info.packet));
1083 ast_copy_string(rdata->pkt_info.src_name, src_name,
sizeof(rdata->pkt_info.src_name));
1084 rdata->pkt_info.src_port = src_port;
1085 pj_sockaddr_parse(pj_AF_UNSPEC(), 0, pj_cstr(&
tmp, src_name), &rdata->pkt_info.src_addr);
1086 pj_sockaddr_set_port(&rdata->pkt_info.src_addr, src_port);
1088 pjsip_parse_rdata(packet, strlen(packet), rdata);
1089 if (!rdata->msg_info.msg || !pj_list_empty(&rdata->msg_info.parse_err)) {
1094 pjsip_contact_hdr *contact_hdr;
1096 contact_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_CONTACT,
NULL);
1098 contact_hdr->uri = pjsip_parse_uri(rdata->tp_info.pool, (
char *)
contact,
1099 strlen(
contact), PJSIP_PARSE_URI_AS_NAMEADDR);
1100 if (!contact_hdr->uri) {
1107 pj_strdup2(rdata->tp_info.pool, &rdata->msg_info.via->recvd_param, rdata->pkt_info.src_name);
1108 rdata->msg_info.via->rport_param = -1;
1110 rdata->tp_info.transport->key.type = pjsip_transport_get_type_from_name(pj_cstr(&
tmp, transport_type));
1111 rdata->tp_info.transport->type_name = transport_type;
1112 pj_strdup2(rdata->tp_info.pool, &rdata->tp_info.transport->local_name.host, local_name);
1113 rdata->tp_info.transport->local_name.port = local_port;
1119 char *transport_type,
const char *local_name,
int local_port)
1122 local_name, local_port,
NULL);
1126 static const pjsip_method
info_method = {PJSIP_OTHER_METHOD, {
"INFO", 4} };
1133 {
"INVITE", &pjsip_invite_method },
1134 {
"CANCEL", &pjsip_cancel_method },
1135 {
"ACK", &pjsip_ack_method },
1136 {
"BYE", &pjsip_bye_method },
1137 {
"REGISTER", &pjsip_register_method },
1138 {
"OPTIONS", &pjsip_options_method },
1139 {
"SUBSCRIBE", &pjsip_subscribe_method },
1140 {
"NOTIFY", &pjsip_notify_method },
1159 if (pjsip_dlg_create_request(dlg,
method, -1, tdata) != PJ_SUCCESS) {
1169 .name = {
"Out of dialog supplement hook", 29 },
1171 .priority = PJSIP_MOD_PRIORITY_APPLICATION - 1,
1176 const char *uri,
struct ast_sip_contact *provided_contact, pjsip_tx_data **tdata)
1179 pj_str_t remote_uri;
1182 pjsip_tpselector selector = { .type = PJSIP_TPSELECTOR_NONE, };
1184 const char *fromuser;
1201 pj_cstr(&remote_uri,
contact->uri);
1203 pj_cstr(&remote_uri, uri);
1213 sip_uri = pjsip_parse_uri(pool, remote_uri.ptr, remote_uri.slen, 0);
1214 if (!sip_uri || (!PJSIP_URI_SCHEME_IS_SIP(sip_uri) && !PJSIP_URI_SCHEME_IS_SIPS(sip_uri))) {
1215 ast_log(
LOG_ERROR,
"Unable to create outbound %.*s request to endpoint %s as URI '%s' is not valid\n",
1216 (
int) pj_strlen(&
method->name), pj_strbuf(&
method->name),
1218 pj_strbuf(&remote_uri));
1227 endpoint ? endpoint->
fromdomain :
NULL, &remote_uri, &selector)) {
1228 ast_log(
LOG_ERROR,
"Unable to create From header for %.*s request to endpoint %s\n",
1229 (
int) pj_strlen(&
method->name), pj_strbuf(&
method->name),
1237 &from, &remote_uri, &from,
NULL, -1,
NULL, tdata) != PJ_SUCCESS) {
1238 ast_log(
LOG_ERROR,
"Unable to create outbound %.*s request to endpoint %s\n",
1239 (
int) pj_strlen(&
method->name), pj_strbuf(&
method->name),
1246 pjsip_tx_data_set_transport(*tdata, &selector);
1251 pjsip_contact_hdr *contact_hdr;
1252 pjsip_sip_uri *contact_uri;
1253 static const pj_str_t HCONTACT = {
"Contact", 7 };
1254 static const pj_str_t HCONTACTSHORT = {
"m", 1 };
1256 contact_hdr = pjsip_msg_find_hdr_by_names((*tdata)->msg, &HCONTACT, &HCONTACTSHORT,
NULL);
1258 contact_uri = pjsip_uri_get_uri(contact_hdr->uri);
1259 pj_strdup2((*tdata)->pool, &contact_uri->user, endpoint->
contact_user);
1269 ast_log(
LOG_ERROR,
"Unable to apply outbound proxy on request %.*s to endpoint %s as outbound proxy URI '%s' is not valid\n",
1332 if (supplement == iter) {
1342 if (pjsip_dlg_send_request(dlg, tdata, -1,
NULL) != PJ_SUCCESS) {
1357 pj_cstr(&
method, supplement_method);
1362 #define TIMER_INACTIVE 0
1363 #define TIMEOUT_TIMER2 5
1434 if (e->body.tsx_state.type == PJSIP_EVENT_TIMER) {
1435 ast_debug(2,
"%p: PJSIP tsx timer expired\n", req_wrapper);
1439 ast_debug(3,
"%p: Timeout already handled\n", req_wrapper);
1444 ast_debug(2,
"%p: PJSIP tsx response received\n", req_wrapper);
1455 int timers_cancelled = 0;
1457 ast_debug(3,
"%p: Cancelling timer\n", req_wrapper);
1459 timers_cancelled = pj_timer_heap_cancel_if_active(
1462 if (timers_cancelled > 0) {
1466 ast_debug(3,
"%p: Timer cancelled\n", req_wrapper);
1474 ast_debug(3,
"%p: Timer already expired\n", req_wrapper);
1487 ast_debug(2,
"%p: Callbacks executed\n", req_wrapper);
1503 ast_debug(2,
"%p: Internal tsx timer expired after %d msec\n",
1504 req_wrapper, req_wrapper->
timeout);
1513 ast_debug(3,
"%p: Timeout already handled\n", req_wrapper);
1519 ast_debug(3,
"%p: Timer handled here\n", req_wrapper);
1528 PJSIP_EVENT_INIT_TX_MSG(
event, req_wrapper->
tdata);
1529 event.body.tsx_state.type = PJSIP_EVENT_TIMER;
1532 ast_debug(2,
"%p: Callbacks executed\n", req_wrapper);
1542 pjsip_tx_data_dec_ref(req_wrapper->
tdata);
1543 ast_debug(2,
"%p: wrapper destroyed\n", req_wrapper);
1547 pjsip_tx_data *
tdata, pj_int32_t
timeout,
void *
token, pjsip_endpt_send_callback cb)
1550 pj_status_t ret_val;
1555 pjsip_tx_data_dec_ref(
tdata);
1562 pjsip_tx_data_dec_ref(
tdata);
1566 ast_debug(2,
"%p: Wrapper created\n", req_wrapper);
1574 pjsip_tx_data_add_ref(
tdata);
1577 pj_time_val timeout_timer_val = {
timeout / 1000,
timeout % 1000 };
1590 ret_val = pj_timer_heap_schedule(pjsip_endpt_get_timer_heap(endpt),
1592 if (ret_val != PJ_SUCCESS) {
1594 "Failed to set timer. Not sending %.*s request to endpoint %s.\n",
1595 (
int) pj_strlen(&
tdata->msg->line.req.method.name),
1596 pj_strbuf(&
tdata->msg->line.req.method.name),
1598 ao2_t_ref(req_wrapper, -2,
"Drop timer and routine ref");
1599 pjsip_tx_data_dec_ref(
tdata);
1609 if (ret_val != PJ_SUCCESS) {
1610 char errmsg[PJ_ERR_MSG_SIZE];
1618 pj_strerror(ret_val, errmsg,
sizeof(errmsg));
1620 (
int) ret_val, errmsg, (
int) pj_strlen(&
tdata->msg->line.req.method.name),
1621 pj_strbuf(&
tdata->msg->line.req.method.name),
1625 int timers_cancelled;
1628 timers_cancelled = pj_timer_heap_cancel_if_active(
1629 pjsip_endpt_get_timer_heap(endpt),
1631 if (timers_cancelled > 0) {
1642 ret_val = PJ_SUCCESS;
1658 ret_val = PJ_SUCCESS;
1671 || (
tdata->dest_info.cur_addr ==
tdata->dest_info.addr.count - 1)) {
1677 ++
tdata->dest_info.cur_addr;
1679 via = (pjsip_via_hdr*)pjsip_msg_find_hdr(
tdata->msg, PJSIP_H_VIA,
NULL);
1680 via->branch_param.slen = 0;
1682 pjsip_tx_data_invalidate_msg(
tdata);
1692 pjsip_transaction *tsx;
1693 pjsip_tx_data *tdata;
1700 tsx = e->body.tsx_state.tsx;
1702 switch (tsx->status_code) {
1708 e->body.tsx_state.src.rdata, tsx->last_tx, &tdata);
1713 tdata = tsx->last_tx;
1718 pjsip_tx_data_add_ref(tdata);
1738 if (e->type == PJSIP_EVENT_TSX_STATE) {
1739 switch(e->body.tsx_state.type) {
1740 case PJSIP_EVENT_TRANSPORT_ERROR:
1741 case PJSIP_EVENT_TIMER:
1751 case PJSIP_EVENT_RX_MSG:
1752 challenge = e->body.tsx_state.src.rdata;
1790 void (*callback)(
void *token, pjsip_event *e))
1798 pjsip_tx_data_dec_ref(tdata);
1831 void (*callback)(
void *token, pjsip_event *e))
1833 ast_assert(tdata->msg->type == PJSIP_REQUEST_MSG);
1844 pjsip_route_hdr *route;
1845 static const pj_str_t ROUTE_HNAME = {
"Route", 5 };
1848 pj_strdup2_with_null(tdata->pool, &
tmp, proxy);
1849 if (!(route = pjsip_parse_hdr(tdata->pool, &ROUTE_HNAME,
tmp.ptr,
tmp.slen,
NULL))) {
1853 pj_list_insert_nodes_before(&tdata->msg->hdr, (pjsip_hdr*)route);
1862 pjsip_generic_string_hdr *hdr;
1864 pj_cstr(&hdr_name,
name);
1865 pj_cstr(&hdr_value,
value);
1867 hdr = pjsip_generic_string_hdr_create(tdata->pool, &hdr_name, &hdr_value);
1869 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) hdr);
1880 pj_cstr(&subtype, body->
subtype);
1883 return pjsip_msg_body_create(pool, &
type, &subtype, &body_text);
1889 tdata->msg->body = pjsip_body;
1897 pjsip_msg_body *body = pjsip_multipart_create(tdata->pool,
NULL,
NULL);
1899 for (i = 0; i < num_bodies; ++i) {
1900 pjsip_multipart_part *part = pjsip_multipart_create_part(tdata->pool);
1902 pjsip_multipart_add_part(tdata->pool, body, part);
1905 tdata->msg->body = body;
1911 size_t combined_size = strlen(body_text) + tdata->msg->body->len;
1914 ast_str_set(&body_buffer, 0,
"%.*s%s", (
int) tdata->msg->body->len, (
char *) tdata->msg->body->data, body_text);
1916 tdata->msg->body->data = pj_pool_alloc(tdata->pool, combined_size);
1917 pj_memcpy(tdata->msg->body->data,
ast_str_buffer(body_buffer), combined_size);
1918 tdata->msg->body->len = combined_size;
1976 memset(&std, 0,
sizeof(std));
1979 std.
task = sip_task;
2037 size_t chars_to_copy =
MIN(size - 1, pj_strlen(src));
2038 memcpy(dest, pj_strbuf(src), chars_to_copy);
2039 dest[chars_to_copy] =
'\0';
2044 int res =
ast_asprintf(dest,
"%.*s", (
int)pj_strlen(src), pj_strbuf(src));
2057 rc = pjsip_media_type_cmp(
a,
b, 0) ? 0 : 1;
2065 pjsip_media_type *
b =
NULL;
2071 while ((
b = va_arg(ap, pjsip_media_type *)) != (pjsip_media_type *)
SENTINEL) {
2072 if (pjsip_media_type_cmp(
a,
b, 0) == 0) {
2086 if (!content_type) {
2092 return pjsip_media_type_cmp(content_type, &
compare, 0) ? 0 : -1;
2103 const pj_time_val delay = {0, 10};
2117 #define SIP_SERVANT_ID 0x5E2F1D
2121 pj_thread_desc *
desc;
2123 uint32_t *servant_id;
2127 ast_log(
LOG_ERROR,
"Could not set SIP servant ID in thread-local storage.\n");
2134 ast_log(
LOG_ERROR,
"Could not get thread desc from thread-local storage. Expect awful things to occur\n");
2139 if (pj_thread_register(
"Asterisk Thread", *
desc, &
thread) != PJ_SUCCESS) {
2146 uint32_t *servant_id;
2149 pthread_self() == *(pthread_t *)pj_thread_get_os_handle(
monitor_thread)) {
2163 unsigned int hval = 0;
2169 return pj_hash_get(ht, key, PJ_HASH_KEY_STRING, &hval);
2173 const char *key,
void *
val)
2176 ht = pj_hash_create(pool, 11);
2179 pj_hash_set(pool, ht, key, PJ_HASH_KEY_STRING, 0,
val);
2188 if (pjsip_rdata_get_dlg(rdata)) {
2211 pjsip_cseq_hdr *cseq = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_CSEQ,
NULL);
2236 if (
status != PJ_SUCCESS) {
2237 pjsip_tx_data_dec_ref(tdata);
2240 return status == PJ_SUCCESS ? 0 : -1;
2245 pjsip_transaction *tsx;
2247 if (pjsip_tsx_create_uas(
NULL, rdata, &tsx) != PJ_SUCCESS) {
2256 pjsip_tx_data_dec_ref(tdata);
2259 pjsip_tsx_recv_msg(tsx, rdata);
2263 if (pjsip_tsx_send_msg(tsx, tdata) != PJ_SUCCESS) {
2264 pjsip_tx_data_dec_ref(tdata);
2298 if (af == pj_AF_INET()) {
2300 }
else if (af == pj_AF_INET6()) {
2308 char *
buf,
size_t buf_len)
2340 if (!strcasecmp(dtmf_mode,
"info")) {
2342 }
else if (!strcasecmp(dtmf_mode,
"rfc4733")) {
2344 }
else if (!strcasecmp(dtmf_mode,
"inband")) {
2346 }
else if (!strcasecmp(dtmf_mode,
"none")) {
2348 }
else if (!strcasecmp(dtmf_mode,
"auto")) {
2350 }
else if (!strcasecmp(dtmf_mode,
"auto_info")) {
2364 value =
"local_merge";
2366 value =
"local_first";
2370 value =
"remote_merge";
2372 value =
"remote_first";
2384 if (strcmp(pref_str,
"local") == 0) {
2386 }
else if (is_outgoing && strcmp(pref_str,
"local_merge") == 0) {
2388 }
else if (strcmp(pref_str,
"local_first") == 0) {
2390 }
else if (strcmp(pref_str,
"remote") == 0) {
2392 }
else if (is_outgoing && strcmp(pref_str,
"remote_merge") == 0) {
2394 }
else if (strcmp(pref_str,
"remote_first") == 0) {
2412 pjsip_name_addr *id_name_addr;
2413 pjsip_sip_uri *id_uri;
2415 id_name_addr = (pjsip_name_addr *) id_hdr->uri;
2416 id_uri = pjsip_uri_get_uri(id_name_addr->uri);
2418 if (
id->name.valid) {
2420 int name_buf_len = strlen(
id->name.str) * 2 + 1;
2424 pj_strdup2(pool, &id_name_addr->display, name_buf);
2426 pj_strdup2(pool, &id_name_addr->display,
NULL);
2430 if (
id->number.valid) {
2431 pj_strdup2(pool, &id_uri->user,
id->number.str);
2438 const pjsip_hdr *
request_headers = pjsip_endpt_get_request_headers(endpt);
2442 pjsip_hdr *to_erase = iter;
2444 pj_list_erase(to_erase);
2458 #ifdef TEST_FRAMEWORK
2465 info->name =
"xml_sanitization_end_null";
2466 info->category =
"/res/res_pjsip/";
2467 info->summary =
"Ensure XML sanitization works as expected with a long string";
2468 info->description =
"This test sanitizes a string which exceeds the output\n"
2469 "buffer size. Once done the string is confirmed to be NULL terminated.";
2476 if (sanitized[7] !=
'\0') {
2490 info->name =
"xml_sanitization_exceeds_buffer";
2491 info->category =
"/res/res_pjsip/";
2492 info->summary =
"Ensure XML sanitization does not exceed buffer when output won't fit";
2493 info->description =
"This test sanitizes a string which before sanitization would\n"
2494 "fit within the output buffer. After sanitization, however, the string would\n"
2495 "exceed the buffer. Once done the string is confirmed to be NULL terminated.";
2502 if (sanitized[7] !=
'\0') {
2553 pj_pool_release(temp_pool);
2569 const unsigned int flags = 0;
2578 ast_log(
LOG_ERROR,
"Failed to create PJSIP endpoint structure. Aborting load\n");
2589 ast_log(
LOG_ERROR,
"Failed to create memory pool for SIP. Aborting load\n");
2609 if (
status != PJ_SUCCESS) {
2630 pjmedia_strerror(0,
NULL, 0);
2652 if (pj_init() != PJ_SUCCESS) {
2656 if (pjlib_util_init() != PJ_SUCCESS) {
2661 if (pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE, pjmedia_strerror)
2663 ast_log(
LOG_WARNING,
"Failed to register pjmedia error codes. Codes will not be decoded.\n");
2682 ast_log(
LOG_ERROR,
"Failed to initialize SIP 'system' configuration section. Aborting load\n");
2697 ast_log(
LOG_ERROR,
"Failed to create SIP serializer pool. Aborting load\n");
2712 ast_log(
LOG_ERROR,
"Failed to initialize SIP transport monitor. Aborting load\n");
2720 ast_log(
LOG_ERROR,
"Failed to pre-initialize OPTIONS handling. Aborting load\n");
2725 ast_log(
LOG_ERROR,
"Failed to initialize SIP configuration. Aborting load\n");
2733 ast_log(
LOG_ERROR,
"Failed to initialize SIP transport management. Aborting load\n");
2738 ast_log(
LOG_ERROR,
"Failed to register distributor module. Aborting load\n");
2743 ast_log(
LOG_ERROR,
"Failed to initialize supplement hooks. Aborting load\n");
2748 ast_log(
LOG_ERROR,
"Failed to initialize OPTIONS handling. Aborting load\n");
2753 ast_log(
LOG_ERROR,
"Failed to initialize message IP updating. Aborting load\n");
2812 .requires =
"dnsmgr,res_pjproject,res_sorcery_config,res_sorcery_memory,res_sorcery_astdb",
2813 .optional_modules =
"res_statsd",
static int compare(const char *text, const char *template)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ao2_t_ref(o, delta, tag)
@ AO2_ALLOC_OPT_LOCK_NOLOCK
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define ao2_alloc_options(data_size, destructor_fn, options)
#define ao2_bump(obj)
Bump refcount on an AO2 object by one, returning the object.
#define ao2_alloc(data_size, destructor_fn)
static char context[AST_MAX_CONTEXT]
Standard Command Line Interface.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
int sip_cli_print_global(struct ast_sip_cli_context *context)
void ast_sip_destroy_system(void)
int sip_cli_print_system(struct ast_sip_cli_context *context)
int ast_sip_initialize_system(void)
void ast_sip_initialize_dns(void)
void sip_get_threadpool_options(struct ast_threadpool_options *threadpool_options)
Generic File Format Support. Should be included by clients of the file handling routines....
int ast_sip_push_task(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Pushes a task to SIP servants.
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.
int ast_sip_thread_is_servant(void)
Determine if the current thread is a SIP servant thread.
int ast_sip_push_task_synchronous(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
Push a task to SIP servants and wait for it to complete.
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.
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.
struct ast_taskprocessor * ast_sip_create_serializer(const char *name)
Create a new serializer for SIP tasks.
Support for logging to various files, console and syslog Configuration in file logger....
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
A set of macros to manage forward-linked lists.
#define AST_RWLIST_REMOVE_CURRENT
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized.
#define AST_RWLIST_INSERT_AFTER
#define AST_RWLIST_TRAVERSE_SAFE_END
#define AST_RWLIST_TRAVERSE
#define AST_RWLIST_INSERT_HEAD
#define AST_RWLIST_INSERT_TAIL
#define AST_RWLIST_INSERT_BEFORE_CURRENT
Asterisk locking-related definitions:
#define ast_cond_destroy(cond)
#define ast_cond_wait(cond, mutex)
#define ast_cond_init(cond, attr)
#define ast_mutex_init(pmutex)
#define ast_mutex_unlock(a)
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
pthread_cond_t ast_cond_t
#define ast_mutex_destroy(a)
#define ast_mutex_lock(a)
#define ast_cond_signal(cond)
Asterisk module definitions.
@ AST_MODFLAG_GLOBAL_SYMBOLS
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODPRI_CHANNEL_DEPEND
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
int ast_sockaddr_parse(struct ast_sockaddr *addr, const char *str, int flags)
Parse an IPv4 or IPv6 address string.
static struct ast_serializer_shutdown_group * shutdown_group
Shutdown group for options serializers.
void ast_pjproject_log_intercept_begin(int fd)
Begin PJPROJECT log interception for CLI output.
void ast_pjproject_log_intercept_end(void)
End PJPROJECT log interception for CLI output.
void ast_pjproject_caching_pool_destroy(pj_caching_pool *cp)
Destroy caching pool factory and all cached pools.
void ast_pjproject_caching_pool_init(pj_caching_pool *cp, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
Initialize the caching pool factory.
static pjsip_dialog * create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status, create_dlg_uac create_fun)
struct ast_threadpool * ast_sip_threadpool(void)
Retrieve the SIP threadpool object.
static pjsip_endpoint * ast_pjsip_endpoint
void ast_sip_unregister_supplement(struct ast_sip_supplement *supplement)
Unregister a an supplement to SIP out of dialog processing.
static pj_sockaddr host_ip_ipv4
int ast_sip_is_media_type_in(pjsip_media_type *a,...)
Check if a media type is in a list of others.
void ast_sip_add_usereqphone(const struct ast_sip_endpoint *endpoint, pj_pool_t *pool, pjsip_uri *uri)
Add 'user=phone' parameter to URI if enabled and user is a phone number.
static int unload_pjsip(void *data)
static void supplement_outgoing_response(pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
static const pjsip_method info_method
void ast_sip_unregister_service(pjsip_module *module)
static void * monitor_thread_exec(void *endpt)
pj_status_t(* create_dlg_uac)(pjsip_user_agent *ua, pjsip_rx_data *rdata, const pj_str_t *contact, pjsip_dialog **p_dlg)
static struct ast_sip_outbound_authenticator * registered_outbound_authenticator
pjsip_media_type pjsip_media_type_application_media_control_xml
static struct ast_cli_entry cli_commands[]
static int create_in_dialog_request(const pjsip_method *method, struct pjsip_dialog *dlg, pjsip_tx_data **tdata)
int ast_sip_call_codec_str_to_pref(struct ast_flags *pref, const char *pref_str, int is_outgoing)
Convert a call codec preference string to preference flags.
pjsip_media_type pjsip_media_type_application_json
int ast_sip_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Determine if an incoming request requires authentication.
int ast_sip_send_response(pjsip_response_addr *res_addr, pjsip_tx_data *tdata, struct ast_sip_endpoint *sip_endpoint)
Send a response to an out of dialog request.
int ast_copy_pj_str2(char **dest, const pj_str_t *src)
Create and copy a pj_str_t into a standard character buffer.
int ast_sip_get_host_ip(int af, pj_sockaddr *addr)
Retrieve the local host address in IP form.
int ast_sip_register_service(pjsip_module *module)
Register a SIP service in Asterisk.
static int create_out_of_dialog_request(const pjsip_method *method, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *provided_contact, pjsip_tx_data **tdata)
static void send_request_timer_callback(pj_timer_heap_t *theap, pj_timer_entry *entry)
static int reload_configuration_task(void *obj)
int ast_sip_register_outbound_authenticator(struct ast_sip_outbound_authenticator *auth)
Register an outbound SIP authenticator.
static int ast_sip_push_task_wait(struct ast_taskprocessor *serializer, int(*sip_task)(void *), void *task_data)
static void send_request_wrapper_destructor(void *obj)
static int unregister_service(void *data)
static void send_request_data_destroy(void *obj)
static int uas_use_sips_contact(pjsip_rx_data *rdata)
Determine if a SIPS Contact header is required.
pjsip_media_type pjsip_media_type_application_sdp
const char * ast_sip_call_codec_pref_to_str(struct ast_flags pref)
Convert the call codec preference flags to a string.
pjsip_dialog * ast_sip_create_dialog_uas(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
General purpose method for creating a UAS dialog with an endpoint.
void ast_sip_register_supplement(struct ast_sip_supplement *supplement)
Register a supplement to SIP out of dialog processing.
static char * cli_show_endpoint_identifiers(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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.
pjsip_media_type pjsip_media_type_text_plain
pj_thread_t * monitor_thread
void ast_sip_unregister_outbound_authenticator(struct ast_sip_outbound_authenticator *auth)
Unregister an outbound SIP authenticator.
pjsip_media_type pjsip_media_type_application_pidf_xml
static char * cli_dump_endpt(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
void * ast_sip_dict_get(void *ht, const char *key)
Retrieves the value associated with the given key.
int ast_sip_create_rdata(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type, const char *local_name, int local_port)
General purpose method for creating an rdata structure using specific information.
enum ast_sip_check_auth_result ast_sip_check_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata)
Method to determine authentication status of an incoming request.
int ast_sip_register_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Register a SIP endpoint identifier.
static void send_request_cb(void *token, pjsip_event *e)
pjsip_dialog * ast_sip_create_dialog_uac(const struct ast_sip_endpoint *endpoint, const char *uri, const char *request_user)
General purpose method for creating a UAC dialog with an endpoint.
static const pjsip_method message_method
int ast_sip_format_endpoint_ami(struct ast_sip_endpoint *endpoint, struct ast_sip_ami *ami, int *count)
Formats the endpoint and sends over AMI.
int ast_sip_dtmf_to_str(const enum ast_sip_dtmf_mode dtmf, char *buf, size_t buf_len)
Convert the DTMF mode enum value into a string.
static struct ast_threadpool * sip_threadpool
int ast_sip_set_tpselector_from_transport(const struct ast_sip_transport *transport, pjsip_tpselector *selector)
Sets pjsip_tpselector from ast_sip_transport.
int ast_sip_set_tpselector_from_ep_or_uri(const struct ast_sip_endpoint *endpoint, pjsip_sip_uri *sip_uri, pjsip_tpselector *selector)
Sets pjsip_tpselector from an endpoint or uri.
static int check_request_status(struct send_request_data *req_data, pjsip_event *e)
pjsip_endpoint * ast_sip_get_pjsip_endpoint(void)
Get a pointer to the PJSIP endpoint.
static void sip_thread_start(void)
void ast_sip_unregister_endpoint_identifier(struct ast_sip_endpoint_identifier *identifier)
Unregister a SIP endpoint identifier.
static int reload_module(void)
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.
static int send_in_dialog_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg)
#define SERIALIZER_POOL_SIZE
int ast_sip_send_out_of_dialog_request(pjsip_tx_data *tdata, struct ast_sip_endpoint *endpoint, int timeout, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending an Out-Of-Dialog SIP request.
pjsip_media_type pjsip_media_type_application_simple_message_summary
static char host_ip_ipv6_string[PJ_INET6_ADDRSTRLEN]
char * ast_sip_rdata_get_header_value(pjsip_rx_data *rdata, const pj_str_t str)
Get a specific header value from rdata.
static struct ast_threadstorage pj_thread_storage
int ast_sip_dlg_set_transport(const struct ast_sip_endpoint *endpoint, pjsip_dialog *dlg, pjsip_tpselector *selector)
Set the transport on a dialog.
static struct @485 methods[]
static pj_sockaddr host_ip_ipv6
static pj_status_t endpt_send_request(struct ast_sip_endpoint *endpoint, pjsip_tx_data *tdata, pj_int32_t timeout, void *token, pjsip_endpt_send_callback cb)
void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth)
Unregister a SIP authenticator.
int ast_sip_send_request(pjsip_tx_data *tdata, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, void *token, void(*callback)(void *token, pjsip_event *e))
General purpose method for sending a SIP request.
long ast_sip_threadpool_queue_size(void)
Return the size of the SIP threadpool's task queue.
static char * cli_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static pj_bool_t supplement_on_rx_request(pjsip_rx_data *rdata)
void ast_sip_register_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Register an endpoint formatter.
int ast_sip_add_body(pjsip_tx_data *tdata, const struct ast_sip_body *body)
Add a body to an outbound SIP message.
pjsip_dialog * ast_sip_create_dialog_uas_locked(const struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pj_status_t *status)
General purpose method for creating a UAS dialog with an endpoint.
int ast_sip_are_media_types_equal(pjsip_media_type *a, pjsip_media_type *b)
Compare pjsip media types.
void ast_sip_tpselector_unref(pjsip_tpselector *selector)
Unreference a pjsip_tpselector.
void never_called_res_pjsip(void)
int ast_sip_get_transport_name(const struct ast_sip_endpoint *endpoint, pjsip_sip_uri *sip_uri, char *buf, size_t buf_len)
Get the transport name from an endpoint or request uri.
void ast_sip_unregister_endpoint_formatter(struct ast_sip_endpoint_formatter *obj)
Unregister an endpoint formatter.
int ast_sip_register_authenticator(struct ast_sip_authenticator *auth)
Register a SIP authenticator.
static const pjsip_method * get_pjsip_method(const char *method)
int ast_sip_create_rdata_with_contact(pjsip_rx_data *rdata, char *packet, const char *src_name, int src_port, char *transport_type, const char *local_name, int local_port, const char *contact)
General purpose method for creating an rdata structure using specific information.
int ast_sip_add_body_multipart(pjsip_tx_data *tdata, const struct ast_sip_body *bodies[], int num_bodies)
Add a multipart body to an outbound SIP message.
pjsip_media_type pjsip_media_type_application_rlmi_xml
static int monitor_continue
static void remove_request_headers(pjsip_endpoint *endpt)
pjsip_media_type pjsip_media_type_multipart_mixed
static int register_service(void *data)
pjsip_media_type pjsip_media_type_application_xpidf_xml
static int load_module(void)
int ast_sip_set_outbound_proxy(pjsip_tx_data *tdata, const char *proxy)
Set the outbound proxy for an outbound SIP message.
static struct ast_sip_authenticator * registered_authenticator
const char * ast_sip_get_host_ip_string(int af)
Retrieve the local host address in string form.
int ast_sip_will_uri_survive_restart(pjsip_sip_uri *uri, struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
int ast_sip_register_endpoint_identifier_with_name(struct ast_sip_endpoint_identifier *identifier, const char *name)
Register a SIP endpoint identifier with a name.
pjsip_media_type pjsip_media_type_multipart_alternative
int ast_sip_set_tpselector_from_transport_name(const char *transport_name, pjsip_tpselector *selector)
Sets pjsip_tpselector from ast_sip_transport.
int ast_sip_create_request(const char *method, struct pjsip_dialog *dlg, struct ast_sip_endpoint *endpoint, const char *uri, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP request.
pj_caching_pool caching_pool
struct ast_sip_endpoint * ast_sip_identify_endpoint(pjsip_rx_data *rdata)
Determine the endpoint that has sent a SIP message.
static void endpt_send_request_cb(void *token, pjsip_event *e)
const pjsip_method * pmethod
int ast_sip_str_to_dtmf(const char *dtmf_mode)
Convert the DTMF mode name into an enum.
void * ast_sip_dict_set(pj_pool_t *pool, void *ht, const char *key, void *val)
Set the value for the given key.
static int do_cli_dump_endpt(void *v_a)
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
static int unload_module(void)
static pjsip_module supplement_module
static char host_ip_ipv4_string[PJ_INET6_ADDRSTRLEN]
static int load_pjsip(void)
static pjsip_msg_body * ast_body_to_pjsip_body(pj_pool_t *pool, const struct ast_sip_body *body)
static pj_bool_t does_method_match(const pj_str_t *message_method, const char *supplement_method)
static struct ast_threadstorage servant_id_storage
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.
int ast_sip_is_content_type(pjsip_media_type *content_type, char *type, char *subtype)
Checks if the given content type matches type/subtype.
int ast_sip_append_body(pjsip_tx_data *tdata, const char *body_text)
Append body data to a SIP message.
#define ENDPOINT_IDENTIFIER_FORMAT
int ast_sip_create_request_with_auth(const struct ast_sip_auth_vector *auths, pjsip_rx_data *challenge, pjsip_tx_data *old_request, pjsip_tx_data **new_request)
Create a response to an authentication challenge.
pjsip_media_type pjsip_media_type_application_cpim_xpidf_xml
static struct send_request_data * send_request_data_alloc(struct ast_sip_endpoint *endpoint, void *token, void(*callback)(void *token, pjsip_event *e))
static void stop_monitor_thread(void)
static int sync_task(void *data)
pjsip_media_type pjsip_media_type_multipart_related
static struct ast_serializer_pool * sip_serializer_pool
int ast_sip_failover_request(pjsip_tx_data *tdata)
Set a request to use the next value in the list of resolved addresses.
static int sip_dialog_create_from(pj_pool_t *pool, pj_str_t *from, const char *user, const char *domain, const pj_str_t *target, pjsip_tpselector *selector)
void ast_sip_modify_id_header(pj_pool_t *pool, pjsip_fromto_hdr *id_hdr, const struct ast_party_id *id)
Set name and number information on an identity header.
int ast_sip_create_response(const pjsip_rx_data *rdata, int st_code, struct ast_sip_contact *contact, pjsip_tx_data **tdata)
General purpose method for creating a SIP response.
struct ast_sip_contact * ast_sip_location_retrieve_contact_from_aor_list(const char *aor_list)
Retrieve the first bound contact from a list of AORs.
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.
char * ast_sip_get_endpoint_identifier_order(void)
Retrieve the global endpoint_identifier_order setting.
#define ast_sip_call_codec_pref_test(__param, __codec_pref)
Returns true if the preference is set in the parameter.
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
void ast_sip_message_apply_transport(const char *transport_name, pjsip_tx_data *tdata)
Apply the configuration for a transport to an outgoing message.
#define AST_SIP_X_AST_TXP
#define ast_sip_mod_data_set(pool, mod_data, id, key, val)
Utilizing a mod_data array for a given id, set the value associated with the given key.
unsigned int ast_sip_get_disable_multi_domain(void)
Retrieve the system setting 'disable multi domain'.
ast_sip_dtmf_mode
DTMF modes for SIP endpoints.
#define ast_sip_mod_data_get(mod_data, id, key)
Using the dictionary stored in mod_data array at a given id, retrieve the value associated with the g...
struct ast_sip_transport_state * ast_sip_get_transport_state(const char *transport_id)
Retrieve transport state.
#define MAX_RX_CHALLENGES
ast_sip_check_auth_result
Possible returns from ast_sip_check_authentication.
@ AST_SIP_AUTHENTICATION_SUCCESS
@ AST_SIP_CALL_CODEC_PREF_ALL
@ AST_SIP_CALL_CODEC_PREF_LOCAL
@ AST_SIP_CALL_CODEC_PREF_REMOTE
@ AST_SIP_CALL_CODEC_PREF_UNION
@ AST_SIP_CALL_CODEC_PREF_FIRST
@ AST_SIP_CALL_CODEC_PREF_INTERSECT
#define AST_SIP_X_AST_TXP_LEN
void ast_sip_get_default_from_user(char *from_user, size_t size)
Retrieve the global default from user.
static void challenge(const char *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
astobj2 callback for adding digest challenges to responses
void ast_sip_sanitize_xml(const char *input, char *output, size_t len)
Replace offensive XML characters with XML entities.
int ast_sip_initialize_scheduler(void)
Initialize scheduler.
int ast_res_pjsip_preinit_options_handling(void)
int ast_sip_initialize_transport_management(void)
void ast_sip_initialize_resolver(void)
int ast_res_pjsip_init_options_handling(int reload)
int ast_sip_initialize_distributor(void)
int ast_res_pjsip_reload_configuration(void)
int ast_sip_destroy_scheduler(void)
void ast_sip_initialize_global_headers(void)
void ast_res_pjsip_cleanup_options_handling(void)
void ast_sip_destroy_transport_management(void)
int ast_sip_initialize_transport_events(void)
void ast_sip_destroy_distributor(void)
int ast_res_pjsip_initialize_configuration(void)
void ast_sip_destroy_global_headers(void)
void ast_res_pjsip_destroy_configuration(void)
int ast_res_pjsip_init_message_filter(void)
void ast_sip_destroy_transport_events(void)
void ast_res_pjsip_cleanup_message_filter(void)
const pjsip_method pjsip_publish_method
Defined method for PUBLISH.
struct ast_taskprocessor * ast_serializer_pool_get(struct ast_serializer_pool *pool)
Retrieve a serializer from the pool.
struct ast_serializer_pool * ast_serializer_pool_create(const char *name, unsigned int size, struct ast_threadpool *threadpool, int timeout)
Create a serializer pool.
int ast_serializer_pool_destroy(struct ast_serializer_pool *pool)
Destroy the serializer pool.
Sorcery Data Access Layer API.
void * ast_sorcery_retrieve_by_id(const struct ast_sorcery *sorcery, const char *type, const char *id)
Retrieve an object using its unique identifier.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_alloca(init_len)
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
descriptor for a cli entry.
struct ast_cli_entry * next
Structure used to handle boolean flags.
Structure for mutex and tracking information.
Information needed to identify an endpoint in a call.
An interchangeable way of handling digest authentication for SIP.
enum ast_sip_check_auth_result(* check_authentication)(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata)
Check that an incoming request passes authentication.
int(* requires_authentication)(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Check if a request requires authentication See ast_sip_requires_authentication for more details.
CLI Formatter Context passed to all formatters.
An entity responsible for identifying the source of a SIP message.
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.
unsigned int rewrite_contact
An entity with which Asterisk communicates.
struct ast_sip_auth_vector outbound_auths
const ast_string_field transport
const ast_string_field aors
const ast_string_field outbound_proxy
const ast_string_field fromdomain
unsigned int allow_unauthenticated_options
const ast_string_field fromuser
struct ast_sip_endpoint_nat_configuration nat
struct ast_sip_endpoint_info_configuration info
an interchangeable way of responding to authentication challenges
int(* create_request_with_auth)(const struct ast_sip_auth_vector *auths, struct pjsip_rx_data *challenge, struct pjsip_tx_data *old_request, struct pjsip_tx_data **new_request)
Create a new request with authentication credentials.
A supplement to SIP message processing.
void(* outgoing_request)(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)
Called on an outgoing SIP request This method is always called from a SIP servant thread.
int(* incoming_request)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata)
Called on incoming SIP request This method can indicate a failure in processing in its return....
void(* outgoing_response)(struct ast_sip_endpoint *endpoint, struct ast_sip_contact *contact, struct pjsip_tx_data *tdata)
Called on an outgoing SIP response This method is always called from a SIP servant thread.
void(* incoming_response)(struct ast_sip_endpoint *endpoint, struct pjsip_rx_data *rdata)
Called on an incoming SIP response This method is always called from a SIP servant thread.
enum ast_sip_supplement_priority priority
struct ast_sip_supplement * next
Structure for SIP transport information.
struct pjsip_tpfactory * factory
Transport factory.
struct pjsip_transport * transport
Transport itself.
Support for dynamic strings.
A ast_taskprocessor structure is a singleton by name.
An opaque threadpool structure.
struct ast_sip_endpoint_identifier * identifier
Structure to hold information about an outbound request.
struct ast_sip_endpoint * endpoint
unsigned int challenge_count
void(* callback)(void *token, pjsip_event *e)
unsigned int send_cb_called
pj_timer_entry * timeout_timer
void(* callback)(void *token, pjsip_event *e)
userdata associated with baseline taskprocessor test
structure to hold users read from users.conf
An API for managing task processing threads that can be shared across modules.
int ast_taskprocessor_is_task(struct ast_taskprocessor *tps)
Am I the given taskprocessor's current task.
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
#define AST_TEST_DEFINE(hdr)
void ast_threadpool_shutdown(struct ast_threadpool *pool)
Shut down a threadpool and destroy it.
struct ast_taskprocessor * ast_threadpool_serializer_group(const char *name, struct ast_threadpool *pool, struct ast_serializer_shutdown_group *shutdown_group)
Serialized execution of tasks within a ast_threadpool.
long ast_threadpool_queue_size(struct ast_threadpool *pool)
Return the size of the threadpool's task queue.
struct ast_threadpool * ast_threadpool_create(const char *name, struct ast_threadpool_listener *listener, const struct ast_threadpool_options *options)
Create a new threadpool.
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
int error(const char *format,...)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
char * ast_escape_quoted(const char *string, char *outbuf, int buflen)
Escape characters found in a quoted string.
#define ast_set_flag(p, flag)
Universally unique identifier support.