
/* videoserver.c */

#include <stdio.h>
#include <ctype.h>
#include <sys/time.h>

#include "videoserver.h"

#include "video_conf.h"
extern char *getenv();

/* 
	main should be called as:

		videoserver <output name> [optional service id]

	where <output-name> is a valid output device in the host machine's
	/etc/video.conf file. (see video.conf.doc)

	An example would be "unix:0" or `hostname`:0 or "unix:1" or `hostname`:1
	for a local server, or "CH-8" for a server which outputs to campus cable
	channel number 8.

	The port number for IPC will be: 
	  VIDSERVE_SERVER_BASE_ID + <display-number>*10,
	unless you are starting a REMOTE server, in which case it will be 
	  VIDSERVE_SERVER_BASE_ID.
*/	

static VCONF_DEVTABLE	vdt;	/* video device table for the server */

#define MAXCLIENTS 10
#define MAXMONITORS 10

	/*----------------------------------------------------------*/
	/*	
	/*	State of each possible client
	/*	
	/*----------------------------------------------------------*/

struct client {

	int state;				/* state of this client */
						/* descriptor */
#define CL_DEAD 1				/* client not started */
#define CL_STARTING 2				/* accepted, reply ongoing */
#define CL_UP 3					/* ready to go */

	int action;				/* what are we doing now */

#define CL_RECEIVE 4				/* waiting for a packet */
#define CL_SEND    5				/* sending a packet */
#define CL_ACCEPT  6				/* sending a reply */

	CONNECTION con;				/* connection to this */
						/* client, if any */
	OPERATION pending_op;			/* pending operation */
						/* on this connection, */
						/* if any */

	int	waiting;			/* received a request while mon was busy */
	TUPLE	request;			/* input from client */
	TUPLE	reply;				/* output to client */
};

struct monitor
{
	FILE *	fp_w;			/* file for pipe writes */
	FILE *	fp_r;			/* file for pipe reads */
	int	fd;			/* the fd for testing reads (fp_r) */
	int	not_responding;		/* is the monitor's device not responding? */

	int	state;			/* what are we doing now? */
#define MON_DEAD    10			/* hasn't been awakened yet */
#define	MON_IDLE    11 			/* waiting for a client request */
#define MON_BUSY    12			/* waiting for a reply from rpd_pipe */

	int	myclient;		/* the index of the client to respond to */
};

static TUPLE_DESCRIPTOR req_desc;
static TUPLE_DESCRIPTOR rep_desc;

static TUPLE_DESCRIPTOR vtbl_desc;

static TUPLE vdev_tuple[MAXMONITORS];
static RELATION mytable;

static struct client client[MAXCLIENTS];
static struct monitor monitor[MAXMONITORS];

static int	repcode, repval, reperr;

static int	locked = 0;		/* is the videoserver currently locked by some client? */
static int	locking_client = -1;	/* index of client which is locking the videoserver */

	/*----------------------------------------------------------*/
	/*	
	/*	Connections and operations for listening for
	/*	new clients.
	/*	
	/*----------------------------------------------------------*/

static CONNECTION listencon;			/* listen on this */
						/* connection */
static OPERATION  listenop;			/* this operation is used */
						/* repeatedly for listening */
						/* for new clients */

static int	nextcl = 0;			/* index of the next client */
						/* we'll accept */
static int	nmons = 0;		/* number of monitors connected to this server */
static int      startmon = nmons;   /* MH added this for multiple heads */

	/*----------------------------------------------------------*/
	/*	
	/*	Miscellaneous variables used in acquiring connections.
	/*	These are ignored in a simple server like this;  a 
	/*	more sophisticated server might want to validate the
	/*	names of its clients before accepting connections.
	/*	
	/*----------------------------------------------------------*/

static TUPLE client_tuple;			/* client request goes */
						/* here */
static char otherside[100];
static int othersize;

static char outname[64];
static char servicename[64];
static char thishost[64];

/* following are for the select() call */
static fd_set	myReadFDs;		/* permanent */
static fd_set	readfds, writefds, exceptfds;		/* for each select() call */
static struct timeval myTimeout;	/* permanent */
static struct timeval timeout;		/* for each call */
static int	nfound, nfds;

int
goodbye()
{
	exit(1);
}

int
main(argc,argv)

	int	argc;
	char	*argv[];
{
int		sid = VIDSERVE_SERVER_BASE_ID;	/* the service id# */
int		got_sid = 0;

char		outhost[64];
int		head = 0;
LIST_OF_OPERATIONS op_list;	/* for op_select_any */
LIST_OF_OPERATIONS lock_list;
register int i,j;		/* loop index */
int	nrpds = 0;
TUPLE	t;
int	sw, ch;
char	sstr[16];
char	command[128];	/* command line */
char	line[256];	/* from a monitor */
int	waiting = 0;
int	nwaiting = 0;
int	failed = 0;
int	stat;
int	TimeOut;
char	from[64];
int	fromlen = 64;

	if( argc > 2 )
	{
	fprintf(stderr,
			"usage: %s <output-name>.\n",argv[0]);
		goodbye();
	}

	if( argc == 1 )
		strcpy(outname,getenv("DISPLAY"));
	else
		strcpy(outname,argv[1]);

	FD_ZERO(&readfds);
	FD_ZERO(&writefds);
	FD_ZERO(&exceptfds);

	gethostname(thishost,64);

	if( index(outname,':') )	/* allow name shortcuts */
	{
		if( !strcmp(outname,":0") || !strcmp(outname,"unix:0") )
		{
			sprintf(outname,"%s:0",thishost);
			got_sid = 1;
			sid = VIDSERVE_SERVER_BASE_ID;
		}
		else if( !strcmp(outname,":1") || !strcmp(outname,"unix:1") )
		{
			sprintf(outname,"%s:1",thishost);
			got_sid = 1;
			sid = VIDSERVE_SERVER_BASE_ID+10;
			nmons += 2; /* MH added this kludge 11/26 */
			startmon = nmons;  /* MH, 11/26 */
		}
	}

	vconf_mkupper( outname );
/*
	if( argc == 3 )
	{
		sid = atoi(argv[2]);
		got_sid = 1;	
		printf("videoserver: using service id #%d\n",sid);
	}
*/
	if( vconf_get_table( outname, VCONF_FILENAME, &vdt ) != VCONF_AOK )
			goodbye();
	if( vdt.ndevs < 1 )
	{
		printf("no devices controllable for output on '%s'\n",outname);
		goodbye();
	}

	/* more checking for correct output device for server */

	for( i=0; i<vdt.ndevs; i++ )
	{
		vconf_mkupper( vdt.dev[i].name );
		switch( vdt.dev[i].type )
		{
			case OUTPUT_DEV:
				/* set the service id */
				if( !got_sid && !strcmp(vdt.dev[i].name,outname) )
				{
					if( index(outname,':') )	/* local server */
					{
						sscanf(outname,"%s:%d",outhost,&head);
						sid = VIDSERVE_SERVER_BASE_ID+(head*10);
						nmons *= 2; /*MH added this */
						startmon = nmons; /* MH, 11/26*/
					}
					else	/* remote server */
					{
						vconf_split_chan( vdt.dev[i].channel, &sw, &ch );
						sid = VIDSERVE_SERVER_BASE_ID+(sw*10);
						/* kludge, but this guarantees unique server
						id's on this machine, because there can't be
						two duplicate swtr numbers */
					}	
				}
				break;
			default:
				break;
		}
	}
/*
	printf("devices controllable by this server:\n");

	for( i=0; i < vdt.ndevs; i++ )
	{
		printf("\n=========================================\n");
		printf("device #%d:\n",i);
		printf("\ttype : %s\n",vconf_nameoftype(vdt.dev[i].type) );
		printf("\tname : %s\n",vdt.dev[i].name);
		printf("\tmodel: %s\n",vdt.dev[i].model);
		printf("\tmon  : %s\n",vdt.dev[i].mon_proc);
		printf("\tport : /dev/%s\n",vdt.dev[i].tty);
		printf("\tbaud : %d\n",vdt.dev[i].baud);
		printf("\tpar  : %s\n",vconf_nameofparity(vdt.dev[i].parity));
		printf("\tchan : %s\n",vdt.dev[i].channel);
	}
*/
	gdb_init();				/* set up gdb */

	/* build the server request and standard reply descriptors */

	req_desc = create_tuple_descriptor( SERVER_REQUEST_FIELDS, 
		server_request_field_names, server_request_field_types );
	rep_desc = create_tuple_descriptor( STD_REPLY_FIELDS, 
		std_reply_field_names, std_reply_field_types );

	init_clients();				/* null the client states */
	init_monitors();			/* null the monitor states */

	sprintf(servicename,"%s:#%d",thishost,sid);
	printf("videoserver for '%s' listening at port '%s'\n",outname,servicename);

	sprintf(sstr,"#%d",sid);
	do_listen(sstr);			/* start the listening */
						/* connection and queue */
						/* a listening operation */
	make_oplist(&op_list);			/* create wait list */

	/* now standardize the device names in this table, and start the monitors */

	for( i=0; i<vdt.ndevs; i++ )
	{
		switch( vdt.dev[i].type )
		{
			case SWTR_DEV:
				/* start the swtr mon */

				sprintf(command,
					"%s %s </dev/ttyq%x >/dev/ttyq%x 2>/dev/null",
					vdt.dev[i].mon_proc,
					vdt.dev[i].name,
					(nmons*2),(nmons*2)+1 );

				printf("COMMAND: '%s'\n",command);
				popen(command,"r");
				sprintf(command,"/dev/ptyq%x",(nmons*2));
				monitor[nmons].fp_w = fopen(command,"w");
				sprintf(command,"/dev/ptyq%x",(nmons*2)+1);
				monitor[nmons].fp_r = fopen(command,"r");

				strcpy(vdt.dev[i].name,"SWTR");
				nmons++;
				break;
			case RPD_DEV:
				/* start the rpd mon */

				sprintf(command,
					"%s %s </dev/ttyq%x >/dev/ttyq%x 2>/dev/null",
					vdt.dev[i].mon_proc,
					vdt.dev[i].name,
					(nmons*2),(nmons*2)+1 );

				printf("COMMAND: '%s'\n",command);
				popen(command,"r");
				sprintf(command,"/dev/ptyq%x",(nmons*2));
				monitor[nmons].fp_w = fopen(command,"w");
				sprintf(command,"/dev/ptyq%x",(nmons*2)+1);
				monitor[nmons].fp_r = fopen(command,"r");

				sprintf(vdt.dev[i].name,"RPD-%d",++nrpds);
				nmons++;
				break;
			default:
				break;
		}
	}

	/* build the vdt relation */

	vtbl_desc = create_tuple_descriptor( VTBL_FIELDS,
		vtbl_field_names, vtbl_field_types );

	/* fill the vdt relation */

	mytable = create_relation( vtbl_desc );

	for( i=0; i<vdt.ndevs; i++ )
	{
		t = vdev_tuple[i] = create_tuple( vtbl_desc );
		initialize_tuple( t );

		*(int *)FIELD_FROM_TUPLE(t,0) = vdt.dev[i].type;

		string_alloc((STRING *)FIELD_FROM_TUPLE(t,1), 32);
		strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(t,1))),vdt.dev[i].name);

		string_alloc((STRING *)FIELD_FROM_TUPLE(t,2), 32);
		strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(t,2))),vdt.dev[i].model);

		string_alloc((STRING *)FIELD_FROM_TUPLE(t,3), 64);
		strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(t,3))),vdt.dev[i].mon_proc);

		string_alloc((STRING *)FIELD_FROM_TUPLE(t,4), 16);
		strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(t,4))),vdt.dev[i].tty);
 
		*(int *)FIELD_FROM_TUPLE(t,5) = vdt.dev[i].baud;

		*(int *)FIELD_FROM_TUPLE(t,6) = vdt.dev[i].parity;

		string_alloc((STRING *)FIELD_FROM_TUPLE(t,7), 16);
		strcpy(STRING_DATA(*((STRING *)FIELD_FROM_TUPLE(t,7))),vdt.dev[i].channel);

		ADD_TUPLE_TO_RELATION( mytable, t );
	}

	/* now must wait for all the monitors to come up; set their states to
	MON_IDLE if successful or MON_DEAD if not */

	FD_ZERO(&myReadFDs);

	for( nfds=0, i=startmon; i<nmons; i++ )
	{
		monitor[i].fd = fileno(monitor[i].fp_r);
/*		printf("read fd for monitor %d is %d\n",i,monitor[i].fd); */
		if( monitor[i].fd > nfds )
			nfds = monitor[i].fd;	/* get the max number */
		FD_SET(monitor[i].fd,&myReadFDs);
	}
	nfds += 1;	/* one greater than maximum file descriptor */

	fprintf(stderr,"videoserver: waiting up to 30 seconds for devices to activate ...\n");

	set_timeout( 30000, &TimeOut );	/* wait no more than 30 seconds */
	nwaiting = nmons;

	while( TimeOut != 1 && nwaiting )
	{
		timeout.tv_sec = 1;	/* check fd's every second */
		timeout.tv_usec = 0;

		bcopy(&myReadFDs,&readfds,sizeof(fd_set));

		nfound = select( nfds, &readfds, NULL,NULL, &timeout );
		if( nfound > 0 )	/* at least one ready to read */
		{
	/*		printf("something happened\n"); */
			for( i=0; i<nmons; i++ )
				if( FD_ISSET(monitor[i].fd,&readfds) )
				{
				/*	printf("scanning input from mon %d\n",i); */
					fgets(line,255,monitor[i].fp_r);
					sscanf(line,"%d %d %d",
						&repcode,&repval,&reperr);
					if( repcode < 0 && repval < 0 && reperr < 0 )
					{
						monitor[i].state = MON_DEAD;
						monitor[i].fp_r = NULL;
						monitor[i].fp_w = NULL;
						monitor[i].fd = -1;
						monitor[i].not_responding = 1;
				/*		printf("monitor %d is dead!\n",i); */
					}
					else
					{
						monitor[i].state = MON_IDLE;
						monitor[i].not_responding = 0;
				/*		printf("monitor %d is reading\n",i); */
						--nwaiting;
					}
				}
		}
		else if( nfound == 0 )
		{
		/*	printf("timer went off\n"); */
		}
		/*
		else
			printf("error in select\n"); 
		*/
	}
	set_timeout( 0, &TimeOut );	/* un-set the timer */

	if( nwaiting == 0 )
	fprintf(stderr,
		"videoserver: all devices present and accounted for.\n");
	else
	{
		fprintf(stderr,
		"videoserver: couldn't attach to all of the devices.\n");
		goodbye();
	}

	
	/*----------------------------------------------------------*/
	/*	
	/*	     Loop forever taking care of business.
	/*	
	/*	1) If any new connection requests have come in,
	/*	   accept them.
	/*	
	/*	2) For each client on which some activity is newly
	/*	   completed, take care of it.
	/*	
	/*----------------------------------------------------------*/

	while (TRUE) 
	{
		if (OP_DONE(listenop))
		{
		/*	printf("got a new connection\n"); */
			new_connection();
		}
		for(i=0; i<MAXCLIENTS; i++)
		{
			if (OP_DONE(client[i].pending_op) || client[i].waiting)
				do_client(i);
		}
		if( !locked )
		{
			bcopy(&myReadFDs,&readfds,sizeof(fd_set));
			nfound = op_select_any(op_list, nfds, &readfds, 
				&writefds, &exceptfds, NULL);
			if( nfound > 0 )
			{
			/*	printf("something happened\n"); */
				for( i=0; i<nmons; i++ )
				{
					if( FD_ISSET(monitor[i].fd,&readfds) )
						do_monitor(i);
				}
			}
		}
		else
		{
			lock_list = create_list_of_operations(1,
				client[locking_client].pending_op );
			bcopy(&myReadFDs,&readfds,sizeof(fd_set));
			nfound = op_select_any(lock_list, nfds, &readfds, 
				&writefds, &exceptfds, NULL);
			if( nfound > 0 )
			{
			/*	printf("something happened\n"); */
				for( i=0; i<nmons; i++ )
				{
					if( FD_ISSET(monitor[i].fd,&readfds) )
						do_monitor(i);
				}
			}
		}
	}
}

/************************************************************************/
/*	
/*				do_client
/*	
/*	An operation has completed on the specified client.
/*	
/************************************************************************/

int
do_client(id)
int id;
{
	register struct client *cp = &(client[id]);
	register struct monitor *mp;
	int	devnum;
	int	reqtype;
	int	reqp1;
	int	reqp2;
	int	reqp3;	
	int	reqp4;
	int	res;
	int	failed = 0;

	if( cp->waiting )
		cp->waiting = 0;

       /*
        * If there has been an error, shutdown the client.
        */
	if (OP_STATUS(cp->pending_op) == OP_CANCELLED) 
	{
		sever_connection(cp->con);
		reset_operation(cp->pending_op);
		cp->state = CL_DEAD;
		cp->action = 0;
		/* unlock device, if locked and this client was the culprit */
		if( locked && locking_client == id )
		{
			locked = 0;
			locking_client = -1;
		}
		return;
	}

       /*
        * The operation completed successfully.  Figure out what it was
        * and do the right thing.
        */

	switch (cp->action) 
	{
	      case CL_ACCEPT:
	      case CL_SEND:
/*		if( cp->action == CL_ACCEPT )
			printf("accepting connection from client %d\n",id); */

		start_receiving_object(cp->pending_op, cp->con, 
				       (char *) &cp->request,
				       TUPLE_T);
		cp->action = CL_RECEIVE;
		return;
		break;
	      case CL_RECEIVE:

		/* next line is added for locking capability */
		if( locked && locking_client != id)
		{
			reset_operation( cp->pending_op );
			cp->waiting = 1;			
			return;
		}

		devnum = *((int *)FIELD_FROM_TUPLE(cp->request,0));
		reqtype = *((int *)FIELD_FROM_TUPLE(cp->request,1));
		initialize_tuple( cp->reply );

		if( devnum == VIDSERVE_SERVER_DEVICE )
		{
			switch( reqtype )
			{
			case	VIDSERVE_RESET:	/* should forward reset to all devices!!! */
				locked = 0;
				locking_client = -1;
				break;
			case	VIDSERVE_LOCK:
				locked = 1;
				locking_client = id;
				break;
			case	VIDSERVE_UNLOCK:
				locked = 0;
				locking_client = -1;
				break;
			case	VIDSERVE_GET_DEVICE_TABLE:
				start_sending_object(cp->pending_op, cp->con, 
					       &mytable,
					       RELATION_T);
				cp->action = CL_SEND;
				return;		/* unique case; returns relation */
				break;
			default:
				fprintf(stderr,"%s: unknown videoserver request id #%d\n",
					servicename,reqtype);
				*((int *)FIELD_FROM_TUPLE(cp->reply,0)) = 
					VIDSERVE_REQ_FAILURE;
				break;
			}
			start_sending_object(cp->pending_op, cp->con, 
				       &cp->reply,
				       TUPLE_T);
			cp->action = CL_SEND;
		}
		else
		{
			/* forward message to a device */

/*			printf(">>> message for device %d\n",devnum); */

			if( devnum >=0 && devnum < nmons )
			{
				mp = &(monitor[devnum]);
				if( mp->state == MON_BUSY )
				{
					reset_operation( cp->pending_op );
					cp->waiting = 1;
					return;	/* hangs until current request finished */
				}

				/* indicate we are servicing this op */
				reset_operation( cp->pending_op );

				if( mp->state == MON_DEAD )
				{
					initialize_tuple(cp->reply);
					*((int *)FIELD_FROM_TUPLE(cp->request,0)) = VIDSERVE_REQ_FAILURE;
					*((int *)FIELD_FROM_TUPLE(cp->request,1)) = 0;
					*((int *)FIELD_FROM_TUPLE(cp->request,2)) = -2;
					start_sending_object(cp->pending_op, cp->con, 
					       &cp->reply,
					       TUPLE_T);
					cp->action = CL_SEND;
					return;
				}

				/* monitor state must be MON_IDLE */

				reqp1 = *((int *)FIELD_FROM_TUPLE(cp->request,2));
				reqp2 = *((int *)FIELD_FROM_TUPLE(cp->request,3));
				reqp3 = *((int *)FIELD_FROM_TUPLE(cp->request,4));
				reqp4 = *((int *)FIELD_FROM_TUPLE(cp->request,5));
				initialize_tuple(cp->reply);

				mp->state = MON_BUSY;
				mp->myclient = id;
		/*		printf(">>> forwarding message is %d %d %d %d %d\n",
					reqtype,reqp1,reqp2,reqp3,reqp4); */
				fprintf(mp->fp_w,"%d %d %d %d %d\n",
					reqtype,reqp1,reqp2,reqp3,reqp4);
				fflush(mp->fp_w);
			}
			else
			{
				fprintf(stderr,"videoserver: request to unknown device\n");
				/* must send back error msg to client */
				*((int *)FIELD_FROM_TUPLE(cp->reply,0)) = 
					VIDSERVE_REQ_FAILURE;
				start_sending_object(cp->pending_op, cp->con, 
					       &cp->reply,
					       TUPLE_T);
				cp->action = CL_SEND;
			}
		}
	default:
		fprintf("videoserver: strange case!\n");
		break;
	}	/* end of big switch */
}

/************************************************************************/
/*	
/*				do_monitor
/*	
/*	An operation has completed on the specified monitor
/*	
/************************************************************************/

int
do_monitor(id)
int id;
{
	register struct monitor *mp = &(monitor[id]);
	register struct client *cp;
	int	repcode, repval, reperr;
	char	line[256];
	int	failed = 0;

	fgets(line,255,mp->fp_r);
	sscanf(line,"%d %d %d\n",
		&repcode,&repval,&reperr);
	if( reperr < 0 )
		mp->not_responding = 1;
	else
		mp->not_responding = 0;

	/* forward the reply to the originating client */
	cp = &(client[mp->myclient]);
	*((int *)FIELD_FROM_TUPLE(cp->reply,0)) = repcode;
	*((int *)FIELD_FROM_TUPLE(cp->reply,1)) = repval;
	*((int *)FIELD_FROM_TUPLE(cp->reply,2)) = reperr;
	start_sending_object(cp->pending_op, cp->con, 
	       (char *)&cp->reply,TUPLE_T);
	cp->action = CL_SEND;

	mp->state = MON_IDLE;
	mp->myclient = -1;
}

/************************************************************************/
/*	
/*			  init_clients
/*	
/************************************************************************/

int
init_clients()
{
	register struct client *c;

	for (c=client; c<client+MAXCLIENTS; c++){
		c->state = CL_DEAD;
		c->action = 0;
		c->con = NULL;
		c->pending_op = create_operation();
		reset_operation(c->pending_op);	
		c->request = create_tuple(req_desc);
		c->reply = create_tuple(rep_desc);
		initialize_tuple(c->request);
		initialize_tuple(c->reply);
	}
}

/************************************************************************/
/*	
/*			  init_monitors
/*	
/************************************************************************/

int
init_monitors()
{
	register struct monitor *m;

	for (m=monitor; m<monitor+MAXMONITORS; m++)
	{
		m->fp_w = NULL;
		m->fp_r = NULL;
		m->fd = -1;
		m->state = MON_DEAD;
		m->not_responding = 1;
		m->myclient = -1;
	}
}


/************************************************************************/
/*	
/*			make_oplist
/*	
/************************************************************************/

int
make_oplist(oplp)
LIST_OF_OPERATIONS *oplp;
{
       /*
        * ugh! we've got to fix create_list_of_operations to be
        * more flexible!!
        */

	*oplp = create_list_of_operations(MAXCLIENTS+1, listenop,
					  client[0].pending_op,
					  client[1].pending_op,
					  client[2].pending_op,
					  client[3].pending_op,
					  client[4].pending_op,
					  client[5].pending_op,
					  client[6].pending_op,
					  client[7].pending_op,
					  client[8].pending_op,
					  client[9].pending_op);
}
/************************************************************************/
/*	
/*				do_listen
/*	
/*	Do the one time setup for listening for clients, and
/*	also start a listen for an actual client.
/*	
/************************************************************************/

int
do_listen(service)
char *service;
{
CONNECTION	test;
int		stat;

	/*----------------------------------------------------------*/
	/*	
	/*	Make a listening connection
	/*	
	/*----------------------------------------------------------*/

	/* first check to see if anyone else is at the GDB port; if so,
		give it up */

	test = start_server_connection(servicename,"");
	stat = connection_status( test );
	if( stat == CON_UP )
	{
		fprintf(stderr,"videoserver: duplicate monitor at GDB port '%s'; quitting\n",
			service);
		sever_connection(test);
		goodbye();
	}
	sever_connection(test);
	
	listencon = create_listening_connection(service);

	if (listencon == NULL || connection_status(listencon) != CON_UP) {
		fprintf(stderr,"videoserver: couldn't create listen connection at '%s'.\n",
			service);
		goodbye();
	}
	fprintf(stderr,"videoserver: listening connection created on port '%s'.\n",
		service);	

	/*----------------------------------------------------------*/
	/*	
	/*	On that connection, put up an operation to listen
	/*	for our first client.
	/*	
	/*----------------------------------------------------------*/

	listenop = create_operation();

	othersize = sizeof(otherside); 

	start_accepting_client(listencon, listenop, &(client[nextcl].con),
			       (char *)otherside,
			       &othersize, &client_tuple);

}

/************************************************************************/
/*	
/*			new_connection
/*	
/*	We have just gotten a connection for client nextcl.  
/*	
/************************************************************************/

int
new_connection()
{
	register struct client *cp = &client[nextcl];
       /*
        * Make sure there's been no error
        */
	if(OP_STATUS(listenop) != OP_COMPLETE ||
	   cp->con == NULL) {
		fprintf(stderr,"videoserver: %s error on listen op\n",servicename);
		goodbye();
	}
       /*
        * Set up the new connection and reply to the client
        */
	cp->state = CL_STARTING;
	cp->action = CL_ACCEPT;
	start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED,
				 "", "");

       /*
        * Find a new free connection descriptor.  Blow up if we've used the
        * last one
        */
	for (nextcl=0; nextcl<MAXCLIENTS; nextcl++)
		if (client[nextcl].state == CL_DEAD)
			break;

	if (nextcl == MAXCLIENTS) {
		fprintf(stderr,"videoserver: '%s' has too many clients, giving up\n",
			servicename);
		goodbye();
	}
       /*
        * Start listening again
        */
	reset_operation(listenop);
	othersize = sizeof(otherside);

	start_accepting_client(listencon, listenop, &(client[nextcl].con),
			       (char *)otherside,
			       &othersize, &client_tuple);


}
