436 .
type =
"session_header_datastore",
442 .
type =
"inheritable_header_datastore",
449 .
type =
"response_header_datastore",
472 pjsip_hdr *hdr = msg->hdr.next;
475 while (
hdr &&
hdr != &msg->hdr) {
477 le->
hdr = pjsip_hdr_clone(pool,
hdr);
495 pj_pool_t *pool =
session->inv_session->dlg->pool;
503 !(datastore->data = pj_pool_alloc(pool,
sizeof(
struct hdr_list))) ||
525 pj_pool_t *pool =
session->inv_session->dlg->pool;
528 pjsip_status_line
status = rdata->msg_info.msg->line.status;
531 if (
session->inv_session->state != PJSIP_INV_STATE_CONNECTING ||
status.code!=200) {
539 !(datastore->data = pj_pool_alloc(pool,
sizeof(
struct hdr_list))) ||
567 if (pj_stricmp2(&le->
hdr->name, header_name) == 0 && i++ == header_number) {
590 pjsip_hdr *hdr =
NULL;
592 int pj_hdr_string_len;
595 size_t plen, wlen = 0;
603 if (!datastore || !datastore->data) {
604 ast_debug(1,
"There was no datastore from which to read headers.\n");
608 list = datastore->data;
615 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->
len - 1);
616 if (pj_hdr_string_len == -1) {
618 "Not enough buffer space in pjsip_hdr_print_on\n");
621 pj_hdr_string[pj_hdr_string_len] =
'\0';
622 p = strchr(pj_hdr_string,
':');
625 "A malformed header was returned from pjsip_hdr_print_on\n");
629 pj_hdr_string[p - pj_hdr_string] =
'\0';
632 if (wlen + plen + 1 > data->
len) {
634 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
638 pos = strstr(data->
buf, p);
639 if (pos && pos[1] ==
',') {
640 if (pos == data->
buf) {
642 }
else if (pos[-1] ==
',') {
662 data->
buf[wlen-1] =
'\0';
681 pjsip_hdr *hdr =
NULL;
683 int pj_hdr_string_len;
693 if (!datastore || !datastore->data) {
694 ast_debug(1,
"There was no datastore from which to read headers.\n");
698 list = datastore->data;
719 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->
len - 1);
720 if (pj_hdr_string_len == -1) {
722 "Not enough buffer space in pjsip_hdr_print_on\n");
726 pj_hdr_string[pj_hdr_string_len] =
'\0';
728 p = strchr(pj_hdr_string,
':');
731 "A malformed header was returned from pjsip_hdr_print_on.\n");
738 if (plen + 1 > data->
len) {
740 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
764 pj_pool_t *pool =
session->inv_session->dlg->pool;
765 pj_str_t pj_header_name;
766 pj_str_t pj_header_value;
776 || !(datastore->data = pj_pool_alloc(pool,
sizeof(
struct hdr_list)))
790 le->
hdr = (pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name,
792 list = datastore->data;
821 ast_debug(3,
"Adding inheritable header %s with value %s to channel %s\n", header_name,
824 if (!chan_datastore) {
828 if (chan_datastore) {
832 ast_debug(3,
"Created new inheritable SIP header channel datastore for channel %s\n",
835 ast_log(
LOG_ERROR,
"Failed to allocate channel datastore for channel %s to store inheritable SIP headers\n",
844 ast_debug(3,
"Upgraded SIP header channel datastore to inheritable for channel %s\n",
850 headers = chan_datastore->
data;
853 ast_log(
LOG_ERROR,
"Failed to allocate variable for channel %s to store inheritable SIP headers\n",
860 new_var->
next = headers;
861 chan_datastore->
data = new_var;
863 ast_debug(1,
"Inherited Header %s added with value %s for channel %s\n",
885 pjsip_hdr *hdr =
NULL;
893 if (!datastore || !datastore->data) {
906 ast_debug(3,
"Found header %s in session datastore, updating value to %s for channel %p\n",
909 pj_strdup2(pool, &((pjsip_generic_string_hdr *) hdr)->hvalue, data->
header_value);
930 int i = 1, num_matching_headers = 0, target_header_index;
934 ast_debug(3,
"Attempting to update header %s for channel %s\n", header_name,
937 if (!inherited_datastore || !inherited_datastore->
data) {
943 headers = inherited_datastore->
data;
947 if (strcasecmp(
var->name, header_name) == 0) {
948 num_matching_headers++;
954 if (num_matching_headers == 0) {
959 }
else if (num_matching_headers < header_number) {
960 ast_log(
AST_LOG_ERROR,
"There were only %d headers named %s on channel %s, cannot update header number %d.\n",
961 num_matching_headers, header_name,
ast_channel_name(channel), header_number);
966 target_header_index = num_matching_headers - header_number + 1;
969 if (strcasecmp(
var->name, header_name) == 0 && i++ == target_header_index) {
981 if (
var == headers) {
983 inherited_datastore->
data = new_var;
986 prev->
next = new_var;
992 ast_debug(3,
"Updated header %s with new value %s for channel %s\n",
1021 int removed_count = 0;
1029 if (!datastore || !datastore->data) {
1034 list = datastore->data;
1038 ast_debug(3,
"Found wildcard match, removing header %.*s from channel %p\n",
1039 (
int)le->
hdr->name.slen, le->
hdr->name.ptr,
1046 ast_debug(3,
"Found exact match, removing header %.*s from channel %p\n",
1047 (
int)le->
hdr->name.slen, le->
hdr->name.ptr,
1056 if (removed_count == 0) {
1061 if (data->
buf && data->
len) {
1062 snprintf(data->
buf, data->
len,
"%d", removed_count);
1063 ast_debug(3,
"Removed %d headers matching %s from channel %s\n", removed_count, data->
header_name,
1081 size_t len = strlen(header_name);
1084 int removed_count = 0;
1089 ast_debug(3,
"Attempting to remove header %s from channel %s\n",
1093 if (!inherited_datastore || !inherited_datastore->
data) {
1100 headers = inherited_datastore->
data;
1103 if (strcmp(header_name,
"*") == 0) {
1106 ast_debug(3,
"Removed all inheritable headers from channel %s\n",
1118 if (
len >= 1 && header_name[
len - 1] ==
'*') {
1120 match = (strncasecmp(
var->name, header_name,
len - 1) == 0);
1122 ast_debug(3,
"Found wildcard match, removing header %s with value %s from channel %s\n",
1127 match = (strcasecmp(
var->name, header_name) == 0);
1129 ast_debug(3,
"Found exact match, removing header %s with value %s from channel %s\n",
1136 if (
var == headers) {
1139 inherited_datastore->
data = headers;
1157 inherited_datastore->
data = headers;
1159 if (removed_count == 0) {
1160 ast_debug(3,
"No headers matching %s found for channel %s\n",
1164 ast_debug(3,
"Removed %d headers matching %s from channel %s\n", removed_count, header_name,
1260 if (!
args.header_number) {
1277 if (!strcasecmp(
args.action,
"read")) {
1279 }
else if (!strcasecmp(
args.action,
"remove")) {
1284 "Unknown action '%s' is not valid, must be 'read' or 'remove'.\n",
1318 if (!
args.header_number) {
1335 if (!strcasecmp(
args.action,
"read")) {
1339 "Unknown action '%s' is not valid, must be 'read'.\n",
1375 if (!
args.header_number) {
1392 if (!strcasecmp(
args.action,
"add")) {
1395 }
else if (!strcasecmp(
args.action,
"update")) {
1398 }
else if (!strcasecmp(
args.action,
"remove")) {
1403 "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n",
1425 ast_log(
LOG_ERROR,
"The PJSIP_INHERITABLE_HEADER function requires a channel.\n");
1436 if (!
args.header_number) {
1446 if (!strcasecmp(
args.action,
"add")) {
1448 }
else if (!strcasecmp(
args.action,
"update")) {
1450 }
else if (!strcasecmp(
args.action,
"remove")) {
1454 "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n",
1461 .
name =
"PJSIP_HEADER",
1467 .
name =
"PJSIP_INHERITABLE_HEADER",
1472 .
name =
"PJSIP_HEADERS",
1477 .
name =
"PJSIP_RESPONSE_HEADER",
1482 .
name =
"PJSIP_RESPONSE_HEADERS",
1502 int header_count = 0;
1508 if (
session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED) {
1509 ast_debug(3,
"Already confirmed (state=%d)\n",
1515 if (
session->channel &&
session->inv_session->role == PJSIP_ROLE_UAC) {
1522 if (chan_datastore && chan_datastore->
inheritance && chan_datastore->
data) {
1526 if (inherited_datastore) {
1531 if (inherited_datastore->
data) {
1535 ast_log(
LOG_ERROR,
"Failed to duplicate ast_variable list for channel %s\n",
1537 ao2_ref(inherited_datastore, -1);
1538 inherited_datastore =
NULL;
1541 ast_log(
LOG_ERROR,
"Failed to allocate inherited session datastore for channel %s\n",
1549 if (!session_datastore && !inherited_datastore) {
1554 if (session_datastore && session_datastore->data) {
1555 hdr_list = session_datastore->data;
1557 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) pjsip_hdr_clone(tdata->pool, le->
hdr));
1560 ast_debug(3,
"Added %d regular header(s) to channel %s\n", header_count,
1567 if (inherited_datastore && inherited_datastore->
data) {
1568 int inherited_count = 0;
1577 ast_debug(3,
"Added %d inherited header(s) to channel %s\n", inherited_count,
1579 header_count += inherited_count;
1582 ao2_ref(inherited_datastore, -1);
1585 ast_debug(3,
"Added total of %d header(s) to channel %s\n", header_count,
1617 pj_str_t param_name;
1619 pjsip_fromto_hdr *dlg_info;
1620 pjsip_name_addr *dlg_info_name_addr;
1621 pjsip_sip_uri *dlg_info_uri;
1625 dlg_info =
session->inv_session->dlg->remote.info;
1626 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1627 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1632 param = pjsip_param_find(&dlg_info_uri->other_param, ¶m_name);
1634 param = pjsip_param_find(&dlg_info->other_param, ¶m_name);
1638 ast_debug(1,
"No %s parameter found named %s\n",
1643 param_len = pj_strlen(¶m->value);
1644 if (param_len >= data->
len) {
1645 ast_log(
LOG_ERROR,
"Buffer is too small for parameter value (%zu > %zu)\n", param_len, data->
len);
1649 ast_debug(2,
"Successfully read %s parameter %s (length %zu)\n",
1654 data->
buf[param_len] =
'\0';
1669 pj_pool_t *pool =
session->inv_session->dlg->pool;
1671 pjsip_fromto_hdr *dlg_info;
1672 pjsip_name_addr *dlg_info_name_addr;
1673 pjsip_sip_uri *dlg_info_uri;
1675 dlg_info =
session->inv_session->dlg->local.info;
1676 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1677 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1678 if (!PJSIP_URI_SCHEME_IS_SIP(dlg_info_uri) && !PJSIP_URI_SCHEME_IS_SIPS(dlg_info_uri)) {
1683 ast_debug(1,
"Adding custom %s param %s = %s\n",
1696#define param_add(pool, list, pname, pvalue) { \
1697 pjsip_param *param; \
1698 param = PJ_POOL_ALLOC_T(pool, pjsip_param); \
1699 pj_strdup2(pool, ¶m->name, pname); \
1700 pj_strdup2(pool, ¶m->value, pvalue); \
1701 pj_list_insert_before(list, param); \
1748 if (!strcasecmp(
args.param_type,
"header")) {
1750 }
else if (!strcasecmp(
args.param_type,
"uri")) {
1797 if (!strcasecmp(
args.param_type,
"header")) {
1799 }
else if (!strcasecmp(
args.param_type,
"uri")) {
1811 .
name =
"PJSIP_HEADER_PARAM",
1846 .
requires =
"res_pjsip,res_pjsip_session",
Asterisk main include file. File version handling, generic pbx functions.
static struct ast_mansession session
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
#define DATASTORE_INHERIT_FOREVER
#define ast_channel_lock(chan)
#define ast_channel_unlock(chan)
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
#define ast_datastore_alloc(info, uid)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
struct ast_variable * ast_variables_reverse(struct ast_variable *var)
Reverse a variable list.
#define ast_variable_new(name, value, filename)
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
#define ast_debug(level,...)
Log a DEBUG message.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
@ AST_MODULE_LOAD_SUCCESS
Core PBX routines and definitions.
#define ast_custom_function_register(acf)
Register a custom function.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name)
Remove a session datastore from the session.
#define ast_sip_session_register_supplement(supplement)
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
void ast_sip_session_unregister_supplement(struct ast_sip_session_supplement *supplement)
Unregister a an supplement to SIP session processing.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Main Channel structure associated with a channel.
Data structure associated with a custom dialplan function.
Structure for a data store type.
Structure for a data store object.
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
A supplement to SIP message processing.
struct ast_module *const char * method
A structure describing a SIP session.
struct ast_channel * channel
struct pjsip_inv_session * inv_session
struct ast_taskprocessor * serializer
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Linked list for accumulating headers.
struct hdr_list_entry::@498 nextptr
enum param_type paramtype
struct ast_sip_channel_pvt * channel
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.