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