xref: /onnv-gate/usr/src/lib/libsip/common/sip_xaction.c (revision 5842:e93f793783f6)
12882Svi117747 /*
22882Svi117747  * CDDL HEADER START
32882Svi117747  *
42882Svi117747  * The contents of this file are subject to the terms of the
52882Svi117747  * Common Development and Distribution License (the "License").
62882Svi117747  * You may not use this file except in compliance with the License.
72882Svi117747  *
82882Svi117747  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
92882Svi117747  * or http://www.opensolaris.org/os/licensing.
102882Svi117747  * See the License for the specific language governing permissions
112882Svi117747  * and limitations under the License.
122882Svi117747  *
132882Svi117747  * When distributing Covered Code, include this CDDL HEADER in each
142882Svi117747  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
152882Svi117747  * If applicable, add the following below this CDDL HEADER, with the
162882Svi117747  * fields enclosed by brackets "[]" replaced with your own identifying
172882Svi117747  * information: Portions Copyright [yyyy] [name of copyright owner]
182882Svi117747  *
192882Svi117747  * CDDL HEADER END
202882Svi117747  */
212882Svi117747 
222882Svi117747 /*
23*5842Sgm209912  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
242882Svi117747  * Use is subject to license terms.
252882Svi117747  */
262882Svi117747 
272882Svi117747 #pragma ident	"%Z%%M%	%I%	%E% SMI"
282882Svi117747 
293439Svi117747 #include <stdlib.h>
303439Svi117747 #include <assert.h>
313439Svi117747 #include <errno.h>
323439Svi117747 #include <pthread.h>
333439Svi117747 #include <strings.h>
343439Svi117747 
352882Svi117747 #include "sip_parse_uri.h"
362882Svi117747 #include "sip_msg.h"
372882Svi117747 #include "sip_miscdefs.h"
382882Svi117747 #include "sip_xaction.h"
392882Svi117747 #include "sip_hash.h"
402882Svi117747 
412882Svi117747 #define	RFC_3261_BRANCH "z9hG4bK"
422882Svi117747 
432882Svi117747 /*
442882Svi117747  * The transaction hash table
452882Svi117747  */
462882Svi117747 sip_hash_t	sip_xaction_hash[SIP_HASH_SZ];
472882Svi117747 
482882Svi117747 int (*sip_xaction_ulp_trans_err)(sip_transaction_t, int, void *) = NULL;
492882Svi117747 void (*sip_xaction_ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int) = NULL;
502882Svi117747 
512882Svi117747 int sip_xaction_add(sip_xaction_t *, char *, _sip_msg_t *, sip_method_t);
522882Svi117747 static boolean_t sip_is_conn_obj_cache(sip_conn_object_t, void *);
532882Svi117747 
542882Svi117747 /*
552882Svi117747  * Get the md5 hash of the required fields
562882Svi117747  */
572882Svi117747 int
sip_find_md5_digest(char * bid,_sip_msg_t * msg,uint16_t * hindex,sip_method_t method)582882Svi117747 sip_find_md5_digest(char *bid, _sip_msg_t *msg, uint16_t *hindex,
592882Svi117747     sip_method_t method)
602882Svi117747 {
612882Svi117747 	boolean_t	is_2543;
622882Svi117747 
632882Svi117747 	is_2543 = (bid == NULL ||
642882Svi117747 	    strncmp(bid, RFC_3261_BRANCH, strlen(RFC_3261_BRANCH)) != 0);
652882Svi117747 
662882Svi117747 	if (is_2543 && msg == NULL)
672882Svi117747 		return (EINVAL);
682882Svi117747 	if (is_2543) {
692882Svi117747 		_sip_header_t	*from = NULL;
702882Svi117747 		_sip_header_t	*cid = NULL;
712882Svi117747 		_sip_header_t	*via = NULL;
722882Svi117747 		const sip_str_t	*to_uri = NULL;
732882Svi117747 		int		cseq;
742882Svi117747 		int		error = 0;
752882Svi117747 
762882Svi117747 		/*
772882Svi117747 		 * Since the response might contain parameters not in the
782882Svi117747 		 * request, just use the to URI.
792882Svi117747 		 */
802882Svi117747 		to_uri = sip_get_to_uri_str((sip_msg_t)msg, &error);
812882Svi117747 		if (to_uri == NULL || error != 0)
822882Svi117747 			return (EINVAL);
832882Svi117747 		cseq = sip_get_callseq_num((sip_msg_t)msg, &error);
842882Svi117747 		if (cseq < 0 || error != 0)
852882Svi117747 			return (EINVAL);
862882Svi117747 		(void) pthread_mutex_lock(&msg->sip_msg_mutex);
872882Svi117747 		via = sip_search_for_header(msg, SIP_VIA, NULL);
882882Svi117747 		from = sip_search_for_header(msg, SIP_FROM, NULL);
892882Svi117747 		cid = sip_search_for_header(msg, SIP_CALL_ID, NULL);
902882Svi117747 		(void) pthread_mutex_unlock(&msg->sip_msg_mutex);
912882Svi117747 		if (via == NULL || from == NULL || cid == NULL)
922882Svi117747 			return (EINVAL);
932882Svi117747 		sip_md5_hash(via->sip_hdr_start,
942882Svi117747 		    via->sip_hdr_end - via->sip_hdr_start,
952882Svi117747 		    cid->sip_hdr_start,
962882Svi117747 		    cid->sip_hdr_end - cid->sip_hdr_start,
972882Svi117747 		    from->sip_hdr_start,
982882Svi117747 		    from->sip_hdr_end - from->sip_hdr_start,
992882Svi117747 		    (char *)&cseq, sizeof (int),
1002882Svi117747 		    (char *)&method, sizeof (sip_method_t),
1012882Svi117747 		    to_uri->sip_str_ptr, to_uri->sip_str_len,
1022882Svi117747 		    (uchar_t *)hindex);
1032882Svi117747 	} else {
1042882Svi117747 		sip_md5_hash(bid, strlen(bid), (char *)&method,
1052882Svi117747 		    sizeof (sip_method_t), NULL, 0, NULL, 0, NULL, 0, NULL, 0,
1062882Svi117747 		    (uchar_t *)hindex);
1072882Svi117747 	}
1082882Svi117747 	return (0);
1092882Svi117747 }
1102882Svi117747 
1112882Svi117747 /*
1122882Svi117747  * Add object to the connection cache object. Not checking for duplicates!!
1132882Svi117747  */
1142882Svi117747 int
sip_add_conn_obj_cache(sip_conn_object_t obj,void * cobj)1152882Svi117747 sip_add_conn_obj_cache(sip_conn_object_t obj, void *cobj)
1162882Svi117747 {
1172882Svi117747 	void			**obj_val;
1182882Svi117747 	sip_conn_obj_pvt_t	*pvt_data;
1192882Svi117747 	sip_conn_cache_t	*xaction_list;
1202882Svi117747 	sip_xaction_t		*sip_trans = (sip_xaction_t *)cobj;
1212882Svi117747 
1222882Svi117747 	/*
1232882Svi117747 	 * Is already cached
1242882Svi117747 	 */
1252882Svi117747 	if (sip_trans->sip_xaction_conn_obj != NULL) {
1262882Svi117747 		if (sip_is_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
1272882Svi117747 		    (void *)sip_trans)) {
1282882Svi117747 			return (0);
1292882Svi117747 		}
1302882Svi117747 		/*
1312882Svi117747 		 * Transaction has cached a different conn_obj, release it
1322882Svi117747 		 */
1332882Svi117747 		sip_del_conn_obj_cache(sip_trans->sip_xaction_conn_obj,
1342882Svi117747 		    (void *)sip_trans);
1352882Svi117747 	}
1362882Svi117747 
1372882Svi117747 	xaction_list = malloc(sizeof (sip_conn_cache_t));
1382882Svi117747 	if (xaction_list == NULL)
1392882Svi117747 		return (ENOMEM);
1402882Svi117747 	xaction_list->obj = cobj;
1412882Svi117747 	xaction_list->next = xaction_list->prev = NULL;
1422882Svi117747 
1432882Svi117747 	obj_val = (void *)obj;
1442882Svi117747 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
1452882Svi117747 	if (pvt_data == NULL) {
1462882Svi117747 		free(xaction_list);
1472882Svi117747 		return (EINVAL);
1482882Svi117747 	}
1492882Svi117747 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
1502882Svi117747 
1512882Svi117747 	if (pvt_data->sip_conn_obj_cache == NULL) {
1522882Svi117747 		pvt_data->sip_conn_obj_cache = xaction_list;
1532882Svi117747 	} else {
1542882Svi117747 		xaction_list->next =  pvt_data->sip_conn_obj_cache;
1552882Svi117747 		pvt_data->sip_conn_obj_cache->prev = xaction_list;
1562882Svi117747 		pvt_data->sip_conn_obj_cache = xaction_list;
1572882Svi117747 	}
1582882Svi117747 	sip_refhold_conn(obj);
1592882Svi117747 	sip_trans->sip_xaction_conn_obj = obj;
1602882Svi117747 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
1612882Svi117747 	return (0);
1622882Svi117747 }
1632882Svi117747 
1642882Svi117747 /*
1652882Svi117747  * Walk thru the list of transactions that have cached this obj and
1662882Svi117747  * and return true if 'cobj' is one of them.
1672882Svi117747  */
1682882Svi117747 static boolean_t
sip_is_conn_obj_cache(sip_conn_object_t obj,void * cobj)1692882Svi117747 sip_is_conn_obj_cache(sip_conn_object_t obj, void *cobj)
1702882Svi117747 {
1712882Svi117747 	void			**obj_val;
1722882Svi117747 	sip_conn_obj_pvt_t	*pvt_data;
1732882Svi117747 	sip_conn_cache_t	*xaction_list;
1742882Svi117747 	sip_xaction_t		*trans;
1752882Svi117747 	sip_xaction_t		*ctrans = (sip_xaction_t *)cobj;
1762882Svi117747 
1772882Svi117747 	obj_val = (void *)obj;
1782882Svi117747 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
1792882Svi117747 	if (pvt_data == NULL)
1802882Svi117747 		return (B_FALSE);
1812882Svi117747 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
1822882Svi117747 	xaction_list = pvt_data->sip_conn_obj_cache;
1832882Svi117747 	while (xaction_list != NULL) {
1842882Svi117747 		trans = (sip_xaction_t *)xaction_list->obj;
1852882Svi117747 		if (ctrans != trans) {
1862882Svi117747 			xaction_list = xaction_list->next;
1872882Svi117747 			continue;
1882882Svi117747 		}
1892882Svi117747 		(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
1902882Svi117747 		return (B_TRUE);
1912882Svi117747 	}
1922882Svi117747 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
1932882Svi117747 	return (B_FALSE);
1942882Svi117747 }
1952882Svi117747 
1962882Svi117747 
1972882Svi117747 /*
1982882Svi117747  * Walk thru the list of transactions that have cached this obj and
1992882Svi117747  * refrele the objs.
2002882Svi117747  */
2012882Svi117747 void
sip_del_conn_obj_cache(sip_conn_object_t obj,void * cobj)2022882Svi117747 sip_del_conn_obj_cache(sip_conn_object_t obj, void *cobj)
2032882Svi117747 {
2042882Svi117747 	void			**obj_val;
2052882Svi117747 	sip_conn_obj_pvt_t	*pvt_data;
2062882Svi117747 	sip_conn_cache_t	*xaction_list;
2072882Svi117747 	sip_conn_cache_t	*tmp_list;
2082882Svi117747 	sip_xaction_t		*trans;
2092882Svi117747 	sip_xaction_t		*ctrans = NULL;
2102882Svi117747 
2112882Svi117747 	if (cobj != NULL)
2122882Svi117747 		ctrans = (sip_xaction_t *)cobj;
2132882Svi117747 
2142882Svi117747 	obj_val = (void *)obj;
2152882Svi117747 	pvt_data = (sip_conn_obj_pvt_t *)*obj_val;
2162882Svi117747 	if (pvt_data == NULL) {	/* ASSERT FALSE if ctrans != NULL?? */
2172882Svi117747 		if (ctrans != NULL) {
2182882Svi117747 			sip_refrele_conn(obj);
2192882Svi117747 			ctrans->sip_xaction_conn_obj = NULL;
2202882Svi117747 		}
2212882Svi117747 		return;
2222882Svi117747 	}
2232882Svi117747 	(void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock);
2242882Svi117747 	xaction_list = pvt_data->sip_conn_obj_cache;
2252882Svi117747 	while (xaction_list != NULL) {
2262882Svi117747 		tmp_list = xaction_list;
2272882Svi117747 		trans = (sip_xaction_t *)xaction_list->obj;
2282882Svi117747 		assert(trans != NULL);
2292882Svi117747 		if (ctrans != NULL && ctrans != trans) {
2302882Svi117747 			xaction_list = xaction_list->next;
2312882Svi117747 			continue;
2322882Svi117747 		}
2332882Svi117747 		if (ctrans == NULL)
2342882Svi117747 			(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
2352882Svi117747 		assert(trans->sip_xaction_conn_obj == obj);
2362882Svi117747 		sip_refrele_conn(obj);
2372882Svi117747 		trans->sip_xaction_conn_obj = NULL;
2382882Svi117747 		if (ctrans == NULL)
2392882Svi117747 			(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
2402882Svi117747 		xaction_list = xaction_list->next;
2412882Svi117747 
2422882Svi117747 		/*
2432882Svi117747 		 * Take the obj out of the list
2442882Svi117747 		 */
2452882Svi117747 		if (tmp_list == pvt_data->sip_conn_obj_cache) {
2462882Svi117747 			if (xaction_list == NULL) {
2472882Svi117747 				pvt_data->sip_conn_obj_cache = NULL;
2482882Svi117747 			} else {
2492882Svi117747 				xaction_list->prev = NULL;
2502882Svi117747 				pvt_data->sip_conn_obj_cache = xaction_list;
2512882Svi117747 			}
2522882Svi117747 		} else if (xaction_list == NULL) {
2532882Svi117747 			assert(tmp_list->prev != NULL);
2542882Svi117747 			tmp_list->prev->next = NULL;
2552882Svi117747 		} else {
2562882Svi117747 			assert(tmp_list->prev != NULL);
2572882Svi117747 			tmp_list->prev->next = xaction_list;
2582882Svi117747 			xaction_list->prev = tmp_list->prev;
2592882Svi117747 		}
2602882Svi117747 		tmp_list->prev = NULL;
2612882Svi117747 		tmp_list->next = NULL;
2622882Svi117747 		tmp_list->obj = NULL;
2632882Svi117747 
2642882Svi117747 		free(tmp_list);
2652882Svi117747 	}
2662882Svi117747 	(void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock);
2672882Svi117747 }
2682882Svi117747 
2692882Svi117747 /*
2702882Svi117747  * Check for a transaction match. Passed to sip_hash_find().
2712882Svi117747  */
2722882Svi117747 boolean_t
sip_xaction_match(void * obj,void * hindex)2732882Svi117747 sip_xaction_match(void *obj, void *hindex)
2742882Svi117747 {
2752882Svi117747 	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
2762882Svi117747 
2772882Svi117747 	tmp = (sip_xaction_t *)obj;
2782882Svi117747 
2792882Svi117747 	if (SIP_IS_XACTION_TERMINATED(tmp->sip_xaction_state))
2802882Svi117747 		return (B_FALSE);
2812882Svi117747 	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
2822882Svi117747 	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
2832882Svi117747 		SIP_XACTION_REFCNT_INCR(tmp);
2842882Svi117747 		return (B_TRUE);
2852882Svi117747 	}
2862882Svi117747 	return (B_FALSE);
2872882Svi117747 }
2882882Svi117747 
2892882Svi117747 
2902882Svi117747 /*
2912882Svi117747  * Find a transaction
2922882Svi117747  */
2932882Svi117747 static sip_xaction_t *
sip_xaction_find(char * branchid,_sip_msg_t * msg,int which)2942882Svi117747 sip_xaction_find(char *branchid, _sip_msg_t *msg, int which)
2952882Svi117747 {
2962882Svi117747 	sip_xaction_t		*tmp;
2972882Svi117747 	uint16_t		hash_index[8];
2982882Svi117747 	int			hindex;
2992882Svi117747 	sip_method_t		method;
3002882Svi117747 	int			error;
3012882Svi117747 	sip_message_type_t	*sip_msg_info;
3022882Svi117747 
3032882Svi117747 	sip_msg_info = msg->sip_msg_req_res;
3042882Svi117747 	method = sip_get_callseq_method((sip_msg_t)msg, &error);
3052882Svi117747 	if (error != 0)
3062882Svi117747 		return (NULL);
3072882Svi117747 
3082882Svi117747 	/*
3092882Svi117747 	 * If we are getting a ACK/CANCEL we need to match with the
3102882Svi117747 	 * corresponding INVITE, if any.
3112882Svi117747 	 */
3122882Svi117747 	if (sip_msg_info->is_request && which == SIP_SERVER_TRANSACTION &&
3132882Svi117747 	    (method == ACK || method == CANCEL)) {
3142882Svi117747 		method = INVITE;
3152882Svi117747 	}
3162882Svi117747 	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
3172882Svi117747 		return (NULL);
3182882Svi117747 	hindex = SIP_DIGEST_TO_HASH(hash_index);
3192882Svi117747 	tmp = (sip_xaction_t *)sip_hash_find(sip_xaction_hash,
3202882Svi117747 	    (void *)hash_index, hindex, sip_xaction_match);
3212882Svi117747 	return (tmp);
3222882Svi117747 }
3232882Svi117747 
3242882Svi117747 /*
3252882Svi117747  * create a transaction.
3262882Svi117747  */
3272882Svi117747 static sip_xaction_t *
sip_xaction_create(sip_conn_object_t obj,_sip_msg_t * msg,char * branchid,int * error)3282882Svi117747 sip_xaction_create(sip_conn_object_t obj, _sip_msg_t *msg, char *branchid,
3292882Svi117747     int *error)
3302882Svi117747 {
3312882Svi117747 	sip_xaction_t		*trans;
3322882Svi117747 	sip_message_type_t	*sip_msg_info;
3332882Svi117747 	int			state = 0;
3342882Svi117747 	int			prev_state = 0;
3352882Svi117747 	sip_method_t		method;
3362882Svi117747 	int			ret;
3372882Svi117747 	int			timer1 = sip_timer_T1;
3382882Svi117747 	int			timer4 = sip_timer_T4;
3392882Svi117747 	int			timerd = sip_timer_TD;
3402882Svi117747 
3412882Svi117747 	if (error != NULL)
3422882Svi117747 		*error = 0;
3432882Svi117747 	/*
3442882Svi117747 	 * Make sure we are not creating a transaction for
3452882Svi117747 	 * an ACK request.
3462882Svi117747 	 */
3472882Svi117747 	trans = (sip_xaction_t *)malloc(sizeof (sip_xaction_t));
3482882Svi117747 	if (trans == NULL) {
3492882Svi117747 		if (error != NULL)
3502882Svi117747 			*error = ENOMEM;
3512882Svi117747 		return (NULL);
3522882Svi117747 	}
3532882Svi117747 	bzero(trans, sizeof (sip_xaction_t));
3542882Svi117747 	if (branchid == NULL) {
3552882Svi117747 		trans->sip_xaction_branch_id = (char *)sip_branchid(NULL);
3562882Svi117747 		if (trans->sip_xaction_branch_id == NULL) {
3572882Svi117747 			free(trans);
3582882Svi117747 			if (error != NULL)
3592882Svi117747 				*error = ENOMEM;
3602882Svi117747 			return (NULL);
3612882Svi117747 		}
3622882Svi117747 	} else {
3632882Svi117747 		trans->sip_xaction_branch_id = (char *)malloc(strlen(branchid)
3642882Svi117747 		    + 1);
3652882Svi117747 		if (trans->sip_xaction_branch_id == NULL) {
3662882Svi117747 			free(trans);
3672882Svi117747 			if (error != NULL)
3682882Svi117747 				*error = ENOMEM;
3692882Svi117747 			return (NULL);
3702882Svi117747 		}
3712882Svi117747 		(void) strncpy(trans->sip_xaction_branch_id, branchid,
3722882Svi117747 		    strlen(branchid));
3732882Svi117747 		trans->sip_xaction_branch_id[strlen(branchid)] = '\0';
3742882Svi117747 	}
3752882Svi117747 	(void) pthread_mutex_init(&trans->sip_xaction_mutex, NULL);
3762882Svi117747 	SIP_MSG_REFCNT_INCR(msg);
3772882Svi117747 	trans->sip_xaction_orig_msg = msg;
3782882Svi117747 	assert(msg->sip_msg_req_res != NULL);
3792882Svi117747 	sip_msg_info = msg->sip_msg_req_res;
3802882Svi117747 	if (sip_msg_info->is_request) {
3812882Svi117747 		method = sip_msg_info->sip_req_method;
3822882Svi117747 	} else {
3832882Svi117747 		method = sip_get_callseq_method((sip_msg_t)msg, &ret);
3842882Svi117747 		if (ret != 0) {
3852882Svi117747 			free(trans->sip_xaction_branch_id);
3862882Svi117747 			free(trans);
3872882Svi117747 			if (error != NULL)
3882882Svi117747 				*error = ret;
3892882Svi117747 			return (NULL);
3902882Svi117747 		}
3912882Svi117747 		if (method == INVITE)
3922882Svi117747 			state = SIP_SRV_INV_PROCEEDING;
3932882Svi117747 		else
3942882Svi117747 			state = SIP_SRV_TRYING;
3952882Svi117747 	}
3962882Svi117747 	trans->sip_xaction_method = method;
3972882Svi117747 	trans->sip_xaction_state = state;
3982882Svi117747 
3992882Svi117747 	/*
4002882Svi117747 	 * Get connection object specific timeouts, if present
4012882Svi117747 	 */
4022882Svi117747 	if (sip_conn_timer1 != NULL)
4032882Svi117747 		timer1 = sip_conn_timer1(obj);
4042882Svi117747 	if (sip_conn_timer4 != NULL)
4052882Svi117747 		timer4 = sip_conn_timer4(obj);
4062882Svi117747 	if (sip_conn_timerd != NULL)
4072882Svi117747 		timerd = sip_conn_timerd(obj);
4082882Svi117747 
4092882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TA, 2 * timer1);
4102882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TB, 64 * timer1)
4112882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TD,  timerd);
4122882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TE, timer1);
4132882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TF, 64 * timer1);
4142882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TG, 2 * timer1);
4152882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TH, 64 * timer1);
4162882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TI, timer4);
4172882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TJ, 64 * timer1);
4182882Svi117747 	SIP_INIT_TIMER(trans->sip_xaction_TK, timer4);
4192882Svi117747 
4202882Svi117747 	if ((ret = sip_xaction_add(trans, branchid, msg, method)) != 0) {
4212882Svi117747 		(void) pthread_mutex_destroy(&trans->sip_xaction_mutex);
4222882Svi117747 		free(trans->sip_xaction_branch_id);
4232882Svi117747 		free(trans);
4242882Svi117747 		if (error != NULL)
4252882Svi117747 			*error = ret;
4262882Svi117747 		return (NULL);
4272882Svi117747 	}
4282882Svi117747 	if (sip_xaction_ulp_state_cb != NULL &&
4292882Svi117747 	    prev_state != trans->sip_xaction_state) {
4302882Svi117747 		sip_xaction_ulp_state_cb((sip_transaction_t)trans,
4312882Svi117747 		    (sip_msg_t)msg, prev_state, trans->sip_xaction_state);
4322882Svi117747 	}
4332882Svi117747 	return (trans);
4342882Svi117747 }
4352882Svi117747 
4362882Svi117747 /*
4372882Svi117747  * Find a transaction, create if asked for
4382882Svi117747  */
4392882Svi117747 sip_xaction_t *
sip_xaction_get(sip_conn_object_t obj,sip_msg_t msg,boolean_t create,int which,int * error)4402882Svi117747 sip_xaction_get(sip_conn_object_t obj, sip_msg_t msg, boolean_t create,
4412882Svi117747     int which, int *error)
4422882Svi117747 {
4432882Svi117747 	char			*branchid;
4442882Svi117747 	sip_xaction_t		*sip_trans;
4452882Svi117747 	_sip_msg_t		*_msg;
4462882Svi117747 	sip_message_type_t	*sip_msg_info;
4472882Svi117747 
4482882Svi117747 	if (error != NULL)
4492882Svi117747 		*error = 0;
4502882Svi117747 
4512882Svi117747 	_msg = (_sip_msg_t *)msg;
4522882Svi117747 	sip_msg_info = ((_sip_msg_t *)msg)->sip_msg_req_res;
4532882Svi117747 
4542882Svi117747 	branchid = sip_get_branchid(msg, NULL);
4552882Svi117747 	sip_trans = sip_xaction_find(branchid, _msg, which);
4562882Svi117747 	if (sip_trans == NULL && create) {
4572882Svi117747 		/*
4582882Svi117747 		 * If we are sending a request, must be conformant to RFC 3261.
4592882Svi117747 		 */
4602882Svi117747 		if (sip_msg_info->is_request &&
4612882Svi117747 		    (branchid == NULL || strncmp(branchid,
4622882Svi117747 		    RFC_3261_BRANCH, strlen(RFC_3261_BRANCH) != 0))) {
4632882Svi117747 			if (error != NULL)
4642882Svi117747 				*error = EINVAL;
4652882Svi117747 			if (branchid != NULL)
4662882Svi117747 				free(branchid);
4672882Svi117747 			return (NULL);
4682882Svi117747 		}
4692882Svi117747 		sip_trans = sip_xaction_create(obj, _msg, branchid, error);
4702882Svi117747 		if (sip_trans != NULL)
4712882Svi117747 			SIP_XACTION_REFCNT_INCR(sip_trans);
4722882Svi117747 	}
4732882Svi117747 	if (branchid != NULL)
4742882Svi117747 		free(branchid);
4752882Svi117747 	return (sip_trans);
4762882Svi117747 }
4772882Svi117747 
4782882Svi117747 
4792882Svi117747 /*
4802882Svi117747  * Delete a transaction if the reference count is 0. Passed to
4812882Svi117747  * sip_hash_delete().
4822882Svi117747  */
4832882Svi117747 boolean_t
sip_xaction_remove(void * obj,void * hindex,int * found)4842882Svi117747 sip_xaction_remove(void *obj, void *hindex, int *found)
4852882Svi117747 {
4862882Svi117747 	sip_xaction_t	*tmp = (sip_xaction_t *)obj;
487*5842Sgm209912 	int		count = 0;
488*5842Sgm209912 	sip_msg_chain_t	*msg_chain;
489*5842Sgm209912 	sip_msg_chain_t	*nmsg_chain;
4902882Svi117747 
4912882Svi117747 	*found = 0;
4922882Svi117747 	tmp = (sip_xaction_t *)obj;
4932882Svi117747 	(void) pthread_mutex_lock(&tmp->sip_xaction_mutex);
4942882Svi117747 	if (bcmp(tmp->sip_xaction_hash_digest, hindex,
4952882Svi117747 	    sizeof (tmp->sip_xaction_hash_digest)) == 0) {
4962882Svi117747 		*found = 1;
4972882Svi117747 		if (tmp->sip_xaction_ref_cnt != 0) {
4982882Svi117747 			(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
4992882Svi117747 			return (B_FALSE);
5002882Svi117747 		}
5012882Svi117747 		(void) pthread_mutex_destroy(&tmp->sip_xaction_mutex);
5022882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TA);
5032882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TB);
5042882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TD);
5052882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TE);
5062882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TF);
5072882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TG);
5082882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TH);
5092882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TI);
5102882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TJ);
5112882Svi117747 		SIP_CANCEL_TIMER(tmp->sip_xaction_TK);
512*5842Sgm209912 		sip_write_to_log((void *)tmp, SIP_TRANSACTION_LOG, NULL, 0);
5132882Svi117747 		free(tmp->sip_xaction_branch_id);
5142882Svi117747 		if (tmp->sip_xaction_last_msg != NULL) {
5152882Svi117747 			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_last_msg);
5162882Svi117747 			tmp->sip_xaction_last_msg = NULL;
5172882Svi117747 		}
5182882Svi117747 		if (tmp->sip_xaction_orig_msg != NULL) {
5192882Svi117747 			SIP_MSG_REFCNT_DECR(tmp->sip_xaction_orig_msg);
5202882Svi117747 			tmp->sip_xaction_orig_msg = NULL;
5212882Svi117747 		}
5222882Svi117747 		if (tmp->sip_xaction_conn_obj != NULL) {
5232882Svi117747 			sip_del_conn_obj_cache(tmp->sip_xaction_conn_obj,
5242882Svi117747 			    (void *)tmp);
5252882Svi117747 		}
526*5842Sgm209912 		/*
527*5842Sgm209912 		 * If the transaction logging is disabled before we could
528*5842Sgm209912 		 * write the captured messages into the transaction log, then
529*5842Sgm209912 		 * we need to free those captured messsages
530*5842Sgm209912 		 */
531*5842Sgm209912 		for (count = 0; count <= SIP_SRV_NONINV_TERMINATED; count++) {
532*5842Sgm209912 			msg_chain = tmp->sip_xaction_log[count].sip_msgs;
533*5842Sgm209912 			while (msg_chain != NULL) {
534*5842Sgm209912 				nmsg_chain = msg_chain->next;
535*5842Sgm209912 				if (msg_chain->sip_msg != NULL)
536*5842Sgm209912 					free(msg_chain->sip_msg);
537*5842Sgm209912 				free(msg_chain);
538*5842Sgm209912 				msg_chain = nmsg_chain;
539*5842Sgm209912 			}
540*5842Sgm209912 		}
5412882Svi117747 		free(tmp);
5422882Svi117747 		return (B_TRUE);
5432882Svi117747 	}
5442882Svi117747 	(void) pthread_mutex_unlock(&tmp->sip_xaction_mutex);
5452882Svi117747 	return (B_FALSE);
5462882Svi117747 }
5472882Svi117747 
5482882Svi117747 /*
5492882Svi117747  * Delete a SIP transaction
5502882Svi117747  */
5512882Svi117747 void
sip_xaction_delete(sip_xaction_t * trans)5522882Svi117747 sip_xaction_delete(sip_xaction_t *trans)
5532882Svi117747 {
5542882Svi117747 	int	hindex;
5552882Svi117747 
5562882Svi117747 	(void) pthread_mutex_lock(&trans->sip_xaction_mutex);
5572882Svi117747 	hindex = SIP_DIGEST_TO_HASH(trans->sip_xaction_hash_digest);
5582882Svi117747 	if (trans->sip_xaction_ref_cnt != 0) {
5592882Svi117747 		(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
5602882Svi117747 		return;
5612882Svi117747 	}
5622882Svi117747 	(void) pthread_mutex_unlock(&trans->sip_xaction_mutex);
5632882Svi117747 	sip_hash_delete(sip_xaction_hash, trans->sip_xaction_hash_digest,
5642882Svi117747 	    hindex, sip_xaction_remove);
5652882Svi117747 }
5662882Svi117747 
5672882Svi117747 /*
5682882Svi117747  * Add a SIP transaction into the hash list.
5692882Svi117747  */
5702882Svi117747 int
sip_xaction_add(sip_xaction_t * trans,char * branchid,_sip_msg_t * msg,sip_method_t method)5712882Svi117747 sip_xaction_add(sip_xaction_t *trans, char *branchid, _sip_msg_t *msg,
5722882Svi117747     sip_method_t method)
5732882Svi117747 {
5742882Svi117747 	uint16_t	hash_index[8];
5752882Svi117747 
5762882Svi117747 	if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0)
5772882Svi117747 		return (EINVAL);
5782882Svi117747 
5792882Svi117747 	/*
5802882Svi117747 	 * trans is not in the list as yet, so no need to hold the lock
5812882Svi117747 	 */
5822882Svi117747 	bcopy(hash_index, trans->sip_xaction_hash_digest, sizeof (hash_index));
5832882Svi117747 
5842882Svi117747 	if (sip_hash_add(sip_xaction_hash, (void *)trans,
5852882Svi117747 	    SIP_DIGEST_TO_HASH(hash_index)) != 0) {
5862882Svi117747 		return (ENOMEM);
5872882Svi117747 	}
5882882Svi117747 	return (0);
5892882Svi117747 }
5902882Svi117747 
5912882Svi117747 
5922882Svi117747 /*
5932882Svi117747  * Given a state, return the  string - This is mostly for debug purposes
5942882Svi117747  */
5952882Svi117747 char *
sip_get_xaction_state(int state)5962882Svi117747 sip_get_xaction_state(int state)
5972882Svi117747 {
5982882Svi117747 	switch (state) {
599*5842Sgm209912 		case SIP_NEW_TRANSACTION:
600*5842Sgm209912 			return ("SIP_NEW_TRANSACTION");
6012882Svi117747 		case SIP_CLNT_CALLING:
6022882Svi117747 			return ("SIP_CLNT_CALLING");
6032882Svi117747 		case SIP_CLNT_INV_PROCEEDING:
6042882Svi117747 			return ("SIP_CLNT_INV_PROCEEDING");
6052882Svi117747 		case SIP_CLNT_INV_TERMINATED:
6062882Svi117747 			return ("SIP_CLNT_INV_TERMINATED");
6072882Svi117747 		case SIP_CLNT_INV_COMPLETED:
6082882Svi117747 			return ("SIP_CLNT_INV_COMPLETED");
6092882Svi117747 		case SIP_CLNT_TRYING:
6102882Svi117747 			return ("SIP_CLNT_TRYING");
6112882Svi117747 		case SIP_CLNT_NONINV_PROCEEDING:
6122882Svi117747 			return ("SIP_CLNT_NONINV_PROCEEDING");
6132882Svi117747 		case SIP_CLNT_NONINV_TERMINATED:
6142882Svi117747 			return ("SIP_CLNT_NONINV_TERMINATED");
6152882Svi117747 		case SIP_CLNT_NONINV_COMPLETED:
6162882Svi117747 			return ("SIP_CLNT_NONINV_COMPLETED");
6172882Svi117747 		case SIP_SRV_INV_PROCEEDING:
6182882Svi117747 			return ("SIP_SRV_INV_PROCEEDING");
6192882Svi117747 		case SIP_SRV_INV_COMPLETED:
6202882Svi117747 			return ("SIP_SRV_INV_COMPLETED");
6212882Svi117747 		case SIP_SRV_CONFIRMED:
6222882Svi117747 			return ("SIP_SRV_CONFIRMED");
6232882Svi117747 		case SIP_SRV_INV_TERMINATED:
6242882Svi117747 			return ("SIP_SRV_INV_TERMINATED");
6252882Svi117747 		case SIP_SRV_TRYING:
6262882Svi117747 			return ("SIP_SRV_TRYING");
6272882Svi117747 		case SIP_SRV_NONINV_PROCEEDING:
6282882Svi117747 			return ("SIP_SRV_NONINV_PROCEEDING");
6292882Svi117747 		case SIP_SRV_NONINV_COMPLETED:
6302882Svi117747 			return ("SIP_SRV_NONINV_COMPLETED");
6312882Svi117747 		case SIP_SRV_NONINV_TERMINATED:
6322882Svi117747 			return ("SIP_SRV_NONINV_TERMINATED");
6332882Svi117747 		default :
634*5842Sgm209912 			return ("UNKNOWN");
6352882Svi117747 	}
6362882Svi117747 }
6372882Svi117747 
6382882Svi117747 /*
6392882Svi117747  * Initialize the hash table etc.
6402882Svi117747  */
6412882Svi117747 void
sip_xaction_init(int (* ulp_trans_err)(sip_transaction_t,int,void *),void (* ulp_state_cb)(sip_transaction_t,sip_msg_t,int,int))6422882Svi117747 sip_xaction_init(int (*ulp_trans_err)(sip_transaction_t, int, void *),
6432882Svi117747     void (*ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int))
6442882Svi117747 {
6452882Svi117747 	int	cnt;
6462882Svi117747 
6472882Svi117747 	for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) {
6482882Svi117747 		sip_xaction_hash[cnt].hash_count = 0;
6492882Svi117747 		sip_xaction_hash[cnt].hash_head = NULL;
6502882Svi117747 		sip_xaction_hash[cnt].hash_tail = NULL;
6512882Svi117747 		(void) pthread_mutex_init(
6522882Svi117747 		    &sip_xaction_hash[cnt].sip_hash_mutex, NULL);
6532882Svi117747 	}
6542882Svi117747 	if (ulp_trans_err != NULL)
6552882Svi117747 		sip_xaction_ulp_trans_err = ulp_trans_err;
6562882Svi117747 	if (ulp_state_cb != NULL)
6572882Svi117747 		sip_xaction_ulp_state_cb = ulp_state_cb;
6582882Svi117747 }
659