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
sip_find_md5_digest(char * bid,_sip_msg_t * msg,uint16_t * hindex,sip_method_t method)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
sip_add_conn_obj_cache(sip_conn_object_t obj,void * cobj)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
sip_is_conn_obj_cache(sip_conn_object_t obj,void * cobj)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
sip_del_conn_obj_cache(sip_conn_object_t obj,void * cobj)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
sip_xaction_match(void * obj,void * hindex)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 *
sip_xaction_find(char * branchid,_sip_msg_t * msg,int which)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 *
sip_xaction_create(sip_conn_object_t obj,_sip_msg_t * msg,char * branchid,int * error)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 *
sip_xaction_get(sip_conn_object_t obj,sip_msg_t msg,boolean_t create,int which,int * error)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
sip_xaction_remove(void * obj,void * hindex,int * found)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
sip_xaction_delete(sip_xaction_t * trans)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
sip_xaction_add(sip_xaction_t * trans,char * branchid,_sip_msg_t * msg,sip_method_t method)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 *
sip_get_xaction_state(int state)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
sip_xaction_init(int (* ulp_trans_err)(sip_transaction_t,int,void *),void (* ulp_state_cb)(sip_transaction_t,sip_msg_t,int,int))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