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