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