xref: /illumos-gate/usr/src/lib/libsip/common/sip_ui.c (revision 2c2c4183)
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 <stdlib.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <strings.h>
35 #include <pthread.h>
36 #include <sip.h>
37 
38 #include "sip_msg.h"
39 #include "sip_miscdefs.h"
40 #include "sip_parse_uri.h"
41 #include "sip_xaction.h"
42 
43 #define	SIP_BUF_SIZE	128
44 
45 /*
46  * Find the header named header, consecutive calls with old_header
47  * passed in will return next header of the same type.
48  * If no name is passed the first header is returned. consectutive calls
49  * with no name but an old header will return the next header.
50  */
51 const struct sip_header *
52 sip_get_header(sip_msg_t sip_msg, char *header_name, sip_header_t old_header,
53     int *error)
54 {
55 	_sip_msg_t		*_sip_msg;
56 	const struct sip_header	*sip_hdr;
57 
58 	if (error != NULL)
59 		*error = 0;
60 	if (sip_msg == NULL) {
61 		if (error != NULL)
62 			*error = EINVAL;
63 		return (NULL);
64 	}
65 	_sip_msg = (_sip_msg_t *)sip_msg;
66 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
67 	sip_hdr = (sip_header_t)sip_search_for_header((_sip_msg_t *)sip_msg,
68 	    header_name, (_sip_header_t *)old_header);
69 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
70 	if (sip_hdr == NULL && error != NULL)
71 		*error = EINVAL;
72 	return (sip_hdr);
73 }
74 
75 /*
76  * Return the request line as a string. Caller releases the returned string.
77  */
78 char *
79 sip_reqline_to_str(sip_msg_t sip_msg, int *error)
80 {
81 	char	*reqstr;
82 
83 	if (error != NULL)
84 		*error = 0;
85 	if (sip_msg == NULL || !sip_msg_is_request(sip_msg, error)) {
86 		if (error != NULL)
87 			*error = EINVAL;
88 		return (NULL);
89 	}
90 	reqstr = _sip_startline_to_str((_sip_msg_t *)sip_msg, error);
91 	return (reqstr);
92 }
93 
94 /*
95  * Return the response line as a string. Caller releases the returned string.
96  */
97 char *
98 sip_respline_to_str(sip_msg_t sip_msg, int *error)
99 {
100 	char	*respstr;
101 
102 	if (error != NULL)
103 		*error = 0;
104 	if (sip_msg == NULL || sip_msg_is_request(sip_msg, error)) {
105 		if (error != NULL)
106 			*error = EINVAL;
107 		return (NULL);
108 	}
109 	respstr = _sip_startline_to_str((_sip_msg_t *)sip_msg, error);
110 	return (respstr);
111 }
112 
113 /*
114  * return the first value of the header
115  */
116 const struct sip_value *
117 sip_get_header_value(const struct sip_header *sip_header, int *error)
118 {
119 	_sip_header_t		*_sip_header;
120 	sip_parsed_header_t	*sip_parsed_header;
121 	int			ret = 0;
122 	const struct sip_value	*value;
123 
124 	if (error != NULL)
125 		*error = 0;
126 	if (sip_header == NULL) {
127 		if (error != NULL)
128 			*error = EINVAL;
129 		return (NULL);
130 	}
131 	_sip_header = (_sip_header_t *)sip_header;
132 	if (_sip_header->sip_hdr_sipmsg != NULL) {
133 		(void) pthread_mutex_lock(
134 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
135 	}
136 	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
137 		if (_sip_header->sip_hdr_sipmsg != NULL) {
138 			(void) pthread_mutex_unlock(
139 			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
140 		}
141 		if (error != NULL)
142 			*error = EINVAL;
143 		return (NULL);
144 	}
145 	ret = _sip_header->sip_header_functions->header_parse_func(
146 	    _sip_header, &sip_parsed_header);
147 	if (_sip_header->sip_hdr_sipmsg != NULL) {
148 		(void) pthread_mutex_unlock
149 		    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
150 	}
151 	if (error != NULL)
152 		*error = ret;
153 
154 	if (ret != 0)
155 		return (NULL);
156 	value = (sip_header_value_t)sip_parsed_header->value;
157 	while (value != NULL && value->value_state == SIP_VALUE_DELETED)
158 		value = value->next;
159 	if (value != NULL && value->value_state == SIP_VALUE_BAD &&
160 	    error != NULL) {
161 		*error = EPROTO;
162 	}
163 	return ((sip_header_value_t)value);
164 }
165 
166 /*
167  * Return the next value of the header.
168  */
169 const struct sip_value *
170 sip_get_next_value(sip_header_value_t old_value, int *error)
171 {
172 	const struct sip_value *value;
173 
174 	if (error != NULL)
175 		*error = 0;
176 	if (old_value == NULL || old_value->next == NULL) {
177 		if (error != NULL)
178 			*error = EINVAL;
179 		return (NULL);
180 	}
181 	/*
182 	 * We never free the deleted values so no need to hold a lock.
183 	 */
184 	value = (sip_header_value_t)old_value->next;
185 	while (value != NULL && value->value_state == SIP_VALUE_DELETED)
186 		value = value->next;
187 	if (value != NULL && value->value_state == SIP_VALUE_BAD &&
188 	    error != NULL) {
189 		*error = EPROTO;
190 	}
191 	return ((sip_header_value_t)value);
192 }
193 
194 /*
195  * Given a SIP message, delete the header "header_name".
196  */
197 int
198 sip_delete_header_by_name(sip_msg_t msg, char *header_name)
199 {
200 	_sip_msg_t	*_msg = (_sip_msg_t *)msg;
201 	sip_header_t	sip_hdr;
202 	_sip_header_t	*_sip_hdr;
203 
204 	if (_msg == NULL || header_name == NULL)
205 		return (EINVAL);
206 	(void) pthread_mutex_lock(&_msg->sip_msg_mutex);
207 	if (_msg->sip_msg_cannot_be_modified) {
208 		(void) pthread_mutex_unlock(&_msg->sip_msg_mutex);
209 		return (EPERM);
210 	}
211 	sip_hdr = (sip_header_t)sip_search_for_header(_msg, header_name, NULL);
212 	if (sip_hdr == NULL) {
213 		(void) pthread_mutex_unlock(&_msg->sip_msg_mutex);
214 		return (EINVAL);
215 	}
216 	_sip_hdr = (_sip_header_t *)sip_hdr;
217 	_sip_hdr->sip_header_state = SIP_HEADER_DELETED;
218 	_sip_hdr->sip_hdr_sipmsg->sip_msg_len -= _sip_hdr->sip_hdr_end -
219 	    _sip_hdr->sip_hdr_start;
220 	assert(_sip_hdr->sip_hdr_sipmsg->sip_msg_len >= 0);
221 	if (_msg->sip_msg_buf != NULL)
222 		_msg->sip_msg_modified = B_TRUE;
223 	(void) pthread_mutex_unlock(&_msg->sip_msg_mutex);
224 
225 	return (0);
226 }
227 
228 /*
229  * Mark the header as deleted.
230  */
231 int
232 sip_delete_header(sip_header_t sip_header)
233 {
234 	_sip_header_t	*_sip_header;
235 
236 	if (sip_header == NULL)
237 		return (EINVAL);
238 	_sip_header = (_sip_header_t *)sip_header;
239 	(void) pthread_mutex_lock(&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
240 	if (_sip_header->sip_hdr_sipmsg->sip_msg_cannot_be_modified) {
241 		(void) pthread_mutex_unlock
242 		    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
243 		return (EPERM);
244 	}
245 	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
246 		(void) pthread_mutex_unlock(
247 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
248 		return (EINVAL);
249 	}
250 	_sip_header->sip_header_state = SIP_HEADER_DELETED;
251 	_sip_header->sip_hdr_sipmsg->sip_msg_len -= _sip_header->sip_hdr_end -
252 	    _sip_header->sip_hdr_start;
253 	assert(_sip_header->sip_hdr_sipmsg->sip_msg_len >= 0);
254 	if (_sip_header->sip_hdr_sipmsg->sip_msg_buf != NULL)
255 		_sip_header->sip_hdr_sipmsg->sip_msg_modified = B_TRUE;
256 	(void) pthread_mutex_unlock
257 	    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
258 	return (0);
259 }
260 
261 /*
262  * Mark the value as deleted.
263  */
264 int
265 sip_delete_value(sip_header_t sip_header, sip_header_value_t sip_header_value)
266 {
267 	_sip_header_t	*_sip_header;
268 	sip_value_t	*_sip_header_value;
269 	int		vlen;
270 	char		*c;
271 
272 	if (sip_header == NULL || sip_header_value == NULL)
273 		return (EINVAL);
274 	_sip_header = (_sip_header_t *)sip_header;
275 	(void) pthread_mutex_lock(&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
276 	if (_sip_header->sip_hdr_sipmsg->sip_msg_cannot_be_modified) {
277 		(void) pthread_mutex_unlock(&_sip_header->
278 		    sip_hdr_sipmsg->sip_msg_mutex);
279 		return (EPERM);
280 	}
281 	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
282 		(void) pthread_mutex_unlock(
283 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
284 		return (EINVAL);
285 	}
286 	_sip_header_value = (sip_value_t *)sip_header_value;
287 	if (_sip_header_value->value_state == SIP_VALUE_DELETED) {
288 		(void) pthread_mutex_unlock(
289 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
290 		return (EINVAL);
291 	}
292 	_sip_header->sip_header_state = SIP_HEADER_DELETED_VAL;
293 	_sip_header_value->value_state = SIP_VALUE_DELETED;
294 	vlen = _sip_header_value->value_end - _sip_header_value->value_start;
295 	if (_sip_header->sip_hdr_parsed->value == _sip_header_value) {
296 		c = _sip_header_value->value_start;
297 		while (*c-- != SIP_HCOLON)
298 			vlen++;
299 	} else {
300 		c = _sip_header_value->value_start;
301 		while (*c-- != SIP_COMMA)
302 			vlen++;
303 	}
304 	if (_sip_header_value->next == NULL) {
305 		sip_value_t	*value = _sip_header->sip_hdr_parsed->value;
306 		boolean_t	crlf_present =  B_FALSE;
307 		char		*s;
308 
309 		while (value != NULL && value != _sip_header_value) {
310 			crlf_present = B_FALSE;
311 
312 			if (value->value_state == SIP_VALUE_DELETED) {
313 				value = value->next;
314 				continue;
315 			}
316 			s = value->value_end;
317 			while (s != value->value_start) {
318 				if (*s == '\r' && strncmp(s, SIP_CRLF,
319 				    strlen(SIP_CRLF)) == 0) {
320 					crlf_present = B_TRUE;
321 					break;
322 				}
323 				s--;
324 			}
325 			value = value->next;
326 		}
327 		if (!crlf_present) {
328 			c = _sip_header_value->value_end;
329 			while (*c-- != '\r')
330 				vlen--;
331 			assert(vlen > 0);
332 		}
333 	}
334 	_sip_header->sip_hdr_sipmsg->sip_msg_len -= vlen;
335 	if (_sip_header->sip_hdr_sipmsg->sip_msg_buf != NULL)
336 		_sip_header->sip_hdr_sipmsg->sip_msg_modified = B_TRUE;
337 	(void) pthread_mutex_unlock
338 	    (&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
339 	return (0);
340 }
341 
342 /*
343  * Given a param list, check if a param name exists.
344  */
345 boolean_t
346 sip_is_param_present(const sip_param_t *param_list, char *param_name,
347     int param_len)
348 {
349 	const sip_param_t	*param = param_list;
350 
351 	while (param != NULL) {
352 		if (param->param_name.sip_str_len == param_len &&
353 		    strncasecmp(param->param_name.sip_str_ptr, param_name,
354 			param_len) == 0) {
355 			return (B_TRUE);
356 		}
357 		param = param->param_next;
358 	}
359 	return (B_FALSE);
360 }
361 
362 
363 /*
364  * Given a value header return the value of the named param.
365  */
366 const sip_str_t *
367 sip_get_param_value(sip_header_value_t header_value, char *param_name,
368     int *error)
369 {
370 	sip_value_t	*_sip_header_value;
371 	sip_param_t	*sip_param;
372 
373 	if (error != NULL)
374 		*error = 0;
375 	if (header_value == NULL || param_name == NULL) {
376 		if (error != NULL)
377 			*error = EINVAL;
378 		return (NULL);
379 	}
380 	_sip_header_value = (sip_value_t *)header_value;
381 	if (_sip_header_value->value_state == SIP_VALUE_DELETED) {
382 		if (error != NULL)
383 			*error = EINVAL;
384 		return (NULL);
385 	}
386 	if (_sip_header_value->param_list == NULL) {
387 		if (error != NULL)
388 			*error = EINVAL;
389 		return (NULL);
390 	}
391 	sip_param = sip_get_param_from_list(_sip_header_value->param_list,
392 	    param_name);
393 	if (sip_param != NULL)
394 		return (&sip_param->param_value);
395 	return (NULL);
396 }
397 
398 /*
399  * Return the list of params in the header
400  */
401 const sip_param_t *
402 sip_get_params(sip_header_value_t header_value, int *error)
403 {
404 	sip_value_t	*sip_header_value;
405 
406 	if (error != NULL)
407 		*error = 0;
408 	if (header_value == NULL) {
409 		if (error != NULL)
410 			*error = EINVAL;
411 		return (NULL);
412 	}
413 	sip_header_value = (sip_value_t *)header_value;
414 	if (sip_header_value->value_state == SIP_VALUE_DELETED) {
415 		if (error != NULL)
416 			*error = EINVAL;
417 		return (NULL);
418 	}
419 	return (sip_header_value->param_list);
420 }
421 
422 /*
423  * Return true if this is a SIP request
424  */
425 boolean_t
426 sip_msg_is_request(sip_msg_t sip_msg, int *error)
427 {
428 	_sip_msg_t		*_sip_msg;
429 	sip_message_type_t	*sip_msg_info;
430 	boolean_t		ret;
431 
432 	if (error != NULL)
433 		*error = 0;
434 	if (sip_msg == NULL) {
435 		if (error != NULL)
436 			*error = EINVAL;
437 		return (B_FALSE);
438 	}
439 	_sip_msg = (_sip_msg_t *)sip_msg;
440 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
441 	if (_sip_msg->sip_msg_req_res == NULL) {
442 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
443 		if (error != NULL)
444 			*error = EINVAL;
445 		return (B_FALSE);
446 	}
447 	sip_msg_info = _sip_msg->sip_msg_req_res;
448 	ret = sip_msg_info->is_request;
449 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
450 	return (ret);
451 }
452 
453 /*
454  * Return true if this is a SIP response
455  */
456 boolean_t
457 sip_msg_is_response(sip_msg_t sip_msg, int *error)
458 {
459 	boolean_t		is_resp;
460 	_sip_msg_t		*_sip_msg;
461 	sip_message_type_t	*sip_msg_info;
462 
463 	if (error != NULL)
464 		*error = 0;
465 	if (sip_msg == NULL) {
466 		if (error != NULL)
467 			*error = EINVAL;
468 		return (B_FALSE);
469 	}
470 	_sip_msg = (_sip_msg_t *)sip_msg;
471 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
472 	if (_sip_msg->sip_msg_req_res == NULL) {
473 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
474 		if (error != NULL)
475 			*error = EINVAL;
476 		return (B_FALSE);
477 	}
478 	sip_msg_info = _sip_msg->sip_msg_req_res;
479 	is_resp = !sip_msg_info->is_request;
480 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
481 	return (is_resp);
482 }
483 
484 /*
485  * Return the method in the request line
486  */
487 sip_method_t
488 sip_get_request_method(sip_msg_t sip_msg, int *error)
489 {
490 	_sip_msg_t		*_sip_msg;
491 	sip_message_type_t	*sip_msg_info;
492 	sip_method_t 		ret = -1;
493 
494 	if (error != NULL)
495 		*error = 0;
496 	if (sip_msg == NULL) {
497 		if (error != NULL)
498 			*error = EINVAL;
499 		return (ret);
500 	}
501 	_sip_msg = (_sip_msg_t *)sip_msg;
502 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
503 	sip_msg_info = _sip_msg->sip_msg_req_res;
504 	if (_sip_msg->sip_msg_req_res == NULL) {
505 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
506 		if (error != NULL)
507 			*error = EINVAL;
508 		return (ret);
509 	}
510 	if (sip_msg_info->is_request)
511 		ret = sip_msg_info->sip_req_method;
512 	else if (error != NULL)
513 		*error = EINVAL;
514 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
515 	return (ret);
516 }
517 
518 /*
519  * Return the URI from the request line
520  */
521 const sip_str_t *
522 sip_get_request_uri_str(sip_msg_t sip_msg, int *error)
523 {
524 	_sip_msg_t		*_sip_msg;
525 	sip_message_type_t	*sip_msg_info;
526 	sip_str_t 		*ret = NULL;
527 	struct sip_uri		*parsed_uri;
528 
529 	if (error != NULL)
530 		*error = 0;
531 	if (sip_msg == NULL) {
532 		if (error != NULL)
533 			*error = EINVAL;
534 		return (NULL);
535 	}
536 	_sip_msg = (_sip_msg_t *)sip_msg;
537 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
538 	if (_sip_msg->sip_msg_req_res == NULL) {
539 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
540 		if (error != NULL)
541 			*error = EINVAL;
542 		return (NULL);
543 	}
544 	sip_msg_info = _sip_msg->sip_msg_req_res;
545 	if (sip_msg_info->is_request)
546 		ret = &sip_msg_info->sip_req_uri;
547 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
548 
549 	/*
550 	 * If the error is required, check the validity of the URI via
551 	 * sip_uri_parse().
552 	 */
553 	if (error != NULL) {
554 		parsed_uri = sip_parse_uri(ret, error);
555 		if (parsed_uri != NULL)
556 			sip_free_parsed_uri((sip_uri_t)parsed_uri);
557 	}
558 	return (ret);
559 }
560 
561 /*
562  * Return the response code
563  */
564 int
565 sip_get_response_code(sip_msg_t sip_msg, int *error)
566 {
567 	_sip_msg_t		*_sip_msg;
568 	sip_message_type_t	*sip_msg_info;
569 	int 			ret = -1;
570 
571 	if (error != NULL)
572 		*error = 0;
573 	if (sip_msg == NULL) {
574 		if (error != NULL)
575 			*error = EINVAL;
576 		return (ret);
577 	}
578 	_sip_msg = (_sip_msg_t *)sip_msg;
579 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
580 	if (_sip_msg->sip_msg_req_res == NULL) {
581 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
582 		if (error != NULL)
583 			*error = EINVAL;
584 		return (ret);
585 	}
586 	sip_msg_info = _sip_msg->sip_msg_req_res;
587 	if (!sip_msg_info->is_request)
588 		ret = sip_msg_info->sip_resp_code;
589 	else if (error != NULL)
590 		*error = EINVAL;
591 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
592 	return (ret);
593 }
594 
595 /*
596  * Get the response phrase
597  */
598 const sip_str_t *
599 sip_get_response_phrase(sip_msg_t sip_msg, int *error)
600 {
601 	_sip_msg_t		*_sip_msg;
602 	sip_message_type_t	*sip_msg_info;
603 	sip_str_t 		*ret = NULL;
604 
605 	if (error != NULL)
606 		*error = 0;
607 	if (sip_msg == NULL) {
608 		if (error != NULL)
609 			*error = EINVAL;
610 		return (ret);
611 	}
612 	_sip_msg = (_sip_msg_t *)sip_msg;
613 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
614 	if (_sip_msg->sip_msg_req_res == NULL) {
615 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
616 		if (error != NULL)
617 			*error = EINVAL;
618 		return (ret);
619 	}
620 	sip_msg_info = _sip_msg->sip_msg_req_res;
621 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
622 	if (!sip_msg_info->is_request) {
623 		if (sip_msg_info->sip_resp_phrase_len == 0)
624 			ret = NULL;
625 		else
626 			ret = &sip_msg_info->sip_resp_phrase;
627 	} else if (error != NULL) {
628 		*error = EINVAL;
629 	}
630 	return (ret);
631 }
632 
633 /*
634  * Get the SIP version string
635  */
636 const sip_str_t *
637 sip_get_sip_version(sip_msg_t sip_msg, int *error)
638 {
639 	_sip_msg_t		*_sip_msg;
640 	sip_message_type_t	*sip_msg_info;
641 	sip_str_t		*ret = NULL;
642 
643 	if (error != NULL)
644 		*error = 0;
645 	if (sip_msg == NULL) {
646 		if (error != NULL)
647 			*error = EINVAL;
648 		return (ret);
649 	}
650 	_sip_msg = (_sip_msg_t *)sip_msg;
651 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
652 	if (_sip_msg->sip_msg_req_res == NULL) {
653 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
654 		if (error != NULL)
655 			*error = EINVAL;
656 		return (ret);
657 	}
658 	sip_msg_info = _sip_msg->sip_msg_req_res;
659 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
660 	ret = &sip_msg_info->sip_proto_version.version;
661 	return (ret);
662 }
663 
664 /*
665  * Return the length of the SIP message
666  */
667 int
668 sip_get_msg_len(sip_msg_t sip_msg, int *error)
669 {
670 	_sip_msg_t	*_sip_msg;
671 
672 	if (error != NULL)
673 		*error = 0;
674 	if (sip_msg == NULL) {
675 		if (error != NULL)
676 			*error = EINVAL;
677 		return (-1);
678 	}
679 	_sip_msg = (_sip_msg_t *)sip_msg;
680 
681 	return (_sip_msg->sip_msg_len);
682 }
683 
684 /*
685  * Get content as a string. Caller frees the string
686  */
687 char *
688 sip_get_content(sip_msg_t sip_msg, int *error)
689 {
690 	_sip_msg_t	*_sip_msg;
691 	sip_content_t	*sip_content;
692 	char		*content;
693 	int		len;
694 	char		*p;
695 
696 	if (error != NULL)
697 		*error = 0;
698 
699 	if (sip_msg == NULL) {
700 		if (error != NULL)
701 			*error = EINVAL;
702 		return (NULL);
703 	}
704 	_sip_msg = (_sip_msg_t *)sip_msg;
705 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
706 	if (_sip_msg->sip_msg_content == NULL) {
707 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
708 		if (error != NULL)
709 			*error = EINVAL;
710 		return (NULL);
711 	}
712 	content = malloc(_sip_msg->sip_msg_content_len + 1);
713 	if (content == NULL) {
714 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
715 		if (error != NULL)
716 			*error = ENOMEM;
717 		return (NULL);
718 	}
719 	p = content;
720 	sip_content = _sip_msg->sip_msg_content;
721 	while (sip_content != NULL) {
722 		len =  sip_content->sip_content_end -
723 		    sip_content->sip_content_start;
724 		(void) strncpy(p, sip_content->sip_content_start, len);
725 		p += len;
726 		sip_content = sip_content->sip_content_next;
727 	}
728 	content[_sip_msg->sip_msg_content_len] = '\0';
729 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
730 	return (content);
731 }
732 
733 /*
734  * copy sip_header with param, if any, to sip_msg
735  */
736 int
737 sip_copy_header(sip_msg_t sip_msg, sip_header_t sip_header, char *param)
738 {
739 	_sip_msg_t	*_sip_msg;
740 	_sip_header_t	*_sip_header;
741 	int		ret;
742 
743 	if (sip_msg == NULL || sip_header == NULL)
744 		return (EINVAL);
745 	_sip_msg = (_sip_msg_t *)sip_msg;
746 	_sip_header = (_sip_header_t *)sip_header;
747 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
748 	if (_sip_msg->sip_msg_cannot_be_modified) {
749 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
750 		return (EPERM);
751 	}
752 	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
753 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
754 		return (EINVAL);
755 	}
756 
757 	ret = _sip_copy_header(_sip_msg, _sip_header, param, B_TRUE);
758 	if (_sip_msg->sip_msg_buf != NULL)
759 		_sip_msg->sip_msg_modified = B_TRUE;
760 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
761 	return (ret);
762 }
763 
764 /*
765  * copy the header specified by header_name, with param, if any
766  */
767 int
768 sip_copy_header_by_name(sip_msg_t old_msg, sip_msg_t new_msg,
769     char *header_name, char *param)
770 {
771 	int		ret;
772 	_sip_msg_t	*_old_msg = (_sip_msg_t *)old_msg;
773 	_sip_msg_t	*_new_msg = (_sip_msg_t *)new_msg;
774 
775 	if (_old_msg == NULL || _new_msg == NULL || header_name == NULL ||
776 	    _old_msg == _new_msg) {
777 		return (EINVAL);
778 	}
779 	(void) pthread_mutex_lock(&_new_msg->sip_msg_mutex);
780 	if (_new_msg->sip_msg_cannot_be_modified) {
781 		(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
782 		return (EPERM);
783 	}
784 
785 	(void) pthread_mutex_lock(&_old_msg->sip_msg_mutex);
786 	ret = _sip_find_and_copy_header(_old_msg, _new_msg, header_name, param,
787 	    B_FALSE);
788 	(void) pthread_mutex_unlock(&_old_msg->sip_msg_mutex);
789 	if (_new_msg->sip_msg_buf != NULL)
790 		_new_msg->sip_msg_modified = B_TRUE;
791 	(void) pthread_mutex_unlock(&_new_msg->sip_msg_mutex);
792 	return (ret);
793 }
794 
795 /*
796  * add the given header to sip_message
797  */
798 int
799 sip_add_header(sip_msg_t sip_msg, char *header_string)
800 {
801 	int		header_size;
802 	_sip_header_t	*new_header;
803 	_sip_msg_t	*_sip_msg;
804 
805 	if (sip_msg == NULL || header_string == NULL)
806 		return (EINVAL);
807 	_sip_msg = (_sip_msg_t *)sip_msg;
808 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
809 	if (_sip_msg->sip_msg_cannot_be_modified) {
810 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
811 		return (EPERM);
812 	}
813 	header_size = strlen(header_string) + strlen(SIP_CRLF);
814 	new_header = sip_new_header(header_size);
815 	if (new_header == NULL) {
816 		(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
817 		return (ENOMEM);
818 	}
819 
820 	(void) snprintf(new_header->sip_hdr_start, header_size + 1, "%s%s",
821 	    header_string, SIP_CRLF);
822 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
823 	if (_sip_msg->sip_msg_buf != NULL)
824 		_sip_msg->sip_msg_modified = B_TRUE;
825 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
826 	return (0);
827 }
828 
829 /*
830  * add the given param to the sip_header. create a new header with the param
831  * and mark the old header as deleted.
832  */
833 sip_header_t
834 sip_add_param(sip_header_t sip_header, char *param, int *error)
835 {
836 	_sip_header_t	*_sip_header;
837 	_sip_header_t	*new_header;
838 	int		hdrlen;
839 	_sip_msg_t	*_sip_msg;
840 	int		param_len;
841 	char		*tmp_ptr;
842 
843 	if (error != NULL)
844 		*error = 0;
845 
846 	if (param == NULL || sip_header == NULL) {
847 		if (error != NULL)
848 			*error = EINVAL;
849 		return (NULL);
850 	}
851 
852 	_sip_header = (_sip_header_t *)sip_header;
853 
854 	(void) pthread_mutex_lock(&_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
855 	if (_sip_header->sip_hdr_sipmsg->sip_msg_cannot_be_modified) {
856 		if (error != NULL)
857 			*error = EPERM;
858 		(void) pthread_mutex_unlock(
859 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
860 		return (NULL);
861 	}
862 	if (_sip_header->sip_header_state == SIP_HEADER_DELETED) {
863 		if (error != NULL)
864 			*error = EINVAL;
865 		(void) pthread_mutex_unlock(
866 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
867 		return (NULL);
868 	}
869 
870 	param_len = SIP_SPACE_LEN + sizeof (char) + SIP_SPACE_LEN +
871 	    strlen(param);
872 	hdrlen = _sip_header->sip_hdr_end - _sip_header->sip_hdr_start;
873 	new_header = sip_new_header(hdrlen + param_len);
874 	if (new_header == NULL) {
875 		if (error != NULL)
876 			*error = ENOMEM;
877 		(void) pthread_mutex_unlock(
878 		    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
879 		return (NULL);
880 	}
881 	(void) memcpy(new_header->sip_hdr_start, _sip_header->sip_hdr_start,
882 	    hdrlen);
883 	new_header->sip_hdr_end = new_header->sip_hdr_start + hdrlen;
884 	hdrlen = param_len + 1;
885 	/*
886 	 * Find CRLF
887 	 */
888 	tmp_ptr = new_header->sip_hdr_end;
889 	while (*tmp_ptr-- != '\n') {
890 		hdrlen++;
891 		if (tmp_ptr == new_header->sip_hdr_start) {
892 			sip_free_header(new_header);
893 			if (error != NULL)
894 				*error = EINVAL;
895 			(void) pthread_mutex_unlock(
896 			    &_sip_header->sip_hdr_sipmsg->sip_msg_mutex);
897 			return (NULL);
898 		}
899 	}
900 	(void) snprintf(tmp_ptr, hdrlen + 1,
901 	    " %c %s%s", SIP_SEMI, param, SIP_CRLF);
902 	new_header->sip_hdr_end += param_len;
903 	new_header->sip_header_functions = _sip_header->sip_header_functions;
904 	_sip_msg = _sip_header->sip_hdr_sipmsg;
905 	_sip_add_header(_sip_msg, new_header, B_TRUE, B_FALSE, NULL);
906 	if (_sip_header->sip_hdr_sipmsg->sip_msg_buf != NULL)
907 		_sip_header->sip_hdr_sipmsg->sip_msg_modified = B_TRUE;
908 	(void) pthread_mutex_unlock(&new_header->sip_hdr_sipmsg->sip_msg_mutex);
909 	(void) sip_delete_header(sip_header);
910 	return ((sip_header_t)new_header);
911 }
912 
913 /*
914  * Get Request URI
915  */
916 const struct sip_uri *
917 sip_get_request_uri(sip_msg_t sip_msg, int *error)
918 {
919 	_sip_msg_t		*_sip_msg;
920 	sip_message_type_t	*sip_msg_info;
921 	const struct sip_uri	*ret = NULL;
922 
923 	if (error != NULL)
924 		*error = 0;
925 
926 	if (sip_msg == NULL) {
927 		if (error != NULL)
928 			*error = EINVAL;
929 		return (NULL);
930 	}
931 	_sip_msg = (_sip_msg_t *)sip_msg;
932 	(void) pthread_mutex_lock(&_sip_msg->sip_msg_mutex);
933 	sip_msg_info = _sip_msg->sip_msg_req_res;
934 	if (sip_msg_info != NULL && sip_msg_info->is_request) {
935 		ret = sip_msg_info->sip_req_parse_uri;
936 	} else {
937 		if (error != NULL)
938 			*error = EINVAL;
939 	}
940 	(void) pthread_mutex_unlock(&_sip_msg->sip_msg_mutex);
941 
942 	if (ret != NULL) {
943 		if (ret->sip_uri_scheme.sip_str_len == 0 ||
944 		    ret->sip_uri_scheme.sip_str_ptr == NULL) {
945 			ret = NULL;
946 			if (error != NULL)
947 				*error = EINVAL;
948 		} else if (ret->sip_uri_errflags != 0 && error != NULL) {
949 			*error = EINVAL;
950 		}
951 	}
952 	return ((sip_uri_t)ret);
953 }
954 
955 /*
956  * returns a comma separated string of all the sent-by values registered by
957  * the UA.
958  */
959 char *
960 sip_sent_by_to_str(int *error)
961 {
962 	sent_by_list_t	*sb;
963 	int		sb_len = 0;
964 	int		slen;
965 	char		*sb_str;
966 	char		*p;
967 	int		count = 0;
968 	int		cnt = 0;
969 
970 	if (error != NULL)
971 		*error = 0;
972 
973 	(void) pthread_mutex_lock(&sip_sent_by_lock);
974 	if (sip_sent_by == NULL) {
975 		(void) pthread_mutex_unlock(&sip_sent_by_lock);
976 		return (NULL);
977 	}
978 	sb = sip_sent_by;
979 	for (cnt = 0; cnt < sip_sent_by_count; cnt++) {
980 		sb_len += strlen(sb->sb_val);
981 		sb = sb->sb_next;
982 	}
983 	/*
984 	 * for the commas
985 	 */
986 	sb_len += sip_sent_by_count - 1;
987 	sb_str = malloc(sb_len + 1);
988 	if (sb_str == NULL) {
989 		if (error != NULL)
990 			*error = ENOMEM;
991 		(void) pthread_mutex_unlock(&sip_sent_by_lock);
992 		return (NULL);
993 	}
994 	sb = sip_sent_by;
995 	p = sb_str;
996 	slen = sb_len + 1;
997 	for (cnt = 0; cnt < sip_sent_by_count; cnt++) {
998 		if (cnt == 0) {
999 			count = snprintf(p, slen, "%s", sb->sb_val);
1000 		} else {
1001 			count = snprintf(p, slen, "%c%s", SIP_COMMA,
1002 			    sb->sb_val);
1003 		}
1004 		p += count;
1005 		slen -= count;
1006 		sb = sb->sb_next;
1007 	}
1008 	sb_str[sb_len] = '\0';
1009 	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1010 	return (sb_str);
1011 }
1012 
1013 /*
1014  * A comma separated list of sent-by values.
1015  */
1016 int
1017 sip_register_sent_by(char *val)
1018 {
1019 	sent_by_list_t	*sb = NULL;
1020 	sent_by_list_t	*sb_tail = NULL;
1021 	char		*str;
1022 	int		count = 0;
1023 
1024 	if (val == NULL)
1025 		return (EINVAL);
1026 	str = strtok(val, ",");
1027 	while (str != NULL) {
1028 		int	slen;
1029 		char	*start = str;
1030 		char	*end = str + strlen(str) - 1;
1031 
1032 		while (isspace(*start))
1033 			start++;
1034 		while (isspace(*end))
1035 			end--;
1036 		if (end <= start)
1037 			goto err_ret;
1038 		slen = end - start + 1;
1039 		sb_tail = (sent_by_list_t *)malloc(sizeof (*sb_tail));
1040 		if (sb_tail == NULL)
1041 			goto err_ret;
1042 		sb_tail->sb_next = sb_tail->sb_prev = NULL;
1043 		if ((sb_tail->sb_val = (char *)malloc(slen + 1)) == NULL) {
1044 			free(sb_tail);
1045 			goto err_ret;
1046 		}
1047 		(void) strncpy(sb_tail->sb_val, start, slen);
1048 		sb_tail->sb_val[slen] = '\0';
1049 		if (sb == NULL) {
1050 			sb = sb_tail;
1051 		} else {
1052 			sb_tail->sb_next = sb;
1053 			sb->sb_prev = sb_tail;
1054 			sb = sb_tail;
1055 		}
1056 		count++;
1057 		str = strtok(NULL, ",");
1058 	}
1059 	sb_tail = sb;
1060 	while (sb_tail->sb_next != NULL)
1061 		sb_tail = sb_tail->sb_next;
1062 	(void) pthread_mutex_lock(&sip_sent_by_lock);
1063 	if (sip_sent_by != NULL) {
1064 		sb_tail->sb_next = sip_sent_by;
1065 		sip_sent_by->sb_prev = sb_tail;
1066 	}
1067 	sip_sent_by = sb;
1068 	sip_sent_by_count += count;
1069 	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1070 	return (0);
1071 err_ret:
1072 	sb_tail = sb;
1073 	for (; count > 0; count--) {
1074 		sb = sb_tail->sb_next;
1075 		free(sb_tail->sb_val);
1076 		sb_tail->sb_next = NULL;
1077 		sb_tail->sb_prev = NULL;
1078 		free(sb_tail);
1079 		sb_tail = sb;
1080 	}
1081 	return (EINVAL);
1082 }
1083 
1084 /*
1085  * Un-register sent-by values; 'val' contains a comma separated list
1086  */
1087 void
1088 sip_unregister_sent_by(char *val)
1089 {
1090 	sent_by_list_t	*sb;
1091 	char		*str;
1092 	int		count = 0;
1093 
1094 	(void) pthread_mutex_lock(&sip_sent_by_lock);
1095 	str = strtok(val, ",");
1096 	while (str != NULL) {
1097 		sb = sip_sent_by;
1098 		for (count = 0; count < sip_sent_by_count; count++) {
1099 			if (strncmp(sb->sb_val, str, strlen(str)) == 0) {
1100 				if (sb == sip_sent_by) {
1101 					if (sb->sb_next != NULL)
1102 						sip_sent_by = sb->sb_next;
1103 					else
1104 						sip_sent_by = NULL;
1105 				} else if (sb->sb_next == NULL) {
1106 					sb->sb_prev->sb_next = NULL;
1107 				} else {
1108 					sb->sb_prev->sb_next = sb->sb_next;
1109 					sb->sb_next->sb_prev = sb->sb_prev;
1110 				}
1111 				sip_sent_by_count--;
1112 				sb->sb_next = NULL;
1113 				sb->sb_prev = NULL;
1114 				free(sb->sb_val);
1115 				free(sb);
1116 				break;
1117 			}
1118 			sb = sb->sb_next;
1119 		}
1120 		str = strtok(NULL, ",");
1121 	}
1122 	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1123 }
1124 
1125 /*
1126  * Un-register all the sent-by values
1127  */
1128 void
1129 sip_unregister_all_sent_by()
1130 {
1131 	sent_by_list_t	*sb;
1132 	int		count;
1133 
1134 	(void) pthread_mutex_lock(&sip_sent_by_lock);
1135 	sb = sip_sent_by;
1136 	for (count = 0; count < sip_sent_by_count; count++) {
1137 		sip_sent_by = sb->sb_next;
1138 		free(sb->sb_val);
1139 		sb->sb_next = NULL;
1140 		sb->sb_prev = NULL;
1141 		free(sb);
1142 		sb = sip_sent_by;
1143 	}
1144 	sip_sent_by = NULL;
1145 	sip_sent_by_count = 0;
1146 	(void) pthread_mutex_unlock(&sip_sent_by_lock);
1147 }
1148 
1149 /*
1150  * Given a response code, return the corresponding phrase
1151  */
1152 char *
1153 sip_get_resp_desc(int resp_code)
1154 {
1155 	switch (resp_code) {
1156 	case SIP_TRYING:
1157 		return ("TRYING");
1158 	case SIP_RINGING:
1159 		return ("RINGING");
1160 	case SIP_CALL_IS_BEING_FORWARDED:
1161 		return ("CALL_IS_BEING_FORWARDED");
1162 	case SIP_QUEUED:
1163 		return ("QUEUED");
1164 	case SIP_SESSION_PROGRESS:
1165 		return ("SESSION_PROGRESS");
1166 	case SIP_OK:
1167 		return ("OK");
1168 	case SIP_ACCEPTED:
1169 		return ("ACCEPTED");
1170 	case SIP_MULTIPLE_CHOICES:
1171 		return ("MULTIPLE_CHOICES");
1172 	case SIP_MOVED_PERMANENTLY:
1173 		return ("MOVED_PERMANENTLY");
1174 	case SIP_MOVED_TEMPORARILY:
1175 		return ("MOVED_TEMPORARILY");
1176 	case SIP_USE_PROXY:
1177 		return ("USE_PROXY");
1178 	case SIP_ALTERNATIVE_SERVICE:
1179 		return ("ALTERNATIVE_SERVICE");
1180 	case SIP_BAD_REQUEST:
1181 		return ("BAD_REQUEST");
1182 	case SIP_UNAUTHORIZED:
1183 		return ("UNAUTHORIZED");
1184 	case SIP_PAYMENT_REQUIRED:
1185 		return ("PAYMENT_REQUIRED");
1186 	case SIP_FORBIDDEN:
1187 		return ("FORBIDDEN");
1188 	case SIP_NOT_FOUND:
1189 		return ("NOT_FOUND");
1190 	case SIP_METHOD_NOT_ALLOWED:
1191 		return ("METHOD_NOT_ALLOWED");
1192 	case SIP_NOT_ACCEPTABLE:
1193 		return ("NOT_ACCEPTABLE");
1194 	case SIP_PROXY_AUTH_REQUIRED:
1195 		return ("PROXY_AUTH_REQUIRED");
1196 	case SIP_REQUEST_TIMEOUT:
1197 		return ("REQUEST_TIMEOUT");
1198 	case SIP_GONE:
1199 		return ("GONE");
1200 	case SIP_REQUEST_ENTITY_2_LARGE:
1201 		return ("REQUEST_ENTITY_2_LARGE");
1202 	case SIP_REQUEST_URI_2_LONG:
1203 		return ("REQUEST_URI_2_LONG");
1204 	case SIP_UNSUPPORTED_MEDIA_TYPE:
1205 		return ("UNSUPPORTED_MEDIA_TYPE");
1206 	case SIP_UNSUPPORTED_URI_SCHEME:
1207 		return ("UNSUPPORTED_URI_SCHEME");
1208 	case SIP_BAD_EXTENSION:
1209 		return ("BAD_EXTENSION");
1210 	case SIP_EXTENSION_REQUIRED:
1211 		return ("EXTENSION_REQUIRED");
1212 	case SIP_INTERVAL_2_BRIEF:
1213 		return ("INTERVAL_2_BRIEF");
1214 	case SIP_TEMPORARILY_UNAVAIL:
1215 		return ("TEMPORARILY_UNAVAIL");
1216 	case SIP_CALL_NON_EXISTANT:
1217 		return ("CALL_NON_EXISTANT");
1218 	case SIP_LOOP_DETECTED:
1219 		return ("LOOP_DETECTED");
1220 	case SIP_TOO_MANY_HOOPS:
1221 		return ("TOO_MANY_HOOPS");
1222 	case SIP_ADDRESS_INCOMPLETE:
1223 		return ("ADDRESS_INCOMPLETE");
1224 	case SIP_AMBIGUOUS:
1225 		return ("AMBIGUOUS");
1226 	case SIP_BUSY_HERE:
1227 		return ("BUSY_HERE");
1228 	case SIP_REQUEST_TERMINATED:
1229 		return ("REQUEST_TERMINATED");
1230 	case SIP_NOT_ACCEPTABLE_HERE:
1231 		return ("NOT_ACCEPTABLE_HERE");
1232 	case SIP_BAD_EVENT:
1233 		return ("BAD_EVENT");
1234 	case SIP_REQUEST_PENDING:
1235 		return ("REQUEST_PENDING");
1236 	case SIP_UNDECIPHERABLE:
1237 		return ("UNDECIPHERABLE");
1238 	case SIP_SERVER_INTERNAL_ERROR:
1239 		return ("SERVER_INTERNAL_ERROR");
1240 	case SIP_NOT_IMPLEMENTED:
1241 		return ("NOT_IMPLEMENTED");
1242 	case SIP_BAD_GATEWAY:
1243 		return ("BAD_GATEWAY");
1244 	case SIP_SERVICE_UNAVAILABLE:
1245 		return ("SERVICE_UNAVAILABLE");
1246 	case SIP_SERVER_TIMEOUT:
1247 		return ("SERVER_TIMEOUT");
1248 	case SIP_VERSION_NOT_SUPPORTED:
1249 		return ("VERSION_NOT_SUPPORTED");
1250 	case SIP_MESSAGE_2_LARGE:
1251 		return ("MESSAGE_2_LARGE");
1252 	case SIP_BUSY_EVERYWHERE:
1253 		return ("BUSY_EVERYWHERE");
1254 	case SIP_DECLINE:
1255 		return ("DECLINE");
1256 	case SIP_DOES_NOT_EXIST_ANYWHERE:
1257 		return ("DOES_NOT_EXIST_ANYWHERE");
1258 	case SIP_NOT_ACCEPTABLE_ANYWHERE:
1259 		return ("NOT_ACCEPTABLE_ANYWHERE");
1260 	default:
1261 		return ("UNKNOWN");
1262 	}
1263 }
1264 
1265 /*
1266  * The following three fns initialize and destroy the private library
1267  * data in sip_conn_object_t. The assumption is that the 1st member
1268  * of sip_conn_object_t is reserved for library use. The private data
1269  * is used only for byte-stream protocols such as TCP to accumulate
1270  * a complete SIP message, based on the CONTENT-LENGTH value, before
1271  * processing it.
1272  */
1273 int
1274 sip_init_conn_object(sip_conn_object_t obj)
1275 {
1276 	void			**obj_val;
1277 	sip_conn_obj_pvt_t	*pvt_data;
1278 
1279 	if (obj == NULL)
1280 		return (EINVAL);
1281 	pvt_data =  malloc(sizeof (sip_conn_obj_pvt_t));
1282 	if (pvt_data == NULL)
1283 		return (ENOMEM);
1284 	pvt_data->sip_conn_obj_cache = NULL;
1285 	pvt_data->sip_conn_obj_reass = malloc(sizeof (sip_reass_entry_t));
1286 	if (pvt_data->sip_conn_obj_reass == NULL) {
1287 		free(pvt_data);
1288 		return (ENOMEM);
1289 	}
1290 	bzero(pvt_data->sip_conn_obj_reass, sizeof (sip_reass_entry_t));
1291 	(void) pthread_mutex_init(&pvt_data->sip_conn_obj_reass_lock, NULL);
1292 	(void) pthread_mutex_init(&pvt_data->sip_conn_obj_cache_lock, NULL);
1293 	sip_refhold_conn(obj);
1294 	obj_val = (void *)obj;
1295 	*obj_val = (void *)pvt_data;
1296 
1297 	return (0);
1298 }
1299 
1300 /*
1301  * Clear private date, if any
1302  */
1303 void
1304 sip_clear_stale_data(sip_conn_object_t obj)
1305 {
1306 	void			**obj_val;
1307 	sip_conn_obj_pvt_t	*pvt_data;
1308 	sip_reass_entry_t	*reass;
1309 
1310 	if (obj == NULL)
1311 		return;
1312 	obj_val = (void *)obj;
1313 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
1314 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_reass_lock);
1315 	reass = pvt_data->sip_conn_obj_reass;
1316 	if (reass->sip_reass_msg != NULL) {
1317 		assert(reass->sip_reass_msglen > 0);
1318 		free(reass->sip_reass_msg);
1319 		reass->sip_reass_msglen = 0;
1320 	}
1321 	assert(reass->sip_reass_msglen == 0);
1322 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_reass_lock);
1323 }
1324 
1325 /*
1326  * Walk through all the transactions, remove if this obj has been cached
1327  * by any.
1328  */
1329 void
1330 sip_conn_destroyed(sip_conn_object_t obj)
1331 {
1332 	void			**obj_val;
1333 	sip_conn_obj_pvt_t	*pvt_data;
1334 
1335 	if (obj == NULL)
1336 		return;
1337 	obj_val = (void *)obj;
1338 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
1339 
1340 	sip_clear_stale_data(obj);
1341 	free(pvt_data->sip_conn_obj_reass);
1342 	pvt_data->sip_conn_obj_reass = NULL;
1343 	(void) pthread_mutex_destroy(&pvt_data->sip_conn_obj_reass_lock);
1344 
1345 	sip_del_conn_obj_cache(obj, NULL);
1346 	(void) pthread_mutex_destroy(&pvt_data->sip_conn_obj_cache_lock);
1347 
1348 	free(pvt_data);
1349 	*obj_val = NULL;
1350 	sip_refrele_conn(obj);
1351 }
1352