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