Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*** MODULEINFO
20  <depend>pjproject</depend>
21  <depend>res_pjsip</depend>
22  <depend>res_pjsip_session</depend>
23  <support_level>core</support_level>
24  ***/
25 
26 #include "asterisk.h"
27 
28 #include <pjsip.h>
29 #include <pjsip_ua.h>
30 
31 #include "asterisk/res_pjsip.h"
33 #include "asterisk/channel.h"
34 #include "asterisk/pbx.h"
35 #include "asterisk/app.h"
36 #include "asterisk/module.h"
37 #include "asterisk/utils.h"
38 
39 /*** DOCUMENTATION
40  <function name="PJSIP_HEADER" language="en_US">
41  <synopsis>
42  Gets headers from an inbound PJSIP channel. Adds, updates or removes the
43  specified SIP header from an outbound PJSIP channel.
44  </synopsis>
45  <syntax>
46  <parameter name="action" required="true">
47  <enumlist>
48  <enum name="read"><para>Returns instance <replaceable>number</replaceable>
49  of header <replaceable>name</replaceable>.</para></enum>
50 
51  <enum name="add"><para>Adds a new header <replaceable>name</replaceable>
52  to this session.</para></enum>
53 
54  <enum name="update"><para>Updates instance <replaceable>number</replaceable>
55  of header <replaceable>name</replaceable> to a new value.
56  The header must already exist.</para></enum>
57 
58  <enum name="remove"><para>Removes all instances of previously added headers
59  whose names match <replaceable>name</replaceable>. A <literal>*</literal>
60  may be appended to <replaceable>name</replaceable> to remove all headers
61  <emphasis>beginning with</emphasis> <replaceable>name</replaceable>.
62  <replaceable>name</replaceable> may be set to a single <literal>*</literal>
63  to clear <emphasis>all</emphasis> previously added headers. In all cases,
64  the number of headers actually removed is returned.</para></enum>
65  </enumlist>
66  </parameter>
67 
68  <parameter name="name" required="true"><para>The name of the header.</para></parameter>
69 
70  <parameter name="number" required="false">
71  <para>If there's more than 1 header with the same name, this specifies which header
72  to read or update. If not specified, defaults to <literal>1</literal> meaning
73  the first matching header. Not valid for <literal>add</literal> or
74  <literal>remove</literal>.</para>
75  </parameter>
76 
77  </syntax>
78  <description>
79  <para>PJSIP_HEADER allows you to read specific SIP headers from the inbound
80  PJSIP channel as well as write(add, update, remove) headers on the outbound
81  channel. One exception is that you can read headers that you have already
82  added on the outbound channel.</para>
83  <para>Examples:</para>
84  <para>;</para>
85  <para>; Set 'somevar' to the value of the 'From' header.</para>
86  <para>exten => 1,1,Set(somevar=${PJSIP_HEADER(read,From)})</para>
87  <para>;</para>
88  <para>; Set 'via2' to the value of the 2nd 'Via' header.</para>
89  <para>exten => 1,1,Set(via2=${PJSIP_HEADER(read,Via,2)})</para>
90  <para>;</para>
91  <para>; Add an 'X-Myheader' header with the value of 'myvalue'.</para>
92  <para>exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)</para>
93  <para>;</para>
94  <para>; Add an 'X-Myheader' header with an empty value.</para>
95  <para>exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=)</para>
96  <para>;</para>
97  <para>; Update the value of the header named 'X-Myheader' to 'newvalue'.</para>
98  <para>; 'X-Myheader' must already exist or the call will fail.</para>
99  <para>exten => 1,1,Set(PJSIP_HEADER(update,X-MyHeader)=newvalue)</para>
100  <para>;</para>
101  <para>; Remove all headers whose names exactly match 'X-MyHeader'.</para>
102  <para>exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)</para>
103  <para>;</para>
104  <para>; Remove all headers that begin with 'X-My'.</para>
105  <para>exten => 1,1,Set(PJSIP_HEADER(remove,X-My*)=)</para>
106  <para>;</para>
107  <para>; Remove all previously added headers.</para>
108  <para>exten => 1,1,Set(PJSIP_HEADER(remove,*)=)</para>
109  <para>;</para>
110 
111  <note><para>The <literal>remove</literal> action can be called by reading
112  <emphasis>or</emphasis> writing PJSIP_HEADER.</para>
113  <para>;</para>
114  <para>; Display the number of headers removed</para>
115  <para>exten => 1,1,Verbose( Removed ${PJSIP_HEADER(remove,X-MyHeader)} headers)</para>
116  <para>;</para>
117  <para>; Set a variable to the number of headers removed</para>
118  <para>exten => 1,1,Set(count=${PJSIP_HEADER(remove,X-MyHeader)})</para>
119  <para>;</para>
120  <para>; Just remove them ignoring any count</para>
121  <para>exten => 1,1,Set(=${PJSIP_HEADER(remove,X-MyHeader)})</para>
122  <para>exten => 1,1,Set(PJSIP_HEADER(remove,X-MyHeader)=)</para>
123  <para>;</para>
124  </note>
125 
126  <note><para>If you call PJSIP_HEADER in a normal dialplan context you'll be
127  operating on the <emphasis>caller's (incoming)</emphasis> channel which
128  may not be what you want. To operate on the <emphasis>callee's (outgoing)</emphasis>
129  channel call PJSIP_HEADER in a pre-dial handler. </para>
130  <para>Example:</para>
131  <para>;</para>
132  <para>[handler]</para>
133  <para>exten => addheader,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)</para>
134  <para>exten => addheader,2,Set(PJSIP_HEADER(add,X-MyHeader2)=myvalue2)</para>
135  <para>;</para>
136  <para>[somecontext]</para>
137  <para>exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1))</para>
138  <para>;</para>
139  </note>
140  </description>
141  </function>
142  ***/
143 
144 /*! \brief Linked list for accumulating headers */
146  pjsip_hdr *hdr;
148 };
150 
151 /*! \brief Datastore for saving headers */
152 static const struct ast_datastore_info header_datastore = {
153  .type = "header_datastore",
154 };
155 
156 /*! \brief Data structure used for ast_sip_push_task_wait_serializer */
157 struct header_data {
159  char *header_name;
160  const char *header_value;
161  char *buf;
163  size_t len;
164 };
165 
166 /*!
167  * \internal
168  * \brief Insert the header pointers into the linked list.
169  *
170  * For each header in the message, allocate a list entry,
171  * clone the header, then insert the entry.
172  */
173 static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg)
174 {
175  pjsip_hdr *hdr = msg->hdr.next;
176  struct hdr_list_entry *le;
177 
178  while (hdr && hdr != &msg->hdr) {
179  le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
180  le->hdr = pjsip_hdr_clone(pool, hdr);
181  AST_LIST_INSERT_TAIL(list, le, nextptr);
182  hdr = hdr->next;
183  }
184 
185  return 0;
186 }
187 
188 /*!
189  * \internal
190  * \brief Session supplement callback on an incoming INVITE request
191  *
192  * Retrieve the header_datastore from the session or create one if it doesn't exist.
193  * Create and initialize the list if needed.
194  * Insert the headers.
195  */
196 static int incoming_request(struct ast_sip_session *session, pjsip_rx_data * rdata)
197 {
198  pj_pool_t *pool = session->inv_session->dlg->pool;
199  RAII_VAR(struct ast_datastore *, datastore,
200  ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);
201 
202  if (!datastore) {
203  if (!(datastore =
204  ast_sip_session_alloc_datastore(&header_datastore, header_datastore.type))
205  ||
206  !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||
207  ast_sip_session_add_datastore(session, datastore)) {
208  ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
209  return 0;
210  }
211  AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
212  }
213  insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);
214 
215  return 0;
216 }
217 
218 /*!
219  * \internal
220  * \brief Search list for nth occurrence of specific header.
221  */
222 static pjsip_hdr *find_header(struct hdr_list *list, const char *header_name,
223  int header_number)
224 {
225  struct hdr_list_entry *le;
226  pjsip_hdr *hdr = NULL;
227  int i = 1;
228 
229  if (!list || ast_strlen_zero(header_name) || header_number < 1) {
230  return NULL;
231  }
232 
233  AST_LIST_TRAVERSE(list, le, nextptr) {
234  if (pj_stricmp2(&le->hdr->name, header_name) == 0 && i++ == header_number) {
235  hdr = le->hdr;
236  break;
237  }
238  }
239 
240  return hdr;
241 }
242 
243 
244 /*!
245  * \internal
246  * \brief Implements PJSIP_HEADER 'read' by searching the for the requested header.
247  *
248  * Retrieve the header_datastore.
249  * Search for the nth matching header.
250  * Validate the pjsip_hdr found.
251  * Parse pjsip_hdr into a name and value.
252  * Return the value.
253  */
254 static int read_header(void *obj)
255 {
256  struct header_data *data = obj;
257  pjsip_hdr *hdr = NULL;
258  char *pj_hdr_string;
259  size_t pj_hdr_string_len;
260  char *p;
261  size_t plen;
262  RAII_VAR(struct ast_datastore *, datastore,
263  ast_sip_session_get_datastore(data->channel->session, header_datastore.type),
264  ao2_cleanup);
265 
266  if (!datastore || !datastore->data) {
267  ast_debug(1, "There was no datastore from which to read headers.\n");
268  return -1;
269  }
270 
271  hdr = find_header((struct hdr_list *) datastore->data, data->header_name,
272  data->header_number);
273 
274  if (!hdr) {
275  ast_debug(1, "There was no header named %s.\n", data->header_name);
276  return -1;
277  }
278 
279  pj_hdr_string = ast_alloca(data->len);
280  pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, data->len);
281  pj_hdr_string[pj_hdr_string_len] = '\0';
282 
283  p = strchr(pj_hdr_string, ':');
284  if (!p) {
286  "A malformed header was returned from pjsip_hdr_print_on.\n");
287  return -1;
288  }
289 
290  ++p;
291  p = ast_strip(p);
292  plen = strlen(p);
293  if (plen + 1 > data->len) {
295  "Buffer isn't big enough to hold header value. %zu > %zu\n", plen + 1,
296  data->len);
297  return -1;
298  }
299 
300  ast_copy_string(data->buf, p, data->len);
301 
302  return 0;
303 }
304 
305 /*!
306  * \internal
307  * \brief Implements PJSIP_HEADER 'add' by inserting the specified header into thge list.
308  *
309  * Retrieve the header_datastore from the session or create one if it doesn't exist.
310  * Create and initialize the list if needed.
311  * Create the pj_strs for name and value.
312  * Create pjsip_msg and hdr_list_entry.
313  * Add the entry to the list.
314  */
315 static int add_header(void *obj)
316 {
317  struct header_data *data = obj;
318  struct ast_sip_session *session = data->channel->session;
319  pj_pool_t *pool = session->inv_session->dlg->pool;
320  pj_str_t pj_header_name;
321  pj_str_t pj_header_value;
322  struct hdr_list_entry *le;
323  struct hdr_list *list;
324 
325  RAII_VAR(struct ast_datastore *, datastore,
326  ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);
327 
328  if (!datastore) {
329  if (!(datastore = ast_sip_session_alloc_datastore(&header_datastore,
330  header_datastore.type))
331  || !(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list)))
332  || ast_sip_session_add_datastore(session, datastore)) {
333  ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");
334  return -1;
335  }
336  AST_LIST_HEAD_INIT_NOLOCK((struct hdr_list *) datastore->data);
337  }
338 
339  ast_debug(1, "Adding header %s with value %s\n", data->header_name,
340  data->header_value);
341 
342  pj_cstr(&pj_header_name, data->header_name);
343  pj_cstr(&pj_header_value, data->header_value);
344  le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));
345  le->hdr = (pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name,
346  &pj_header_value);
347  list = datastore->data;
348 
349  AST_LIST_INSERT_TAIL(list, le, nextptr);
350 
351  return 0;
352 }
353 
354 /*!
355  * \internal
356  * \brief Implements PJSIP_HEADER 'update' by finding the specified header and updating it.
357  *
358  * Retrieve the header_datastore from the session or create one if it doesn't exist.
359  * Create and initialize the list if needed.
360  * Create the pj_strs for name and value.
361  * Create pjsip_msg and hdr_list_entry.
362  * Add the entry to the list.
363  */
364 static int update_header(void *obj)
365 {
366  struct header_data *data = obj;
367  pjsip_hdr *hdr = NULL;
368  RAII_VAR(struct ast_datastore *, datastore,
369  ast_sip_session_get_datastore(data->channel->session, header_datastore.type),
370  ao2_cleanup);
371 
372  if (!datastore || !datastore->data) {
373  ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
374  return -1;
375  }
376 
377  hdr = find_header((struct hdr_list *) datastore->data, data->header_name,
378  data->header_number);
379 
380  if (!hdr) {
381  ast_log(AST_LOG_ERROR, "There was no header named %s.\n", data->header_name);
382  return -1;
383  }
384 
385  pj_strcpy2(&((pjsip_generic_string_hdr *) hdr)->hvalue, data->header_value);
386 
387  return 0;
388 }
389 
390 /*!
391  * \internal
392  * \brief Implements PJSIP_HEADER 'remove' by finding the specified header and removing it.
393  *
394  * Retrieve the header_datastore from the session. Fail if it doesn't exist.
395  * If the header_name is exactly '*', the entire list is simply destroyed.
396  * Otherwise search the list for the matching header name which may be a partial name.
397  */
398 static int remove_header(void *obj)
399 {
400  struct header_data *data = obj;
401  size_t len = strlen(data->header_name);
402  struct hdr_list *list;
403  struct hdr_list_entry *le;
404  int removed_count = 0;
405  RAII_VAR(struct ast_datastore *, datastore,
406  ast_sip_session_get_datastore(data->channel->session, header_datastore.type),
407  ao2_cleanup);
408 
409  if (!datastore || !datastore->data) {
410  ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");
411  return -1;
412  }
413 
414  list = datastore->data;
416  if (data->header_name[len - 1] == '*') {
417  if (pj_strnicmp2(&le->hdr->name, data->header_name, len - 1) == 0) {
419  removed_count++;
420  }
421  } else {
422  if (pj_stricmp2(&le->hdr->name, data->header_name) == 0) {
424  removed_count++;
425  }
426  }
427  }
429 
430  if (data->buf && data->len) {
431  snprintf(data->buf, data->len, "%d", removed_count);
432  }
433 
434  return 0;
435 }
436 
437 /*!
438  * \brief Implements function 'read' callback.
439  *
440  * Valid actions are 'read' and 'remove'.
441  */
442 static int func_read_header(struct ast_channel *chan, const char *function, char *data,
443  char *buf, size_t len)
444 {
445  struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
446  struct header_data header_data;
447  int number;
449  AST_APP_ARG(action);
452 
453  if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
454  ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
455  return -1;
456  }
457 
458  if (ast_strlen_zero(args.action)) {
459  ast_log(AST_LOG_ERROR, "This function requires an action.\n");
460  return -1;
461  }
462  if (ast_strlen_zero(args.header_name)) {
463  ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
464  return -1;
465  }
466  if (!args.header_number) {
467  number = 1;
468  } else {
469  sscanf(args.header_number, "%30d", &number);
470  if (number < 1) {
471  number = 1;
472  }
473  }
474 
475  header_data.channel = channel;
476  header_data.header_name = args.header_name;
477  header_data.header_number = number;
478  header_data.header_value = NULL;
479  header_data.buf = buf;
480  header_data.len = len;
481 
482  if (!strcasecmp(args.action, "read")) {
484  read_header, &header_data);
485  } else if (!strcasecmp(args.action, "remove")) {
487  remove_header, &header_data);
488  } else {
490  "Unknown action '%s' is not valid, must be 'read' or 'remove'.\n",
491  args.action);
492  return -1;
493  }
494 }
495 
496 /*!
497  * \brief Implements function 'write' callback.
498  *
499  * Valid actions are 'add', 'update' and 'remove'.
500  */
501 static int func_write_header(struct ast_channel *chan, const char *cmd, char *data,
502  const char *value)
503 {
504  struct ast_sip_channel_pvt *channel = chan ? ast_channel_tech_pvt(chan) : NULL;
505  struct header_data header_data;
506  int header_number;
508  AST_APP_ARG(action);
509  AST_APP_ARG(header_name); AST_APP_ARG(header_number););
511 
512  if (!channel || strncmp(ast_channel_name(chan), "PJSIP/", 6)) {
513  ast_log(LOG_ERROR, "This function requires a PJSIP channel.\n");
514  return -1;
515  }
516 
517  if (ast_strlen_zero(args.action)) {
518  ast_log(AST_LOG_ERROR, "This function requires an action.\n");
519  return -1;
520  }
521  if (ast_strlen_zero(args.header_name)) {
522  ast_log(AST_LOG_ERROR, "This function requires a header name.\n");
523  return -1;
524  }
525  if (!args.header_number) {
526  header_number = 1;
527  } else {
528  sscanf(args.header_number, "%30d", &header_number);
529  if (header_number < 1) {
530  header_number = 1;
531  }
532  }
533 
534  header_data.channel = channel;
535  header_data.header_name = args.header_name;
536  header_data.header_number = header_number;
537  header_data.header_value = value;
538  header_data.buf = NULL;
539  header_data.len = 0;
540 
541  if (!strcasecmp(args.action, "add")) {
543  add_header, &header_data);
544  } else if (!strcasecmp(args.action, "update")) {
546  update_header, &header_data);
547  } else if (!strcasecmp(args.action, "remove")) {
549  remove_header, &header_data);
550  } else {
552  "Unknown action '%s' is not valid, must be 'add', 'update', or 'remove'.\n",
553  args.action);
554  return -1;
555  }
556 }
557 
559  .name = "PJSIP_HEADER",
560  .read = func_read_header,
561  .write = func_write_header,
562 };
563 
564 /*!
565  * \internal
566  * \brief Session supplement callback for outgoing INVITE requests
567  *
568  * Retrieve the header_datastore from the session.
569  * Add each header in the list to the outgoing message.
570  *
571  * These pjsip_hdr structures will have been created by add_header.
572  * Because outgoing_request may be called more than once with the same header
573  * list (as in the case of an authentication exchange), each pjsip_hdr structure
574  * MUST be newly cloned for each outgoing message.
575  */
576 static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data * tdata)
577 {
578  pj_pool_t *pool = session->inv_session->dlg->pool;
579  struct hdr_list *list;
580  struct hdr_list_entry *le;
581  RAII_VAR(struct ast_datastore *, datastore,
582  ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);
583 
584  if (!datastore || !datastore->data ||
585  (session->inv_session->state >= PJSIP_INV_STATE_CONFIRMED)) {
586  return;
587  }
588 
589  list = datastore->data;
590  AST_LIST_TRAVERSE(list, le, nextptr) {
591  pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) pjsip_hdr_clone(pool, le->hdr));
592  }
593  ast_sip_session_remove_datastore(session, datastore->uid);
594 }
595 
597  .method = "INVITE",
598  .priority = AST_SIP_SUPPLEMENT_PRIORITY_CHANNEL - 1000,
599  .incoming_request = incoming_request,
600  .outgoing_request = outgoing_request,
601 };
602 
603 static int load_module(void)
604 {
605  ast_sip_session_register_supplement(&header_funcs_supplement);
606  ast_custom_function_register(&pjsip_header_function);
607 
609 }
610 
611 static int unload_module(void)
612 {
613  ast_custom_function_unregister(&pjsip_header_function);
614  ast_sip_session_unregister_supplement(&header_funcs_supplement);
615  return 0;
616 }
617 
618 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Header Functions",
619  .support_level = AST_MODULE_SUPPORT_CORE,
620  .load = load_module,
621  .unload = unload_module,
622  .load_pri = AST_MODPRI_APP_DEPEND,
623  .requires = "res_pjsip,res_pjsip_session",
624 );
const char * name
Definition: pbx.h:119
const char * type
Definition: datastore.h:32
static int unload_module(void)
Main Channel structure associated with a channel.
static int incoming_request(struct ast_sip_session *session, pjsip_rx_data *rdata)
Asterisk main include file. File version handling, generic pbx functions.
void * ast_channel_tech_pvt(const struct ast_channel *chan)
struct ast_sip_channel_pvt * channel
struct hdr_list_entry::@482 nextptr
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
static pj_pool_t * pool
Global memory pool for configuration and timers.
static int insert_headers(pj_pool_t *pool, struct hdr_list *list, pjsip_msg *msg)
Structure for a data store type.
Definition: datastore.h:31
A structure which contains a channel implementation and session.
struct ast_sip_session * session
Pointer to session.
Data structure used for ast_sip_push_task_wait_serializer.
static int func_write_header(struct ast_channel *chan, const char *cmd, char *data, const char *value)
Implements function &#39;write&#39; callback.
Definition: muted.c:95
Structure for a data store object.
Definition: datastore.h:68
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
const char * args
#define NULL
Definition: resample.c:96
int value
Definition: syslog.c:37
struct pjsip_inv_session * inv_session
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:614
A structure describing a SIP session.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
static const struct ast_datastore_info header_datastore
Datastore for saving headers.
Utility functions.
#define ast_strlen_zero(foo)
Definition: strings.h:52
Number structure.
Definition: app_followme.c:154
void ast_sip_session_remove_datastore(struct ast_sip_session *session, const char *name)
Remove a session datastore from the session.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
#define AST_LOG_ERROR
Definition: logger.h:290
General Asterisk PBX channel definitions.
static int read_header(void *obj)
struct ast_datastore * ast_sip_session_alloc_datastore(const struct ast_datastore_info *info, const char *uid)
Alternative for ast_datastore_alloc()
struct ast_datastore * ast_sip_session_get_datastore(struct ast_sip_session *session, const char *name)
Retrieve a session datastore.
#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:911
static struct ast_mansession session
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:5218
Data structure associated with a custom dialplan function.
Definition: pbx.h:118
static int remove_header(void *obj)
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:219
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:556
AST_LIST_HEAD_NOLOCK(contactliststruct, contact)
Core PBX routines and definitions.
struct ast_taskprocessor * serializer
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)
#define LOG_ERROR
Definition: logger.h:285
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:730
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:409
static pjsip_hdr * find_header(struct hdr_list *list, const char *header_name, int header_number)
static struct ast_custom_function pjsip_header_function
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
A supplement to SIP message processing.
#define AST_LIST_HEAD_INIT_NOLOCK(head)
Initializes a list head structure.
Definition: linkedlists.h:680
Linked list for accumulating headers.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
pjsip_hdr * hdr
const char * ast_channel_name(const struct ast_channel *chan)
static int update_header(void *obj)
static int func_read_header(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
Implements function &#39;read&#39; callback.
static struct ast_sip_session_supplement header_funcs_supplement
static int add_header(void *obj)
const char * header_value
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:528
static int load_module(void)
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define ast_custom_function_register(acf)
Register a custom function.
Definition: pbx.h:1508
int ast_sip_session_add_datastore(struct ast_sip_session *session, struct ast_datastore *datastore)
Add a datastore to a SIP session.
#define AST_APP_ARG(name)
Define an application argument.
#define ast_sip_session_register_supplement(supplement)