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"
39 #include "sip_miscdefs.h"
40 #include "sip_xaction.h"
41 #include "sip_dialog.h"
43 #define TIME_BUF_SIZE 50
46 * Contains API's which enable/disable transaction or dialog logging,
47 * API's which records/measures SIP Traffic.
50 * Needed for measuring SIP traffic counters.
52 sip_traffic_counters_t sip_counters
;
55 * Needed for dialog/transaction logging.
57 sip_logfile_t trans_log
;
58 sip_logfile_t dialog_log
;
61 * This function increments the appropriate inbound/outbound counters for
62 * SIP requests/responses.
65 sip_measure_traffic(boolean_t is_request
, sip_method_t method
, int resp_code
,
66 boolean_t outbound
, int msg_size
)
69 assert(mutex_held(&sip_counters
.sip_counter_mutex
));
72 sip_counters
.sip_total_bytes_sent
+= msg_size
;
74 sip_counters
.sip_total_bytes_rcvd
+= msg_size
;
78 ++sip_counters
.sip_total_req_sent
;
80 ++sip_counters
.sip_total_req_rcvd
;
84 ++sip_counters
.sip_invite_req_sent
;
86 ++sip_counters
.sip_invite_req_rcvd
;
90 ++sip_counters
.sip_ack_req_sent
;
92 ++sip_counters
.sip_ack_req_rcvd
;
96 ++sip_counters
.sip_options_req_sent
;
98 ++sip_counters
.sip_options_req_rcvd
;
102 ++sip_counters
.sip_bye_req_sent
;
104 ++sip_counters
.sip_bye_req_rcvd
;
108 ++sip_counters
.sip_cancel_req_sent
;
110 ++sip_counters
.sip_cancel_req_rcvd
;
114 ++sip_counters
.sip_register_req_sent
;
116 ++sip_counters
.sip_register_req_rcvd
;
120 ++sip_counters
.sip_refer_req_sent
;
122 ++sip_counters
.sip_refer_req_rcvd
;
126 ++sip_counters
.sip_info_req_sent
;
128 ++sip_counters
.sip_info_req_rcvd
;
132 ++sip_counters
.sip_subscribe_req_sent
;
134 ++sip_counters
.sip_subscribe_req_rcvd
;
138 ++sip_counters
.sip_notify_req_sent
;
140 ++sip_counters
.sip_notify_req_rcvd
;
144 ++sip_counters
.sip_prack_req_sent
;
146 ++sip_counters
.sip_prack_req_rcvd
;
153 ++sip_counters
.sip_total_resp_sent
;
155 ++sip_counters
.sip_total_resp_rcvd
;
156 if (SIP_PROVISIONAL_RESP(resp_code
)) {
158 ++sip_counters
.sip_1xx_resp_sent
;
160 ++sip_counters
.sip_1xx_resp_rcvd
;
161 } else if (SIP_OK_RESP(resp_code
)) {
163 ++sip_counters
.sip_2xx_resp_sent
;
165 ++sip_counters
.sip_2xx_resp_rcvd
;
166 } else if (SIP_REDIRECT_RESP(resp_code
)) {
168 ++sip_counters
.sip_3xx_resp_sent
;
170 ++sip_counters
.sip_3xx_resp_rcvd
;
171 } else if (SIP_REQFAIL_RESP(resp_code
)) {
173 ++sip_counters
.sip_4xx_resp_sent
;
175 ++sip_counters
.sip_4xx_resp_rcvd
;
176 } else if (SIP_SRVFAIL_RESP(resp_code
)) {
178 ++sip_counters
.sip_5xx_resp_sent
;
180 ++sip_counters
.sip_5xx_resp_rcvd
;
181 } else if (SIP_GLOBFAIL_RESP(resp_code
)) {
183 ++sip_counters
.sip_6xx_resp_sent
;
185 ++sip_counters
.sip_6xx_resp_rcvd
;
191 * Enables Transaction logging. The flags argument controls the detail
195 sip_enable_trans_logging(FILE *logfile
, int flags
)
197 if (logfile
== NULL
|| flags
!= SIP_DETAIL_LOGGING
)
200 (void) pthread_mutex_lock(&trans_log
.sip_logfile_mutex
);
201 if (!trans_log
.sip_logging_enabled
) {
202 trans_log
.sip_logfile
= logfile
;
203 trans_log
.sip_logging_enabled
= B_TRUE
;
205 (void) pthread_mutex_unlock(&trans_log
.sip_logfile_mutex
);
211 * Enables dialog logging. The flags argument controls the detail
215 sip_enable_dialog_logging(FILE *logfile
, int flags
)
217 if (logfile
== NULL
|| flags
!= SIP_DETAIL_LOGGING
)
220 (void) pthread_mutex_lock(&dialog_log
.sip_logfile_mutex
);
221 if (!dialog_log
.sip_logging_enabled
) {
222 dialog_log
.sip_logfile
= logfile
;
223 dialog_log
.sip_logging_enabled
= B_TRUE
;
225 (void) pthread_mutex_unlock(&dialog_log
.sip_logfile_mutex
);
230 sip_disable_trans_logging()
232 (void) pthread_mutex_lock(&trans_log
.sip_logfile_mutex
);
233 if (trans_log
.sip_logging_enabled
)
234 trans_log
.sip_logging_enabled
= B_FALSE
;
235 (void) pthread_mutex_unlock(&trans_log
.sip_logfile_mutex
);
239 sip_disable_dialog_logging()
241 (void) pthread_mutex_lock(&dialog_log
.sip_logfile_mutex
);
242 if (dialog_log
.sip_logging_enabled
)
243 dialog_log
.sip_logging_enabled
= B_FALSE
;
244 (void) pthread_mutex_unlock(&dialog_log
.sip_logfile_mutex
);
248 sip_print_digest(uint16_t *digest
, int len
, FILE *fp
)
252 for (cnt
= 0; cnt
< len
; cnt
++)
253 (void) fprintf(fp
, "%u ", digest
[cnt
]);
254 (void) fprintf(fp
, "\n\n");
258 * Logs all the messages exchanged within a transaction to the transaction
259 * log file. Logged messages are then freed.
262 sip_write_xaction_to_log(void *obj
)
264 sip_xaction_t
*trans
= (sip_xaction_t
*)obj
;
267 sip_msg_chain_t
*msg_chain
;
268 sip_msg_chain_t
*nmsg_chain
;
269 char timebuf
[TIME_BUF_SIZE
];
271 FILE *sip_trans_logfile
= trans_log
.sip_logfile
;
273 assert(trans
!= NULL
&& sip_trans_logfile
!= NULL
);
274 (void) fprintf(sip_trans_logfile
, "************* Begin Transaction"
276 (void) fprintf(sip_trans_logfile
, "Branchid\t\t: %s\n",
277 trans
->sip_xaction_branch_id
);
278 (void) fprintf(sip_trans_logfile
, "Digest\t\t\t: ");
279 sip_print_digest(trans
->sip_xaction_hash_digest
, 8, sip_trans_logfile
);
280 (void) fprintf(sip_trans_logfile
, "-----------------------------\n");
281 for (count
= 0; count
<= SIP_SRV_NONINV_TERMINATED
; count
++) {
282 sip_log
= &trans
->sip_xaction_log
[count
];
283 if (sip_log
->sip_msgcnt
== 0)
285 (void) fprintf(sip_trans_logfile
, "Transaction State\t: %s\n\n",
286 sip_get_xaction_state(count
));
287 msg_chain
= sip_log
->sip_msgs
;
288 while (msg_chain
!= NULL
) {
289 nmsg_chain
= msg_chain
->next
;
290 (void) strftime(timebuf
, sizeof (timebuf
), NULL
,
291 localtime_r(&msg_chain
->msg_timestamp
, &tms
));
292 (void) fprintf(sip_trans_logfile
, "%s| Message -"
293 " %d\n%s", timebuf
, msg_chain
->msg_seq
, msg_chain
->
295 free(msg_chain
->sip_msg
);
297 --sip_log
->sip_msgcnt
;
298 msg_chain
= nmsg_chain
;
300 (void) fprintf(sip_trans_logfile
,
301 "-----------------------------\n");
302 (trans
->sip_xaction_log
[count
]).sip_msgs
= NULL
;
304 (void) fprintf(sip_trans_logfile
, "************* End Transaction "
306 (void) fflush(sip_trans_logfile
);
310 * Logs all the messages exchanged within a dialog to the dialog
311 * log file. Logged messages are then freed.
314 sip_write_dlg_to_log(void *obj
)
316 _sip_dialog_t
*dialog
= (_sip_dialog_t
*)obj
;
319 sip_msg_chain_t
*msg_chain
;
320 sip_msg_chain_t
*nmsg_chain
;
321 char timebuf
[TIME_BUF_SIZE
];
323 FILE *sip_dialog_logfile
= dialog_log
.sip_logfile
;
325 assert(dialog
!= NULL
&& sip_dialog_logfile
!= NULL
);
327 (void) fprintf(sip_dialog_logfile
, "************* Begin Dialog "
329 (void) fprintf(sip_dialog_logfile
, "Digest\t\t\t: ");
330 sip_print_digest(dialog
->sip_dlg_id
, 8, sip_dialog_logfile
);
331 (void) fprintf(sip_dialog_logfile
, "-----------------------------\n");
332 for (count
= 0; count
<= SIP_DLG_DESTROYED
; count
++) {
333 sip_log
= &dialog
->sip_dlg_log
[count
];
334 if (sip_log
->sip_msgcnt
== 0)
336 (void) fprintf(sip_dialog_logfile
, "Dialog State\t\t: %s\n\n",
337 sip_get_dialog_state_str(count
));
338 msg_chain
= sip_log
->sip_msgs
;
339 while (msg_chain
!= NULL
) {
340 nmsg_chain
= msg_chain
->next
;
341 (void) strftime(timebuf
, sizeof (timebuf
), NULL
,
342 localtime_r(&msg_chain
->msg_timestamp
, &tms
));
343 (void) fprintf(sip_dialog_logfile
, "%s| Message -"
344 " %d\n%s", timebuf
, msg_chain
->msg_seq
, msg_chain
->
346 free(msg_chain
->sip_msg
);
348 --sip_log
->sip_msgcnt
;
349 msg_chain
= nmsg_chain
;
351 (void) fprintf(sip_dialog_logfile
,
352 "-----------------------------\n");
353 (dialog
->sip_dlg_log
[count
]).sip_msgs
= NULL
;
355 (void) fprintf(sip_dialog_logfile
, "************* End Dialog "
357 (void) fflush(sip_dialog_logfile
);
361 * Calls the appropriate function to log transaction or dialog messages.
362 * If this function is called because of assertion failure, then the file and
363 * line where the assertion failed is logged to the log file.
366 sip_write_to_log(void *obj
, int type
, char *file
, int line
)
368 if (type
& SIP_TRANSACTION_LOG
) {
369 (void) pthread_mutex_lock(&trans_log
.sip_logfile_mutex
);
370 if (trans_log
.sip_logging_enabled
) {
371 if (type
& SIP_ASSERT_ERROR
) {
372 (void) fprintf(trans_log
.sip_logfile
,
373 "Assertion Failure at %s:%d\n", file
, line
);
375 sip_write_xaction_to_log(obj
);
377 (void) pthread_mutex_unlock(&trans_log
.sip_logfile_mutex
);
379 (void) pthread_mutex_lock(&dialog_log
.sip_logfile_mutex
);
380 if (dialog_log
.sip_logging_enabled
) {
381 if (type
& SIP_ASSERT_ERROR
) {
382 (void) fprintf(dialog_log
.sip_logfile
,
383 "Assertion Failure at %s:%d\n", file
, line
);
385 sip_write_dlg_to_log(obj
);
387 (void) pthread_mutex_unlock(&dialog_log
.sip_logfile_mutex
);
392 * This function records the messages that are exchanged within a dialog or
393 * transaction. If logging is enabled the recorded messages are then dumped
394 * to the log file just before deleting the transaction or dialog.
397 sip_add_log(sip_log_t
*sip_log
, sip_msg_t sip_msg
, int seq
, int type
)
400 sip_msg_chain_t
*new_msg
;
401 sip_msg_chain_t
*msg_chain
= sip_log
->sip_msgs
;
404 * No need to take any locks here. Caller of this function MUST
405 * have already taken the transaction or dialog lock.
407 if (((type
== SIP_DIALOG_LOG
) && !dialog_log
.sip_logging_enabled
) ||
408 ((type
== SIP_TRANSACTION_LOG
) && !trans_log
.sip_logging_enabled
)) {
412 new_msg
= calloc(1, sizeof (sip_msg_chain_t
));
416 msgstr
= sip_msg_to_str(sip_msg
, NULL
);
417 if (msgstr
== NULL
) {
422 new_msg
->sip_msg
= msgstr
;
423 new_msg
->msg_seq
= seq
;
424 new_msg
->msg_timestamp
= time(NULL
);
425 new_msg
->next
= NULL
;
426 if (sip_log
->sip_msgcnt
== 0) {
427 sip_log
->sip_msgs
= new_msg
;
429 while (msg_chain
->next
!= NULL
)
430 msg_chain
= msg_chain
->next
;
431 msg_chain
->next
= new_msg
;
433 sip_log
->sip_msgcnt
++;
437 * Given a counter group and counter name within the group, returns the value
438 * associated with the counter in 'cntval'.
441 sip_get_counter_value(int group
, int counter
, void *cntval
, size_t cntlen
)
443 if (group
!= SIP_TRAFFIC_COUNTERS
|| cntval
== NULL
)
445 if ((counter
== SIP_COUNTER_START_TIME
|| counter
==
446 SIP_COUNTER_STOP_TIME
) && (cntlen
!= sizeof (time_t))) {
448 } else if (cntlen
!= sizeof (uint64_t)) {
452 (void) pthread_mutex_lock(&sip_counters
.sip_counter_mutex
);
454 case SIP_TOTAL_BYTES_RCVD
:
455 *(uint64_t *)cntval
= sip_counters
.sip_total_bytes_rcvd
;
457 case SIP_TOTAL_BYTES_SENT
:
458 *(uint64_t *)cntval
= sip_counters
.sip_total_bytes_sent
;
460 case SIP_TOTAL_REQ_RCVD
:
461 *(uint64_t *)cntval
= sip_counters
.sip_total_req_rcvd
;
463 case SIP_TOTAL_REQ_SENT
:
464 *(uint64_t *)cntval
= sip_counters
.sip_total_req_sent
;
466 case SIP_TOTAL_RESP_RCVD
:
467 *(uint64_t *)cntval
= sip_counters
.sip_total_resp_rcvd
;
469 case SIP_TOTAL_RESP_SENT
:
470 *(uint64_t *)cntval
= sip_counters
.sip_total_resp_sent
;
472 case SIP_ACK_REQ_RCVD
:
473 *(uint64_t *)cntval
= sip_counters
.sip_ack_req_rcvd
;
475 case SIP_ACK_REQ_SENT
:
476 *(uint64_t *)cntval
= sip_counters
.sip_ack_req_sent
;
478 case SIP_BYE_REQ_RCVD
:
479 *(uint64_t *)cntval
= sip_counters
.sip_bye_req_rcvd
;
481 case SIP_BYE_REQ_SENT
:
482 *(uint64_t *)cntval
= sip_counters
.sip_bye_req_sent
;
484 case SIP_CANCEL_REQ_RCVD
:
485 *(uint64_t *)cntval
= sip_counters
.sip_cancel_req_rcvd
;
487 case SIP_CANCEL_REQ_SENT
:
488 *(uint64_t *)cntval
= sip_counters
.sip_cancel_req_sent
;
490 case SIP_INFO_REQ_RCVD
:
491 *(uint64_t *)cntval
= sip_counters
.sip_info_req_rcvd
;
493 case SIP_INFO_REQ_SENT
:
494 *(uint64_t *)cntval
= sip_counters
.sip_info_req_sent
;
496 case SIP_INVITE_REQ_RCVD
:
497 *(uint64_t *)cntval
= sip_counters
.sip_invite_req_rcvd
;
499 case SIP_INVITE_REQ_SENT
:
500 *(uint64_t *)cntval
= sip_counters
.sip_invite_req_sent
;
502 case SIP_NOTIFY_REQ_RCVD
:
503 *(uint64_t *)cntval
= sip_counters
.sip_notify_req_rcvd
;
505 case SIP_NOTIFY_REQ_SENT
:
506 *(uint64_t *)cntval
= sip_counters
.sip_notify_req_sent
;
508 case SIP_OPTIONS_REQ_RCVD
:
509 *(uint64_t *)cntval
= sip_counters
.sip_options_req_rcvd
;
511 case SIP_OPTIONS_REQ_SENT
:
512 *(uint64_t *)cntval
= sip_counters
.sip_options_req_sent
;
514 case SIP_PRACK_REQ_RCVD
:
515 *(uint64_t *)cntval
= sip_counters
.sip_prack_req_rcvd
;
517 case SIP_PRACK_REQ_SENT
:
518 *(uint64_t *)cntval
= sip_counters
.sip_prack_req_sent
;
520 case SIP_REFER_REQ_RCVD
:
521 *(uint64_t *)cntval
= sip_counters
.sip_refer_req_rcvd
;
523 case SIP_REFER_REQ_SENT
:
524 *(uint64_t *)cntval
= sip_counters
.sip_refer_req_sent
;
526 case SIP_REGISTER_REQ_RCVD
:
527 *(uint64_t *)cntval
= sip_counters
.
528 sip_register_req_rcvd
;
530 case SIP_REGISTER_REQ_SENT
:
531 *(uint64_t *)cntval
= sip_counters
.
532 sip_register_req_sent
;
534 case SIP_SUBSCRIBE_REQ_RCVD
:
535 *(uint64_t *)cntval
= sip_counters
.
536 sip_subscribe_req_rcvd
;
538 case SIP_SUBSCRIBE_REQ_SENT
:
539 *(uint64_t *)cntval
= sip_counters
.
540 sip_subscribe_req_sent
;
542 case SIP_UPDATE_REQ_RCVD
:
543 *(uint64_t *)cntval
= sip_counters
.sip_update_req_rcvd
;
545 case SIP_UPDATE_REQ_SENT
:
546 *(uint64_t *)cntval
= sip_counters
.sip_update_req_sent
;
548 case SIP_1XX_RESP_RCVD
:
549 *(uint64_t *)cntval
= sip_counters
.sip_1xx_resp_rcvd
;
551 case SIP_1XX_RESP_SENT
:
552 *(uint64_t *)cntval
= sip_counters
.sip_1xx_resp_sent
;
554 case SIP_2XX_RESP_RCVD
:
555 *(uint64_t *)cntval
= sip_counters
.sip_2xx_resp_rcvd
;
557 case SIP_2XX_RESP_SENT
:
558 *(uint64_t *)cntval
= sip_counters
.sip_2xx_resp_sent
;
560 case SIP_3XX_RESP_RCVD
:
561 *(uint64_t *)cntval
= sip_counters
.sip_3xx_resp_rcvd
;
563 case SIP_3XX_RESP_SENT
:
564 *(uint64_t *)cntval
= sip_counters
.sip_3xx_resp_sent
;
566 case SIP_4XX_RESP_RCVD
:
567 *(uint64_t *)cntval
= sip_counters
.sip_4xx_resp_rcvd
;
569 case SIP_4XX_RESP_SENT
:
570 *(uint64_t *)cntval
= sip_counters
.sip_4xx_resp_sent
;
572 case SIP_5XX_RESP_RCVD
:
573 *(uint64_t *)cntval
= sip_counters
.sip_5xx_resp_rcvd
;
575 case SIP_5XX_RESP_SENT
:
576 *(uint64_t *)cntval
= sip_counters
.sip_5xx_resp_sent
;
578 case SIP_6XX_RESP_RCVD
:
579 *(uint64_t *)cntval
= sip_counters
.sip_6xx_resp_rcvd
;
581 case SIP_6xx_RESP_SENT
:
582 *(uint64_t *)cntval
= sip_counters
.sip_6xx_resp_sent
;
584 case SIP_COUNTER_START_TIME
:
585 *(time_t *)cntval
= sip_counters
.starttime
;
587 case SIP_COUNTER_STOP_TIME
:
588 *(time_t *)cntval
= sip_counters
.stoptime
;
591 (void) pthread_mutex_unlock(&sip_counters
.
595 (void) pthread_mutex_unlock(&sip_counters
.sip_counter_mutex
);
600 * Enables the SIP performance/traffic counting. Also reset's the previous
601 * counter values and starts counting afresh.
604 sip_enable_counters(int group
)
606 if (group
!= SIP_TRAFFIC_COUNTERS
)
608 (void) pthread_mutex_lock(&sip_counters
.sip_counter_mutex
);
609 /* If it's not enabled, enable it and capture the start time */
610 if (!sip_counters
.enabled
) {
611 /* zero all the counters except for the mutex at the end */
612 (void) bzero(&sip_counters
, sizeof (sip_traffic_counters_t
) -
613 sizeof (pthread_mutex_t
));
614 sip_counters
.enabled
= B_TRUE
;
615 sip_counters
.starttime
= time(NULL
);
616 sip_counters
.stoptime
= 0;
618 (void) pthread_mutex_unlock(&sip_counters
.sip_counter_mutex
);
623 * Disables the SIP performance/traffic counting. If already disabled it just
624 * exits without doing anyting. It records the stop time.
627 sip_disable_counters(int group
)
629 if (group
!= SIP_TRAFFIC_COUNTERS
)
631 (void) pthread_mutex_lock(&sip_counters
.sip_counter_mutex
);
632 if (sip_counters
.enabled
) {
633 sip_counters
.enabled
= B_FALSE
;
634 sip_counters
.stoptime
= time(NULL
);
636 (void) pthread_mutex_unlock(&sip_counters
.sip_counter_mutex
);