Review Board 1.7.16


res_pjsip_header_funcs: New module to create PJSIP_HEADER, PJSIPAddHeader and PJSIPRemoveHeader

Review Request #2858 - Created Sept. 15, 2013 and submitted

George Joseph
12
ASTERISK-22498
Reviewers
asterisk-dev
mmichelson
Asterisk
For PJSIP_HEADER, an incoming supplemental session callback is registered that takes the pjsip_hdrs from the incoming session and stores them in a linked list in the session datastore.  Calls to PJSIP_HEADER traverse over the list and return the nth matching header where 'n' is the 'number' argument to the function.

For PJSIPAddHeader, the first call creates a datastore and linked list and adds the datastore to the session.  The header is then created as a pjsip_hdr and added to the list.  An outgoing supplemental session callback then traverses the list and adds the headers to the outgoing pjsip_msg.

For PJSIPRemoveHeader, the list created with PJSIPAddHeader is traversed and all matching entries are removed.  As with SIPRemoveHeader, an empty arguments removes all headers previously added.

Rather than cloning the incoming pjsip_msg or using pjsip_msg to accumulate the outgoing headers, I used a simple AST_LIST. There was a lot of overhead with the clone functions and some tricky behavior with the pjsip_msg/pjsip_hdr internal lists. Using the AST_LISTs cut down on both instructions and memory.  

All memory allocation is from the pj_pool attached to the session.
Tested successfully...
PJSIP_HEADER return the full value of nth specified header from either the incoming session, or headers previously added to the outgoing session by PJSIPHeader.
PJSIP_HEADER fails if there was no header specified in the function call.
PJSIP_HEADER fails if there was no datastore on the incoming session (should never happen).
PJSIP_HEADER fails if the nth header wasn't found.

PJSIPAddHeader adds a pjsip_hdr structure to the linked list when the input string is properly formatted as "header_name:\s*header_value".
PJSIPAddHeader fails if no ':' was found in the input string.
PJSIPAddHeader fails if after parsing either the header name or value is empty.

PJSIPRemoveHeader removes all matching headers from the linked list when a partial header name is specified.
PJSIPRemoveHeader removes all matching headers from the linked list when a full header is specified with a trailing ':'.
PJSIPRemoveHeader removes all previously added header from the linked list when no header is specified.
PJSIPRemoveHeader returns successfully (silently) if there was no linked list.


Diff revision 3

This is not the most recent revision of the diff. The latest diff is revision 4. See what's changed.

1 2 3 4
1 2 3 4

  1. /branches/12/res/res_pjsip_header_funcs.c: Loading...
/branches/12/res/res_pjsip_header_funcs.c
New 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
 *

    
   
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"

    
   
32
#include "asterisk/res_pjsip_session.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, adds, updates or removes the specified SIP header from a PJSIP session.

    
   
43
		</synopsis>

    
   
44
		<syntax>

    
   
45
			<parameter name="action" required="true">

    
   
46
				<enumlist>

    
   
47
					<enum name="read"><para>Returns instance <replaceable>number</replaceable>

    
   
48
					of the header named <replaceable>name</replaceable>.</para></enum>

    
   
49
					<enum name="add"><para>Adds a new header named <replaceable>name</replaceable>

    
   
50
					to this session.</para></enum>

    
   
51
					<enum name="update"><para>Updates instance <replaceable>number</replaceable> of the header

    
   
52
					named <replaceable>name</replaceable> to a new value.  The header must already

    
   
53
					exist.</para></enum>

    
   
54
					<enum name="remove"><para>Removes all instances of previously added headers whose names match

    
   
55
					<replaceable>name</replaceable>.

    
   
56
					A <literal>*</literal> may be appended to <replaceable>name</replaceable> to

    
   
57
					remove all headers <emphasis>beginning with</emphasis> <replaceable>name</replaceable>.

    
   
58
					A single <literal>*</literal> may be provided for <replaceable>name</replaceable>

    
   
59
					to clear <emphasis>all</emphasis> previously added headers.

    
   
60
					</para></enum>

    
   
61
				</enumlist>

    
   
62
			</parameter>

    
   
63
			<parameter name="name" required="true"><para>The name of the header.</para></parameter>

    
   
64
			<parameter name="number" required="false">

    
   
65
				<para>If not specified, defaults to <literal>1</literal> meaning the first matching header.</para>

    
   
66
			</parameter>

    
   
67
		</syntax>

    
   
68
		<description>

    
   
69
			<para>Examples:</para>

    
   
70
			<para>;</para>

    
   
71
			<para>; Set 'somevar' to the value of the 'From' header.</para>

    
   
72
			<para>exten => 1,1,Set(somevar=PJSIP_HEADER(read,From))</para>

    
   
73
			<para>;</para>

    
   
74
			<para>; Set 'via2' to the value of the 2nd 'Via' header.</para>

    
   
75
			<para>exten => 1,1,Set(via2=PJSIP_HEADER(read,Via,2))</para>

    
   
76
			<para>;</para>

    
   
77
			<para>; Add an 'X-Myheader' header with the value of 'myvalue'.</para>

    
   
78
			<para>exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)</para>

    
   
79
			<para>;</para>

    
   
80
			<para>; Add an 'X-Myheader' header with an empty value.</para>

    
   
81
			<para>exten => 1,1,Set(PJSIP_HEADER(add,X-MyHeader)=)</para>

    
   
82
			<para>;</para>

    
   
83
			<para>; Update the value of the header named 'X-Myheader' to 'newvalue'.</para>

    
   
84
			<para>; 'X-Myheader' must already exist or the call will fail.</para>

    
   
85
			<para>exten => 1,1,Set(PJSIP_HEADER(update,X-MyHeader)=newvalue)</para>

    
   
86
			<para>;</para>

    
   
87
			<para>; Remove all headers whose names exactly match 'X-MyHeader'.</para>

    
   
88
			<para>exten => 1,1,PJSIP_HEADER(remove,X-MyHeader)</para>

    
   
89
			<para>;</para>

    
   
90
			<para>; Remove all headers that begin with 'X-My'.</para>

    
   
91
			<para>exten => 1,1,PJSIP_HEADER(remove,X-My*)</para>

    
   
92
			<para>;</para>

    
   
93
			<para>; Remove all previously added headers.</para>

    
   
94
			<para>exten => 1,1,PJSIP_HEADER(remove,*)</para>

    
   
95
			<para>;</para>

    
   
96
			<note><para>If you call PJSIP_HEADER in a normal dialplan context, you'll be operating on

    
   
97
			the <emphasis>calling</emphasis> channel which may not be what you want.  To operate on

    
   
98
			the <emphasis>called</emphasis> channel (to set headers on the outgoing channel for instance),

    
   
99
			call PJSIP_HEADER in a pre-dial handler.

    
   
100
			</para>

    
   
101
			<para>Example:</para>

    
   
102
			<para>;</para>

    
   
103
			<para>[handler]</para>

    
   
104
			<para>exten => addheader,1,Set(PJSIP_HEADER(add,X-MyHeader)=myvalue)</para>

    
   
105
			<para>exten => addheader,2,Set(PJSIP_HEADER(add,X-MyHeader2)=myvalue2)</para>

    
   
106
			<para>;</para>

    
   
107
			<para>[somecontext]</para>

    
   
108
			<para>exten => 1,1,Dial(PJSIP/${EXTEN},,b(handler^addheader^1)</para>

    
   
109
			<para>;</para>

    
   
110
			</note>

    
   
111
		</description>

    
   
112
	</function>

    
   
113
 ***/

    
   
114

   

    
   
115
/*! \brief Linked list for accumulating headers */

    
   
116
struct hdr_list_entry {

    
   
117
	pjsip_hdr *hdr;

    
   
118
	  AST_LIST_ENTRY(hdr_list_entry) nextptr;

    
   
119
};

    
   
120
AST_LIST_HEAD(hdr_list, hdr_list_entry);

    
   
121

   

    
   
122
/*! \brief Destructor for hdr_list */

    
   
123
static void hdr_list_destroy(void *obj)

    
   
124
{

    
   
125
	AST_LIST_HEAD_DESTROY((struct hdr_list *) obj);

    
   
126
}

    
   
127

   

    
   
128
/*! \brief Datastore for saving headers */

    
   
129
static const struct ast_datastore_info header_datastore = {

    
   
130
	.type = "header_datastore",

    
   
131
	.destroy = hdr_list_destroy,

    
   
132
};

    
   
133

   

    
   
134
/*!

    
   
135
 * \internal

    
   
136
 * \brief Insert the header pointers into the linked list.

    
   
137
 *

    
   
138
 * For each header in the message, allocate a list entry,

    
   
139
 * clone the header, then insert the entry.

    
   
140
 */

    
   
141
static int insert_headers(pj_pool_t * pool, struct hdr_list *list, pjsip_msg * msg)

    
   
142
{

    
   
143
	pjsip_hdr *hdr = msg->hdr.next;

    
   
144
	struct hdr_list_entry *le;

    
   
145

   

    
   
146
	AST_LIST_LOCK(list);

    
   
147
	while (hdr && hdr != &msg->hdr) {

    
   
148
		le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));

    
   
149
		le->hdr = pjsip_hdr_clone(pool, hdr);

    
   
150
		AST_LIST_INSERT_TAIL(list, le, nextptr);

    
   
151
		hdr = hdr->next;

    
   
152
	}

    
   
153
	AST_LIST_UNLOCK(list);

    
   
154
	return 0;

    
   
155
}

    
   
156

   

    
   
157
/*!

    
   
158
 * \internal

    
   
159
 * \brief Session supplement callback on an incoming INVITE request

    
   
160
 *

    
   
161
 * Retrieve the header_datastore from the session or create one if it doesn't exist.

    
   
162
 * Create and initialize the list if needed.

    
   
163
 * Insert the headers.

    
   
164
 */

    
   
165
static int incoming_request(struct ast_sip_session *session, pjsip_rx_data * rdata)

    
   
166
{

    
   
167
	pj_pool_t *pool = session->inv_session->dlg->pool;

    
   
168
	RAII_VAR(struct ast_datastore *, datastore,

    
   
169
			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);

    
   
170
	if (!datastore) {

    
   
171
		if (!

    
   
172
			(datastore =

    
   
173
			 ast_sip_session_alloc_datastore(&header_datastore, header_datastore.type)) ||

    
   
174
			!(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||

    
   
175
			ast_sip_session_add_datastore(session, datastore)) {

    
   
176
			ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");

    
   
177
			return 0;

    
   
178
		}

    
   
179
		AST_LIST_HEAD_INIT((struct hdr_list *) datastore->data);

    
   
180
	}

    
   
181
	insert_headers(pool, (struct hdr_list *) datastore->data, rdata->msg_info.msg);

    
   
182
	return 0;

    
   
183
}

    
   
184

   

    
   
185
/*!

    
   
186
 * \internal

    
   
187
 * \brief Search list for nth occurrence of specific header.

    
   
188
 */

    
   
189
static pjsip_hdr *find_header(struct hdr_list *list, const char *header_name,

    
   
190
							  int header_number)

    
   
191
{

    
   
192
	struct hdr_list_entry *le;

    
   
193
	pjsip_hdr *hdr = NULL;

    
   
194
	int i = 1;

    
   
195

   

    
   
196
	if (!list || ast_strlen_zero(header_name) || header_number < 1) {

    
   
197
		return NULL;

    
   
198
	}

    
   
199

   

    
   
200
	AST_LIST_LOCK(list);

    
   
201
	AST_LIST_TRAVERSE(list, le, nextptr) {

    
   
202
		if (pj_stricmp2(&le->hdr->name, header_name) == 0 && i++ == header_number) {

    
   
203
			hdr = le->hdr;

    
   
204
			break;

    
   
205
		}

    
   
206
	}

    
   
207
	AST_LIST_UNLOCK(list);

    
   
208
	return hdr;

    
   
209
}

    
   
210

   

    
   
211

   

    
   
212
/*!

    
   
213
 * \internal

    
   
214
 * \brief Implements PJSIP_HEADER 'read' by searching the for the requested header.

    
   
215
 *

    
   
216
 * Retrieve the header_datastore.

    
   
217
 * Search for the nth matching header.

    
   
218
 * Validate the pjsip_hdr found.

    
   
219
 * Parse pjsip_hdr into a name and value.

    
   
220
 * Return the value.

    
   
221
 */

    
   
222
static int read_header(struct ast_channel *chan, char *header_name, int header_number,

    
   
223
					   char *buf, size_t len)

    
   
224
{

    
   
225
	struct ast_sip_channel_pvt *channel = ast_channel_tech_pvt(chan);

    
   
226
	pjsip_hdr *hdr = NULL;

    
   
227
	char *pj_hdr_string;

    
   
228
	size_t pj_hdr_string_len;

    
   
229
	char *p;

    
   
230
	size_t plen;

    
   
231

   

    
   
232
	RAII_VAR(struct ast_datastore *, datastore,

    
   
233
			 ast_sip_session_get_datastore(channel->session, header_datastore.type),

    
   
234
			 ao2_cleanup);

    
   
235
	if (!datastore || !datastore->data) {

    
   
236
		ast_debug(1, "There was no datastore from which to read headers.\n");

    
   
237
		return -1;

    
   
238
	}

    
   
239

   

    
   
240
	hdr = find_header((struct hdr_list *) datastore->data, header_name, header_number);

    
   
241

   

    
   
242
	if (!hdr) {

    
   
243
		ast_debug(1, "There was no header named %s.\n", header_name);

    
   
244
		return -1;

    
   
245
	}

    
   
246

   

    
   
247
	pj_hdr_string = ast_alloca(len);

    
   
248
	pj_hdr_string_len = pjsip_hdr_print_on(hdr, pj_hdr_string, len);

    
   
249
	pj_hdr_string[pj_hdr_string_len] = '\0';

    
   
250

   

    
   
251
	p = strchr(pj_hdr_string, ':');

    
   
252
	if (!p) {

    
   
253
		ast_log(AST_LOG_ERROR,

    
   
254
				"A malformed header was returned from pjsip_hdr_print_on.\n");

    
   
255
		return -1;

    
   
256
	}

    
   
257

   

    
   
258
	++p;

    
   
259
	p = ast_strip(p);

    
   
260
	plen = strlen(p);

    
   
261
	if (plen + 1 > len) {

    
   
262
		ast_log(AST_LOG_ERROR,

    
   
263
				"Buffer isn't big enough to hold header value.  %lu > %lu\n", plen + 1,

    
   
264
				len);

    
   
265
		return -1;

    
   
266
	}

    
   
267

   

    
   
268
	ast_copy_string(buf, p, len);

    
   
269
	return 0;

    
   
270
}

    
   
271

   

    
   
272
/*!

    
   
273
 * \internal

    
   
274
 * \brief Implements PJSIP_HEADER 'add' by inserting the specified header into thge list.

    
   
275
 *

    
   
276
 * Retrieve the header_datastore from the session or create one if it doesn't exist.

    
   
277
 * Create and initialize the list if needed.

    
   
278
 * Create the pj_strs for name and value.

    
   
279
 * Create pjsip_msg and hdr_list_entry.

    
   
280
 * Add the entry to the list.

    
   
281
 */

    
   
282
static int add_header(struct ast_channel *chan, const char *header_name,

    
   
283
					  const char *header_value)

    
   
284
{

    
   
285
	struct ast_sip_channel_pvt *chan_pvt = ast_channel_tech_pvt(chan);

    
   
286
	struct ast_sip_session *session = chan_pvt->session;

    
   
287
	pj_pool_t *pool = session->inv_session->dlg->pool;

    
   
288
	pj_str_t pj_header_name;

    
   
289
	pj_str_t pj_header_value;

    
   
290
	struct hdr_list_entry *le;

    
   
291
	struct hdr_list *list;

    
   
292

   

    
   
293
	RAII_VAR(struct ast_datastore *, datastore,

    
   
294
			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);

    
   
295
	if (!datastore) {

    
   
296
		if (!

    
   
297
			(datastore =

    
   
298
			 ast_sip_session_alloc_datastore(&header_datastore, header_datastore.type)) ||

    
   
299
			!(datastore->data = pj_pool_alloc(pool, sizeof(struct hdr_list))) ||

    
   
300
			ast_sip_session_add_datastore(session, datastore)) {

    
   
301
			ast_log(AST_LOG_ERROR, "Unable to create datastore for header functions.\n");

    
   
302
			return -1;

    
   
303
		}

    
   
304
		AST_LIST_HEAD_INIT((struct hdr_list *) datastore->data);

    
   
305
	}

    
   
306

   

    
   
307
	ast_debug(1, "Adding header %s with value %s\n", header_name, header_value);

    
   
308

   

    
   
309
	pj_cstr(&pj_header_name, header_name);

    
   
310
	pj_cstr(&pj_header_value, header_value);

    
   
311
	le = pj_pool_zalloc(pool, sizeof(struct hdr_list_entry));

    
   
312
	le->hdr =

    
   
313
		(pjsip_hdr *) pjsip_generic_string_hdr_create(pool, &pj_header_name,

    
   
314
													  &pj_header_value);

    
   
315
	list = datastore->data;

    
   
316
	AST_LIST_LOCK(list);

    
   
317
	AST_LIST_INSERT_TAIL(list, le, nextptr);

    
   
318
	AST_LIST_UNLOCK(list);

    
   
319

   

    
   
320
	return 0;

    
   
321
}

    
   
322

   

    
   
323
/*!

    
   
324
 * \internal

    
   
325
 * \brief Implements PJSIP_HEADER 'update' by finding the specified header and updating it.

    
   
326
 *

    
   
327
 * Retrieve the header_datastore from the session or create one if it doesn't exist.

    
   
328
 * Create and initialize the list if needed.

    
   
329
 * Create the pj_strs for name and value.

    
   
330
 * Create pjsip_msg and hdr_list_entry.

    
   
331
 * Add the entry to the list.

    
   
332
 */

    
   
333
static int update_header(struct ast_channel *chan,

    
   
334
						 const char *header_name, const char *header_value,

    
   
335
						 int header_number)

    
   
336
{

    
   
337
	struct ast_sip_channel_pvt *chan_pvt = ast_channel_tech_pvt(chan);

    
   
338
	struct ast_sip_session *session = chan_pvt->session;

    
   
339
	pjsip_hdr *hdr = NULL;

    
   
340

   

    
   
341
	RAII_VAR(struct ast_datastore *, datastore,

    
   
342
			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);

    
   
343
	if (!datastore || !datastore->data) {

    
   
344
		ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");

    
   
345
		return -1;

    
   
346
	}

    
   
347

   

    
   
348
	hdr = find_header((struct hdr_list *) datastore->data, header_name, header_number);

    
   
349

   

    
   
350
	if (!hdr) {

    
   
351
		ast_debug(1, "There was no header named %s.\n", header_name);

    
   
352
		return -1;

    
   
353
	}

    
   
354

   

    
   
355
	pj_strcpy2(&((pjsip_generic_string_hdr *) hdr)->hvalue, header_value);

    
   
356

   

    
   
357
	return 0;

    
   
358
}

    
   
359

   

    
   
360
/*!

    
   
361
 * \internal

    
   
362
 * \brief Implements PJSIP_HEADER 'remove' by finding the specified header and removing it.

    
   
363
 *

    
   
364
 * Retrieve the header_datastore from the session.  Fail if it doesn't exist.

    
   
365
 * If the header_name is exactly '*', the entire list is simply destroyed.

    
   
366
 * Otherwise search the list for the matching header name which may be a partial name.

    
   
367
 */

    
   
368
static int remove_header(struct ast_channel *chan, const char *header_name)

    
   
369
{

    
   
370
	struct ast_sip_channel_pvt *chan_pvt = ast_channel_tech_pvt(chan);

    
   
371
	struct ast_sip_session *session = chan_pvt->session;

    
   
372
	size_t len = strlen(header_name);

    
   
373
	struct hdr_list *list;

    
   
374
	struct hdr_list_entry *le;

    
   
375

   

    
   
376
	RAII_VAR(struct ast_datastore *, datastore,

    
   
377
			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);

    
   
378
	if (!datastore || !datastore->data) {

    
   
379
		ast_log(AST_LOG_ERROR, "No headers had been previously added to this session.\n");

    
   
380
		return -1;

    
   
381
	}

    
   
382

   

    
   
383
	if (strcmp(header_name, "*") == 0) {

    
   
384
		datastore->data = NULL;

    
   
385
		return 0;

    
   
386
	}

    
   
387

   

    
   
388
	list = datastore->data;

    
   
389
	AST_LIST_LOCK(list);

    
   
390
	AST_LIST_TRAVERSE_SAFE_BEGIN(list, le, nextptr) {

    
   
391
		if (header_name[len - 1] == '*') {

    
   
392
			if (pj_strnicmp2(&le->hdr->name, header_name, len - 1) == 0) {

    
   
393
				AST_LIST_REMOVE_CURRENT(nextptr);

    
   
394
			}

    
   
395
		} else {

    
   
396
			if (pj_stricmp2(&le->hdr->name, header_name) == 0) {

    
   
397
				AST_LIST_REMOVE_CURRENT(nextptr);

    
   
398
			}

    
   
399
		}

    
   
400
	}

    
   
401
	AST_LIST_TRAVERSE_SAFE_END;

    
   
402
	AST_LIST_UNLOCK(list);

    
   
403

   

    
   
404
	return 0;

    
   
405
}

    
   
406

   

    
   
407
/*!

    
   
408
 * \brief Implements function 'read' callback.

    
   
409
 *

    
   
410
 * Valid actions are 'read' and 'remove'.

    
   
411
 */

    
   
412
static int func_read_header(struct ast_channel *chan, const char *function, char *data,

    
   
413
							char *buf, size_t len)

    
   
414
{

    
   
415
	int number;

    
   
416
	AST_DECLARE_APP_ARGS(args, AST_APP_ARG(action); AST_APP_ARG(header_name);

    
   
417
						 AST_APP_ARG(header_number);

    
   
418
		);

    
   
419
	AST_STANDARD_APP_ARGS(args, data);

    
   
420

   

    
   
421
	if (ast_strlen_zero(args.action)) {

    
   
422
		ast_log(AST_LOG_ERROR, "This function requires an action.\n");

    
   
423
		return -1;

    
   
424
	}

    
   
425
	if (ast_strlen_zero(args.header_name)) {

    
   
426
		ast_log(AST_LOG_ERROR, "This function requires a header name.\n");

    
   
427
		return -1;

    
   
428
	}

    
   
429
	if (!args.header_number) {

    
   
430
		number = 1;

    
   
431
	} else {

    
   
432
		sscanf(args.header_number, "%30d", &number);

    
   
433
		if (number < 1) {

    
   
434
			number = 1;

    
   
435
		}

    
   
436
	}

    
   
437

   

    
   
438
	if (stricmp(args.action, "read") == 0) {

    
   
439
		return read_header(chan, args.header_name, number, buf, len);

    
   
440
	} else if (stricmp(args.action, "remove") == 0) {

    
   
441
		return remove_header(chan, args.header_name);

    
   
442
	} else {

    
   
443
		ast_log(AST_LOG_ERROR,

    
   
444
				"Unknown action \'%s\' is not valid,  Must be \'read\' or \'remove\'.\n",

    
   
445
				args.action);

    
   
446
		return -1;

    
   
447
	}

    
   
448
}

    
   
449

   

    
   
450
/*!

    
   
451
 * \brief Implements function 'write' callback.

    
   
452
 *

    
   
453
 * Valid actions are 'add', 'update' and 'remove'.

    
   
454
 */

    
   
455
static int func_write_header(struct ast_channel *chan, const char *cmd, char *data,

    
   
456
							 const char *value)

    
   
457
{

    
   
458
	int header_number;

    
   
459
	AST_DECLARE_APP_ARGS(args, AST_APP_ARG(action); AST_APP_ARG(header_name);

    
   
460
						 AST_APP_ARG(header_number);

    
   
461
		);

    
   
462
	AST_STANDARD_APP_ARGS(args, data);

    
   
463

   

    
   
464
	if (ast_strlen_zero(args.action)) {

    
   
465
		ast_log(AST_LOG_ERROR, "This function requires an action.\n");

    
   
466
		return -1;

    
   
467
	}

    
   
468
	if (ast_strlen_zero(args.header_name)) {

    
   
469
		ast_log(AST_LOG_ERROR, "This function requires a header name.\n");

    
   
470
		return -1;

    
   
471
	}

    
   
472
	if (!args.header_number) {

    
   
473
		header_number = 1;

    
   
474
	} else {

    
   
475
		sscanf(args.header_number, "%30d", &header_number);

    
   
476
		if (header_number < 1) {

    
   
477
			header_number = 1;

    
   
478
		}

    
   
479
	}

    
   
480

   

    
   
481
	if (stricmp(args.action, "add") == 0) {

    
   
482
		return add_header(chan, args.header_name, value);

    
   
483
	} else if (stricmp(args.action, "update") == 0) {

    
   
484
		return update_header(chan, args.header_name, value, header_number);

    
   
485
	} else if (stricmp(args.action, "remove") == 0) {

    
   
486
		return remove_header(chan, args.header_name);

    
   
487
	} else {

    
   
488
		ast_log(AST_LOG_ERROR,

    
   
489
				"Unknown action \'%s\' is not valid,  Must be \'add\', \'update\', or \'remove\'.\n",

    
   
490
				args.action);

    
   
491
		return -1;

    
   
492
	}

    
   
493
}

    
   
494

   

    
   
495
static struct ast_custom_function pjsip_header_function = {

    
   
496
	.name = "PJSIP_HEADER",

    
   
497
	.read = func_read_header,

    
   
498
	.write = func_write_header,

    
   
499
};

    
   
500

   

    
   
501
/*!

    
   
502
 * \internal

    
   
503
 * \brief Session supplement callback for outgoing INVITE requests

    
   
504
 *

    
   
505
 * Retrieve the header_datastore from the session.

    
   
506
 * Add each header in the list to the outgoing message.

    
   
507
 *

    
   
508
 * These pjsip_hdr structures will have been created by add_header.

    
   
509
 * Because outgoing_request may be called more than once with the same header

    
   
510
 * list (as in the case of an authentication exchange), each pjsip_hdr structure

    
   
511
 * MUST be newly cloned for each outgoing message.

    
   
512
 */

    
   
513
static void outgoing_request(struct ast_sip_session *session, pjsip_tx_data * tdata)

    
   
514
{

    
   
515
	pj_pool_t *pool = session->inv_session->dlg->pool;

    
   
516
	struct hdr_list *list;

    
   
517
	struct hdr_list_entry *le;

    
   
518
	RAII_VAR(struct ast_datastore *, datastore,

    
   
519
			 ast_sip_session_get_datastore(session, header_datastore.type), ao2_cleanup);

    
   
520
	if (!datastore || !datastore->data) {

    
   
521
		return;

    
   
522
	}

    
   
523

   

    
   
524
	list = datastore->data;

    
   
525
	AST_LIST_LOCK(list);

    
   
526
	AST_LIST_TRAVERSE(list, le, nextptr) {

    
   
527
		pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr *) pjsip_hdr_clone(pool, le->hdr));

    
   
528
	}

    
   
529
	AST_LIST_UNLOCK(list);

    
   
530
}

    
   
531

   

    
   
532
static struct ast_sip_session_supplement header_funcs_supplement = {

    
   
533
	.method = "INVITE",

    
   
534
	.priority = AST_SIP_SESSION_SUPPLEMENT_PRIORITY_CHANNEL - 1000,

    
   
535
	.incoming_request = incoming_request,

    
   
536
	.outgoing_request = outgoing_request,

    
   
537
};

    
   
538

   

    
   
539
static int load_module(void)

    
   
540
{

    
   
541
	ast_sip_session_register_supplement(&header_funcs_supplement);

    
   
542
	ast_custom_function_register(&pjsip_header_function);

    
   
543

   

    
   
544
	return AST_MODULE_LOAD_SUCCESS;

    
   
545
}

    
   
546

   

    
   
547
static int unload_module(void)

    
   
548
{

    
   
549
	ast_custom_function_unregister(&pjsip_header_function);

    
   
550
	ast_sip_session_unregister_supplement(&header_funcs_supplement);

    
   
551
	return 0;

    
   
552
}

    
   
553

   

    
   
554
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP Header Functions",.load =

    
   
555
				load_module,.unload = unload_module,.load_pri = AST_MODPRI_APP_DEPEND,);
  1. /branches/12/res/res_pjsip_header_funcs.c: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.