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