xref: /illumos-gate/usr/src/lib/libsip/common/sip_headers.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <assert.h>
31 #include <errno.h>
32 #include <pthread.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <sip.h>
36 
37 #include "sip_msg.h"
38 #include "sip_miscdefs.h"
39 #include "sip_parse_generic.h"
40 
41 sip_methods_t sip_methods[MAX_SIP_METHODS] = {
42 	{"UNKNOWN", 7},
43 	{"INVITE", 6},
44 	{"ACK", 3},
45 	{"OPTIONS", 7},
46 	{"BYE", 3},
47 	{"CANCEL", 6},
48 	{"REGISTER", 8},
49 	{"REFER", 5},
50 	{"INFO", 4},
51 	{"SUBSCRIBE", 9},
52 	{"NOTIFY", 6},
53 	{"PRACK", 5}
54 };
55 
56 /*
57  * Built-In Header function table
58  */
59 sip_header_function_t sip_header_function_table[] = {
60 	{"Unknown", NULL, sip_parse_unknown_header, NULL, NULL, NULL},
61 	{"CONTACT", "m", sip_parse_cftr_header, NULL, NULL,
62 	sip_free_cftr_header},
63 	{"FROM", "F", sip_parse_cftr_header, NULL, NULL, sip_free_cftr_header},
64 	{"TO", "T", sip_parse_cftr_header, NULL, NULL, sip_free_cftr_header},
65 	{"CONTENT-LENGTH", "l", sip_parse_clen_header, NULL, NULL,
66 	sip_free_phdr},
67 	{"CONTENT-TYPE", "c", sip_parse_ctype_header, NULL, NULL,
68 	sip_free_phdr},
69 	{"CALL-ID", "i", sip_parse_cid_header, NULL, NULL, sip_free_phdr},
70 	{"CSEQ", NULL, sip_parse_cseq_header, NULL, NULL, sip_free_phdr},
71 	{"VIA", "v", sip_parse_via_header, NULL, NULL, sip_free_phdr},
72 	{"Max-Forwards", NULL, sip_parse_maxf_header, NULL, NULL,
73 	sip_free_phdr},
74 	{"RECORD-ROUTE", NULL, sip_parse_cftr_header, NULL, NULL,
75 	sip_free_cftr_header},
76 	{"ROUTE", NULL, sip_parse_cftr_header, NULL, NULL,
77 	sip_free_cftr_header},
78 	{"ACCEPT", NULL, sip_parse_acpt_header, NULL, NULL, sip_free_phdr},
79 	{"ACCEPT-ENCODING", NULL, sip_parse_acpt_encode_header, NULL, NULL,
80 	sip_free_phdr},
81 	{"ACCEPT-LANGUAGE", NULL, sip_parse_acpt_lang_header, NULL, NULL,
82 	sip_free_phdr},
83 	{"ALERT-INFO", NULL, sip_parse_alert_header, NULL, NULL, sip_free_phdr},
84 	{"ALLOW", NULL, sip_parse_allow_header, NULL, NULL, sip_free_phdr},
85 	{"CALL-INFO", NULL, sip_parse_callinfo_header, NULL, NULL,
86 	sip_free_phdr},
87 	{"CONTENT-DISPOSITION", NULL, sip_parse_contentdis_header, NULL, NULL,
88 	sip_free_phdr},
89 	{"CONTENT-ENCODING", "e", sip_parse_contentencode_header, NULL, NULL,
90 	sip_free_phdr},
91 	{"CONTENT-LANGUAGE", NULL, sip_parse_contentlang_header, NULL, NULL,
92 	sip_free_phdr},
93 	{"DATE", NULL, sip_parse_date_header, NULL, NULL, sip_free_phdr},
94 	{"ERROR-INFO", NULL, sip_parse_errorinfo_header, NULL, NULL,
95 	sip_free_phdr},
96 	{"EXPIRES", NULL, sip_parse_expire_header, NULL, NULL, sip_free_phdr},
97 	{"IN-REPLY-TO", NULL, sip_parse_inreplyto_header, NULL, NULL,
98 	sip_free_phdr},
99 	{"MIN-EXPIRES", NULL, sip_parse_minexpire_header, NULL, NULL,
100 	sip_free_phdr},
101 	{"MIME-VERSION", NULL, sip_parse_mimeversion_header, NULL, NULL,
102 	sip_free_phdr},
103 	{"ORGANIZATION", NULL, sip_parse_org_header, NULL, NULL, sip_free_phdr},
104 	{"PRIORITY", NULL, sip_parse_priority_header, NULL, NULL,
105 	sip_free_phdr},
106 	{"REQUIRE", NULL, sip_parse_require_header, NULL, NULL, sip_free_phdr},
107 	{"REPLY-TO", NULL, sip_parse_replyto_header, NULL, NULL, sip_free_phdr},
108 	{"RETRY-AFTER", NULL, sip_parse_retryaft_header, NULL, NULL,
109 	sip_free_phdr},
110 	{"SERVER", NULL, sip_parse_server_header, NULL, NULL, sip_free_phdr},
111 	{"SUBJECT", "s", sip_parse_subject_header, NULL, NULL, sip_free_phdr},
112 	{"TIMESTAMP", NULL, sip_parse_timestamp_header, NULL, NULL,
113 	sip_free_phdr},
114 	{"UNSUPPORTED", NULL, sip_parse_usupport_header, NULL, NULL,
115 	sip_free_phdr},
116 	{"SUPPORTED", "k", sip_parse_support_header, NULL, NULL, sip_free_phdr},
117 	{"USER-AGENT", NULL, sip_parse_useragt_header, NULL, NULL,
118 	sip_free_phdr},
119 	{"WARNING", NULL, sip_parse_warn_header, NULL, NULL, sip_free_phdr},
120 	{"ALLOW-EVENTS", "u", sip_parse_allow_events_header, NULL, NULL,
121 	sip_free_phdr},
122 	{"EVENT", "o", sip_parse_event_header, NULL, NULL, sip_free_phdr},
123 	{"SUBSCRIPTION-STATE", NULL, sip_parse_substate_header, NULL, NULL,
124 	sip_free_phdr},
125 	{"AUTHORIZATION", NULL, sip_parse_author_header, NULL, NULL,
126 	sip_free_phdr},
127 	{"AUTHENTICATION-INFO", NULL, sip_parse_ainfo_header, NULL, NULL,
128 	sip_free_phdr},
129 	{"PROXY-AUTHORIZATION", NULL, sip_parse_pauthor_header, NULL, NULL,
130 	sip_free_phdr},
131 	{"PROXY-AUTHENTICATE", NULL, sip_parse_pauthen_header, NULL, NULL,
132 	sip_free_phdr},
133 	{"PROXY-REQUIRE", NULL, sip_parse_preq_header, NULL, NULL,
134 	sip_free_phdr},
135 	{"WWW-AUTHENTICATE", NULL, sip_parse_wauthen_header, NULL, NULL,
136 	sip_free_phdr},
137 	{"RSEQ", NULL, sip_parse_rseq, NULL, NULL, sip_free_phdr},
138 	{"RACK", NULL, sip_parse_rack, NULL, NULL, sip_free_phdr},
139 	{"P-ASSERTED-IDENTITY", NULL, sip_parse_passertedid, NULL, NULL,
140 	sip_free_phdr},
141 	{"P-PREFERRED-IDENTITY", NULL, sip_parse_ppreferredid, NULL, NULL,
142 	sip_free_phdr},
143 	{"PRIVACY", NULL, sip_parse_privacy_header, NULL, NULL, sip_free_phdr},
144 	{NULL, NULL, NULL, NULL, NULL, NULL},
145 };
146 
147 #define	MAX_SIP_HEADERS	\
148 	sizeof (sip_header_function_table) / sizeof (sip_header_function_t)
149 
150 /*
151  * External/application provided function table
152  */
153 sip_header_function_t *sip_header_function_table_external = NULL;
154 
155 /*
156  * Free parameter list
157  */
158 static void
159 sip_free_params(sip_param_t *param_list)
160 {
161 	sip_param_t *param, *next_param;
162 
163 	param = param_list;
164 
165 	while (param != NULL) {
166 		next_param = param->param_next;
167 		free(param);
168 		param = next_param;
169 	}
170 }
171 
172 /*
173  * Common header free routine
174  */
175 void
176 sip_free_phdr(sip_parsed_header_t *header)
177 {
178 	sip_hdr_value_t	*value;
179 	sip_hdr_value_t	*next_value;
180 
181 	if (header == NULL)
182 		return;
183 	value = (sip_hdr_value_t *)header->value;
184 	while (value != NULL) {
185 		sip_free_params(value->sip_param_list);
186 		next_value = value->sip_next_value;
187 		free(value);
188 		value = next_value;
189 	}
190 	free(header);
191 }
192 
193 /*
194  * Free Contact/From/To header
195  */
196 void
197 sip_free_cftr_header(sip_parsed_header_t *header)
198 {
199 	sip_hdr_value_t	*value;
200 	sip_hdr_value_t	*next_value;
201 
202 	if (header == NULL)
203 		return;
204 	value = (sip_hdr_value_t *)header->value;
205 	while (value != NULL) {
206 		next_value = value->sip_next_value;
207 		sip_free_params(value->sip_param_list);
208 		if (value->cftr_name != NULL)
209 			free(value->cftr_name);
210 		if (value->sip_value_parsed_uri != NULL) {
211 			sip_free_parsed_uri(value->sip_value_parsed_uri);
212 			value->sip_value_parsed_uri = NULL;
213 		}
214 		free(value);
215 		value = next_value;
216 	}
217 	free(header);
218 }
219 
220 /*
221  * Return new header
222  */
223 _sip_header_t *
224 sip_new_header(int header_size)
225 {
226 	_sip_header_t *new_header;
227 
228 	new_header = calloc(1, sizeof (_sip_header_t));
229 	if (new_header == NULL)
230 		return (NULL);
231 
232 	/*
233 	 * We are using snprintf which adds a null character
234 	 * so allocate an extra byte which is not part of
235 	 * the message header
236 	 */
237 	new_header->sip_hdr_start = calloc(1, header_size + 1);
238 	if (new_header->sip_hdr_start == NULL) {
239 		free(new_header);
240 		return (NULL);
241 	}
242 	new_header->sip_hdr_end = new_header->sip_hdr_start + header_size;
243 	new_header->sip_hdr_current = new_header->sip_hdr_start;
244 	new_header->sip_hdr_allocated = B_TRUE;
245 	return (new_header);
246 }
247 
248 /*
249  * Free the given header
250  */
251 void
252 sip_free_header(_sip_header_t *sip_header)
253 {
254 	if (sip_header->sip_hdr_allocated) {
255 		assert(sip_header->sip_hdr_start != NULL);
256 		free(sip_header->sip_hdr_start);
257 	}
258 	if (sip_header->sip_hdr_parsed != NULL) {
259 		assert(sip_header->sip_header_functions != NULL);
260 		if (sip_header->sip_header_functions->header_free != NULL) {
261 			sip_header->sip_header_functions->header_free(
262 			    sip_header->sip_hdr_parsed);
263 		}
264 	}
265 	free(sip_header);
266 }
267 
268 /*
269  * Return a copy of the header passed in.
270  */
271 _sip_header_t *
272 sip_dup_header(_sip_header_t *from)
273 {
274 	size_t		hdr_size;
275 	_sip_header_t	*to;
276 
277 	hdr_size = from->sip_hdr_end - from->sip_hdr_start;
278 	to = sip_new_header(hdr_size);
279 	if (to == NULL)
280 		return (NULL);
281 	if (from->sip_header_state == SIP_HEADER_DELETED_VAL) {
282 		to->sip_hdr_end = to->sip_hdr_start +
283 		    sip_copy_values(to->sip_hdr_start, from);
284 	} else {
285 		(void) memcpy(to->sip_hdr_start, from->sip_hdr_start, hdr_size);
286 		to->sip_hdr_end = to->sip_hdr_start + hdr_size;
287 	}
288 	to->sip_header_functions = from->sip_header_functions;
289 	return (to);
290 }
291 
292 /*
293  * Copy header with extra_param, if any, to sip_msg
294  */
295 int
296 _sip_copy_header(_sip_msg_t *sip_msg, _sip_header_t *header, char *extra_param,
297     boolean_t skip_crlf)
298 {
299 	_sip_header_t	*new_header;
300 	int		hdrlen;
301 	int		extra_len = 0;
302 	int		ncrlf = 0;
303 	char		*p;
304 
305 #ifdef	__solaris__
306 	assert(mutex_held(&sip_msg->sip_msg_mutex));
307 #endif
308 	if (extra_param != NULL) {
309 		extra_len = SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
310 		    strlen(extra_param);
311 	}
312 	/*
313 	 * Just take one if there are more, i.e. if this is the last header
314 	 * before the content.
315 	 */
316 	if (skip_crlf) {
317 		if (header->sip_hdr_end - strlen(SIP_CRLF) <=
318 		    header->sip_hdr_start) {
319 			goto proceed;
320 		}
321 		p = header->sip_hdr_end - strlen(SIP_CRLF);
322 		while (strncmp(SIP_CRLF, p, strlen(SIP_CRLF)) == 0) {
323 			ncrlf++;
324 			if (p - strlen(SIP_CRLF) < header->sip_hdr_start)
325 				break;
326 			p -= strlen(SIP_CRLF);
327 		}
328 		/*
329 		 * Take one CRLF.
330 		 */
331 		ncrlf = (ncrlf - 1) * strlen(SIP_CRLF);
332 	}
333 proceed:
334 	hdrlen = header->sip_hdr_end - header->sip_hdr_start - ncrlf;
335 	new_header = sip_new_header(hdrlen + extra_len);
336 	if (new_header == NULL)
337 		return (ENOMEM);
338 	if (header->sip_header_state == SIP_HEADER_DELETED_VAL) {
339 		int	len;
340 
341 		len = sip_copy_values(new_header->sip_hdr_start, header);
342 		new_header->sip_hdr_end = new_header->sip_hdr_start + len;
343 		hdrlen = hdrlen - len + extra_len;
344 	} else {
345 		(void) memcpy(new_header->sip_hdr_start, header->sip_hdr_start,
346 		    hdrlen);
347 		new_header->sip_hdr_end = new_header->sip_hdr_start + hdrlen;
348 		hdrlen = extra_len;
349 	}
350 	if (extra_param != NULL) {
351 		/*
352 		 * Find CR
353 		 */
354 		if (sip_find_cr(new_header) != 0) {
355 			sip_free_header(new_header);
356 			return (EINVAL);
357 		}
358 		hdrlen += new_header->sip_hdr_end - new_header->sip_hdr_current;
359 		(void) snprintf(new_header->sip_hdr_current, hdrlen + 1,
360 		    " %c %s%s", SIP_SEMI, extra_param, SIP_CRLF);
361 	}
362 
363 	new_header->sip_hdr_end += extra_len;
364 	new_header->sip_header_functions = header->sip_header_functions;
365 	_sip_add_header(sip_msg, new_header, B_TRUE, B_FALSE, NULL);
366 	return (0);
367 }
368 
369 /*
370  * Copy all "header_name" headers from _old_msg to _new_msg
371  */
372 int
373 _sip_find_and_copy_all_header(_sip_msg_t *_old_msg, _sip_msg_t *_new_msg,
374     char *header_name)
375 {
376 	_sip_header_t	*header;
377 	int		ret = 0;
378 
379 	if (_old_msg == NULL || _new_msg == NULL)
380 		return (EINVAL);
381 #ifdef	__solaris__
382 	assert(mutex_held(&_old_msg->sip_msg_mutex));
383 #endif
384 	if (_old_msg != _new_msg)
385 		(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
386 	header = sip_search_for_header(_old_msg, header_name, NULL);
387 	while (header != NULL) {
388 		ret = _sip_copy_header(_new_msg, header, NULL, B_TRUE);
389 		if (ret != 0)
390 			break;
391 		header = sip_search_for_header(_old_msg, header_name, header);
392 	}
393 	if (_old_msg != _new_msg)
394 		(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
395 	return (ret);
396 }
397 
398 /*
399  * Copy header_name from _old_msg to _new_msg with extra_parm.
400  */
401 int
402 _sip_find_and_copy_header(sip_msg_t _old_msg, sip_msg_t _new_msg,
403     char *header_name, char *extra_param, boolean_t lock_newmsg)
404 {
405 	_sip_header_t	*header;
406 	int		ret;
407 
408 	if (_old_msg == NULL || _new_msg == NULL)
409 		return (EINVAL);
410 #ifdef	__solaris__
411 	assert(mutex_held(&_old_msg->sip_msg_mutex));
412 #endif
413 	header = sip_search_for_header(_old_msg, header_name, NULL);
414 	if (header == NULL)
415 		return (EINVAL);
416 	if (lock_newmsg)
417 		(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
418 	ret = _sip_copy_header(_new_msg, header, extra_param, B_TRUE);
419 	if (lock_newmsg)
420 		(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
421 	return (ret);
422 }
423 
424 /*
425  * Copy all headers from old_msg to new_msg
426  */
427 int
428 sip_copy_all_headers(sip_msg_t old_msg, sip_msg_t new_msg)
429 {
430 	_sip_header_t	*header;
431 	_sip_msg_t	*_old_msg;
432 	_sip_msg_t	*_new_msg;
433 	int		ret = 0;
434 
435 	if (old_msg == NULL || new_msg == NULL)
436 		return (EINVAL);
437 	_old_msg = (_sip_msg_t *)old_msg;
438 	_new_msg = (_sip_msg_t *)new_msg;
439 
440 	(void) pthread_mutex_lock(&_old_msg->sip_msg_mutex);
441 	(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
442 	header = sip_search_for_header(_old_msg, NULL, NULL);
443 	while (header != NULL) {
444 		ret = _sip_copy_header(_new_msg, header, NULL, B_FALSE);
445 		if (ret != 0)
446 			goto done;
447 		header = sip_search_for_header(_old_msg, NULL, header);
448 	}
449 done:
450 	(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
451 	(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
452 	return (ret);
453 }
454 
455 /*
456  * Copy start line from msg to sip_msg
457  */
458 int
459 sip_copy_start_line(sip_msg_t msg, sip_msg_t sip_msg)
460 {
461 	int		len;
462 	_sip_header_t	*new_header;
463 	_sip_msg_t	*_old_msg;
464 	_sip_msg_t	*_sip_msg;
465 
466 	if (msg == NULL || sip_msg == NULL)
467 		return (EINVAL);
468 	_old_msg = (_sip_msg_t *)msg;
469 	_sip_msg = (_sip_msg_t *)sip_msg;
470 
471 	(void) pthread_mutex_lock(&_old_msg->sip_msg_mutex);
472 	if (_old_msg->sip_msg_start_line == NULL) {
473 		(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
474 		return (EINVAL);
475 	}
476 	len = _old_msg->sip_msg_start_line->sip_hdr_end -
477 	    _old_msg->sip_msg_start_line->sip_hdr_start;
478 	new_header = sip_new_header(len);
479 	if (new_header == NULL) {
480 		(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
481 		return (ENOMEM);
482 	}
483 	new_header->sip_hdr_sipmsg = _sip_msg;
484 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
485 	_sip_msg->sip_msg_start_line = new_header;
486 	_sip_msg->sip_msg_len = len;
487 	(void) strncpy(_sip_msg->sip_msg_start_line->sip_hdr_start,
488 	    _old_msg->sip_msg_start_line->sip_hdr_start, len);
489 	(void) sip_parse_first_line(_sip_msg->sip_msg_start_line,
490 	    &_sip_msg->sip_msg_req_res);
491 	(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
492 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
493 	return (0);
494 }
495 
496 /*
497  * Delete start line from sip_msg
498  */
499 int
500 sip_delete_start_line_locked(_sip_msg_t *_sip_msg)
501 {
502 	_sip_header_t	*header;
503 	_sip_header_t	*next_header;
504 
505 	if (_sip_msg->sip_msg_start_line == NULL)
506 		return (EINVAL);
507 
508 	header = _sip_msg->sip_msg_start_line;
509 	while (header != NULL) {
510 		next_header = header->sip_hdr_next;
511 		_sip_msg->sip_msg_len -= (header->sip_hdr_end -
512 		    header->sip_hdr_start);
513 		sip_free_header(header);
514 		header = next_header;
515 	}
516 	_sip_msg->sip_msg_start_line = NULL;
517 
518 	/*
519 	 * Also delete the sip_msg_req_res info since we don't have a start
520 	 * line.
521 	 */
522 	while (_sip_msg->sip_msg_req_res != NULL) {
523 		sip_message_type_t	*sip_msg_type_ptr;
524 
525 		sip_msg_type_ptr = _sip_msg->sip_msg_req_res->sip_next;
526 		if (_sip_msg->sip_msg_req_res->is_request) {
527 			sip_request_t	*reqline;
528 
529 			reqline = &_sip_msg->sip_msg_req_res->U.sip_request;
530 			if (reqline->sip_parse_uri != NULL) {
531 				sip_free_parsed_uri(reqline->sip_parse_uri);
532 				reqline->sip_parse_uri = NULL;
533 			}
534 		}
535 		free(_sip_msg->sip_msg_req_res);
536 		_sip_msg->sip_msg_req_res = sip_msg_type_ptr;
537 	}
538 	return (0);
539 }
540 
541 
542 /*
543  * Delete start line from sip_msg
544  */
545 int
546 sip_delete_start_line(sip_msg_t sip_msg)
547 {
548 	_sip_msg_t	*_sip_msg;
549 	int		ret;
550 
551 	if (sip_msg == NULL)
552 		return (EINVAL);
553 
554 	_sip_msg = (_sip_msg_t *)sip_msg;
555 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
556 	ret = sip_delete_start_line_locked(_sip_msg);
557 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
558 
559 	return (ret);
560 }
561 
562 /*
563  * Delete all headers from _sip_msg
564  */
565 void
566 sip_delete_all_headers(_sip_msg_t *_sip_msg)
567 {
568 	_sip_header_t *header;
569 
570 #ifdef	__solaris__
571 	assert(mutex_held(&_sip_msg->sip_msg_mutex));
572 #endif
573 
574 	header = _sip_msg->sip_msg_headers_start;
575 	while (header != NULL) {
576 		_sip_header_t *next_header;
577 		next_header = header->sip_hdr_next;
578 		sip_free_header(header);
579 		header = next_header;
580 	}
581 	_sip_msg->sip_msg_headers_start = NULL;
582 	_sip_msg->sip_msg_headers_end = NULL;
583 }
584 
585 /*
586  * Delete and free the named header. If header_name is null
587  * free all headers.
588  */
589 void
590 sip_delete_headers(sip_msg_t sip_msg, char *header_name)
591 {
592 	_sip_header_t *header;
593 	_sip_msg_t *_sip_msg;
594 
595 	_sip_msg = (_sip_msg_t *)sip_msg;
596 #ifdef	__solaris__
597 	assert(mutex_held(&_sip_msg->sip_msg_mutex));
598 #endif
599 	header = sip_search_for_header(_sip_msg, header_name, NULL);
600 	if (header == NULL)
601 		return;
602 	while (header != NULL) {
603 		if (_sip_msg->sip_msg_headers_start == header) {
604 			_sip_msg->sip_msg_headers_start = header->sip_hdr_next;
605 		} else {
606 			header->sip_hdr_prev->sip_hdr_next =
607 			    header->sip_hdr_next;
608 		}
609 		if (_sip_msg->sip_msg_headers_end == header) {
610 			_sip_msg->sip_msg_headers_end = header->sip_hdr_prev;
611 		} else {
612 			header->sip_hdr_next->sip_hdr_prev =
613 			    header->sip_hdr_prev;
614 		}
615 		sip_free_header(header);
616 		if (header_name != NULL)
617 			return;
618 		else
619 			header = sip_search_for_header(_sip_msg, NULL, NULL);
620 	}
621 }
622 
623 /*
624  * Add a header to sip_msg. If header_name is provided then the new header
625  * is added before that header, if first is set, or after. If append is
626  * set, then the header is added to the end of the header list.
627  */
628 void
629 _sip_add_header(_sip_msg_t *sip_msg, _sip_header_t *new_header,
630     boolean_t append, boolean_t first, char *header_name)
631 {
632 	_sip_header_t	*header = NULL;
633 
634 	if (sip_msg == NULL || new_header == NULL)
635 		return;
636 #ifdef	__solaris__
637 	assert(mutex_held(&sip_msg->sip_msg_mutex));
638 #endif
639 	new_header->sip_hdr_sipmsg = sip_msg;
640 	if (header_name != NULL) {
641 		_sip_header_t	*header_tmp;
642 
643 		header = sip_search_for_header(sip_msg, header_name, NULL);
644 		header_tmp = header;
645 		if (!first) {
646 			while (header != NULL) {
647 				header_tmp = header;
648 				header = sip_search_for_header(sip_msg,
649 				    header_name, header);
650 			}
651 		}
652 		header = header_tmp;
653 		if (header == NULL)
654 			append =  B_TRUE;
655 	}
656 
657 	if (header != NULL) {
658 		if (append) {
659 			new_header->sip_hdr_prev = header;
660 			if (sip_msg->sip_msg_headers_end == header) {
661 				sip_msg->sip_msg_headers_end = new_header;
662 				new_header->sip_hdr_next = NULL;
663 			} else {
664 				header->sip_hdr_next->sip_hdr_prev = new_header;
665 				new_header->sip_hdr_next = header->sip_hdr_next;
666 			}
667 			header->sip_hdr_next = new_header;
668 		} else {
669 			new_header->sip_hdr_next = header;
670 			if (sip_msg->sip_msg_headers_start == header) {
671 				sip_msg->sip_msg_headers_start = new_header;
672 				new_header->sip_hdr_prev = NULL;
673 			} else {
674 				header->sip_hdr_prev->sip_hdr_next = new_header;
675 				new_header->sip_hdr_prev = header->sip_hdr_prev;
676 			}
677 			header->sip_hdr_prev = new_header;
678 		}
679 	} else {
680 		if (append) {
681 			if (sip_msg->sip_msg_headers_end != NULL) {
682 				sip_msg->sip_msg_headers_end->sip_hdr_next =
683 				    new_header;
684 			} else {
685 				sip_msg->sip_msg_headers_start = new_header;
686 			}
687 			new_header->sip_hdr_prev =
688 			    sip_msg->sip_msg_headers_end;
689 			new_header->sip_hdr_next = NULL;
690 			sip_msg->sip_msg_headers_end = new_header;
691 		} else {
692 			if (sip_msg->sip_msg_headers_start != NULL) {
693 				sip_msg->sip_msg_headers_start->sip_hdr_prev =
694 				    new_header;
695 			} else {
696 				sip_msg->sip_msg_headers_end = new_header;
697 			}
698 			new_header->sip_hdr_next =
699 			    sip_msg->sip_msg_headers_start;
700 			new_header->sip_hdr_prev = NULL;
701 			sip_msg->sip_msg_headers_start = new_header;
702 		}
703 	}
704 	sip_msg->sip_msg_len += new_header->sip_hdr_end -
705 	    new_header->sip_hdr_start;
706 }
707 
708 /*
709  * Scan through the function table and return the entry for the given header
710  * type.
711  */
712 sip_header_function_t *
713 _sip_get_header_functions(sip_header_function_t *sip_header_function_table,
714     _sip_header_t *sip_header, char *header_name)
715 {
716 	int	len;
717 	int	i = 0;
718 
719 	if (sip_header == NULL && header_name == NULL)
720 		return (NULL);
721 
722 	/*
723 	 * If header_name is NULL we first have to locate the name
724 	 */
725 	if (header_name == NULL) {
726 		if (sip_skip_white_space(sip_header) != 0) {
727 			return (NULL);
728 		}
729 		header_name = sip_header->sip_hdr_current;
730 		if (sip_find_separator(sip_header, SIP_HCOLON, (char)NULL,
731 		    (char)NULL, B_FALSE) != 0) {
732 			return (NULL);
733 		}
734 		len = sip_header->sip_hdr_current - header_name;
735 	} else {
736 		len = strlen(header_name);
737 	}
738 
739 	if (len > 0) {
740 		while (sip_header_function_table[i].header_name != NULL ||
741 		    sip_header_function_table[i].header_short_name != NULL) {
742 			if (sip_header_function_table[i].header_name != NULL &&
743 			    len ==
744 			    strlen(sip_header_function_table[i].header_name)) {
745 				if (strncasecmp(header_name,
746 				    sip_header_function_table[i].
747 				    header_name, len) == 0) {
748 					break;
749 				}
750 			} else if (sip_header_function_table[i].
751 			    header_short_name != NULL && len ==
752 			    strlen(sip_header_function_table[i].
753 			    header_short_name)) {
754 				if (strncasecmp(header_name,
755 				    sip_header_function_table[i].
756 				    header_short_name, len) == 0) {
757 					break;
758 				}
759 			}
760 			i++;
761 		}
762 	}
763 
764 	if (sip_header != NULL)
765 		sip_header->sip_hdr_current = sip_header->sip_hdr_start;
766 	if (sip_header_function_table[i].header_name == NULL)
767 		return (NULL);
768 	return (&sip_header_function_table[i]);
769 }
770 
771 /*
772  * Return the entry from the function table for the given header
773  */
774 sip_header_function_t *
775 sip_get_header_functions(_sip_header_t *sip_header, char *header_name)
776 {
777 	sip_header_function_t	*func;
778 	sip_header_function_t	*header_f_table = NULL;
779 
780 	if (sip_header_function_table_external != NULL) {
781 		header_f_table = _sip_get_header_functions(
782 		    sip_header_function_table_external,
783 		    sip_header, header_name);
784 		if (header_f_table != NULL)
785 			return (header_f_table);
786 	}
787 	func = _sip_get_header_functions(sip_header_function_table, sip_header,
788 	    header_name);
789 	return (func);
790 }
791 
792 /*
793  * Search for the header name passed in.
794  */
795 _sip_header_t *
796 sip_search_for_header(_sip_msg_t *sip_msg, char *header_name,
797     _sip_header_t *old_header)
798 {
799 	int			len = 0;
800 	int			full_len = 0;
801 	int			compact_len = 0;
802 	_sip_header_t		*header = NULL;
803 	char			*compact_name = NULL;
804 	char			*full_name = NULL;
805 	sip_header_function_t	*header_f_table = NULL;
806 
807 	if (sip_msg == NULL)
808 		return (NULL);
809 #ifdef	__solaris__
810 	assert(mutex_held(&sip_msg->sip_msg_mutex));
811 #endif
812 
813 	if (header_name != NULL) {
814 		header_f_table = sip_get_header_functions(NULL, header_name);
815 		if (header_f_table != NULL) {
816 			full_name = header_f_table->header_name;
817 			compact_name = header_f_table->header_short_name;
818 			if (full_name != NULL)
819 				full_len = strlen(full_name);
820 			if (compact_name != NULL)
821 				compact_len = strlen(compact_name);
822 		} else {
823 			header_f_table = &sip_header_function_table[0];
824 			full_name = header_name;
825 			full_len  = strlen(full_name);
826 		}
827 	}
828 
829 	if (old_header != NULL)
830 		header = old_header->sip_hdr_next;
831 	else
832 		header = sip_msg->sip_msg_headers_start;
833 
834 	while (header != NULL) {
835 
836 		if (header->sip_header_state == SIP_HEADER_DELETED) {
837 			header = header->sip_hdr_next;
838 			continue;
839 		}
840 
841 		if (compact_len == 0 && full_len == 0)
842 			break;
843 
844 		header->sip_hdr_current = header->sip_hdr_start;
845 
846 		if (sip_skip_white_space(header)) {
847 			header = header->sip_hdr_next;
848 			continue;
849 		}
850 
851 		len = header->sip_hdr_end - header->sip_hdr_current;
852 
853 		if (full_name != NULL && (full_len <= len) &&
854 		    strncasecmp(header->sip_hdr_current, full_name,
855 		    full_len) == 0) {
856 			header->sip_hdr_current += full_len;
857 			if (sip_skip_white_space(header)) {
858 				header = header->sip_hdr_next;
859 				continue;
860 			}
861 
862 			if (*header->sip_hdr_current == SIP_HCOLON) {
863 				header_name = full_name;
864 				break;
865 			}
866 		}
867 
868 		if (compact_name != NULL && (compact_len <= len) &&
869 		    strncasecmp(header->sip_hdr_current, compact_name,
870 		    compact_len) == 0) {
871 			header->sip_hdr_current += compact_len;
872 			if (sip_skip_white_space(header)) {
873 				header = header->sip_hdr_next;
874 				continue;
875 			}
876 			if (*header->sip_hdr_current == SIP_HCOLON) {
877 				header_name = compact_name;
878 				break;
879 			}
880 		}
881 		header = header->sip_hdr_next;
882 	}
883 
884 	if (header != NULL) {
885 		header->sip_hdr_current = header->sip_hdr_start;
886 		if (header_f_table == NULL) {
887 			header_f_table =
888 			    sip_get_header_functions(header, header_name);
889 			if (header_f_table == NULL)
890 				header_f_table = &sip_header_function_table[0];
891 		}
892 
893 		header->sip_header_functions = header_f_table;
894 	}
895 	return (header);
896 }
897 
898 /*
899  * Return the start line as a string. Caller frees string
900  */
901 char *
902 _sip_startline_to_str(_sip_msg_t *sip_msg, int *error)
903 {
904 	char		*slstr;
905 	int		len;
906 
907 	if (error != NULL)
908 		*error = 0;
909 
910 	if (sip_msg == NULL || sip_msg->sip_msg_start_line == NULL) {
911 		if (error != NULL)
912 			*error = EINVAL;
913 		return (NULL);
914 	}
915 	(void) pthread_mutex_lock(&sip_msg->sip_msg_mutex);
916 	len = sip_msg->sip_msg_start_line->sip_hdr_end -
917 	    sip_msg->sip_msg_start_line->sip_hdr_start - 2;
918 	if ((slstr = malloc(len + 1)) == NULL) {
919 		(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
920 		if (error != NULL)
921 			*error = ENOMEM;
922 		return (NULL);
923 	}
924 	(void) strncpy(slstr, sip_msg->sip_msg_start_line->sip_hdr_start, len);
925 	(void) pthread_mutex_unlock(&sip_msg->sip_msg_mutex);
926 	slstr[len] = '\0';
927 	return (slstr);
928 }
929 
930 /*
931  * Return the given header as a string. Caller frees string
932  */
933 char *
934 sip_hdr_to_str(sip_header_t sip_header, int *error)
935 {
936 	char		*hdrstr;
937 	char		*tmpptr;
938 	_sip_header_t	*_sip_header;
939 	int		len;
940 
941 	if (error != NULL)
942 		*error = 0;
943 
944 	if (sip_header == NULL) {
945 		if (error != NULL)
946 			*error = EINVAL;
947 		return (NULL);
948 	}
949 	_sip_header = (_sip_header_t *)sip_header;
950 	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
951 		if (_sip_header->sip_hdr_sipmsg != NULL) {
952 			(void) pthread_mutex_unlock(
953 			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
954 		}
955 		if (error != NULL)
956 			*error = EINVAL;
957 		return (NULL);
958 	}
959 	if (_sip_header->sip_hdr_sipmsg != NULL) {
960 		(void) pthread_mutex_lock(
961 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
962 	}
963 	len = _sip_header->sip_hdr_end - _sip_header->sip_hdr_start;
964 	hdrstr = malloc(len);
965 	if (hdrstr == NULL) {
966 		if (_sip_header->sip_hdr_sipmsg != NULL) {
967 			(void) pthread_mutex_unlock(
968 			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
969 		}
970 		if (error != NULL)
971 			*error = ENOMEM;
972 		return (NULL);
973 	}
974 	if (_sip_header->sip_header_state == SIP_HEADER_DELETED_VAL) {
975 		len = sip_copy_values(hdrstr, _sip_header);
976 	} else {
977 		(void) strncpy(hdrstr, _sip_header->sip_hdr_start, len);
978 	}
979 	if (_sip_header->sip_hdr_sipmsg != NULL) {
980 		(void) pthread_mutex_unlock(
981 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
982 	}
983 	tmpptr = hdrstr + len;
984 	while (*tmpptr-- != '\n') {
985 		if (tmpptr == _sip_header->sip_hdr_start) {
986 			free(hdrstr);
987 			if (error != NULL)
988 				*error = EINVAL;
989 			return (NULL);
990 		}
991 	}
992 	*tmpptr = '\0';
993 	return (hdrstr);
994 }
995 
996 /*
997  * Given a param list find the named parameter.
998  * Returns a pointer to the value or NULL.
999  */
1000 sip_param_t *
1001 sip_get_param_from_list(sip_param_t *param_list, char *param_name)
1002 {
1003 	while (param_list != NULL) {
1004 		if (param_list->param_name.sip_str_len == strlen(param_name) &&
1005 		    strncasecmp(param_list->param_name.sip_str_ptr, param_name,
1006 		    strlen(param_name)) == 0) {
1007 			return (param_list);
1008 		}
1009 		param_list = param_list->param_next;
1010 	}
1011 	return (NULL);
1012 }
1013