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