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