140cb5e5dSvi117747 /* 240cb5e5dSvi117747 * CDDL HEADER START 340cb5e5dSvi117747 * 440cb5e5dSvi117747 * The contents of this file are subject to the terms of the 540cb5e5dSvi117747 * Common Development and Distribution License (the "License"). 640cb5e5dSvi117747 * You may not use this file except in compliance with the License. 740cb5e5dSvi117747 * 840cb5e5dSvi117747 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 940cb5e5dSvi117747 * or http://www.opensolaris.org/os/licensing. 1040cb5e5dSvi117747 * See the License for the specific language governing permissions 1140cb5e5dSvi117747 * and limitations under the License. 1240cb5e5dSvi117747 * 1340cb5e5dSvi117747 * When distributing Covered Code, include this CDDL HEADER in each 1440cb5e5dSvi117747 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1540cb5e5dSvi117747 * If applicable, add the following below this CDDL HEADER, with the 1640cb5e5dSvi117747 * fields enclosed by brackets "[]" replaced with your own identifying 1740cb5e5dSvi117747 * information: Portions Copyright [yyyy] [name of copyright owner] 1840cb5e5dSvi117747 * 1940cb5e5dSvi117747 * CDDL HEADER END 2040cb5e5dSvi117747 */ 2140cb5e5dSvi117747 2240cb5e5dSvi117747 /* 23*943efbc3Sgm209912 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 2440cb5e5dSvi117747 * Use is subject to license terms. 2540cb5e5dSvi117747 */ 2640cb5e5dSvi117747 2740cb5e5dSvi117747 #pragma ident "%Z%%M% %I% %E% SMI" 2840cb5e5dSvi117747 292c2c4183Svi117747 #include <stdlib.h> 302c2c4183Svi117747 #include <assert.h> 312c2c4183Svi117747 #include <errno.h> 322c2c4183Svi117747 #include <pthread.h> 332c2c4183Svi117747 #include <strings.h> 342c2c4183Svi117747 3540cb5e5dSvi117747 #include "sip_parse_uri.h" 3640cb5e5dSvi117747 #include "sip_msg.h" 3740cb5e5dSvi117747 #include "sip_miscdefs.h" 3840cb5e5dSvi117747 #include "sip_xaction.h" 3940cb5e5dSvi117747 #include "sip_hash.h" 4040cb5e5dSvi117747 4140cb5e5dSvi117747 #define RFC_3261_BRANCH "z9hG4bK" 4240cb5e5dSvi117747 4340cb5e5dSvi117747 /* 4440cb5e5dSvi117747 * The transaction hash table 4540cb5e5dSvi117747 */ 4640cb5e5dSvi117747 sip_hash_t sip_xaction_hash[SIP_HASH_SZ]; 4740cb5e5dSvi117747 4840cb5e5dSvi117747 int (*sip_xaction_ulp_trans_err)(sip_transaction_t, int, void *) = NULL; 4940cb5e5dSvi117747 void (*sip_xaction_ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int) = NULL; 5040cb5e5dSvi117747 5140cb5e5dSvi117747 int sip_xaction_add(sip_xaction_t *, char *, _sip_msg_t *, sip_method_t); 5240cb5e5dSvi117747 static boolean_t sip_is_conn_obj_cache(sip_conn_object_t, void *); 5340cb5e5dSvi117747 5440cb5e5dSvi117747 /* 5540cb5e5dSvi117747 * Get the md5 hash of the required fields 5640cb5e5dSvi117747 */ 5740cb5e5dSvi117747 int 5840cb5e5dSvi117747 sip_find_md5_digest(char *bid, _sip_msg_t *msg, uint16_t *hindex, 5940cb5e5dSvi117747 sip_method_t method) 6040cb5e5dSvi117747 { 6140cb5e5dSvi117747 boolean_t is_2543; 6240cb5e5dSvi117747 6340cb5e5dSvi117747 is_2543 = (bid == NULL || 6440cb5e5dSvi117747 strncmp(bid, RFC_3261_BRANCH, strlen(RFC_3261_BRANCH)) != 0); 6540cb5e5dSvi117747 6640cb5e5dSvi117747 if (is_2543 && msg == NULL) 6740cb5e5dSvi117747 return (EINVAL); 6840cb5e5dSvi117747 if (is_2543) { 6940cb5e5dSvi117747 _sip_header_t *from = NULL; 7040cb5e5dSvi117747 _sip_header_t *cid = NULL; 7140cb5e5dSvi117747 _sip_header_t *via = NULL; 7240cb5e5dSvi117747 const sip_str_t *to_uri = NULL; 7340cb5e5dSvi117747 int cseq; 7440cb5e5dSvi117747 int error = 0; 7540cb5e5dSvi117747 7640cb5e5dSvi117747 /* 7740cb5e5dSvi117747 * Since the response might contain parameters not in the 7840cb5e5dSvi117747 * request, just use the to URI. 7940cb5e5dSvi117747 */ 8040cb5e5dSvi117747 to_uri = sip_get_to_uri_str((sip_msg_t)msg, &error); 8140cb5e5dSvi117747 if (to_uri == NULL || error != 0) 8240cb5e5dSvi117747 return (EINVAL); 8340cb5e5dSvi117747 cseq = sip_get_callseq_num((sip_msg_t)msg, &error); 8440cb5e5dSvi117747 if (cseq < 0 || error != 0) 8540cb5e5dSvi117747 return (EINVAL); 8640cb5e5dSvi117747 (void) pthread_mutex_lock(&msg->sip_msg_mutex); 8740cb5e5dSvi117747 via = sip_search_for_header(msg, SIP_VIA, NULL); 8840cb5e5dSvi117747 from = sip_search_for_header(msg, SIP_FROM, NULL); 8940cb5e5dSvi117747 cid = sip_search_for_header(msg, SIP_CALL_ID, NULL); 9040cb5e5dSvi117747 (void) pthread_mutex_unlock(&msg->sip_msg_mutex); 9140cb5e5dSvi117747 if (via == NULL || from == NULL || cid == NULL) 9240cb5e5dSvi117747 return (EINVAL); 9340cb5e5dSvi117747 sip_md5_hash(via->sip_hdr_start, 9440cb5e5dSvi117747 via->sip_hdr_end - via->sip_hdr_start, 9540cb5e5dSvi117747 cid->sip_hdr_start, 9640cb5e5dSvi117747 cid->sip_hdr_end - cid->sip_hdr_start, 9740cb5e5dSvi117747 from->sip_hdr_start, 9840cb5e5dSvi117747 from->sip_hdr_end - from->sip_hdr_start, 9940cb5e5dSvi117747 (char *)&cseq, sizeof (int), 10040cb5e5dSvi117747 (char *)&method, sizeof (sip_method_t), 10140cb5e5dSvi117747 to_uri->sip_str_ptr, to_uri->sip_str_len, 10240cb5e5dSvi117747 (uchar_t *)hindex); 10340cb5e5dSvi117747 } else { 10440cb5e5dSvi117747 sip_md5_hash(bid, strlen(bid), (char *)&method, 10540cb5e5dSvi117747 sizeof (sip_method_t), NULL, 0, NULL, 0, NULL, 0, NULL, 0, 10640cb5e5dSvi117747 (uchar_t *)hindex); 10740cb5e5dSvi117747 } 10840cb5e5dSvi117747 return (0); 10940cb5e5dSvi117747 } 11040cb5e5dSvi117747 11140cb5e5dSvi117747 /* 11240cb5e5dSvi117747 * Add object to the connection cache object. Not checking for duplicates!! 11340cb5e5dSvi117747 */ 11440cb5e5dSvi117747 int 11540cb5e5dSvi117747 sip_add_conn_obj_cache(sip_conn_object_t obj, void *cobj) 11640cb5e5dSvi117747 { 11740cb5e5dSvi117747 void **obj_val; 11840cb5e5dSvi117747 sip_conn_obj_pvt_t *pvt_data; 11940cb5e5dSvi117747 sip_conn_cache_t *xaction_list; 12040cb5e5dSvi117747 sip_xaction_t *sip_trans = (sip_xaction_t *)cobj; 12140cb5e5dSvi117747 12240cb5e5dSvi117747 /* 12340cb5e5dSvi117747 * Is already cached 12440cb5e5dSvi117747 */ 12540cb5e5dSvi117747 if (sip_trans->sip_xaction_conn_obj != NULL) { 12640cb5e5dSvi117747 if (sip_is_conn_obj_cache(sip_trans->sip_xaction_conn_obj, 12740cb5e5dSvi117747 (void *)sip_trans)) { 12840cb5e5dSvi117747 return (0); 12940cb5e5dSvi117747 } 13040cb5e5dSvi117747 /* 13140cb5e5dSvi117747 * Transaction has cached a different conn_obj, release it 13240cb5e5dSvi117747 */ 13340cb5e5dSvi117747 sip_del_conn_obj_cache(sip_trans->sip_xaction_conn_obj, 13440cb5e5dSvi117747 (void *)sip_trans); 13540cb5e5dSvi117747 } 13640cb5e5dSvi117747 13740cb5e5dSvi117747 xaction_list = malloc(sizeof (sip_conn_cache_t)); 13840cb5e5dSvi117747 if (xaction_list == NULL) 13940cb5e5dSvi117747 return (ENOMEM); 14040cb5e5dSvi117747 xaction_list->obj = cobj; 14140cb5e5dSvi117747 xaction_list->next = xaction_list->prev = NULL; 14240cb5e5dSvi117747 14340cb5e5dSvi117747 obj_val = (void *)obj; 14440cb5e5dSvi117747 pvt_data = (sip_conn_obj_pvt_t *)*obj_val; 14540cb5e5dSvi117747 if (pvt_data == NULL) { 14640cb5e5dSvi117747 free(xaction_list); 14740cb5e5dSvi117747 return (EINVAL); 14840cb5e5dSvi117747 } 14940cb5e5dSvi117747 (void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock); 15040cb5e5dSvi117747 15140cb5e5dSvi117747 if (pvt_data->sip_conn_obj_cache == NULL) { 15240cb5e5dSvi117747 pvt_data->sip_conn_obj_cache = xaction_list; 15340cb5e5dSvi117747 } else { 15440cb5e5dSvi117747 xaction_list->next = pvt_data->sip_conn_obj_cache; 15540cb5e5dSvi117747 pvt_data->sip_conn_obj_cache->prev = xaction_list; 15640cb5e5dSvi117747 pvt_data->sip_conn_obj_cache = xaction_list; 15740cb5e5dSvi117747 } 15840cb5e5dSvi117747 sip_refhold_conn(obj); 15940cb5e5dSvi117747 sip_trans->sip_xaction_conn_obj = obj; 16040cb5e5dSvi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock); 16140cb5e5dSvi117747 return (0); 16240cb5e5dSvi117747 } 16340cb5e5dSvi117747 16440cb5e5dSvi117747 /* 16540cb5e5dSvi117747 * Walk thru the list of transactions that have cached this obj and 16640cb5e5dSvi117747 * and return true if 'cobj' is one of them. 16740cb5e5dSvi117747 */ 16840cb5e5dSvi117747 static boolean_t 16940cb5e5dSvi117747 sip_is_conn_obj_cache(sip_conn_object_t obj, void *cobj) 17040cb5e5dSvi117747 { 17140cb5e5dSvi117747 void **obj_val; 17240cb5e5dSvi117747 sip_conn_obj_pvt_t *pvt_data; 17340cb5e5dSvi117747 sip_conn_cache_t *xaction_list; 17440cb5e5dSvi117747 sip_xaction_t *trans; 17540cb5e5dSvi117747 sip_xaction_t *ctrans = (sip_xaction_t *)cobj; 17640cb5e5dSvi117747 17740cb5e5dSvi117747 obj_val = (void *)obj; 17840cb5e5dSvi117747 pvt_data = (sip_conn_obj_pvt_t *)*obj_val; 17940cb5e5dSvi117747 if (pvt_data == NULL) 18040cb5e5dSvi117747 return (B_FALSE); 18140cb5e5dSvi117747 (void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock); 18240cb5e5dSvi117747 xaction_list = pvt_data->sip_conn_obj_cache; 18340cb5e5dSvi117747 while (xaction_list != NULL) { 18440cb5e5dSvi117747 trans = (sip_xaction_t *)xaction_list->obj; 18540cb5e5dSvi117747 if (ctrans != trans) { 18640cb5e5dSvi117747 xaction_list = xaction_list->next; 18740cb5e5dSvi117747 continue; 18840cb5e5dSvi117747 } 18940cb5e5dSvi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock); 19040cb5e5dSvi117747 return (B_TRUE); 19140cb5e5dSvi117747 } 19240cb5e5dSvi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock); 19340cb5e5dSvi117747 return (B_FALSE); 19440cb5e5dSvi117747 } 19540cb5e5dSvi117747 19640cb5e5dSvi117747 19740cb5e5dSvi117747 /* 19840cb5e5dSvi117747 * Walk thru the list of transactions that have cached this obj and 19940cb5e5dSvi117747 * refrele the objs. 20040cb5e5dSvi117747 */ 20140cb5e5dSvi117747 void 20240cb5e5dSvi117747 sip_del_conn_obj_cache(sip_conn_object_t obj, void *cobj) 20340cb5e5dSvi117747 { 20440cb5e5dSvi117747 void **obj_val; 20540cb5e5dSvi117747 sip_conn_obj_pvt_t *pvt_data; 20640cb5e5dSvi117747 sip_conn_cache_t *xaction_list; 20740cb5e5dSvi117747 sip_conn_cache_t *tmp_list; 20840cb5e5dSvi117747 sip_xaction_t *trans; 20940cb5e5dSvi117747 sip_xaction_t *ctrans = NULL; 21040cb5e5dSvi117747 21140cb5e5dSvi117747 if (cobj != NULL) 21240cb5e5dSvi117747 ctrans = (sip_xaction_t *)cobj; 21340cb5e5dSvi117747 21440cb5e5dSvi117747 obj_val = (void *)obj; 21540cb5e5dSvi117747 pvt_data = (sip_conn_obj_pvt_t *)*obj_val; 21640cb5e5dSvi117747 if (pvt_data == NULL) { /* ASSERT FALSE if ctrans != NULL?? */ 21740cb5e5dSvi117747 if (ctrans != NULL) { 21840cb5e5dSvi117747 sip_refrele_conn(obj); 21940cb5e5dSvi117747 ctrans->sip_xaction_conn_obj = NULL; 22040cb5e5dSvi117747 } 22140cb5e5dSvi117747 return; 22240cb5e5dSvi117747 } 22340cb5e5dSvi117747 (void) pthread_mutex_lock(&pvt_data->sip_conn_obj_cache_lock); 22440cb5e5dSvi117747 xaction_list = pvt_data->sip_conn_obj_cache; 22540cb5e5dSvi117747 while (xaction_list != NULL) { 22640cb5e5dSvi117747 tmp_list = xaction_list; 22740cb5e5dSvi117747 trans = (sip_xaction_t *)xaction_list->obj; 22840cb5e5dSvi117747 assert(trans != NULL); 22940cb5e5dSvi117747 if (ctrans != NULL && ctrans != trans) { 23040cb5e5dSvi117747 xaction_list = xaction_list->next; 23140cb5e5dSvi117747 continue; 23240cb5e5dSvi117747 } 23340cb5e5dSvi117747 if (ctrans == NULL) 23440cb5e5dSvi117747 (void) pthread_mutex_lock(&trans->sip_xaction_mutex); 23540cb5e5dSvi117747 assert(trans->sip_xaction_conn_obj == obj); 23640cb5e5dSvi117747 sip_refrele_conn(obj); 23740cb5e5dSvi117747 trans->sip_xaction_conn_obj = NULL; 23840cb5e5dSvi117747 if (ctrans == NULL) 23940cb5e5dSvi117747 (void) pthread_mutex_unlock(&trans->sip_xaction_mutex); 24040cb5e5dSvi117747 xaction_list = xaction_list->next; 24140cb5e5dSvi117747 24240cb5e5dSvi117747 /* 24340cb5e5dSvi117747 * Take the obj out of the list 24440cb5e5dSvi117747 */ 24540cb5e5dSvi117747 if (tmp_list == pvt_data->sip_conn_obj_cache) { 24640cb5e5dSvi117747 if (xaction_list == NULL) { 24740cb5e5dSvi117747 pvt_data->sip_conn_obj_cache = NULL; 24840cb5e5dSvi117747 } else { 24940cb5e5dSvi117747 xaction_list->prev = NULL; 25040cb5e5dSvi117747 pvt_data->sip_conn_obj_cache = xaction_list; 25140cb5e5dSvi117747 } 25240cb5e5dSvi117747 } else if (xaction_list == NULL) { 25340cb5e5dSvi117747 assert(tmp_list->prev != NULL); 25440cb5e5dSvi117747 tmp_list->prev->next = NULL; 25540cb5e5dSvi117747 } else { 25640cb5e5dSvi117747 assert(tmp_list->prev != NULL); 25740cb5e5dSvi117747 tmp_list->prev->next = xaction_list; 25840cb5e5dSvi117747 xaction_list->prev = tmp_list->prev; 25940cb5e5dSvi117747 } 26040cb5e5dSvi117747 tmp_list->prev = NULL; 26140cb5e5dSvi117747 tmp_list->next = NULL; 26240cb5e5dSvi117747 tmp_list->obj = NULL; 26340cb5e5dSvi117747 26440cb5e5dSvi117747 free(tmp_list); 26540cb5e5dSvi117747 } 26640cb5e5dSvi117747 (void) pthread_mutex_unlock(&pvt_data->sip_conn_obj_cache_lock); 26740cb5e5dSvi117747 } 26840cb5e5dSvi117747 26940cb5e5dSvi117747 /* 27040cb5e5dSvi117747 * Check for a transaction match. Passed to sip_hash_find(). 27140cb5e5dSvi117747 */ 27240cb5e5dSvi117747 boolean_t 27340cb5e5dSvi117747 sip_xaction_match(void *obj, void *hindex) 27440cb5e5dSvi117747 { 27540cb5e5dSvi117747 sip_xaction_t *tmp = (sip_xaction_t *)obj; 27640cb5e5dSvi117747 27740cb5e5dSvi117747 tmp = (sip_xaction_t *)obj; 27840cb5e5dSvi117747 27940cb5e5dSvi117747 if (SIP_IS_XACTION_TERMINATED(tmp->sip_xaction_state)) 28040cb5e5dSvi117747 return (B_FALSE); 28140cb5e5dSvi117747 if (bcmp(tmp->sip_xaction_hash_digest, hindex, 28240cb5e5dSvi117747 sizeof (tmp->sip_xaction_hash_digest)) == 0) { 28340cb5e5dSvi117747 SIP_XACTION_REFCNT_INCR(tmp); 28440cb5e5dSvi117747 return (B_TRUE); 28540cb5e5dSvi117747 } 28640cb5e5dSvi117747 return (B_FALSE); 28740cb5e5dSvi117747 } 28840cb5e5dSvi117747 28940cb5e5dSvi117747 29040cb5e5dSvi117747 /* 29140cb5e5dSvi117747 * Find a transaction 29240cb5e5dSvi117747 */ 29340cb5e5dSvi117747 static sip_xaction_t * 29440cb5e5dSvi117747 sip_xaction_find(char *branchid, _sip_msg_t *msg, int which) 29540cb5e5dSvi117747 { 29640cb5e5dSvi117747 sip_xaction_t *tmp; 29740cb5e5dSvi117747 uint16_t hash_index[8]; 29840cb5e5dSvi117747 int hindex; 29940cb5e5dSvi117747 sip_method_t method; 30040cb5e5dSvi117747 int error; 30140cb5e5dSvi117747 sip_message_type_t *sip_msg_info; 30240cb5e5dSvi117747 30340cb5e5dSvi117747 sip_msg_info = msg->sip_msg_req_res; 30440cb5e5dSvi117747 method = sip_get_callseq_method((sip_msg_t)msg, &error); 30540cb5e5dSvi117747 if (error != 0) 30640cb5e5dSvi117747 return (NULL); 30740cb5e5dSvi117747 30840cb5e5dSvi117747 /* 30940cb5e5dSvi117747 * If we are getting a ACK/CANCEL we need to match with the 31040cb5e5dSvi117747 * corresponding INVITE, if any. 31140cb5e5dSvi117747 */ 31240cb5e5dSvi117747 if (sip_msg_info->is_request && which == SIP_SERVER_TRANSACTION && 31340cb5e5dSvi117747 (method == ACK || method == CANCEL)) { 31440cb5e5dSvi117747 method = INVITE; 31540cb5e5dSvi117747 } 31640cb5e5dSvi117747 if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0) 31740cb5e5dSvi117747 return (NULL); 31840cb5e5dSvi117747 hindex = SIP_DIGEST_TO_HASH(hash_index); 31940cb5e5dSvi117747 tmp = (sip_xaction_t *)sip_hash_find(sip_xaction_hash, 32040cb5e5dSvi117747 (void *)hash_index, hindex, sip_xaction_match); 32140cb5e5dSvi117747 return (tmp); 32240cb5e5dSvi117747 } 32340cb5e5dSvi117747 32440cb5e5dSvi117747 /* 32540cb5e5dSvi117747 * create a transaction. 32640cb5e5dSvi117747 */ 32740cb5e5dSvi117747 static sip_xaction_t * 32840cb5e5dSvi117747 sip_xaction_create(sip_conn_object_t obj, _sip_msg_t *msg, char *branchid, 32940cb5e5dSvi117747 int *error) 33040cb5e5dSvi117747 { 33140cb5e5dSvi117747 sip_xaction_t *trans; 33240cb5e5dSvi117747 sip_message_type_t *sip_msg_info; 33340cb5e5dSvi117747 int state = 0; 33440cb5e5dSvi117747 int prev_state = 0; 33540cb5e5dSvi117747 sip_method_t method; 33640cb5e5dSvi117747 int ret; 33740cb5e5dSvi117747 int timer1 = sip_timer_T1; 33840cb5e5dSvi117747 int timer4 = sip_timer_T4; 33940cb5e5dSvi117747 int timerd = sip_timer_TD; 34040cb5e5dSvi117747 34140cb5e5dSvi117747 if (error != NULL) 34240cb5e5dSvi117747 *error = 0; 34340cb5e5dSvi117747 /* 34440cb5e5dSvi117747 * Make sure we are not creating a transaction for 34540cb5e5dSvi117747 * an ACK request. 34640cb5e5dSvi117747 */ 34740cb5e5dSvi117747 trans = (sip_xaction_t *)malloc(sizeof (sip_xaction_t)); 34840cb5e5dSvi117747 if (trans == NULL) { 34940cb5e5dSvi117747 if (error != NULL) 35040cb5e5dSvi117747 *error = ENOMEM; 35140cb5e5dSvi117747 return (NULL); 35240cb5e5dSvi117747 } 35340cb5e5dSvi117747 bzero(trans, sizeof (sip_xaction_t)); 35440cb5e5dSvi117747 if (branchid == NULL) { 35540cb5e5dSvi117747 trans->sip_xaction_branch_id = (char *)sip_branchid(NULL); 35640cb5e5dSvi117747 if (trans->sip_xaction_branch_id == NULL) { 35740cb5e5dSvi117747 free(trans); 35840cb5e5dSvi117747 if (error != NULL) 35940cb5e5dSvi117747 *error = ENOMEM; 36040cb5e5dSvi117747 return (NULL); 36140cb5e5dSvi117747 } 36240cb5e5dSvi117747 } else { 36340cb5e5dSvi117747 trans->sip_xaction_branch_id = (char *)malloc(strlen(branchid) 36440cb5e5dSvi117747 + 1); 36540cb5e5dSvi117747 if (trans->sip_xaction_branch_id == NULL) { 36640cb5e5dSvi117747 free(trans); 36740cb5e5dSvi117747 if (error != NULL) 36840cb5e5dSvi117747 *error = ENOMEM; 36940cb5e5dSvi117747 return (NULL); 37040cb5e5dSvi117747 } 37140cb5e5dSvi117747 (void) strncpy(trans->sip_xaction_branch_id, branchid, 37240cb5e5dSvi117747 strlen(branchid)); 37340cb5e5dSvi117747 trans->sip_xaction_branch_id[strlen(branchid)] = '\0'; 37440cb5e5dSvi117747 } 37540cb5e5dSvi117747 (void) pthread_mutex_init(&trans->sip_xaction_mutex, NULL); 37640cb5e5dSvi117747 SIP_MSG_REFCNT_INCR(msg); 37740cb5e5dSvi117747 trans->sip_xaction_orig_msg = msg; 37840cb5e5dSvi117747 assert(msg->sip_msg_req_res != NULL); 37940cb5e5dSvi117747 sip_msg_info = msg->sip_msg_req_res; 38040cb5e5dSvi117747 if (sip_msg_info->is_request) { 38140cb5e5dSvi117747 method = sip_msg_info->sip_req_method; 38240cb5e5dSvi117747 } else { 38340cb5e5dSvi117747 method = sip_get_callseq_method((sip_msg_t)msg, &ret); 38440cb5e5dSvi117747 if (ret != 0) { 38540cb5e5dSvi117747 free(trans->sip_xaction_branch_id); 38640cb5e5dSvi117747 free(trans); 38740cb5e5dSvi117747 if (error != NULL) 38840cb5e5dSvi117747 *error = ret; 38940cb5e5dSvi117747 return (NULL); 39040cb5e5dSvi117747 } 39140cb5e5dSvi117747 if (method == INVITE) 39240cb5e5dSvi117747 state = SIP_SRV_INV_PROCEEDING; 39340cb5e5dSvi117747 else 39440cb5e5dSvi117747 state = SIP_SRV_TRYING; 39540cb5e5dSvi117747 } 39640cb5e5dSvi117747 trans->sip_xaction_method = method; 39740cb5e5dSvi117747 trans->sip_xaction_state = state; 39840cb5e5dSvi117747 39940cb5e5dSvi117747 /* 40040cb5e5dSvi117747 * Get connection object specific timeouts, if present 40140cb5e5dSvi117747 */ 40240cb5e5dSvi117747 if (sip_conn_timer1 != NULL) 40340cb5e5dSvi117747 timer1 = sip_conn_timer1(obj); 40440cb5e5dSvi117747 if (sip_conn_timer4 != NULL) 40540cb5e5dSvi117747 timer4 = sip_conn_timer4(obj); 40640cb5e5dSvi117747 if (sip_conn_timerd != NULL) 40740cb5e5dSvi117747 timerd = sip_conn_timerd(obj); 40840cb5e5dSvi117747 40940cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TA, 2 * timer1); 41040cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TB, 64 * timer1) 41140cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TD, timerd); 41240cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TE, timer1); 41340cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TF, 64 * timer1); 41440cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TG, 2 * timer1); 41540cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TH, 64 * timer1); 41640cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TI, timer4); 41740cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TJ, 64 * timer1); 41840cb5e5dSvi117747 SIP_INIT_TIMER(trans->sip_xaction_TK, timer4); 41940cb5e5dSvi117747 42040cb5e5dSvi117747 if ((ret = sip_xaction_add(trans, branchid, msg, method)) != 0) { 42140cb5e5dSvi117747 (void) pthread_mutex_destroy(&trans->sip_xaction_mutex); 42240cb5e5dSvi117747 free(trans->sip_xaction_branch_id); 42340cb5e5dSvi117747 free(trans); 42440cb5e5dSvi117747 if (error != NULL) 42540cb5e5dSvi117747 *error = ret; 42640cb5e5dSvi117747 return (NULL); 42740cb5e5dSvi117747 } 42840cb5e5dSvi117747 if (sip_xaction_ulp_state_cb != NULL && 42940cb5e5dSvi117747 prev_state != trans->sip_xaction_state) { 43040cb5e5dSvi117747 sip_xaction_ulp_state_cb((sip_transaction_t)trans, 43140cb5e5dSvi117747 (sip_msg_t)msg, prev_state, trans->sip_xaction_state); 43240cb5e5dSvi117747 } 43340cb5e5dSvi117747 return (trans); 43440cb5e5dSvi117747 } 43540cb5e5dSvi117747 43640cb5e5dSvi117747 /* 43740cb5e5dSvi117747 * Find a transaction, create if asked for 43840cb5e5dSvi117747 */ 43940cb5e5dSvi117747 sip_xaction_t * 44040cb5e5dSvi117747 sip_xaction_get(sip_conn_object_t obj, sip_msg_t msg, boolean_t create, 44140cb5e5dSvi117747 int which, int *error) 44240cb5e5dSvi117747 { 44340cb5e5dSvi117747 char *branchid; 44440cb5e5dSvi117747 sip_xaction_t *sip_trans; 44540cb5e5dSvi117747 _sip_msg_t *_msg; 44640cb5e5dSvi117747 sip_message_type_t *sip_msg_info; 44740cb5e5dSvi117747 44840cb5e5dSvi117747 if (error != NULL) 44940cb5e5dSvi117747 *error = 0; 45040cb5e5dSvi117747 45140cb5e5dSvi117747 _msg = (_sip_msg_t *)msg; 45240cb5e5dSvi117747 sip_msg_info = ((_sip_msg_t *)msg)->sip_msg_req_res; 45340cb5e5dSvi117747 45440cb5e5dSvi117747 branchid = sip_get_branchid(msg, NULL); 45540cb5e5dSvi117747 sip_trans = sip_xaction_find(branchid, _msg, which); 45640cb5e5dSvi117747 if (sip_trans == NULL && create) { 45740cb5e5dSvi117747 /* 45840cb5e5dSvi117747 * If we are sending a request, must be conformant to RFC 3261. 45940cb5e5dSvi117747 */ 46040cb5e5dSvi117747 if (sip_msg_info->is_request && 46140cb5e5dSvi117747 (branchid == NULL || strncmp(branchid, 46240cb5e5dSvi117747 RFC_3261_BRANCH, strlen(RFC_3261_BRANCH) != 0))) { 46340cb5e5dSvi117747 if (error != NULL) 46440cb5e5dSvi117747 *error = EINVAL; 46540cb5e5dSvi117747 if (branchid != NULL) 46640cb5e5dSvi117747 free(branchid); 46740cb5e5dSvi117747 return (NULL); 46840cb5e5dSvi117747 } 46940cb5e5dSvi117747 sip_trans = sip_xaction_create(obj, _msg, branchid, error); 47040cb5e5dSvi117747 if (sip_trans != NULL) 47140cb5e5dSvi117747 SIP_XACTION_REFCNT_INCR(sip_trans); 47240cb5e5dSvi117747 } 47340cb5e5dSvi117747 if (branchid != NULL) 47440cb5e5dSvi117747 free(branchid); 47540cb5e5dSvi117747 return (sip_trans); 47640cb5e5dSvi117747 } 47740cb5e5dSvi117747 47840cb5e5dSvi117747 47940cb5e5dSvi117747 /* 48040cb5e5dSvi117747 * Delete a transaction if the reference count is 0. Passed to 48140cb5e5dSvi117747 * sip_hash_delete(). 48240cb5e5dSvi117747 */ 48340cb5e5dSvi117747 boolean_t 48440cb5e5dSvi117747 sip_xaction_remove(void *obj, void *hindex, int *found) 48540cb5e5dSvi117747 { 48640cb5e5dSvi117747 sip_xaction_t *tmp = (sip_xaction_t *)obj; 487*943efbc3Sgm209912 int count = 0; 488*943efbc3Sgm209912 sip_msg_chain_t *msg_chain; 489*943efbc3Sgm209912 sip_msg_chain_t *nmsg_chain; 49040cb5e5dSvi117747 49140cb5e5dSvi117747 *found = 0; 49240cb5e5dSvi117747 tmp = (sip_xaction_t *)obj; 49340cb5e5dSvi117747 (void) pthread_mutex_lock(&tmp->sip_xaction_mutex); 49440cb5e5dSvi117747 if (bcmp(tmp->sip_xaction_hash_digest, hindex, 49540cb5e5dSvi117747 sizeof (tmp->sip_xaction_hash_digest)) == 0) { 49640cb5e5dSvi117747 *found = 1; 49740cb5e5dSvi117747 if (tmp->sip_xaction_ref_cnt != 0) { 49840cb5e5dSvi117747 (void) pthread_mutex_unlock(&tmp->sip_xaction_mutex); 49940cb5e5dSvi117747 return (B_FALSE); 50040cb5e5dSvi117747 } 50140cb5e5dSvi117747 (void) pthread_mutex_destroy(&tmp->sip_xaction_mutex); 50240cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TA); 50340cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TB); 50440cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TD); 50540cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TE); 50640cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TF); 50740cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TG); 50840cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TH); 50940cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TI); 51040cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TJ); 51140cb5e5dSvi117747 SIP_CANCEL_TIMER(tmp->sip_xaction_TK); 512*943efbc3Sgm209912 sip_write_to_log((void *)tmp, SIP_TRANSACTION_LOG, NULL, 0); 51340cb5e5dSvi117747 free(tmp->sip_xaction_branch_id); 51440cb5e5dSvi117747 if (tmp->sip_xaction_last_msg != NULL) { 51540cb5e5dSvi117747 SIP_MSG_REFCNT_DECR(tmp->sip_xaction_last_msg); 51640cb5e5dSvi117747 tmp->sip_xaction_last_msg = NULL; 51740cb5e5dSvi117747 } 51840cb5e5dSvi117747 if (tmp->sip_xaction_orig_msg != NULL) { 51940cb5e5dSvi117747 SIP_MSG_REFCNT_DECR(tmp->sip_xaction_orig_msg); 52040cb5e5dSvi117747 tmp->sip_xaction_orig_msg = NULL; 52140cb5e5dSvi117747 } 52240cb5e5dSvi117747 if (tmp->sip_xaction_conn_obj != NULL) { 52340cb5e5dSvi117747 sip_del_conn_obj_cache(tmp->sip_xaction_conn_obj, 52440cb5e5dSvi117747 (void *)tmp); 52540cb5e5dSvi117747 } 526*943efbc3Sgm209912 /* 527*943efbc3Sgm209912 * If the transaction logging is disabled before we could 528*943efbc3Sgm209912 * write the captured messages into the transaction log, then 529*943efbc3Sgm209912 * we need to free those captured messsages 530*943efbc3Sgm209912 */ 531*943efbc3Sgm209912 for (count = 0; count <= SIP_SRV_NONINV_TERMINATED; count++) { 532*943efbc3Sgm209912 msg_chain = tmp->sip_xaction_log[count].sip_msgs; 533*943efbc3Sgm209912 while (msg_chain != NULL) { 534*943efbc3Sgm209912 nmsg_chain = msg_chain->next; 535*943efbc3Sgm209912 if (msg_chain->sip_msg != NULL) 536*943efbc3Sgm209912 free(msg_chain->sip_msg); 537*943efbc3Sgm209912 free(msg_chain); 538*943efbc3Sgm209912 msg_chain = nmsg_chain; 539*943efbc3Sgm209912 } 540*943efbc3Sgm209912 } 54140cb5e5dSvi117747 free(tmp); 54240cb5e5dSvi117747 return (B_TRUE); 54340cb5e5dSvi117747 } 54440cb5e5dSvi117747 (void) pthread_mutex_unlock(&tmp->sip_xaction_mutex); 54540cb5e5dSvi117747 return (B_FALSE); 54640cb5e5dSvi117747 } 54740cb5e5dSvi117747 54840cb5e5dSvi117747 /* 54940cb5e5dSvi117747 * Delete a SIP transaction 55040cb5e5dSvi117747 */ 55140cb5e5dSvi117747 void 55240cb5e5dSvi117747 sip_xaction_delete(sip_xaction_t *trans) 55340cb5e5dSvi117747 { 55440cb5e5dSvi117747 int hindex; 55540cb5e5dSvi117747 55640cb5e5dSvi117747 (void) pthread_mutex_lock(&trans->sip_xaction_mutex); 55740cb5e5dSvi117747 hindex = SIP_DIGEST_TO_HASH(trans->sip_xaction_hash_digest); 55840cb5e5dSvi117747 if (trans->sip_xaction_ref_cnt != 0) { 55940cb5e5dSvi117747 (void) pthread_mutex_unlock(&trans->sip_xaction_mutex); 56040cb5e5dSvi117747 return; 56140cb5e5dSvi117747 } 56240cb5e5dSvi117747 (void) pthread_mutex_unlock(&trans->sip_xaction_mutex); 56340cb5e5dSvi117747 sip_hash_delete(sip_xaction_hash, trans->sip_xaction_hash_digest, 56440cb5e5dSvi117747 hindex, sip_xaction_remove); 56540cb5e5dSvi117747 } 56640cb5e5dSvi117747 56740cb5e5dSvi117747 /* 56840cb5e5dSvi117747 * Add a SIP transaction into the hash list. 56940cb5e5dSvi117747 */ 57040cb5e5dSvi117747 int 57140cb5e5dSvi117747 sip_xaction_add(sip_xaction_t *trans, char *branchid, _sip_msg_t *msg, 57240cb5e5dSvi117747 sip_method_t method) 57340cb5e5dSvi117747 { 57440cb5e5dSvi117747 uint16_t hash_index[8]; 57540cb5e5dSvi117747 57640cb5e5dSvi117747 if (sip_find_md5_digest(branchid, msg, hash_index, method) != 0) 57740cb5e5dSvi117747 return (EINVAL); 57840cb5e5dSvi117747 57940cb5e5dSvi117747 /* 58040cb5e5dSvi117747 * trans is not in the list as yet, so no need to hold the lock 58140cb5e5dSvi117747 */ 58240cb5e5dSvi117747 bcopy(hash_index, trans->sip_xaction_hash_digest, sizeof (hash_index)); 58340cb5e5dSvi117747 58440cb5e5dSvi117747 if (sip_hash_add(sip_xaction_hash, (void *)trans, 58540cb5e5dSvi117747 SIP_DIGEST_TO_HASH(hash_index)) != 0) { 58640cb5e5dSvi117747 return (ENOMEM); 58740cb5e5dSvi117747 } 58840cb5e5dSvi117747 return (0); 58940cb5e5dSvi117747 } 59040cb5e5dSvi117747 59140cb5e5dSvi117747 59240cb5e5dSvi117747 /* 59340cb5e5dSvi117747 * Given a state, return the string - This is mostly for debug purposes 59440cb5e5dSvi117747 */ 59540cb5e5dSvi117747 char * 59640cb5e5dSvi117747 sip_get_xaction_state(int state) 59740cb5e5dSvi117747 { 59840cb5e5dSvi117747 switch (state) { 599*943efbc3Sgm209912 case SIP_NEW_TRANSACTION: 600*943efbc3Sgm209912 return ("SIP_NEW_TRANSACTION"); 60140cb5e5dSvi117747 case SIP_CLNT_CALLING: 60240cb5e5dSvi117747 return ("SIP_CLNT_CALLING"); 60340cb5e5dSvi117747 case SIP_CLNT_INV_PROCEEDING: 60440cb5e5dSvi117747 return ("SIP_CLNT_INV_PROCEEDING"); 60540cb5e5dSvi117747 case SIP_CLNT_INV_TERMINATED: 60640cb5e5dSvi117747 return ("SIP_CLNT_INV_TERMINATED"); 60740cb5e5dSvi117747 case SIP_CLNT_INV_COMPLETED: 60840cb5e5dSvi117747 return ("SIP_CLNT_INV_COMPLETED"); 60940cb5e5dSvi117747 case SIP_CLNT_TRYING: 61040cb5e5dSvi117747 return ("SIP_CLNT_TRYING"); 61140cb5e5dSvi117747 case SIP_CLNT_NONINV_PROCEEDING: 61240cb5e5dSvi117747 return ("SIP_CLNT_NONINV_PROCEEDING"); 61340cb5e5dSvi117747 case SIP_CLNT_NONINV_TERMINATED: 61440cb5e5dSvi117747 return ("SIP_CLNT_NONINV_TERMINATED"); 61540cb5e5dSvi117747 case SIP_CLNT_NONINV_COMPLETED: 61640cb5e5dSvi117747 return ("SIP_CLNT_NONINV_COMPLETED"); 61740cb5e5dSvi117747 case SIP_SRV_INV_PROCEEDING: 61840cb5e5dSvi117747 return ("SIP_SRV_INV_PROCEEDING"); 61940cb5e5dSvi117747 case SIP_SRV_INV_COMPLETED: 62040cb5e5dSvi117747 return ("SIP_SRV_INV_COMPLETED"); 62140cb5e5dSvi117747 case SIP_SRV_CONFIRMED: 62240cb5e5dSvi117747 return ("SIP_SRV_CONFIRMED"); 62340cb5e5dSvi117747 case SIP_SRV_INV_TERMINATED: 62440cb5e5dSvi117747 return ("SIP_SRV_INV_TERMINATED"); 62540cb5e5dSvi117747 case SIP_SRV_TRYING: 62640cb5e5dSvi117747 return ("SIP_SRV_TRYING"); 62740cb5e5dSvi117747 case SIP_SRV_NONINV_PROCEEDING: 62840cb5e5dSvi117747 return ("SIP_SRV_NONINV_PROCEEDING"); 62940cb5e5dSvi117747 case SIP_SRV_NONINV_COMPLETED: 63040cb5e5dSvi117747 return ("SIP_SRV_NONINV_COMPLETED"); 63140cb5e5dSvi117747 case SIP_SRV_NONINV_TERMINATED: 63240cb5e5dSvi117747 return ("SIP_SRV_NONINV_TERMINATED"); 63340cb5e5dSvi117747 default : 634*943efbc3Sgm209912 return ("UNKNOWN"); 63540cb5e5dSvi117747 } 63640cb5e5dSvi117747 } 63740cb5e5dSvi117747 63840cb5e5dSvi117747 /* 63940cb5e5dSvi117747 * Initialize the hash table etc. 64040cb5e5dSvi117747 */ 64140cb5e5dSvi117747 void 64240cb5e5dSvi117747 sip_xaction_init(int (*ulp_trans_err)(sip_transaction_t, int, void *), 64340cb5e5dSvi117747 void (*ulp_state_cb)(sip_transaction_t, sip_msg_t, int, int)) 64440cb5e5dSvi117747 { 64540cb5e5dSvi117747 int cnt; 64640cb5e5dSvi117747 64740cb5e5dSvi117747 for (cnt = 0; cnt < SIP_HASH_SZ; cnt++) { 64840cb5e5dSvi117747 sip_xaction_hash[cnt].hash_count = 0; 64940cb5e5dSvi117747 sip_xaction_hash[cnt].hash_head = NULL; 65040cb5e5dSvi117747 sip_xaction_hash[cnt].hash_tail = NULL; 65140cb5e5dSvi117747 (void) pthread_mutex_init( 65240cb5e5dSvi117747 &sip_xaction_hash[cnt].sip_hash_mutex, NULL); 65340cb5e5dSvi117747 } 65440cb5e5dSvi117747 if (ulp_trans_err != NULL) 65540cb5e5dSvi117747 sip_xaction_ulp_trans_err = ulp_trans_err; 65640cb5e5dSvi117747 if (ulp_state_cb != NULL) 65740cb5e5dSvi117747 sip_xaction_ulp_state_cb = ulp_state_cb; 65840cb5e5dSvi117747 } 659