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