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