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*3439Svi117747 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 242882Svi117747 * Use is subject to license terms. 252882Svi117747 */ 262882Svi117747 272882Svi117747 #pragma ident "%Z%%M% %I% %E% SMI" 282882Svi117747 29*3439Svi117747 #include <stdlib.h> 30*3439Svi117747 #include <assert.h> 31*3439Svi117747 #include <errno.h> 32*3439Svi117747 #include <pthread.h> 33*3439Svi117747 #include <strings.h> 34*3439Svi117747 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 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 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 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 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 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 * 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 * 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 * 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 4842882Svi117747 sip_xaction_remove(void *obj, void *hindex, int *found) 4852882Svi117747 { 4862882Svi117747 sip_xaction_t *tmp = (sip_xaction_t *)obj; 4872882Svi117747 4882882Svi117747 *found = 0; 4892882Svi117747 tmp = (sip_xaction_t *)obj; 4902882Svi117747 (void) pthread_mutex_lock(&tmp->sip_xaction_mutex); 4912882Svi117747 if (bcmp(tmp->sip_xaction_hash_digest, hindex, 4922882Svi117747 sizeof (tmp->sip_xaction_hash_digest)) == 0) { 4932882Svi117747 *found = 1; 4942882Svi117747 if (tmp->sip_xaction_ref_cnt != 0) { 4952882Svi117747 (void) pthread_mutex_unlock(&tmp->sip_xaction_mutex); 4962882Svi117747 return (B_FALSE); 4972882Svi117747 } 4982882Svi117747 (void) pthread_mutex_destroy(&tmp->sip_xaction_mutex); 4992882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TA); 5002882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TB); 5012882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TD); 5022882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TE); 5032882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TF); 5042882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TG); 5052882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TH); 5062882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TI); 5072882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TJ); 5082882Svi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TK); 5092882Svi117747 free(tmp->sip_xaction_branch_id); 5102882Svi117747 if (tmp->sip_xaction_last_msg != NULL) { 5112882Svi117747 SIP_MSG_REFCNT_DECR(tmp->sip_xaction_last_msg); 5122882Svi117747 tmp->sip_xaction_last_msg = NULL; 5132882Svi117747 } 5142882Svi117747 if (tmp->sip_xaction_orig_msg != NULL) { 5152882Svi117747 SIP_MSG_REFCNT_DECR(tmp->sip_xaction_orig_msg); 5162882Svi117747 tmp->sip_xaction_orig_msg = NULL; 5172882Svi117747 } 5182882Svi117747 if (tmp->sip_xaction_conn_obj != NULL) { 5192882Svi117747 sip_del_conn_obj_cache(tmp->sip_xaction_conn_obj, 5202882Svi117747 (void *)tmp); 5212882Svi117747 } 5222882Svi117747 free(tmp); 5232882Svi117747 return (B_TRUE); 5242882Svi117747 } 5252882Svi117747 (void) pthread_mutex_unlock(&tmp->sip_xaction_mutex); 5262882Svi117747 return (B_FALSE); 5272882Svi117747 } 5282882Svi117747 5292882Svi117747 /* 5302882Svi117747 * Delete a SIP transaction 5312882Svi117747 */ 5322882Svi117747 void 5332882Svi117747 sip_xaction_delete(sip_xaction_t *trans) 5342882Svi117747 { 5352882Svi117747 int hindex; 5362882Svi117747 5372882Svi117747 (void) pthread_mutex_lock(&trans->sip_xaction_mutex); 5382882Svi117747 hindex = SIP_DIGEST_TO_HASH(trans->sip_xaction_hash_digest); 5392882Svi117747 if (trans->sip_xaction_ref_cnt != 0) { 5402882Svi117747 (void) pthread_mutex_unlock(&trans->sip_xaction_mutex); 5412882Svi117747 return; 5422882Svi117747 } 5432882Svi117747 (void) pthread_mutex_unlock(&trans->sip_xaction_mutex); 5442882Svi117747 sip_hash_delete(sip_xaction_hash, trans->sip_xaction_hash_digest, 5452882Svi117747 hindex, sip_xaction_remove); 5462882Svi117747 } 5472882Svi117747 5482882Svi117747 /* 5492882Svi117747 * Add a SIP transaction into the hash list. 5502882Svi117747 */ 5512882Svi117747 int 5522882Svi117747 sip_xaction_add(sip_xaction_t *trans, char *branchid, _sip_msg_t *msg, 5532882Svi117747 sip_method_t method) 5542882Svi117747 { 5552882Svi117747 uint16_t hash_index[8]; 5562882Svi117747 5572882Svi117747 if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0) 5582882Svi117747 return (EINVAL); 5592882Svi117747 5602882Svi117747 /* 5612882Svi117747 * trans is not in the list as yet, so no need to hold the lock 5622882Svi117747 */ 5632882Svi117747 bcopy(hash_index, trans->sip_xaction_hash_digest, sizeof (hash_index)); 5642882Svi117747 5652882Svi117747 if (sip_hash_add(sip_xaction_hash, (void *)trans, 5662882Svi117747 SIP_DIGEST_TO_HASH(hash_index)) != 0) { 5672882Svi117747 return (ENOMEM); 5682882Svi117747 } 5692882Svi117747 return (0); 5702882Svi117747 } 5712882Svi117747 5722882Svi117747 5732882Svi117747 /* 5742882Svi117747 * Given a state, return the string - This is mostly for debug purposes 5752882Svi117747 */ 5762882Svi117747 char * 5772882Svi117747 sip_get_xaction_state(int state) 5782882Svi117747 { 5792882Svi117747 switch (state) { 5802882Svi117747 case SIP_CLNT_CALLING: 5812882Svi117747 return ("SIP_CLNT_CALLING"); 5822882Svi117747 case SIP_CLNT_INV_PROCEEDING: 5832882Svi117747 return ("SIP_CLNT_INV_PROCEEDING"); 5842882Svi117747 case SIP_CLNT_INV_TERMINATED: 5852882Svi117747 return ("SIP_CLNT_INV_TERMINATED"); 5862882Svi117747 case SIP_CLNT_INV_COMPLETED: 5872882Svi117747 return ("SIP_CLNT_INV_COMPLETED"); 5882882Svi117747 case SIP_CLNT_TRYING: 5892882Svi117747 return ("SIP_CLNT_TRYING"); 5902882Svi117747 case SIP_CLNT_NONINV_PROCEEDING: 5912882Svi117747 return ("SIP_CLNT_NONINV_PROCEEDING"); 5922882Svi117747 case SIP_CLNT_NONINV_TERMINATED: 5932882Svi117747 return ("SIP_CLNT_NONINV_TERMINATED"); 5942882Svi117747 case SIP_CLNT_NONINV_COMPLETED: 5952882Svi117747 return ("SIP_CLNT_NONINV_COMPLETED"); 5962882Svi117747 case SIP_SRV_INV_PROCEEDING: 5972882Svi117747 return ("SIP_SRV_INV_PROCEEDING"); 5982882Svi117747 case SIP_SRV_INV_COMPLETED: 5992882Svi117747 return ("SIP_SRV_INV_COMPLETED"); 6002882Svi117747 case SIP_SRV_CONFIRMED: 6012882Svi117747 return ("SIP_SRV_CONFIRMED"); 6022882Svi117747 case SIP_SRV_INV_TERMINATED: 6032882Svi117747 return ("SIP_SRV_INV_TERMINATED"); 6042882Svi117747 case SIP_SRV_TRYING: 6052882Svi117747 return ("SIP_SRV_TRYING"); 6062882Svi117747 case SIP_SRV_NONINV_PROCEEDING: 6072882Svi117747 return ("SIP_SRV_NONINV_PROCEEDING"); 6082882Svi117747 case SIP_SRV_NONINV_COMPLETED: 6092882Svi117747 return ("SIP_SRV_NONINV_COMPLETED"); 6102882Svi117747 case SIP_SRV_NONINV_TERMINATED: 6112882Svi117747 return ("SIP_SRV_NONINV_TERMINATED"); 6122882Svi117747 default : 6132882Svi117747 return ("unknown"); 6142882Svi117747 } 6152882Svi117747 } 6162882Svi117747 6172882Svi117747 /* 6182882Svi117747 * Initialize the hash table etc. 6192882Svi117747 */ 6202882Svi117747 void 6212882Svi117747 sip_xaction_init(int (*ulp_trans_err)(sip_transaction_t, int, void *), 6222882Svi117747 void (*ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int)) 6232882Svi117747 { 6242882Svi117747 int cnt; 6252882Svi117747 6262882Svi117747 for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) { 6272882Svi117747 sip_xaction_hash[cnt].hash_count = 0; 6282882Svi117747 sip_xaction_hash[cnt].hash_head = NULL; 6292882Svi117747 sip_xaction_hash[cnt].hash_tail = NULL; 6302882Svi117747 (void) pthread_mutex_init( 6312882Svi117747 &sip_xaction_hash[cnt].sip_hash_mutex, NULL); 6322882Svi117747 } 6332882Svi117747 if (ulp_trans_err != NULL) 6342882Svi117747 sip_xaction_ulp_trans_err = ulp_trans_err; 6352882Svi117747 if (ulp_state_cb != NULL) 6362882Svi117747 sip_xaction_ulp_state_cb = ulp_state_cb; 6372882Svi117747 } 638