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