| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Asterisk -- An open source telephony toolkit. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright (C) 2013, Digium, Inc. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Mark Michelson <mmichelson@digium.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * See http://www.asterisk.org for more information about
 | 
					
						
							|  |  |  |  * the Asterisk project. Please do not directly contact | 
					
						
							|  |  |  |  * any of the maintainers of this project for assistance; | 
					
						
							|  |  |  |  * the project provides a web site, mailing lists and IRC | 
					
						
							|  |  |  |  * channels for your use. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software, distributed under the terms of | 
					
						
							|  |  |  |  * the GNU General Public License Version 2. See the LICENSE file | 
					
						
							|  |  |  |  * at the top of the source tree. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "asterisk.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <pjsip.h>
 | 
					
						
							|  |  |  | #include <pjlib.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-30 18:14:50 +00:00
										 |  |  | #include "asterisk/res_pjsip.h"
 | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | #include "asterisk/linkedlists.h"
 | 
					
						
							| 
									
										
										
										
											2015-01-27 19:12:56 +00:00
										 |  |  | #include "include/res_pjsip_private.h"
 | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static pj_status_t add_request_headers(pjsip_tx_data *tdata); | 
					
						
							|  |  |  | static pj_status_t add_response_headers(pjsip_tx_data *tdata); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*!
 | 
					
						
							|  |  |  |  * \brief Indicator we've already handled a specific request/response | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * PJSIP tends to reuse requests and responses. If we already have added | 
					
						
							|  |  |  |  * headers to a request or response, we mark the message with this value | 
					
						
							|  |  |  |  * so that we know not to re-add the headers again. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2013-07-24 17:33:45 +00:00
										 |  |  | static unsigned int handled_id = 0xCA115785; | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | static pjsip_module global_header_mod = { | 
					
						
							|  |  |  | 	.name = {"Global headers", 13}, | 
					
						
							|  |  |  | 	.priority = PJSIP_MOD_PRIORITY_APPLICATION, | 
					
						
							|  |  |  | 	.on_tx_request = add_request_headers, | 
					
						
							|  |  |  | 	.on_tx_response = add_response_headers, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct header { | 
					
						
							|  |  |  | 	AST_DECLARE_STRING_FIELDS( | 
					
						
							|  |  |  | 		AST_STRING_FIELD(name); | 
					
						
							|  |  |  | 		AST_STRING_FIELD(value); | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | 	AST_LIST_ENTRY(header) next; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct header *alloc_header(const char *name, const char *value) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct header *alloc; | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 	alloc = ast_calloc_with_stringfields(1, struct header, 32); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!alloc) { | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ast_string_field_set(alloc, name, name); | 
					
						
							|  |  |  | 	ast_string_field_set(alloc, value, value); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return alloc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void destroy_header(struct header *to_destroy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	ast_string_field_free_memory(to_destroy); | 
					
						
							|  |  |  | 	ast_free(to_destroy); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | AST_RWLIST_HEAD(header_list, header); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct header_list request_headers; | 
					
						
							|  |  |  | static struct header_list response_headers; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void add_headers_to_message(struct header_list *headers, pjsip_tx_data *tdata) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct header *iter; | 
					
						
							|  |  |  | 	SCOPED_LOCK(lock, headers, AST_RWLIST_RDLOCK, AST_RWLIST_UNLOCK); | 
					
						
							|  |  |  | 	if (tdata->mod_data[global_header_mod.id] == &handled_id) { | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE(headers, iter, next) { | 
					
						
							| 
									
										
										
										
											2016-09-07 21:00:16 +00:00
										 |  |  | 		pj_str_t name; | 
					
						
							|  |  |  | 		pjsip_generic_string_hdr *hdr; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		hdr = pjsip_msg_find_hdr_by_name(tdata->msg, pj_cstr(&name, iter->name), NULL); | 
					
						
							|  |  |  | 		if (hdr) { | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 		ast_sip_add_header(tdata, iter->name, iter->value); | 
					
						
							|  |  |  | 	}; | 
					
						
							|  |  |  | 	tdata->mod_data[global_header_mod.id] = &handled_id; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static pj_status_t add_request_headers(pjsip_tx_data *tdata) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	add_headers_to_message(&request_headers, tdata); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return PJ_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static pj_status_t add_response_headers(pjsip_tx_data *tdata) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	add_headers_to_message(&response_headers, tdata); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return PJ_SUCCESS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void remove_header(struct header_list *headers, const char *to_remove) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct header *iter; | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_BEGIN(headers, iter, next) { | 
					
						
							|  |  |  | 		if (!strcasecmp(iter->name, to_remove)) { | 
					
						
							|  |  |  | 			AST_LIST_REMOVE_CURRENT(next); | 
					
						
							| 
									
										
										
										
											2015-01-23 15:21:56 +00:00
										 |  |  | 			destroy_header(iter); | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_LIST_TRAVERSE_SAFE_END; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int add_header(struct header_list *headers, const char *name, const char *value, int replace) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2015-03-11 15:22:01 +00:00
										 |  |  | 	struct header *to_add = NULL; | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-11 15:22:01 +00:00
										 |  |  | 	if (!ast_strlen_zero(value)) { | 
					
						
							|  |  |  | 		to_add = alloc_header(name, value); | 
					
						
							|  |  |  | 		if (!to_add) { | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	AST_RWLIST_WRLOCK(headers); | 
					
						
							| 
									
										
										
										
											2017-12-22 09:23:22 -05:00
										 |  |  | 	if (replace) { | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 		remove_header(headers, name); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-11 15:22:01 +00:00
										 |  |  | 	if (to_add) { | 
					
						
							|  |  |  | 		AST_LIST_INSERT_TAIL(headers, to_add, next); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | 	AST_RWLIST_UNLOCK(headers); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_sip_add_global_request_header(const char *name, const char *value, int replace) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return add_header(&request_headers, name, value, replace); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int ast_sip_add_global_response_header(const char *name, const char *value, int replace) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return add_header(&response_headers, name, value, replace); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_sip_initialize_global_headers(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	AST_RWLIST_HEAD_INIT(&request_headers); | 
					
						
							|  |  |  | 	AST_RWLIST_HEAD_INIT(&response_headers); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-29 03:57:17 -05:00
										 |  |  | 	ast_sip_register_service(&global_header_mod); | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void destroy_headers(struct header_list *headers) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct header *iter; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while ((iter = AST_RWLIST_REMOVE_HEAD(headers, next))) { | 
					
						
							|  |  |  | 		destroy_header(iter); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	AST_RWLIST_HEAD_DESTROY(headers); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void ast_sip_destroy_global_headers(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	destroy_headers(&request_headers); | 
					
						
							|  |  |  | 	destroy_headers(&response_headers); | 
					
						
							| 
									
										
										
										
											2015-01-27 19:12:56 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-12-29 03:57:17 -05:00
										 |  |  | 	ast_sip_unregister_service(&global_header_mod); | 
					
						
							| 
									
										
										
										
											2013-07-18 19:25:51 +00:00
										 |  |  | } |