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