2 * Copyright (c) 1997, 2001 Hellmuth Michaelis. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 *---------------------------------------------------------------------------
27 * i4b daemon - main program entry
28 * -------------------------------
32 * last edit-date: [Sat May 13 13:03:56 2006]
34 *---------------------------------------------------------------------------*/
39 #ifdef I4B_EXTERNAL_MONITOR
47 #ifdef I4B_EXTERNAL_MONITOR
49 #ifdef I4B_NOTCPIP_MONITOR
50 /* monitor via local socket */
51 static void mloop(int sockfd);
52 #else /* I4B_NOTCPIP_MONITOR */
53 /* monitor via local and tcp/ip socket */
54 static void mloop(int localsock, int remotesock);
55 #endif /* I4B_NOTCPIP_MONITOR */
57 #else /* I4B_EXTERNAL_MONITOR */
58 /* no monitoring at all */
60 #endif /* I4B_EXTERNAL_MONITOR */
63 static void kbdrdhdl(void);
66 static void isdnrdhdl(void);
67 static void usage(void);
69 #define MSG_BUF_SIZ 1024 /* message buffer size */
71 /*---------------------------------------------------------------------------*
72 * usage display and exit
73 *---------------------------------------------------------------------------*/
77 fprintf(stderr, "\n");
78 fprintf(stderr, "isdnd - i4b ISDN manager daemon, version %02d.%02d.%d\n", VERSION, REL, STEP);
80 fprintf(stderr, " usage: isdnd [-c file] [-d level] [-F] [-f [-r dev] [-t termtype]]\n");
82 fprintf(stderr, " usage: isdnd [-c file] [-F] [-f [-r dev] [-t termtype]]\n");
84 fprintf(stderr, " [-l] [-L file] [-m] [-s facility] [-u time]\n");
85 fprintf(stderr, " -c <filename> configuration file name (def: %s)\n", CONFIG_FILE_DEF);
87 fprintf(stderr, " -d <level> set debug flag bits:\n");
88 fprintf(stderr, " general = 0x%04x, rates = 0x%04x, timing = 0x%04x\n", DL_MSG, DL_RATES, DL_TIME);
89 fprintf(stderr, " state = 0x%04x, retry = 0x%04x, dial = 0x%04x\n", DL_STATE, DL_RCVRY, DL_DIAL);
90 fprintf(stderr, " process = 0x%04x, kernio = 0x%04x, ctrlstat = 0x%04x\n", DL_PROC, DL_DRVR, DL_CNST);
91 fprintf(stderr, " rc-file = 0x%04x, budget = 0x%04x, valid = 0x%04x\n", DL_RCCF, DL_BDGT, DL_VALID);
92 fprintf(stderr, " -dn no debug output on fullscreen display\n");
94 fprintf(stderr, " -f fullscreen status display\n");
95 fprintf(stderr, " -F do not become a daemon process\n");
96 fprintf(stderr, " -l use a logfile instead of syslog\n");
97 fprintf(stderr, " -L <file> use file instead of %s for logging\n", LOG_FILE_DEF);
98 fprintf(stderr, " -P pretty print real config to stdout and exit\n");
99 fprintf(stderr, " -r <device> redirect output to other device (for -f)\n");
100 fprintf(stderr, " -s <facility> use facility instead of %d for syslog logging\n", LOG_LOCAL0 >> 3);
101 fprintf(stderr, " -t <termtype> terminal type of redirected screen (for -f)\n");
102 fprintf(stderr, " -u <time> length of a charging unit in seconds\n");
103 #ifdef I4B_EXTERNAL_MONITOR
104 fprintf(stderr, " -m inhibit network/local monitoring (protocol %02d.%02d)\n", MPROT_VERSION, MPROT_REL);
106 fprintf(stderr, "\n");
110 /*---------------------------------------------------------------------------*
112 *---------------------------------------------------------------------------*/
114 main(int argc, char **argv)
119 #ifdef I4B_EXTERNAL_MONITOR
120 int sockfd = -1; /* local monitor socket */
121 #ifndef I4B_NOTCPIP_MONITOR
122 int remotesockfd = -1; /* tcp/ip monitor socket */
126 setlocale (LC_ALL, "");
128 while ((i = getopt(argc, argv, "mc:d:fFlL:Pr:s:t:u:")) != -1)
132 #ifdef I4B_EXTERNAL_MONITOR
146 else if((sscanf(optarg, "%i", &debug_flags)) == 1)
157 fprintf(stderr, "Sorry, no fullscreen mode available - daemon compiled without USE_CURSES\n");
171 strlcpy(logfile, optarg, sizeof(logfile));
187 logfacility = strtoul(optarg, NULL, 10);
188 facility = logfacility << 3;
190 if((facility < LOG_KERN) ||
191 (facility > LOG_FTP && facility < LOG_LOCAL0) ||
192 (facility > LOG_LOCAL7))
194 fprintf(stderr, "Error, option -s has invalid logging facility %d", logfacility);
197 logfacility = facility;
201 fprintf(stderr, "Error: option -s requires a numeric argument!\n");
214 unit_length = strtoul(optarg, NULL, 10);
215 if(unit_length < ULSRC_CMDLMIN)
216 unit_length = ULSRC_CMDLMIN;
217 else if(unit_length > ULSRC_CMDLMAX)
218 unit_length = ULSRC_CMDLMAX;
223 fprintf(stderr, "Error: option -T requires a numeric argument!\n");
241 umask(UMASK); /* set our umask ... */
243 init_log(); /* initialize the logging subsystem */
246 check_pid(); /* check if we are already running */
250 if(do_fork || (do_fullscreen && do_rdev)) /* daemon mode ? */
253 write_pid(); /* write our pid to file */
255 /* set signal handler(s) */
257 signal(SIGCHLD, sigchild_handler); /* process handling */
258 signal(SIGHUP, rereadconfig); /* reread configuration */
259 signal(SIGUSR1, reopenfiles); /* reopen acct/log files*/
260 signal(SIGPIPE, SIG_IGN); /* handled manually */
261 signal(SIGINT, do_exit); /* clean up on SIGINT */
262 signal(SIGTERM, do_exit); /* clean up on SIGTERM */
263 signal(SIGQUIT, do_exit); /* clean up on SIGQUIT */
266 /* open isdn device */
268 if((isdnfd = open(I4BDEVICE, O_RDWR)) < 0)
270 llog(LL_ERR, "main: cannot open %s: %s", I4BDEVICE, strerror(errno));
274 /* check kernel and userland have same version/release numbers */
276 if((ioctl(isdnfd, I4B_VR_REQ, &mvr)) < 0)
278 llog(LL_ERR, "main: ioctl I4B_VR_REQ failed: %s", strerror(errno));
282 if(mvr.version != VERSION)
284 llog(LL_ERR, "main: version mismatch, kernel %d, daemon %d", mvr.version, VERSION);
288 if(mvr.release != REL)
290 llog(LL_ERR, "main: release mismatch, kernel %d, daemon %d", mvr.release, REL);
296 llog(LL_ERR, "main: step mismatch, kernel %d, daemon %d", mvr.step, STEP);
300 /* init controller state array */
304 /* read runtime configuration file and configure ourselves */
306 configure(configfile, 0);
308 if(config_error_flag)
310 llog(LL_ERR, "there were %d error(s) in the configuration file, terminating!", config_error_flag);
314 /* set controller ISDN protocol */
316 init_controller_protocol();
318 /* init active controllers, if any */
320 signal(SIGCHLD, SIG_IGN); /*XXX*/
322 init_active_controller();
324 signal(SIGCHLD, sigchild_handler); /*XXX*/
326 /* handle the rates stuff */
328 if((i = readrates(ratesfile)) == ERROR)
330 if(rate_error != NULL)
331 llog(LL_ERR, "%s", rate_error);
337 got_rate = 1; /* flag, ratesfile read and ok */
338 DBGL(DL_RCCF, (llog(LL_DBG, "ratesfile %s read successfully", ratesfile)));
342 if(rate_error != NULL)
343 llog(LL_WRN, "%s", rate_error);
346 /* if writing accounting info, open file, set unbuffered */
350 if((acctfp = fopen(acctfile, "a")) == NULL)
352 llog(LL_ERR, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
355 setvbuf(acctfp, (char *)NULL, _IONBF, 0);
358 /* initialize alias processing */
361 init_alias(aliasfile);
365 init_holidays(holidayfile);
367 /* init remote monitoring */
369 #ifdef I4B_EXTERNAL_MONITOR
373 sockfd = monitor_create_local_socket();
374 #ifndef I4B_NOTCPIP_MONITOR
375 remotesockfd = monitor_create_remote_socket(monitorport);
380 /* in case fullscreendisplay, initialize */
389 /* init realtime priority */
392 if(rt_prio != RTPRIO_NOTUSED)
396 rtp.type = RTP_PRIO_REALTIME;
399 if((rtprio(RTP_SET, getpid(), &rtp)) == -1)
401 llog(LL_ERR, "rtprio failed: %s", strerror(errno));
407 starttime = time(NULL); /* get starttime */
409 srandom(580403); /* init random number gen */
411 mloop( /* enter loop of no return .. */
412 #ifdef I4B_EXTERNAL_MONITOR
414 #ifndef I4B_NOTCPIP_MONITOR
423 /*---------------------------------------------------------------------------*
425 *---------------------------------------------------------------------------*/
433 llog(LL_DMN, "daemon terminating, exitval = %d", exitval);
440 #ifdef I4B_EXTERNAL_MONITOR
447 /*---------------------------------------------------------------------------*
449 *---------------------------------------------------------------------------*/
451 error_exit(int exitval, const char *fmt, ...)
457 llog(LL_DMN, "fatal error, daemon terminating, exitval = %d", exitval);
464 #ifdef I4B_EXTERNAL_MONITOR
468 if(mailto[0] && mailer[0])
473 char ebuffer[EXITBL];
474 char sbuffer[EXITBL];
478 vsnprintf(ebuffer, EXITBL-1, fmt, ap);
481 signal(SIGCHLD, SIG_IGN); /* remove handler */
483 snprintf(sbuffer, sizeof(sbuffer), "%s%s%s%s%s%s%s%s",
484 "cat << ENDOFDATA | ",
486 " -s \"i4b isdnd: fatal error, terminating\" ",
488 "\nThe isdnd terminated because of a fatal error:\n\n",
490 "\n\nYours sincerely,\n the isdnd\n",
498 /*---------------------------------------------------------------------------*
500 *---------------------------------------------------------------------------*/
503 #ifdef I4B_EXTERNAL_MONITOR
505 #ifndef I4B_NOTCPIP_MONITOR
512 struct timeval timeout;
518 llog(LL_DMN, "i4b isdn daemon started (pid = %d)", getpid());
526 FD_SET(fileno(stdin), &set);
529 FD_SET(isdnfd, &set);
533 #ifdef I4B_EXTERNAL_MONITOR
536 if (localmonitor != -1) {
537 /* always watch for new connections */
538 FD_SET(localmonitor, &set);
539 if(localmonitor > high_selfd)
540 high_selfd = localmonitor;
542 #ifndef I4B_NOTCPIP_MONITOR
543 if (remotemonitor != -1) {
544 FD_SET(remotemonitor, &set);
545 if(remotemonitor > high_selfd)
546 high_selfd = remotemonitor;
550 /* if there are client connections, let monitor module
551 * enter them into the fdset */
554 monitor_prepselect(&set, &high_selfd);
562 ret = select(high_selfd + 1, &set, NULL, NULL, &timeout);
566 if(FD_ISSET(isdnfd, &set))
570 if(FD_ISSET(fileno(stdin), &set))
574 #ifdef I4B_EXTERNAL_MONITOR
577 if(localmonitor != -1 && FD_ISSET(localmonitor, &set))
578 monitor_handle_connect(localmonitor, 1);
580 #ifndef I4B_NOTCPIP_MONITOR
581 if(remotemonitor != -1 && FD_ISSET(remotemonitor, &set))
582 monitor_handle_connect(remotemonitor, 0);
585 monitor_handle_input(&set);
593 llog(LL_ERR, "mloop: ERROR, select error on isdn device, errno = %d!", errno);
594 error_exit(1, "mloop: ERROR, select error on isdn device, errno = %d!", errno);
598 /* handle timeout and recovery */
605 /*---------------------------------------------------------------------------*
606 * data from keyboard available, read and process it
607 *---------------------------------------------------------------------------*/
615 llog(LL_ERR, "kbdrdhdl: ERROR, read error on controlling tty, errno = %d!", errno);
616 error_exit(1, "kbdrdhdl: ERROR, read error on controlling tty, errno = %d!", errno);
621 case 0x0c: /* control L */
633 /*---------------------------------------------------------------------------*
634 * data from /dev/isdn available, read and process them
635 *---------------------------------------------------------------------------*/
639 static unsigned char msg_rd_buf[MSG_BUF_SIZ];
640 msg_hdr_t *hp = (msg_hdr_t *)&msg_rd_buf[0];
644 if((len = read(isdnfd, msg_rd_buf, MSG_BUF_SIZ)) > 0)
648 case MSG_CONNECT_IND:
649 msg_connect_ind((msg_connect_ind_t *)msg_rd_buf);
652 case MSG_CONNECT_ACTIVE_IND:
653 msg_connect_active_ind((msg_connect_active_ind_t *)msg_rd_buf);
656 case MSG_DISCONNECT_IND:
657 msg_disconnect_ind((msg_disconnect_ind_t *)msg_rd_buf);
660 case MSG_DIALOUT_IND:
661 msg_dialout((msg_dialout_ind_t *)msg_rd_buf);
665 msg_accounting((msg_accounting_ind_t *)msg_rd_buf);
668 case MSG_IDLE_TIMEOUT_IND:
669 msg_idle_timeout_ind((msg_idle_timeout_ind_t *)msg_rd_buf);
672 case MSG_CHARGING_IND:
673 msg_charging_ind((msg_charging_ind_t *)msg_rd_buf);
676 case MSG_PROCEEDING_IND:
677 msg_proceeding_ind((msg_proceeding_ind_t *)msg_rd_buf);
681 msg_alert_ind((msg_alert_ind_t *)msg_rd_buf);
684 case MSG_DRVRDISC_REQ:
685 msg_drvrdisc_req((msg_drvrdisc_req_t *)msg_rd_buf);
688 case MSG_L12STAT_IND:
689 msg_l12stat_ind((msg_l12stat_ind_t *)msg_rd_buf);
693 msg_teiasg_ind((msg_teiasg_ind_t *)msg_rd_buf);
697 msg_pdeact_ind((msg_pdeact_ind_t *)msg_rd_buf);
700 case MSG_NEGCOMP_IND:
701 msg_negcomplete_ind((msg_negcomplete_ind_t *)msg_rd_buf);
704 case MSG_IFSTATE_CHANGED_IND:
705 msg_ifstatechg_ind((msg_ifstatechg_ind_t *)msg_rd_buf);
708 case MSG_DIALOUTNUMBER_IND:
709 msg_dialoutnumber((msg_dialoutnumber_ind_t *)msg_rd_buf);
713 msg_packet_ind((msg_packet_ind_t *)msg_rd_buf);
717 msg_keypad((msg_keypad_ind_t *)msg_rd_buf);
721 llog(LL_WRN, "ERROR, unknown message received from %sisdn (0x%x)", _PATH_DEV, msg_rd_buf[0]);
727 llog(LL_WRN, "ERROR, read error on isdn device, errno = %d, length = %d", errno, len);
731 /*---------------------------------------------------------------------------*
732 * re-read the config file on SIGHUP or menu command
733 *---------------------------------------------------------------------------*/
735 rereadconfig(int dummy)
737 extern int entrycount;
739 llog(LL_DMN, "re-reading configuration file");
743 #if I4B_EXTERNAL_MONITOR
744 monitor_clear_rights();
750 /* read runtime configuration file and configure ourselves */
752 configure(configfile, 1);
754 if(config_error_flag)
756 llog(LL_ERR, "rereadconfig: there were %d error(s) in the configuration file, terminating!", config_error_flag);
757 error_exit(1, "rereadconfig: there were %d error(s) in the configuration file, terminating!", config_error_flag);
762 /* reread alias database */
764 init_alias(aliasfile);
768 /*---------------------------------------------------------------------------*
769 * re-open the log/acct files on SIGUSR1
770 *---------------------------------------------------------------------------*/
772 reopenfiles(int dummy)
784 /* if user specified a suffix, rename the old file */
786 if(rotatesuffix[0] != '\0')
788 char filename[MAXPATHLEN];
790 snprintf(filename, sizeof(filename), "%s%s", acctfile, rotatesuffix);
792 if((rename(acctfile, filename)) != 0)
794 llog(LL_ERR, "reopenfiles: acct rename failed, cause = %s", strerror(errno));
795 error_exit(1, "reopenfiles: acct rename failed, cause = %s", strerror(errno));
799 if((acctfp = fopen(acctfile, "a")) == NULL)
801 llog(LL_ERR, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
802 error_exit(1, "ERROR, can't open acctfile %s for writing, terminating!", acctfile);
804 setvbuf(acctfp, (char *)NULL, _IONBF, 0);
811 /* if user specified a suffix, rename the old file */
813 if(rotatesuffix[0] != '\0')
815 char filename[MAXPATHLEN];
817 snprintf(filename, sizeof(filename), "%s%s", logfile, rotatesuffix);
819 if((rename(logfile, filename)) != 0)
821 llog(LL_ERR, "reopenfiles: log rename failed, cause = %s", strerror(errno));
822 error_exit(1, "reopenfiles: log rename failed, cause = %s", strerror(errno));
826 if((logfp = fopen(logfile, "a")) == NULL)
828 fprintf(stderr, "ERROR, cannot open logfile %s: %s\n",
829 logfile, strerror(errno));
830 error_exit(1, "reopenfiles: ERROR, cannot open logfile %s: %s\n",
831 logfile, strerror(errno));
834 /* set unbuffered operation */
836 setvbuf(logfp, (char *)NULL, _IONBF, 0);