source to "phone" system (part 4 of 4)

Jonathan C. Broome broome at ucbvax.BERKELEY.EDU
Sun Dec 29 18:44:12 AEST 1985


#-----cut here-----cut here-----cut here-----cut here-----
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Makefile
#	convd.c
# This archive created: Sat Dec 28 01:11:14 1985
export PATH; PATH=/bin:$PATH
mkdir convd
cd convd
echo shar: extracting "'Makefile'" '(1515 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
cat << \!Funky!Stuff! > 'Makefile'
#
#  Makefile for phone conversation daemon        20 December 1985
#

# This one is pretty straightforward - no special flags for it.

CFLAGS	=	-O
SRCS	=	convd.c
DEST	=	convd
RDEST	=	/usr/local/lib/convd

all: ${DEST}

${DEST}:	${SRCS}
	/bin/rm -f ${DEST}
	cc ${CFLAGS} -o ${DEST} ${SRCS}

install:	${DEST}
	/bin/rm -f ${RDEST}
	cp ${DEST} ${RDEST}

clean:
	/bin/rm -f ${DEST} core *.o

shar:	Makefile ${SRCS}
	shar -v Makefile ${SRCS} > ../shar.convd

dist: ${DEST}
	-cp  ${DEST} ${RDEST}
	-rcp ${DEST} buddy:${RDEST}
	-rcp ${DEST} franny:${RDEST}
	-rcp ${DEST} holden:${RDEST}
	-rcp ${DEST} seymour:${RDEST}
	-rcp ${DEST} zooey:${RDEST}
	-rcp ${DEST} miro:${RDEST}
	-rcp ${DEST} cory:${RDEST}

depend: ${SRCS}
	mv Makefile makefile.old
	sed '/^# Dependencies follow/,$$d' makefile.old > Makefile
	echo '# Dependencies follow' >> Makefile
	includes -so ${SRCS} >> Makefile
	echo ' ' >> Makefile
	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >> Makefile
	echo '# see depend: above' >> Makefile

# DO NOT DELETE THE FOLLOWING LINE
# Dependencies follow

convd.o: /usr/include/errno.h

convd.o: /usr/include/sys/ttydev.h

convd.o: /usr/include/sys/ttychars.h

convd.o: /usr/include/sys/ioctl.h

convd.o: /usr/include/signal.h

convd.o: /usr/include/netdb.h

convd.o: /usr/include/netinet/in.h

convd.o: /usr/include/sys/socket.h

convd.o: /usr/include/sys/uio.h

convd.o: /usr/include/sys/types.h

convd.o: /usr/include/stdio.h

convd.o: ./../common.h
 
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see depend: above
!Funky!Stuff!
fi # end of overwriting check
echo shar: extracting "'convd.c'" '(9758 characters)'
if test -f 'convd.c'
then
	echo shar: will not over-write existing file "'convd.c'"
else
cat << \!Funky!Stuff! > 'convd.c'
#define	KERNEL_BUG

#ifndef lint
static char RCSid[] = "$Header: convd.c,v 1.1 85/10/29 14:20:06 broome Exp $";
#endif


/*
 *   The conversation daemon --- does all the main work 
 *   for one conversation.  It is invoked with stdin (fd 0)
 *   on the service port; it listens for requests there and
 *   does the right thing.
 *
 *   See the comments in ../client/readstream.c for an
 *   explanation of the command encoding scheme used here.
 *
 *   NOTE: this code relies heavily upon the writev() system call
 *   which provides for scatter/gather arrays of data, thus allowing
 *   us to to write out multiple arrays of characters in a single
 *   system call, thus avoiding having to copy data from one buffer
 *   to another.
 *
 *   Also ... note that we don't use slot #0 - the client program
 *   wants to remap the user's window into slot zero, so we help
 *   out by never assigning *anyone* that slot.
 */


/*
 * $Log:	convd.c,v $
 * Revision 1.1  85/10/29  14:20:06  broome
 * Initial revision
 */


#include "../common.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <errno.h>

#define BUFFER    128				/* size of char buffer to use     */
#define MAXSLOTS  32                /* max users/conversation         */

struct slot {
	int    inuse;                   /* this slot in use?              */
	char   *info;                   /* user's login, host, tty, etc.  */
	char   buffer[BUFFER];			/* text buffer                    */
	int    new;						/* index of most recent character */
	int    old;						/* index of oldest character      */
	int    fd;                      /* open stream file descriptor    */
	int    mask;					/* mask set on this file descrip. */
} slots[MAXSLOTS];        			/* all users in this conversation */

extern	int errno;
int		users;						/* number of users on             */
int		stayaround;					/* still waiting for first users  */
int		currslot;					/* current slot                   */
int		highslot;					/* highest slot number in use     */


#ifdef	KERNEL_BUG
int		warned = 0;
#endif

#define SIZ BUFFER					/* read this many chars from clients */
char	buf[SIZ];
char	*strsave();
char	*malloc();
int		sigalrm();


main ()
{
	register	struct slot *cslot;
	register	char *c;
	register	int  i;
	register	int  sl;
	register	int  fds;
	register	int  r;
	register	int  changed;
	static		int  new, old;
	struct		iovec iov[2];
	char 		recvbuf[SIZ];
	char		sel[1];		/* for selecting current window */
	int  		mask;		/* saved mask ... */
	int			rmask;		/* munged by select() */
	int			ind;

#ifdef NICE
	(void) nice (-3);		/* get a little bit of priority */
#endif

	users = 0;             /*  noone here yet */
	stayaround = 1;
	currslot = -1;
	highslot = -1;
	changed = 0;

	signal (SIGPIPE, SIG_IGN);	/* we'll find out soon enough */
	signal (SIGALRM, sigalrm);	/* to handle timeout */
	alarm (60 * 60);			/* go away if noone home */
	initslots ();         	 	/* clean everything out first */
	mask = 1 << 0;				/* stdin is service socket */

	iov[0].iov_base = sel;
	iov[0].iov_len = 1;
	iov[1].iov_base = recvbuf;

	do {
		rmask = mask;
		if ((fds = select (32, &rmask, 0, 0, 0)) <= 0)
			continue;
		if (rmask & (1 << 0))					/* service port */
			service (&mask);					/* let it modify mask */

		for (sl = 0; sl <= highslot && fds; sl++) {     /* client port */
			cslot = &slots[sl];
			if (cslot->inuse == 0)
				continue;
			if (rmask & cslot->mask) {			/* on this slot */
				fds--;							/* decrement slots to check */
				if ((r = read (cslot->fd, recvbuf, SIZ)) <= 0) {   /* EOF */
					mask &= ~(cslot->mask);		/* remove from mask */
					deluser (sl);
					if (sl == currslot)			/* have to switch windows */
						currslot = -1;			/* just in case ... */
				} else {
					iov[1].iov_len = r;
					new = cslot->new;			/* index of where to add */
					old = cslot->old;			/* index of oldest char  */
					c = &cslot->buffer[new];	/* so point to newest    */
					for (i = 0; i < r; i++) {
						*c++ = recvbuf[i];
						new++;
						if (new == BUFFER) {	/* at end of buffer    */
							new = 0;			/* so loop back around */
							c = cslot->buffer;
						} else if (new == old) {	/* full buffer         */
							old++;					/* so advance the end  */
							if (old == BUFFER)		/* wrapped around here */
								old = 0;
						}
					}
					cslot->new = new;  cslot->old = old; 	/* save pointers */

					if (sl != currslot) {     /* switch to this slot */
						sel[0] = (META | sl);
						currslot = sl;
						ind = 0;
					} else
						ind = 1;
					for (i = 0; i <= highslot; i++)		/* ship out to others */
						if (slots[i].inuse)
							(void) writev (slots[i].fd, &iov[ind], 2-ind);
				}
			}
		}
	} while ((users > 1) || (stayaround == 1));

	shutdown (0, 2);
	exit (17);
}



/*
 *  Set all the slots to an unused state before starting...
 */

initslots ()
{
	int i;
	for (i = 0; i < MAXSLOTS; i++) {
		slots[i].inuse = 0;
		slots[i].fd = -1;
	}
}


/*
 *  Handle a request on the service port.
 *  Modifies the socket select mask appropriately.
 */

service (mask)
int  *mask;
{
	register	int  new;
	register	int  j;
	register	char *i;
	struct		sockaddr_in addr;
	int			len;
	int			r;

	len = sizeof (addr);
	if ((new = accept (0, &addr, &len)) < 0) {
		if (errno != EINTR) 
#ifdef	KERNEL_BUG
			if (warned++ == 0)
#endif	KERNEL_BUG
				fatal (errno);
		return;
	}

	for (j = 1; j < MAXSLOTS; j++)
		if (slots[j].inuse == 0)
			break;

	if (j == MAXSLOTS) {
		write (new, "Too many users!\n", 16);
		shutdown (new, 2);
		close (new);
		return;
	}
	if ((r = read (new, buf, SIZ)) == 0) {	/* EOF ?? */
		close (new);
		return;
	}
	buf[r] = '\0';

	/* save name, host, tty, realname */
	slots[j].info = strsave (buf);

	if (j > highslot)
		highslot = j;

	slots[j].inuse = 1;
	slots[j].fd = new;
	slots[j].new = 0;
	slots[j].mask = 1 << new;
	slots[j].old = 0;
	users++;

	*mask |= (1 << new);					/* add new fd to mask */

	r = 1;
	ioctl (new, FIONBIO, &r);				/* mark socket as non-blocking */

	sprintf (buf, "%c%s%c", META | ADDUSER | j, 
				slots[j].info, META);
	sendit (buf, strlen (buf));		/* tell whole group about me */
	intro (new);					/* and fill me in on things */

	return;
}


/*
 *  Retransmit a message to all the users.
 */

sendit (buf, len)
char   *buf;
int     len;
{
	register int   i;

	for (i = 1; i <= highslot; i++)
		if (slots[i].inuse)
			if (write (slots[i].fd, buf, len) != len)
				perror ("sendit: write");
}


/*
 *  Delete a user from this conversation.
 */

deluser (i)
int i;
{
	int	ch;

	if (--users < 2) {
		shutdown (0, 2);
		close (0);
		exit (0);
	}
	stayaround = 0;
	slots[i].inuse = 0;

	close (slots[i].fd);
	free (slots[i].info);

	ch = META | DELUSER | i;
	sendit (&ch, 1);
}



/*
 *  Save a string.
 */

char *
strsave (s)
char *s;
{
	char *new, *malloc();

	if (new = malloc (strlen (s) + 1))
		strcpy (new, s);
	return (new);
}



/*
 *   Send the new filedes all the users and all the buffers.
 *   We first send UPDATE | 0 to tell the user to delay updating
 *   the screen until we've sent all the text buffers, at which 
 *   point we send UPDATE | 01 to signal that we're done and
 *   the screen should be updated.
 */

intro (fd)
int  fd;
{
	struct   iovec iov[3];		/* used for multi-buffer writes */
	register int old, new;
	register int  s;			/* slot number */
	register int  i;
	register char *c;
	register int num;			/* number of buffers to write out */
	char     sc;				/* used for slot number selection */

	/* tell user not to update screen until done with intro */
	sc = META | UPDATE | 00;	
	write (fd, &sc, 1);

	/* first go through and add all the windows */
	for (s = 0; s <= highslot; s++) {
		if (slots[s].inuse == 0 || slots[s].fd == fd)
			continue;
		sprintf (buf, "%c%s%c", META | ADDUSER | s, 
			slots[s].info, META);
		write (fd, buf, strlen (buf));
	}

	/* now go through and give him all the buffers */
	for (s = 0; s <= highslot; s++) {
		if (slots[s].inuse == 0 || slots[s].fd == fd)
			continue;

		sc = META | s;				/* switch to this slot */
		iov[0].iov_base = ≻
		iov[0].iov_len  = 1;

#ifdef notdef
		/raboof ======== foo bar baz zot blip/
			  ^ new      ^ old                ^ BUFFER
		|-----|          |-------------------|
		slots[s].new     BUFFER - slots[s].old
#endif notdef

		new = slots[s].new;
		old = slots[s].old;
		iov[1].iov_base = &slots[s].buffer[old];
		iov[1].iov_len  = (old > new ? BUFFER - old : new - old);
		if (old > new) {
			iov[2].iov_base = slots[s].buffer;
			iov[2].iov_len  = new;
			num = 3;
		} else 
			num = 2;

		writev (fd, iov, num);				/* write all at once!!! */
	}

	/* now he can update the screen */
	sc = META | UPDATE | 01;
	write (fd, &sc, 1);
}


/*
 *  Come here on alarm signal. If less than 2 users, exit.
 */

sigalrm ()
{
	if (users < 2) {
		shutdown (0, 2);
		close (0);
		exit (0);
	}
	return;
}


/*
 *  We have encountered some kind of nasty error.
 *  Tell all the users about it and go away.
 */

fatal (err)
int err;
{
	extern char *sys_errlist[];
	extern int  sys_nerr;
	char   buf[128];
	char   mesg[256];
	char   host[32];
	int    s;

	gethostname (host, 32);

	sprintf (mesg, "\nMessage from phone conversation daemon @ %s:\n", host);

	if (err < sys_nerr)
		sprintf (buf, "Fatal error: %s\n", sys_errlist[err]);
	else
		sprintf (buf, "Fatal error: %d", err);
	
#ifdef KERNEL_BUG		/* try to keep going */
	strcat (mesg, buf);
	strcat (mesg,"Warning: no more users can join this conversation! Sorry.\n");
#endif KERNEL_BUG

	for (s = 0; s <= highslot; s++)
		if (slots[s].inuse)
			write (slots[s].fd, mesg, strlen (mesg));
	
#ifndef	KERNEL_BUG
	chdir ("/");
	abort ();
	exit (1);
#endif	KERNEL_BUG

}
!Funky!Stuff!
fi # end of overwriting check
#	End of shell archive
exit 0



More information about the Comp.sources.unix mailing list