#ifndef LINT
static char sccsid[] =
"%W% %G% %Y% Copyright 1992 Livingston Enterprises Inc";
#endif  LINT

/*
 *	This program is intended to provide a network data channel to
 *	a specific TCP port on a remote host.  Input is through standard
 *	IN and output is across the network.  This is primarily intended
 *	for use with the PortMaster "netdata" service.
 *
 *	Arguments: PortMaster_Name PortMaster_Port
 */

#include <stdio.h>
#include <ctype.h>
#include <pwd.h>
#include <sys/param.h>
#include <sys/time.h>
#include <sys/file.h>
#include <sys/signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/ioctl.h>

#include <netinet/in.h>

#include <netdb.h>
#include <errno.h>

extern int	errno;

char	*program_name;
char	buffer[1024];
char	buffer1[2048];
int	map_flag;

main(argc, argv)
int	argc;
char	**argv;
{
	char	*pm_name;		/* Host name of the PortMaster */
	int	pm_port;		/* The port to connect to. */
	int	fd;
	int	nread;

	/* Process Command Line Arguments */
	program_name = *argv;
	argc--;
	argv++;

	pm_name = (char *)NULL;
	pm_port = 0;
	map_flag = 0;

	while(argc) {
		if(**argv == '-') {
			if(strcmp(*argv, "-CR") == 0) {
				map_flag = 1;
			}
			else {
				usage();
			}
		}
		else if(pm_name == (char *)NULL) {
			/* Use this as the PortMaster Name */
			pm_name = *argv;
		}
		else if(pm_port == 0) {
			/* Use this as the port */
			pm_port = atoi(*argv);
		}
		else {
			usage();
		}

		argc--;
		argv++;
	}

	/* Validate Command Line Arguments */
	if(pm_name == (char *)NULL || pm_port == 0) {
		usage();
	}

	fd = pm_open(pm_name, pm_port);
	if(fd < 0) {
		perror("pm_open");
		exit(-1);
	}
	sleep(1);
	while((nread = read(0, buffer, sizeof(buffer))) > 0) {
		if(map_flag) {
			nread = crnl(buffer1, buffer, nread);
			if(write(fd, buffer1, nread) != nread) {
				/* Couldn't write the same number of bytes */
				exit(-1);
			}
		}
		else {
			if(write(fd, buffer, nread) != nread) {
				/* Couldn't write the same number of bytes */
				exit(-1);
			}
		}
	}
	sleep(4);
	exit(0);
}

crnl(out, in, length)
char	*out;
char	*in;
{
	int	i;
	int	new_length;

	new_length = 0;
	for(i = 0;i < length;i++) {
		if(*in == '\n') {
			*out++ = '\r';
			new_length++;
		}
		*out++ = *in++;
		new_length++;
	}
	return(new_length);
}

usage()
{
	fprintf(stderr,
		"Usage: %s PortMaster_Name PortMaster_Port\n",
		program_name);
	exit(1);
}

#define MAX_RETRIES	4

pm_open(hostname, port_addr)
char		*hostname;
int		port_addr;
{
	int	retries;
	int	newfd;
	int	hold_errno;

	retries = 0;
	do {
		newfd = pm_doopen(hostname, port_addr);
		if(newfd >= 0 || errno != ECONNREFUSED) {
			return(newfd);
		}
		/*
		 * sleep 2 seconds and try again if the connection was
		 * refused.
		 */
		hold_errno = errno;
		sleep(2);
		errno = hold_errno;

	} while(retries++ < MAX_RETRIES);
	return(newfd);
}

pm_doopen(hostname, port_addr)
char		*hostname;
int		port_addr;
{
	struct sockaddr_in sin;
	struct hostent *hp;
	int	s;
	u_short	local_port;

	/* Get the host internet structure */
	hp = gethostbyname(hostname);
	if (hp == 0) {
		errno = EADDRNOTAVAIL;
		return(-1);
	}

	/* Open a new socket */
	s = socket(AF_INET, SOCK_STREAM, 0);
	if(s < 0)
		return(-1);

	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	local_port = 1025;
	do {
		local_port++;
		sin.sin_port = htons((u_short)local_port);
	} while((bind(s, (caddr_t)&sin, sizeof (sin)) < 0) &&
						local_port < 64000);
	if(local_port >= 64000) {
		close(s);
		return(-1);
	}

	/* Connect to the remote system */
	sin.sin_family = hp->h_addrtype;
	bcopy(hp->h_addr, (caddr_t)&sin.sin_addr, hp->h_length);
	sin.sin_port = htons((u_short)port_addr);

	if(connect(s, &sin, sizeof (sin)) < 0) {
		close(s);
		return(-1);
	}
	return(s);
}
