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