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