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