2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Mark Michelson <mmichelson@digium.com>
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.
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.
24 #include "asterisk/res_pjsip.h"
25 #include "asterisk/linkedlists.h"
26 #include "include/res_pjsip_private.h"
28 static pj_status_t add_request_headers(pjsip_tx_data *tdata);
29 static pj_status_t add_response_headers(pjsip_tx_data *tdata);
32 * \brief Indicator we've already handled a specific request/response
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.
38 static unsigned int handled_id = 0xCA115785;
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,
48 AST_DECLARE_STRING_FIELDS(
49 AST_STRING_FIELD(name);
50 AST_STRING_FIELD(value);
52 AST_LIST_ENTRY(header) next;
55 static struct header *alloc_header(const char *name, const char *value)
59 alloc = ast_calloc_with_stringfields(1, struct header, 32);
65 ast_string_field_set(alloc, name, name);
66 ast_string_field_set(alloc, value, value);
71 static void destroy_header(struct header *to_destroy)
73 ast_string_field_free_memory(to_destroy);
77 AST_RWLIST_HEAD(header_list, header);
79 static struct header_list request_headers;
80 static struct header_list response_headers;
82 static void add_headers_to_message(struct header_list *headers, pjsip_tx_data *tdata)
85 SCOPED_LOCK(lock, headers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK);
86 if (tdata->mod_data[global_header_mod.id] == &handled_id) {
89 AST_LIST_TRAVERSE(headers, iter, next) {
90 ast_sip_add_header(tdata, iter->name, iter->value);
92 tdata->mod_data[global_header_mod.id] = &handled_id;
95 static pj_status_t add_request_headers(pjsip_tx_data *tdata)
97 add_headers_to_message(&request_headers, tdata);
102 static pj_status_t add_response_headers(pjsip_tx_data *tdata)
104 add_headers_to_message(&response_headers, tdata);
109 static void remove_header(struct header_list *headers, const char *to_remove)
112 AST_LIST_TRAVERSE_SAFE_BEGIN(headers, iter, next) {
113 if (!strcasecmp(iter->name, to_remove)) {
114 AST_LIST_REMOVE_CURRENT(next);
115 destroy_header(iter);
119 AST_LIST_TRAVERSE_SAFE_END;
122 static int add_header(struct header_list *headers, const char *name, const char *value, int replace)
124 struct header *to_add;
126 to_add = alloc_header(name, value);
131 AST_RWLIST_WRLOCK(headers);
133 remove_header(headers, name);
135 AST_LIST_INSERT_TAIL(headers, to_add, next);
136 AST_RWLIST_UNLOCK(headers);
141 int ast_sip_add_global_request_header(const char *name, const char *value, int replace)
143 return add_header(&request_headers, name, value, replace);
146 int ast_sip_add_global_response_header(const char *name, const char *value, int replace)
148 return add_header(&response_headers, name, value, replace);
151 void ast_sip_initialize_global_headers(void)
153 AST_RWLIST_HEAD_INIT(&request_headers);
154 AST_RWLIST_HEAD_INIT(&response_headers);
156 internal_sip_register_service(&global_header_mod);
159 static void destroy_headers(struct header_list *headers)
163 while ((iter = AST_RWLIST_REMOVE_HEAD(headers, next))) {
164 destroy_header(iter);
166 AST_RWLIST_HEAD_DESTROY(headers);
169 void ast_sip_destroy_global_headers(void)
171 destroy_headers(&request_headers);
172 destroy_headers(&response_headers);
174 internal_sip_unregister_service(&global_header_mod);