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