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