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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
35 #include "sip_parse_uri.h"
37 #include "sip_miscdefs.h"
38 #include "sip_xaction.h"
41 #define RFC_3261_BRANCH "z9hG4bK"
44 * The transaction hash table
46 sip_hash_t sip_xaction_hash
[SIP_HASH_SZ
];
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
;
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 *);
55 * Get the md5 hash of the required fields
58 sip_find_md5_digest(char *bid
, _sip_msg_t
*msg
, uint16_t *hindex
,
63 is_2543
= (bid
== NULL
||
64 strncmp(bid
, RFC_3261_BRANCH
, strlen(RFC_3261_BRANCH
)) != 0);
66 if (is_2543
&& msg
== NULL
)
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
;
77 * Since the response might contain parameters not in the
78 * request, just use the to URI.
80 to_uri
= sip_get_to_uri_str((sip_msg_t
)msg
, &error
);
81 if (to_uri
== NULL
|| error
!= 0)
83 cseq
= sip_get_callseq_num((sip_msg_t
)msg
, &error
);
84 if (cseq
< 0 || error
!= 0)
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
)
93 sip_md5_hash(via
->sip_hdr_start
,
94 via
->sip_hdr_end
- via
->sip_hdr_start
,
96 cid
->sip_hdr_end
- cid
->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
,
104 sip_md5_hash(bid
, strlen(bid
), (char *)&method
,
105 sizeof (sip_method_t
), NULL
, 0, NULL
, 0, NULL
, 0, NULL
, 0,
112 * Add object to the connection cache object. Not checking for duplicates!!
115 sip_add_conn_obj_cache(sip_conn_object_t obj
, void *cobj
)
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
;
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
)) {
131 * Transaction has cached a different conn_obj, release it
133 sip_del_conn_obj_cache(sip_trans
->sip_xaction_conn_obj
,
137 xaction_list
= malloc(sizeof (sip_conn_cache_t
));
138 if (xaction_list
== NULL
)
140 xaction_list
->obj
= cobj
;
141 xaction_list
->next
= xaction_list
->prev
= NULL
;
143 obj_val
= (void *)obj
;
144 pvt_data
= (sip_conn_obj_pvt_t
*)*obj_val
;
145 if (pvt_data
== NULL
) {
149 (void) pthread_mutex_lock(&pvt_data
->sip_conn_obj_cache_lock
);
151 if (pvt_data
->sip_conn_obj_cache
== NULL
) {
152 pvt_data
->sip_conn_obj_cache
= xaction_list
;
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
;
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
);
165 * Walk thru the list of transactions that have cached this obj and
166 * and return true if 'cobj' is one of them.
169 sip_is_conn_obj_cache(sip_conn_object_t obj
, void *cobj
)
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
;
177 obj_val
= (void *)obj
;
178 pvt_data
= (sip_conn_obj_pvt_t
*)*obj_val
;
179 if (pvt_data
== NULL
)
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
;
189 (void) pthread_mutex_unlock(&pvt_data
->sip_conn_obj_cache_lock
);
192 (void) pthread_mutex_unlock(&pvt_data
->sip_conn_obj_cache_lock
);
198 * Walk thru the list of transactions that have cached this obj and
202 sip_del_conn_obj_cache(sip_conn_object_t obj
, void *cobj
)
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
;
212 ctrans
= (sip_xaction_t
*)cobj
;
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
;
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
;
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
;
239 (void) pthread_mutex_unlock(&trans
->sip_xaction_mutex
);
240 xaction_list
= xaction_list
->next
;
243 * Take the obj out of the list
245 if (tmp_list
== pvt_data
->sip_conn_obj_cache
) {
246 if (xaction_list
== NULL
) {
247 pvt_data
->sip_conn_obj_cache
= NULL
;
249 xaction_list
->prev
= NULL
;
250 pvt_data
->sip_conn_obj_cache
= xaction_list
;
252 } else if (xaction_list
== NULL
) {
253 assert(tmp_list
->prev
!= NULL
);
254 tmp_list
->prev
->next
= NULL
;
256 assert(tmp_list
->prev
!= NULL
);
257 tmp_list
->prev
->next
= xaction_list
;
258 xaction_list
->prev
= tmp_list
->prev
;
260 tmp_list
->prev
= NULL
;
261 tmp_list
->next
= NULL
;
262 tmp_list
->obj
= NULL
;
266 (void) pthread_mutex_unlock(&pvt_data
->sip_conn_obj_cache_lock
);
270 * Check for a transaction match. Passed to sip_hash_find().
273 sip_xaction_match(void *obj
, void *hindex
)
275 sip_xaction_t
*tmp
= (sip_xaction_t
*)obj
;
277 tmp
= (sip_xaction_t
*)obj
;
279 if (SIP_IS_XACTION_TERMINATED(tmp
->sip_xaction_state
))
281 if (bcmp(tmp
->sip_xaction_hash_digest
, hindex
,
282 sizeof (tmp
->sip_xaction_hash_digest
)) == 0) {
283 SIP_XACTION_REFCNT_INCR(tmp
);
293 static sip_xaction_t
*
294 sip_xaction_find(char *branchid
, _sip_msg_t
*msg
, int which
)
297 uint16_t hash_index
[8];
301 sip_message_type_t
*sip_msg_info
;
303 sip_msg_info
= msg
->sip_msg_req_res
;
304 method
= sip_get_callseq_method((sip_msg_t
)msg
, &error
);
309 * If we are getting a ACK/CANCEL we need to match with the
310 * corresponding INVITE, if any.
312 if (sip_msg_info
->is_request
&& which
== SIP_SERVER_TRANSACTION
&&
313 (method
== ACK
|| method
== CANCEL
)) {
316 if (sip_find_md5_digest(branchid
, msg
, hash_index
, method
) != 0)
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
);
325 * create a transaction.
327 static sip_xaction_t
*
328 sip_xaction_create(sip_conn_object_t obj
, _sip_msg_t
*msg
, char *branchid
,
331 sip_xaction_t
*trans
;
332 sip_message_type_t
*sip_msg_info
;
337 int timer1
= sip_timer_T1
;
338 int timer4
= sip_timer_T4
;
339 int timerd
= sip_timer_TD
;
344 * Make sure we are not creating a transaction for
347 trans
= (sip_xaction_t
*)malloc(sizeof (sip_xaction_t
));
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
) {
363 trans
->sip_xaction_branch_id
= (char *)malloc(strlen(branchid
)
365 if (trans
->sip_xaction_branch_id
== NULL
) {
371 (void) strncpy(trans
->sip_xaction_branch_id
, branchid
,
373 trans
->sip_xaction_branch_id
[strlen(branchid
)] = '\0';
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
;
383 method
= sip_get_callseq_method((sip_msg_t
)msg
, &ret
);
385 free(trans
->sip_xaction_branch_id
);
391 if (method
== INVITE
)
392 state
= SIP_SRV_INV_PROCEEDING
;
394 state
= SIP_SRV_TRYING
;
396 trans
->sip_xaction_method
= method
;
397 trans
->sip_xaction_state
= state
;
400 * Get connection object specific timeouts, if present
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
);
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
);
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
);
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
);
437 * Find a transaction, create if asked for
440 sip_xaction_get(sip_conn_object_t obj
, sip_msg_t msg
, boolean_t create
,
441 int which
, int *error
)
444 sip_xaction_t
*sip_trans
;
446 sip_message_type_t
*sip_msg_info
;
451 _msg
= (_sip_msg_t
*)msg
;
452 sip_msg_info
= ((_sip_msg_t
*)msg
)->sip_msg_req_res
;
454 branchid
= sip_get_branchid(msg
, NULL
);
455 sip_trans
= sip_xaction_find(branchid
, _msg
, which
);
456 if (sip_trans
== NULL
&& create
) {
458 * If we are sending a request, must be conformant to RFC 3261.
460 if (sip_msg_info
->is_request
&&
461 (branchid
== NULL
|| strncmp(branchid
,
462 RFC_3261_BRANCH
, strlen(RFC_3261_BRANCH
) != 0))) {
465 if (branchid
!= NULL
)
469 sip_trans
= sip_xaction_create(obj
, _msg
, branchid
, error
);
470 if (sip_trans
!= NULL
)
471 SIP_XACTION_REFCNT_INCR(sip_trans
);
473 if (branchid
!= NULL
)
480 * Delete a transaction if the reference count is 0. Passed to
484 sip_xaction_remove(void *obj
, void *hindex
, int *found
)
486 sip_xaction_t
*tmp
= (sip_xaction_t
*)obj
;
488 sip_msg_chain_t
*msg_chain
;
489 sip_msg_chain_t
*nmsg_chain
;
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) {
497 if (tmp
->sip_xaction_ref_cnt
!= 0) {
498 (void) pthread_mutex_unlock(&tmp
->sip_xaction_mutex
);
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
;
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
;
522 if (tmp
->sip_xaction_conn_obj
!= NULL
) {
523 sip_del_conn_obj_cache(tmp
->sip_xaction_conn_obj
,
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
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
);
538 msg_chain
= nmsg_chain
;
544 (void) pthread_mutex_unlock(&tmp
->sip_xaction_mutex
);
549 * Delete a SIP transaction
552 sip_xaction_delete(sip_xaction_t
*trans
)
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
);
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
);
568 * Add a SIP transaction into the hash list.
571 sip_xaction_add(sip_xaction_t
*trans
, char *branchid
, _sip_msg_t
*msg
,
574 uint16_t hash_index
[8];
576 if (sip_find_md5_digest(branchid
, msg
, hash_index
, method
) != 0)
580 * trans is not in the list as yet, so no need to hold the lock
582 bcopy(hash_index
, trans
->sip_xaction_hash_digest
, sizeof (hash_index
));
584 if (sip_hash_add(sip_xaction_hash
, (void *)trans
,
585 SIP_DIGEST_TO_HASH(hash_index
)) != 0) {
593 * Given a state, return the string - This is mostly for debug purposes
596 sip_get_xaction_state(int 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");
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");
639 * Initialize the hash table etc.
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))
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
);
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
;