
# This is a shell archive.  Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by knutson on Fri Oct 29 16:50:51 CDT 1993
# Contents:  README Makefile call dialer.c dialer.doc showlog.c tcpanswer
#	tcpcall tcpdialer.c
 
echo x - README
sed 's/^@//' > "README" <<'@//E*O*F README//'
READ ME FIRST for the IHHD dialer software

INSTALLATION

	Look at the Makefile and change the CFLAGS, LDFLAGS, and CC as
	appropriate for your system.

	Type 'make' to build it.

	If you have problems with undefined external references for bcopy,
	add the following line to the top of the file:

	#define bcopy(a, b, n)	memcpy(b, a, n)

	You may need to add #include <memory.h> above it.

	The mail archives have other hints about compilation problems.

TESTING
	Try running 'dialer -rp 7 cactus.org'.  If you connect and can
	type things and have them echoed back, then it looks like it's
	going to work.

	See the contrib/8bittst software for further tests.
@//E*O*F README//
chmod u=r,g=r,o=r README
 
echo x - Makefile
sed 's/^@//' > "Makefile" <<'@//E*O*F Makefile//'
### Possible compile options for various operating systems
##
## SunOS 4.1.2
CC= cc
CFLAGS= -g
##
## HPUX 8.07 or greater
#CC= cc
#CFLAGS= -g -Aa -D_HPUX_SOURCE
##
## SysV 3.2
#CC= cc
#CFLAGS= -g -DSIGCHLD=SIGCLD
#LDFLAGS= -lsocket

RELEASE=1.6.4

all: dialer tcpdialer showlog

shar:
	shar README Makefile call dialer.c dialer.doc showlog.c tcpanswer tcpcall tcpdialer.c >dialer$(RELEASE).shar

clean:
	rm -f *.o dialer tcpdialer
@//E*O*F Makefile//
chmod u=r,g=r,o=r Makefile
 
echo x - call
sed 's/^@//' > "call" <<'@//E*O*F call//'
#!/bin/sh

biff=`biff | sed 's/is //'`
mesg=`mesg | sed 's/is //'`
biff n
mesg n

dialer $*

biff $biff
mesg $mesg
@//E*O*F call//
chmod u=rwx,g=rwx,o=rx call
 
echo x - dialer.c
sed 's/^@//' > "dialer.c" <<'@//E*O*F dialer.c//'
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include <time.h>

/*
 * udpdialer - talk to a switch and remote dialer.
 *
 * usage: udpdialer [ -e escape_char ] [ -l logfile ] [ -s ] [ -rp port ] [ -lp port ] host
 * 
 * ARGUMENTS
 * -e escape_char Change escape character, enter as numeric value of the
 *			character, use '\01' to set it to CNTRL-A
 * -l logfile	Log data transfer to logfile.out and logfile.in.
 * -s		Generate I/O stats when done.
 * -lp port	Local port number to use.
 * -rp port	Port number to use when on remote host.
 * host		Remote host to contact.
 *
 * Terminate using by typing ^C^C^C (three control-Cs).
 */

static char* sccsid = "@(#)dialer.c	1.9	10/29/93";

#define MOUTHPIECE	0
#define MAXPKTSIZE	1024
#define ON		1
#define OFF		0
#define CTRLC		'\003'

FILE* outputlogf = NULL;
FILE* inputlogf = NULL;
struct sockaddr_in datagram;
struct sgttyb saved_tty;
time_t start_time = 0;
char* program;
char* remotehost = NULL;
char* logfile = NULL;
char packet[MAXPKTSIZE];
char escape_char = CTRLC;
short remoteport = 6123;
short localport = 6123;
short statistics = 0;
int pktcount = 0;
int minpktsize = MAXPKTSIZE + 1;
int maxpktsize = 0;
int totalsize = 0;
int sock;

void terminate();
void sig_child_handler();

main(argc, argv)
	int 	argc;
	char**	argv;
{

	program = *argv;

	for (argc--, argv++; argc; argc--, argv++) {
		if (!strcmp(*argv, "-rp")) {
			remoteport = atoi(*(argv+1));
			argc--;
			argv++;
		}
		else if (!strcmp(*argv, "-lp")) {
			localport = atoi(*(argv+1));
			argc--;
			argv++;
		}
		else if (!strcmp(*argv, "-e")) {
			argv++;
			argc--;
			escape_char = atoi(*argv) && 0xff;
			fprintf(stderr, "escape char set to %d\n",escape_char);
		}
		else if (!strcmp(*argv, "-l")) {
			logfile = *(argv+1);
			argv++;
			argc--;
		}
		else if (!strcmp(*argv, "-s")) {
			statistics = 1;
		}
		else if (!strncmp(*argv, "-", 1)) {
			fprintf(stderr, "usage: dialer [ -e escape_char ] [ -l logfile ] [ -s ] [ -rp port ] [ -lp port ] host \n");
			exit(1);
		}
		else {
			remotehost = *argv;
			break;
		}
	}

	/* verify proper mode */
	if ( !remotehost ) {
		fprintf(stderr, "usage: dialer [ -s ] [ -rp port ] [ -lp port ] host \n");
		exit(1);
	}

	init_socket();
	init_datagram(remotehost, remoteport);

	save_tty_settings();
	raw();
	echo(OFF);

	/* the following never return */
	if (make_handset() == MOUTHPIECE) {
		signal(SIGTERM, terminate);
		do_mouthpiece();
	}
	else {
		/* when mouthpiece dies, we should too */
		signal(SIGCHLD, sig_child_handler);

		do_earpiece();
	}

	exit(0);
}

/* this socket will be used for both sending and receiving */
init_socket() {

	struct sockaddr_in name;

	sock = socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
		perror("opening datagram socket");
		exit(2);
	}

	/* bind it */
	name.sin_family = AF_INET;
	name.sin_addr.s_addr = INADDR_ANY;
	name.sin_port = htons(localport);
	if (bind(sock, (struct sockaddr*)&name, sizeof name) < 0) {
		perror("binding datagram socket");
		exit(2);
	}
}

/* setup the the socket structure for sending datagrams to the remote site */
init_datagram(hostname, port)
	char* hostname;
	short port;
{

	struct hostent* hp;

	if (!(hp = gethostbyname(hostname))) {
		fprintf(stderr, "%s: unknown host\n", hostname);
		exit(2);
	}

	bcopy((char*)hp->h_addr, (char*)&datagram.sin_addr, hp->h_length);
	datagram.sin_family = AF_INET;
	datagram.sin_port = htons(port);
}

/* create a reader process */
make_handset() {

	/*
	 * The reader process reads the tty and sends the data
	 * to the remote host.
	 */

	int pid = fork();
	if (pid < 0) {
		perror("forking reader process");
		exit(3);
	}

	return pid;
}

do_mouthpiece() {

	struct timeval tv;
	int bytecount;
	int endsequence = 0;
	char logname[1024];

	/* logfile prep */
	if (logfile) {
		strcpy(logname, logfile);
		strcat(logname, ".out");
		outputlogf = fopen(logname, "w");
	}

	/* record starting time */
	time(&start_time);

	while (1) {
		/* keep delay between read/write to a minimum! */
		bytecount = read(0, packet, 1024);
		if (bytecount) {
			if (sendto(sock, packet, bytecount, 0,
				   (struct sockaddr*)&datagram, sizeof datagram) < 0)
				perror("sending datagram message");

			/* log data */
			if (outputlogf) {
				gettimeofday(&tv, NULL);
				fwrite(&tv, sizeof(tv), 1, outputlogf);
				fwrite(&bytecount, sizeof(bytecount), 1, outputlogf);
				fwrite(packet, sizeof(char), bytecount, outputlogf);
			}

			if (bytecount == 1 && (packet[0]&0177) == escape_char) {
				if (++endsequence == 3)
					terminate();
			}
			else
				endsequence = 0;

			/* statistics generation */
			pktcount++;
			totalsize += bytecount;
			if (bytecount < minpktsize) minpktsize = bytecount;
			else if (bytecount > maxpktsize) maxpktsize = bytecount;
		}
	}
}

do_earpiece() {

	struct timeval tv;
	int bytecount;
	char logname[1024];

	/* logfile prep */
	if (logfile) {
		strcpy(logname, logfile);
		strcat(logname, ".in");
		inputlogf = fopen(logname, "w");
	}

	while (1) {
		bytecount = read(sock, packet, 1024);
		write(1, packet, bytecount);

		/* log data */
		if (inputlogf) {
			gettimeofday(&tv, NULL);
			fwrite(&tv, sizeof(tv), 1, inputlogf);
			fwrite(&bytecount, sizeof(bytecount), 1, inputlogf);
			fwrite(packet, sizeof(char), bytecount, inputlogf);
		}
	}
}

/* save the original tty settings */
save_tty_settings() {
	gtty(0, &saved_tty);
}

/* restore the original tty settings */
restore_tty_settings() {
	stty(0, &saved_tty);
}

/* place the terminal in raw mode */
raw() {
	struct sgttyb tty;

	gtty(0, &tty);
	tty.sg_flags |= RAW;
	stty(0, &tty);
}

/* place the terminal in cooked mode */
cooked() {
	struct sgttyb tty;

	gtty(0, &tty);
	tty.sg_flags &= ~RAW;
	stty(0, &tty);
}

echo(on) 
	int on;
{

	struct sgttyb tty;

	gtty(0, &tty);
	if (on) {
		tty.sg_flags |= ECHO;
	}
	else
		tty.sg_flags &= ~ECHO;

	stty(0, &tty);
}

void sig_child_handler() {

	restore_tty_settings();

	if (outputlogf)
		fclose(outputlogf);
	if (inputlogf)
		fclose(inputlogf);

	exit(0);
}

void terminate() {

	time_t time_diff = time(0) - start_time;

	if (outputlogf)
		fclose(outputlogf);
	if (inputlogf)
		fclose(inputlogf);

	/* report statistics */
	if (statistics) {
		printf("%d packets, %d bytes, %d/%d/%d min/avg/max pkt size\r\n",
			pktcount, totalsize, minpktsize, totalsize/pktcount, 
			maxpktsize);
		if (time_diff)
			printf("%d seconds, %g pkt/s, %d b/s\r\n",
				time_diff, (float)pktcount / (float)time_diff, 
				totalsize/time_diff);
	}

	exit(0);
}
@//E*O*F dialer.c//
chmod u=r,g=r,o=r dialer.c
 
echo x - dialer.doc
sed 's/^@//' > "dialer.doc" <<'@//E*O*F dialer.doc//'
GETTING STARTED

You must have access to a host which is connected to the Internet.
While this is not entirely true (you could connect to someone else on
the same machine), it doesn't make much sense to use it if you're not.

You will also need a compiled version of the dialer code to do the
testing.  If you don't have it, you can get it from the archive.  The
dialer code may be retrieved from /pub/IHHD on cactus.org using
anonymous ftp.

It must be compiled for the machine you plan to run it on.  Typically,
running make is enough.


FINDING SOMEONE TO CONNECT WITH

Use the ihhd mailing list to make contact with someone who can help you
test what you are interested in.  Be sure to relate all pertinent info
such as the software you want to test, versions, modems speeds, etc.
It is not necessary to having modems that match speeds, but it will
affect your results.

MAKING A CONNECTION

Coordinate the time and place where you and your partner will be
testing from.  Remember to include timezones since the Internet is a
big place.  Also, be sure to let each other know the specific hostname
of the host you will be running from and which dialer you will be
using.  Initial coordination can be done using email.  Last minute
coordination can be done using talk, email, and even the dialer.

When the time comes to test, use your favorite terminal emulator
software to dial in and login to your test host.

When you are ready to test, run the dialer command specifying your
partner's hostname.  For example, if your partner is connecting from
the host cactus.org, you will type:

	% dialer cactus.org

This will send your data to the dialer on cactus.org.  Your partner
will type:

	% dialer <yourhostname>

You will be able to talk to each other by typing.  You won't be able to
see what you type.  You should type both a CR and an LF to terminate
your lines.

Once you have entered your dialer command, you should try typing
something like:

hello<CR><LF>

at regular intervals until you get a reply from your partner.  This is
necessary because the dialer uses an unconnected data transfer
protocol.  You never really know if another party is there receiving
your data unless they acknowledge what you are typing.  Later software
releases will fix this.

Use the dialer to discuss the steps in getting your tests underway.
When you are ready to start, exit your terminal emulator without
dropping the phone connection.  Start the software package you wish to
test and configure it for a direct serial connection using the same
port and baud rate that you were using for your terminal emulator.

You're now ready to test.  When you are through, you can exit the
dialer by typing ^C^C^C (3 CNTRL-C characters).

To use the tcpdialer, one partner will use the command:

	% tcpdialer -answer

and the other partner will use the command:

	% tcpdialer -call <remotehost>

where <remotehost> is the host your partner is on.

There are also some shell scripts (call, tcpanswer, and tcpcall) which
are interface scripts the dialer and tcpdialer.  In addition to running
the appropriate dialer, they also turn off/on system messages using the
msg and biff commands.  Using the interface scripts is the preferred
methods.

HOW TO TEST

Here are some data points you may want to gather in your testing:

What is the configuration of the two machines being used (type, OS,
etc.)?

Use ping to determine turn around times for packets.  Use 100 64 byte
packets and record the min/avg/max times.

You may collect packet statistics from the dialer by invoking it with
the -s option.  When you exit the dialer, it will report character and
packet counts and rates for data that was sent by you.  To get the
other sides data, your partner will need to do the same.  For the best
results, you should restart the dialer before each test and stop it
immediately after the test.  Data collection doesn't start until the
first data is sent through the dialer.

If possible, you may want to compare local host to PC operation or PC
to PC operation before or after your compare PC to dialer operation.
This will give you a good base from which to compare performance.

If you and your partner are using different speed modem connections,
then you may want to vary the test and compare the differences when one
person is the "caller" and the other is the "answerer" and if matching
modem connection speeds is any different than different modem speed
connections.

Lastly, write down your information and report it to the ihhd mailing
list so we can tally results and try to improve the software.
@//E*O*F dialer.doc//
chmod u=r,g=r,o=r dialer.doc
 
echo x - showlog.c
sed 's/^@//' > "showlog.c" <<'@//E*O*F showlog.c//'
#include <sys/time.h>
#include <stdio.h>
#include <time.h>
#include <ctype.h>

/*
 * showlog - display the content of a dialer created log file
 *
 * usage: showlog logfile
 */

static char* sccsid = "@(#)showlog.c	1.2	5/13/93";

main(argc, argv)
	int argc;
	char** argv;
{
	FILE* logf = fopen(*++argv, "r");
	struct timeval tv;
	struct tm* tm;
	unsigned char buf[1024];
	int bytecount;
	int i;

	if (!logf) {
		fprintf(stderr, "cannot open %s\n", *argv);
		exit(1);
	}

	while (fread(&tv, sizeof(tv), 1, logf)) {
		tm = localtime((time_t*)&tv.tv_sec);

		printf("%02.2d:%02.2d:%02.2d.%06.6d: ",tm->tm_hour, tm->tm_min, tm->tm_sec,
		       tv.tv_usec);

		if (!fread(&bytecount, sizeof(bytecount), 1, logf)) {
			fprintf(stderr, "premature EOF\n");
			exit(1);
		}
		printf("%d bytes: ", bytecount);

		if (fread(buf, sizeof(char), bytecount, logf) != bytecount) {
			fprintf(stderr, "premature EOF\n");
			exit(1);
		}

		for (i = 0; i < bytecount; i++) {
			if (buf[i] > 0177) {
				printf("M-");
				buf[i] &= 0177;
			}
			if (iscntrl(buf[i])) {
				printf("^");
				buf[i] = (buf[i] + '@') & 0177;
			}
			if (isprint(buf[i]))
				printf("%c", buf[i]);
			else
				fprintf(stderr, "unprintable char???");
		}

		printf("\n");
	}
}
@//E*O*F showlog.c//
chmod u=r,g=r,o=r showlog.c
 
echo x - tcpanswer
sed 's/^@//' > "tcpanswer" <<'@//E*O*F tcpanswer//'
#!/bin/sh

case `biff` in
*[yY]*)
	biff=y
	biff n;;
*[nN]*)
	biff=n;;
*)
	# cannot determine biff state
	biff=;;
esac

case `mesg` in
*[yY]*)
	mesg=y
	mesg n;;
*[nN]*)
	mesg=n;;
*)
	# cannot determine mesg state
	mesg=;;
esac

trap "biff $biff; mesg $mesg; exit 1" 2 3

tcpdialer -answer

if [ "$biff" != "" ]; then
	biff $biff
fi

if [ "$mesg" != "" ]; then
	mesg $mesg
fi
@//E*O*F tcpanswer//
chmod u=rwx,g=rwx,o=rx tcpanswer
 
echo x - tcpcall
sed 's/^@//' > "tcpcall" <<'@//E*O*F tcpcall//'
#!/bin/sh

biff=`biff | sed 's/is //'`
mesg=`mesg | sed 's/is //'`
biff n
mesg n

tcpdialer -call $*

biff $biff
mesg $mesg
@//E*O*F tcpcall//
chmod u=rwx,g=rwx,o=rx tcpcall
 
echo x - tcpdialer.c
sed 's/^@//' > "tcpdialer.c" <<'@//E*O*F tcpdialer.c//'
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <sgtty.h>
#include <signal.h>
#include <time.h>

/*
 * tcpdialer - talk to a switch and remote dialer.
 *
 * usage: tcpdialer [ -e escape_char ] [ -l logfile ] [ -s ] [ -rp port ] [ -lp port ] [ -m max_tries ] -call host | -answer
 * 
 * ARGUMENTS
 * -e escape_char Change escape character, enter as numeric value of the
 *			character, use '\01' to set it to CNTRL-A
 * -l logfile	Log data transfer to logfile.out and logfile.in.
 * -s		Generate I/O stats when done.
 * -lp port	Local port number to use.
 * -rp port	Port number to use when on remote host.
 * -m max_tries	Maximum number of connection attempts.
 * -call host	Remote host to call.
 * -answer	Answer any callers.
 *
 * Terminate using by typing ^C^C^C (three control-Cs).
 */

static char* sccsid = "@(#)tcpdialer.c	1.7	10/29/93";

#define MOUTHPIECE	0
#define MAXPKTSIZE	1024
#define ON		1
#define OFF		0
#define CTRLC		'\003'

FILE* outputlogf = NULL;
FILE* inputlogf = NULL;
struct sockaddr_in datagram;
struct sgttyb saved_tty;
time_t start_time = 0;
char* program;
char* remotehost = NULL;
char* logfile = NULL;
char packet[MAXPKTSIZE];
char escape_char = CTRLC;
short remoteport = 6123;
short localport = 6123;
short statistics = 0;
short answermode = 0;
short max_tries = 30;
int pktcount = 0;
int minpktsize = MAXPKTSIZE + 1;
int maxpktsize = 0;
int totalsize = 0;
int sock;

void terminate();
void sig_child_handler();

main(argc, argv)
	int 	argc;
	char**	argv;
{

	program = *argv;

	for (argc--, argv++; argc; argc--, argv++) {
		if (!strcmp(*argv, "-rp")) {
			remoteport = atoi(*(argv+1));
			argc--;
			argv++;
		}
		else if (!strcmp(*argv, "-lp")) {
			localport = atoi(*(argv+1));
			argc--;
			argv++;
		}
		else if (!strcmp(*argv, "-e")) {
			argv++;
			argc--;
			escape_char = atoi(*argv) && 0xff;
			fprintf(stderr, "escape char set to %d\n",escape_char);
		}
		else if (!strcmp(*argv, "-l")) {
			logfile = *(argv+1);
			argv++;
			argc--;
		}
		else if (!strcmp(*argv, "-s")) {
			statistics = 1;
		}
		else if (!strcmp(*argv, "-m")) {
			max_tries = atoi(*(argv+1));
			argc--;
			argv++;
		}
		else if (!strcmp(*argv, "-call")) {
			remotehost = *++argv;
			argc--;
		}
		else if (!strcmp(*argv, "-answer")) {
			answermode = 1;
		}
		else {
			fprintf(stderr, "usage: dialer [ -e escape_char ] [ -l logfile ] [ -s ] [ -rp port ] [ -lp port ] [ -m max_tries ] -call host | -answer \n");
			exit(1);
		}
	}

	/* verify proper mode */
	if ( remotehost && answermode ) {
		fprintf(stderr, "usage: dialer [ -s ] [ -rp port ] [ -lp port ] [ -m max_tries ] -call host | -answer \n");
		exit(1);
	}
	if ( !remotehost && !answermode ) {
		fprintf(stderr, "usage: dialer [ -s ] [ -rp port ] [ -lp port ] [ -m max_tries ] -call host | -answer \n");
		exit(1);
	}

	init_socket();

	save_tty_settings();
	raw();
	echo(OFF);

	/* the following never return */
	if (make_handset() == MOUTHPIECE) {
		signal(SIGTERM, terminate);
		do_mouthpiece();
	}
	else {
		/* when mouthpiece dies, we should too */
		signal(SIGCHLD, sig_child_handler);

		do_earpiece();
	}

	exit(0);
}

/* this socket will be used for both sending and receiving */
init_socket() {

	void open_sock();
	struct sockaddr_in name;
	struct sockaddr_in saddr;
	struct hostent* hp;
	int msgsock;
	int errcode;
	int tries = 0;
	int len;

	open_sock();

	/* bind it */
	if (answermode) {
		name.sin_family = AF_INET;
		name.sin_addr.s_addr = INADDR_ANY;
		name.sin_port = htons(localport);
		if (bind(sock, (struct sockaddr*)&name, sizeof name) < 0) {
			perror("binding datagram socket");
			exit(2);
		}

		printf("Waiting for call...");
		fflush(stdout);
		listen(sock, 2);
		msgsock = accept(sock, (struct sockaddr*)0, (int*)0);
		if (msgsock == -1) {
			perror("accepting connection from remote host");
			exit(2);
		}
		len = sizeof(saddr);
		if (getpeername(msgsock, &saddr, &len) == 0) {
			printf("\007answered call from %s\n",inet_ntoa(saddr.sin_addr));
		}
		else {
			printf("\007answered call\n");
		}
		close(sock);
		sock = msgsock;
	}
	else {
		name.sin_family = AF_INET;
		hp = gethostbyname(remotehost);
		if (hp == 0) {
			fprintf(stderr, "%s: unknown host\n", remotehost);
			exit(2);
		}
		bcopy((char*)hp->h_addr, (char*)&name.sin_addr,hp->h_length);
		name.sin_port = htons(remoteport);

		/* try to make the connection */
		while (1) {
			printf("Ringing %s...", remotehost);
			fflush(stdout);
			errcode = connect(sock, (struct sockaddr*)&name,
					  sizeof name);
			if (errcode == -1) {
				if (errno == ECONNREFUSED || errno == EINTR) {
					sleep(5);
					if (++tries < max_tries) {
						printf("\n");
						close(sock);
						open_sock();
						continue;
					}
					else {
						/* too many retries */
						perror("connect");
						exit(2);
					}
				}
				else {
					/* error during connect */
					perror("connect");
					exit(2);
				}
			}
			else {
				printf("\007connected\n");
				break;
			}
		}
	}
}

void open_sock() {

	int on = 1;

	sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0) {
		perror("opening datagram socket");
		exit(2);
	}

#ifdef SO_KEEPALIVE
	/* use keepalives to force us to die when the remote dies */
	if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) == -1) {
	  	perror("cannot set sock option");
	}
#endif
}

/* create a reader process */
make_handset() {

	/*
	 * The reader process reads the tty and sends the data
	 * to the remote host.
	 */

	int pid = fork();
	if (pid < 0) {
		perror("forking reader process");
		exit(3);
	}

	return pid;
}

do_mouthpiece() {

	struct timeval tv;
	int bytecount;
	int endsequence = 0;
	char logname[1024];

	/* logfile prep */
	if (logfile) {
		strcpy(logname, logfile);
		strcat(logname, ".out");
		outputlogf = fopen(logname, "w");
	}

	/* record starting time */
	time(&start_time);

	while (1) {
		/* keep delay between read/write to a minimum! */
		bytecount = read(0, packet, 1024);
		if (bytecount) {
			if (write(sock, packet, bytecount) < 0)
				perror("sending datagram message");
	
			/* log data */
			if (outputlogf) {
				gettimeofday(&tv, NULL);
				fwrite(&tv, sizeof(tv), 1, outputlogf);
				fwrite(&bytecount, sizeof(bytecount), 1, outputlogf);
				fwrite(packet, sizeof(char), bytecount, outputlogf);
			}

			if (bytecount == 1 && (packet[0]&0177) == escape_char) {
				if (++endsequence == 3)
					terminate();
			}
			else
				endsequence = 0;

			/* statistics generation */
			pktcount++;
			totalsize += bytecount;
			if (bytecount < minpktsize) minpktsize = bytecount;
			else if (bytecount > maxpktsize) maxpktsize = bytecount;
		}
	}
}

do_earpiece() {

	struct timeval tv;
	int bytecount;
	char logname[1024];

	/* logfile prep */
	if (logfile) {
		strcpy(logname, logfile);
		strcat(logname, ".in");
		inputlogf = fopen(logname, "w");
	}

	while (1) {
		bytecount = read(sock, packet, 1024);
		if (bytecount > 0) {
			write(1, packet, bytecount);

			/* log data */
			if (inputlogf) {
				gettimeofday(&tv, NULL);
				fwrite(&tv, sizeof(tv), 1, inputlogf);
				fwrite(&bytecount, sizeof(bytecount), 1, inputlogf);
				fwrite(packet, sizeof(char), bytecount, inputlogf);
			}
		}
	}
}

/* save the original tty settings */
save_tty_settings() {
	gtty(0, &saved_tty);
}

/* restore the original tty settings */
restore_tty_settings() {
	stty(0, &saved_tty);
}

/* place the terminal in raw mode */
raw() {
	struct sgttyb tty;

	gtty(0, &tty);
	tty.sg_flags |= RAW;
	stty(0, &tty);
}

/* place the terminal in cooked mode */
cooked() {
	struct sgttyb tty;

	gtty(0, &tty);
	tty.sg_flags &= ~RAW;
	stty(0, &tty);
}

echo(on) 
	int on;
{

	struct sgttyb tty;

	gtty(0, &tty);
	if (on) {
		tty.sg_flags |= ECHO;
	}
	else
		tty.sg_flags &= ~ECHO;

	stty(0, &tty);
}

void sig_child_handler() {

	restore_tty_settings();

	if (outputlogf)
		fclose(outputlogf);
	if (inputlogf)
		fclose(inputlogf);

	exit(0);
}

void terminate() {

	time_t time_diff = time(0) - start_time;

	if (outputlogf)
		fclose(outputlogf);
	if (inputlogf)
		fclose(inputlogf);

	/* report statistics */
	if (statistics) {
		printf("%d packets, %d bytes, %d/%d/%d min/avg/max pkt size\r\n",
			pktcount, totalsize, minpktsize, totalsize/pktcount, 
			maxpktsize);
		if (time_diff)
			printf("%d seconds, %g pkt/s, %d b/s\r\n",
				time_diff, (float)pktcount / (float)time_diff, 
				totalsize/time_diff);
	}

	exit(0);
}
@//E*O*F tcpdialer.c//
chmod u=r,g=r,o=r tcpdialer.c
 
exit 0
