Asterisk - The Open Source Telephony Project GIT-master-8924258
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
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 <since>
44 <version>12.0.0</version>
45 </since>
46 <synopsis>
47 Gets headers from an inbound PJSIP channel. Adds, updates or removes the
48 specified SIP header from an outbound PJSIP channel.
49 </synopsis>
50 <syntax>
51 <parameter name="action" required="true">
52 <enumlist>
53 <enum name="read"><para>Returns instance <replaceable>number</replaceable>
54 of header <replaceable>name</replaceable>. A <literal>*</literal>
55 may be appended to <replaceable>name</replaceable> to iterate over all
56 headers <emphasis>beginning with</emphasis> <replaceable>name</replaceable>.
57 </para></enum>
58
59 <enum name="add"><para>Adds a new header <replaceable>name</replaceable>
60 to this session.</para></enum>
61
62 <enum name="update"><para>Updates instance <replaceable>number</replaceable>
63 of header <replaceable>name</replaceable> to a new value.
64 The header must already exist.</para></enum>
65
66 <enum name="remove"><para>Removes all instances of previously added headers
67 whose names match <replaceable>name</replaceable>. A <literal>*</literal>
68 may be appended to <replaceable>name</replaceable> to remove all headers
69 <emphasis>beginning with</emphasis> <replaceable>name</replaceable>.
70 <replaceable>name</replaceable> may be set to a single <literal>*</literal>
71 to clear <emphasis>all</emphasis> previously added headers. In all cases,
72 the number of headers actually removed is returned.</para></enum>
73 </enumlist>
74 </parameter>
75
76 <parameter name="name" required="true"><para>The name of the header.</para></parameter>
77
78 <parameter name="number" required="false">
79 <para>If there's more than 1 header with the same name, this specifies which header
80 to read or update. If not specified, defaults to <literal>1</literal> meaning
81 the first matching header. Not valid for <literal>add</literal> or
82 <literal>remove</literal>.</para>
83 </parameter>
84
85 </syntax>
86 <description>
87 <para>PJSIP_HEADER allows you to read specific SIP headers from the inbound
88 PJSIP channel as well as write(add, update, remove) headers on the outbound
89 channel. One exception is that you can read headers that you have already
90 added on the outbound channel.</para>
91 <para>Examples:</para>
92 <example title="Set somevar to the value of the From header">
93 exten => 1,1,Set(somevar=${PJSIP_HEADER(read,From)})
94 </example>
95 <example title="Set via2 to the value of the 2nd Via header">
96 exten => 1,1,Set(via2=${PJSIP_HEADER(read,Via,2)})
97 </example>
98 <example title="Set xhdr to the value of the 1st X-header">
99 exten => 1,1,Set(xhdr=${PJSIP_HEADER(read,X-*,1)})
100 </example>
101 <example title="Add an X-Myheader header with the value of myvalue">
102 exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)
103 </example>
104 <example title="Add an X-Myheader header with an empty value">
105 exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=)
106 </example>
107 <example title="Update the value of the header named X-Myheader to newvalue">
108 ; 'X-Myheader' must already exist or the call will fail.
109 exten => 1,1,Set(PJSIP_HEADER(update,X-MyHeader)=newvalue)
110 </example>
111 <example title="Remove all headers whose names exactly match X-MyHeader">
112 exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)
113 </example>
114 <example title="Remove all headers that begin with X-My">
115 exten => 1,1,Set(PJSIP_HEADER(remove,X-My*)=)
116 </example>
117 <example title="Remove all previously added headers">
118 exten => 1,1,Set(PJSIP_HEADER(remove,*)=)
119 </example>
120 <note><para>The <literal>remove</literal> action can be called by reading
121 <emphasis>or</emphasis> writing PJSIP_HEADER.</para></note>
122 <example title="Display the number of headers removed">
123 exten => 1,1,Verbose( Removed ${PJSIP_HEADER(remove,X-MyHeader)} headers)
124 </example>
125 <example title="Set a variable to the number of headers removed">
126 exten => 1,1,Set(count=${PJSIP_HEADER(remove,X-MyHeader)})
127 </example>
128 <example title="Just remove them ignoring any count">
129 exten => 1,1,Set(=${PJSIP_HEADER(remove,X-MyHeader)})
130 exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)
131 </example>
132
133 <note><para>If you call PJSIP_HEADER in a normal dialplan context you'll be
134 operating on the <emphasis>caller's (incoming)</emphasis> channel which
135 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
136 channel call PJSIP_HEADER in a pre-dial handler. </para></note>
137 <example title="Set headers on callee channel">
138 [handler]
139 exten => addheader,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)
140 exten => addheader,2,Set(PJSIP_HEADER(add,X-MyHeader2)=myvalue2)
141
142 [somecontext]
143 exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1))
144 </example>
145 </description>
146 </function>
147 <function name="PJSIP_HEADERS" language="en_US">
148 <since>
149 <version>16.20.0</version>
150 <version>18.6.0</version>
151 </since>
152 <synopsis>
153 Gets the list of SIP header names from an INVITE message.
154 </synopsis>
155 <syntax>
156 <parameter name="prefix">
157 <para>If specified, only the headers matching the given prefix are returned.</para>
158 </parameter>
159 </syntax>
160 <description>
161 <para>Returns a comma-separated list of header names (without values) from the
162 INVITE message. Multiple headers with the same name are included in the list only once.
163 </para>
164 <para>For example, <literal>${PJSIP_HEADERS(Co)}</literal> might return
165 <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,
166 you may use <literal>${PJSIP_HEADERS(X-)}</literal> to enumerate optional extended
167 headers.</para>
168 </description>
169 <see-also>
170 <ref type="function">PJSIP_HEADER</ref>
171 </see-also>
172 </function>
173 <function name="PJSIP_RESPONSE_HEADER" language="en_US">
174 <since>
175 <version>16.28.0</version>
176 <version>18.14.0</version>
177 <version>19.6.0</version>
178 </since>
179 <synopsis>
180 Gets headers of 200 response from an outbound PJSIP channel.
181 </synopsis>
182 <syntax>
183 <parameter name="action" required="true">
184 <enumlist>
185 <enum name="read">
186 <para>Returns instance <replaceable>number</replaceable>
187 of response header <replaceable>name</replaceable>.</para>
188 </enum>
189 </enumlist>
190 </parameter>
191
192 <parameter name="name" required="true">
193 <para>The <replaceable>name</replaceable> of the response header.
194 A <literal>*</literal> can be appended to the <replaceable>name</replaceable>
195 to iterate over all response headers <emphasis>beginning with</emphasis>
196 <replaceable>name</replaceable>.</para>
197 </parameter>
198
199 <parameter name="number" required="false">
200 <para>If there's more than 1 header with the same name, this specifies which header
201 to read. If not specified, defaults to <literal>1</literal> meaning
202 the first matching header.
203 </para>
204 </parameter>
205
206 </syntax>
207 <description>
208 <para>PJSIP_RESPONSE_HEADER allows you to read specific SIP headers of 200 response
209 from the outbound PJSIP channel.</para>
210 <para>Examples:</para>
211 <example title="Set 'somevar' to the value of the 'From' header">
212 exten => 1,1,Set(somevar=${PJSIP_RESPONSE_HEADER(read,From)})
213 </example>
214 <example title="Set 'via2' to the value of the 2nd 'Via' header">
215 exten => 1,1,Set(via2=${PJSIP_RESPONSE_HEADER(read,Via,2)})
216 </example>
217 <example title="Set 'xhdr' to the value of the 1sx X-header">
218 exten => 1,1,Set(xhdr=${PJSIP_RESPONSE_HEADER(read,X-*,1)})
219 </example>
220
221 <note><para>If you call PJSIP_RESPONSE_HEADER in a normal dialplan context you'll be
222 operating on the <emphasis>caller's (incoming)</emphasis> channel which
223 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
224 channel call PJSIP_RESPONSE_HEADER in a pre-connect handler.</para>
225 </note>
226 <example title="Usage on pre-connect handler">
227 [handler]
228 exten => readheader,1,NoOp(PJSIP_RESPONSE_HEADER(read,X-MyHeader))
229 [somecontext]
230 exten => 1,1,Dial(PJSIP/${EXTEN},,U(handler^readheader^1))
231 </example>
232 </description>
233 <see-also>
234 <ref type="function">PJSIP_RESPONSE_HEADERS</ref>
235 <ref type="function">PJSIP_HEADER</ref>
236 </see-also>
237 </function>
238 <function name="PJSIP_RESPONSE_HEADERS" language="en_US">
239 <since>
240 <version>16.28.0</version>
241 <version>18.14.0</version>
242 <version>19.6.0</version>
243 </since>
244 <synopsis>
245 Gets the list of SIP header names from the 200 response of INVITE message.
246 </synopsis>
247 <syntax>
248 <parameter name="prefix">
249 <para>If specified, only the headers matching the given prefix are returned.</para>
250 </parameter>
251 </syntax>
252 <description>
253 <para>Returns a comma-separated list of header names (without values) from the 200
254 response of INVITE message. Multiple headers with the same name are included in the
255 list only once.</para>
256 <para>For example, <literal>${PJSIP_RESPONSE_HEADERS(Co)}</literal> might return
257 <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,
258 you may use <literal>${PJSIP_RESPONSE_HEADERS(X-)}</literal> to enumerate optional
259 extended headers.</para>
260 </description>
261 <see-also>
262 <ref type="function">PJSIP_RESPONSE_HEADER</ref>
263 <ref type="function">PJSIP_HEADERS</ref>
264 </see-also>
265 </function>
266 <function name="PJSIP_HEADER_PARAM" language="en_US">
267 <since>
268 <version>18.16.0</version>
269 <version>20.1.0</version>
270 </since>
271 <synopsis>
272 Get or set header/URI parameters on a PJSIP channel.
273 </synopsis>
274 <syntax>
275 <parameter name="header_name" required="true">
276 <para>Header in which parameter should be read or set.</para>
277 <para>Currently, the only supported header is <literal>From</literal>.</para>
278 </parameter>
279 <parameter name="parameter_type" required="true">
280 <para>The type of parameter to get or set.</para>
281 <para>Default is header parameter.</para>
282 <enumlist>
283 <enum name="header">
284 <para>Header parameter.</para>
285 </enum>
286 <enum name="uri">
287 <para>URI parameter.</para>
288 </enum>
289 </enumlist>
290 </parameter>
291 <parameter name="parameter_name" required="true">
292 <para>Name of parameter.</para>
293 </parameter>
294 </syntax>
295 <description>
296 <para>PJSIP_HEADER_PARAM allows you to read or set parameters in a SIP header on a
297 PJSIP channel.</para>
298 <para>Both URI parameters and header parameters can be read and set using
299 this function. URI parameters appear in the URI (inside the &lt;&gt; in the header)
300 while header parameters appear afterwards.</para>
301 <note><para>If you call PJSIP_HEADER_PARAM in a normal dialplan context you'll be
302 operating on the <emphasis>caller's (incoming)</emphasis> channel which
303 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
304 channel call PJSIP_HEADER_PARAM in a pre-dial handler. </para></note>
305 <example title="Set URI parameter in From header on outbound channel">
306 [handler]
307 exten => addheader,1,Set(PJSIP_HEADER_PARAM(From,uri,isup-oli)=27)
308 same => n,Return()
309 [somecontext]
310 exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1))
311 </example>
312 <example title="Read URI parameter in From header on inbound channel">
313 same => n,Set(value=${PJSIP_HEADER_PARAM(From,uri,isup-oli)})
314 </example>
315 </description>
316 </function>
317 ***/
318
319/*! \brief Linked list for accumulating headers */
321 pjsip_hdr *hdr;
323};
325
326/*! \brief Datastore for saving headers */
328 .type = "header_datastore",
329};
330/*! \brief Datastore for saving response headers */
332 .type = "response_header_datastore",
333};
334
335/*! \brief Data structure used for ast_sip_push_task_wait_serializer */
339 const char *header_value;
340 char *buf;
342 size_t len;
344};
345
346/*!
347 * \internal
348 * \brief Insert the header pointers into the linked list.
349 *
350 * For each header in the message, allocate a list entry,
351 * clone the header, then insert the entry.
352 */
353static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg)
354{
355 pjsip_hdr *hdr = msg->hdr.next;
356 struct hdr_list_entry *le;
357
358 while (hdr && hdr != &msg->hdr) {
359 le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
360 le->hdr = pjsip_hdr_clone(pool, hdr);
361 AST_LIST_INSERT_TAIL(list, le, nextptr);
362 hdr = hdr->next;
363 }
364
365 return 0;
366}
367
368/*!
369 * \internal
370 * \brief Session supplement callback on an incoming INVITE request
371 *
372 * Retrieve the header_datastore from the session or create one if it doesn't exist.
373 * Create and initialize the list if needed.
374 * Insert the headers.
375 */
376static int incoming_request(struct ast_sip_session *session, pjsip_rx_data * rdata)
377{
378 pj_pool_t *pool = session->inv_session->dlg->pool;
379 RAII_VAR(struct ast_datastore *, datastore,
381
382 if (!datastore) {
383 if (!(datastore =
385 ||
386 !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
388 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
389 return 0;
390 }
391 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
392 }
393 insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
394
395 return 0;
396}
397
398/*!
399 * \internal
400 * \brief Session supplement callback on an incoming INVITE response
401 *
402 * Retrieve the response_header_datastore from the session or create one if it doesn't exist.
403 * Create and initialize the list if needed.
404 * Insert the headers.
405 */
406static void incoming_response(struct ast_sip_session *session, pjsip_rx_data * rdata)
407{
408 pj_pool_t *pool = session->inv_session->dlg->pool;
409 RAII_VAR(struct ast_datastore *, datastore,
411 pjsip_status_line status = rdata->msg_info.msg->line.status;
412
413 /* Skip responses different of 200 OK, when 2xx is received. */
414 if (session->inv_session->state != PJSIP_INV_STATE_CONNECTING || status.code!=200) {
415 return;
416 }
417
418 if (!datastore) {
419 if (!(datastore =
421 ||
422 !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
424 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
425 return;
426 }
427 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
428 }
429 insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
430
431 return;
432}
433
434/*!
435 * \internal
436 * \brief Search list for nth occurrence of specific header.
437 */
438static pjsip_hdr *find_header(struct hdr_list *list, const char *header_name,
439 int header_number)
440{
441 struct hdr_list_entry *le;
442 pjsip_hdr *hdr = NULL;
443 int i = 1;
444
445 if (!list || ast_strlen_zero(header_name) || header_number < 1) {
446 return NULL;
447 }
448
449 AST_LIST_TRAVERSE(list, le, nextptr) {
450 if (pj_stricmp2(&le->hdr->name, header_name) == 0 && i++ == header_number) {
451 hdr = le->hdr;
452 break;
453 }
454 }
455
456 return hdr;
457}
458
459/*!
460 * \internal
461 * \brief Implements PJSIP_HEADERS/PJSIP_RESPONSE_HEADERS by searching for the requested header prefix.
462 *
463 * Retrieve the header_datastore.
464 * Search for the all matching headers.
465 * Validate the pjsip_hdr found.
466 * Parse pjsip_hdr into a name and copy to the buffer.
467 * Return the value.
468 */
469static int read_headers(void *obj)
470{
471 struct header_data *data = obj;
472 size_t len = !ast_strlen_zero(data->header_name) ? strlen(data->header_name) : 0;
473 pjsip_hdr *hdr = NULL;
474 char *pj_hdr_string;
475 int pj_hdr_string_len;
476 char *p;
477 char *pos;
478 size_t plen, wlen = 0;
479 struct hdr_list_entry *le;
480 struct hdr_list *list;
481
482 RAII_VAR(struct ast_datastore *, datastore,
485
486 if (!datastore || !datastore->data) {
487 ast_debug(1, "There was no datastore from which to read headers.\n");
488 return -1;
489 }
490
491 list = datastore->data;
492 pj_hdr_string = ast_alloca(data->len);
493 AST_LIST_TRAVERSE(list, le, nextptr) {
494 if (!len || pj_strnicmp2(&le->hdr->name, data->header_name, len) == 0) {
495 /* Found matched header, append to buf */
496 hdr = le->hdr;
497
498 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len - 1);
499 if (pj_hdr_string_len == -1) {
501 "Not enough buffer space in pjsip_hdr_print_on\n");
502 return -1;
503 }
504 pj_hdr_string[pj_hdr_string_len] = '\0';
505 p = strchr(pj_hdr_string, ':');
506 if (!p) {
508 "A malformed header was returned from pjsip_hdr_print_on\n");
509 continue;
510 }
511
512 pj_hdr_string[p - pj_hdr_string] = '\0';
513 p = ast_strip(pj_hdr_string);
514 plen = strlen(p);
515 if (wlen + plen + 1 > data->len) {
517 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
518 data->len);
519 return -1;
520 }
521 pos = strstr(data->buf, p);
522 if (pos && pos[1] == ',') {
523 if (pos == data->buf) {
524 continue;
525 } else if (pos[-1] == ',') {
526 continue;
527 }
528 }
529 ast_copy_string(data->buf + wlen, p, data->len - wlen);
530 wlen += plen;
531 ast_copy_string(data->buf + wlen, ",", data->len - wlen);
532 wlen++;
533 }
534 }
535
536 if (wlen == 0) {
537 if (!len) {
538 /* No headers at all on this channel */
539 return 0;
540 } else {
541 ast_debug(1, "There was no header beginning with %s.\n", data->header_name);
542 return -1;
543 }
544 } else {
545 data->buf[wlen-1] = '\0';
546 }
547 return 0;
548}
549
550/*!
551 * \internal
552 * \brief Implements PJSIP_HEADER/PJSIP_RESPONSE_HEADER 'read' by searching the for the requested header.
553 *
554 * Retrieve the header_datastore.
555 * Search for the nth matching header.
556 * Validate the pjsip_hdr found.
557 * Parse pjsip_hdr into a name and value.
558 * Return the value.
559 */
560static int read_header(void *obj)
561{
562 struct header_data *data = obj;
563 size_t len = strlen(data->header_name);
564 pjsip_hdr *hdr = NULL;
565 char *pj_hdr_string;
566 int pj_hdr_string_len;
567 char *p;
568 size_t plen;
569 struct hdr_list_entry *le;
570 struct hdr_list *list;
571 int i = 1;
572 RAII_VAR(struct ast_datastore *, datastore,
575
576 if (!datastore || !datastore->data) {
577 ast_debug(1, "There was no datastore from which to read headers.\n");
578 return -1;
579 }
580
581 list = datastore->data;
582 AST_LIST_TRAVERSE(list, le, nextptr) {
583 if (data->header_name[len - 1] == '*') {
584 if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0 && i++ == data->header_number) {
585 hdr = le->hdr;
586 break;
587 }
588 } else {
589 if (pj_stricmp2(&le->hdr->name, data->header_name) == 0 && i++ == data->header_number) {
590 hdr = le->hdr;
591 break;
592 }
593 }
594 }
595
596 if (!hdr) {
597 ast_debug(1, "There was no header named %s.\n", data->header_name);
598 return -1;
599 }
600
601 pj_hdr_string = ast_alloca(data->len);
602 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len - 1);
603 if (pj_hdr_string_len == -1) {
605 "Not enough buffer space in pjsip_hdr_print_on\n");
606 return -1;
607 }
608
609 pj_hdr_string[pj_hdr_string_len] = '\0';
610
611 p = strchr(pj_hdr_string, ':');
612 if (!p) {
614 "A malformed header was returned from pjsip_hdr_print_on.\n");
615 return -1;
616 }
617
618 ++p;
619 p = ast_strip(p);
620 plen = strlen(p);
621 if (plen + 1 > data->len) {
623 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
624 data->len);
625 return -1;
626 }
627
628 ast_copy_string(data->buf, p, data->len);
629
630 return 0;
631}
632
633/*!
634 * \internal
635 * \brief Implements PJSIP_HEADER 'add' by inserting the specified header into the list.
636 *
637 * Retrieve the header_datastore from the session or create one if it doesn't exist.
638 * Create and initialize the list if needed.
639 * Create the pj_strs for name and value.
640 * Create pjsip_msg and hdr_list_entry.
641 * Add the entry to the list.
642 */
643static int add_header(void *obj)
644{
645 struct header_data *data = obj;
646 struct ast_sip_session *session = data->channel->session;
647 pj_pool_t *pool = session->inv_session->dlg->pool;
648 pj_str_t pj_header_name;
649 pj_str_t pj_header_value;
650 struct hdr_list_entry *le;
651 struct hdr_list *list;
652
653 RAII_VAR(struct ast_datastore *, datastore,
655
656 if (!datastore) {
658 data->header_datastore->type))
659 || !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list)))
660 || ast_sip_session_add_datastore(session, datastore)) {
661 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
662 return -1;
663 }
664 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
665 }
666
667 ast_debug(1, "Adding header %s with value %s\n", data->header_name,
668 data->header_value);
669
670 pj_cstr(&pj_header_name, data->header_name);
671 pj_cstr(&pj_header_value, data->header_value);
672 le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
673 le->hdr = (pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name,
674 &pj_header_value);
675 list = datastore->data;
676
677 AST_LIST_INSERT_TAIL(list, le, nextptr);
678
679 return 0;
680}
681
682/*!
683 * \internal
684 * \brief Implements PJSIP_HEADER 'update' by finding the specified header and updating it.
685 *
686 * Retrieve the header_datastore from the session or create one if it doesn't exist.
687 * Create and initialize the list if needed.
688 * Create the pj_strs for name and value.
689 * Create pjsip_msg and hdr_list_entry.
690 * Add the entry to the list.
691 */
692static int update_header(void *obj)
693{
694 struct header_data *data = obj;
695 pj_pool_t *pool = data->channel->session->inv_session->dlg->pool;
696 pjsip_hdr *hdr = NULL;
697 RAII_VAR(struct ast_datastore *, datastore,
700
701 if (!datastore || !datastore->data) {
702 ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
703 return -1;
704 }
705
706 hdr = find_header((struct hdr_list *) datastore->data, data->header_name,
707 data->header_number);
708
709 if (!hdr) {
710 ast_log(AST_LOG_ERROR, "There was no header named %s.\n", data->header_name);
711 return -1;
712 }
713
714 pj_strdup2(pool, &((pjsip_generic_string_hdr *) hdr)->hvalue, data->header_value);
715
716 return 0;
717}
718
719/*!
720 * \internal
721 * \brief Implements PJSIP_HEADER 'remove' by finding the specified header and removing it.
722 *
723 * Retrieve the header_datastore from the session. Fail if it doesn't exist.
724 * If the header_name is exactly '*', the entire list is simply destroyed.
725 * Otherwise search the list for the matching header name which may be a partial name.
726 */
727static int remove_header(void *obj)
728{
729 struct header_data *data = obj;
730 size_t len = strlen(data->header_name);
731 struct hdr_list *list;
732 struct hdr_list_entry *le;
733 int removed_count = 0;
734 RAII_VAR(struct ast_datastore *, datastore,
737
738 if (!datastore || !datastore->data) {
739 ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
740 return -1;
741 }
742
743 list = datastore->data;
745 if (data->header_name[len - 1] == '*') {
746 if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0) {
748 removed_count++;
749 }
750 } else {
751 if (pj_stricmp2(&le->hdr->name, data->header_name) == 0) {
753 removed_count++;
754 }
755 }
756 }
758
759 if (data->buf && data->len) {
760 snprintf(data->buf, data->len, "%d", removed_count);
761 }
762
763 return 0;
764}
765
766/*!
767 * \brief Read list of unique SIP headers
768 */
769static int func_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
770{
771 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
774 AST_APP_ARG(header_pattern);
775 );
777
778 if (!chan || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
779 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
780 return -1;
781 }
782
784 header_data.header_name = args.header_pattern;
789
791
792}
793
794/*!
795 * \brief Read list of unique SIP response headers
796 */
797static int func_response_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
798{
799 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
802 AST_APP_ARG(header_pattern);
803 );
805
806 if (!chan || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
807 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
808 return -1;
809 }
810
811 if (ast_strlen_zero(args.header_pattern)) {
812 ast_log(AST_LOG_ERROR, "This function requires a pattern.\n");
813 return -1;
814 }
815
817 header_data.header_name = args.header_pattern;
822
824
825}
826
827/*!
828 * \brief Implements PJSIP_HEADER function 'read' callback.
829 *
830 * Valid actions are 'read' and 'remove'.
831 */
832static int func_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
833{
834 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
836 int number;
838 AST_APP_ARG(action);
841
842 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
843 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
844 return -1;
845 }
846
847 if (ast_strlen_zero(args.action)) {
848 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
849 return -1;
850 }
851 if (ast_strlen_zero(args.header_name)) {
852 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
853 return -1;
854 }
855 if (!args.header_number) {
856 number = 1;
857 } else {
858 sscanf(args.header_number, "%30d", &number);
859 if (number < 1) {
860 number = 1;
861 }
862 }
863
865 header_data.header_name = args.header_name;
871
872 if (!strcasecmp(args.action, "read")) {
874 } else if (!strcasecmp(args.action, "remove")) {
877 } else {
879 "Unknown action '%s' is not valid, must be 'read' or 'remove'.\n",
880 args.action);
881 return -1;
882 }
883}
884
885/*!
886 * \brief Implements PJSIP_RESPONSE_HEADER function 'read' callback.
887 *
888 * Valid actions are 'read'
889 */
890static int func_response_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
891{
892 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
894 int number;
896 AST_APP_ARG(action);
899
900 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
901 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
902 return -1;
903 }
904
905 if (ast_strlen_zero(args.action)) {
906 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
907 return -1;
908 }
909 if (ast_strlen_zero(args.header_name)) {
910 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
911 return -1;
912 }
913 if (!args.header_number) {
914 number = 1;
915 } else {
916 sscanf(args.header_number, "%30d", &number);
917 if (number < 1) {
918 number = 1;
919 }
920 }
921
923 header_data.header_name = args.header_name;
929
930 if (!strcasecmp(args.action, "read")) {
932 } else {
934 "Unknown action '%s' is not valid, must be 'read'.\n",
935 args.action);
936 return -1;
937 }
938}
939
940/*!
941 * \brief Implements PJSIP_HEADER function 'write' callback.
942 *
943 * Valid actions are 'add', 'update' and 'remove'.
944 */
945static int func_write_header(struct ast_channel *chan, const char *cmd, char *data,
946 const char *value)
947{
948 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
950 int header_number;
952 AST_APP_ARG(action);
955
956 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
957 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
958 return -1;
959 }
960
961 if (ast_strlen_zero(args.action)) {
962 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
963 return -1;
964 }
965 if (ast_strlen_zero(args.header_name)) {
966 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
967 return -1;
968 }
969 if (!args.header_number) {
970 header_number = 1;
971 } else {
972 sscanf(args.header_number, "%30d", &header_number);
973 if (header_number < 1) {
974 header_number = 1;
975 }
976 }
977
979 header_data.header_name = args.header_name;
983 header_data.len = 0;
985
986 if (!strcasecmp(args.action, "add")) {
989 } else if (!strcasecmp(args.action, "update")) {
992 } else if (!strcasecmp(args.action, "remove")) {
995 } else {
997 "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n",
998 args.action);
999 return -1;
1000 }
1001}
1002
1004 .name = "PJSIP_HEADER",
1005 .read = func_read_header,
1006 .write = func_write_header,
1007};
1008
1010 .name = "PJSIP_HEADERS",
1011 .read = func_read_headers
1012};
1013
1015 .name = "PJSIP_RESPONSE_HEADER",
1017};
1018
1020 .name = "PJSIP_RESPONSE_HEADERS",
1022};
1023
1024/*!
1025 * \internal
1026 * \brief Session supplement callback for outgoing INVITE requests
1027 *
1028 * Retrieve the header_datastore from the session.
1029 * Add each header in the list to the outgoing message.
1030 *
1031 * These pjsip_hdr structures will have been created by add_header.
1032 * Because outgoing_request may be called more than once with the same header
1033 * list (as in the case of an authentication exchange), each pjsip_hdr structure
1034 * MUST be newly cloned for each outgoing message.
1035 */
1036static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data * tdata)
1037{
1038 struct hdr_list *list;
1039 struct hdr_list_entry *le;
1040 RAII_VAR(struct ast_datastore *, datastore,
1042
1043 if (!datastore || !datastore->data ||
1044 (session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED)) {
1045 return;
1046 }
1047
1048 list = datastore->data;
1049 AST_LIST_TRAVERSE(list, le, nextptr) {
1050 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) pjsip_hdr_clone(tdata->pool, le->hdr));
1051 }
1053}
1054
1056 .method = "INVITE",
1057 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
1058 .incoming_request = incoming_request,
1059 .outgoing_request = outgoing_request,
1060 .incoming_response = incoming_response,
1061};
1062
1066};
1067
1072 const char *param_value; /* Only used for write */
1074 /* For read function only */
1075 char *buf;
1076 size_t len;
1077};
1078
1079static int read_param(void *obj)
1080{
1081 struct param_data *data = obj;
1082 struct ast_sip_session *session = data->channel->session;
1083 pj_str_t param_name;
1084
1085 pjsip_fromto_hdr *dlg_info;
1086 pjsip_name_addr *dlg_info_name_addr;
1087 pjsip_sip_uri *dlg_info_uri;
1088 pjsip_param *param;
1089 size_t param_len;
1090
1091 dlg_info = session->inv_session->dlg->remote.info; /* Remote dialog for incoming */
1092 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1093 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1094
1095 pj_cstr(&param_name, data->param_name);
1096
1097 if (data->paramtype == PARAMETER_URI) { /* URI parameter */
1098 param = pjsip_param_find(&dlg_info_uri->other_param, &param_name);
1099 } else { /* Header parameter */
1100 param = pjsip_param_find(&dlg_info->other_param, &param_name);
1101 }
1102
1103 if (!param) {
1104 ast_debug(1, "No %s parameter found named %s\n",
1105 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name);
1106 return -1;
1107 }
1108
1109 param_len = pj_strlen(&param->value);
1110 if (param_len >= data->len) {
1111 ast_log(LOG_ERROR, "Buffer is too small for parameter value (%zu > %zu)\n", param_len, data->len);
1112 return -1;
1113 }
1114
1115 ast_debug(2, "Successfully read %s parameter %s (length %zu)\n",
1116 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, param_len);
1117 if (param_len) {
1118 ast_copy_string(data->buf, pj_strbuf(&param->value), data->len);
1119 }
1120 data->buf[param_len] = '\0';
1121
1122 return 0;
1123}
1124
1125/*!
1126 * \internal
1127 * \brief Implements PJSIP_HEADER_PARAM 'add' by adding the specified parameter.
1128 * \note Unlike add_header, we can't add parameters in the outgoing_request callback: that's too late.
1129 * That's why we do it here and not in a callback.
1130 */
1131static int add_param(void *obj)
1132{
1133 struct param_data *data = obj;
1134 struct ast_sip_session *session = data->channel->session;
1135 pj_pool_t *pool = session->inv_session->dlg->pool;
1136
1137 pjsip_fromto_hdr *dlg_info;
1138 pjsip_name_addr *dlg_info_name_addr;
1139 pjsip_sip_uri *dlg_info_uri;
1140
1141 dlg_info = session->inv_session->dlg->local.info; /* Local for outgoing */
1142 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1143 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1144 if (!PJSIP_URI_SCHEME_IS_SIP(dlg_info_uri) && !PJSIP_URI_SCHEME_IS_SIPS(dlg_info_uri)) {
1145 ast_log(LOG_WARNING, "Non SIP/SIPS URI\n");
1146 return -1;
1147 }
1148
1149 ast_debug(1, "Adding custom %s param %s = %s\n",
1150 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, data->param_value);
1151
1152 /* This works the same as doing this in set_from_header in res_pjsip_session.c
1153 * The way that this maps to pjproject is a little confusing.
1154 * Say we have <sip:foo@bar.com;p1=abc;p2=def?h1=qrs&h2=tuv>;o1=foo;o2=bar
1155 * p1 and p2 are URI parameters.
1156 * (h1 and h2 are URI headers)
1157 * o1 and o2 are header parameters (and don't have anything to do with the URI)
1158 * In pjproject, other_param is used for adding all custom parameters.
1159 * We use the URI for URI stuff, including URI parameters, and the header directly for header parameters.
1160 */
1161
1162#define param_add(pool, list, pname, pvalue) { \
1163 pjsip_param *param; \
1164 param = PJ_POOL_ALLOC_T(pool, pjsip_param); \
1165 pj_strdup2(pool, &param->name, pname); \
1166 pj_strdup2(pool, &param->value, pvalue); \
1167 pj_list_insert_before(list, param); \
1168}
1169
1170 if (data->paramtype == PARAMETER_URI) { /* URI parameter */
1171 param_add(pool, &dlg_info_uri->other_param, data->param_name, S_OR(data->param_value, ""));
1172 } else { /* Header parameter */
1173 param_add(pool, &dlg_info->other_param, data->param_name, S_OR(data->param_value, ""));
1174 }
1175
1176 return 0;
1177}
1178
1179static int func_read_param(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
1180{
1181 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1182 struct param_data param_data;
1183
1188 );
1189
1191
1193
1194 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1195 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1196 return -1;
1197 }
1198 if (ast_strlen_zero(args.param_type)) {
1199 ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n");
1200 return -1;
1201 }
1202 if (ast_strlen_zero(args.param_name)) {
1203 ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n");
1204 return -1;
1205 }
1206
1207 /* Currently, only From is supported, but this could be extended in the future. */
1208 if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) {
1209 ast_log(LOG_WARNING, "Only the From header is currently supported\n");
1210 return -1;
1211 }
1212
1213 param_data.param_name = args.param_name;
1214 if (!strcasecmp(args.param_type, "header")) {
1216 } else if (!strcasecmp(args.param_type, "uri")) {
1218 } else {
1219 ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type);
1220 return -1;
1221 }
1222
1223 param_data.buf = buf;
1224 param_data.len = len;
1225
1227}
1228
1229static int func_write_param(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1230{
1231 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1232 struct param_data param_data;
1237 );
1238
1240
1242
1243 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1244 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1245 return -1;
1246 }
1247 if (ast_strlen_zero(args.param_type)) {
1248 ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n");
1249 return -1;
1250 }
1251 if (ast_strlen_zero(args.param_name)) {
1252 ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n");
1253 return -1;
1254 }
1255
1256 /* Currently, only From is supported, but this could be extended in the future. */
1257 if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) {
1258 ast_log(LOG_WARNING, "Only the From header is currently supported\n");
1259 return -1;
1260 }
1261
1262 param_data.param_name = args.param_name;
1263 if (!strcasecmp(args.param_type, "header")) {
1265 } else if (!strcasecmp(args.param_type, "uri")) {
1267 } else {
1268 ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type);
1269 return -1;
1270 }
1272
1274}
1275
1277 .name = "PJSIP_HEADER_PARAM",
1278 .read = func_read_param,
1279 .write = func_write_param,
1280};
1281
1282static int load_module(void)
1283{
1290
1292}
1293
1294static int unload_module(void)
1295{
1302 return 0;
1303}
1304
1306 .support_level = AST_MODULE_SUPPORT_CORE,
1307 .load = load_module,
1308 .unload = unload_module,
1309 .load_pri = AST_MODPRI_APP_DEPEND,
1310 .requires = "res_pjsip,res_pjsip_session",
jack_status_t status
Definition: app_jack.c:149
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:1559
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition: res_pjsip.h:3339
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::@460 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:157
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