1 /*
2 * Original - (c) Alexey V. Kuznetsov, avk@gamma.ru, 2001, 2002 CDR Reader
3 * for PBXs
4 *
5 * Modifications for the ATSlog project: Andrew
6 * Denis CyxoB www.yamiyam.dp.ua
7 * Andrew Kornilov <akornilov@gmail.com>
8 * Alex Samorukov <samm@os2.kiev.ua> RFC 854
9 * WILL/WONT DO/DONT negotiation is based on the BSD netcat
10 *
11 * ATSlog version 2.1.1 build 664 www.atslog.com
12 */
13
14 #include <ctype.h>
15 #include <stdio.h>
16 #include <stdarg.h>
17 #include <stdlib.h>
18 #include <string.h>
19 #include <time.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <sys/wait.h>
23 #include "atslogd.h"
24 #ifdef USE_LIBWRAP
25 #include <tcpd.h>
26 int allow_severity = 0; /* OpenBSD require this symbols */
27 int deny_severity = 0;
28 #endif /* USE_LIBWRAP */
29 #include <netdb.h>
30
31 #include <signal.h>
32 #include <sys/socket.h>
33 #include <netinet/tcp.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 #include <arpa/telnet.h>
37
38 #include <termios.h>
39 #include <sysexits.h>
40
41 #ifndef GETOPT
42 #include <unistd.h>
43 #endif
44
45
46 typedef long HANDLE;
47 typedef long DWORD;
48 #define INVALID_HANDLE_VALUE (HANDLE)(-1)
49
50 #define MAXSTRINGLEN 1028
51 #ifndef MAXPATHLEN
52 #define MAXPATHLEN 256
53 #endif
54 #define MAXFILENAMELEN 256
55 #define MAXERRORLEN 256
56
57
58 #define SPACE_TO_ZERO(x) ((x)==' ' ? '0' : (x))
59
60 HANDLE h2close = INVALID_HANDLE_VALUE;
61
62 char dbg = 0,lastchar='\0';
63 char copy_to_stderr = 0;
64 char copy_to_stdout = 0;
65 FILE *errout;
66 FILE *pfd = NULL;
67 char *pid_file = "/var/run/atslogd.pid";
68 char *logfile = NULL;
69 char dirname [MAXPATHLEN + 1 + MAXFILENAMELEN + 1];
70 char filename [MAXFILENAMELEN + 1] = "raw";
71 int dirlen = 0;
72 int pid = 0;
73 int filenamelen = 0;
74 /* count of childrens */
75 int childcount = 0;
76 /* default maximum clients for TCP port */
77 int maxtcpclients = 1;
78 /* startup tty settings */
79 struct termios oldtio;
80 int is_tcp = 0, is_rtcp = 0;
81 int tflag = 0; /* Telnet Emulation */
82
83 #define LT_RAW 0
84 #define LT_DEFINITY 1
85 #define LT_MERLIN 2
86 #define LT_PANASONIC 3
87 #define LT_MERIDIAN 4
88 #define LT_GHX 5
89 #define LT_MD110 6
90
91 struct String {
92 char *s;
93 struct String *next;
94 };
95
96 FILE *cur_logfile = NULL;
97 int cur_month = 0, new_month = 0;
98 int cur_day = 0, new_day = 0;
99 struct String *cdrs = NULL;
100 struct String *cdrs_last = NULL;
101
102 #ifdef GETOPT
103
104 char *optarg = NULL;
105 int optind = 1;
106
107 static int
getopt(int argc,char * argv[],char * sw)108 getopt(int argc, char *argv[], char *sw)
109 {
110 char *s, sym;
111 if (optind >= argc)
112 return (-1);
113 if (argv[optind][0] != '-' && argv[optind][0] != '/')
114 return (-1);
115 sym = argv[optind][1];
116 s = strchr(sw, sym);
117 optind++;
118 if (s == NULL || *s == 0) {
119 return sym;
120 }
121 if (s[1] == ':') {
122 if (optind >= argc) {
123 optarg = NULL;
124 } else {
125 optarg = argv[optind];
126 optind++;
127 }
128 }
129 return sym;
130 }
131
132 #else
133
134 extern char *optarg;
135 extern int optind;
136
137 #endif
138
139 void
close_tty(HANDLE hCom)140 close_tty(HANDLE hCom)
141 {
142 /* restore tty settings and close serial port */
143 tcsetattr(hCom, TCSANOW, &oldtio);
144 close(hCom);
145 }
146
147 /* taken from the http://www.developerweb.net/forum/archive/index.php/t-3025.html */
daemonize(void)148 void daemonize(void) {
149 int fd;
150 switch (fork()) {
151 case 0:
152 break;
153 case -1:
154 // Error
155 fprintf(stderr, "Error demonizing (fork)! %d - %s\n", errno, strerror(errno));
156 exit(0);
157 break;
158 default:
159 _exit(0);
160 }
161
162 if (setsid() < 0) {
163 fprintf(stderr, "Error demonizing (setsid)! %d - %s\n", errno, strerror(errno));
164 exit(0);
165 }
166 switch (fork()) {
167 case 0:
168 break;
169 case -1:
170 // Error
171 fprintf(stderr, "Error demonizing (fork2)! %d - %s\n", errno, strerror(errno));
172 exit(0);
173 break;
174 default:
175 _exit(0);
176 }
177 /* Are we really need this? */
178 // chdir("/");
179
180 fd = open("/dev/null", O_RDONLY);
181 if (fd != 0) {
182 dup2(fd, 0);
183 close(fd);
184 }
185 fd = open("/dev/null", O_WRONLY);
186 if (fd != 1) {
187 dup2(fd, 1);
188 close(fd);
189 }
190 fd = open("/dev/null", O_WRONLY);
191 if (fd != 2) {
192 dup2(fd, 2);
193 close(fd);
194 }
195 }
196
197 FILE *
open_pid()198 open_pid()
199 {
200 FILE *fd = NULL;
201 fd = fopen(pid_file, "w");
202 return fd;
203 }
204
205 void
close_pid()206 close_pid()
207 {
208 if (pfd != NULL)
209 unlink(pid_file);
210 pfd = NULL;
211 }
212
213 void
my_exit(int code)214 my_exit(int code)
215 {
216 close_pid();
217 exit(code);
218 }
219
220 int
my_syslog(char * s,...)221 my_syslog(char *s,...)
222 {
223 va_list va;
224 time_t tm = time(NULL);
225 struct tm lt;
226 int l = strlen(s) - 1;
227 char db [100];
228 static char fmtstr[25] = {"%a %b %d %H:%M:%S %Z %Y"};
229 lt = *localtime(&tm);
230 (void)strftime(db, sizeof(db), fmtstr, <);
231
232 va_start(va, s);
233
234 (void)fprintf(errout, "%s atslogd[%d]: ", db, getpid());
235 if (copy_to_stderr)
236 (void)fprintf(stderr, "%s atslogd[%d]: ", db, getpid());
237 if (s[l] == '\n')
238 s[l] = 0;
239 (void)vfprintf(errout, s, va);
240 (void)fprintf(errout, "\n");
241 if (copy_to_stderr) {
242 (void)vfprintf(stderr, s, va);
243 (void)fprintf(stderr, "\n");
244 }
245 fflush(errout);
246 if (copy_to_stderr)
247 fflush(stderr);
248 return 0;
249 }
250
251 static void *
my_malloc(int size,char do_clr)252 my_malloc(int size, char do_clr)
253 {
254 void *p = malloc(size);
255 if (p == NULL) {
256 my_syslog("Can't allocate %d bytes: %s", strerror(errno));
257 my_exit(1);
258 }
259 if (do_clr)
260 memset(p, 0, size);
261 return p;
262 }
263
264 static char *
my_strdup(char * s)265 my_strdup(char *s)
266 {
267 int l = strlen(s) + 1;
268 char *p;
269 p = my_malloc(l, 0);
270 memcpy(p, s, l);
271 return p;
272 }
273
274 static void
my_write(unsigned char * s,FILE * fp,int len)275 my_write(unsigned char *s, FILE * fp, int len)
276 {
277 int i;
278 for (i = 0; i < len; i++) {
279 /* strip 0x02 (STX) characters (NEC) */
280 if (s[i] == 0x02)
281 continue;
282 /* replace 0x03 (ETX) with \n for the NEC PBX */
283 /* Some PBX do only \r as line terminators */
284 if (s[i] == 0x03 || s[i] == '\r')
285 s[i] = '\n';
286 if(s[i]=='\n' && lastchar=='\n') /* skip blank lines */
287 continue;
288 fputc(s[i], fp);
289 if (copy_to_stdout) {
290 fputc(s[i], stdout);
291 }
292 lastchar=s[i];
293 }
294 }
295
296 static void
my_fflush(FILE * fp)297 my_fflush(FILE * fp)
298 {
299 fflush(fp);
300 if (copy_to_stdout) {
301 fflush(stdout);
302 }
303 }
304
305 static void
sighandler(int sig)306 sighandler(int sig)
307 {
308 if (h2close != INVALID_HANDLE_VALUE) {
309 my_syslog("Closing CDR stream");
310 if ((is_tcp) || (is_rtcp)) {
311 close(h2close);
312 } else
313 close_tty(h2close);
314 }
315 waitpid(-1, NULL, WNOHANG);
316 my_syslog("Exiting on signal %d", sig);
317 my_exit(0);
318 }
319
320 static void
sighuphandler(int sig)321 sighuphandler(int sig)
322 {
323 my_syslog("Catch SIGHUP(%d), recreate logfile", sig);
324
325 if (cur_logfile != NULL) {
326 fclose(cur_logfile);
327 cur_logfile = NULL;
328 }
329
330 memcpy(dirname + dirlen, filename, strlen(filename));
331 if ((cur_logfile = fopen(dirname, "at")) == NULL) {
332 my_syslog("Can't open CDR file '%s': %s", dirname, strerror(errno));
333 my_exit(1);
334 }
335
336 if (errout && errout!=stderr) {
337 fclose(errout);
338 if ((errout = fopen(logfile, "at")) == NULL) {
339 my_syslog("Can't open log file '%s': %s", logfile, strerror(errno));
340 my_exit(1);
341 }
342 }
343
344
345 }
346
347 static void
sigchldhandler(int sig)348 sigchldhandler(int sig)
349 {
350 my_syslog("Catch SIGCHLD, waiting for childs");
351 waitpid(-1, NULL, WNOHANG);
352 childcount--;
353 }
354
355 static void
setsighandler(int sig)356 setsighandler(int sig)
357 {
358 struct sigaction sa;
359 sigset_t ss;
360 sigemptyset(&ss);
361 sigaddset(&ss, sig);
362 if (sigprocmask(SIG_UNBLOCK, &ss, NULL) == (-1)) {
363 my_syslog("Can't unblock signal %d: %s", sig, strerror(errno));
364 my_exit(1);
365 }
366 memset(&sa, 0, sizeof(sa));
367 sa.sa_flags = SA_RESTART;
368 if (sig == SIGHUP)
369 sa.sa_handler = sighuphandler;
370 else if (sig == SIGCHLD)
371 sa.sa_handler = sigchldhandler;
372 else
373 sa.sa_handler = sighandler;
374 if (sigaction(sig, &sa, NULL) == (-1)) {
375 my_syslog("Can't set signal handler on %d: %s", sig, strerror(errno));
376 my_exit(1);
377 }
378 }
379
380 char *
my_strerror(void)381 my_strerror(void)
382 {
383 static char ret_err[MAXERRORLEN + 1];
384 int rc;
385 int l;
386 snprintf(ret_err, sizeof(ret_err), "(%d) ", errno);
387 l = strlen(ret_err);
388 strncpy(ret_err + l, strerror(errno), MAXERRORLEN - l);
389 ret_err[MAXERRORLEN] = 0;
390 rc = strlen(ret_err + l);
391 if (rc == 0) {
392 ret_err[l - 1] = 0;
393 } else {
394 if (ret_err[l + rc - 1] == '\n')
395 ret_err[l + rc - 1] = 0;
396 }
397 return ret_err;
398 }
399
400
401 HANDLE
open_tty(char * tty_name)402 open_tty(char *tty_name)
403 {
404 HANDLE hCom;
405 struct termios newtio;
406
407 /*
408 * we need to open tty in non blocking mode to set CLOCAL value, and
409 * then reopen it in normal mode to prevent waiting for CARRIER line
410 * on opening /dev/ttySx devices
411 */
412 hCom = open(tty_name, O_RDWR | O_NONBLOCK);
413 if (hCom == INVALID_HANDLE_VALUE) {
414 my_syslog("open_tty on '%s' failed: %s", tty_name, my_strerror());
415 return hCom;
416 }
417 tcgetattr(hCom, &oldtio);
418 bzero(&newtio, sizeof(newtio));
419 newtio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CSTOPB;
420 newtio.c_iflag = IGNPAR;
421 newtio.c_oflag = 0;
422 newtio.c_lflag = 0;
423 tcflush(hCom, TCIFLUSH);
424 tcsetattr(hCom, TCSANOW, &newtio);
425 close(hCom);
426
427 /* reopen in blocking mode */
428 hCom = open(tty_name, O_RDWR);
429
430 if (hCom == INVALID_HANDLE_VALUE) {
431 my_syslog("open_tty on '%s' failed: %s", tty_name, my_strerror());
432 }
433 return hCom;
434 }
435
436 int
set_tty_params(HANDLE hCom,long speed,int data_bits,char parity,int stop_bits)437 set_tty_params(HANDLE hCom, long speed, int data_bits, char parity, int stop_bits)
438 {
439 static struct Speed {
440 long speed;
441 DWORD wspeed;
442 } speeds [] = {
443 {
444 1200, B1200
445 },
446 {
447 2400, B2400
448 },
449 {
450 4800, B4800
451 },
452 {
453 9600, B9600
454 },
455 {
456 19200, B19200
457 },
458 {
459 38400, B38400
460 },
461 {
462 57600, B57600
463 },
464 {
465 115200, B115200
466 },
467 {
468 0, 0
469 }
470 };
471
472 struct Speed *sp;
473
474 struct termios tt;
475
476 for (sp = speeds; sp->speed; sp++) {
477 if (sp->speed == speed)
478 break;
479 }
480 if (sp->speed == 0) {
481 my_syslog("Invalid speed: %ld", speed);
482 return (-1);
483 }
484 if (stop_bits != 1 && stop_bits != 2) {
485 my_syslog("Invalid number of stop bits: %d", stop_bits);
486 return (-1);
487 }
488 if (data_bits < 5 || data_bits > 8) {
489 my_syslog("Invalid number of data bits: %d", data_bits);
490 return (-1);
491 }
492 cfmakeraw(&tt);
493 tt.c_iflag = 0;
494 tt.c_oflag = 0;
495 tt.c_lflag = 0;
496 tt.c_cflag = CREAD | CLOCAL | CRTSCTS | HUPCL;
497 switch (data_bits) {
498 case 5:
499 tt.c_cflag |= CS5;
500 break;
501 case 6:
502 tt.c_cflag |= CS6;
503 break;
504 case 7:
505 tt.c_cflag |= CS7;
506 break;
507 default:
508 tt.c_cflag |= CS8;
509 break;
510 }
511 if (stop_bits == 2)
512 tt.c_cflag |= CSTOPB;
513 switch (parity) {
514 case 'e':
515 tt.c_cflag |= PARENB;
516 break;
517 case 'o':
518 tt.c_cflag |= PARENB | PARODD;
519 break;
520 case 0:
521 case 'n':
522 break;
523 default:
524 my_syslog("Invalid parity: '%c'", parity);
525 return (-1);
526 }
527 /*
528 * read() will return when VMIN bytes of input are available, or if
529 * interrupted. Otherwise it will wait indefinitely.
530 */
531 tt.c_cc[VTIME] = 0;
532 tt.c_cc[VMIN] = 1;
533 cfsetspeed(&tt, sp->wspeed);
534 if (tcsetattr(hCom, TCSANOW, &tt) == (-1)) {
535 my_syslog("tcsetattr failed: %s", my_strerror());
536 return (-1);
537 }
538 return 0;
539 }
540
541
542 /*
543 * ensure all of data on socket comes through. f==read || f==write
544 */
545 ssize_t
atomicio(ssize_t (* f)(int,void *,size_t),int fd,void * _s,size_t n)546 atomicio(ssize_t(*f) (int, void *, size_t), int fd, void *_s, size_t n){
547 char *s = _s;
548 ssize_t res , pos = 0;
549
550 while (n > pos) {
551 res = (f) (fd, s + pos, n - pos);
552 switch (res) {
553 case -1:
554 if (errno == EINTR || errno == EAGAIN)
555 continue;
556 case 0:
557 return (res);
558 default:
559 pos += res;
560 }
561 }
562 return (pos);
563 }
564
565
566 int
read_block(HANDLE hCom,unsigned char * buf,int bufsize)567 read_block(HANDLE hCom, unsigned char *buf, int bufsize)
568 {
569 unsigned char obuf[4];
570 unsigned char *p, *end;
571 int count , stop;
572
573 if(dbg)
574 my_syslog("read_block: %d bufsize", bufsize);
575
576
577 do {
578 stop = 1;
579 count = read(hCom, buf, bufsize);
580 if(dbg)
581 my_syslog("read(): %d bytes", count);
582 if (tflag) {
583 end = buf + count;
584 obuf[0] = '\0';
585
586 for (p = buf; p < end; p++) {
587 if (*p != IAC)
588 break;
589 stop = 0; /* we dont really need IAC
590 * block */
591 obuf[0] = IAC;
592 p++;
593 if ((*p == WILL) || (*p == WONT))
594 obuf[1] = DONT;
595 if ((*p == DO) || (*p == DONT))
596 obuf[1] = WONT;
597 if (obuf) {
598 p++;
599 obuf[2] = *p;
600 obuf[3] = '\0';
601 if (atomicio((ssize_t(*) (int, void *, size_t)) write,
602 hCom, obuf, 3) != 3)
603 my_syslog("telnet: Write Error");
604 obuf[0] = '\0';
605 }
606 }
607 }
608 } while (!stop);
609 return count;
610 }
611
612 #ifdef USE_LIBWRAP
613 int
auth_libwrap(int socketfp)614 auth_libwrap(int socketfp)
615 {
616 struct request_info req;
617 request_init(&req, RQ_DAEMON, "atslogd", RQ_FILE, socketfp, 0);
618 fromhost(&req);
619 if (!hosts_access(&req)) {
620 my_syslog("Connection refused by libwrap");
621 return 0;
622 }
623 return 1;
624 }
625 #endif /* USE_LIBWRAP */
626
627
628 HANDLE
open_io(char * io_name,long speed,int data_bits,char parity,int stop_bits)629 open_io(char *io_name, long speed, int data_bits, char parity, int stop_bits)
630 {
631 HANDLE hCom;
632 int rc;
633
634 hCom = open_tty(io_name);
635 if (hCom == INVALID_HANDLE_VALUE) {
636 my_syslog("Can't open serial device '%s'", io_name);
637 return INVALID_HANDLE_VALUE;
638 }
639 rc = set_tty_params(hCom, speed, data_bits, parity, stop_bits);
640 if (rc == (-1)) {
641 my_syslog("Unable to set TTY device parameters");
642 return INVALID_HANDLE_VALUE;
643 }
644 h2close = hCom;
645 return hCom;
646 }
647
648 void
usage(FILE * fp)649 usage(FILE * fp)
650 {
651 (void)fprintf(fp,
652 "ATSlog version 2.1.1 build 664 www.atslog.com\n"
653 "Usage: atslogd [-D dir] [-L logfile] [-F filename] [-s speed] [-c csize]\n"
654 " [-p parity] [-f sbits] [-d] [-e] [-o] [-x number] [-w seconds]\n"
655 " [-b] [-P pidfile] tcp[:address]:port|rtcp:address:port|dev\n"
656 "Options:\n"
657 " -D directory Specify a location where atslogd should place CDR log files,\n"
658 " default is current dir\n"
659 " -L logfile file for error messages, default is stderr\n"
660 " -F filename name of file where CDR messages will be put, default is 'raw'\n"
661 " -s speed tspeed of the serial device, default 9600\n"
662 " -c char_size length of the character; valid values from 5 to 8\n"
663 " -p parity parity of the serial device:\n"
664 " e - even parity, o - odd parity, n - no parity,\n"
665 " -f stop_bits number of the stop bits; valid values 1 or 2\n"
666 " -d operate in DEBUG mode\n"
667 " -e copy error messages to stderr (in case if -L has value)\n"
668 " -o write CDR additionally to stdout\n"
669 " -x connections number of the allowed TCP clients. Default is 1\n"
670 " -t emulation of the TELNET protocol\n"
671 " -w seconds timeout before I/O port will be opened next time after EOF;\n"
672 " default is 5\n"
673 " -b daemonize on startup\n"
674 " -P pid-file Specify an alternative file in which to store the process ID.\n"
675 " /var/run/atslogd.pid by default\n"
676 " tcp[:host]:port IP address and TCP port to listen for the incoming\n"
677 " connections. You may omit address and daemon will bind\n"
678 " on all available IP addresses\n"
679 " rtcp:host:port Remote IP address and TCP port to connect\n"
680 " dev serial device to use\n"
681 "\n"
682 #ifdef USE_LIBWRAP
683 "You can use libwrap to limit access for the tcp connections.\n"
684 "See /etc/hosts.allow and /etc/hosts.deny\n\n");
685 #else /* USE_LIBWRAP */
686 );
687 #endif /* USE_LIBWRAP */
688
689 my_exit(1);
690 }
691
692
693
694 int
main(int argc,char * argv[])695 main(int argc, char *argv[])
696 {
697 int rc;
698 long speed = 9600;
699 int data_bits = 8, stop_bits = 1;
700 char parity = 0;
701 int next_open_timeout = 5;
702 unsigned char buf[1024];
703 unsigned short tcpPort = 0, rtcpPort = 0;
704 char *hostname = NULL, *rhostname = NULL;
705 char *token = NULL, *saveptr = NULL, *port = NULL;
706
707 int opt = 1;
708 int pid;
709 HANDLE s , new_s;
710
711 struct sockaddr_in sa_lserver, sa_rclient;
712 socklen_t sa_rclient_len;
713 struct hostent *he_rserver = NULL;
714 struct hostent *he_lserver = NULL;
715
716 char do_daemonize = 0;
717 sigset_t ss;
718
719 HANDLE hCom;
720
721 while ((rc = getopt(argc, argv, "tbohdes:D:L:P:F:p:c:f:x:w:s:")) != (-1)) {
722 switch (rc) {
723 case 'D':
724 dirlen = strlen(optarg);
725 if (dirlen > MAXPATHLEN) {
726 (void)fprintf(stderr, "Too long directory name\n");
727 my_exit(1);
728 }
729 if (dirlen == 0) {
730 dirname[0] = '.';
731 dirlen = 1;
732 } else {
733 memcpy(dirname, optarg, dirlen);
734 }
735 switch (dirname[dirlen - 1]) {
736 case '/':
737 case '\\':
738 break;
739 default:
740 dirname[dirlen++] = '/';
741 break;
742 }
743 break;
744 case 'L':
745 logfile = optarg;
746 break;
747 case 'F':
748 filenamelen = strlen(optarg);
749 if (filenamelen > MAXFILENAMELEN) {
750 (void)fprintf(stderr, "Too long file name\n");
751 my_exit(1);
752 }
753 memcpy(filename, optarg, filenamelen);
754 break;
755 case 's':
756 speed = atol(optarg);
757 break;
758 case 't':
759 tflag = 1;
760 break;
761 case 'p':
762 parity = optarg[0];
763 break;
764 case 'c':
765 data_bits = atoi(optarg);
766 break;
767 case 'f':
768 stop_bits = atoi(optarg);
769 break;
770 case 'd':
771 dbg = 1;
772 break;
773 case 'e':
774 copy_to_stderr = 1;
775 break;
776 case 'x':
777 maxtcpclients = atoi(optarg);
778 break;
779 case 'w':
780 next_open_timeout = atoi(optarg);
781 break;
782 case 'b':
783 do_daemonize = 1;
784 break;
785 case 'P':
786 pid_file = optarg;
787 break;
788 case 'o':
789 copy_to_stdout = 1;
790 break;
791 case 'h':
792 usage(stdout);
793 default:
794 (void)fprintf(stderr, "Unknown switch: %c\n", (char)rc);
795 my_exit(1);
796 }
797 }
798
799 argc -= optind;
800 argv += optind;
801
802 if (do_daemonize)
803 daemonize();
804
805 if (logfile) {
806 errout = fopen(logfile, "at");
807 if (errout == NULL) {
808 (void)fprintf(stderr, "Can't open '%s': %s\n", logfile, strerror(errno));
809 my_exit(1);
810 }
811 } else {
812 errout = stderr;
813 copy_to_stderr = 0;
814 }
815
816 if (argc <= 0) {
817 my_syslog("No input TTY device given");
818 usage(stderr);
819 }
820 my_syslog("Starting");
821
822
823 pid = getpid();
824 if (do_daemonize && pid == (-1)) {
825 my_syslog("Can't become daemon, exiting");
826 my_exit(1);
827 }
828 pfd = open_pid();
829 if (pfd != NULL) {
830 (void)fprintf(pfd, "%d\n", getpid());
831 fclose(pfd);
832 } else {
833 my_syslog("Can't write to '%s' PID file, exiting", pid_file);
834 my_exit(1);
835 }
836
837 pid = getpid();
838
839 if (do_daemonize && pid == (-1)) {
840 my_syslog("Can't become daemon, exiting");
841 my_exit(1);
842 }
843 pfd = open_pid();
844 if (pfd != NULL) {
845 (void)fprintf(pfd, "%ld\n", (long)pid);
846 fclose(pfd);
847 } else {
848 my_syslog("Can't write to '%s' PID file, exiting", pid_file);
849 my_exit(1);
850 }
851
852 sigfillset(&ss);
853 if (sigprocmask(SIG_SETMASK, &ss, NULL) == (-1)) {
854 my_syslog("Can't block all signals: %s", strerror(errno));
855 my_exit(1);
856 }
857 setsighandler(SIGHUP);
858 setsighandler(SIGINT);
859 setsighandler(SIGTERM);
860 setsighandler(SIGCHLD);
861
862 if (strchr(argv[0], ':') != NULL)
863 token = (char *)strtok_r(argv[0], ":", &saveptr);
864 if (token != NULL) {
865 if (strcasecmp(token, "tcp") == 0) {
866 is_tcp = 1;
867 hostname = (char *)strtok_r(NULL, ":", &saveptr);
868 if (hostname == NULL)
869 usage(stderr);
870 port = (char *)strtok_r(NULL, ":", &saveptr);
871 if (port == NULL) {
872 port = my_strdup(hostname);
873 hostname = NULL;
874 }
875 if (hostname != NULL) {
876 if ((he_lserver = gethostbyname(hostname)) == NULL) {
877 my_syslog("Invalid hostname: %s", hostname);
878 exit(1);
879 }
880 }
881 tcpPort = atoi(port);
882 } else if (strcasecmp(token, "rtcp") == 0) {
883 is_rtcp = 1;
884 rhostname = (char *)strtok_r(NULL, ":", &saveptr);
885 if (rhostname == NULL)
886 usage(stderr);
887 port = (char *)strtok_r(NULL, ":", &saveptr);
888 if (port == NULL)
889 usage(stderr);
890 rtcpPort = atoi(port);
891 } else {
892 my_syslog("Unknown token %s", token);
893 my_exit(1);
894 }
895
896 }
897 if (is_tcp)
898 /* listen */
899 {
900 if (tcpPort == 0) {
901 my_syslog("Invalid TCP port 0 to listen");
902 hCom = INVALID_HANDLE_VALUE;
903 my_exit(1);
904 }
905 s = socket(PF_INET, SOCK_STREAM, 0);
906 if (s == INVALID_HANDLE_VALUE) {
907 my_syslog("socket() failed: %s", my_strerror());
908 my_exit(1);
909 }
910 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)) < 0) {
911 my_syslog("setsockopt() failed: %s", my_strerror());
912 my_exit(1);
913 }
914 /*
915 * send keepalive packets. if remote end hangs then we'll can
916 * know this ?
917 */
918 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, sizeof(opt)) < 0) {
919 my_syslog("setsockopt() failed: %s", my_strerror());
920 my_exit(1);
921 }
922 h2close = s;
923 memset(&sa_lserver, 0, sizeof(sa_lserver));
924 memset(&sa_rclient, 0, sizeof(sa_rclient));
925 sa_rclient.sin_family = sa_lserver.sin_family = AF_INET;
926 sa_lserver.sin_port = htons(tcpPort);
927 if (hostname != NULL) {
928 memcpy(&sa_lserver.sin_addr, he_lserver->h_addr_list[0], he_lserver->h_length);
929 }
930 if (bind(s, (struct sockaddr *)&sa_lserver, sizeof(sa_lserver)) == (-1)) {
931 if (hostname != NULL)
932 my_syslog("bind() on port %s:%d failed: %s", hostname, tcpPort, my_strerror());
933 else
934 my_syslog("bind() on port %d failed: %s", tcpPort, my_strerror());
935 my_exit(1);
936 }
937 if (listen(s, 5) == (-1)) {
938 my_syslog("listen() failed: %s", my_strerror());
939 my_exit(1);
940 }
941 if (hostname != NULL)
942 my_syslog("Waiting TCP connection on port %s:%d", hostname, tcpPort);
943 else
944 my_syslog("Waiting TCP connection on port %d", tcpPort);
945 for (;;) {
946 sa_rclient_len = sizeof(sa_rclient);
947 if ((new_s = accept(s, (struct sockaddr *)&sa_rclient, &sa_rclient_len)) == (-1)) {
948 my_syslog("accept() failed: %s", my_strerror());
949 h2close = INVALID_HANDLE_VALUE;
950 hCom = h2close;
951 close(s);
952 break;
953 }
954 if (childcount >= maxtcpclients) {
955 my_syslog("Connection from %s:%d refused because maximum number of clients [%d] has been reached", inet_ntoa(sa_rclient.sin_addr), ntohs(sa_rclient.sin_port), maxtcpclients);
956 close(new_s);
957 h2close = INVALID_HANDLE_VALUE;
958 hCom = h2close;
959 sleep(2);
960 continue;
961 } else
962 my_syslog("Connection from %s:%d", inet_ntoa(sa_rclient.sin_addr), ntohs(sa_rclient.sin_port));
963 #ifdef USE_LIBWRAP
964 /* using libwrap for controll access */
965 if (!auth_libwrap(new_s)) {
966 h2close = INVALID_HANDLE_VALUE;
967 hCom = h2close;
968 close(new_s);
969 continue;
970 } else
971 #endif /* USE_LIBWRAP */
972 {
973 pid = fork();
974 if (pid == 0) {
975 /*
976 * now we are the
977 * champions...errr...child ;-)
978 */
979 /* close input socket */
980 close(s);
981 /*
982 * temp. disable handler to revent
983 * closing NULL in signal
984 */
985 /* handler */
986 h2close = INVALID_HANDLE_VALUE;
987 hCom = new_s;
988 break;
989 } else if (pid == -1) {
990 /* can't fork. system error */
991 switch (errno) {
992 case EAGAIN:
993 {
994 /*
995 * resource temp.
996 * unavail. try again
997 * later ;-)
998 */
999 my_syslog("fork() failed: %s", my_strerror());
1000 h2close = INVALID_HANDLE_VALUE;
1001 hCom = h2close;
1002 close(new_s);
1003 close(s);
1004 my_exit(1);
1005 };
1006 case ENOMEM:
1007 {
1008 /*
1009 * not enough system
1010 * memory. hangup?
1011 */
1012 my_syslog("fork() failed: %s", my_strerror());
1013 h2close = INVALID_HANDLE_VALUE;
1014 hCom = h2close;
1015 close(new_s);
1016 close(s);
1017 my_exit(1);
1018 };
1019 }
1020 } else {
1021 /* parent code */
1022 /* close child socket */
1023 childcount++;
1024 h2close = INVALID_HANDLE_VALUE;
1025 hCom = h2close;
1026 close(new_s);
1027 /* continue accepting connection */
1028 continue;
1029 }
1030 }
1031 }
1032 if (hCom == INVALID_HANDLE_VALUE) {
1033 if (hostname != NULL)
1034 my_syslog("Can't open '%s:%s'", hostname, tcpPort);
1035 else
1036 my_syslog("Can't open '%s'", tcpPort);
1037
1038 hCom = INVALID_HANDLE_VALUE;
1039 h2close = hCom;
1040 } else {
1041 h2close = hCom;
1042 }
1043
1044 } else if (is_rtcp) {
1045 /* connect */
1046 if ((he_rserver = gethostbyname(rhostname)) == NULL) {
1047 my_syslog("Invalid hostname to connect: %s", rhostname);
1048 hCom = INVALID_HANDLE_VALUE;
1049 my_exit(1);
1050 }
1051 if (rtcpPort == 0) {
1052 my_syslog("Invalid TCP port number to connect: %d", rtcpPort);
1053 hCom = INVALID_HANDLE_VALUE;
1054 my_exit(1);
1055 }
1056 rtcp:
1057 s = socket(PF_INET, SOCK_STREAM, 0);
1058 if (s == INVALID_HANDLE_VALUE) {
1059 my_syslog("socket() failed: %s", my_strerror());
1060 my_exit(1);
1061 }
1062 /* send keepalive packets. if remote end hangs then */
1063 /* we'll can know this ? */
1064 if (setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, sizeof(opt)) < 0) {
1065 my_syslog("setsockopt() failed: %s", my_strerror());
1066 my_exit(1);
1067 }
1068 /* fine tuning of the keepalive options.
1069 Because there are no such options in BSD stack this will
1070 work for the Linux only*/
1071 #ifdef TCP_KEEPCNT
1072 opt=5; /* maximum number of keepalive probes to be sent. */
1073 if (setsockopt(s, IPPROTO_TCP, TCP_KEEPCNT, (char *)&opt, sizeof(opt)) < 0) {
1074 my_syslog("setsockopt() failed: %s", my_strerror());
1075 my_exit(1);
1076 }
1077 #endif
1078 #ifdef TCP_KEEPINTVL
1079 opt=2; /* number of seconds to wait before retransmitting a keepalive probe. */
1080 if (setsockopt(s, IPPROTO_TCP, TCP_KEEPINTVL, (char *)&opt, sizeof(opt)) < 0) {
1081 my_syslog("setsockopt() failed: %s", my_strerror());
1082 my_exit(1);
1083 }
1084 #endif
1085 #ifdef TCP_KEEPIDLE
1086 opt=60; /* number of seconds to wait before retransmitting a keepalive probe. */
1087 if (setsockopt(s, IPPROTO_TCP, TCP_KEEPIDLE, (char *)&opt, sizeof(opt)) < 0) {
1088 my_syslog("setsockopt() failed: %s", my_strerror());
1089 my_exit(1);
1090 }
1091 #endif
1092 memset(&sa_rclient, 0, sizeof(sa_rclient));
1093 memcpy(&sa_rclient.sin_addr.s_addr, he_rserver->h_addr_list[0], he_rserver->h_length);
1094 sa_rclient.sin_family = AF_INET;
1095 sa_rclient.sin_port = htons(rtcpPort);
1096 if (connect(s, (struct sockaddr *)&sa_rclient, sizeof(sa_rclient)) < 0) {
1097 my_syslog("connect() failed: %s", my_strerror());
1098 hCom = INVALID_HANDLE_VALUE;
1099 h2close = hCom;
1100 if (is_rtcp) {
1101 sleep(next_open_timeout);
1102 goto rtcp;
1103 }
1104 my_exit(1);
1105 } else
1106 my_syslog("Connected to %s:%d", inet_ntoa(sa_rclient.sin_addr), ntohs(sa_rclient.sin_port));
1107 hCom = s;
1108 h2close = hCom;
1109
1110 } else
1111 hCom = open_io(argv[0], speed, data_bits, parity, stop_bits);
1112
1113 if (hCom == INVALID_HANDLE_VALUE) {
1114 my_syslog("Can't open '%s', exiting", argv[0]);
1115 my_exit(1);
1116 }
1117 memcpy(dirname + dirlen, filename, strlen(filename));
1118 if ((cur_logfile = fopen(dirname, "at")) == NULL) {
1119 my_syslog("Can't open CDR file '%s': %s", dirname, strerror(errno));
1120 my_exit(1);
1121 }
1122 while (1)
1123 {
1124 rc = read_block(hCom, buf, sizeof(buf));
1125 if (rc <= 0)
1126 {
1127 if ((is_tcp) || (is_rtcp))
1128 {
1129 /* because we read() in blocking mode so if */
1130 /* we've got 0 -> remote peer hangs */
1131 if (errno != EINTR)
1132 {
1133 my_syslog("Connection with remote peer %s:%d has been closed", inet_ntoa(sa_rclient.sin_addr), ntohs(sa_rclient.sin_port));
1134 h2close = INVALID_HANDLE_VALUE;
1135 close(hCom);
1136 if (is_rtcp)
1137 {
1138 my_syslog("Reconnect");
1139 goto rtcp;
1140 }
1141 else
1142 my_syslog("Exiting");
1143 my_exit(0);
1144
1145 }
1146 }
1147 else
1148 {
1149 h2close = INVALID_HANDLE_VALUE;
1150 close_tty(hCom);
1151 sleep(next_open_timeout);
1152 hCom = open_io(argv[0], speed, data_bits, parity, stop_bits);
1153 if (hCom == INVALID_HANDLE_VALUE)
1154 {
1155 my_syslog("Can't open '%s', exiting", argv[0]);
1156 my_exit(1);
1157 }
1158 }
1159 continue;
1160 }
1161 my_write(buf, cur_logfile, rc);
1162 my_fflush(cur_logfile);
1163 }
1164 my_exit(0);
1165 return 0;
1166 }
1167
1168