alpha phase is open, this means:
[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 Join              *join;
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, join_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 = 999;
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 joins and call their handler */
531                 join_again:
532                 join = join_first;
533                 while(join)
534                 {
535                         debug_prefix = "join";
536                         debug_count++;
537                         ret = join->handler();
538                         if (ret)
539                                 all_idle = 0;
540                         if (ret < 0) /* join has been destroyed */
541                                 goto join_again;
542                         join = join->next;
543                 }
544 #ifdef DEBUG_DURATION
545                 GET_NOW();
546                 join_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_JOIN:
579                                 debug_prefix = "msg epoint->join";
580                                 join = find_join_id(message->id_to);
581                                 if (join)
582                                 {
583                                         join->message_epoint(message->id_from, message->type, &message->param);
584                                 } else
585                                 {
586                                         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);
587                                 }
588                                 break;
589
590                                 case JOIN_TO_EPOINT:
591                                 debug_prefix = "msg join->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_join(message->id_from, message->type, &message->param);
598                                         } else
599                                         {
600                                                 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);
601                                         }
602                                 } else
603                                 {
604                                         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);
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 Join:%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)(join_duration*100),
674                                 (int)(message_duration*100),
675                                 (int)(admin_duration*100));
676                         idle_duration = isdn_duration = port_duration = epoint_duration = join_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         SPRINT(tracetext, "%s terminated", NAME);
690         printf("%s\n", tracetext);
691         start_trace(0, NULL, NULL, NULL, 0, 0, 0, tracetext);
692         if (ret)
693                 add_trace("error", NULL, "%d", ret);
694         end_trace();
695         ret=0;
696
697         /* free all */
698 free:
699
700
701         /* set scheduler & priority
702          */
703         if (options.schedule > 1)
704         {
705                 memset(&schedp, 0, sizeof(schedp));
706                 schedp.sched_priority = 0;
707                 sched_setscheduler(0, SCHED_OTHER, &schedp);
708         }
709         /* reset signals */
710         if (created_signal)
711         {
712                 signal(SIGINT,SIG_DFL);
713                 signal(SIGHUP,SIG_DFL);
714                 signal(SIGTERM,SIG_DFL);
715                 signal(SIGPIPE,SIG_DFL);
716         }
717
718         /* destroy objects */
719         debug_prefix = "free";
720
721         while(port_first)
722         {
723                 debug_count++;
724                 delete port_first;
725         }
726         while(epoint_first)
727         {
728                 debug_count++;
729                 delete epoint_first;
730         }
731         epoint_first = NULL;
732         debug_count++;
733         join_free();
734
735         /* free interfaces */
736         if (interface_first)
737                 free_interfaces(interface_first);
738         interface_first = NULL;
739
740         /* close isdn ports */
741         mISDNport_close_all();
742
743         /* flush messages */
744         debug_count++;
745         i = 0;
746         while ((message = message_get()))
747         {
748                 i++;
749                 message_free(message);
750         }
751         if (i)
752         {
753                 PDEBUG(DEBUG_MSG, "freed %d pending messages\n", i);
754         }
755
756         /* free tones */
757         if (toneset_first)
758                 free_tones();
759
760         /* free admin socket */
761         admin_cleanup();
762
763         /* close lock */
764         if (created_lock)
765                 flock(lockfd, LOCK_UN);
766         if (lockfd >= 0)
767                 close(lockfd);
768
769         /* free rulesets */
770         if (ruleset_first)
771                 ruleset_free(ruleset_first);
772         ruleset_first = NULL;
773
774         /* free mutex */
775         if (created_mutexe)
776                 if (pthread_mutex_destroy(&mutexe))
777                         fprintf(stderr, "cannot destroy 'PERROR' mutex\n");
778 //      if (created_mutext)
779 //              if (pthread_mutex_destroy(&mutext))
780 //                      fprintf(stderr, "cannot destroy 'trace' mutex\n");
781         if (created_mutexd)
782                 if (pthread_mutex_destroy(&mutexd))
783                         fprintf(stderr, "cannot destroy 'PDEBUG' mutex\n");
784
785         /* close debug */
786         if (created_debug)
787                 debug_close();
788         global_debug = 0;
789
790         /* display memory leak */
791 #define MEMCHECK(a, b) \
792         if (b) \
793         { \
794                 SPRINT(tracetext, a, NAME); \
795                 start_trace(0, NULL, NULL, NULL, 0, 0, 0, tracetext); \
796                 if (ret) add_trace("blocks", NULL, "%d", b); \
797                 end_trace(); \
798                 printf("\n******************************\n\007"); \
799                 printf("\nERROR: %d %s\n", b, a); \
800                 printf("\n******************************\n"); \
801                 ret = -1; \
802         }
803         MEMCHECK("",memuse)
804         MEMCHECK("memory block(s) left (port.cpp ...)",pmemuse)
805         MEMCHECK("memory block(s) left (epoint*.cpp ...)",ememuse)
806         MEMCHECK("memory block(s) left (join*.cpp)",cmemuse)
807         MEMCHECK("memory block(s) left (message.c)",mmemuse)
808         MEMCHECK("memory block(s) left (route.c)",rmemuse)
809         MEMCHECK("memory block(s) left (args)",amemuse)
810         MEMCHECK("class(es) left",classuse)
811         MEMCHECK("file descriptor(s) left",fduse)
812         MEMCHECK("file handler(s) left",fhuse)
813
814         /* take me out */
815         return(ret);
816 }
817
818
819 #ifdef BUDETECT_DEF
820 /* special debug function to detect buffer overflow
821  */
822 int budetect_stop = 0;
823 void budetect(const char *file, int line, char *function)
824 {
825         if (budetect_stop)
826                 return;
827         /* modify this function to detect race-bugs */
828 #warning DID YOU MODIFY THIS FUNCTION TO DETECT THE BUFFER OVERFLOW BUG?
829         class Port *port;
830         class PmISDN *pmisdn;
831         struct mISDNport *mISDNport = mISDNport_first;
832         int i, ii;
833
834         while(mISDNport)
835         {
836                 i = 0;
837                 ii = mISDNport->b_num;
838                 while(i < ii)
839                 {
840                         if (mISDNport->b_port[i])
841                         {
842                                 port = port_first;
843                                 while(port)
844                                 {
845                                         if ((port->p_type&PORT_CLASS_MASK) == PORT_CLASS_ISDN)
846                                         {
847                                                 pmisdn = (class PmISDN *)port;
848                                                 if (pmisdn->p_isdn_crypt_listen)
849                                                 {
850                                                         PERROR_RUNTIME("************************************************\n");
851                                                         PERROR_RUNTIME("** BUG detected in %s, line %d, function %s\n", file, line, function);
852                                                         PERROR_RUNTIME("** p_isdn_crypt_listen = %d\n", pmisdn->p_isdn_crypt_listen);
853                                                         PERROR_RUNTIME("************************************************\n");
854                                                         budetect_stop = 1;
855                                                 }
856                                         }
857                                         if (port == mISDNport->b_port[i])
858                                                 break;
859                                         port = port->next;
860                                         if (!port)
861                                         {
862                                                 PERROR_RUNTIME("************************************************\n");
863                                                 PERROR_RUNTIME("** BUG detected in %s, line %d, function %s\n", file, line, function);
864                                                 PERROR_RUNTIME("** b_port not in list.\n");
865                                                 PERROR_RUNTIME("************************************************\n");
866                                                 budetect_stop = 1;
867                                         }
868                                 }
869                         }
870                         i++;
871                 }
872                 mISDNport = mISDNport->next;
873         }
874
875 }
876 #endif
877