static char IDtcpclient[] = "@(#)tcpclient 07/10/15";
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* tcpclient [-/+options] host port
*
* This is a basic TCP client program, which  talks  to  tcpserver  and
* swaps  a  few  messages.  It takes a hostname and port number on its
* command line, which default to "localhost" and 2345.
*
* Options may start with '+' or '-' to enable/disable  features;  with
* the  options  for which this doesn't make sense, either may be used.
* An option letter may be upper or lower case.
*
* The options recognized are:
*
* -m"message"
*   sends  the  message  to  the  recipient.   It is used as a sprintf
*   format, and will get two args: the message count, and a '\n'.  The
*   default message is "Message %d.%c".
*
* -n<n>
*   number of messages:  write <n> messages; the default is 1.
*
* -s<s>
*   sleep time:  wait <s> seconds between messages; the default is 1.
*
* -t<t>
*   timeout:  waits <t> seconds for replies; the default is 10.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "V.h"
#include "sys_socket.h"
#include "sys_in.h"
#include "sys_netdb.h"

#define BUF 50		/* Enough to hold longest message */

char  buf[BUF];
char *dfl_host = "localhost";
char *hostname = 0;
char  ifmt[] = "%d";
char *msg = "Message %d.%c";
int   msgs = 1;		/* Number of messages to send */
TIMV  tmout = {1};	/* How long to wait in select() */
char *portname = 0;
int   port = 0;
U32   now, then;	/* Timestamps */
U32   rmask = 0;	/* Select read mask */
int   rsleep = 10;	/* Seconds to wait for supplies */
int   wsleep = 1;	/* Seconds between writes */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*/
main(ac,av)
	int   ac;
	char**av;
{	int   r=0;	/* Result (exit status) */
	char *p;
	int   c0, c1;
	int   a, i, m, n, sock;
	SKin addr;
	HOST *hp, *gethostbyname();

	ac = Vinit(ac,av);


	for (a=1; a<ac; a++) {
		V3 "Arg %2d: \"%s\"",a,av[a] D;
		switch (c0 = av[a][0]) {
		case '-':
		case '+':
			V3 "Opt %2d: \"%s\"",a,av[a] D;
			switch (c1 = av[a][1]) {
			case 'm':
			case 'M':
				msg = av[a] + 2;
				V2 "Msg: %s",Dspp(msg) D;
				H6(msg,strlen(msg),"msg");
				break;
			case 'n':
			case 'N':
				if (sscanf(av[a]+2,ifmt,&msgs) < 1)
					++n;
				V2 "Writing %d messages.",msgs D;
				break;
			case 's':
			case 'S':
				if (sscanf(av[a]+2,ifmt,&wsleep) < 1)
					++n;
				V2 "Wait %d seconds between messages.",wsleep D;
				break;
			case 't':
			case 'T':
				if (sscanf(av[a]+2,ifmt,&rsleep) < 1)
					++n;
				V2 "Wait %d seconds for replies.",rsleep D;
				break;
			default:
				V1 "Arg %2d: \"%s\" ignored.",a,av[a] D;
				break;
			}
			break;
		default:
			if (!portname && (sscanf(av[a],ifmt,&port) > 0)) {
				portname = av[a];
				V2 "Port: \"%s\"",portname D;
				V3 "port: %d.",port D;
			} else
			if (!hostname) {
				hostname = av[a];
				V2 "Host: \"%s\"",hostname D;
			} else {
				V1 "Arg %2d: \"%s\" ignored.",a,av[a] D;
			}
			break;
		}
	}
	if (!port) port = 2345;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Create socket on which to read.                                      *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	V6 "before socket(AF_INET=%d, SOCK_STREAM=%d, 0)",AF_INET,SOCK_STREAM D;
	sock = Socket(AF_INET, SOCK_STREAM, 0);
	if (sock < 0) {
		V1 "### Can't get datagram socket [Err %d=%s=%s]",Errinfo D;
		r = 2;
		Fail;
	}
	V3 "Got TCP stream socket %d.",sock D;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Construct address of socket to send to.   Gethostbyname()  retuns  a *
* structure  including the network address of the specified host.  The *
* port number is taken from the command line.                          *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	if (!hostname) {
		hostname = dfl_host;
		V3 "No host; using \"%s\"",hostname D;
	}
	hp = Gethostbyn(hostname);
	Bcopy(hp->h_addr,&(addr.sin_addr.s_addr),hp->h_length);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	H6(&addr,sizeof(addr),"addr");

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Try to make a connection to the server.                              *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	if (Connect(sock,&addr,sizeof(addr)) < 0) {
		V1 "Can't connect to %s.%u.",
			ipdot(&addr.sin_addr),
			ntohs( addr.sin_port) D;
		Fail;
	}
	V3 "Connected to %s.%u.",
		ipdot(&addr.sin_addr),
		ntohs( addr.sin_port) D;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Send the messages. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	for (m=1; m<=msgs; m++) {
		Sleep(wsleep);
		H6(msg,strlen(msg),"msg");
		sprintf(buf,msg,m,'\n');
		n = strlen(buf);
		V5 "Msg %2d: %s",m,Dsps(buf,n) D;
		H6(buf,n,"buf");

		if (Write(sock, buf, n) < 0) {
			V1 "Can't send message %d [Err %d=%s=%s]",m,Errinfo D;
			r = m;
			Fail;
		}
		if (Vlvl) printf("Put: %s\n",Dsps(buf,n));
	}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Stick around for rsleep seconds, waiting for replies.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	fprintf(stderr,"Wait %d seconds for replies ...\n",rsleep);
	then = UnixTime(0);
loop:
	now = UnixTime(0);
	if ((tmout.tv_sec = rsleep - (now - then)) < 0) {
		V2 "Out of time." D;
		Done;
	}
	rmask = 1 << sock;
	errno = 0;
	if ((i = Select(sock+1, &rmask,0,0,&tmout)) > 0) {
		V3 "Got input, rmask=%08X",rmask D;
		if ((n = Read(sock, buf, BUF)) > 0) {
			buf[n] = 0;
			V2 "Got from %s.%d %s\n",
				ipdot(&addr.sin_addr),
				ntohs( addr.sin_port),
				Dsps(buf,n) D;
		/*	Write(1,buf,n); */
			if (Vlvl) printf("Got: %s\n",Dsps(buf,n));
			Loop;
		}
	}
	if (i == 0) {
		V2 "Timeout." D;
		Done;
	}
	if (errno) {
		V2 "Can't read from socket [Err %d=%s=%s]",Errinfo D;
	} else {
		V2 "EOF from socket." D;
	}
fail:
done:
	Close(sock);	/* For debug messages */
	Exit(r);
}
usage()
{
	printf("Usage: %s [-/+options] [host] [port]\n", pname);
}

