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