Asterisk - The Open Source Telephony Project  21.4.1
pjsip_global_headers.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Mark Michelson <mmichelson@digium.com>
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 #include "asterisk.h"
20 
21 #include <pjsip.h>
22 #include <pjlib.h>
23 
24 #include "asterisk/res_pjsip.h"
25 #include "asterisk/linkedlists.h"
26 #include "include/res_pjsip_private.h"
27 
28 static pj_status_t add_request_headers(pjsip_tx_data *tdata);
29 static pj_status_t add_response_headers(pjsip_tx_data *tdata);
30 
31 /*!
32  * \brief Indicator we've already handled a specific request/response
33  *
34  * PJSIP tends to reuse requests and responses. If we already have added
35  * headers to a request or response, we mark the message with this value
36  * so that we know not to re-add the headers again.
37  */
38 static unsigned int handled_id = 0xCA115785;
39 
40 static pjsip_module global_header_mod = {
41  .name = {"Global headers", 13},
42  .priority = PJSIP_MOD_PRIORITY_APPLICATION,
43  .on_tx_request = add_request_headers,
44  .on_tx_response = add_response_headers,
45 };
46 
47 struct header {
49  AST_STRING_FIELD(name);
50  AST_STRING_FIELD(value);
51  );
52  AST_LIST_ENTRY(header) next;
53 };
54 
55 static struct header *alloc_header(const char *name, const char *value)
56 {
57  struct header *alloc;
58 
59  alloc = ast_calloc_with_stringfields(1, struct header, 32);
60 
61  if (!alloc) {
62  return NULL;
63  }
64 
65  ast_string_field_set(alloc, name, name);
66  ast_string_field_set(alloc, value, value);
67 
68  return alloc;
69 }
70 
71 static void destroy_header(struct header *to_destroy)
72 {
73  ast_string_field_free_memory(to_destroy);
74  ast_free(to_destroy);
75 }
76 
78 
79 static struct header_list request_headers;
80 static struct header_list response_headers;
81 
82 static void add_headers_to_message(struct header_list *headers, pjsip_tx_data *tdata)
83 {
84  struct header *iter;
86  if (tdata->mod_data[global_header_mod.id] == &handled_id) {
87  return;
88  }
89  AST_LIST_TRAVERSE(headers, iter, next) {
90  pj_str_t name;
91  pjsip_generic_string_hdr *hdr;
92 
93  hdr = pjsip_msg_find_hdr_by_name(tdata->msg, pj_cstr(&name, iter->name), NULL);
94  if (hdr) {
95  continue;
96  }
97 
98  ast_sip_add_header(tdata, iter->name, iter->value);
99  };
100  tdata->mod_data[global_header_mod.id] = &handled_id;
101 }
102 
103 static pj_status_t add_request_headers(pjsip_tx_data *tdata)
104 {
105  add_headers_to_message(&request_headers, tdata);
106 
107  return PJ_SUCCESS;
108 }
109 
110 static pj_status_t add_response_headers(pjsip_tx_data *tdata)
111 {
112  add_headers_to_message(&response_headers, tdata);
113 
114  return PJ_SUCCESS;
115 }
116 
117 static void remove_header(struct header_list *headers, const char *to_remove)
118 {
119  struct header *iter;
120  AST_LIST_TRAVERSE_SAFE_BEGIN(headers, iter, next) {
121  if (!strcasecmp(iter->name, to_remove)) {
123  destroy_header(iter);
124  break;
125  }
126  }
128 }
129 
130 static int add_header(struct header_list *headers, const char *name, const char *value, int replace)
131 {
132  struct header *to_add = NULL;
133 
134  if (!ast_strlen_zero(value)) {
135  to_add = alloc_header(name, value);
136  if (!to_add) {
137  return -1;
138  }
139  }
140 
141  AST_RWLIST_WRLOCK(headers);
142  if (replace) {
143  remove_header(headers, name);
144  }
145  if (to_add) {
146  AST_LIST_INSERT_TAIL(headers, to_add, next);
147  }
148  AST_RWLIST_UNLOCK(headers);
149 
150  return 0;
151 }
152 
153 int ast_sip_add_global_request_header(const char *name, const char *value, int replace)
154 {
155  return add_header(&request_headers, name, value, replace);
156 }
157 
158 int ast_sip_add_global_response_header(const char *name, const char *value, int replace)
159 {
160  return add_header(&response_headers, name, value, replace);
161 }
162 
163 void ast_sip_initialize_global_headers(void)
164 {
165  AST_RWLIST_HEAD_INIT(&request_headers);
166  AST_RWLIST_HEAD_INIT(&response_headers);
167 
168  ast_sip_register_service(&global_header_mod);
169 }
170 
171 static void destroy_headers(struct header_list *headers)
172 {
173  struct header *iter;
174 
175  while ((iter = AST_RWLIST_REMOVE_HEAD(headers, next))) {
176  destroy_header(iter);
177  }
178  AST_RWLIST_HEAD_DESTROY(headers);
179 }
180 
181 void ast_sip_destroy_global_headers(void)
182 {
183  destroy_headers(&request_headers);
184  destroy_headers(&response_headers);
185 
186  ast_sip_unregister_service(&global_header_mod);
187 }
#define AST_RWLIST_HEAD_DESTROY(head)
Destroys an rwlist head structure.
Definition: linkedlists.h:667
Asterisk main include file. File version handling, generic pbx functions.
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
Definition: linkedlists.h:78
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
Definition: linkedlists.h:52
#define ast_calloc_with_stringfields(n, type, size)
Allocate a structure with embedded stringfields in a single allocation.
Definition: stringfields.h:432
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
#define AST_RWLIST_HEAD_INIT(head)
Initializes an rwlist head structure.
Definition: linkedlists.h:639
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
Definition: linkedlists.h:615
ast_mutex_t lock
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
Definition: linkedlists.h:557
#define SCOPED_LOCK(varname, lock, lockfunc, unlockfunc)
Scoped Locks.
Definition: lock.h:583
A set of macros to manage forward-linked lists.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:731
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
Definition: linkedlists.h:410
#define AST_RWLIST_HEAD(name, type)
Defines a structure to be used to hold a read/write list of specified type.
Definition: linkedlists.h:199
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
Definition: linkedlists.h:151
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
Definition: linkedlists.h:529
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:521