/*
 * Copyright (c) 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-sock.c,v 1.2 2005/08/24 22:50:24 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/test.h"
#include "sm/io.h"
#include "sm/ctype.h"
#include "sm/signal.h"
#include "sm/socket.h"
#include "sm/sockcnf.h"
#include "timing.h"

#include <stdio.h>

#define SM_CHECK_NET_UNIX	1
static char *nsocket = "./cltsrv";

#include "t-net-common.c"

/*
**  CLIENT -- write wr characters to localhost:port
**
**	Parameters:
**		ip -- IP address to use
**		port -- port
**		wr -- number of chars to send
**		delay -- sleep time before close
**		bsize -- buffer size to use
**		timeout -- timeout
**		both -- if >0: do write and read ("both" times)
**			sets double buffering
**		iter -- number of iterations (writing data)
**		net -- use an INET (or LOCAL) socket
**
**	Returns:
**		none
*/

static void
client(char *ip, int port, int wr, int delay, int bsize, int timeout, int both, int iter, bool net)
{
	int fd;
	sm_ret_T ret;
	sockspec_T sock;

	if (Verbose > 1)
		fprintf(stderr, "clt: connect\n");
	sm_memzero(&sock, sizeof(sock));
	if (net)
	{
		sock.sckspc_type = SOCK_TYPE_INET;
		sock.sock_inet.inetsckspc_port = port;
		sock.sock_inet.inetsckspc_addr = inet_addr(ip);
	}
	else
	{
		sock.sckspc_type = SOCK_TYPE_UNIX;
		sock.sock_unix.unixsckspc_path = nsocket;
	}
	fd = INVALID_SOCKET;
	ret = sock_connect(&sock, &fd);
	if (Verbose > 1)
		fprintf(stderr, "clt: connected=%d\n", fd);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		return;
	SM_TEST(fd >= 0);
	if (fd < 0)
		return;
	while (iter-- > 0)
	{
		ret = write_sock(fd, wr, delay, bsize, timeout, both);
		SM_TEST(sm_is_success(ret));
		if (!sm_is_success(ret))
		{
			if (Verbose > 0)
				fprintf(stderr, "client: error %x\n", ret);
			return;
		}
	}
}

/*
**  SERVER -- receive rd characters on localhost:port
**
**	Parameters:
**		ip -- IP address to use
**		port -- port
**		rd -- number of chars to receive
**		rep -- loop through all of this rep times
**		delay -- sleep time before close
**		bsize -- buffer size to use
**		backlog -- size of listen queue
**		timeout -- timeout
**		both -- if >0: do write and read ("both" times)
**			sets double buffering
**		iter -- number of iterations (reading data)
**		net -- use an INET (or LOCAL) socket
**
**	Returns:
**		none
*/

static void
server(char *ip, int port, int rd, int rep, int delay, int bsize, int backlog, int timeout, int both, int iter, bool net)
{
	int fd, lfd;
	sm_ret_T ret;
	sm_sockaddr_T addr;
	sockaddr_len_T addrlen;
	sockspec_T sock;

	ret = 0;
	lfd = fd = INVALID_SOCKET;
	if (net)
	{
		sock.sckspc_type = SOCK_TYPE_INET;
		sock.sock_inet.inetsckspc_port = port;
		sock.sock_inet.inetsckspc_addr = inet_addr(ip);
	}
	else
	{
		sock.sckspc_type = SOCK_TYPE_UNIX;
		sock.sock_unix.unixsckspc_path = nsocket;
		sock.sock_unix.unixsckspc_umask = 0600;
	}
	ret = sock_listen(&sock, backlog, &lfd);
	SM_TEST(sm_is_success(ret));
	if (!sm_is_success(ret))
		goto err;
	SM_TEST(lfd >= 0);
	if (lfd < 0)
		return;
	while (rep-- > 0)
	{
		addrlen = sizeof(addr);
		if (Verbose > 1)
			fprintf(stderr, "srv: accept\n");
		ret = socket_accept(lfd, &addr, &addrlen, &fd);
		SM_TEST(sm_is_success(ret));
		if (!sm_is_success(ret))
			goto err;
		SM_TEST(fd >= 0);
		if (fd < 0)
			goto err;
		while (iter-- > 0)
		{
			ret = read_sock(fd, rd, delay, bsize, timeout, both);
			if (sm_is_err(ret))
				goto err;
		}
		fd = -1;
		if (Verbose > 0)
			fprintf(stderr, "srv: read_sock done=%x\n", ret);
		if (sm_is_err(ret))
			goto err;
	}
  err:
	if (fd >= 0)
		close(fd);
	if (lfd >= 0)
		close(lfd);
}

int
main(int argc, char *argv[])
{
	bool clt, any;
	int c, port, rd, wr, rep, delay, backlog, bsize, timeout, both, iter;
	char *ip;
	bool net;

	opterr = 0;
	clt = true;
	any = false;
	port = SM_DEFPORT;
	rd = wr = 0;
	rep = 1;
	delay = 0;
	bsize = 0;
	backlog = 20;
	timeout = 5;
	Verbose = 0;
	both = 0;
	iter = 1;
	ip = "127.0.0.1";
	net = true;
	while ((c = getopt(argc, argv, "b:Bc:d:i:I:l:p:r:R:s:St:TuU:V")) != -1)
	{
		any = true;
		switch (c)
		{
		  case 'B':
			both++;
			break;
		  case 'b':
			bsize = atoi(optarg);
			break;
		  case 'c':
			clt = true;
			wr = atoi(optarg);
			break;
		  case 'd':
			delay = atoi(optarg);
			break;
		  case 'i':
			iter = atoi(optarg);
			break;
		  case 'I':
			ip = strdup(optarg);
			if (ip == NULL)
			{
				fprintf(stderr, "out of memory");
				return 1;
			}
			break;
		  case 'l':
			backlog = atoi(optarg);
			break;
		  case 'p':
			port = atoi(optarg);
			break;
		  case 'r':
			rep = atoi(optarg);
			break;
		  case 'R':
			both = atoi(optarg);
			break;
		  case 's':
			clt = false;
			rd = atoi(optarg);
			break;
		  case 't':
			timeout = atoi(optarg);
			break;
		  case 'u':
			net = false;
			break;
		  case 'S':
			fprintf(stderr, "sizeof sm_file_T: %d\n", sizeof(sm_file_T));
			fprintf(stderr, "sizeof sm_stream_T: %d\n", sizeof(sm_stream_T));
			fprintf(stderr, "sizeof smbuf_T: %d\n", sizeof(smbuf_T));
			break;
		  case 'T':
			Timing = true;
			break;
		  case 'U':
			nsocket = strdup(optarg);
			if (nsocket == NULL)
			{
				fprintf(stderr, "out of memory");
				return 1;
			}
			break;
		  case 'V':
			++Verbose;
			break;
		  default:
			usage(argv[0]);
			return 1;
		}
	}
	signal(SIGPIPE, SIG_IGN);
	sm_test_begin(argc, argv, "test net 0");
	if (!any)
		goto end;

	if (clt)
		client(ip, port, wr, delay, bsize, timeout, both, iter, net);
	else
	{
		server(ip, port, rd, rep, delay, bsize, backlog, timeout, both, iter, net);
	}
  end:
	(void) unlink(nsocket);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1