backup
[lcr.git] / main.c
1 /*****************************************************************************\
2 **                                                                           **
3 ** Linux Call Router                                                         **
4 **                                                                           **
5 **---------------------------------------------------------------------------**
6 ** Copyright: Andreas Eversberg                                              **
7 **                                                                           **
8 ** Main function                                                             **
9 **                                                                           **
10 \*****************************************************************************/ 
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15 #include <sys/types.h>
16 #include <sys/wait.h>
17 #include <sys/stat.h>
18 #include <unistd.h>
19 #include <signal.h>
20 #include <stdarg.h>
21 #include <fcntl.h>
22 #include <sys/ioctl.h>
23 #include <sys/file.h>
24 #include <errno.h>
25 #include <sys/mman.h>
26 #include <sys/resource.h>
27 #include "main.h"
28
29 MESSAGES
30
31 double now_d, last_d;
32 time_t now;
33 struct tm *now_tm;
34 struct timeval now_tv;
35 struct timezone now_tz;
36 #define GET_NOW() \
37         { \
38                 gettimeofday(&now_tv, &now_tz); \
39                 now_d = ((double)(now_tv.tv_usec))/1000000 + now_tv.tv_sec; \
40                 now = now_tv.tv_sec; \
41                 now_tm = localtime(&now); \
42         }
43
44 int global_debug = 0;
45 int quit=0;
46
47 #if 0
48 struct lcr_fdset lcr_fdset[FD_SETSIZE];
49 #endif
50
51 pthread_mutex_t mutexd; // debug output mutex
52 //pthread_mutex_t mutext; // trace output mutex
53 pthread_mutex_t mutexe; // error output mutex
54
55 int memuse = 0;
56 int mmemuse = 0;
57 int cmemuse = 0;
58 int ememuse = 0;
59 int pmemuse = 0;
60 int amemuse = 0;
61 int rmemuse = 0;
62 int classuse = 0;
63 int fduse = 0;
64 int fhuse = 0;
65
66 char *debug_prefix = 0;
67 int debug_count = 0;
68 int last_debug = 0;
69 int debug_newline = 1;
70 int nooutput = 0;
71
72 void debug_usleep(int msec, char *file, int line, int hour, int min, int sec)
73 {
74         usleep(msec);
75 }
76
77 void debug(const char *function, int line, char *prefix, char *buffer)
78 {
79         /* if we have a new debug count, we add a mark */
80         if (last_debug != debug_count)
81         {
82                 last_debug = debug_count;
83                 if (!nooutput)
84                         printf("\033[34m--------------------- %04d.%02d.%02d %02d:%02d:%02d %06d\033[36m\n", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, debug_count%1000000);
85                 if (options.deb&DEBUG_LOG && global_debug)
86                         dprint(DBGM_MAN, 0, "--------------------- %04d.%02d.%02d %02d:%02d:%02d %06d\n", now_tm->tm_year+1900, now_tm->tm_mon+1, now_tm->tm_mday, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec, debug_count%1000000);
87         }
88
89         if (!nooutput)
90         {
91                 if (debug_newline)
92                         printf("\033[32m%06d %s\033[37m%s", debug_count%1000000, prefix?prefix:"", prefix?" ":"");
93                 if (function)
94                         printf("(in %s() line %d): %s", function, line, buffer);
95                 else
96                         printf("%s", buffer);
97         }
98
99         if (options.deb&DEBUG_LOG && global_debug)
100         {
101                 if (debug_newline)
102                 {
103                         if (function)
104                                 dprint(DBGM_MAN, 0, "%s%s(in %s() line %d): %s", prefix?prefix:"", prefix?" ":"", function, line, buffer);
105                         else
106                                 dprint(DBGM_MAN, 0, "%s%s: %s", prefix?prefix:"", prefix?" ":"", buffer);
107                 }
108         }
109
110         debug_newline = 0;
111         if (buffer[0])
112                 if (buffer[strlen(buffer)-1] == '\n')
113                         debug_newline = 1;
114 }
115
116
117 void _printdebug(const char *function, int line, unsigned long mask, const char *fmt, ...)
118 {
119         char buffer[4096];
120         va_list args;
121
122         if (!(options.deb & mask))
123                 return;
124         pthread_mutex_lock(&mutexd);
125
126         va_start(args,fmt);
127         VUNPRINT(buffer,sizeof(buffer)-1,fmt,args);
128         buffer[sizeof(buffer)-1]=0;
129         va_end(args);
130
131         debug(function, line, debug_prefix, buffer);
132
133         pthread_mutex_unlock(&mutexd);
134 }
135
136 void _printerror(const char *function, int line, const char *fmt, ...)
137 {
138         char buffer[4096];
139         va_list args;
140
141         pthread_mutex_lock(&mutexe);
142
143         va_start(args,fmt);
144         VUNPRINT(buffer,sizeof(buffer)-1,fmt,args);
145         buffer[sizeof(buffer)-1]=0;
146         va_end(args);
147
148         if (options.deb)
149                 debug(function, line, "ERROR", buffer);
150         else /* only if we do not debug */
151         {
152                 if (function)
153                         fprintf(stderr, "ERROR (in %s() line %d) %s", function, line, buffer);
154                 else
155                         fprintf(stderr, "ERROR %s", buffer);
156         }
157
158         pthread_mutex_unlock(&mutexe);
159 }
160
161
162 void sighandler(int sigset)
163 {
164         struct sched_param schedp;
165
166         if (sigset == SIGHUP)
167                 return;
168         if (sigset == SIGPIPE)
169                 return;
170         if (!quit)
171         {
172                 quit=1;
173                 /* set scheduler & priority */
174                 if (options.schedule > 1)
175                 {
176                         memset(&schedp, 0, sizeof(schedp));
177                         schedp.sched_priority = 0;
178                         sched_setscheduler(0, SCHED_OTHER, &schedp);
179                 }
180                 fprintf(stderr, "LCR: Signal received: %d\n", sigset);
181                 PERROR("Signal received: %d\n", sigset);
182         }
183 }
184
185
186 /*
187  * the main
188  */
189 int main(int argc, char *argv[])
190 {
191         int                     ret = -1;
192         int                     lockfd = -1; /* file lock */
193         struct message          *message;
194         class Port              *port;
195         class Endpoint          *epoint;
196         class Join              *join;
197         int                     i;
198         int                     all_idle;
199         char                    prefix_string[64];
200         struct sched_param      schedp;
201         char                    *debug_prefix = "alloc";
202         int                     created_mutexd = 0,/* created_mutext = 0,*/ created_mutexe = 0,
203                                 created_lock = 0, created_signal = 0, created_debug = 0;
204         int                     idletime = 0, idlecheck = 0;
205         char                    tracetext[256];
206
207 #if 0
208         /* init fdset */
209         memset(lcr_fdset, 0, sizeof(lcr_fdset));
210 #endif
211
212         /* current time */
213         GET_NOW();
214
215         /* show version */
216         printf("\n** %s  Version %s\n\n", NAME, VERSION_STRING);
217
218         /* show options */
219         if (argc <= 1)
220         {
221                 usage:
222                 printf("\n");
223                 printf("Usage: lcr (query | start | fork | rules | route)\n");
224                 printf("query     = Show available isdn ports.\n");
225                 printf("start     = Run lcr normally, abort with CTRL+C.\n");
226                 printf("fork      = Do daemon fork and run as background process.\n");
227                 printf("interface = Get help of available interface syntax.\n");
228                 printf("rules     = Get help of available routing rule syntax.\n");
229                 printf("rules [action] = Get individual help for given action.\n");
230 //              printf("route = Show current routing as it is parsed.\n");
231                 printf("\n");
232                 ret = 999;
233                 goto free;
234         }
235
236         /* init crc */
237         crc_init();
238
239         /* check for root (real or effective) */
240         if (getuid() && geteuid())
241         {
242                 fprintf(stderr, "Please run %s as super-user.\n", NAME);
243                 goto free;
244         }
245
246         /* the mutex init */
247         if (pthread_mutex_init(&mutexd, NULL))
248         {
249                 fprintf(stderr, "cannot create 'PDEBUG' mutex\n");
250                 goto free;
251         }
252         created_mutexd = 1;
253 //      if (pthread_mutex_init(&mutext, NULL))
254 //      {
255 //              fprintf(stderr, "cannot create 'trace' mutex\n");
256 //              goto free;
257 //      }
258 //      created_mutext = 1;
259         if (pthread_mutex_init(&mutexe, NULL))
260         {
261                 fprintf(stderr, "cannot create 'PERROR' mutex\n");
262                 goto free;
263         }
264         created_mutexe = 1;
265
266         /* show interface */
267         if (!(strcasecmp(argv[1],"interface")))
268         {
269                 doc_interface();
270                 ret = 0;
271                 goto free;
272         }
273
274         /* show rules */
275         if (!(strcasecmp(argv[1],"rules")))
276         {
277                 if (argc <= 2)
278                         doc_rules(NULL);
279                 else
280                         doc_rules(argv[2]);
281                 ret = 0;
282                 goto free;
283         }
284
285         /* query available isdn ports */
286         if (!(strcasecmp(argv[1],"query")))
287         {
288                 mISDN_port_info();
289                 ret = 0;
290                 goto free;
291         }
292
293         /* read options */
294         if (read_options() == 0)
295                 goto free;
296
297         /* init mISDN */
298         if (mISDN_initialize() < 0)
299                 goto free;
300         created_debug = 1;
301
302         /* read ruleset(s) */
303         if (!(ruleset_first = ruleset_parse()))
304                 goto free;
305
306         /* set pointer to main ruleset */
307         ruleset_main = getrulesetbyname("main");
308         if (!ruleset_main)
309         {
310                 fprintf(stderr, "\n***\n -> Missing 'main' ruleset, causing ALL calls to be disconnected.\n***\n\n");
311                 PDEBUG(DEBUG_LOG, "Missing 'main' ruleset, causing ALL calls to be disconnected.\n");
312                 sleep(2);
313         }
314
315 #if 0
316         /* query available isdn ports */
317         if (!(strcasecmp(argv[1],"route")))
318         {
319                 ruleset_debug(ruleset_first);
320                 ret = 0;
321                 goto free;
322         }
323 #endif
324
325         /* do fork in special cases */
326         if (!(strcasecmp(argv[1],"fork")))
327         {
328                 pid_t pid;
329
330                 /* do daemon fork */
331                 pid = fork();
332
333                 if (pid < 0)
334                 {
335                         fprintf(stderr, "Cannot fork!\n");
336                         goto free;
337                 }
338                 if (pid != 0)
339                 {
340                         exit(0);
341                 }
342                 usleep(200000);
343                 printf("\n");
344                 
345                 /* do second fork */
346                 pid = fork();
347
348                 if (pid < 0)
349                 {
350                         fprintf(stderr, "Cannot fork!\n");
351                         goto free;
352                 }
353                 if (pid != 0)
354                 {
355                         printf("LCR: Starting daemon.\n");
356                         exit(0);
357                 }
358                 nooutput = 1;
359         } else
360         /* if not start */
361         if (!!strcasecmp(argv[1],"start"))
362         {
363                 goto usage;
364         }
365
366         /* create lock and lock! */
367         if ((lockfd = open("/var/run/lcr.lock", O_CREAT, 0)) < 0)
368         {
369                 fprintf(stderr, "Cannot create lock file: /var/run/lcr.lock\n");
370                 goto free;
371         }
372         if (flock(lockfd, LOCK_EX|LOCK_NB) < 0)
373         {
374                 if (errno == EWOULDBLOCK)
375                         fprintf(stderr, "LCR: Another LCR process is running. Please kill the other one.\n");
376                 else    fprintf(stderr, "Locking process failed: errno=%d\n", errno);
377                 goto free;
378         }
379         created_lock = 1;
380
381         /* initialize admin socket */
382         if (admin_init())
383         {
384                 fprintf(stderr, "Unable to initialize admin socket.\n");
385                 goto free;
386         }
387
388         /* generate alaw / ulaw tables */
389         generate_tables(options.law);
390
391         /* load tones (if requested) */
392         if (fetch_tones() == 0)
393         {
394                 fprintf(stderr, "Unable to fetch tones into memory.\n");
395                 goto free;
396         }
397
398         /* read interfaces and open ports */
399         if (!read_interfaces())
400         {
401                 PERROR_RUNTIME("No interfaces specified or failed to parse interface.conf.\n");
402                 fprintf(stderr, "No interfaces specified or failed to parse interface.conf.\n");
403                 goto free;
404         }
405         relink_interfaces();
406         interface_first = interface_newlist;
407         interface_newlist = NULL;
408         
409         /* locking memory paging */
410         i = 0;
411         while(i < 10)
412         {
413                 if (mlockall(MCL_CURRENT | MCL_FUTURE) >= 0)
414                         break;
415                 usleep(200000);
416                 i++;
417         }
418         if (i == 10)
419         {
420                 switch(errno)
421                 {
422                         case ENOMEM:
423                         fprintf(stderr, "Not enough memory to lock paging, exitting...\n");
424                         break;
425                         case EPERM:
426                         fprintf(stderr, "No permission to lock paging, exitting...\n");
427                         break;
428                         case EFAULT:
429                         fprintf(stderr, "'Bad address' while locking paging, exitting...\n");
430                         break;
431                         default:
432                         fprintf(stderr, "Unknown error %d while locking paging, exitting...\n", errno);
433                 }
434                 goto free;
435         }
436
437         /* set real time scheduler & priority */
438         if (options.schedule > 1)
439         {
440                 memset(&schedp, 0, sizeof(schedp));
441                 schedp.sched_priority = options.schedule;
442                 ret = sched_setscheduler(0, SCHED_RR, &schedp);
443                 if (ret < 0)
444                 {
445                         PERROR("Scheduling failed with given priority %d (errno = %d).\nCheck options.conf 'schedule', exitting...\n", options.schedule, errno);
446                         goto free;
447                 }
448         }
449
450         /* signal handlers */   
451         signal(SIGINT,sighandler);
452         signal(SIGHUP,sighandler);
453         signal(SIGTERM,sighandler);
454         signal(SIGPIPE,sighandler);
455         created_signal = 1;
456
457         /*** main loop ***/
458         SPRINT(tracetext, "%s %s started, waiting for calls...", NAME, VERSION_STRING);
459         start_trace(0, NULL, NULL, NULL, 0, 0, 0, tracetext);
460         printf("%s\n", tracetext);
461         end_trace();
462         GET_NOW();
463         quit = 0;
464         while(!quit)
465         {
466                 last_d = now_d;
467                 GET_NOW();
468                 if (now_d-last_d > 1.0)
469                 {
470                         PERROR("LCR was stalling %d.%d seconds\n", ((int)((now_d-last_d)*10.0))/10, (int)((now_d-last_d)*10.0));
471                 }
472                 /* all loops must be counted from the beginning since nodes might get freed during handler */
473                 all_idle = 1;
474
475 #warning debugging usleep crash
476                 debug_usleep(1, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
477
478                 /* handle mISDN messages from kernel */
479                 debug_prefix = "ISDN";
480                 if (mISDN_handler())
481                         all_idle = 0;
482 #warning debugging usleep crash
483                 debug_usleep(1, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
484
485 BUDETECT
486
487                 /* loop through all port ports and call their handler */
488                 port_again:
489                 port = port_first;
490                 while(port)
491                 {
492                         debug_prefix = port->p_name;
493                         debug_count++;
494                         ret = port->handler();
495                         if (ret)
496                                 all_idle = 0;
497                         if (ret < 0) /* port has been destroyed */
498                                 goto port_again;
499                         port = port->next;
500                 }
501
502                 /* loop through all epoint and call their handler */
503                 epoint_again:
504                 epoint = epoint_first;
505                 while(epoint)
506                 {
507                         debug_prefix = prefix_string;
508                         SPRINT(prefix_string, "ep%ld", epoint->ep_serial);
509                         debug_count++;
510                         ret = epoint->handler();
511                         if (ret)
512                                 all_idle = 0;
513                         if (ret < 0) /* epoint has been destroyed */
514                                 goto epoint_again;
515                         epoint = epoint->next;
516                 }
517
518                 /* loop through all joins and call their handler */
519                 join_again:
520                 join = join_first;
521                 while(join)
522                 {
523                         debug_prefix = "join";
524                         debug_count++;
525                         ret = join->handler();
526                         if (ret)
527                                 all_idle = 0;
528                         if (ret < 0) /* join has been destroyed */
529                                 goto join_again;
530                         join = join->next;
531                 }
532
533                 debug_prefix = 0;
534
535                 /* process any message */
536                 debug_count++;
537                 debug_prefix = "message";
538                 while ((message = message_get()))
539                 {
540                         all_idle = 0;
541                         switch(message->flow)
542                         {
543                                 case PORT_TO_EPOINT:
544                                 debug_prefix = "msg port->epoint";
545                                 epoint = find_epoint_id(message->id_to);
546                                 if (epoint)
547                                 {
548                                         if (epoint->ep_app)
549                                         {
550                                                 epoint->ep_app->ea_message_port(message->id_from, message->type, &message->param);
551                                         } else
552                                         {
553                                                 PDEBUG(DEBUG_MSG, "Warning: message %s from port %d to endpoint %d. endpoint doesn't have an application.\n", messages_txt[message->type], message->id_from, message->id_to);
554                                         }
555                                 } else
556                                 {
557                                         PDEBUG(DEBUG_MSG, "Warning: message %s from port %d to endpoint %d. endpoint doesn't exist anymore.\n", messages_txt[message->type], message->id_from, message->id_to);
558                                 }
559                                 break;
560
561                                 case EPOINT_TO_JOIN:
562                                 debug_prefix = "msg epoint->join";
563                                 join = find_join_id(message->id_to);
564                                 if (join)
565                                 {
566                                         join->message_epoint(message->id_from, message->type, &message->param);
567                                 } else
568                                 {
569                                         PDEBUG(DEBUG_MSG, "Warning: message %s from endpoint %d to join %d. join doesn't exist anymore\n", messages_txt[message->type], message->id_from, message->id_to);
570                                 }
571                                 break;
572
573                                 case JOIN_TO_EPOINT:
574                                 debug_prefix = "msg join->epoint";
575                                 epoint = find_epoint_id(message->id_to);
576                                 if (epoint)
577                                 {
578                                         if (epoint->ep_app)
579                                         {
580                                                 epoint->ep_app->ea_message_join(message->id_from, message->type, &message->param);
581                                         } else
582                                         {
583                                                 PDEBUG(DEBUG_MSG, "Warning: message %s from join %d to endpoint %d. endpoint doesn't have an application.\n", messages_txt[message->type], message->id_from, message->id_to);
584                                         }
585                                 } else
586                                 {
587                                         PDEBUG(DEBUG_MSG, "Warning: message %s from join %d to endpoint %d. endpoint doesn't exist anymore.\n", messages_txt[message->type], message->id_from, message->id_to);
588                                 }
589                                 break;
590
591                                 case EPOINT_TO_PORT:
592                                 debug_prefix = "msg epoint->port";
593                                 port = find_port_id(message->id_to);
594                                 if (port)
595                                 {
596                                         port->message_epoint(message->id_from, message->type, &message->param);
597 BUDETECT
598                                 } else
599                                 {
600                                         PDEBUG(DEBUG_MSG, "Warning: message %s from endpoint %d to port %d. port doesn't exist anymore\n", messages_txt[message->type], message->id_from, message->id_to);
601                                 }
602                                 break;
603
604                                 default:
605                                 PERROR("Message flow %d unknown.\n", message->flow);
606                         }
607                         message_free(message);
608                         debug_count++;
609                         debug_prefix = "message";
610                 }
611 BUDETECT
612
613                 /* handle socket */
614                 if (admin_handle())
615                         all_idle = 0;
616 BUDETECT
617
618 #if 0
619                 /* check for child to exit (eliminate zombies) */
620                 if (waitpid(-1, NULL, WNOHANG) > 0)
621                 {
622                         PDEBUG(DEBUG_EPOINT, "a child process (created by endpoint) has exitted.\n");
623                         all_idle = 0;
624                 }
625 #endif
626 #warning debugging usleep crash
627                 debug_usleep(1, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
628
629                 /* do idle checking */
630                 if (idlecheck != now)
631                 {
632                         PDEBUG(DEBUG_IDLETIME, "Idle time : %d%%\n", idletime/10000);
633                         idletime = 0;
634                         idlecheck = now;
635                 }
636
637                 /* did we do nothing? so we wait to give time to other processes */
638                 if (all_idle)
639                 {
640                         debug_usleep(4000, __FILE__, __LINE__, now_tm->tm_hour, now_tm->tm_min, now_tm->tm_sec);
641                         idletime += 4000;
642                 }
643         }
644         SPRINT(tracetext, "%s terminated", NAME);
645         printf("%s\n", tracetext);
646         start_trace(0, NULL, NULL, NULL, 0, 0, 0, tracetext);
647         if (ret)
648                 add_trace("error", NULL, "%d", ret);
649         end_trace();
650         ret=0;
651
652         /* free all */
653 free:
654
655
656         /* set scheduler & priority
657          */
658         if (options.schedule > 1)
659         {
660                 memset(&schedp, 0, sizeof(schedp));
661                 schedp.sched_priority = 0;
662                 sched_setscheduler(0, SCHED_OTHER, &schedp);
663         }
664         /* reset signals */
665         if (created_signal)
666         {
667                 signal(SIGINT,SIG_DFL);
668                 signal(SIGHUP,SIG_DFL);
669                 signal(SIGTERM,SIG_DFL);
670                 signal(SIGPIPE,SIG_DFL);
671         }
672
673         /* destroy objects */
674         debug_prefix = "free";
675
676         while(port_first)
677         {
678                 debug_count++;
679                 delete port_first;
680         }
681         while(epoint_first)
682         {
683                 debug_count++;
684                 delete epoint_first;
685         }
686         epoint_first = NULL;
687         debug_count++;
688         join_free();
689
690         /* free interfaces */
691         if (interface_first)
692                 free_interfaces(interface_first);
693         interface_first = NULL;
694
695         /* close isdn ports */
696         mISDNport_close_all();
697
698         /* flush messages */
699         debug_count++;
700         i = 0;
701         while ((message = message_get()))
702         {
703                 i++;
704                 message_free(message);
705         }
706         if (i)
707         {
708                 PDEBUG(DEBUG_MSG, "freed %d pending messages\n", i);
709         }
710
711         /* free tones */
712         if (toneset_first)
713                 free_tones();
714
715         /* free admin socket */
716         admin_cleanup();
717
718         /* close lock */
719         if (created_lock)
720                 flock(lockfd, LOCK_UN);
721         if (lockfd >= 0)
722                 close(lockfd);
723
724         /* free rulesets */
725         if (ruleset_first)
726                 ruleset_free(ruleset_first);
727         ruleset_first = NULL;
728
729         /* free mutex */
730         if (created_mutexe)
731                 if (pthread_mutex_destroy(&mutexe))
732                         fprintf(stderr, "cannot destroy 'PERROR' mutex\n");
733 //      if (created_mutext)
734 //              if (pthread_mutex_destroy(&mutext))
735 //                      fprintf(stderr, "cannot destroy 'trace' mutex\n");
736         if (created_mutexd)
737                 if (pthread_mutex_destroy(&mutexd))
738                         fprintf(stderr, "cannot destroy 'PDEBUG' mutex\n");
739
740         /* deinitialize mISDN */
741         mISDN_deinitialize();
742         global_debug = 0;
743
744         /* display memory leak */
745 #define MEMCHECK(a, b) \
746         if (b) \
747         { \
748                 SPRINT(tracetext, a, NAME); \
749                 start_trace(0, NULL, NULL, NULL, 0, 0, 0, tracetext); \
750                 if (ret) add_trace("blocks", NULL, "%d", b); \
751                 end_trace(); \
752                 printf("\n******************************\n\007"); \
753                 printf("\nERROR: %d %s\n", b, a); \
754                 printf("\n******************************\n"); \
755                 ret = -1; \
756         }
757         MEMCHECK("",memuse)
758         MEMCHECK("memory block(s) left (port.cpp ...)",pmemuse)
759         MEMCHECK("memory block(s) left (epoint*.cpp ...)",ememuse)
760         MEMCHECK("memory block(s) left (join*.cpp)",cmemuse)
761         MEMCHECK("memory block(s) left (message.c)",mmemuse)
762         MEMCHECK("memory block(s) left (route.c)",rmemuse)
763         MEMCHECK("memory block(s) left (args)",amemuse)
764         MEMCHECK("class(es) left",classuse)
765         MEMCHECK("file descriptor(s) left",fduse)
766         MEMCHECK("file handler(s) left",fhuse)
767
768         /* take me out */
769         return(ret);
770 }
771
772
773 #ifdef BUDETECT_DEF
774 /* special debug function to detect buffer overflow
775  */
776 int budetect_stop = 0;
777 void budetect(const char *file, int line, char *function)
778 {
779         if (budetect_stop)
780                 return;
781         /* modify this function to detect race-bugs */
782 #warning DID YOU MODIFY THIS FUNCTION TO DETECT THE BUFFER OVERFLOW BUG?
783         class Port *port;
784         class PmISDN *pmisdn;
785         struct mISDNport *mISDNport = mISDNport_first;
786         int i, ii;
787
788         while(mISDNport)
789         {
790                 i = 0;
791                 ii = mISDNport->b_num;
792                 while(i < ii)
793                 {
794                         if (mISDNport->b_port[i])
795                         {
796                                 port = port_first;
797                                 while(port)
798                                 {
799                                         if ((port->p_type&PORT_CLASS_MASK) == PORT_CLASS_ISDN)
800                                         {
801                                                 pmisdn = (class PmISDN *)port;
802                                                 if (pmisdn->p_isdn_crypt_listen)
803                                                 {
804                                                         PERROR_RUNTIME("************************************************\n");
805                                                         PERROR_RUNTIME("** BUG detected in %s, line %d, function %s\n", file, line, function);
806                                                         PERROR_RUNTIME("** p_isdn_crypt_listen = %d\n", pmisdn->p_isdn_crypt_listen);
807                                                         PERROR_RUNTIME("************************************************\n");
808                                                         budetect_stop = 1;
809                                                 }
810                                         }
811                                         if (port == mISDNport->b_port[i])
812                                                 break;
813                                         port = port->next;
814                                         if (!port)
815                                         {
816                                                 PERROR_RUNTIME("************************************************\n");
817                                                 PERROR_RUNTIME("** BUG detected in %s, line %d, function %s\n", file, line, function);
818                                                 PERROR_RUNTIME("** b_port not in list.\n");
819                                                 PERROR_RUNTIME("************************************************\n");
820                                                 budetect_stop = 1;
821                                         }
822                                 }
823                         }
824                         i++;
825                 }
826                 mISDNport = mISDNport->next;
827         }
828
829 }
830 #endif
831