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