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