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