/*
 * Copyright (c) 2002-2005 Sendmail, Inc. and its suppliers.
 *	All rights reserved.
 *
 * By using this file, you agree to the terms and conditions set
 * forth in the LICENSE file which can be found at the top level of
 * the sendmail distribution.
 */

#include "sm/generic.h"
SM_RCSID("@(#)$Id: t-unixcl.c,v 1.13 2005/10/24 22:47:09 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/test.h"
#include "sm/io.h"
#include "sm/ctype.h"
#include "sm/types.h"
#include "sm/fcntl.h"
#include "sm/unixsock.h"
#include "sm/time.h"
#include "sm/signal.h"

#include <stdio.h>

extern char *optarg;
extern int optind;
extern int optopt;
extern int opterr;

static int Verbose;

#define SM_BUFSIZE	8192

static void
usage(const char *prg)
{
	fprintf(stderr, "usage: %s [options] socket\n", prg);
	fprintf(stderr, "open a connection to a server via a Unix domain socket for writing\n");
	fprintf(stderr, "-r   also read from socket\n");
	fprintf(stderr, "-V   increase verbosity\n");
	exit(0);
}

/*
**  CLIENT -- send data read from stdin over a socket (byte by byte)
**	(yes, it's highly inefficient, but it's only a test program)
**
**	Parameters:
**		sockname -- name of socket or IP address
**		rd -- also read?
**		port -- use port (if IP address)
**
**	Returns:
**		none
*/

static void
client(char *sockname, bool rd, int port)
{
	int fd;
	int res, c;
	char buf[2];
	fd_set rdset;
	timeval_T timeout;
	int flags;

	if (Verbose > 1)
		fprintf(stderr, "clt: connect\n");
	if (port > 0)
		(void) net_client_connect(sockname, port, &fd);
	else
		(void) unix_client_connect(sockname, &fd);
	if (Verbose > 1)
		fprintf(stderr, "clt: connected=%d, errno=%d\n", fd, errno);
	SM_TEST(fd >= 0);
	if (fd < 0)
		return;

	buf[1] = '\0';
	FD_ZERO(&rdset);
	flags = fcntl(fd, F_GETFL, 0);
	SM_TEST(flags != -1);
	res = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
	SM_TEST(res != -1);
	while ((c = getchar()) != EOF)
	{
		buf[0] = (char) c;
		res = write(fd, buf, 1);
		SM_TEST(res == 1 || errno == EPIPE);
		if (res != 1)
		{
			fprintf(stderr, "clt: write_fd failed=%x, errno=%d\n",
				res, errno);
			break;
		}
		if (rd)
		{
			do
			{
				FD_ZERO(&rdset);
				FD_SET(fd, &rdset);
				timeout.tv_sec = 0;
				timeout.tv_usec = 0;
				res = select(fd + 1, &rdset, NULL, NULL,
						&timeout);
				if (res == 1 && FD_ISSET(fd, &rdset))
				{
					c = read(fd, buf, 1);
					if (c == 1)
					{
						fprintf(stdout, "%c", buf[0]);
					}

					/* EOF... */
					if (c == 0)
						rd = false;
				}
			} while (rd && res == 1 && FD_ISSET(fd, &rdset));
			fflush(stdout);
		}
	}
	if (rd)
	{
		do
		{
			FD_ZERO(&rdset);
			FD_SET(fd, &rdset);
			timeout.tv_sec = 1;
			timeout.tv_usec = 0;
			res = select(fd + 1, &rdset, NULL, NULL,
					&timeout);
			if (res == 1 && FD_ISSET(fd, &rdset))
			{
				c = read(fd, buf, 1);
				if (c == 1)
				{
					fprintf(stdout, "%c", buf[0]);
				}

				/* EOF... */
				if (c == 0)
					rd = false;
			}
		} while (rd && res == 1 && FD_ISSET(fd, &rdset));
		fflush(stdout);
	}
	close(fd);
}

int
main(int argc, char *argv[])
{
	int c;
	char *sockname, *prg;
	int port;
	bool rd;

	prg = argv[0];
	opterr = 0;
	Verbose = 0;
	port = 0;
	sockname = NULL;
	rd = false;
	while ((c = getopt(argc, argv, "p:rV")) != -1)
	{
		switch (c)
		{
		  case 'p':
			port = atoi(optarg);
			break;
		  case 'r':
			rd = true;
			break;
		  case 'V':
			++Verbose;
			break;
		  default:
			usage(prg);
		}
	}
	argc -= optind;
	argv += optind;
	if (argc < 1)
		usage(prg);
	sockname = argv[0];
	--argc;
	++argv;

	signal(SIGPIPE, SIG_IGN);
	sm_test_begin(argc, argv, "unix socket client");
	client(sockname, rd, port);
	c = sm_test_end();
	return c;
}


syntax highlighted by Code2HTML, v. 0.9.1