/*
 * Copyright (c) 2002, 2004, 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-rcbsrvclt.c,v 1.10 2005/05/31 21:00:28 ca Exp $")
#include "sm/assert.h"
#include "sm/error.h"
#include "sm/test.h"
#include "sm/memops.h"
#include "sm/io.h"
#include "sm/ctype.h"
#include "sm/fcntl.h"
#include "sm/rcb.h"
#include "sm/unixsock.h"
#include "sm/check.h"
#include "t-rcb.h"

#include <stdio.h>

/*
**  RCB Server/Client
**	This program acts as a server for RCBs.
**	It accepts incoming connections, and starts function to deal
**	with them (no thread, sequential operation).
**	That function (connection()) reads one RCB, displays its content
**	(see rcvrcb() in t-rcb-sr.c for details), then reads data from
**	stdin, creates an RCB out of it and sends it to the client
**	(see sendrcb() in t-rcb-sr.c for details).
*/

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

int Verbose;

void
usage(const char *prg)
{
	fprintf(stderr, "usage: %s [options] socket\n", prg);
	exit(0);
}

/* dirty hack ahead: specify timeout for function call */
#define TMO 
#include "t-rcb-sr.c"

/*
**  CONNECTION -- receive and send rcb (alternating)
**
**	Parameters:
**		fd -- file descriptor
**
**	Returns:
**		none
*/

void
connection(int fd, bool clientfirst)
{
	sm_rcb_P rcb;
	sm_ret_T ret;

	ret = SM_SUCCESS;
	rcb = sm_rcb_new(NULL, SM_RCBSIZE, SM_MAXRCBSIZE);
	SM_TEST(rcb != NULL);
	if (rcb == NULL)
		goto done;

	do
	{
		if (clientfirst)
		{
			if (Verbose > 3)
				fprintf(stderr, "clt: rcb_rcv\n");
			ret = rcvrcb(rcb, fd, true);
			if (sm_is_err(ret))
				break;
		}
		clientfirst = true;

		if (Verbose > 3)
			fprintf(stderr, "src: sendrcb\n");
		ret = sendrcb(rcb, fd);
		if (sm_is_err(ret))
			break;
	} while (!sm_is_err(ret));

  done:
	if (rcb != NULL)
		sm_rcb_free(rcb);
}

/*
**  SERVER -- wait for connections
**
**	Parameters:
**		sockname -- name of socket
**
**	Returns:
**		none
*/

void
server(char *sockname, bool clientfirst)
{
	int fd, lfd, servfd;
	struct sockaddr addr;
	sockaddr_len_T addrlen;

	lfd = fd = servfd = -1;
	unlink(sockname);
	lfd = unix_server_listen(sockname, 10);
	SM_TEST(lfd >= 0);
	if (lfd < 0)
		return;

	for (;;)
	{
		addrlen = sizeof(addr);
		if (Verbose > 1)
			fprintf(stderr, "srv: accept\n");
		fd = unix_server_accept(lfd, &addr, &addrlen);
		SM_TEST(fd >= 0);
		if (fd < 0)
			goto err;
		if (Verbose > 1)
			fprintf(stderr, "srv: accepted fd=%d\n", fd);

		connection(fd, clientfirst);
		(void) close(fd);
	}

  err:
	if (fd >= 0)
		close(fd);
	if (lfd >= 0)
		close(lfd);
}

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

	opterr = 0;
	Verbose = 0;
	sockname = NULL;
	clientfirst = true;
	prg = argv[0];
	while ((c = getopt(argc, argv, "cV")) != -1)
	{
		switch (c)
		{
		  case 'V':
			++Verbose;
			break;
		  case 'c':
			clientfirst = false;
			break;
		  default:
			usage(prg);
		}
	}
	sm_test_begin(argc, argv, "unix socket rcb server");
	argc -= optind;
	argv += optind;
	if (argc <= 0)
		usage(prg);
	sockname = argv[0];
	server(sockname, clientfirst);
	return sm_test_end();
}


syntax highlighted by Code2HTML, v. 0.9.1