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