static char IDudpclient[] = "@(#)udpclient %D";
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* udpclient [-/+options] host port
*
* This  is  a  basic  UDP client program, which talks to udpserver 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.
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
:1#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";
HOST  hostent = {0};	/* Where to put host info */
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 */
SKin  sndr = {0};	/* Address of sender */
int   sndl = 0;		/* Actual size of sndr */
int   wsleep = 1;	/* Seconds between writes */

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

:1	ac = Vinit(ac,av);


	for (a=1; a<ac; a++) {
:3		V3 "Arg %2d: \"%s\"",a,av[a] V;
		switch (c0 = av[a][0]) {
		case '-':
		case '+':
:2			V3 "Opt %2d: \"%s\"",a,av[a] V;
			switch (c1 = av[a][1]) {
			case 'm':
			case 'M':
				msg = av[a] + 2;
:2				V2 "Msg: \"%s\"",Dsps(msg,-1) V;
:5				H6(msg,strlen(msg),"msg");
				break;
			case 'n':
			case 'N':
				if (sscanf(av[a]+2,ifmt,&msgs) < 1)
					++n;
:2				V2 "Writing %d messages.",msgs V;
				break;
			case 's':
			case 'S':
				if (sscanf(av[a]+2,ifmt,&wsleep) < 1)
					++n;
:2				V2 "Wait %d seconds between messages.",wsleep V;
				break;
			case 't':
			case 'T':
				if (sscanf(av[a]+2,ifmt,&rsleep) < 1)
					++n;
:2				V2 "Wait %d seconds for replies.",rsleep V;
				break;
:1			default:
:1				V1 "Arg %2d: \"%s\" ignored.",a,av[a] V;
:1				break;
			}
			break;
		default:
			if (!portname && (sscanf(av[a],ifmt,&port) > 0)) {
				portname = av[a];
:2				V2 "Port: \"%s\"",portname V;
:3				V3 "port: %d.",port V;
			} else
			if (!hostname) {
				hostname = av[a];
:2				V2 "Host: \"%s\"",hostname V;
:1			} else {
:1				V1 "Arg %2d: \"%s\" ignored.",a,av[a] V;
			}
			break;
		}
	}
	if (!port) port = 2345;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Create socket on which to read.                                      *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
:6	V6 "before socket(AF_INET=%d, SOCK_DGRAM=%d, 0)",AF_INET,SOCK_DGRAM V;
	sock = Socket(AF_INET, SOCK_DGRAM, 0);
	if (sock < 0) {
:1		V1 "### Can't get datagram socket [Err %d=%s=%s]",Errinfo V;
		r = 2;
		Fail;
	}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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;
:3		V3 "No host; using \"%s\"",hostname V;
	}
	hp = Gethostbyn(hostname);
	if (hp) {
		Bcopy(hp->h_addr,&(addr.sin_addr.s_addr),hp->h_length);
		addr.sin_family = AF_INET;
		addr.sin_port = htons(port);
:6		H6(&addr,sizeof(addr),"addr");
	} else {
:1		V1 "Can't gethostbyname for \"%s\" [Err %d=%s=%s]",hostname,Errinfo V;
		exit(errno);
	}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Send the messages. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
	for (m=1; m<=msgs; m++) {
		Sleep(wsleep);
:5		H6(msg,strlen(msg),"msg");
		sprintf(buf,msg,m,'\n');
		n = strlen(buf);
:5		V5 "Msg %2d: \"%s\"",m,Dsps(buf,n) V;
:3		H3(buf,n,"Put");

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

