xref: /illumos-gate/usr/src/lib/libsip/common/sip_logging.c (revision f998c95e3b7029fe5f7542e115f7474ddb8024d7)
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
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
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
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
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
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
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
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
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
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
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
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
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
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