Browse code

- New stats code

ric authored on 28/08/2002 18:59:38
Showing 2 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,836 @@
1
+#ifdef STATS
2
+#include "stats.h"
3
+#include <stdio.h>
4
+#include <stdlib.h>
5
+#include <string.h>
6
+#include <time.h>
7
+#include <sys/types.h>
8
+#include <unistd.h>
9
+#include "dprint.h"
10
+#include "mem/shm_mem.h"
11
+#include "sr_module.h"
12
+
13
+/* SNMP includes */
14
+#include "modules/snmp/snmp_handler.h"
15
+#include "modules/snmp/sipCommonStatsMethod.h"
16
+#include "modules/snmp/sipCommonStatusCode.h"
17
+
18
+struct stats_s *stats;		/* per process stats structure */ 
19
+char *stat_file = NULL;		/* set by the parser */
20
+
21
+/* private variables */
22
+static struct stats_s *global_stats=NULL;
23
+static int stats_segments=-1;	/*used also to determine if we've been init'ed*/
24
+
25
+/* adds up global statistics and puts them into passed struct.
26
+ * -1 returned on failure */
27
+static int collect_stats(struct stats_s *s);
28
+
29
+/***********************8 SNMP Stuff **************************/
30
+/* a small structure we use to pass around the functions needed by
31
+ * all the registration functions */
32
+struct stats_funcs {
33
+	int (*reg_func)(const char *, struct sip_snmp_handler*);
34
+	struct sip_snmp_handler* (*new_func)(size_t);
35
+	void (*free_func)(struct sip_snmp_handler*);
36
+};
37
+
38
+/* SNMP Handler registration functions */
39
+static int sipSummaryStatsTable_register(const struct stats_funcs *f);
40
+static int sipMethodStatsTable_register(const struct stats_funcs *f);
41
+static int sipStatusCodesTable_register(const struct stats_funcs *f);
42
+
43
+/* the handlers */
44
+static int collect_InReqs(struct sip_snmp_obj *, enum handler_op);
45
+static int collect_OutReqs(struct sip_snmp_obj *, enum handler_op);
46
+static int collect_InResp(struct sip_snmp_obj *, enum handler_op);
47
+static int collect_OutResp(struct sip_snmp_obj *, enum handler_op);
48
+static int sipStatsMethod_handler(struct sip_snmp_obj *o, enum handler_op op);
49
+static int sipStatusCodes_handler(struct sip_snmp_obj *o, enum handler_op op);
50
+
51
+int init_stats(int nr_of_processes)
52
+{
53
+	LOG(L_DBG,"init_stats(): initializing stats for %d processes\n", 
54
+		nr_of_processes);
55
+
56
+	if(!stat_file) {
57
+		LOG(L_ERR, "Invalid stats file\n");
58
+		return -1;
59
+	}
60
+
61
+
62
+	global_stats = shm_malloc(nr_of_processes*sizeof(struct stats_s));
63
+	if(!global_stats) {
64
+		LOG(L_ERR, "Out of memory\n");
65
+		return -1;
66
+	}
67
+	stats_segments = nr_of_processes;
68
+
69
+	if(stats_register() == -1)
70
+		LOG(L_WARN, "init_stats(): Couldn't register stats with snmp module\n");
71
+
72
+
73
+	return 0;
74
+}
75
+
76
+/* sets the stats pointer for the passed process */
77
+void setstats(int child_index)
78
+{
79
+	if(stats_segments == -1 || !global_stats) {
80
+		LOG(L_ERR, "Stats not initialized. Cannot set them\n");
81
+		stats = NULL;
82
+		return;
83
+	}
84
+	if(child_index < 0 || child_index >= stats_segments) {
85
+		stats = NULL;
86
+		LOG(L_ERR, "Invalid index %d while setting statistics. Only have "
87
+			"space for %d processes\n", child_index, stats_segments);
88
+		return;
89
+	}
90
+	stats = global_stats+child_index;
91
+	stats->process_index = child_index;
92
+	/* can't use pids[] because we may be called before the corresponding
93
+	 * slot in pids[] is initialized (chk main_loop()) */
94
+	stats->pid = getpid();
95
+	stats->start_time = time(NULL);
96
+}
97
+
98
+/* printheader is used to print pid, date and index */
99
+int dump_statistic(FILE *fp, struct stats_s *istats, int printheader)
100
+{
101
+	struct tm res;
102
+	char t[256];
103
+	if(stats_segments == -1 || !global_stats) {
104
+		LOG(L_ERR, "Stats \"engine\" not initialized\n");
105
+		return -1;
106
+	}
107
+
108
+	if(printheader) {
109
+		localtime_r(&istats->start_time, &res);
110
+		strftime(t, 255, "%c", &res);
111
+		
112
+		fprintf(fp, "stats for process %d (pid %d) started at %s\n", 
113
+				istats->process_index, istats->pid, t);
114
+	}
115
+
116
+	fprintf(fp, "received requests:\ninv: %ld\tack: %ld\tcnc: %ld\t"
117
+		"bye: %ld\tother: %ld\n",
118
+		istats->received_requests_inv,
119
+		istats->received_requests_ack,
120
+		istats->received_requests_cnc,
121
+		istats->received_requests_bye,
122
+		istats->received_requests_other);
123
+	fprintf(fp, "sent requests:\n"
124
+		"inv: %ld\tack: %ld\tcnc: %ld\tbye: %ld\tother: %ld\n",
125
+		istats->sent_requests_inv,
126
+		istats->sent_requests_ack,
127
+		istats->sent_requests_cnc,
128
+		istats->sent_requests_bye,
129
+		istats->sent_requests_other);
130
+	fprintf(fp, "received responses:\n"
131
+		"1: %ld\t2: %ld\t3: %ld\t4: %ld\t5: %ld\t6: %ld\tother: %ld\t"
132
+		"drops: %ld\n",
133
+		istats->received_responses_1,
134
+		istats->received_responses_2,
135
+		istats->received_responses_3,
136
+		istats->received_responses_4,
137
+		istats->received_responses_5,
138
+		istats->received_responses_6,
139
+		istats->received_responses_other,
140
+		istats->received_drops);
141
+	fprintf(fp, "sent responses:\n"
142
+		"1: %ld\t2: %ld\t3: %ld\t4: %ld\t5: %ld\t6: %ld\n",
143
+		istats->sent_responses_1,
144
+		istats->sent_responses_2,
145
+		istats->sent_responses_3,
146
+		istats->sent_responses_4,
147
+		istats->sent_responses_5,
148
+		istats->sent_responses_6);
149
+	fprintf(fp, "processed requests: %ld\t\tprocessed responses: %ld\n"
150
+		"acc req time: %ld\t\t\tacc res time: %ld\nfailed on send: %ld\n\n",
151
+		istats->processed_requests,
152
+		istats->processed_responses,
153
+		istats->acc_req_time,
154
+		istats->acc_res_time,
155
+		istats->failed_on_send);
156
+	return 0;
157
+}
158
+
159
+int dump_all_statistic()
160
+{
161
+	register int i;
162
+	register struct stats_s *c;
163
+	static struct stats_s *g = NULL;
164
+	struct tm res;
165
+	char t[256];
166
+	time_t ts;
167
+	FILE *stat_fp = NULL;
168
+
169
+	if(stats_segments == -1 || !global_stats) {
170
+		LOG(L_ERR, "%s: Can't dump statistics, not initialized!\n", __func__);
171
+		return -1;
172
+	}
173
+
174
+	if(!stat_file) {
175
+		LOG(L_ERR, "%s: Can't dump statistics, invalid stats file\n", __func__);
176
+		return -1;
177
+	}
178
+
179
+	stat_fp = fopen(stat_file, "a");
180
+	if(!stat_fp) {
181
+		LOG(L_ERR, "%s: Couldn't open stats file %s: %s\n", __func__, stat_file,
182
+				strerror(errno));
183
+		return -1;
184
+	}
185
+
186
+	/* time stamp them since we're appending to the file */
187
+	ts = time(NULL);
188
+	localtime_r(&ts, &res);
189
+	strftime(t, 255, "%c", &res);
190
+	fprintf(stat_fp, "#### stats @ %s #####\n", t); 
191
+
192
+	c = global_stats;
193
+	for(i=0; i<stats_segments; i++) {
194
+		if(dump_statistic(stat_fp, c, 1) == -1) {
195
+			LOG(L_ERR, "Error dumping statistics for process %d\n", i);
196
+			goto end;
197
+		}
198
+		c++;
199
+	}
200
+
201
+	fprintf(stat_fp, "## Global Stats ##\n");
202
+	if(!g)
203
+		g = calloc(1, sizeof(struct stats_s));
204
+	if(!g) {
205
+		LOG(L_ERR, "Couldn't dump global stats: %s\n", strerror(errno));
206
+		goto end;
207
+	}
208
+	
209
+	if(collect_stats(g) == -1) {
210
+		LOG(L_ERR, "%s: Couldn't dump global stats\n", __func__);
211
+		goto end;
212
+	}
213
+	if(dump_statistic(stat_fp, g, 0) == -1) {
214
+		LOG(L_ERR, "Couldn't dump global stats\n");
215
+		goto end;
216
+	}
217
+end:
218
+	fprintf(stat_fp, "\n");
219
+	fclose(stat_fp);
220
+
221
+	return 0;
222
+}
223
+
224
+static int collect_stats(struct stats_s *s)
225
+{
226
+	register int i;
227
+	register struct stats_s *c;
228
+	if(!s) {
229
+		LOG(L_ERR, "collect_stats(): Invalid stats pointer passed\n");
230
+		return -1;
231
+	}
232
+	if(!global_stats || stats_segments == -1) {
233
+		LOG(L_ERR, "Can't collect statistics, not initalized!!\n");
234
+		return -1;
235
+	}
236
+
237
+	c = global_stats;
238
+	memset(s, '\0', sizeof(struct stats_s));
239
+	for(i=0; i<stats_segments; i++) {
240
+		s->received_requests_inv += c->received_requests_inv;
241
+		s->received_requests_ack += c->received_requests_ack;
242
+		s->received_requests_cnc += c->received_requests_cnc;
243
+		s->received_requests_bye += c->received_requests_bye;
244
+		s->received_requests_other += c->received_requests_other;
245
+		s->received_responses_1 += c->received_responses_1;
246
+		s->received_responses_2 += c->received_responses_2;
247
+		s->received_responses_3 += c->received_responses_3;
248
+		s->received_responses_4 += c->received_responses_4;
249
+		s->received_responses_5 += c->received_responses_5;
250
+		s->received_responses_6 += c->received_responses_6;
251
+		s->received_responses_other += c->received_responses_other;
252
+		s->received_drops += c->received_drops;
253
+		s->sent_requests_inv += c->sent_requests_inv;
254
+		s->sent_requests_ack += c->sent_requests_ack;
255
+		s->sent_requests_cnc += c->sent_requests_cnc;
256
+		s->sent_requests_bye += c->sent_requests_bye;
257
+		s->sent_requests_other += c->sent_requests_other;
258
+		s->sent_responses_1 += c->sent_responses_1;
259
+		s->sent_responses_2 += c->sent_responses_2;
260
+		s->sent_responses_3 += c->sent_responses_3;
261
+		s->sent_responses_4 += c->sent_responses_4;
262
+		s->sent_responses_5 += c->sent_responses_5;
263
+		s->sent_responses_6 += c->sent_responses_6;
264
+		s->processed_requests += c->processed_requests;
265
+		s->processed_responses += c->processed_responses;
266
+		s->acc_req_time += c->acc_req_time;
267
+		s->acc_res_time += c->acc_res_time;
268
+		s->failed_on_send += c->failed_on_send;
269
+
270
+		c++; /* next, please... */
271
+	}
272
+
273
+	return 0;
274
+}
275
+
276
+/*************************** SNMP Stuff ***********************/
277
+
278
+/* ##### Registration Functions ####### */
279
+
280
+/* Registers the handlers for:
281
+ * - sipSummaryStatsTable
282
+ * - sipMethodStatsTable
283
+ * - sipStatusCodesTable
284
+ * - sipCommonStatusCodeTable
285
+ *
286
+ * Returns 0 if snmp module not present, -1 on error, 1 on successful
287
+ * registration
288
+ */
289
+
290
+#define reg(t) \
291
+	if(t##_register(&f) == -1) {	\
292
+		LOG(L_ERR, "%s: Failed registering SNMP handlers\n", func);	\
293
+		return -1;	\
294
+	}
295
+
296
+int stats_register()
297
+{
298
+	const char *func = __FUNCTION__;
299
+	struct stats_funcs f;
300
+
301
+	f.reg_func = (void*) find_export("snmp_register_handler", 2);
302
+	f.new_func = (void*) find_export("snmp_new_handler", 1);
303
+	f.free_func = (void*) find_export("snmp_free_handler", 1);
304
+	if(!f.reg_func || !f.new_func || !f.free_func) {
305
+		LOG(L_WARN, "%s: Couldn't find necessary SNMP functions. Is the "
306
+			"module loaded?\n", func);
307
+		return 0;
308
+	}
309
+
310
+	reg(sipSummaryStatsTable);
311
+	reg(sipMethodStatsTable);
312
+	reg(sipStatusCodesTable);
313
+
314
+	return 0;
315
+}
316
+
317
+/* Receives the function used to register SNMP handlers. Returns 0
318
+ * on success, -1 on error */
319
+/* Registers:
320
+ * - sipSummaryInRequests
321
+ * - sipSummaryOutRequests
322
+ * - sipSummaryInResponses
323
+ * - sipSummaryOutResponses
324
+ * => sipSummaryTotalTransactions is handled by the tm module */
325
+static int sipSummaryStatsTable_register(const struct stats_funcs *f)
326
+{
327
+	register struct sip_snmp_handler *h;
328
+	register struct sip_snmp_obj *o;
329
+	const char *func = __FUNCTION__;
330
+
331
+	h = f->new_func(sizeof(unsigned long));
332
+	if(!h) {
333
+		LOG(L_ERR, "%s: Error creating handler\n", func);
334
+		return -1;
335
+	}
336
+	o = h->sip_obj;
337
+
338
+	/* this is the same for all of our objects */
339
+	o->type = SER_COUNTER;
340
+	*o->value.integer = 0;	/* default value. The real one is computed on
341
+							   request */
342
+	o->val_len = sizeof(unsigned long);
343
+
344
+	/* sipSummaryInRequests */
345
+	h->on_get = collect_InReqs;
346
+	h->on_set = h->on_end = NULL;
347
+	if(f->reg_func("sipSummaryInRequests", h) == -1) {
348
+		LOG(L_ERR, "%s: Error registering sipSummaryInRequests\n", func);
349
+		f->free_func(h);
350
+		return -1;
351
+	}
352
+
353
+	/* sipSummaryOutRequests */
354
+	h->on_get = collect_OutReqs;
355
+	if(f->reg_func("sipSummaryOutRequests", h) == -1) {
356
+		LOG(L_ERR, "%s: Error registering sipSummaryOutRequests\n", func);
357
+		f->free_func(h);
358
+		return -1;
359
+	}
360
+
361
+	/* sipSummaryInResponses */
362
+	h->on_get = collect_InResp;
363
+	if(f->reg_func("sipSummaryInResponses", h) == -1) {
364
+		LOG(L_ERR, "%s: Error registering sipSummaryInResponses\n", func);
365
+		f->free_func(h);
366
+		return -1;
367
+	}
368
+	
369
+	/* sipSummaryOutResponses */
370
+	h->on_get = collect_OutResp;
371
+	if(f->reg_func("sipSummaryOutResponses", h) == -1) {
372
+		LOG(L_ERR, "%s: Error registering sipSummaryOutResponses\n", func);
373
+		f->free_func(h);
374
+		return -1;
375
+	}
376
+
377
+	f->free_func(h);
378
+
379
+	return 0;
380
+}
381
+
382
+static int sipMethodStatsTable_register(const struct stats_funcs *f)
383
+{
384
+	const char* objs[] = {
385
+		"sipStatsInviteIns",
386
+		"sipStatsInviteOuts",
387
+		"sipStatsAckIns",
388
+		"sipStatsAckOuts",
389
+		"sipStatsByeIns",
390
+		"sipStatsByeOuts",
391
+		"sipStatsCancelIns",
392
+		"sipStatsCancelOuts"
393
+#if 0	/* we don't know about these */
394
+		"sipStatsOptionsIns",
395
+		"sipStatsOptionsOuts",
396
+		"sipStatsRegisterIns",
397
+		"sipStatsRegisterOuts",
398
+		"sipStatsInfoIns",
399
+		"sipStatsInfoOuts"
400
+#endif
401
+	};
402
+	int i, num = 8;
403
+	const char *func = __FUNCTION__;
404
+	register struct sip_snmp_handler *h;
405
+	register struct sip_snmp_obj *o;
406
+
407
+	h = f->new_func(sizeof(unsigned long));
408
+	if(!h) {
409
+		LOG(L_ERR, "%s: Error creating handler\n", func);
410
+		return -1;
411
+	}
412
+	o = h->sip_obj;
413
+	o->type = SER_COUNTER;
414
+	*o->value.integer = 0;
415
+	o->val_len = sizeof(unsigned long);
416
+
417
+	h->on_get = sipStatsMethod_handler;
418
+	h->on_set = h->on_end = NULL;
419
+
420
+	for(i=0; i<num; i++) {
421
+		if(f->reg_func(objs[i], h) == -1) {
422
+			LOG(L_ERR, "%s: Error registering %s\n", func, objs[i]);
423
+			f->free_func(h);
424
+			return -1;
425
+		}
426
+	}
427
+
428
+	f->free_func(h);
429
+
430
+	return 0;
431
+}
432
+
433
+static int sipStatusCodesTable_register(const struct stats_funcs *f)
434
+{
435
+	const char *objs[] = {
436
+		"sipStatsInfoClassIns",
437
+		"sipStatsInfoClassOuts",
438
+		"sipStatsSuccessClassIns",
439
+		"sipStatsSuccessClassOuts",
440
+		"sipStatsRedirClassIns",
441
+		"sipStatsRedirClassOuts",
442
+		"sipStatsReqFailClassIns",
443
+		"sipStatsReqFailClassOuts",
444
+		"sipStatsServerFailClassIns",
445
+		"sipStatsServerFailClassOuts",
446
+		"sipStatsGlobalFailClassIns",
447
+		"sipStatsGlobalFailClassOuts",
448
+		"sipStatsOtherClassesIns",
449
+		"sipStatsOtherClassesOuts"
450
+	};
451
+	int i, num = 14;
452
+	const char *func = __FUNCTION__;
453
+	register struct sip_snmp_handler *h;
454
+	register struct sip_snmp_obj *o;
455
+
456
+	h = f->new_func(sizeof(unsigned long));
457
+	if(!h) {
458
+		LOG(L_ERR, "%s: Error creating handler\n", func);
459
+		return -1;
460
+	}
461
+	o = h->sip_obj;
462
+	o->type = SER_COUNTER;
463
+	*o->value.integer = 0;
464
+	o->val_len = sizeof(unsigned long);
465
+
466
+	h->on_get = sipStatusCodes_handler;
467
+	h->on_set = h->on_end = NULL;
468
+
469
+	for(i=0; i<num; i++) {
470
+		if(f->reg_func(objs[i], h) == -1) {
471
+			LOG(L_ERR, "%s: Error registering %s\n", func, objs[i]);
472
+			f->free_func(h);
473
+			return -1;
474
+		}
475
+	}
476
+
477
+	f->free_func(h);
478
+
479
+	return 0;}
480
+
481
+/* ########################## SNMP Handlers ######################### */
482
+
483
+/*** Handlers for sipSummaryStatsTable */
484
+static int collect_InReqs(struct sip_snmp_obj *o, enum handler_op op)
485
+{
486
+	register int i;
487
+	register struct stats_s *c;
488
+	register unsigned long t1, t2, t3, t4, t5;
489
+	const char *func = __FUNCTION__;
490
+
491
+	if(!global_stats || stats_segments == -1) {
492
+		LOG(L_ERR, "%s: Can't collect stats, they have not been initialized."
493
+			"Did you call init_stats()?\n", func);
494
+		return -1;
495
+	}
496
+
497
+	if(op != SER_GET) {
498
+		LOG(L_ERR, "%s: Invalid handler operation passed\n", func);
499
+		return -1;
500
+	}
501
+
502
+	if(!o->value.integer) {
503
+		o->value.integer = calloc(1, sizeof(unsigned long));
504
+		if(!o->value.integer) {
505
+			LOG(L_ERR, "%s: %s\n", func, strerror(errno));
506
+			return -1;
507
+		}
508
+	}
509
+
510
+	c = global_stats;
511
+	t1 = t2 = t3 = t4 = t5 = 0;
512
+	for(i=0; i<stats_segments; i++, c++) {
513
+		t1 += c->received_requests_inv;
514
+		t2 += c->received_requests_ack;
515
+		t3 += c->received_requests_cnc;
516
+		t4 += c->received_requests_bye;
517
+		t5 += c->received_requests_other;
518
+	}
519
+
520
+	*o->value.integer = t1 + t2 + t3 + t4 + t5; 
521
+	o->val_len = sizeof(unsigned long);
522
+	o->type = SER_COUNTER;
523
+	
524
+	return 0;
525
+}
526
+
527
+static int collect_OutReqs(struct sip_snmp_obj *o, enum handler_op op)
528
+{
529
+	register int i;
530
+	register struct stats_s *c;
531
+	register unsigned long t1, t2, t3, t4, t5;
532
+	const char *func = __FUNCTION__;
533
+
534
+	if(!global_stats || stats_segments == -1) {
535
+		LOG(L_ERR, "%s: Can't collect stats, they have not been initialized."
536
+			"Did you call init_stats()?\n", func);
537
+		return -1;
538
+	}
539
+
540
+	if(op != SER_GET) {
541
+		LOG(L_ERR, "%s: Invalid handler operation passed\n", func);
542
+		return -1;
543
+	}
544
+
545
+	if(!o->value.integer) {
546
+		o->value.integer = calloc(1, sizeof(unsigned long));
547
+		if(!o->value.integer) {
548
+			LOG(L_ERR, "%s: %s\n", func, strerror(errno));
549
+			return -1;
550
+		}
551
+	}
552
+
553
+	c = global_stats;
554
+	t1 = t2 = t3 = t4 = t5 = 0;
555
+	for(i=0; i<stats_segments; i++, c++) {
556
+		t1 += c->sent_requests_inv;
557
+		t2 += c->sent_requests_ack;
558
+		t3 += c->sent_requests_cnc;
559
+		t4 += c->sent_requests_bye;
560
+		t5 += c->sent_requests_other;
561
+	}
562
+
563
+	*o->value.integer = t1 + t2 + t3 + t4 + t5; 
564
+	o->val_len = sizeof(unsigned long);
565
+	o->type = SER_COUNTER;
566
+	
567
+	return 0;
568
+}
569
+
570
+static int collect_InResp(struct sip_snmp_obj *o, enum handler_op op)
571
+{
572
+	register int i;
573
+	register struct stats_s *c;
574
+	register unsigned long t1, t2, t3, t4, t5, t6, t7;
575
+	const char *func = __FUNCTION__;
576
+
577
+	if(!global_stats || stats_segments == -1) {
578
+		LOG(L_ERR, "%s: Can't collect stats, they have not been initialized."
579
+			"Did you call init_stats()?\n", func);
580
+		return -1;
581
+	}
582
+
583
+	if(op != SER_GET) {
584
+		LOG(L_ERR, "%s: Invalid handler operation passed\n", func);
585
+		return -1;
586
+	}
587
+
588
+	if(!o->value.integer) {
589
+		o->value.integer = calloc(1, sizeof(unsigned long));
590
+		if(!o->value.integer) {
591
+			LOG(L_ERR, "%s: %s\n", func, strerror(errno));
592
+			return -1;
593
+		}
594
+	}
595
+
596
+	c = global_stats;
597
+	t1 = t2 = t3 = t4 = t5 = t6 = t7 = 0;
598
+	for(i=0; i<stats_segments; i++, c++) {
599
+		t1 += c->received_responses_1;
600
+		t2 += c->received_responses_2;
601
+		t3 += c->received_responses_3;
602
+		t4 += c->received_responses_4;
603
+		t5 += c->received_responses_5;
604
+		t6 += c->received_responses_6;
605
+		t7 += c->received_responses_other;
606
+	}
607
+
608
+	*o->value.integer = t1 + t2 + t3 + t4 + t5 + t6 + t7; 
609
+	o->val_len = sizeof(unsigned long);
610
+	o->type = SER_COUNTER;
611
+	
612
+	return 0;
613
+}
614
+
615
+static int collect_OutResp(struct sip_snmp_obj *o, enum handler_op op)
616
+{
617
+	register int i;
618
+	register struct stats_s *c;
619
+	register unsigned long t1, t2, t3, t4, t5, t6, t7;
620
+	const char *func = __FUNCTION__;
621
+
622
+	if(!global_stats || stats_segments == -1) {
623
+		LOG(L_ERR, "%s: Can't collect stats, they have not been initialized\n",
624
+			func);
625
+		return -1;
626
+	}
627
+
628
+	if(op != SER_GET) {
629
+		LOG(L_ERR, "%s: Invalid handler operation passed\n", func);
630
+		return -1;
631
+	}
632
+
633
+	if(!o->value.integer) {
634
+		o->value.integer = calloc(1, sizeof(unsigned long));
635
+		if(!o->value.integer) {
636
+			LOG(L_ERR, "%s: %s\n", func, strerror(errno));
637
+			return -1;
638
+		}
639
+	}
640
+
641
+	c = global_stats;
642
+	t1 = t2 = t3 = t4 = t5 = t6 = t7 = 0;
643
+	for(i=0; i<stats_segments; i++, c++) {
644
+		t1 += c->sent_responses_1;
645
+		t2 += c->sent_responses_2;
646
+		t3 += c->sent_responses_3;
647
+		t4 += c->sent_responses_4;
648
+		t5 += c->sent_responses_5;
649
+		t6 += c->sent_responses_6;
650
+		/* XXX: Not in stats struct 
651
+		t7 += c->sent_responses_other;
652
+		*/
653
+	}
654
+
655
+	*o->value.integer = t1 + t2 + t3 + t4 + t5 + t6 + t7; 
656
+	o->val_len = sizeof(unsigned long);
657
+	o->type = SER_COUNTER;
658
+	
659
+	return 0;
660
+}
661
+
662
+/***** Handlers for sipMethodStatsTable ******/
663
+/* Collects the specified stat and puts the result in total. s defines
664
+ * the starting point in the stats array, normally global_stats */
665
+#define collect_this_stat(stat, total, s) \
666
+	for(i=0; i<stats_segments; i++)	\
667
+		total += s++->stat;
668
+
669
+static int sipStatsMethod_handler(struct sip_snmp_obj *o, enum handler_op op)
670
+{
671
+	register struct stats_s *c;
672
+	register unsigned long total;
673
+	register int i;
674
+	const char *func = __FUNCTION__;
675
+
676
+	if(!o) {
677
+		LOG(L_ERR, "%s: Invalid sip SNMP object passed\n", func);
678
+		return -1;
679
+	}
680
+
681
+	if(!global_stats || stats_segments == -1) {
682
+		LOG(L_ERR, "%s: Can't collect stats, they have not been initialized\n",
683
+			func);
684
+		return -1;
685
+	}
686
+
687
+	if(op != SER_GET) {
688
+		LOG(L_ERR, "%s: Invalid handler operation passed\n", func);
689
+		return -1;
690
+	}
691
+
692
+	if(!o->value.integer) {
693
+		o->value.integer = calloc(1, sizeof(unsigned long));
694
+		if(!o->value.integer) {
695
+			LOG(L_ERR, "%s: %s\n", func, strerror(errno));
696
+			return -1;
697
+		}
698
+	}
699
+
700
+	c = global_stats;
701
+	total = 0;
702
+	switch(o->col) {
703
+		/* these definitions are taken from sipMethodStatsHandler */
704
+		case COLUMN_SIPSTATSINVITEINS: 
705
+			collect_this_stat(received_requests_inv, total, c);
706
+			break;
707
+		case COLUMN_SIPSTATSINVITEOUTS: 
708
+			collect_this_stat(sent_requests_inv, total, c);
709
+			break;
710
+		case COLUMN_SIPSTATSACKINS: 
711
+			collect_this_stat(received_requests_ack, total, c);
712
+			break;
713
+		case COLUMN_SIPSTATSACKOUTS: 
714
+			collect_this_stat(sent_requests_ack, total, c);
715
+			break;
716
+		case COLUMN_SIPSTATSBYEINS: 
717
+			collect_this_stat(received_requests_bye, total, c);
718
+			break;
719
+		case COLUMN_SIPSTATSBYEOUTS: 
720
+			collect_this_stat(sent_requests_bye, total, c);
721
+			break;
722
+		case COLUMN_SIPSTATSCANCELINS: 
723
+			collect_this_stat(received_requests_cnc, total, c);
724
+			break;
725
+		case COLUMN_SIPSTATSCANCELOUTS: 
726
+			collect_this_stat(sent_requests_cnc, total, c);
727
+			break;
728
+		/* ser doesn't have notion for these. We don't
729
+		 * register them with snmp. Here just as remainder */
730
+#if 0
731
+		case COLUMN_SIPSTATSOPTIONSINS:
732
+		case COLUMN_SIPSTATSOPTIONSOUTS:
733
+		case COLUMN_SIPSTATSREGISTERINS:
734
+		case COLUMN_SIPSTATSREGISTEROUTS:
735
+		case COLUMN_SIPSTATSINFOINS:
736
+		case COLUMN_SIPSTATSINFOOUTS:
737
+			break;
738
+#endif
739
+	}
740
+
741
+	*o->value.integer = total;
742
+	o->val_len = sizeof(unsigned long);
743
+	o->type = SER_COUNTER;
744
+
745
+	return 0;
746
+}
747
+
748
+static int sipStatusCodes_handler(struct sip_snmp_obj *o, enum handler_op op)
749
+{
750
+	register struct stats_s *c;
751
+	register unsigned long total;
752
+	register int i;
753
+	const char *func = __FUNCTION__;
754
+
755
+	if(!o) {
756
+		LOG(L_ERR, "%s: Invalid sip SNMP object passed\n", func);
757
+		return -1;
758
+	}
759
+
760
+	if(!global_stats || stats_segments == -1) {
761
+		LOG(L_ERR, "%s: Can't collect stats, they have not been initialized\n",
762
+			func);
763
+		return -1;
764
+	}
765
+
766
+	if(op != SER_GET) {
767
+		LOG(L_ERR, "%s: Invalid handler operation passed\n", func);
768
+		return -1;
769
+	}
770
+
771
+	if(!o->value.integer) {
772
+		o->value.integer = calloc(1, sizeof(unsigned long));
773
+		if(!o->value.integer) {
774
+			LOG(L_ERR, "%s: %s\n", func, strerror(errno));
775
+			return -1;
776
+		}
777
+	}
778
+
779
+	c = global_stats;
780
+	total = 0;
781
+	switch(o->col) {
782
+		case COLUMN_SIPSTATSINFOCLASSINS:
783
+			collect_this_stat(received_responses_1, total, c);
784
+			break;
785
+		case COLUMN_SIPSTATSINFOCLASSOUTS:
786
+			collect_this_stat(sent_responses_1, total, c);
787
+			break;
788
+		case COLUMN_SIPSTATSSUCCESSCLASSINS:
789
+			collect_this_stat(received_responses_2, total, c);
790
+			break;
791
+		case COLUMN_SIPSTATSSUCCESSCLASSOUTS:
792
+			collect_this_stat(sent_responses_2, total, c);
793
+			break;
794
+		case COLUMN_SIPSTATSREDIRCLASSINS:
795
+			collect_this_stat(received_responses_3, total, c);
796
+			break;
797
+		case COLUMN_SIPSTATSREDIRCLASSOUTS:
798
+			collect_this_stat(sent_responses_3, total, c);
799
+			break;
800
+		case COLUMN_SIPSTATSREQFAILCLASSINS:
801
+			collect_this_stat(received_responses_4, total, c);
802
+			break;
803
+		case COLUMN_SIPSTATSREQFAILCLASSOUTS:
804
+			collect_this_stat(sent_responses_4, total, c);
805
+			break;
806
+		case COLUMN_SIPSTATSSERVERFAILCLASSINS:
807
+			collect_this_stat(received_responses_5, total, c);
808
+			break;
809
+		case COLUMN_SIPSTATSSERVERFAILCLASSOUTS:
810
+			collect_this_stat(sent_responses_5, total, c);
811
+			break;
812
+		case COLUMN_SIPSTATSGLOBALFAILCLASSINS:
813
+			collect_this_stat(received_responses_6, total, c);
814
+			break;
815
+		case COLUMN_SIPSTATSGLOBALFAILCLASSOUTS:
816
+			collect_this_stat(sent_responses_6, total, c);
817
+			break;
818
+		case COLUMN_SIPSTATSOTHERCLASSESINS:
819
+			collect_this_stat(received_responses_other, total, c);
820
+			break;
821
+		case COLUMN_SIPSTATSOTHERCLASSESOUTS:
822
+			/* FIXME: For some reason this is not defined in
823
+			 * struct stats_s... */
824
+			/* collect_this_stat(sent_responses_other, total, c); */
825
+			total = 0;
826
+			break;
827
+	}
828
+
829
+	*o->value.integer = total;
830
+	o->val_len = sizeof(unsigned long);
831
+	o->type = SER_COUNTER;
832
+
833
+	return 0;
834
+}
835
+
836
+#endif
... ...
@@ -36,6 +36,7 @@
36 36
 
37 37
 #define         _statusline(class, dir )       case class: stats->dir##_responses_##class++; break;
38 38
 
39
+/* FIXME: Don't have case for _other (see received_responses_other) */
39 40
 #define _update_response( statusclass, dir )		\
40 41
         { if (stat_file!=NULL)                          \
41 42
                 switch( statusclass ) {                 \
... ...
@@ -84,7 +85,7 @@ struct stats_s {
84 85
 	received_requests_bye,
85 86
 	received_requests_other,
86 87
 
87
-	received_responses_1, 		/* received_requests */
88
+	received_responses_1, 		/* received_responses */
88 89
 	received_responses_2,
89 90
 	received_responses_3,
90 91
 	received_responses_4,
... ...
@@ -92,7 +93,7 @@ struct stats_s {
92 93
 	received_responses_6,
93 94
 	received_responses_other,
94 95
 
95
-	received_drops, 		/* all messages we received and did not process
96
+	received_drops,	/* all messages we received and did not process
96 97
 					   successfully; reasons include SIP sanity checks 
97 98
 					   (missing Vias, neither request nor response, 
98 99
 					   failed parsing), ser errors (malloc, action
... ...
@@ -115,6 +116,7 @@ struct stats_s {
115 116
 	sent_responses_4,
116 117
 	sent_responses_5,
117 118
 	sent_responses_6,
119
+	/* FIXME: Don't want sent_responses_other?? */
118 120
 
119 121
 	processed_requests,
120 122
 	processed_responses,
... ...
@@ -122,18 +124,17 @@ struct stats_s {
122 124
 	acc_res_time,
123 125
 
124 126
 	failed_on_send;			
125
-			  
126 127
 };
127 128
 
128
-
129 129
 extern struct stats_s *stats;
130
+extern char *stat_file;
130 131
 
132
+int init_stats( int nr_of_processes );
131 133
 void setstats( int child_index );
132
-void dump_statistic( FILE *fp, struct stats_s *istats );
133 134
 int dump_all_statistic();
134
-int init_stats( int nr_of_processes );
135
-
136
-
135
+int dump_statistic(FILE *fp, struct stats_s *istats, int printheader);
136
+/* Registers handlers with SNMP module */
137
+int stats_register(); 
137 138
 
138 139
 #endif
139 140
 #endif