Asterisk - The Open Source Telephony Project GIT-master-4f2b068
Loading...
Searching...
No Matches
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_INHERITABLE_HEADER" language="en_US">
148 <since>
149 <version>20.19.0</version>
150 <version>22.9.0</version>
151 <version>23.3.0</version>
152 </since>
153 <synopsis>
154 Adds, updates or removes the specified SIP header from a PJSIP or non-PJSIP channel
155 to be inherited to an outbound PJSIP channel.
156 </synopsis>
157 <syntax>
158 <parameter name="action" required="true">
159 <enumlist>
160
161 <enum name="add"><para>Adds a new header <replaceable>name</replaceable>
162 to this channel.</para></enum>
163
164 <enum name="update"><para>Updates instance <replaceable>number</replaceable>
165 of header <replaceable>name</replaceable> to a new value.
166 The header must already exist.</para></enum>
167
168 <enum name="remove"><para>Removes all instances of previously added headers
169 whose names match <replaceable>name</replaceable>. A <literal>*</literal>
170 may be appended to <replaceable>name</replaceable> to remove all headers
171 <emphasis>beginning with</emphasis> <replaceable>name</replaceable>.
172 <replaceable>name</replaceable> may be set to a single <literal>*</literal>
173 to clear <emphasis>all</emphasis> previously added headers. In all cases,
174 the number of headers actually removed is returned.</para></enum>
175 </enumlist>
176 </parameter>
177
178 <parameter name="name" required="true"><para>The name of the header.</para></parameter>
179
180 <parameter name="number" required="false">
181 <para>If there's more than 1 header with the same name, this specifies which header
182 to read or update. If not specified, defaults to <literal>1</literal> meaning
183 the first matching header. Not valid for <literal>add</literal> or
184 <literal>remove</literal>.</para>
185 </parameter>
186
187 </syntax>
188 <description>
189 <para>PJSIP_INHERITABLE_HEADER allows you to write specific SIP headers on a calling
190 channel to be inherited by an outbound PJSIP channel.</para>
191 <para>Examples:</para>
192 <example title="Add an inheritable X-Myheader header with the value of myvalue">
193 exten => 1,1,Set(PJSIP_INHERITABLE_HEADER(add,X-MyHeader)=myvalue)
194 </example>
195 <example title="Add an inheritable X-Myheader header with an empty value">
196 exten => 1,1,Set(PJSIP_INHERITABLE_HEADER(add,X-MyHeader)=)
197 </example>
198 <example title="Add an inheritable X-MyHeader that will be inherited by child channel">
199 exten => 1,1,Set(PJSIP_INHERITABLE_HEADER(add,X-MyHeader)=myvalue)
200 </example>
201 <example title="Update the value of the inheritable header named X-Myheader to newvalue">
202 ; 'X-Myheader' must already exist or the call will fail.
203 exten => 1,1,Set(PJSIP_INHERITABLE_HEADER(update,X-MyHeader)=newvalue)
204 </example>
205 <example title="Remove all inheritable headers whose names exactly match X-MyHeader">
206 exten => 1,1,Set(PJSIP_INHERITABLE_HEADER(remove,X-MyHeader)=)
207 </example>
208 <example title="Remove all inheritable headers that begin with X-My">
209 exten => 1,1,Set(PJSIP_INHERITABLE_HEADER(remove,X-My*)=)
210 </example>
211
212 <note><para>If you call PJSIP_INHERITABLE_HEADER in a normal dialplan context you'll be
213 operating on the <emphasis>caller's</emphasis> channel which
214 will then be inherited to the <emphasis>callee's (outgoing)</emphasis>
215 channel. Inherited headers can be updated or removed via PJSIP_INHERITABLE_HEADER
216 in a pre-dial handler. </para>
217 <para>Headers added via PJSIP_INHERITABLE_HEADER are separate from headers
218 added via PJSIP_HEADER. A header added via PJSIP_INHERITABLE_HEADER can only
219 be or removed modified by PJSIP_INHERITABLE_HEADER. A header added via
220 PJSIP_HEADER can only be modified or removed by PJSIP_HEADER.</para></note>
221 <example title="Set and modify headers on callee channel">
222 [handler]
223 exten => modheader,1,Set(PJSIP_INHERITABLE_HEADER(update,X-MyHeader)=myvalue)
224 same => n,Set(PJSIP_INHERITABLE_HEADER(update,X-MyHeader2)=myvalueX)
225 same => n,Set(PJSIP_INHERITABLE_HEADER(remove,X-MyHeader2)=)
226
227 [somecontext]
228 exten => 1,1,Set(PJSIP_INHERITABLE_HEADER(add,X-MyHeader1)=myvalue1)
229 same => n,Set(PJSIP_INHERITABLE_HEADER(add,X-MyHeader2)=myvalue2)
230 same => n,Set(PJSIP_INHERITABLE_HEADER(add,X-MyHeader3)=myvalue3)
231 same => n,Dial(PJSIP/${EXTEN},,b(handler^modheader^1))
232 </example>
233 </description>
234 </function>
235 <function name="PJSIP_HEADERS" language="en_US">
236 <since>
237 <version>16.20.0</version>
238 <version>18.6.0</version>
239 </since>
240 <synopsis>
241 Gets the list of SIP header names from an INVITE message.
242 </synopsis>
243 <syntax>
244 <parameter name="prefix">
245 <para>If specified, only the headers matching the given prefix are returned.</para>
246 </parameter>
247 </syntax>
248 <description>
249 <para>Returns a comma-separated list of header names (without values) from the
250 INVITE message. Multiple headers with the same name are included in the list only once.
251 </para>
252 <para>For example, <literal>${PJSIP_HEADERS(Co)}</literal> might return
253 <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,
254 you may use <literal>${PJSIP_HEADERS(X-)}</literal> to enumerate optional extended
255 headers.</para>
256 </description>
257 <see-also>
258 <ref type="function">PJSIP_HEADER</ref>
259 </see-also>
260 </function>
261 <function name="PJSIP_RESPONSE_HEADER" language="en_US">
262 <since>
263 <version>16.28.0</version>
264 <version>18.14.0</version>
265 <version>19.6.0</version>
266 </since>
267 <synopsis>
268 Gets headers of 200 response from an outbound PJSIP channel.
269 </synopsis>
270 <syntax>
271 <parameter name="action" required="true">
272 <enumlist>
273 <enum name="read">
274 <para>Returns instance <replaceable>number</replaceable>
275 of response header <replaceable>name</replaceable>.</para>
276 </enum>
277 </enumlist>
278 </parameter>
279
280 <parameter name="name" required="true">
281 <para>The <replaceable>name</replaceable> of the response header.
282 A <literal>*</literal> can be appended to the <replaceable>name</replaceable>
283 to iterate over all response headers <emphasis>beginning with</emphasis>
284 <replaceable>name</replaceable>.</para>
285 </parameter>
286
287 <parameter name="number" required="false">
288 <para>If there's more than 1 header with the same name, this specifies which header
289 to read. If not specified, defaults to <literal>1</literal> meaning
290 the first matching header.
291 </para>
292 </parameter>
293
294 </syntax>
295 <description>
296 <para>PJSIP_RESPONSE_HEADER allows you to read specific SIP headers of 200 response
297 from the outbound PJSIP channel.</para>
298 <para>Examples:</para>
299 <example title="Set 'somevar' to the value of the 'From' header">
300 exten => 1,1,Set(somevar=${PJSIP_RESPONSE_HEADER(read,From)})
301 </example>
302 <example title="Set 'via2' to the value of the 2nd 'Via' header">
303 exten => 1,1,Set(via2=${PJSIP_RESPONSE_HEADER(read,Via,2)})
304 </example>
305 <example title="Set 'xhdr' to the value of the 1sx X-header">
306 exten => 1,1,Set(xhdr=${PJSIP_RESPONSE_HEADER(read,X-*,1)})
307 </example>
308
309 <note><para>If you call PJSIP_RESPONSE_HEADER in a normal dialplan context you'll be
310 operating on the <emphasis>caller's (incoming)</emphasis> channel which
311 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
312 channel call PJSIP_RESPONSE_HEADER in a pre-connect handler.</para>
313 </note>
314 <example title="Usage on pre-connect handler">
315 [handler]
316 exten => readheader,1,NoOp(PJSIP_RESPONSE_HEADER(read,X-MyHeader))
317 [somecontext]
318 exten => 1,1,Dial(PJSIP/${EXTEN},,U(handler^readheader^1))
319 </example>
320 </description>
321 <see-also>
322 <ref type="function">PJSIP_RESPONSE_HEADERS</ref>
323 <ref type="function">PJSIP_HEADER</ref>
324 </see-also>
325 </function>
326 <function name="PJSIP_RESPONSE_HEADERS" language="en_US">
327 <since>
328 <version>16.28.0</version>
329 <version>18.14.0</version>
330 <version>19.6.0</version>
331 </since>
332 <synopsis>
333 Gets the list of SIP header names from the 200 response of INVITE message.
334 </synopsis>
335 <syntax>
336 <parameter name="prefix">
337 <para>If specified, only the headers matching the given prefix are returned.</para>
338 </parameter>
339 </syntax>
340 <description>
341 <para>Returns a comma-separated list of header names (without values) from the 200
342 response of INVITE message. Multiple headers with the same name are included in the
343 list only once.</para>
344 <para>For example, <literal>${PJSIP_RESPONSE_HEADERS(Co)}</literal> might return
345 <literal>Contact,Content-Length,Content-Type</literal>. As a practical example,
346 you may use <literal>${PJSIP_RESPONSE_HEADERS(X-)}</literal> to enumerate optional
347 extended headers.</para>
348 </description>
349 <see-also>
350 <ref type="function">PJSIP_RESPONSE_HEADER</ref>
351 <ref type="function">PJSIP_HEADERS</ref>
352 </see-also>
353 </function>
354 <function name="PJSIP_HEADER_PARAM" language="en_US">
355 <since>
356 <version>18.16.0</version>
357 <version>20.1.0</version>
358 </since>
359 <synopsis>
360 Get or set header/URI parameters on a PJSIP channel.
361 </synopsis>
362 <syntax>
363 <parameter name="header_name" required="true">
364 <para>Header in which parameter should be read or set.</para>
365 <para>Currently, the only supported header is <literal>From</literal>.</para>
366 </parameter>
367 <parameter name="parameter_type" required="true">
368 <para>The type of parameter to get or set.</para>
369 <para>Default is header parameter.</para>
370 <enumlist>
371 <enum name="header">
372 <para>Header parameter.</para>
373 </enum>
374 <enum name="uri">
375 <para>URI parameter.</para>
376 </enum>
377 </enumlist>
378 </parameter>
379 <parameter name="parameter_name" required="true">
380 <para>Name of parameter.</para>
381 </parameter>
382 </syntax>
383 <description>
384 <para>PJSIP_HEADER_PARAM allows you to read or set parameters in a SIP header on a
385 PJSIP channel.</para>
386 <para>Both URI parameters and header parameters can be read and set using
387 this function. URI parameters appear in the URI (inside the &lt;&gt; in the header)
388 while header parameters appear afterwards.</para>
389 <note><para>If you call PJSIP_HEADER_PARAM in a normal dialplan context you'll be
390 operating on the <emphasis>caller's (incoming)</emphasis> channel which
391 may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
392 channel call PJSIP_HEADER_PARAM in a pre-dial handler. </para></note>
393 <example title="Set URI parameter in From header on outbound channel">
394 [handler]
395 exten => addheader,1,Set(PJSIP_HEADER_PARAM(From,uri,isup-oli)=27)
396 same => n,Return()
397 [somecontext]
398 exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1))
399 </example>
400 <example title="Read URI parameter in From header on inbound channel">
401 same => n,Set(value=${PJSIP_HEADER_PARAM(From,uri,isup-oli)})
402 </example>
403 </description>
404 </function>
405 ***/
406
407/*! \brief Linked list for accumulating headers */
413
414/*!
415 * \internal
416 * \brief Duplicate an inheritable headers list for inheritance
417 *
418 * Creates copies of the name-value pairs for inheritance to child channels.
419 */
420static void *inheritable_headers_duplicate(void *data)
421{
422 return ast_variables_dup(data);
423}
424
425/*!
426 * \internal
427 * \brief Destroy callback for inherited header datastore
428 */
429static void inheritable_headers_destroy(void *data)
430{
432}
433
434/*! \brief Datastore for saving headers in session (contains hdr_list, no destroy needed) */
436 .type = "session_header_datastore",
437 /* No destroy or duplicate callback - data is pool-allocated hdr_list */
438};
439
440/*! \brief Datastore for saving inheritable headers (contains hdr_list with ast_malloc'd entries) */
442 .type = "inheritable_header_datastore",
445};
446
447/*! \brief Datastore for saving response headers */
449 .type = "response_header_datastore",
450};
451
452/*! \brief Data structure used for ast_sip_push_task_wait_serializer */
462
463/*!
464 * \internal
465 * \brief Insert the header pointers into the linked list.
466 *
467 * For each header in the message, allocate a list entry,
468 * clone the header, then insert the entry.
469 */
470static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg)
471{
472 pjsip_hdr *hdr = msg->hdr.next;
473 struct hdr_list_entry *le;
474
475 while (hdr && hdr != &msg->hdr) {
476 le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
477 le->hdr = pjsip_hdr_clone(pool, hdr);
478 AST_LIST_INSERT_TAIL(list, le, nextptr);
479 hdr = hdr->next;
480 }
481
482 return 0;
483}
484
485/*!
486 * \internal
487 * \brief Session supplement callback on an incoming INVITE request
488 *
489 * Retrieve the header_datastore from the session or create one if it doesn't exist.
490 * Create and initialize the list if needed.
491 * Insert the headers.
492 */
493static int incoming_request(struct ast_sip_session *session, pjsip_rx_data * rdata)
494{
495 pj_pool_t *pool = session->inv_session->dlg->pool;
496 RAII_VAR(struct ast_datastore *, datastore,
498
499 if (!datastore) {
500 if (!(datastore =
502 ||
503 !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
505 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
506 return 0;
507 }
508 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
509 }
510 insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
511
512 return 0;
513}
514
515/*!
516 * \internal
517 * \brief Session supplement callback on an incoming INVITE response
518 *
519 * Retrieve the response_header_datastore from the session or create one if it doesn't exist.
520 * Create and initialize the list if needed.
521 * Insert the headers.
522 */
523static void incoming_response(struct ast_sip_session *session, pjsip_rx_data * rdata)
524{
525 pj_pool_t *pool = session->inv_session->dlg->pool;
526 RAII_VAR(struct ast_datastore *, datastore,
528 pjsip_status_line status = rdata->msg_info.msg->line.status;
529
530 /* Skip responses different of 200 OK, when 2xx is received. */
531 if (session->inv_session->state != PJSIP_INV_STATE_CONNECTING || status.code!=200) {
532 return;
533 }
534
535 if (!datastore) {
536 if (!(datastore =
538 ||
539 !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
541 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
542 return;
543 }
544 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
545 }
546 insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
547
548 return;
549}
550
551/*!
552 * \internal
553 * \brief Search list for nth occurrence of specific header.
554 */
555static pjsip_hdr *find_header(struct hdr_list *list, const char *header_name,
556 int header_number)
557{
558 struct hdr_list_entry *le;
559 pjsip_hdr *hdr = NULL;
560 int i = 1;
561
562 if (!list || ast_strlen_zero(header_name) || header_number < 1) {
563 return NULL;
564 }
565
566 AST_LIST_TRAVERSE(list, le, nextptr) {
567 if (pj_stricmp2(&le->hdr->name, header_name) == 0 && i++ == header_number) {
568 hdr = le->hdr;
569 break;
570 }
571 }
572
573 return hdr;
574}
575
576/*!
577 * \internal
578 * \brief Implements PJSIP_HEADERS/PJSIP_RESPONSE_HEADERS by searching for the requested header prefix.
579 *
580 * Retrieve the header_datastore.
581 * Search for the all matching headers.
582 * Validate the pjsip_hdr found.
583 * Parse pjsip_hdr into a name and copy to the buffer.
584 * Return the value.
585 */
586static int read_headers(void *obj)
587{
588 struct header_data *data = obj;
589 size_t len = !ast_strlen_zero(data->header_name) ? strlen(data->header_name) : 0;
590 pjsip_hdr *hdr = NULL;
591 char *pj_hdr_string;
592 int pj_hdr_string_len;
593 char *p;
594 char *pos;
595 size_t plen, wlen = 0;
596 struct hdr_list_entry *le;
597 struct hdr_list *list;
598
599 RAII_VAR(struct ast_datastore *, datastore,
602
603 if (!datastore || !datastore->data) {
604 ast_debug(1, "There was no datastore from which to read headers.\n");
605 return -1;
606 }
607
608 list = datastore->data;
609 pj_hdr_string = ast_alloca(data->len);
610 AST_LIST_TRAVERSE(list, le, nextptr) {
611 if (!len || pj_strnicmp2(&le->hdr->name, data->header_name, len) == 0) {
612 /* Found matched header, append to buf */
613 hdr = le->hdr;
614
615 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len - 1);
616 if (pj_hdr_string_len == -1) {
618 "Not enough buffer space in pjsip_hdr_print_on\n");
619 return -1;
620 }
621 pj_hdr_string[pj_hdr_string_len] = '\0';
622 p = strchr(pj_hdr_string, ':');
623 if (!p) {
625 "A malformed header was returned from pjsip_hdr_print_on\n");
626 continue;
627 }
628
629 pj_hdr_string[p - pj_hdr_string] = '\0';
630 p = ast_strip(pj_hdr_string);
631 plen = strlen(p);
632 if (wlen + plen + 1 > data->len) {
634 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
635 data->len);
636 return -1;
637 }
638 pos = strstr(data->buf, p);
639 if (pos && pos[1] == ',') {
640 if (pos == data->buf) {
641 continue;
642 } else if (pos[-1] == ',') {
643 continue;
644 }
645 }
646 ast_copy_string(data->buf + wlen, p, data->len - wlen);
647 wlen += plen;
648 ast_copy_string(data->buf + wlen, ",", data->len - wlen);
649 wlen++;
650 }
651 }
652
653 if (wlen == 0) {
654 if (!len) {
655 /* No headers at all on this channel */
656 return 0;
657 } else {
658 ast_debug(1, "There was no header beginning with %s.\n", data->header_name);
659 return -1;
660 }
661 } else {
662 data->buf[wlen-1] = '\0';
663 }
664 return 0;
665}
666
667/*!
668 * \internal
669 * \brief Implements PJSIP_HEADER/PJSIP_RESPONSE_HEADER 'read' by searching the for the requested header.
670 *
671 * Retrieve the header_datastore.
672 * Search for the nth matching header.
673 * Validate the pjsip_hdr found.
674 * Parse pjsip_hdr into a name and value.
675 * Return the value.
676 */
677static int read_header(void *obj)
678{
679 struct header_data *data = obj;
680 size_t len = strlen(data->header_name);
681 pjsip_hdr *hdr = NULL;
682 char *pj_hdr_string;
683 int pj_hdr_string_len;
684 char *p;
685 size_t plen;
686 struct hdr_list_entry *le;
687 struct hdr_list *list;
688 int i = 1;
689 RAII_VAR(struct ast_datastore *, datastore,
692
693 if (!datastore || !datastore->data) {
694 ast_debug(1, "There was no datastore from which to read headers.\n");
695 return -1;
696 }
697
698 list = datastore->data;
699 AST_LIST_TRAVERSE(list, le, nextptr) {
700 if (len >= 1 && data->header_name[len - 1] == '*') {
701 if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0 && i++ == data->header_number) {
702 hdr = le->hdr;
703 break;
704 }
705 } else {
706 if (pj_stricmp2(&le->hdr->name, data->header_name) == 0 && i++ == data->header_number) {
707 hdr = le->hdr;
708 break;
709 }
710 }
711 }
712
713 if (!hdr) {
714 ast_debug(1, "There was no header named %s.\n", data->header_name);
715 return -1;
716 }
717
718 pj_hdr_string = ast_alloca(data->len);
719 pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len - 1);
720 if (pj_hdr_string_len == -1) {
722 "Not enough buffer space in pjsip_hdr_print_on\n");
723 return -1;
724 }
725
726 pj_hdr_string[pj_hdr_string_len] = '\0';
727
728 p = strchr(pj_hdr_string, ':');
729 if (!p) {
731 "A malformed header was returned from pjsip_hdr_print_on.\n");
732 return -1;
733 }
734
735 ++p;
736 p = ast_strip(p);
737 plen = strlen(p);
738 if (plen + 1 > data->len) {
740 "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
741 data->len);
742 return -1;
743 }
744
745 ast_copy_string(data->buf, p, data->len);
746
747 return 0;
748}
749
750/*!
751 * \internal
752 * \brief Implements PJSIP_HEADER 'add' by inserting the specified header into the list.
753 *
754 * Retrieve the header_datastore from the session or create one if it doesn't exist.
755 * Create and initialize the list if needed.
756 * Create the pj_strs for name and value.
757 * Create pjsip_msg and hdr_list_entry.
758 * Add the entry to the list.
759 */
760static int add_header(void *obj)
761{
762 struct header_data *data = obj;
763 struct ast_sip_session *session = data->channel->session;
764 pj_pool_t *pool = session->inv_session->dlg->pool;
765 pj_str_t pj_header_name;
766 pj_str_t pj_header_value;
767 struct hdr_list_entry *le;
768 struct hdr_list *list;
769
770 RAII_VAR(struct ast_datastore *, datastore,
772
773 if (!datastore) {
776 || !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list)))
777 || ast_sip_session_add_datastore(session, datastore)) {
778 ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
779 return -1;
780 }
781 AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
782 }
783
784 ast_debug(1, "Adding header %s with value %s\n", data->header_name,
785 data->header_value);
786
787 pj_cstr(&pj_header_name, data->header_name);
788 pj_cstr(&pj_header_value, data->header_value);
789 le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
790 le->hdr = (pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name,
791 &pj_header_value);
792 list = datastore->data;
793
794 AST_LIST_INSERT_TAIL(list, le, nextptr);
795
796 return 0;
797}
798
799
800/*!
801 * \internal
802 * \brief Implements PJSIP_INHERITABLE_HEADER 'add' by inserting the specified header into the channel datastore.
803 *
804 * Retrieve the inheritable channel header_datastore from the session or create one if it doesn't exist.
805 * Create and initialize the list if needed.
806 * Create the pj_strs for name and value.
807 * Create pjsip_msg and hdr_list_entry.
808 * Add the entry to the list.
809 * Locks the channel to protect the channel datastore.
810 */
811static int add_inheritable_header(struct ast_channel *channel, const char *header_name, const char *header_value)
812{
813 struct ast_variable *headers = NULL;
814
815 /* Add to channel datastore to be inherited by bridged channel(s) */
816 struct ast_datastore *chan_datastore;
817 struct ast_variable *new_var;
818
819 ast_channel_lock(channel);
821 ast_debug(3, "Adding inheritable header %s with value %s to channel %s\n", header_name,
822 header_value, ast_channel_name(channel));
823
824 if (!chan_datastore) {
825 /* Create new channel datastore */
828 if (chan_datastore) {
829 chan_datastore->data = NULL;
830 chan_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
831 ast_channel_datastore_add(channel, chan_datastore);
832 ast_debug(3, "Created new inheritable SIP header channel datastore for channel %s\n",
833 ast_channel_name(channel));
834 } else {
835 ast_log(LOG_ERROR, "Failed to allocate channel datastore for channel %s to store inheritable SIP headers\n",
836 ast_channel_name(channel));
837 ast_channel_unlock(channel);
838 return -1;
839 }
840 } else {
841 /* Ensure it's marked as inheritable */
842 if (!chan_datastore->inheritance) {
843 chan_datastore->inheritance = DATASTORE_INHERIT_FOREVER;
844 ast_debug(3, "Upgraded SIP header channel datastore to inheritable for channel %s\n",
845 ast_channel_name(channel));
846 }
847 }
848
849 /* Add THIS header to the channel datastore */
850 headers = chan_datastore->data;
851 new_var = ast_variable_new(header_name, header_value, "");
852 if (!new_var) {
853 ast_log(LOG_ERROR, "Failed to allocate variable for channel %s to store inheritable SIP headers\n",
854 ast_channel_name(channel));
855 ast_channel_unlock(channel);
856 return -1;
857 }
858
859 /* Prepend to list */
860 new_var->next = headers;
861 chan_datastore->data = new_var;
862
863 ast_debug(1, "Inherited Header %s added with value %s for channel %s\n",
864 header_name, header_value, ast_channel_name(channel));
865
866 ast_channel_unlock(channel);
867
868 return 0;
869}
870
871/*!
872 * \internal
873 * \brief Implements PJSIP_HEADER 'update' by finding the specified header and updating it.
874 *
875 * Retrieve the header_datastore from the session or create one if it doesn't exist.
876 * Create and initialize the list if needed.
877 * Create the pj_strs for name and value.
878 * Create pjsip_msg and hdr_list_entry.
879 * Add the entry to the list.
880 */
881static int update_header(void *obj)
882{
883 struct header_data *data = obj;
884 pj_pool_t *pool = data->channel->session->inv_session->dlg->pool;
885 pjsip_hdr *hdr = NULL;
886 RAII_VAR(struct ast_datastore *, datastore,
889
890 ast_debug(3, "Attempting to update header %s for channel %p\n", data->header_name,
891 data->channel->session->channel ? ast_channel_name(data->channel->session->channel) : "(none)");
892
893 if (!datastore || !datastore->data) {
894 ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
895 return -1;
896 }
897
898 hdr = find_header((struct hdr_list *) datastore->data, data->header_name,
899 data->header_number);
900
901 if (!hdr) {
902 ast_log(AST_LOG_ERROR, "There was no header named %s.\n", data->header_name);
903 return -1;
904 }
905
906 ast_debug(3, "Found header %s in session datastore, updating value to %s for channel %p\n",
907 data->header_name, data->header_value,
908 data->channel->session->channel ? ast_channel_name(data->channel->session->channel) : "(none)");
909 pj_strdup2(pool, &((pjsip_generic_string_hdr *) hdr)->hvalue, data->header_value);
910
911 return 0;
912}
913
914/*!
915 * \internal
916 * \brief Implements PJSIP_INHERITABLE_HEADER 'update' by finding the specified header and updating it.
917 *
918 * Retrieve the header_datastore from the session or create one if it doesn't exist.
919 * Create and initialize the list if needed.
920 * Create the pj_strs for name and value.
921 * Create pjsip_msg and hdr_list_entry.
922 * Add the entry to the list.
923 * Locks the channel to protect the channel datastore.
924 */
925static int update_inheritable_header(struct ast_channel *channel, const char *header_name, const char *header_value, int header_number)
926{
927 struct ast_datastore *inherited_datastore;
928 struct ast_variable *headers = NULL;
929 struct ast_variable *var, *prev = NULL;
930 int i = 1, num_matching_headers = 0, target_header_index;
931
932 ast_channel_lock(channel);
933 inherited_datastore = ast_channel_datastore_find(channel, &inheritable_header_datastore, NULL);
934 ast_debug(3, "Attempting to update header %s for channel %s\n", header_name,
935 ast_channel_name(channel));
936
937 if (!inherited_datastore || !inherited_datastore->data) {
938 ast_log(AST_LOG_ERROR, "No inheritable headers had been previously added to this channel.\n");
939 ast_channel_unlock(channel);
940 return -1;
941 }
942
943 headers = inherited_datastore->data;
944
945 /* The headers are in reverse order so we need to find out how many there are to know which one to update */
946 for (var = headers; var; var = var->next) {
947 if (strcasecmp(var->name, header_name) == 0) {
948 num_matching_headers++;
949 }
950 }
951
952 /* As we already counted the matching headers, we can skip walking the list again if the count is 0 or
953 is less than the requested header number */
954 if (num_matching_headers == 0) {
955 ast_log(AST_LOG_ERROR, "There was no header named %s on channel %s.\n", header_name,
956 ast_channel_name(channel));
957 ast_channel_unlock(channel);
958 return -1;
959 } else if (num_matching_headers < header_number) {
960 ast_log(AST_LOG_ERROR, "There were only %d headers named %s on channel %s, cannot update header number %d.\n",
961 num_matching_headers, header_name, ast_channel_name(channel), header_number);
962 ast_channel_unlock(channel);
963 return -1;
964 }
965
966 target_header_index = num_matching_headers - header_number + 1;
967 /* Search for the header in the inherited list */
968 for (var = headers; var; var = var->next) {
969 if (strcasecmp(var->name, header_name) == 0 && i++ == target_header_index) {
970 /* Found the header, create a new one with the new value and free the old */
971 struct ast_variable *new_var = ast_variable_new(header_name, header_value, "");
972 if (!new_var) {
973 ast_log(AST_LOG_ERROR, "Failed to allocate variable for updated header for channel %s\n",
974 ast_channel_name(channel));
975 ast_channel_unlock(channel);
976 return -1;
977 }
978
979 new_var->next = var->next;
980
981 if (var == headers) {
982 /* If we're updating the first header in the list, we need to update the head pointer */
983 inherited_datastore->data = new_var;
984 } else if (prev) {
985 /* Otherwise, we need to link the previous header to the new header */
986 prev->next = new_var;
987 }
988
989 var->next = NULL;
991
992 ast_debug(3, "Updated header %s with new value %s for channel %s\n",
993 header_name, header_value, ast_channel_name(channel));
994 ast_channel_unlock(channel);
995 return 0;
996 }
997 prev = var;
998 }
999
1000 /* We should never get here*/
1001 ast_log(AST_LOG_ERROR, "Unable to update header %s on channel %s.\n", header_name,
1002 ast_channel_name(channel));
1003 ast_channel_unlock(channel);
1004 return -1;
1005}
1006
1007/*!
1008 * \internal
1009 * \brief Implements PJSIP_HEADER 'remove' by finding the specified header and removing it.
1010 *
1011 * Retrieve the header_datastore from the session. Fail if it doesn't exist.
1012 * If the header_name is exactly '*', the entire list is simply destroyed.
1013 * Otherwise search the list for the matching header name which may be a partial name.
1014 */
1015static int remove_header(void *obj)
1016{
1017 struct header_data *data = obj;
1018 size_t len = strlen(data->header_name);
1019 struct hdr_list *list;
1020 struct hdr_list_entry *le;
1021 int removed_count = 0;
1022 RAII_VAR(struct ast_datastore *, datastore,
1024 ao2_cleanup);
1025
1026 ast_debug(3, "Attempting to remove header %s from channel %p\n", data->header_name,
1027 data->channel->session->channel ? ast_channel_name(data->channel->session->channel) : "(none)");
1028
1029 if (!datastore || !datastore->data) {
1030 ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
1031 return -1;
1032 }
1033
1034 list = datastore->data;
1036 if (len >= 1 && data->header_name[len - 1] == '*') {
1037 if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0) {
1038 ast_debug(3, "Found wildcard match, removing header %.*s from channel %p\n",
1039 (int)le->hdr->name.slen, le->hdr->name.ptr,
1040 data->channel->session->channel ? ast_channel_name(data->channel->session->channel) : "(none)");
1042 removed_count++;
1043 }
1044 } else {
1045 if (pj_stricmp2(&le->hdr->name, data->header_name) == 0) {
1046 ast_debug(3, "Found exact match, removing header %.*s from channel %p\n",
1047 (int)le->hdr->name.slen, le->hdr->name.ptr,
1048 data->channel->session->channel ? ast_channel_name(data->channel->session->channel) : "(none)");
1050 removed_count++;
1051 }
1052 }
1053 }
1055
1056 if (removed_count == 0) {
1057 ast_debug(3, "No headers named %s found to remove on channel %s.\n", data->header_name,
1058 data->channel->session->channel ? ast_channel_name(data->channel->session->channel) : "(none)");
1059 }
1060
1061 if (data->buf && data->len) {
1062 snprintf(data->buf, data->len, "%d", removed_count);
1063 ast_debug(3, "Removed %d headers matching %s from channel %s\n", removed_count, data->header_name,
1064 data->channel->session->channel ? ast_channel_name(data->channel->session->channel) : "(none)");
1065 }
1066
1067 return 0;
1068}
1069
1070/*!
1071 * \internal
1072 * \brief Implements PJSIP_INHERITABLE_HEADER 'remove' by finding the specified header and removing it.
1073 *
1074 * Retrieve the header_datastore from the session. Fail if it doesn't exist.
1075 * If the header_name is exactly '*', the entire list is simply destroyed.
1076 * Otherwise search the list for the matching header name which may be a partial name.
1077 * Locks the channel to protect the channel datastore.
1078 */
1079static int remove_inheritable_header(struct ast_channel *channel, const char *header_name)
1080{
1081 size_t len = strlen(header_name);
1082 struct ast_variable *headers = NULL;
1083 struct ast_variable *var, *prev = NULL;
1084 int removed_count = 0;
1085 struct ast_datastore *inherited_datastore;
1086
1087 ast_channel_lock(channel);
1088 inherited_datastore = ast_channel_datastore_find(channel, &inheritable_header_datastore, NULL);
1089 ast_debug(3, "Attempting to remove header %s from channel %s\n",
1090 header_name, ast_channel_name(channel));
1091
1092 /* Remove from inherited datastore */
1093 if (!inherited_datastore || !inherited_datastore->data) {
1094 ast_log(AST_LOG_ERROR, "No inheritable headers had been previously added to channel %s.\n",
1095 ast_channel_name(channel));
1096 ast_channel_unlock(channel);
1097 return -1;
1098 }
1099
1100 headers = inherited_datastore->data;
1101
1102 /* If removing all headers */
1103 if (strcmp(header_name, "*") == 0) {
1105 inherited_datastore->data = NULL;
1106 ast_debug(3, "Removed all inheritable headers from channel %s\n",
1107 ast_channel_name(channel));
1108 ast_channel_unlock(channel);
1109 return 0;
1110 }
1111
1112 /* Remove specific headers (exact match or wildcard) */
1113 var = headers;
1114 while (var) {
1115 struct ast_variable *next = var->next;
1116 int match = 0;
1117
1118 if (len >= 1 && header_name[len - 1] == '*') {
1119 /* Wildcard match */
1120 match = (strncasecmp(var->name, header_name, len - 1) == 0);
1121 if (match) {
1122 ast_debug(3, "Found wildcard match, removing header %s with value %s from channel %s\n",
1123 var->name, var->value, ast_channel_name(channel));
1124 }
1125 } else {
1126 /* Exact match */
1127 match = (strcasecmp(var->name, header_name) == 0);
1128 if (match) {
1129 ast_debug(3, "Found exact match, removing header %s with value %s from channel %s\n",
1130 var->name, var->value, ast_channel_name(channel));
1131 }
1132 }
1133
1134 if (match) {
1135 /* Remove this variable */
1136 if (var == headers) {
1137 /* If we're removing the first header in the list, we need to update the head pointer */
1138 headers = next;
1139 inherited_datastore->data = headers;
1140 } else if (prev) {
1141 /* Otherwise, we need to link the previous header to the next header */
1142 prev->next = next;
1143 }
1144
1145 /* destroy the variable */
1146 var->next = NULL;
1148 removed_count++;
1149 var = next;
1150 } else {
1151 prev = var;
1152 var = next;
1153 }
1154 }
1155
1156 /* Update datastore with new list head */
1157 inherited_datastore->data = headers;
1158
1159 if (removed_count == 0) {
1160 ast_debug(3, "No headers matching %s found for channel %s\n",
1161 header_name, ast_channel_name(channel));
1162 }
1163
1164 ast_debug(3, "Removed %d headers matching %s from channel %s\n", removed_count, header_name,
1165 ast_channel_name(channel));
1166
1167 ast_channel_unlock(channel);
1168 return 0;
1169}
1170
1171/*!
1172 * \brief Read list of unique SIP headers
1173 */
1174static int func_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
1175{
1176 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1177 struct header_data header_data;
1179 AST_APP_ARG(header_pattern);
1180 );
1182
1183 if (!chan || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1184 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1185 return -1;
1186 }
1187
1189 header_data.header_name = args.header_pattern;
1194
1196
1197}
1198
1199/*!
1200 * \brief Read list of unique SIP response headers
1201 */
1202static int func_response_read_headers(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
1203{
1204 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1205 struct header_data header_data;
1207 AST_APP_ARG(header_pattern);
1208 );
1210
1211 if (!chan || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1212 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1213 return -1;
1214 }
1215
1216 if (ast_strlen_zero(args.header_pattern)) {
1217 ast_log(AST_LOG_ERROR, "This function requires a pattern.\n");
1218 return -1;
1219 }
1220
1222 header_data.header_name = args.header_pattern;
1227
1229
1230}
1231
1232/*!
1233 * \brief Implements PJSIP_HEADER function 'read' callback.
1234 *
1235 * Valid actions are 'read' and 'remove'.
1236 */
1237static int func_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
1238{
1239 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1240 struct header_data header_data;
1241 int number;
1243 AST_APP_ARG(action);
1246
1247 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1248 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1249 return -1;
1250 }
1251
1252 if (ast_strlen_zero(args.action)) {
1253 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
1254 return -1;
1255 }
1256 if (ast_strlen_zero(args.header_name)) {
1257 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
1258 return -1;
1259 }
1260 if (!args.header_number) {
1261 number = 1;
1262 } else {
1263 sscanf(args.header_number, "%30d", &number);
1264 if (number < 1) {
1265 number = 1;
1266 }
1267 }
1268
1270 header_data.header_name = args.header_name;
1276
1277 if (!strcasecmp(args.action, "read")) {
1279 } else if (!strcasecmp(args.action, "remove")) {
1282 } else {
1284 "Unknown action '%s' is not valid, must be 'read' or 'remove'.\n",
1285 args.action);
1286 return -1;
1287 }
1288}
1289
1290/*!
1291 * \brief Implements PJSIP_RESPONSE_HEADER function 'read' callback.
1292 *
1293 * Valid actions are 'read'
1294 */
1295static int func_response_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
1296{
1297 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1298 struct header_data header_data;
1299 int number;
1301 AST_APP_ARG(action);
1304
1305 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1306 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1307 return -1;
1308 }
1309
1310 if (ast_strlen_zero(args.action)) {
1311 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
1312 return -1;
1313 }
1314 if (ast_strlen_zero(args.header_name)) {
1315 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
1316 return -1;
1317 }
1318 if (!args.header_number) {
1319 number = 1;
1320 } else {
1321 sscanf(args.header_number, "%30d", &number);
1322 if (number < 1) {
1323 number = 1;
1324 }
1325 }
1326
1328 header_data.header_name = args.header_name;
1334
1335 if (!strcasecmp(args.action, "read")) {
1337 } else {
1339 "Unknown action '%s' is not valid, must be 'read'.\n",
1340 args.action);
1341 return -1;
1342 }
1343}
1344
1345/*!
1346 * \brief Implements PJSIP_HEADER function 'write' callback.
1347 *
1348 * Valid actions are 'add', 'update' and 'remove'.
1349 */
1350static int func_write_header(struct ast_channel *chan, const char *cmd, char *data,
1351 const char *value)
1352{
1353 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1354 struct header_data header_data;
1355 int header_number;
1357 AST_APP_ARG(action);
1361
1362 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1363 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1364 return -1;
1365 }
1366
1367 if (ast_strlen_zero(args.action)) {
1368 ast_log(AST_LOG_ERROR, "This function requires an action.\n");
1369 return -1;
1370 }
1371 if (ast_strlen_zero(args.header_name)) {
1372 ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
1373 return -1;
1374 }
1375 if (!args.header_number) {
1376 header_number = 1;
1377 } else {
1378 sscanf(args.header_number, "%30d", &header_number);
1379 if (header_number < 1) {
1380 header_number = 1;
1381 }
1382 }
1383
1385 header_data.header_name = args.header_name;
1389 header_data.len = 0;
1391
1392 if (!strcasecmp(args.action, "add")) {
1395 } else if (!strcasecmp(args.action, "update")) {
1398 } else if (!strcasecmp(args.action, "remove")) {
1401 } else {
1403 "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n",
1404 args.action);
1405 return -1;
1406 }
1407}
1408
1409/*!
1410 * \brief Implements PJSIP_INHERITABLE_HEADER function 'write' callback.
1411 *
1412 * Valid actions are 'add', 'update' and 'remove'.
1413 */
1414static int func_write_inheritable_header(struct ast_channel *chan, const char *cmd, char *data,
1415 const char *value)
1416{
1417 int header_number;
1419 AST_APP_ARG(action);
1423
1424 if (!chan) {
1425 ast_log(LOG_ERROR, "The PJSIP_INHERITABLE_HEADER function requires a channel.\n");
1426 return -1;
1427 }
1428 if (ast_strlen_zero(args.action)) {
1429 ast_log(AST_LOG_ERROR, "The PJSIP_INHERITABLE_HEADER function requires an action.\n");
1430 return -1;
1431 }
1432 if (ast_strlen_zero(args.header_name)) {
1433 ast_log(AST_LOG_ERROR, "The PJSIP_INHERITABLE_HEADER function requires a header name.\n");
1434 return -1;
1435 }
1436 if (!args.header_number) {
1437 header_number = 1;
1438 } else {
1439 sscanf(args.header_number, "%30d", &header_number);
1440 if (header_number < 1) {
1441 header_number = 1;
1442 }
1443 }
1444
1445 /* TODO: we might want to check channel type and use the serializer if PJSIP */
1446 if (!strcasecmp(args.action, "add")) {
1447 return add_inheritable_header(chan, args.header_name, value);
1448 } else if (!strcasecmp(args.action, "update")) {
1449 return update_inheritable_header(chan, args.header_name, value, header_number);
1450 } else if (!strcasecmp(args.action, "remove")) {
1451 return remove_inheritable_header(chan, args.header_name);
1452 } else {
1454 "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n",
1455 args.action);
1456 return -1;
1457 }
1458}
1459
1461 .name = "PJSIP_HEADER",
1462 .read = func_read_header,
1463 .write = func_write_header,
1464};
1465
1467 .name = "PJSIP_INHERITABLE_HEADER",
1469};
1470
1472 .name = "PJSIP_HEADERS",
1473 .read = func_read_headers
1474};
1475
1477 .name = "PJSIP_RESPONSE_HEADER",
1479};
1480
1482 .name = "PJSIP_RESPONSE_HEADERS",
1484};
1485
1486/*!
1487 * \internal
1488 * \brief Session supplement callback for outgoing INVITE requests
1489 *
1490 * Retrieve the header_datastore from the session.
1491 * Add each header in the list to the outgoing message.
1492 *
1493 * These pjsip_hdr structures will have been created by add_header.
1494 * Because outgoing_request may be called more than once with the same header
1495 * list (as in the case of an authentication exchange), each pjsip_hdr structure
1496 * MUST be newly cloned for each outgoing message.
1497 */
1498static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data * tdata)
1499{
1500 struct hdr_list *hdr_list;
1501 struct hdr_list_entry *le;
1502 int header_count = 0;
1503 struct ast_datastore *inherited_datastore = NULL;
1504 RAII_VAR(struct ast_datastore *, session_datastore,
1506
1507 /* Check if we're past the INVITE stage */
1508 if (session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED) {
1509 ast_debug(3, "Already confirmed (state=%d)\n",
1510 session->inv_session->state);
1511 return;
1512 }
1513
1514 /* If we're UAC and have a channel, check the channel datastore for an inheritable header datastore */
1515 if (session->channel && session->inv_session->role == PJSIP_ROLE_UAC) {
1516 struct ast_datastore *chan_datastore = NULL;
1517
1518 ast_channel_lock(session->channel);
1519
1521
1522 if (chan_datastore && chan_datastore->inheritance && chan_datastore->data) {
1525
1526 if (inherited_datastore) {
1527 /* The data is in ast_variable format from the duplicate callback. We need to make our own copy to
1528 avoid sharing the pointer. Reverse the order so they appear in the INVITE in the order added. */
1529 inherited_datastore->data = ast_variables_reverse((struct ast_variable *)
1530 inheritable_headers_duplicate((struct ast_variable *) chan_datastore->data));
1531 if (inherited_datastore->data) {
1532 inherited_datastore->inheritance = chan_datastore->inheritance;
1533 ast_sip_session_add_datastore(session, inherited_datastore);
1534 } else {
1535 ast_log(LOG_ERROR, "Failed to duplicate ast_variable list for channel %s\n",
1536 session->channel ? ast_channel_name(session->channel) : "(none)");
1537 ao2_ref(inherited_datastore, -1);
1538 inherited_datastore = NULL;
1539 }
1540 } else {
1541 ast_log(LOG_ERROR, "Failed to allocate inherited session datastore for channel %s\n",
1542 session->channel ? ast_channel_name(session->channel) : "(none)");
1543 }
1544 }
1545 ast_channel_unlock(session->channel);
1546 }
1547
1548 /* If we have no datastores at all, nothing to do */
1549 if (!session_datastore && !inherited_datastore) {
1550 return;
1551 }
1552
1553 /* Add headers from regular session datastore (non-inheritable headers added on this channel) */
1554 if (session_datastore && session_datastore->data) {
1555 hdr_list = session_datastore->data;
1556 AST_LIST_TRAVERSE(hdr_list, le, nextptr) {
1557 pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) pjsip_hdr_clone(tdata->pool, le->hdr));
1558 header_count++;
1559 }
1560 ast_debug(3, "Added %d regular header(s) to channel %s\n", header_count,
1561 session->channel ? ast_channel_name(session->channel) : "(none)");
1562 /* Remove datastores after use */
1563 ast_sip_session_remove_datastore(session, session_datastore->uid);
1564 }
1565
1566 /* Add headers from inherited datastore (inheritable headers from parent channel) */
1567 if (inherited_datastore && inherited_datastore->data) {
1568 int inherited_count = 0;
1569 struct ast_variable *headers = inherited_datastore->data;
1570 struct ast_variable *var;
1571
1572 for (var = headers; var; var = var->next) {
1573 if (!ast_sip_add_header(tdata, var->name, var->value)) {
1574 inherited_count++;
1575 }
1576 }
1577 ast_debug(3, "Added %d inherited header(s) to channel %s\n", inherited_count,
1578 session->channel ? ast_channel_name(session->channel) : "(none)");
1579 header_count += inherited_count;
1580 /* Remove datastores after use */
1581 ast_sip_session_remove_datastore(session, inherited_datastore->uid);
1582 ao2_ref(inherited_datastore, -1);
1583 }
1584
1585 ast_debug(3, "Added total of %d header(s) to channel %s\n", header_count,
1586 session->channel ? ast_channel_name(session->channel) : "(none)");
1587}
1588
1590 .method = "INVITE",
1591 .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
1592 .incoming_request = incoming_request,
1593 .outgoing_request = outgoing_request,
1594 .incoming_response = incoming_response,
1595};
1596
1601
1606 const char *param_value; /* Only used for write */
1608 /* For read function only */
1609 char *buf;
1610 size_t len;
1611};
1612
1613static int read_param(void *obj)
1614{
1615 struct param_data *data = obj;
1616 struct ast_sip_session *session = data->channel->session;
1617 pj_str_t param_name;
1618
1619 pjsip_fromto_hdr *dlg_info;
1620 pjsip_name_addr *dlg_info_name_addr;
1621 pjsip_sip_uri *dlg_info_uri;
1622 pjsip_param *param;
1623 size_t param_len;
1624
1625 dlg_info = session->inv_session->dlg->remote.info; /* Remote dialog for incoming */
1626 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1627 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1628
1629 pj_cstr(&param_name, data->param_name);
1630
1631 if (data->paramtype == PARAMETER_URI) { /* URI parameter */
1632 param = pjsip_param_find(&dlg_info_uri->other_param, &param_name);
1633 } else { /* Header parameter */
1634 param = pjsip_param_find(&dlg_info->other_param, &param_name);
1635 }
1636
1637 if (!param) {
1638 ast_debug(1, "No %s parameter found named %s\n",
1639 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name);
1640 return -1;
1641 }
1642
1643 param_len = pj_strlen(&param->value);
1644 if (param_len >= data->len) {
1645 ast_log(LOG_ERROR, "Buffer is too small for parameter value (%zu > %zu)\n", param_len, data->len);
1646 return -1;
1647 }
1648
1649 ast_debug(2, "Successfully read %s parameter %s (length %zu)\n",
1650 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, param_len);
1651 if (param_len) {
1652 ast_copy_string(data->buf, pj_strbuf(&param->value), data->len);
1653 }
1654 data->buf[param_len] = '\0';
1655
1656 return 0;
1657}
1658
1659/*!
1660 * \internal
1661 * \brief Implements PJSIP_HEADER_PARAM 'add' by adding the specified parameter.
1662 * \note Unlike add_header, we can't add parameters in the outgoing_request callback: that's too late.
1663 * That's why we do it here and not in a callback.
1664 */
1665static int add_param(void *obj)
1666{
1667 struct param_data *data = obj;
1668 struct ast_sip_session *session = data->channel->session;
1669 pj_pool_t *pool = session->inv_session->dlg->pool;
1670
1671 pjsip_fromto_hdr *dlg_info;
1672 pjsip_name_addr *dlg_info_name_addr;
1673 pjsip_sip_uri *dlg_info_uri;
1674
1675 dlg_info = session->inv_session->dlg->local.info; /* Local for outgoing */
1676 dlg_info_name_addr = (pjsip_name_addr *) dlg_info->uri;
1677 dlg_info_uri = pjsip_uri_get_uri(dlg_info_name_addr);
1678 if (!PJSIP_URI_SCHEME_IS_SIP(dlg_info_uri) && !PJSIP_URI_SCHEME_IS_SIPS(dlg_info_uri)) {
1679 ast_log(LOG_WARNING, "Non SIP/SIPS URI\n");
1680 return -1;
1681 }
1682
1683 ast_debug(1, "Adding custom %s param %s = %s\n",
1684 data->paramtype == PARAMETER_URI ? "URI" : "header", data->param_name, data->param_value);
1685
1686 /* This works the same as doing this in set_from_header in res_pjsip_session.c
1687 * The way that this maps to pjproject is a little confusing.
1688 * Say we have <sip:foo@bar.com;p1=abc;p2=def?h1=qrs&h2=tuv>;o1=foo;o2=bar
1689 * p1 and p2 are URI parameters.
1690 * (h1 and h2 are URI headers)
1691 * o1 and o2 are header parameters (and don't have anything to do with the URI)
1692 * In pjproject, other_param is used for adding all custom parameters.
1693 * We use the URI for URI stuff, including URI parameters, and the header directly for header parameters.
1694 */
1695
1696#define param_add(pool, list, pname, pvalue) { \
1697 pjsip_param *param; \
1698 param = PJ_POOL_ALLOC_T(pool, pjsip_param); \
1699 pj_strdup2(pool, &param->name, pname); \
1700 pj_strdup2(pool, &param->value, pvalue); \
1701 pj_list_insert_before(list, param); \
1702}
1703
1704 if (data->paramtype == PARAMETER_URI) { /* URI parameter */
1705 param_add(pool, &dlg_info_uri->other_param, data->param_name, S_OR(data->param_value, ""));
1706 } else { /* Header parameter */
1707 param_add(pool, &dlg_info->other_param, data->param_name, S_OR(data->param_value, ""));
1708 }
1709
1710 return 0;
1711}
1712
1713static int func_read_param(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
1714{
1715 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1716 struct param_data param_data;
1717
1722 );
1723
1725
1727
1728 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1729 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1730 return -1;
1731 }
1732 if (ast_strlen_zero(args.param_type)) {
1733 ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n");
1734 return -1;
1735 }
1736 if (ast_strlen_zero(args.param_name)) {
1737 ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n");
1738 return -1;
1739 }
1740
1741 /* Currently, only From is supported, but this could be extended in the future. */
1742 if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) {
1743 ast_log(LOG_WARNING, "Only the From header is currently supported\n");
1744 return -1;
1745 }
1746
1747 param_data.param_name = args.param_name;
1748 if (!strcasecmp(args.param_type, "header")) {
1750 } else if (!strcasecmp(args.param_type, "uri")) {
1752 } else {
1753 ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type);
1754 return -1;
1755 }
1756
1757 param_data.buf = buf;
1758 param_data.len = len;
1759
1761}
1762
1763static int func_write_param(struct ast_channel *chan, const char *cmd, char *data, const char *value)
1764{
1765 struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
1766 struct param_data param_data;
1771 );
1772
1774
1776
1777 if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
1778 ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
1779 return -1;
1780 }
1781 if (ast_strlen_zero(args.param_type)) {
1782 ast_log(AST_LOG_ERROR, "This function requires a parameter type.\n");
1783 return -1;
1784 }
1785 if (ast_strlen_zero(args.param_name)) {
1786 ast_log(AST_LOG_ERROR, "This function requires a parameter name.\n");
1787 return -1;
1788 }
1789
1790 /* Currently, only From is supported, but this could be extended in the future. */
1791 if (ast_strlen_zero(args.header_name) || strcasecmp(args.header_name, "From")) {
1792 ast_log(LOG_WARNING, "Only the From header is currently supported\n");
1793 return -1;
1794 }
1795
1796 param_data.param_name = args.param_name;
1797 if (!strcasecmp(args.param_type, "header")) {
1799 } else if (!strcasecmp(args.param_type, "uri")) {
1801 } else {
1802 ast_log(LOG_WARNING, "Parameter type '%s' is invalid: must be 'header' or 'uri'\n", args.param_type);
1803 return -1;
1804 }
1806
1808}
1809
1811 .name = "PJSIP_HEADER_PARAM",
1812 .read = func_read_param,
1813 .write = func_write_param,
1814};
1815
1828
1840
1842 .support_level = AST_MODULE_SUPPORT_CORE,
1843 .load = load_module,
1844 .unload = unload_module,
1845 .load_pri = AST_MODPRI_APP_DEPEND,
1846 .requires = "res_pjsip,res_pjsip_session",
jack_status_t status
Definition app_jack.c:149
#define var
Definition ast_expr2f.c:605
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
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
static int match(struct ast_sockaddr *addr, unsigned short callno, unsigned short dcallno, const struct chan_iax2_pvt *cur, int check_dcallno)
Definition chan_iax2.c:2388
General Asterisk PBX channel definitions.
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_tech_pvt(const struct ast_channel *chan)
int ast_channel_datastore_add(struct ast_channel *chan, struct ast_datastore *datastore)
Add a datastore to a channel.
Definition channel.c:2375
#define DATASTORE_INHERIT_FOREVER
Definition channel.h:194
#define ast_channel_lock(chan)
Definition channel.h:2982
#define ast_channel_unlock(chan)
Definition channel.h:2983
struct ast_datastore * ast_channel_datastore_find(struct ast_channel *chan, const struct ast_datastore_info *info, const char *uid)
Find a datastore on a channel.
Definition channel.c:2389
#define ast_datastore_alloc(info, uid)
Definition datastore.h:85
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)
#define ast_sip_push_task_wait_serializer(serializer, sip_task, task_data)
Definition res_pjsip.h:2189
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
struct ast_variable * ast_variables_reverse(struct ast_variable *var)
Reverse a variable list.
#define ast_variable_new(name, value, filename)
struct ast_variable * ast_variables_dup(struct ast_variable *var)
Duplicate variable list.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition extconf.c:1260
#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.
#define AST_LIST_HEAD_NOLOCK(name, type)
Defines a structure to be used to hold a list of specified type (with no lock).
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Asterisk module definitions.
@ 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:1562
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
@ AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL
Definition res_pjsip.h:3364
int ast_sip_add_header(pjsip_tx_data *tdata, const char *name, const char *value)
Add a header to an outbound SIP message.
Definition res_pjsip.c:2002
static void inheritable_headers_destroy(void *data)
static void * inheritable_headers_duplicate(void *data)
static struct ast_custom_function pjsip_header_function
static int add_inheritable_header(struct ast_channel *channel, const char *header_name, const char *header_value)
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)
static int add_param(void *obj)
static int remove_inheritable_header(struct ast_channel *channel, const char *header_name)
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 const struct ast_datastore_info session_header_datastore
Datastore for saving headers in session (contains hdr_list, no destroy needed)
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_header_inherit_function
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 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 const struct ast_datastore_info inheritable_header_datastore
Datastore for saving inheritable headers (contains hdr_list with ast_malloc'd entries)
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_inheritable_header(struct ast_channel *channel, const char *header_name, const char *header_value, int header_number)
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.
static int func_write_inheritable_header(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Implements PJSIP_INHERITABLE_HEADER function 'write' callback.
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.
static struct @522 args
#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
const char * uid
Definition datastore.h:65
void * data
Definition datastore.h:66
unsigned int inheritance
Definition datastore.h:69
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
A supplement to SIP message processing.
struct ast_module *const char * method
A structure describing a SIP session.
struct ast_channel * channel
struct pjsip_inv_session * inv_session
struct ast_taskprocessor * serializer
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Linked list for accumulating headers.
pjsip_hdr * hdr
struct hdr_list_entry::@498 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.
enum param_type paramtype
struct ast_sip_channel_pvt * channel
const char * param_value
int value
Definition syslog.c:37
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:981