Asterisk - The Open Source Telephony Project GIT-master-f36a736
res_pjsip_header_funcs.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Fairview 5 Engineering, LLC
5 *
6 * George Joseph <george.joseph@fairview5.com>
7 * José Lopes <jose.lopes@nfon.com>
8 * Naveen Albert <asterisk@phreaknet.org>
9 *
10 * See http://www.asterisk.org for more information about
11 * the Asterisk project. Please do not directly contact
12 * any of the maintainers of this project for assistance;
13 * the project provides a web site, mailing lists and IRC
14 * channels for your use.
15 *
16 * This program is free software, distributed under the terms of
17 * the GNU General Public License Version 2. See the LICENSE file
18 * at the top of the source tree.
19 */
20
21/*** MODULEINFO
22 <depend>pjproject</depend>
23 <depend>res_pjsip</depend>
24 <depend>res_pjsip_session</depend>
25 <support_level>core</support_level>
26 ***/
27
28#include "asterisk.h"
29
30#include <pjsip.h>
31#include <pjsip_ua.h>
32
33#include "asterisk/res_pjsip.h"
35#include "asterisk/channel.h"
36#include "asterisk/pbx.h"
37#include "asterisk/app.h"
38#include "asterisk/module.h"
39#include "asterisk/utils.h"
40
41/*** DOCUMENTATION
42 <function name="PJSIP_HEADER" language="en_US">
43 <synopsis>
44 Gets headers from an inbound PJSIP channel. Adds, updates or removes the
45 specified SIP header from an outbound PJSIP channel.
46 </synopsis>
47 <syntax>
48 <parameter name="action" required="true">
49 <enumlist>
50 <enum name="read"><para>Returns instance <replaceable>number</replaceable>
51 of header <replaceable>name</replaceable>. A <literal>*</literal>
52 may be appended to <replaceable>name</replaceable> to iterate over all
53 headers <emphasis>beginning with</emphasis> <replaceable>name</replaceable>.
54 </para></enum>
55
56 <enum name="add"><para>Adds a new header <replaceable>name</replaceable>
57 to this session.</para></enum>
58
59 <enum name="update"><para>Updates instance <replaceable>number</replaceable>
60 of header <replaceable>name</replaceable> to a new value.
61 The header must already exist.</para></enum>
62
63 <enum name="remove"><para>Removes all instances of previously added headers
64 whose names match <replaceable>name</replaceable>. A <literal>*</literal>
65 may be appended to <replaceable>name</replaceable> to remove all headers
66 <emphasis>beginning with</emphasis> <replaceable>name</replaceable>.
67 <replaceable>name</replaceable> may be set to a single <literal>*</literal>
68 to clear <emphasis>all</emphasis> previously added headers. In all cases,
69 the number of headers actually removed is returned.</para></enum>
70 </enumlist>
71 </parameter>
72
73 <parameter name="name" required="true"><para>The name of the header.</para></parameter>
74
75 <parameter name="number" required="false">
76 <para>If there's more than 1 header with the same name, this specifies which header
77 to read or update. If not specified, defaults to <literal>1</literal> meaning
78 the first matching header. Not valid for <literal>add</literal> or
79 <literal>remove</literal>.</para>
80 </parameter>
81
82 </syntax>
83 <description>
84 <para>PJSIP_HEADER allows you to read specific SIP headers from the inbound
85 PJSIP channel as well as write(add, update, remove) headers on the outbound
86 channel. One exception is that you can read headers that you have already
87 added on the outbound channel.</para>
88 <para>Examples:</para>
89 <example title="Set somevar to the value of the From header">
90 exten => 1,1,Set(somevar=${PJSIP_HEADER(read,From)})
91 </example>
92 <example title="Set via2 to the value of the 2nd Via header">
93 exten => 1,1,Set(via2=${PJSIP_HEADER(read,Via,2)})
94 </example>
95 <example title="Set xhdr to the value of the 1st X-header">
96 exten => 1,1,Set(xhdr=${PJSIP_HEADER(read,X-*,1)})
97 </example>
98 <example title="Add an X-Myheader header with the value of myvalue">
99 exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)
100 </example>
101 <example title="Add an X-Myheader header with an empty value">
102 exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=)
103 </example>
104 <example title="Update the value of the header named X-Myheader to newvalue">
105 ; 'X-Myheader' must already exist or the call will fail.
106 exten => 1,1,Set(PJSIP_HEADER(update,X-MyHeader)=newvalue)
107 </example>
108 <example title="Remove all headers whose names exactly match X-MyHeader">
109 exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)
110 </example>
111 <example title="Remove all headers that begin with X-My">
112 exten => 1,1,Set(PJSIP_HEADER(remove,X-My*)=)
113 </example>
114 <example title="Remove all previously added headers">
115 exten => 1,1,Set(PJSIP_HEADER(remove,*)=)
116 </example>
117 <note><para>The <literal>remove</literal> action can be called by reading
118 <emphasis>or</emphasis> writing PJSIP_HEADER.</para></note>
119 <example title="Display the number of headers removed">
120 exten => 1,1,Verbose( Removed ${PJSIP_HEADER(remove,X-MyHeader)} headers)
121 </example>
122 <example title="Set a variable to the number of headers removed">
123 exten => 1,1,Set(count=${PJSIP_HEADER(remove,X-MyHeader)})
124 </example>
125 <example title="Just remove them ignoring any count">
126 exten => 1,1,Set(=${PJSIP_HEADER(remove,X-MyHeader)})
127 exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)
128 </example>
129
130 <note><para>If you call PJSIP_HEADER in a normal dialplan context you'll be
131 operating on the <emphasis>caller's (incoming)</emphasis> channel which
132 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
133 channel call PJSIP_HEADER in a pre-dial handler. </para></note>
134 <example title="Set headers on callee channel">
135 [handler]
136 exten => addheader,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)
137 exten => addheader,2,Set(PJSIP_HEADER(add,X-MyHeader2)=myvalue2)
138
139 [somecontext]
140 exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1))
141 </example>
142 </description>
143 </function>
144 <function name="PJSIP_HEADERS" language="en_US">
145 <since>
146 <version>16.20.0</version>
147 <version>18.6.0</version>
148 <version>19.0.0</version>
149 </since>
150 <synopsis>
151 Gets the list of SIP header names from an INVITE message.
152 </synopsis>
153 <syntax>
154 <parameter name="prefix">
155 <para>If specified, only the headers matching the given prefix are returned.</para>
156 </parameter>
157 </syntax>
158 <description>
159 <para>Returns a comma-separated list of header names (without values) from the
160 INVITE message. Multiple headers with the same name are included in the list only once.
161 </para>
162 <para>For example, <literal>${PJSIP_HEADERS(Co)}</literal> might return
163 <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,
164 you may use <literal>${PJSIP_HEADERS(X-)}</literal> to enumerate optional extended
165 headers.</para>
166 </description>
167 <see-also>
168 <ref type="function">PJSIP_HEADER</ref>
169 </see-also>
170 </function>
171 <function name="PJSIP_RESPONSE_HEADER" language="en_US">
172 <synopsis>
173 Gets headers of 200 response from an outbound PJSIP channel.
174 </synopsis>
175 <syntax>
176 <parameter name="action" required="true">
177 <enumlist>
178 <enum name="read">
179 <para>Returns instance <replaceable>number</replaceable>
180 of response header <replaceable>name</replaceable>.</para>
181 </enum>
182 </enumlist>
183 </parameter>
184
185 <parameter name="name" required="true">
186 <para>The <replaceable>name</replaceable> of the response header.
187 A <literal>*</literal> can be appended to the <replaceable>name</replaceable>
188 to iterate over all response headers <emphasis>beginning with</emphasis>
189 <replaceable>name</replaceable>.</para>
190 </parameter>
191
192 <parameter name="number" required="false">
193 <para>If there's more than 1 header with the same name, this specifies which header
194 to read. If not specified, defaults to <literal>1</literal> meaning
195 the first matching header.
196 </para>
197 </parameter>
198
199 </syntax>
200 <description>
201 <para>PJSIP_RESPONSE_HEADER allows you to read specific SIP headers of 200 response
202 from the outbound PJSIP channel.</para>
203 <para>Examples:</para>
204 <example title="Set 'somevar' to the value of the 'From' header">
205 exten => 1,1,Set(somevar=${PJSIP_RESPONSE_HEADER(read,From)})
206 </example>
207 <example title="Set 'via2' to the value of the 2nd 'Via' header">
208 exten => 1,1,Set(via2=${PJSIP_RESPONSE_HEADER(read,Via,2)})
209 </example>
210 <example title="Set 'xhdr' to the value of the 1sx X-header">
211 exten => 1,1,Set(xhdr=${PJSIP_RESPONSE_HEADER(read,X-*,1)})
212 </example>
213
214 <note><para>If you call PJSIP_RESPONSE_HEADER in a normal dialplan context you'll be
215 operating on the <emphasis>caller's (incoming)</emphasis> channel which
216 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
217 channel call PJSIP_RESPONSE_HEADER in a pre-connect handler.</para>
218 </note>
219 <example title="Usage on pre-connect handler">
220 [handler]
221 exten => readheader,1,NoOp(PJSIP_RESPONSE_HEADER(read,X-MyHeader))
222 [somecontext]
223 exten => 1,1,Dial(PJSIP/${EXTEN},,U(handler^readheader^1))
224 </example>
225 </description>
226 <see-also>
227 <ref type="function">PJSIP_RESPONSE_HEADERS</ref>
228 <ref type="function">PJSIP_HEADER</ref>
229 </see-also>
230 </function>
231 <function name="PJSIP_RESPONSE_HEADERS" language="en_US">
232 <synopsis>
233 Gets the list of SIP header names from the 200 response of INVITE message.
234 </synopsis>
235 <syntax>
236 <parameter name="prefix">
237 <para>If specified, only the headers matching the given prefix are returned.</para>
238 </parameter>
239 </syntax>
240 <description>
241 <para>Returns a comma-separated list of header names (without values) from the 200
242 response of INVITE message. Multiple headers with the same name are included in the
243 list only once.</para>
244 <para>For example, <literal>${PJSIP_RESPONSE_HEADERS(Co)}</literal> might return
245 <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,
246 you may use <literal>${PJSIP_RESPONSE_HEADERS(X-)}</literal> to enumerate optional
247 extended headers.</para>
248 </description>
249 <see-also>
250 <ref type="function">PJSIP_RESPONSE_HEADER</ref>
251 <ref type="function">PJSIP_HEADERS</ref>
252 </see-also>
253 </function>
254 <function name="PJSIP_HEADER_PARAM" language="en_US">
255 <synopsis>
256 Get or set header/URI parameters on a PJSIP channel.
257 </synopsis>
258 <syntax>
259 <parameter name="header_name" required="true">
260 <para>Header in which parameter should be read or set.</para>
261 <para>Currently, the only supported header is <literal>From</literal>.</para>
262 </parameter>
263 <parameter name="parameter_type" required="true">
264 <para>The type of parameter to get or set.</para>
265 <para>Default is header parameter.</para>
266 <enumlist>
267 <enum name="header">
268 <para>Header parameter.</para>
269 </enum>
270 <enum name="uri">
271 <para>URI parameter.</para>
272 </enum>
273 </enumlist>
274 </parameter>
275 <parameter name="parameter_name" required="true">
276 <para>Name of parameter.</para>
277 </parameter>
278 </syntax>
279 <description>
280 <para>PJSIP_HEADER_PARAM allows you to read or set parameters in a SIP header on a
281 PJSIP channel.</para>
282 <para>Both URI parameters and header parameters can be read and set using
283 this function. URI parameters appear in the URI (inside the &lt;&gt; in the header)
284 while header parameters appear afterwards.</para>
285 <note><para>If you call PJSIP_HEADER_PARAM in a normal dialplan context you'll be
286 operating on the <emphasis>caller's (incoming)</emphasis> channel which
287 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
288 channel call PJSIP_HEADER_PARAM in a pre-dial handler. </para></note>
289 <example title="Set URI parameter in From header on outbound channel">
290 [handler]
291 exten => addheader,1,Set(PJSIP_HEADER_PARAM(From,uri,isup-oli)=27)
292 same => n,Return()
293 [somecontext]
294 exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1))
295 </example>
296 <example title="Read URI parameter in From header on inbound channel">
297 same => n,Set(value=${PJSIP_HEADER_PARAM(From,uri,isup-oli)})
298 </example>
299 </description>
300 </function>
301 ***/
302
303/*! \brief Linked list for accumulating headers */
305 pjsip_hdr *hdr;
307};
309
310/*! \brief Datastore for saving headers */
312 .type = "header_datastore",
313};
314/*! \brief Datastore for saving response headers */
316 .type = "response_header_datastore",
317};
318
319/*! \brief Data structure used for ast_sip_push_task_wait_serializer */
323 const char *header_value;
324 char *buf;
326 size_t len;
328};
329
330/*!
331 * \internal
332 * \brief Insert the header pointers into the linked list.
333 *
334 * For each header in the message, allocate a list entry,
335 * clone the header, then insert the entry.
336 */
337static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg)
338{
339 pjsip_hdr *hdr = msg->hdr.next;
340 struct hdr_list_entry *le;
341
342 while (hdr && hdr != &msg->hdr) {
343 le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
344 le->hdr = pjsip_hdr_clone(pool, hdr);
345 AST_LIST_INSERT_TAIL(list, le, nextptr);
346 hdr = hdr->next;
347 }
348
349 return 0;
350}
351
352/*!
353 * \internal
354 * \brief Session supplement callback on an incoming INVITE request
355 *
356 * Retrieve the header_datastore from the session or create one if it doesn't exist.
357 * Create and initialize the list if needed.
358 * Insert the headers.
359 */
360static int incoming_request(struct ast_sip_session *session, pjsip_rx_data * rdata)
361{
362 pj_pool_t *pool = session->inv_session->dlg->pool;
363 RAII_VAR(struct ast_datastore *, datastore,
365
366 if (!datastore) {
367 if (!(datastore =
369 ||
370 !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
372 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
373 return 0;
374 }
375 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
376 }
377 insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
378
379 return 0;
380}
381
382/*!
383 * \internal
384 * \brief Session supplement callback on an incoming INVITE response
385 *
386 * Retrieve the response_header_datastore from the session or create one if it doesn't exist.
387 * Create and initialize the list if needed.
388 * Insert the headers.
389 */
390static void incoming_response(struct ast_sip_session *session, pjsip_rx_data * rdata)
391{
392 pj_pool_t *pool = session->inv_session->dlg->pool;
393 RAII_VAR(struct ast_datastore *, datastore,
395 pjsip_status_line status = rdata->msg_info.msg->line.status;
396
397 /* Skip responses different of 200 OK, when 2xx is received. */
398 if (session->inv_session->state != PJSIP_INV_STATE_CONNECTING || status.code!=200) {
399 return;
400 }
401
402 if (!datastore) {
403 if (!(datastore =
405 ||
406 !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
408 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
409 return;
410 }
411 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
412 }
413 insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
414
415 return;
416}
417
418/*!
419 * \internal
420 * \brief Search list for nth occurrence of specific header.
421 */
422static pjsip_hdr *find_header(struct hdr_list *list, const char *header_name,
423 int header_number)
424{
425 struct hdr_list_entry *le;
426 pjsip_hdr *hdr = NULL;
427 int i = 1;
428
429 if (!list || ast_strlen_zero(header_name) || header_number < 1) {
430 return NULL;
431 }
432
433 AST_LIST_TRAVERSE(list, le, nextptr) {
434 if (pj_stricmp2(&le->hdr->name, header_name) == 0 && i++ == header_number) {
435 hdr = le->hdr;
436 break;
437 }
438 }
439
440 return hdr;
441}
442
443/*!
444 * \internal
445 * \brief Implements PJSIP_HEADERS/PJSIP_RESPONSE_HEADERS by searching for the requested header prefix.
446 *
447 * Retrieve the header_datastore.
448 * Search for the all matching headers.
449 * Validate the pjsip_hdr found.
450 * Parse pjsip_hdr into a name and copy to the buffer.
451 * Return the value.
452 */
453static int read_headers(void *obj)
454{
455 struct header_data *data = obj;
456 size_t len = !ast_strlen_zero(data->header_name) ? strlen(data->header_name) : 0;
457 pjsip_hdr *hdr = NULL;
458 char *pj_hdr_string;
459 int pj_hdr_string_len;
460 char *p;
461 char *pos;
462 size_t plen, wlen = 0;
463 struct hdr_list_entry *le;
464 struct hdr_list *list;
465
466 RAII_VAR(struct ast_datastore *, datastore,
469
470 if (!datastore || !datastore->data) {
471 ast_debug(1, "There was no datastore from which to read headers.\n");
472 return -1;
473 }
474
475 list = datastore->data;
476 pj_hdr_string = ast_alloca(data->len);
477 AST_LIST_TRAVERSE(list, le, nextptr) {
478 if (!len || pj_strnicmp2(&le->hdr->name, data->header_name, len) == 0) {
479 /* Found matched header, append to buf */
480 hdr = le->hdr;
481
482 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len - 1);
483 if (pj_hdr_string_len == -1) {
485 "Not enough buffer space in pjsip_hdr_print_on\n");
486 return -1;
487 }
488 pj_hdr_string[pj_hdr_string_len] = '\0';
489 p = strchr(pj_hdr_string, ':');
490 if (!p) {
492 "A malformed header was returned from pjsip_hdr_print_on\n");
493 continue;
494 }
495
496 pj_hdr_string[p - pj_hdr_string] = '\0';
497 p = ast_strip(pj_hdr_string);
498 plen = strlen(p);
499 if (wlen + plen + 1 > data->len) {
501 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
502 data->len);
503 return -1;
504 }
505 pos = strstr(data->buf, p);
506 if (pos && pos[1] == ',') {
507 if (pos == data->buf) {
508 continue;
509 } else if (pos[-1] == ',') {
510 continue;
511 }
512 }
513 ast_copy_string(data->buf + wlen, p, data->len - wlen);
514 wlen += plen;
515 ast_copy_string(data->buf + wlen, ",", data->len - wlen);
516 wlen++;
517 }
518 }
519
520 if (wlen == 0) {
521 if (!len) {
522 /* No headers at all on this channel */
523 return 0;
524 } else {
525 ast_debug(1, "There was no header beginning with %s.\n", data->header_name);
526 return -1;
527 }
528 } else {
529 data->buf[wlen-1] = '\0';
530 }
531 return 0;
532}
533
534/*!
535 * \internal
536 * \brief Implements PJSIP_HEADER/PJSIP_RESPONSE_HEADER 'read' by searching the for the requested header.
537 *
538 * Retrieve the header_datastore.
539 * Search for the nth matching header.
540 * Validate the pjsip_hdr found.
541 * Parse pjsip_hdr into a name and value.
542 * Return the value.
543 */
544static int read_header(void *obj)
545{
546 struct header_data *data = obj;
547 size_t len = strlen(data->header_name);
548 pjsip_hdr *hdr = NULL;
549 char *pj_hdr_string;
550 int pj_hdr_string_len;
551 char *p;
552 size_t plen;
553 struct hdr_list_entry *le;
554 struct hdr_list *list;
555 int i = 1;
556 RAII_VAR(struct ast_datastore *, datastore,
559
560 if (!datastore || !datastore->data) {
561 ast_debug(1, "There was no datastore from which to read headers.\n");
562 return -1;
563 }
564
565 list = datastore->data;
566 AST_LIST_TRAVERSE(list, le, nextptr) {
567 if (data->header_name[len - 1] == '*') {
568 if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0 && i++ == data->header_number) {
569 hdr = le->hdr;
570 break;
571 }
572 } else {
573 if (pj_stricmp2(&le->hdr->name, data->header_name) == 0 && i++ == data->header_number) {
574 hdr = le->hdr;
575 break;
576 }
577 }
578 }
579
580 if (!hdr) {
581 ast_debug(1, "There was no header named %s.\n", data->header_name);
582 return -1;
583 }
584
585 pj_hdr_string = ast_alloca(data->len);
586 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len - 1);
587 if (pj_hdr_string_len == -1) {
589 "Not enough buffer space in pjsip_hdr_print_on\n");
590 return -1;
591 }
592
593 pj_hdr_string[pj_hdr_string_len] = '\0';
594
595 p = strchr(pj_hdr_string, ':');
596 if (!p) {
598 "A malformed header was returned from pjsip_hdr_print_on.\n");
599 return -1;
600 }
601
602 ++p;
603 p = ast_strip(p);
604 plen = strlen(p);
605 if (plen + 1 > data->len) {
607 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
608 data->len);
609 return -1;
610 }
611
612 ast_copy_string(data->buf, p, data->len);
613
614 return 0;
615}
616
617/*!
618 * \internal
619 * \brief Implements PJSIP_HEADER 'add' by inserting the specified header into the list.
620 *
621 * Retrieve the header_datastore from the session or create one if it doesn't exist.
622 * Create and initialize the list if needed.
623 * Create the pj_strs for name and value.
624 * Create pjsip_msg and hdr_list_entry.
625 * Add the entry to the list.
626 */
627static int add_header(void *obj)
628{
629 struct header_data *data = obj;
630 struct ast_sip_session *session = data->channel->session;
631 pj_pool_t *pool = session->inv_session->dlg->pool;
632 pj_str_t pj_header_name;
633 pj_str_t pj_header_value;
634 struct hdr_list_entry *le;
635 struct hdr_list *list;
636
637 RAII_VAR(struct ast_datastore *, datastore,
639
640 if (!datastore) {
642 data->header_datastore->type))
643 || !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list)))
644 || ast_sip_session_add_datastore(session, datastore)) {
645 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
646 return -1;
647 }
648 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
649 }
650
651 ast_debug(1, "Adding header %s with value %s\n", data->header_name,
652 data->header_value);
653
654 pj_cstr(&pj_header_name, data->header_name);
655 pj_cstr(&pj_header_value, data->header_value);
656 le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
657 le->hdr = (pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name,
658 &pj_header_value);
659 list = datastore->data;
660
661 AST_LIST_INSERT_TAIL(list, le, nextptr);
662
663 return 0;
664}
665
666/*!
667 * \internal
668 * \brief Implements PJSIP_HEADER 'update' by finding the specified header and updating it.
669 *
670 * Retrieve the header_datastore from the session or create one if it doesn't exist.
671 * Create and initialize the list if needed.
672 * Create the pj_strs for name and value.
673 * Create pjsip_msg and hdr_list_entry.
674 * Add the entry to the list.
675 */
676static int update_header(void *obj)
677{
678 struct header_data *data = obj;
679 pj_pool_t *pool = data->channel->session->inv_session->dlg->pool;
680 pjsip_hdr *hdr = NULL;
681 RAII_VAR(struct ast_datastore *, datastore,
684
685 if (!datastore || !datastore->data) {
686 ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
687 return -1;
688 }
689
690 hdr = find_header((struct hdr_list *) datastore->data, data->header_name,
691 data->header_number);
692
693 if (!hdr) {
694 ast_log(AST_LOG_ERROR, "There was no header named %s.\n", data->header_name);
695 return -1;
696 }
697
698 pj_strdup2(pool, &((pjsip_generic_string_hdr *) hdr)->hvalue, data->header_value);
699
700 return 0;
701}
702
703/*!
704 * \internal
705 * \brief Implements PJSIP_HEADER 'remove' by finding the specified header and removing it.
706 *
707 * Retrieve the header_datastore from the session. Fail if it doesn't exist.
708 * If the header_name is exactly '*', the entire list is simply destroyed.
709 * Otherwise search the list for the matching header name which may be a partial name.
710 */
711static int remove_header(void *obj)
712{
713 struct header_data *data = obj;
714 size_t len = strlen(data->header_name);
715 struct hdr_list *list;
716 struct hdr_list_entry *le;
717 int removed_count = 0;
718 RAII_VAR(struct ast_datastore *, datastore,
721
722 if (!datastore || !datastore->data) {
723 ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
724 return -1;
725 }
726
727 list = datastore->data;
729 if (data->header_name[len - 1] == '*') {
730 if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0) {
732 removed_count++;
733 }
734 } else {
735 if (pj_stricmp2(&le->hdr->name, data->header_name) == 0) {
737 removed_count++;
738 }
739 }
740 }
742
743 if (data->buf && data->len) {
744 snprintf(data->buf, data->len, "%d", removed_count);
745 }
746
747 return 0;
748}
749
750/*!
751 * \brief Read list of unique SIP headers
752 */
753static int func_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
754{
755 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
758 AST_APP_ARG(header_pattern);
759 );
761
762 if (!chan || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
763 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
764 return -1;
765 }
766
768 header_data.header_name = args.header_pattern;
773
775
776}
777
778/*!
779 * \brief Read list of unique SIP response headers
780 */
781static int func_response_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
782{
783 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
786 AST_APP_ARG(header_pattern);
787 );
789
790 if (!chan || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
791 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
792 return -1;
793 }
794
795 if (ast_strlen_zero(args.header_pattern)) {
796 ast_log(AST_LOG_ERROR, "This function requires a pattern.\n");
797 return -1;
798 }
799
801 header_data.header_name = args.header_pattern;
806
808
809}
810
811/*!
812 * \brief Implements PJSIP_HEADER function 'read' callback.
813 *
814 * Valid actions are 'read' and 'remove'.
815 */
816static int func_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
817{
818 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
820 int number;
822 AST_APP_ARG(action);
825
826 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
827 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
828 return -1;
829 }
830
831 if (ast_strlen_zero(args.action)) {
832 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
833 return -1;
834 }
835 if (ast_strlen_zero(args.header_name)) {
836 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
837 return -1;
838 }
839 if (!args.header_number) {
840 number = 1;
841 } else {
842 sscanf(args.header_number, "%30d", &number);
843 if (number < 1) {
844 number = 1;
845 }
846 }
847
849 header_data.header_name = args.header_name;
855
856 if (!strcasecmp(args.action, "read")) {
858 } else if (!strcasecmp(args.action, "remove")) {
861 } else {
863 "Unknown action '%s' is not valid, must be 'read' or 'remove'.\n",
864 args.action);
865 return -1;
866 }
867}
868
869/*!
870 * \brief Implements PJSIP_RESPONSE_HEADER function 'read' callback.
871 *
872 * Valid actions are 'read'
873 */
874static int func_response_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
875{
876 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
878 int number;
880 AST_APP_ARG(action);
883
884 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
885 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
886 return -1;
887 }
888
889 if (ast_strlen_zero(args.action)) {
890 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
891 return -1;
892 }
893 if (ast_strlen_zero(args.header_name)) {
894 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
895 return -1;
896 }
897 if (!args.header_number) {
898 number = 1;
899 } else {
900 sscanf(args.header_number, "%30d", &number);
901 if (number < 1) {
902 number = 1;
903 }
904 }
905
907 header_data.header_name = args.header_name;
913
914 if (!strcasecmp(args.action, "read")) {
916 } else {
918 "Unknown action '%s' is not valid, must be 'read'.\n",
919 args.action);
920 return -1;
921 }
922}
923
924/*!
925 * \brief Implements PJSIP_HEADER function 'write' callback.
926 *
927 * Valid actions are 'add', 'update' and 'remove'.
928 */
929static int func_write_header(struct ast_channel *chan, const char *cmd, char *data,
930 const char *value)
931{
932 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
934 int header_number;
936 AST_APP_ARG(action);
939
940 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
941 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
942 return -1;
943 }
944
945 if (ast_strlen_zero(args.action)) {
946 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
947 return -1;
948 }
949 if (ast_strlen_zero(args.header_name)) {
950 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
951 return -1;
952 }
953 if (!args.header_number) {
954 header_number = 1;
955 } else {
956 sscanf(args.header_number, "%30d", &header_number);
957 if (header_number < 1) {
958 header_number = 1;
959 }
960 }
961
963 header_data.header_name = args.header_name;
967 header_data.len = 0;
969
970 if (!strcasecmp(args.action, "add")) {
973 } else if (!strcasecmp(args.action, "update")) {
976 } else if (!strcasecmp(args.action, "remove")) {
979 } else {
981 "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n",
982 args.action);
983 return -1;
984 }
985}
986
988 .name = "PJSIP_HEADER",
989 .read = func_read_header,
990 .write = func_write_header,
991};
992
994 .name = "PJSIP_HEADERS",
995 .read = func_read_headers
996};
997
999 .name = "PJSIP_RESPONSE_HEADER",
1001};
1002
1004 .name = "PJSIP_RESPONSE_HEADERS",
1006};
1007
1008/*!
1009 * \internal
1010 * \brief Session supplement callback for outgoing INVITE requests
1011 *
1012 * Retrieve the header_datastore from the session.
1013 * Add each header in the list to the outgoing message.
1014 *
1015 * These pjsip_hdr structures will have been created by add_header.
1016 * Because outgoing_request may be called more than once with the same header
1017 * list (as in the case of an authentication exchange), each pjsip_hdr structure
1018 * MUST be newly cloned for each outgoing message.
1019 */
1020static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data * tdata)
1021{
1022 struct hdr_list *list;
1023 struct hdr_list_entry *le;
1024 RAII_VAR(struct ast_datastore *, datastore,
1026
1027 if (!datastore || !datastore->data ||
1028 (session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED)) {
1029 return;
1030 }
1031
1032 list = datastore->data;
1033 AST_LIST_TRAVERSE(list, le, nextptr) {
1034 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) pjsip_hdr_clone(tdata->pool, le->hdr));
1035 }
1037}
1038
1040 .method = "INVITE",
1041 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
1042 .incoming_request = incoming_request,
1043 .outgoing_request = outgoing_request,
1044 .incoming_response = incoming_response,
1045};
1046
1050};
1051
1056 const char *param_value; /* Only used for write */
1058 /* For read function only */
1059 char *buf;
1060 size_t len;
1061};
1062
1063static int read_param(void *obj)
1064{
1065 struct param_data *data = obj;
1066 struct ast_sip_session *session = data->channel->session;
1067 pj_str_t param_name;
1068
1069 pjsip_fromto_hdr *dlg_info;
1070 pjsip_name_addr *dlg_info_name_addr;
1071 pjsip_sip_uri *dlg_info_uri;
1072 pjsip_param *param;
1073 size_t param_len;
1074
1075 dlg_info = session->inv_session->dlg->remote.info; /* Remote dialog for incoming */
1076 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1077 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1078
1079 pj_cstr(&param_name, data->param_name);
1080
1081 if (data->paramtype == PARAMETER_URI) { /* URI parameter */
1082 param = pjsip_param_find(&dlg_info_uri->other_param, &param_name);
1083 } else { /* Header parameter */
1084 param = pjsip_param_find(&dlg_info->other_param, &param_name);
1085 }
1086
1087 if (!param) {
1088 ast_debug(1, "No %s parameter found named %s\n",
1089 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name);
1090 return -1;
1091 }
1092
1093 param_len = pj_strlen(&param->value);
1094 if (param_len >= data->len) {
1095 ast_log(LOG_ERROR, "Buffer is too small for parameter value (%zu > %zu)\n", param_len, data->len);
1096 return -1;
1097 }
1098
1099 ast_debug(2, "Successfully read %s parameter %s (length %zu)\n",
1100 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, param_len);
1101 if (param_len) {
1102 ast_copy_string(data->buf, pj_strbuf(&param->value), data->len);
1103 }
1104 data->buf[param_len] = '\0';
1105
1106 return 0;
1107}
1108
1109/*!
1110 * \internal
1111 * \brief Implements PJSIP_HEADER_PARAM 'add' by adding the specified parameter.
1112 * \note Unlike add_header, we can't add parameters in the outgoing_request callback: that's too late.
1113 * That's why we do it here and not in a callback.
1114 */
1115static int add_param(void *obj)
1116{
1117 struct param_data *data = obj;
1118 struct ast_sip_session *session = data->channel->session;
1119 pj_pool_t *pool = session->inv_session->dlg->pool;
1120
1121 pjsip_fromto_hdr *dlg_info;
1122 pjsip_name_addr *dlg_info_name_addr;
1123 pjsip_sip_uri *dlg_info_uri;
1124
1125 dlg_info = session->inv_session->dlg->local.info; /* Local for outgoing */
1126 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1127 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1128 if (!PJSIP_URI_SCHEME_IS_SIP(dlg_info_uri) && !PJSIP_URI_SCHEME_IS_SIPS(dlg_info_uri)) {
1129 ast_log(LOG_WARNING, "Non SIP/SIPS URI\n");
1130 return -1;
1131 }
1132
1133 ast_debug(1, "Adding custom %s param %s = %s\n",
1134 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, data->param_value);
1135
1136 /* This works the same as doing this in set_from_header in res_pjsip_session.c
1137 * The way that this maps to pjproject is a little confusing.
1138 * Say we have <sip:foo@bar.com;p1=abc;p2=def?h1=qrs&h2=tuv>;o1=foo;o2=bar
1139 * p1 and p2 are URI parameters.
1140 * (h1 and h2 are URI headers)
1141 * o1 and o2 are header parameters (and don't have anything to do with the URI)
1142 * In pjproject, other_param is used for adding all custom parameters.
1143 * We use the URI for URI stuff, including URI parameters, and the header directly for header parameters.
1144 */
1145
1146#define param_add(pool, list, pname, pvalue) { \
1147 pjsip_param *param; \
1148 param = PJ_POOL_ALLOC_T(pool, pjsip_param); \
1149 pj_strdup2(pool, &param->name, pname); \
1150 pj_strdup2(pool, &param->value, pvalue); \
1151 pj_list_insert_before(list, param); \
1152}
1153
1154 if (data->paramtype == PARAMETER_URI) { /* URI parameter */
1155 param_add(pool, &dlg_info_uri->other_param, data->param_name, S_OR(data->param_value, ""));
1156 } else { /* Header parameter */
1157 param_add(pool, &dlg_info->other_param, data->param_name, S_OR(data->param_value, ""));
1158 }
1159
1160 return 0;
1161}
1162
1163static int func_read_param(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
1164{
1165 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1166 struct param_data param_data;
1167
1172 );
1173
1175
1177
1178 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1179 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1180 return -1;
1181 }
1182 if (ast_strlen_zero(args.param_type)) {
1183 ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n");
1184 return -1;
1185 }
1186 if (ast_strlen_zero(args.param_name)) {
1187 ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n");
1188 return -1;
1189 }
1190
1191 /* Currently, only From is supported, but this could be extended in the future. */
1192 if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) {
1193 ast_log(LOG_WARNING, "Only the From header is currently supported\n");
1194 return -1;
1195 }
1196
1197 param_data.param_name = args.param_name;
1198 if (!strcasecmp(args.param_type, "header")) {
1200 } else if (!strcasecmp(args.param_type, "uri")) {
1202 } else {
1203 ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type);
1204 return -1;
1205 }
1206
1207 param_data.buf = buf;
1208 param_data.len = len;
1209
1211}
1212
1213static int func_write_param(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1214{
1215 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1216 struct param_data param_data;
1221 );
1222
1224
1226
1227 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1228 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1229 return -1;
1230 }
1231 if (ast_strlen_zero(args.param_type)) {
1232 ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n");
1233 return -1;
1234 }
1235 if (ast_strlen_zero(args.param_name)) {
1236 ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n");
1237 return -1;
1238 }
1239
1240 /* Currently, only From is supported, but this could be extended in the future. */
1241 if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) {
1242 ast_log(LOG_WARNING, "Only the From header is currently supported\n");
1243 return -1;
1244 }
1245
1246 param_data.param_name = args.param_name;
1247 if (!strcasecmp(args.param_type, "header")) {
1249 } else if (!strcasecmp(args.param_type, "uri")) {
1251 } else {
1252 ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type);
1253 return -1;
1254 }
1256
1258}
1259
1261 .name = "PJSIP_HEADER_PARAM",
1262 .read = func_read_param,
1263 .write = func_write_param,
1264};
1265
1266static int load_module(void)
1267{
1274
1276}
1277
1278static int unload_module(void)
1279{
1286 return 0;
1287}
1288
1290 .support_level = AST_MODULE_SUPPORT_CORE,
1291 .load = load_module,
1292 .unload = unload_module,
1293 .load_pri = AST_MODPRI_APP_DEPEND,
1294 .requires = "res_pjsip,res_pjsip_session",
jack_status_t status
Definition: app_jack.c:146
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
Definition: astmm.h:288
#define ast_log
Definition: astobj2.c:42
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
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)
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
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.
Definition: res_pjsip.c:2179
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.
#define AST_LOG_WARNING
#define AST_LOG_ERROR
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:681
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
Definition: linkedlists.h:225
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
Asterisk module definitions.
@ AST_MODFLAG_LOAD_ORDER
Definition: module.h:331
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
Definition: module.h:557
@ AST_MODPRI_APP_DEPEND
Definition: module.h:342
@ AST_MODULE_SUPPORT_CORE
Definition: module.h:121
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
Core PBX routines and definitions.
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1558
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition: res_pjsip.h:3185
static struct ast_custom_function pjsip_header_function
static int read_headers(void *obj)
static struct ast_custom_function pjsip_response_headers_function
static const struct ast_datastore_info response_header_datastore
Datastore for saving response headers.
static void incoming_response(struct ast_sip_session *session, pjsip_rx_data *rdata)
@ PARAMETER_HEADER
static int add_param(void *obj)
static int incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
static int remove_header(void *obj)
static int insert_headers(pj_pool_t *pool, struct hdr_list *list, pjsip_msg *msg)
static struct ast_sip_session_supplement header_funcs_supplement
static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
static struct ast_custom_function pjsip_header_param_function
static pjsip_hdr * find_header(struct hdr_list *list, const char *header_name, int header_number)
static int add_header(void *obj)
static int func_write_param(struct ast_channel *chan, const char *cmd, char *data, const char *value)
static int func_read_param(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
static struct ast_custom_function pjsip_response_header_function
static int read_param(void *obj)
static struct ast_custom_function pjsip_headers_function
static int func_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Implements PJSIP_HEADER function 'read' callback.
static int func_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Read list of unique SIP headers.
static int load_module(void)
#define param_add(pool, list, pname, pvalue)
static int unload_module(void)
static const struct ast_datastore_info header_datastore
Datastore for saving headers.
static int func_write_header(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Implements PJSIP_HEADER function 'write' callback.
static int read_header(void *obj)
static int func_response_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Implements PJSIP_RESPONSE_HEADER function 'read' callback.
static int update_header(void *obj)
static int func_response_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Read list of unique SIP response headers.
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.
Definition: pjsip_session.c:63
#define NULL
Definition: resample.c:96
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:223
Main Channel structure associated with a channel.
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
const char * name
Definition: pbx.h:119
Structure for a data store type.
Definition: datastore.h:31
const char * type
Definition: datastore.h:32
Structure for a data store object.
Definition: datastore.h:64
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
A supplement to SIP message processing.
A structure describing a SIP session.
struct pjsip_inv_session * inv_session
struct ast_taskprocessor * serializer
Linked list for accumulating headers.
pjsip_hdr * hdr
struct hdr_list_entry::@457 nextptr
Data structure used for ast_sip_push_task_wait_serializer
struct ast_sip_channel_pvt * channel
const struct ast_datastore_info * header_datastore
const char * header_value
Number structure.
Definition: app_followme.c:154
enum param_type paramtype
struct ast_sip_channel_pvt * channel
const char * param_value
int value
Definition: syslog.c:37
const char * args
Utility functions.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941