xref: /illumos-gate/usr/src/lib/libsip/common/sip_xaction.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <stdlib.h>
28 #include <assert.h>
29 #include <errno.h>
30 #include <pthread.h>
31 #include <strings.h>
32 
33 #include "sip_parse_uri.h"
34 #include "sip_msg.h"
35 #include "sip_miscdefs.h"
36 #include "sip_xaction.h"
37 #include "sip_hash.h"
38 
39 #define	RFC_3261_BRANCH "z9hG4bK"
40 
41 /*
42  * The transaction hash table
43  */
44 sip_hash_t	sip_xaction_hash[SIP_HASH_SZ];
45 
46 int (*sip_xaction_ulp_trans_err)(sip_transaction_t, int, void *) = NULL;
47 void (*sip_xaction_ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int) = NULL;
48 
49 int sip_xaction_add(sip_xaction_t *, char *, _sip_msg_t *, sip_method_t);
50 static boolean_t sip_is_conn_obj_cache(sip_conn_object_t, void *);
51 
52 /*
53  * Get the md5 hash of the required fields
54  */
55 int
56 sip_find_md5_digest(char *bid, _sip_msg_t *msg, uint16_t *hindex,
57     sip_method_t method)
58 {
59 	boolean_t	is_2543;
60 
61 	is_2543 = (bid == NULL ||
62 	    strncmp(bid, RFC_3261_BRANCH, strlen(RFC_3261_BRANCH)) != 0);
63 
64 	if (is_2543 && msg == NULL)
65 		return (EINVAL);
66 	if (is_2543) {
67 		_sip_header_t	*from = NULL;
68 		_sip_header_t	*cid = NULL;
69 		_sip_header_t	*via = NULL;
70 		const sip_str_t	*to_uri = NULL;
71 		int		cseq;
72 		int		error = 0;
73 
74 		/*
75 		 * Since the response might contain parameters not in the
76 		 * request, just use the to URI.
77 		 */
78 		to_uri = sip_get_to_uri_str((sip_msg_t)msg, &error);
79 		if (to_uri == NULL || error != 0)
80 			return (EINVAL);
81 		cseq = sip_get_callseq_num((sip_msg_t)msg, &error);
82 		if (cseq < 0 || error != 0)
83 			return (EINVAL);
84 		(void) pthread_mutex_lock(&msg->sip_msg_mutex);
85 		via = sip_search_for_header(msg, SIP_VIA, NULL);
86 		from = sip_search_for_header(msg, SIP_FROM, NULL);
87 		cid = sip_search_for_header(msg, SIP_CALL_ID, NULL);
88 		(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
89 		if (via == NULL || from == NULL || cid == NULL)
90 			return (EINVAL);
91 		sip_md5_hash(via->sip_hdr_start,
92 		    via->sip_hdr_end - via->sip_hdr_start,
93 		    cid->sip_hdr_start,
94 		    cid->sip_hdr_end - cid->sip_hdr_start,
95 		    from->sip_hdr_start,
96 		    from->sip_hdr_end - from->sip_hdr_start,
97 		    (char *)&cseq, sizeof (int),
98 		    (char *)&method, sizeof (sip_method_t),
99 		    to_uri->sip_str_ptr, to_uri->sip_str_len,
100 		    (uchar_t *)hindex);
101 	} else {
102 		sip_md5_hash(bid, strlen(bid), (char *)&method,
103 		    sizeof (sip_method_t), NULL, 0, NULL, 0, NULL, 0, NULL, 0,
104 		    (uchar_t *)hindex);
105 	}
106 	return (0);
107 }
108 
109 /*
110  * Add object to the connection cache object. Not checking for duplicates!!
111  */
112 int
113 sip_add_conn_obj_cache(sip_conn_object_t obj, void *cobj)
114 {
115 	void			**obj_val;
116 	sip_conn_obj_pvt_t	*pvt_data;
117 	sip_conn_cache_t	*xaction_list;
118 	sip_xaction_t		*sip_trans = (sip_xaction_t *)cobj;
119 
120 	/*
121 	 * Is already cached
122 	 */
123 	if (sip_trans->sip_xaction_conn_obj != NULL) {
124 		if (sip_is_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
125 		    (void *)sip_trans)) {
126 			return (0);
127 		}
128 		/*
129 		 * Transaction has cached a different conn_obj, release it
130 		 */
131 		sip_del_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
132 		    (void *)sip_trans);
133 	}
134 
135 	xaction_list = malloc(sizeof (sip_conn_cache_t));
136 	if (xaction_list == NULL)
137 		return (ENOMEM);
138 	xaction_list->obj = cobj;
139 	xaction_list->next = xaction_list->prev = NULL;
140 
141 	obj_val = (void *)obj;
142 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
143 	if (pvt_data == NULL) {
144 		free(xaction_list);
145 		return (EINVAL);
146 	}
147 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
148 
149 	if (pvt_data->sip_conn_obj_cache == NULL) {
150 		pvt_data->sip_conn_obj_cache = xaction_list;
151 	} else {
152 		xaction_list->next =  pvt_data->sip_conn_obj_cache;
153 		pvt_data->sip_conn_obj_cache->prev = xaction_list;
154 		pvt_data->sip_conn_obj_cache = xaction_list;
155 	}
156 	sip_refhold_conn(obj);
157 	sip_trans->sip_xaction_conn_obj = obj;
158 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
159 	return (0);
160 }
161 
162 /*
163  * Walk thru the list of transactions that have cached this obj and
164  * and return true if 'cobj' is one of them.
165  */
166 static boolean_t
167 sip_is_conn_obj_cache(sip_conn_object_t obj, void *cobj)
168 {
169 	void			**obj_val;
170 	sip_conn_obj_pvt_t	*pvt_data;
171 	sip_conn_cache_t	*xaction_list;
172 	sip_xaction_t		*trans;
173 	sip_xaction_t		*ctrans = (sip_xaction_t *)cobj;
174 
175 	obj_val = (void *)obj;
176 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
177 	if (pvt_data == NULL)
178 		return (B_FALSE);
179 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
180 	xaction_list = pvt_data->sip_conn_obj_cache;
181 	while (xaction_list != NULL) {
182 		trans = (sip_xaction_t *)xaction_list->obj;
183 		if (ctrans != trans) {
184 			xaction_list = xaction_list->next;
185 			continue;
186 		}
187 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
188 		return (B_TRUE);
189 	}
190 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
191 	return (B_FALSE);
192 }
193 
194 
195 /*
196  * Walk thru the list of transactions that have cached this obj and
197  * refrele the objs.
198  */
199 void
200 sip_del_conn_obj_cache(sip_conn_object_t obj, void *cobj)
201 {
202 	void			**obj_val;
203 	sip_conn_obj_pvt_t	*pvt_data;
204 	sip_conn_cache_t	*xaction_list;
205 	sip_conn_cache_t	*tmp_list;
206 	sip_xaction_t		*trans;
207 	sip_xaction_t		*ctrans = NULL;
208 
209 	if (cobj != NULL)
210 		ctrans = (sip_xaction_t *)cobj;
211 
212 	obj_val = (void *)obj;
213 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
214 	if (pvt_data == NULL) {	/* ASSERT FALSE if ctrans != NULL?? */
215 		if (ctrans != NULL) {
216 			sip_refrele_conn(obj);
217 			ctrans->sip_xaction_conn_obj = NULL;
218 		}
219 		return;
220 	}
221 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
222 	xaction_list = pvt_data->sip_conn_obj_cache;
223 	while (xaction_list != NULL) {
224 		tmp_list = xaction_list;
225 		trans = (sip_xaction_t *)xaction_list->obj;
226 		assert(trans != NULL);
227 		if (ctrans != NULL && ctrans != trans) {
228 			xaction_list = xaction_list->next;
229 			continue;
230 		}
231 		if (ctrans == NULL)
232 			(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
233 		assert(trans->sip_xaction_conn_obj == obj);
234 		sip_refrele_conn(obj);
235 		trans->sip_xaction_conn_obj = NULL;
236 		if (ctrans == NULL)
237 			(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
238 		xaction_list = xaction_list->next;
239 
240 		/*
241 		 * Take the obj out of the list
242 		 */
243 		if (tmp_list == pvt_data->sip_conn_obj_cache) {
244 			if (xaction_list == NULL) {
245 				pvt_data->sip_conn_obj_cache = NULL;
246 			} else {
247 				xaction_list->prev = NULL;
248 				pvt_data->sip_conn_obj_cache = xaction_list;
249 			}
250 		} else if (xaction_list == NULL) {
251 			assert(tmp_list->prev != NULL);
252 			tmp_list->prev->next = NULL;
253 		} else {
254 			assert(tmp_list->prev != NULL);
255 			tmp_list->prev->next = xaction_list;
256 			xaction_list->prev = tmp_list->prev;
257 		}
258 		tmp_list->prev = NULL;
259 		tmp_list->next = NULL;
260 		tmp_list->obj = NULL;
261 
262 		free(tmp_list);
263 	}
264 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
265 }
266 
267 /*
268  * Check for a transaction match. Passed to sip_hash_find().
269  */
270 boolean_t
271 sip_xaction_match(void *obj, void *hindex)
272 {
273 	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
274 
275 	tmp = (sip_xaction_t *)obj;
276 
277 	if (SIP_IS_XACTION_TERMINATED(tmp->sip_xaction_state))
278 		return (B_FALSE);
279 	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
280 	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
281 		SIP_XACTION_REFCNT_INCR(tmp);
282 		return (B_TRUE);
283 	}
284 	return (B_FALSE);
285 }
286 
287 
288 /*
289  * Find a transaction
290  */
291 static sip_xaction_t *
292 sip_xaction_find(char *branchid, _sip_msg_t *msg, int which)
293 {
294 	sip_xaction_t		*tmp;
295 	uint16_t		hash_index[8];
296 	int			hindex;
297 	sip_method_t		method;
298 	int			error;
299 	sip_message_type_t	*sip_msg_info;
300 
301 	sip_msg_info = msg->sip_msg_req_res;
302 	method = sip_get_callseq_method((sip_msg_t)msg, &error);
303 	if (error != 0)
304 		return (NULL);
305 
306 	/*
307 	 * If we are getting a ACK/CANCEL we need to match with the
308 	 * corresponding INVITE, if any.
309 	 */
310 	if (sip_msg_info->is_request && which == SIP_SERVER_TRANSACTION &&
311 	    (method == ACK || method == CANCEL)) {
312 		method = INVITE;
313 	}
314 	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
315 		return (NULL);
316 	hindex = SIP_DIGEST_TO_HASH(hash_index);
317 	tmp = (sip_xaction_t *)sip_hash_find(sip_xaction_hash,
318 	    (void *)hash_index, hindex, sip_xaction_match);
319 	return (tmp);
320 }
321 
322 /*
323  * create a transaction.
324  */
325 static sip_xaction_t *
326 sip_xaction_create(sip_conn_object_t obj, _sip_msg_t *msg, char *branchid,
327     int *error)
328 {
329 	sip_xaction_t		*trans;
330 	sip_message_type_t	*sip_msg_info;
331 	int			state = 0;
332 	int			prev_state = 0;
333 	sip_method_t		method;
334 	int			ret;
335 	int			timer1 = sip_timer_T1;
336 	int			timer4 = sip_timer_T4;
337 	int			timerd = sip_timer_TD;
338 
339 	if (error != NULL)
340 		*error = 0;
341 	/*
342 	 * Make sure we are not creating a transaction for
343 	 * an ACK request.
344 	 */
345 	trans = (sip_xaction_t *)malloc(sizeof (sip_xaction_t));
346 	if (trans == NULL) {
347 		if (error != NULL)
348 			*error = ENOMEM;
349 		return (NULL);
350 	}
351 	bzero(trans, sizeof (sip_xaction_t));
352 	if (branchid == NULL) {
353 		trans->sip_xaction_branch_id = (char *)sip_branchid(NULL);
354 		if (trans->sip_xaction_branch_id == NULL) {
355 			free(trans);
356 			if (error != NULL)
357 				*error = ENOMEM;
358 			return (NULL);
359 		}
360 	} else {
361 		trans->sip_xaction_branch_id = (char *)malloc(strlen(branchid)
362 		    + 1);
363 		if (trans->sip_xaction_branch_id == NULL) {
364 			free(trans);
365 			if (error != NULL)
366 				*error = ENOMEM;
367 			return (NULL);
368 		}
369 		(void) strncpy(trans->sip_xaction_branch_id, branchid,
370 		    strlen(branchid));
371 		trans->sip_xaction_branch_id[strlen(branchid)] = '\0';
372 	}
373 	(void) pthread_mutex_init(&trans->sip_xaction_mutex, NULL);
374 	SIP_MSG_REFCNT_INCR(msg);
375 	trans->sip_xaction_orig_msg = msg;
376 	assert(msg->sip_msg_req_res != NULL);
377 	sip_msg_info = msg->sip_msg_req_res;
378 	if (sip_msg_info->is_request) {
379 		method = sip_msg_info->sip_req_method;
380 	} else {
381 		method = sip_get_callseq_method((sip_msg_t)msg, &ret);
382 		if (ret != 0) {
383 			free(trans->sip_xaction_branch_id);
384 			free(trans);
385 			if (error != NULL)
386 				*error = ret;
387 			return (NULL);
388 		}
389 		if (method == INVITE)
390 			state = SIP_SRV_INV_PROCEEDING;
391 		else
392 			state = SIP_SRV_TRYING;
393 	}
394 	trans->sip_xaction_method = method;
395 	trans->sip_xaction_state = state;
396 
397 	/*
398 	 * Get connection object specific timeouts, if present
399 	 */
400 	if (sip_conn_timer1 != NULL)
401 		timer1 = sip_conn_timer1(obj);
402 	if (sip_conn_timer4 != NULL)
403 		timer4 = sip_conn_timer4(obj);
404 	if (sip_conn_timerd != NULL)
405 		timerd = sip_conn_timerd(obj);
406 
407 	SIP_INIT_TIMER(trans->sip_xaction_TA, 2 * timer1);
408 	SIP_INIT_TIMER(trans->sip_xaction_TB, 64 * timer1)
409 	SIP_INIT_TIMER(trans->sip_xaction_TD,  timerd);
410 	SIP_INIT_TIMER(trans->sip_xaction_TE, timer1);
411 	SIP_INIT_TIMER(trans->sip_xaction_TF, 64 * timer1);
412 	SIP_INIT_TIMER(trans->sip_xaction_TG, 2 * timer1);
413 	SIP_INIT_TIMER(trans->sip_xaction_TH, 64 * timer1);
414 	SIP_INIT_TIMER(trans->sip_xaction_TI, timer4);
415 	SIP_INIT_TIMER(trans->sip_xaction_TJ, 64 * timer1);
416 	SIP_INIT_TIMER(trans->sip_xaction_TK, timer4);
417 
418 	if ((ret = sip_xaction_add(trans, branchid, msg, method)) != 0) {
419 		(void) pthread_mutex_destroy(&trans->sip_xaction_mutex);
420 		free(trans->sip_xaction_branch_id);
421 		free(trans);
422 		if (error != NULL)
423 			*error = ret;
424 		return (NULL);
425 	}
426 	if (sip_xaction_ulp_state_cb != NULL &&
427 	    prev_state != trans->sip_xaction_state) {
428 		sip_xaction_ulp_state_cb((sip_transaction_t)trans,
429 		    (sip_msg_t)msg, prev_state, trans->sip_xaction_state);
430 	}
431 	return (trans);
432 }
433 
434 /*
435  * Find a transaction, create if asked for
436  */
437 sip_xaction_t *
438 sip_xaction_get(sip_conn_object_t obj, sip_msg_t msg, boolean_t create,
439     int which, int *error)
440 {
441 	char			*branchid;
442 	sip_xaction_t		*sip_trans;
443 	_sip_msg_t		*_msg;
444 	sip_message_type_t	*sip_msg_info;
445 
446 	if (error != NULL)
447 		*error = 0;
448 
449 	_msg = (_sip_msg_t *)msg;
450 	sip_msg_info = ((_sip_msg_t *)msg)->sip_msg_req_res;
451 
452 	branchid = sip_get_branchid(msg, NULL);
453 	sip_trans = sip_xaction_find(branchid, _msg, which);
454 	if (sip_trans == NULL && create) {
455 		/*
456 		 * If we are sending a request, must be conformant to RFC 3261.
457 		 */
458 		if (sip_msg_info->is_request &&
459 		    (branchid == NULL || strncmp(branchid,
460 		    RFC_3261_BRANCH, strlen(RFC_3261_BRANCH) != 0))) {
461 			if (error != NULL)
462 				*error = EINVAL;
463 			if (branchid != NULL)
464 				free(branchid);
465 			return (NULL);
466 		}
467 		sip_trans = sip_xaction_create(obj, _msg, branchid, error);
468 		if (sip_trans != NULL)
469 			SIP_XACTION_REFCNT_INCR(sip_trans);
470 	}
471 	if (branchid != NULL)
472 		free(branchid);
473 	return (sip_trans);
474 }
475 
476 
477 /*
478  * Delete a transaction if the reference count is 0. Passed to
479  * sip_hash_delete().
480  */
481 boolean_t
482 sip_xaction_remove(void *obj, void *hindex, int *found)
483 {
484 	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
485 	int		count = 0;
486 	sip_msg_chain_t	*msg_chain;
487 	sip_msg_chain_t	*nmsg_chain;
488 
489 	*found = 0;
490 	tmp = (sip_xaction_t *)obj;
491 	(void) pthread_mutex_lock(&tmp->sip_xaction_mutex);
492 	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
493 	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
494 		*found = 1;
495 		if (tmp->sip_xaction_ref_cnt != 0) {
496 			(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
497 			return (B_FALSE);
498 		}
499 		(void) pthread_mutex_destroy(&tmp->sip_xaction_mutex);
500 		SIP_CANCEL_TIMER(tmp->sip_xaction_TA);
501 		SIP_CANCEL_TIMER(tmp->sip_xaction_TB);
502 		SIP_CANCEL_TIMER(tmp->sip_xaction_TD);
503 		SIP_CANCEL_TIMER(tmp->sip_xaction_TE);
504 		SIP_CANCEL_TIMER(tmp->sip_xaction_TF);
505 		SIP_CANCEL_TIMER(tmp->sip_xaction_TG);
506 		SIP_CANCEL_TIMER(tmp->sip_xaction_TH);
507 		SIP_CANCEL_TIMER(tmp->sip_xaction_TI);
508 		SIP_CANCEL_TIMER(tmp->sip_xaction_TJ);
509 		SIP_CANCEL_TIMER(tmp->sip_xaction_TK);
510 		sip_write_to_log((void *)tmp, SIP_TRANSACTION_LOG, NULL, 0);
511 		free(tmp->sip_xaction_branch_id);
512 		if (tmp->sip_xaction_last_msg != NULL) {
513 			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_last_msg);
514 			tmp->sip_xaction_last_msg = NULL;
515 		}
516 		if (tmp->sip_xaction_orig_msg != NULL) {
517 			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_orig_msg);
518 			tmp->sip_xaction_orig_msg = NULL;
519 		}
520 		if (tmp->sip_xaction_conn_obj != NULL) {
521 			sip_del_conn_obj_cache(tmp->sip_xaction_conn_obj,
522 			    (void *)tmp);
523 		}
524 		/*
525 		 * If the transaction logging is disabled before we could
526 		 * write the captured messages into the transaction log, then
527 		 * we need to free those captured messsages
528 		 */
529 		for (count = 0; count <= SIP_SRV_NONINV_TERMINATED; count++) {
530 			msg_chain = tmp->sip_xaction_log[count].sip_msgs;
531 			while (msg_chain != NULL) {
532 				nmsg_chain = msg_chain->next;
533 				if (msg_chain->sip_msg != NULL)
534 					free(msg_chain->sip_msg);
535 				free(msg_chain);
536 				msg_chain = nmsg_chain;
537 			}
538 		}
539 		free(tmp);
540 		return (B_TRUE);
541 	}
542 	(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
543 	return (B_FALSE);
544 }
545 
546 /*
547  * Delete a SIP transaction
548  */
549 void
550 sip_xaction_delete(sip_xaction_t *trans)
551 {
552 	int	hindex;
553 
554 	(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
555 	hindex = SIP_DIGEST_TO_HASH(trans->sip_xaction_hash_digest);
556 	if (trans->sip_xaction_ref_cnt != 0) {
557 		(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
558 		return;
559 	}
560 	(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
561 	sip_hash_delete(sip_xaction_hash, trans->sip_xaction_hash_digest,
562 	    hindex, sip_xaction_remove);
563 }
564 
565 /*
566  * Add a SIP transaction into the hash list.
567  */
568 int
569 sip_xaction_add(sip_xaction_t *trans, char *branchid, _sip_msg_t *msg,
570     sip_method_t method)
571 {
572 	uint16_t	hash_index[8];
573 
574 	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
575 		return (EINVAL);
576 
577 	/*
578 	 * trans is not in the list as yet, so no need to hold the lock
579 	 */
580 	bcopy(hash_index, trans->sip_xaction_hash_digest, sizeof (hash_index));
581 
582 	if (sip_hash_add(sip_xaction_hash, (void *)trans,
583 	    SIP_DIGEST_TO_HASH(hash_index)) != 0) {
584 		return (ENOMEM);
585 	}
586 	return (0);
587 }
588 
589 
590 /*
591  * Given a state, return the  string - This is mostly for debug purposes
592  */
593 char *
594 sip_get_xaction_state(int state)
595 {
596 	switch (state) {
597 		case SIP_NEW_TRANSACTION:
598 			return ("SIP_NEW_TRANSACTION");
599 		case SIP_CLNT_CALLING:
600 			return ("SIP_CLNT_CALLING");
601 		case SIP_CLNT_INV_PROCEEDING:
602 			return ("SIP_CLNT_INV_PROCEEDING");
603 		case SIP_CLNT_INV_TERMINATED:
604 			return ("SIP_CLNT_INV_TERMINATED");
605 		case SIP_CLNT_INV_COMPLETED:
606 			return ("SIP_CLNT_INV_COMPLETED");
607 		case SIP_CLNT_TRYING:
608 			return ("SIP_CLNT_TRYING");
609 		case SIP_CLNT_NONINV_PROCEEDING:
610 			return ("SIP_CLNT_NONINV_PROCEEDING");
611 		case SIP_CLNT_NONINV_TERMINATED:
612 			return ("SIP_CLNT_NONINV_TERMINATED");
613 		case SIP_CLNT_NONINV_COMPLETED:
614 			return ("SIP_CLNT_NONINV_COMPLETED");
615 		case SIP_SRV_INV_PROCEEDING:
616 			return ("SIP_SRV_INV_PROCEEDING");
617 		case SIP_SRV_INV_COMPLETED:
618 			return ("SIP_SRV_INV_COMPLETED");
619 		case SIP_SRV_CONFIRMED:
620 			return ("SIP_SRV_CONFIRMED");
621 		case SIP_SRV_INV_TERMINATED:
622 			return ("SIP_SRV_INV_TERMINATED");
623 		case SIP_SRV_TRYING:
624 			return ("SIP_SRV_TRYING");
625 		case SIP_SRV_NONINV_PROCEEDING:
626 			return ("SIP_SRV_NONINV_PROCEEDING");
627 		case SIP_SRV_NONINV_COMPLETED:
628 			return ("SIP_SRV_NONINV_COMPLETED");
629 		case SIP_SRV_NONINV_TERMINATED:
630 			return ("SIP_SRV_NONINV_TERMINATED");
631 		default :
632 			return ("UNKNOWN");
633 	}
634 }
635 
636 /*
637  * Initialize the hash table etc.
638  */
639 void
640 sip_xaction_init(int (*ulp_trans_err)(sip_transaction_t, int, void *),
641     void (*ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int))
642 {
643 	int	cnt;
644 
645 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
646 		sip_xaction_hash[cnt].hash_count = 0;
647 		sip_xaction_hash[cnt].hash_head = NULL;
648 		sip_xaction_hash[cnt].hash_tail = NULL;
649 		(void) pthread_mutex_init(
650 		    &sip_xaction_hash[cnt].sip_hash_mutex, NULL);
651 	}
652 	if (ulp_trans_err != NULL)
653 		sip_xaction_ulp_trans_err = ulp_trans_err;
654 	if (ulp_state_cb != NULL)
655 		sip_xaction_ulp_state_cb = ulp_state_cb;
656 }
657