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