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 <stdio.h>
28 #include <string.h>
29 #include <strings.h>
30 #include <stdlib.h>
31 #include <assert.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <sip.h>
35
36 #include "sip_msg.h"
37 #include "sip_miscdefs.h"
38 #include "sip_xaction.h"
39 #include "sip_dialog.h"
40
41 #define TIME_BUF_SIZE 50
42
43 /*
44 * Contains API's which enable/disable transaction or dialog logging,
45 * API's which records/measures SIP Traffic.
46 */
47 /*
48 * Needed for measuring SIP traffic counters.
49 */
50 sip_traffic_counters_t sip_counters;
51
52 /*
53 * Needed for dialog/transaction logging.
54 */
55 sip_logfile_t trans_log;
56 sip_logfile_t dialog_log;
57
58 /*
59 * This function increments the appropriate inbound/outbound counters for
60 * SIP requests/responses.
61 */
62 void
sip_measure_traffic(boolean_t is_request,sip_method_t method,int resp_code,boolean_t outbound,int msg_size)63 sip_measure_traffic(boolean_t is_request, sip_method_t method, int resp_code,
64 boolean_t outbound, int msg_size)
65 {
66 #ifdef __solaris__
67 assert(mutex_held(&sip_counters.sip_counter_mutex));
68 #endif
69 if (outbound)
70 sip_counters.sip_total_bytes_sent += msg_size;
71 else
72 sip_counters.sip_total_bytes_rcvd += msg_size;
73
74 if (is_request) {
75 if (outbound)
76 ++sip_counters.sip_total_req_sent;
77 else
78 ++sip_counters.sip_total_req_rcvd;
79 switch (method) {
80 case INVITE:
81 if (outbound)
82 ++sip_counters.sip_invite_req_sent;
83 else
84 ++sip_counters.sip_invite_req_rcvd;
85 break;
86 case ACK:
87 if (outbound)
88 ++sip_counters.sip_ack_req_sent;
89 else
90 ++sip_counters.sip_ack_req_rcvd;
91 break;
92 case OPTIONS:
93 if (outbound)
94 ++sip_counters.sip_options_req_sent;
95 else
96 ++sip_counters.sip_options_req_rcvd;
97 break;
98 case BYE:
99 if (outbound)
100 ++sip_counters.sip_bye_req_sent;
101 else
102 ++sip_counters.sip_bye_req_rcvd;
103 break;
104 case CANCEL:
105 if (outbound)
106 ++sip_counters.sip_cancel_req_sent;
107 else
108 ++sip_counters.sip_cancel_req_rcvd;
109 break;
110 case REGISTER:
111 if (outbound)
112 ++sip_counters.sip_register_req_sent;
113 else
114 ++sip_counters.sip_register_req_rcvd;
115 break;
116 case REFER:
117 if (outbound)
118 ++sip_counters.sip_refer_req_sent;
119 else
120 ++sip_counters.sip_refer_req_rcvd;
121 break;
122 case INFO:
123 if (outbound)
124 ++sip_counters.sip_info_req_sent;
125 else
126 ++sip_counters.sip_info_req_rcvd;
127 break;
128 case SUBSCRIBE:
129 if (outbound)
130 ++sip_counters.sip_subscribe_req_sent;
131 else
132 ++sip_counters.sip_subscribe_req_rcvd;
133 break;
134 case NOTIFY:
135 if (outbound)
136 ++sip_counters.sip_notify_req_sent;
137 else
138 ++sip_counters.sip_notify_req_rcvd;
139 break;
140 case PRACK:
141 if (outbound)
142 ++sip_counters.sip_prack_req_sent;
143 else
144 ++sip_counters.sip_prack_req_rcvd;
145 break;
146 default:
147 break;
148 }
149 } else {
150 if (outbound)
151 ++sip_counters.sip_total_resp_sent;
152 else
153 ++sip_counters.sip_total_resp_rcvd;
154 if (SIP_PROVISIONAL_RESP(resp_code)) {
155 if (outbound)
156 ++sip_counters.sip_1xx_resp_sent;
157 else
158 ++sip_counters.sip_1xx_resp_rcvd;
159 } else if (SIP_OK_RESP(resp_code)) {
160 if (outbound)
161 ++sip_counters.sip_2xx_resp_sent;
162 else
163 ++sip_counters.sip_2xx_resp_rcvd;
164 } else if (SIP_REDIRECT_RESP(resp_code)) {
165 if (outbound)
166 ++sip_counters.sip_3xx_resp_sent;
167 else
168 ++sip_counters.sip_3xx_resp_rcvd;
169 } else if (SIP_REQFAIL_RESP(resp_code)) {
170 if (outbound)
171 ++sip_counters.sip_4xx_resp_sent;
172 else
173 ++sip_counters.sip_4xx_resp_rcvd;
174 } else if (SIP_SRVFAIL_RESP(resp_code)) {
175 if (outbound)
176 ++sip_counters.sip_5xx_resp_sent;
177 else
178 ++sip_counters.sip_5xx_resp_rcvd;
179 } else if (SIP_GLOBFAIL_RESP(resp_code)) {
180 if (outbound)
181 ++sip_counters.sip_6xx_resp_sent;
182 else
183 ++sip_counters.sip_6xx_resp_rcvd;
184 }
185 }
186 }
187
188 /*
189 * Enables Transaction logging. The flags argument controls the detail
190 * of logging.
191 */
192 int
sip_enable_trans_logging(FILE * logfile,int flags)193 sip_enable_trans_logging(FILE *logfile, int flags)
194 {
195 if (logfile == NULL || flags != SIP_DETAIL_LOGGING)
196 return (EINVAL);
197
198 (void) pthread_mutex_lock(&trans_log.sip_logfile_mutex);
199 if (!trans_log.sip_logging_enabled) {
200 trans_log.sip_logfile = logfile;
201 trans_log.sip_logging_enabled = B_TRUE;
202 }
203 (void) pthread_mutex_unlock(&trans_log.sip_logfile_mutex);
204 return (0);
205 }
206
207
208 /*
209 * Enables dialog logging. The flags argument controls the detail
210 * of logging.
211 */
212 int
sip_enable_dialog_logging(FILE * logfile,int flags)213 sip_enable_dialog_logging(FILE *logfile, int flags)
214 {
215 if (logfile == NULL || flags != SIP_DETAIL_LOGGING)
216 return (EINVAL);
217
218 (void) pthread_mutex_lock(&dialog_log.sip_logfile_mutex);
219 if (!dialog_log.sip_logging_enabled) {
220 dialog_log.sip_logfile = logfile;
221 dialog_log.sip_logging_enabled = B_TRUE;
222 }
223 (void) pthread_mutex_unlock(&dialog_log.sip_logfile_mutex);
224 return (0);
225 }
226
227 void
sip_disable_trans_logging()228 sip_disable_trans_logging()
229 {
230 (void) pthread_mutex_lock(&trans_log.sip_logfile_mutex);
231 if (trans_log.sip_logging_enabled)
232 trans_log.sip_logging_enabled = B_FALSE;
233 (void) pthread_mutex_unlock(&trans_log.sip_logfile_mutex);
234 }
235
236 void
sip_disable_dialog_logging()237 sip_disable_dialog_logging()
238 {
239 (void) pthread_mutex_lock(&dialog_log.sip_logfile_mutex);
240 if (dialog_log.sip_logging_enabled)
241 dialog_log.sip_logging_enabled = B_FALSE;
242 (void) pthread_mutex_unlock(&dialog_log.sip_logfile_mutex);
243 }
244
245 static void
sip_print_digest(uint16_t * digest,int len,FILE * fp)246 sip_print_digest(uint16_t *digest, int len, FILE *fp)
247 {
248 int cnt;
249
250 for (cnt = 0; cnt < len; cnt++)
251 (void) fprintf(fp, "%u ", digest[cnt]);
252 (void) fprintf(fp, "\n\n");
253 }
254
255 /*
256 * Logs all the messages exchanged within a transaction to the transaction
257 * log file. Logged messages are then freed.
258 */
259 static void
sip_write_xaction_to_log(void * obj)260 sip_write_xaction_to_log(void *obj)
261 {
262 sip_xaction_t *trans = (sip_xaction_t *)obj;
263 sip_log_t *sip_log;
264 int count;
265 sip_msg_chain_t *msg_chain;
266 sip_msg_chain_t *nmsg_chain;
267 char timebuf[TIME_BUF_SIZE];
268 struct tm tms;
269 FILE *sip_trans_logfile = trans_log.sip_logfile;
270
271 assert(trans != NULL && sip_trans_logfile != NULL);
272 (void) fprintf(sip_trans_logfile, "************* Begin Transaction"
273 " *************\n");
274 (void) fprintf(sip_trans_logfile, "Branchid\t\t: %s\n",
275 trans->sip_xaction_branch_id);
276 (void) fprintf(sip_trans_logfile, "Digest\t\t\t: ");
277 sip_print_digest(trans->sip_xaction_hash_digest, 8, sip_trans_logfile);
278 (void) fprintf(sip_trans_logfile, "-----------------------------\n");
279 for (count = 0; count <= SIP_SRV_NONINV_TERMINATED; count++) {
280 sip_log = &trans->sip_xaction_log[count];
281 if (sip_log->sip_msgcnt == 0)
282 continue;
283 (void) fprintf(sip_trans_logfile, "Transaction State\t: %s\n\n",
284 sip_get_xaction_state(count));
285 msg_chain = sip_log->sip_msgs;
286 while (msg_chain != NULL) {
287 nmsg_chain = msg_chain->next;
288 (void) strftime(timebuf, sizeof (timebuf), NULL,
289 localtime_r(&msg_chain->msg_timestamp, &tms));
290 (void) fprintf(sip_trans_logfile, "%s| Message -"
291 " %d\n%s", timebuf, msg_chain->msg_seq, msg_chain->
292 sip_msg);
293 free(msg_chain->sip_msg);
294 free(msg_chain);
295 --sip_log->sip_msgcnt;
296 msg_chain = nmsg_chain;
297 }
298 (void) fprintf(sip_trans_logfile,
299 "-----------------------------\n");
300 (trans->sip_xaction_log[count]).sip_msgs = NULL;
301 }
302 (void) fprintf(sip_trans_logfile, "************* End Transaction "
303 "*************\n");
304 (void) fflush(sip_trans_logfile);
305 }
306
307 /*
308 * Logs all the messages exchanged within a dialog to the dialog
309 * log file. Logged messages are then freed.
310 */
311 static void
sip_write_dlg_to_log(void * obj)312 sip_write_dlg_to_log(void *obj)
313 {
314 _sip_dialog_t *dialog = (_sip_dialog_t *)obj;
315 sip_log_t *sip_log;
316 int count;
317 sip_msg_chain_t *msg_chain;
318 sip_msg_chain_t *nmsg_chain;
319 char timebuf[TIME_BUF_SIZE];
320 struct tm tms;
321 FILE *sip_dialog_logfile = dialog_log.sip_logfile;
322
323 assert(dialog != NULL && sip_dialog_logfile != NULL);
324
325 (void) fprintf(sip_dialog_logfile, "************* Begin Dialog "
326 "*************\n");
327 (void) fprintf(sip_dialog_logfile, "Digest\t\t\t: ");
328 sip_print_digest(dialog->sip_dlg_id, 8, sip_dialog_logfile);
329 (void) fprintf(sip_dialog_logfile, "-----------------------------\n");
330 for (count = 0; count <= SIP_DLG_DESTROYED; count++) {
331 sip_log = &dialog->sip_dlg_log[count];
332 if (sip_log->sip_msgcnt == 0)
333 continue;
334 (void) fprintf(sip_dialog_logfile, "Dialog State\t\t: %s\n\n",
335 sip_get_dialog_state_str(count));
336 msg_chain = sip_log->sip_msgs;
337 while (msg_chain != NULL) {
338 nmsg_chain = msg_chain->next;
339 (void) strftime(timebuf, sizeof (timebuf), NULL,
340 localtime_r(&msg_chain->msg_timestamp, &tms));
341 (void) fprintf(sip_dialog_logfile, "%s| Message -"
342 " %d\n%s", timebuf, msg_chain->msg_seq, msg_chain->
343 sip_msg);
344 free(msg_chain->sip_msg);
345 free(msg_chain);
346 --sip_log->sip_msgcnt;
347 msg_chain = nmsg_chain;
348 }
349 (void) fprintf(sip_dialog_logfile,
350 "-----------------------------\n");
351 (dialog->sip_dlg_log[count]).sip_msgs = NULL;
352 }
353 (void) fprintf(sip_dialog_logfile, "************* End Dialog "
354 "*************\n");
355 (void) fflush(sip_dialog_logfile);
356 }
357
358 /*
359 * Calls the appropriate function to log transaction or dialog messages.
360 * If this function is called because of assertion failure, then the file and
361 * line where the assertion failed is logged to the log file.
362 */
363 void
sip_write_to_log(void * obj,int type,char * file,int line)364 sip_write_to_log(void *obj, int type, char *file, int line)
365 {
366 if (type & SIP_TRANSACTION_LOG) {
367 (void) pthread_mutex_lock(&trans_log.sip_logfile_mutex);
368 if (trans_log.sip_logging_enabled) {
369 if (type & SIP_ASSERT_ERROR) {
370 (void) fprintf(trans_log.sip_logfile,
371 "Assertion Failure at %s:%d\n", file, line);
372 }
373 sip_write_xaction_to_log(obj);
374 }
375 (void) pthread_mutex_unlock(&trans_log.sip_logfile_mutex);
376 } else {
377 (void) pthread_mutex_lock(&dialog_log.sip_logfile_mutex);
378 if (dialog_log.sip_logging_enabled) {
379 if (type & SIP_ASSERT_ERROR) {
380 (void) fprintf(dialog_log.sip_logfile,
381 "Assertion Failure at %s:%d\n", file, line);
382 }
383 sip_write_dlg_to_log(obj);
384 }
385 (void) pthread_mutex_unlock(&dialog_log.sip_logfile_mutex);
386 }
387 }
388
389 /*
390 * This function records the messages that are exchanged within a dialog or
391 * transaction. If logging is enabled the recorded messages are then dumped
392 * to the log file just before deleting the transaction or dialog.
393 */
394 void
sip_add_log(sip_log_t * sip_log,sip_msg_t sip_msg,int seq,int type)395 sip_add_log(sip_log_t *sip_log, sip_msg_t sip_msg, int seq, int type)
396 {
397 char *msgstr;
398 sip_msg_chain_t *new_msg;
399 sip_msg_chain_t *msg_chain = sip_log->sip_msgs;
400
401 /*
402 * No need to take any locks here. Caller of this function MUST
403 * have already taken the transaction or dialog lock.
404 */
405 if (((type == SIP_DIALOG_LOG) && !dialog_log.sip_logging_enabled) ||
406 ((type == SIP_TRANSACTION_LOG) && !trans_log.sip_logging_enabled)) {
407 return;
408 }
409
410 new_msg = calloc(1, sizeof (sip_msg_chain_t));
411 if (new_msg == NULL)
412 return;
413
414 msgstr = sip_msg_to_str(sip_msg, NULL);
415 if (msgstr == NULL) {
416 free(new_msg);
417 return;
418 }
419
420 new_msg->sip_msg = msgstr;
421 new_msg->msg_seq = seq;
422 new_msg->msg_timestamp = time(NULL);
423 new_msg->next = NULL;
424 if (sip_log->sip_msgcnt == 0) {
425 sip_log->sip_msgs = new_msg;
426 } else {
427 while (msg_chain->next != NULL)
428 msg_chain = msg_chain->next;
429 msg_chain->next = new_msg;
430 }
431 sip_log->sip_msgcnt++;
432 }
433
434 /*
435 * Given a counter group and counter name within the group, returns the value
436 * associated with the counter in 'cntval'.
437 */
438 int
sip_get_counter_value(int group,int counter,void * cntval,size_t cntlen)439 sip_get_counter_value(int group, int counter, void *cntval, size_t cntlen)
440 {
441 if (group != SIP_TRAFFIC_COUNTERS || cntval == NULL)
442 return (EINVAL);
443 if ((counter == SIP_COUNTER_START_TIME || counter ==
444 SIP_COUNTER_STOP_TIME) && (cntlen != sizeof (time_t))) {
445 return (EINVAL);
446 } else if (cntlen != sizeof (uint64_t)) {
447 return (EINVAL);
448 }
449
450 (void) pthread_mutex_lock(&sip_counters.sip_counter_mutex);
451 switch (counter) {
452 case SIP_TOTAL_BYTES_RCVD:
453 *(uint64_t *)cntval = sip_counters.sip_total_bytes_rcvd;
454 break;
455 case SIP_TOTAL_BYTES_SENT:
456 *(uint64_t *)cntval = sip_counters.sip_total_bytes_sent;
457 break;
458 case SIP_TOTAL_REQ_RCVD:
459 *(uint64_t *)cntval = sip_counters.sip_total_req_rcvd;
460 break;
461 case SIP_TOTAL_REQ_SENT:
462 *(uint64_t *)cntval = sip_counters.sip_total_req_sent;
463 break;
464 case SIP_TOTAL_RESP_RCVD:
465 *(uint64_t *)cntval = sip_counters.sip_total_resp_rcvd;
466 break;
467 case SIP_TOTAL_RESP_SENT:
468 *(uint64_t *)cntval = sip_counters.sip_total_resp_sent;
469 break;
470 case SIP_ACK_REQ_RCVD:
471 *(uint64_t *)cntval = sip_counters.sip_ack_req_rcvd;
472 break;
473 case SIP_ACK_REQ_SENT:
474 *(uint64_t *)cntval = sip_counters.sip_ack_req_sent;
475 break;
476 case SIP_BYE_REQ_RCVD:
477 *(uint64_t *)cntval = sip_counters.sip_bye_req_rcvd;
478 break;
479 case SIP_BYE_REQ_SENT:
480 *(uint64_t *)cntval = sip_counters.sip_bye_req_sent;
481 break;
482 case SIP_CANCEL_REQ_RCVD:
483 *(uint64_t *)cntval = sip_counters.sip_cancel_req_rcvd;
484 break;
485 case SIP_CANCEL_REQ_SENT:
486 *(uint64_t *)cntval = sip_counters.sip_cancel_req_sent;
487 break;
488 case SIP_INFO_REQ_RCVD:
489 *(uint64_t *)cntval = sip_counters.sip_info_req_rcvd;
490 break;
491 case SIP_INFO_REQ_SENT:
492 *(uint64_t *)cntval = sip_counters.sip_info_req_sent;
493 break;
494 case SIP_INVITE_REQ_RCVD:
495 *(uint64_t *)cntval = sip_counters.sip_invite_req_rcvd;
496 break;
497 case SIP_INVITE_REQ_SENT:
498 *(uint64_t *)cntval = sip_counters.sip_invite_req_sent;
499 break;
500 case SIP_NOTIFY_REQ_RCVD:
501 *(uint64_t *)cntval = sip_counters.sip_notify_req_rcvd;
502 break;
503 case SIP_NOTIFY_REQ_SENT:
504 *(uint64_t *)cntval = sip_counters.sip_notify_req_sent;
505 break;
506 case SIP_OPTIONS_REQ_RCVD:
507 *(uint64_t *)cntval = sip_counters.sip_options_req_rcvd;
508 break;
509 case SIP_OPTIONS_REQ_SENT:
510 *(uint64_t *)cntval = sip_counters.sip_options_req_sent;
511 break;
512 case SIP_PRACK_REQ_RCVD:
513 *(uint64_t *)cntval = sip_counters.sip_prack_req_rcvd;
514 break;
515 case SIP_PRACK_REQ_SENT:
516 *(uint64_t *)cntval = sip_counters.sip_prack_req_sent;
517 break;
518 case SIP_REFER_REQ_RCVD:
519 *(uint64_t *)cntval = sip_counters.sip_refer_req_rcvd;
520 break;
521 case SIP_REFER_REQ_SENT:
522 *(uint64_t *)cntval = sip_counters.sip_refer_req_sent;
523 break;
524 case SIP_REGISTER_REQ_RCVD:
525 *(uint64_t *)cntval = sip_counters.
526 sip_register_req_rcvd;
527 break;
528 case SIP_REGISTER_REQ_SENT:
529 *(uint64_t *)cntval = sip_counters.
530 sip_register_req_sent;
531 break;
532 case SIP_SUBSCRIBE_REQ_RCVD:
533 *(uint64_t *)cntval = sip_counters.
534 sip_subscribe_req_rcvd;
535 break;
536 case SIP_SUBSCRIBE_REQ_SENT:
537 *(uint64_t *)cntval = sip_counters.
538 sip_subscribe_req_sent;
539 break;
540 case SIP_UPDATE_REQ_RCVD:
541 *(uint64_t *)cntval = sip_counters.sip_update_req_rcvd;
542 break;
543 case SIP_UPDATE_REQ_SENT:
544 *(uint64_t *)cntval = sip_counters.sip_update_req_sent;
545 break;
546 case SIP_1XX_RESP_RCVD:
547 *(uint64_t *)cntval = sip_counters.sip_1xx_resp_rcvd;
548 break;
549 case SIP_1XX_RESP_SENT:
550 *(uint64_t *)cntval = sip_counters.sip_1xx_resp_sent;
551 break;
552 case SIP_2XX_RESP_RCVD:
553 *(uint64_t *)cntval = sip_counters.sip_2xx_resp_rcvd;
554 break;
555 case SIP_2XX_RESP_SENT:
556 *(uint64_t *)cntval = sip_counters.sip_2xx_resp_sent;
557 break;
558 case SIP_3XX_RESP_RCVD:
559 *(uint64_t *)cntval = sip_counters.sip_3xx_resp_rcvd;
560 break;
561 case SIP_3XX_RESP_SENT:
562 *(uint64_t *)cntval = sip_counters.sip_3xx_resp_sent;
563 break;
564 case SIP_4XX_RESP_RCVD:
565 *(uint64_t *)cntval = sip_counters.sip_4xx_resp_rcvd;
566 break;
567 case SIP_4XX_RESP_SENT:
568 *(uint64_t *)cntval = sip_counters.sip_4xx_resp_sent;
569 break;
570 case SIP_5XX_RESP_RCVD:
571 *(uint64_t *)cntval = sip_counters.sip_5xx_resp_rcvd;
572 break;
573 case SIP_5XX_RESP_SENT:
574 *(uint64_t *)cntval = sip_counters.sip_5xx_resp_sent;
575 break;
576 case SIP_6XX_RESP_RCVD:
577 *(uint64_t *)cntval = sip_counters.sip_6xx_resp_rcvd;
578 break;
579 case SIP_6xx_RESP_SENT:
580 *(uint64_t *)cntval = sip_counters.sip_6xx_resp_sent;
581 break;
582 case SIP_COUNTER_START_TIME:
583 *(time_t *)cntval = sip_counters.starttime;
584 break;
585 case SIP_COUNTER_STOP_TIME:
586 *(time_t *)cntval = sip_counters.stoptime;
587 break;
588 default:
589 (void) pthread_mutex_unlock(&sip_counters.
590 sip_counter_mutex);
591 return (EINVAL);
592 }
593 (void) pthread_mutex_unlock(&sip_counters.sip_counter_mutex);
594 return (0);
595 }
596
597 /*
598 * Enables the SIP performance/traffic counting. Also reset's the previous
599 * counter values and starts counting afresh.
600 */
601 int
sip_enable_counters(int group)602 sip_enable_counters(int group)
603 {
604 if (group != SIP_TRAFFIC_COUNTERS)
605 return (EINVAL);
606 (void) pthread_mutex_lock(&sip_counters.sip_counter_mutex);
607 /* If it's not enabled, enable it and capture the start time */
608 if (!sip_counters.enabled) {
609 /* zero all the counters except for the mutex at the end */
610 (void) bzero(&sip_counters, sizeof (sip_traffic_counters_t) -
611 sizeof (pthread_mutex_t));
612 sip_counters.enabled = B_TRUE;
613 sip_counters.starttime = time(NULL);
614 sip_counters.stoptime = 0;
615 }
616 (void) pthread_mutex_unlock(&sip_counters.sip_counter_mutex);
617 return (0);
618 }
619
620 /*
621 * Disables the SIP performance/traffic counting. If already disabled it just
622 * exits without doing anyting. It records the stop time.
623 */
624 int
sip_disable_counters(int group)625 sip_disable_counters(int group)
626 {
627 if (group != SIP_TRAFFIC_COUNTERS)
628 return (EINVAL);
629 (void) pthread_mutex_lock(&sip_counters.sip_counter_mutex);
630 if (sip_counters.enabled) {
631 sip_counters.enabled = B_FALSE;
632 sip_counters.stoptime = time(NULL);
633 }
634 (void) pthread_mutex_unlock(&sip_counters.sip_counter_mutex);
635 return (0);
636 }
637