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, &lt);
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