/***********************************************************************
*                                                                      *
*               This software is part of the ast package               *
*           Copyright (c) 1990-2006 AT&T Knowledge Ventures            *
*                      and is licensed under the                       *
*                  Common Public License, Version 1.0                  *
*                      by AT&T Knowledge Ventures                      *
*                                                                      *
*                A copy of the License is available at                 *
*            http://www.opensource.org/licenses/cpl1.0.txt             *
*         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
*                                                                      *
*              Information and Software Systems Research               *
*                            AT&T Research                             *
*                           Florham Park NJ                            *
*                                                                      *
*                 Glenn Fowler <gsf@research.att.com>                  *
*                                                                      *
***********************************************************************/
#pragma prototyped
/*
 * Glenn Fowler
 * AT&T Research
 *
 * cs service test
 */

static const char id[] = "@(#)$Id: cs.tst-old (AT&T Research) 1997-11-11 $\0\n";

#define TST_VERSION	"1.0"

#include <cs.h>
#include <ctype.h>
#include <error.h>
#include <tm.h>

typedef struct
{
	Cs_id_t		id;
	int		clone;
	char*		args;
} Connection_t;

typedef struct
{
	int		active;
	int		dormant;
	Connection_t	id[1];
} State_t;

static char	buf[1024];
static char	dat[1024];

static void*
svc_init(void* handle, int maxfd)
{
	State_t*	state;

	NoP(handle);
	if (!(state = newof(0, State_t, 1, (maxfd - 1) * sizeof(Connection_t)))) exit(1);
	cstimeout(20 * 1000L);
	return (void*)state;
}

static int
svc_connect(void* handle, int fd, Cs_id_t* id, int clone, char** argv)
{
	State_t*	state = (State_t*)handle;
	char*		s;
	Sfio_t*		sp;
	char**		ap;

	NoP(clone);
	state->active++;
	state->dormant = 0;
	state->id[fd].id = *id;
	state->id[fd].clone = clone;
	state->id[fd].args = 0;
	if ((ap = argv) && (sp = sfstropen()))
	{
		while (s = *ap++)
		{
			if (ap > argv + 1)
				sfputc(sp, ' ');
			sfputr(sp, s, -1);
		}
		state->id[fd].args = strdup(sfstruse(sp));
		sfclose(sp);
	}
	return 0;
}

static int
svc_read(void* handle, int fd)
{
	State_t*	state = (State_t*)handle;
	int		n;

	if ((n = csread(fd, dat, sizeof(dat), CS_LINE)) <= 0) goto drop;
	dat[--n] = 0;
	if (isalpha(dat[0]) && (dat[1] == 0 || isdigit(dat[1]))) switch (dat[0])
	{
	case 'd':
		error_info.trace = -(int)strtol(dat + 1, NiL, 0);
		n = sfsprintf(buf, sizeof(buf), "I debug level %d\n", -error_info.trace);
		break;
	case 'Q':
		if (state->active == 1) exit(0);
		/*FALLTHROUGH*/
	case 'q':
		goto drop;
	default:
		n = sfsprintf(buf, sizeof(buf), "E %s: unknown command\n", dat);
		break;
	}
	else
		n = sfsprintf(buf, sizeof(buf), "I [%s] server=%s version=%s %s=%s server.pid=%d pid=%d uid=%d gid=%d clone=%d args=`%s'\n", fmttime(*dat ? dat : "%K", time(NiL)), csname(0), TST_VERSION, CS_HOST_LOCAL, csntoa(state->id[fd].id.hid), getpid(), state->id[fd].id.pid, state->id[fd].id.uid, state->id[fd].id.gid, state->id[fd].clone, state->id[fd].args);
	if (cswrite(fd, buf, n) != n) goto drop;
	return 0;
 drop:
	if (state->id[fd].args) free(state->id[fd].args);
	state->active--;
	return -1;
}

static int
svc_timeout(void* handle)
{
	State_t*	state = (State_t*)handle;

	error(1, "timeout active=%d dormant=%d", state->active, state->dormant);
	if (state->active <= 0)
	{
		if (state->dormant)
			exit(0);
		state->dormant = 1;
	}
	return 0;
}

int
main(int argc, char** argv)
{
	NoP(argc);
	csserve(NiL, argv[1], svc_init, NiL, svc_connect, svc_read, NiL, svc_timeout);
	exit(1);
}
