v02i025: monitor X11 Server/Client communications, Part04/04
Mike Wexler
mikew at wyse.wyse.com
Tue Nov 29 04:21:52 AEST 1988
Submitted-by: peterson at sw.mcc.com (James Peterson)
Posting-number: Volume 2, Issue 25
Archive-name: xmonitor/part04
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of archive 4 (of 4)."
# Contents: fd.c server.c x11.h
# Wrapped by mikew at wyse on Mon Nov 28 10:13:39 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'fd.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'fd.c'\"
else
echo shar: Extracting \"'fd.c'\" \(4686 characters\)
sed "s/^X//" >'fd.c' <<'END_OF_FILE'
X/* ************************************************************ *\
X * *
X * Support routines for file descriptors (FD) *
X * *
X * James Peterson, 1987 *
X * (c) Copyright MCC, 1987 *
X * *
X * *
X \* *********************************************************** */
X
X#include "scope.h"
X
X
X/*
X All of this code is to support the handling of file descriptors (FD).
X The idea is to keep a table of the FDs that are in use and why.
X For each FD that is open for input, we keep the name of a procedure
X to call if input arrives for that FD. When an FD is created
X (by an open, pipe, socket, ...) declare that by calling UsingFD.
X When it is no longer in use (close ...), call NotUsingFD.
X*/
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
XInitializeFD()
X{
X register short i;
X
X enterprocedure("InitializeFD");
X /* get the number of file descriptors the system will let us use */
X MaxFD = getdtablesize();
X
X /* allocate space for a File Descriptor (FD) Table */
X FDD = (struct FDDescriptor *)
X Malloc ((long)(MaxFD * sizeof (struct FDDescriptor)));
X
X /* be sure all fd's are closed and marked not busy */
X for (i = 0; i < MaxFD; i++)
X {
X /* 0, 1, 2 are special (stdin, stdout, stderr) */
X if (i > 2)
X close(i);
X FDD[i].Busy = false;
X }
X
X /* save one FD for single file input or output like debugging */
X /* also the getservbyname call is currently using an FD */
X MaxFD -= 4;
X
X nFDsInUse = 0 /* stdin, stdout, stderr */ ;
X ReadDescriptors = 0;
X HighestFD = 0;
X
X UsingFD(fileno(stdin), (int (*)())NULL);
X UsingFD(fileno(stdout), (int (*)())NULL);
X UsingFD(fileno(stderr), (int (*)())NULL);
X}
X
X/* ************************************************************ */
X
XUsingFD(fd, Handler)
X FD fd;
X int (*Handler)();
X{
X if (FDD[fd].Busy)
X NotUsingFD(fd);
X nFDsInUse += 1;
X
X FDD[fd].Busy = true;
X FDD[fd].InputHandler = Handler;
X if (Handler == NULL)
X ReadDescriptors &= ~(1 << fd) /* clear fd bit */ ;
X else
X ReadDescriptors |= 1 << fd /* set fd bit */ ;
X
X if (fd > HighestFD)
X HighestFD = fd;
X
X if (nFDsInUse >= MaxFD)
X panic("no more FDs");
X
X debug(128,(stderr, "Using FD %d, %d of %d in use\n", fd, nFDsInUse, MaxFD));
X}
X
X/* ************************************************************ */
X
XNotUsingFD(fd)
X FD fd;
X{
X debug(128,(stderr, "Not Using FD %d\n", fd));
X
X if (FDD[fd].Busy)
X nFDsInUse -= 1;
X
X FDD[fd].Busy = false;
X ReadDescriptors &= ~(1 << fd) /* clear fd bit */ ;
X
X while (!FDD[HighestFD].Busy && HighestFD > 0)
X HighestFD -= 1;
X
X debug(128,(stderr, "Highest FD %d, in use %d\n", HighestFD, nFDsInUse));
X}
X
X/* ************************************************************ */
X
XEOFonFD(fd)
X FD fd;
X{
X enterprocedure("EOFonFD");
X debug(128,(stderr, "EOF on %d\n", fd));
X close(fd);
X NotUsingFD(fd);
X}
X
X
X/* ************************************************************ */
X/* */
X/* Main Loop -- wait for input from any source and Process */
X/* */
X/* ************************************************************ */
X
X#include <errno.h> /* for EINTR, EADDRINUSE, ... */
Xextern int errno;
X
X
XMainLoop()
X{
X enterprocedure("MainLoop");
X
X while (true)
X {
X int rfds, wfds, xfds;
X short nfds;
X short fd;
X
X /* wait for something */
X rfds = ReadDescriptors;
X wfds = 0;
X xfds = rfds;
X
X debug(128,(stderr, "select %d, rfds = 0%o\n", HighestFD + 1, rfds));
X nfds = select(HighestFD + 1, &rfds, &wfds, &xfds, NULL);
X debug(128,(stderr, "select nfds = 0%o, rfds = 0%o, 0%o, xfds 0%o\n",
X nfds, rfds, wfds, xfds));
X
X if (nfds < 0)
X {
X if (errno == EINTR)
X continue /* to end of while loop */ ;
X debug(1,(stderr, "Bad select - errno = %d\n", errno));
X if (errno == EBADF)
X {
X /* one of the bits in rfds is invalid, close down
X files until it goes away */
X EOFonFD(HighestFD);
X continue;
X }
X
X panic("Select returns error");
X continue /* to end of while loop */ ;
X }
X
X if (nfds == 0)
X {
X TimerExpired();
X continue;
X }
X
X /* check each fd to see if it has input */
X for (fd = 0; 0 < nfds && fd <= HighestFD; fd++)
X {
X /*
X check all returned fd's; this prevents
X starvation of later clients by earlier clients
X */
X
X if ((rfds & (1 << fd)) == 0)
X continue;
X
X nfds -= 1;
X
X if (FDD[fd].InputHandler == NULL)
X {
X panic("FD selected with no handler");
X debug(1,(stderr, "FD %d has NULL handler\n", fd));
X }
X else
X (FDD[fd].InputHandler)(fd);
X }
X }
X}
END_OF_FILE
if test 4686 -ne `wc -c <'fd.c'`; then
echo shar: \"'fd.c'\" unpacked with wrong size!
fi
# end of 'fd.c'
fi
if test -f 'server.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'server.c'\"
else
echo shar: Extracting \"'server.c'\" \(14093 characters\)
sed "s/^X//" >'server.c' <<'END_OF_FILE'
X/* ************************************************** *
X * *
X * Code to decode and print X11 protocol *
X * *
X * James Peterson, 1988 *
X * (c) Copyright MCC, 1988 *
X * *
X * ************************************************** */
X
X#include "scope.h"
X#include "x11.h"
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
XReportFromClient(fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X PrintTime();
X fprintf(stdout, "Client%s --> %4d %s\n",
X ClientName(fd), n, (n == 1 ? "byte" : "bytes"));
X ProcessBuffer(fd, buf, n);
X}
X
XReportFromServer(fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X PrintTime();
X fprintf(stdout, "\t\t\t\t\t%4d %s <-- X11 Server%s\n",
X n, (n == 1 ? "byte" : "bytes"), ClientName(fd));
X ProcessBuffer(fd, buf, n);
X}
X
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X#include <sys/time.h> /* for struct timeval * */
Xstatic long ZeroTime1 = -1;
Xstatic long ZeroTime2 = -1;
Xstatic struct timeval tp;
X
X/* print the time since we started in hundredths (1/100) of seconds */
X
XPrintTime()
X{
X static long lastsec = 0;
X long sec /* seconds */ ;
X long hsec /* hundredths of a second */ ;
X
X gettimeofday(&tp, (struct timezone *)NULL);
X if (ZeroTime1 == -1 || (tp.tv_sec - lastsec) >= 1000)
X {
X ZeroTime1 = tp.tv_sec;
X ZeroTime2 = tp.tv_usec / 10000;
X }
X
X lastsec = tp.tv_sec;
X sec = tp.tv_sec - ZeroTime1;
X hsec = tp.tv_usec / 10000 - ZeroTime2;
X if (hsec < 0)
X {
X hsec += 100;
X sec -= 1;
X }
X fprintf(stdout, "%2d.%02ld: ", sec, hsec);
X}
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* we will need to be able to interpret the values stored in the
X requests as various built-in types. The following routines
X support the types built into X11 */
X
Xlong pad (n)
X long n;
X{
X /* round up to next multiple of 4 */
X return((n + 3) & ~0x3);
X}
X
Xunsigned long ILong (buf)
X unsigned char buf[];
X{
X return((((((buf[0] << 8) | buf[1]) << 8) | buf[2]) << 8) | buf[3]);
X}
X
Xunsigned short IShort (buf)
Xunsigned char buf[];
X{
X return((buf[0] << 8) | buf[1]);
X}
X
Xunsigned short IByte (buf)
Xunsigned char buf[];
X{
X return(buf[0]);
X}
X
XBoolean IBool(buf)
X unsigned char buf[];
X{
X if (buf[0] != 0)
X return(true);
X else
X return(false);
X}
X
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* we will need to save bytes until we get a complete request to
X interpret. The following procedures provide this ability */
X
XSaveBytes(fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X /* check if there is enough space to hold the bytes we want */
X if (CS[fd].NumberofSavedBytes + n > CS[fd].SizeofSavedBytes)
X {
X /* not enough room so far; malloc more space and copy */
X long SizeofNewBytes = (CS[fd].NumberofSavedBytes + n + 1);
X unsigned char *NewBytes = (unsigned char *)Malloc (SizeofNewBytes);
X bcopy(/* from */(char *)CS[fd].SavedBytes,
X /* to */(char *)NewBytes,
X /* count */(int)CS[fd].SizeofSavedBytes);
X Free((char *)CS[fd].SavedBytes);
X CS[fd].SavedBytes = NewBytes;
X CS[fd].SizeofSavedBytes = SizeofNewBytes;
X }
X
X /* now copy the new bytes onto the end of the old bytes */
X bcopy(/* from */(char *)buf,
X /* to */(char *)(CS[fd].SavedBytes + CS[fd].NumberofSavedBytes),
X /* count */(int)n);
X CS[fd].NumberofSavedBytes += n;
X}
X
XRemoveSavedBytes(fd, n)
X FD fd;
X long n;
X{
X /* check if all bytes are being removed -- easiest case */
X if (CS[fd].NumberofSavedBytes <= n)
X CS[fd].NumberofSavedBytes = 0;
X else if (n == 0)
X return;
X else
X {
X /* not all bytes are being removed -- shift the remaining ones down */
X register unsigned char *p = CS[fd].SavedBytes;
X register unsigned char *q = CS[fd].SavedBytes + n;
X register long i = CS[fd].NumberofSavedBytes - n;
X while (i-- > 0)
X *p++ = *q++;
X CS[fd].NumberofSavedBytes -= n;
X }
X}
X
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X
X/* following are the possible values for ByteProcessing */
X/* forward declarations */
Xlong StartSetUpMessage ();
Xlong FinishSetUpMessage ();
Xlong StartRequest ();
Xlong FinishRequest ();
X
Xlong StartSetUpReply ();
Xlong FinishSetUpReply ();
Xlong ServerPacket ();
Xlong FinishReply ();
X
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
XProcessBuffer(fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X unsigned char *BytesToProcess;
X long NumberofUsedBytes;
X
X /* as long as we have enough bytes to do anything -- do it */
X
X while (CS[fd].NumberofSavedBytes + n >= CS[fd].NumberofBytesNeeded)
X {
X /*
X we have enough bytes to do something. We want the bytes to be
X grouped together into one contiguous block of bytes. We have three
X cases:
X
X (1) NumberofSavedBytes = 0; so all needed bytes are in the
X read buffer, buf.
X
X (2) NumberofSavedBytes >= NumberofBytesNeeded; in this case we
X will not need to copy any extra bytes into the save buffer.
X
X (3) 0 < NumberofSavedBytes < NumberofBytesNeeded; so
X some bytes are in the save buffer and others are in the read
X buffer. In this case we need to copy some of the bytes from the
X read buffer to the save buffer to get as many bytes as we need,
X then use these bytes.
X */
X
X if (CS[fd].NumberofSavedBytes == 0)
X {
X /* no saved bytes, so just process the first bytes in the
X read buffer */
X BytesToProcess = buf /* address of request bytes */;
X }
X else
X {
X if (CS[fd].NumberofSavedBytes < CS[fd].NumberofBytesNeeded)
X {
X /* first determine the number of bytes we need to
X transfer; then transfer them and remove them from
X the read buffer. (there may be additional requests
X in the read buffer) */
X long m;
X m = CS[fd].NumberofBytesNeeded - CS[fd].NumberofSavedBytes;
X SaveBytes(fd, buf, m);
X buf += m;
X n -= m;
X }
X BytesToProcess = CS[fd].SavedBytes /* address of request bytes */;
X }
X
X /*
X BytesToProcess points to a contiguous block of NumberofBytesNeeded
X bytes that we should process. The type of processing depends upon
X the state we are in. The processing routine should return the
X number of bytes that it actually used.
X */
X NumberofUsedBytes = (*CS[fd].ByteProcessing)
X (fd, BytesToProcess, CS[fd].NumberofBytesNeeded);
X
X /* the number of bytes that were actually used is normally (but not
X always) the number of bytes needed. Discard the bytes that were
X actually used, not the bytes that were needed. The number of used
X bytes must be less than or equal to the number of needed bytes. */
X
X if (NumberofUsedBytes > 0)
X {
X if (CS[fd].NumberofSavedBytes > 0)
X RemoveSavedBytes(fd, NumberofUsedBytes);
X else
X {
X /* there are no saved bytes, so the bytes that were
X used must have been in the read buffer */
X buf += NumberofUsedBytes;
X n -= NumberofUsedBytes;
X }
X }
X } /* end of while (NumberofSavedBytes + n >= NumberofBytesNeeded) */
X
X /* not enough bytes -- just save the new bytes for more later */
X if (n > 0)
X SaveBytes(fd, buf, n);
X return;
X}
X
X
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X/*
X Byte Processing Routines. Each routine MUST set NumberofBytesNeeded
X and ByteProcessing. It probably needs to do some computation first.
X*/
X
X
XStartClientConnection(fd)
X FD fd;
X{
X enterprocedure("StartClientConnection");
X /* when a new connection is started, we have no saved bytes */
X CS[fd].SavedBytes = NULL;
X CS[fd].SizeofSavedBytes = 0;
X CS[fd].NumberofSavedBytes = 0;
X
X /* when a new connection is started, we have no reply Queue */
X FlushReplyQ(fd);
X
X /* each new connection gets a request sequence number */
X CS[fd].SequenceNumber = 0;
X
X /* we need 12 bytes to start a SetUp message */
X CS[fd].ByteProcessing = StartSetUpMessage;
X CS[fd].NumberofBytesNeeded = 12;
X}
X
XStopClientConnection(fd)
X FD fd;
X{
X enterprocedure("StopClientConnection");
X /* when a new connection is stopped, discard the old buffer */
X
X if (CS[fd].SizeofSavedBytes > 0)
X Free((char*)CS[fd].SavedBytes);
X}
X
Xlong StartSetUpMessage (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X short namelength;
X short datalength;
X
X enterprocedure("StartSetUpMessage");
X /*
X we need the first 12 bytes to be able to determine if, and how many,
X additional bytes we need for name and data authorization. However, we
X can't process the first 12 bytes until we get all of them, so
X return zero bytes used, and increase the number of bytes needed
X */
X
X namelength = IShort(&buf[6]);
X datalength = IShort(&buf[8]);
X CS[fd].ByteProcessing = FinishSetUpMessage;
X CS[fd].NumberofBytesNeeded = n
X + pad((long)namelength) + pad((long)datalength);
X debug(8,(stderr, "need %d bytes to finish startup\n",
X CS[fd].NumberofBytesNeeded - n));
X return(0);
X}
X
Xlong FinishSetUpMessage (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X enterprocedure("FinishSetUpMessage");
X PrintSetUpMessage(buf);
X
X /* after a set-up message, we expect a string of requests */
X CS[fd].ByteProcessing = StartRequest;
X CS[fd].NumberofBytesNeeded = 4;
X return(n);
X}
X
X
Xlong StartRequest (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X short requestlength;
X enterprocedure("StartRequest");
X
X /* bytes 0,1 are ignored now; bytes 2,3 tell us the request length */
X requestlength = IShort(&buf[2]);
X CS[fd].ByteProcessing = FinishRequest;
X CS[fd].NumberofBytesNeeded = 4 * requestlength;
X debug(8,(stderr, "need %d more bytes to finish request\n",
X CS[fd].NumberofBytesNeeded - n));
X return(0);
X}
X
X
Xlong FinishRequest (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X enterprocedure("FinishRequest");
X DecodeRequest(fd, buf, n);
X CS[fd].ByteProcessing = StartRequest;
X CS[fd].NumberofBytesNeeded = 4;
X return(n);
X}
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
XStartServerConnection(fd)
X FD fd;
X{
X enterprocedure("StartServerConnection");
X /* when a new connection is started, we have no saved bytes */
X CS[fd].SavedBytes = NULL;
X CS[fd].SizeofSavedBytes = 0;
X CS[fd].NumberofSavedBytes = 0;
X
X /* when a new connection is started, we have no reply Queue */
X FlushReplyQ(fd);
X
X /* we need 8 bytes to start a SetUp reply */
X CS[fd].ByteProcessing = StartSetUpReply;
X CS[fd].NumberofBytesNeeded = 8;
X}
X
XStopServerConnection(fd)
X FD fd;
X{
X enterprocedure("StopServerConnection");
X /* when a new connection is stopped, discard the old buffer */
X
X if (CS[fd].SizeofSavedBytes > 0)
X Free((char *)CS[fd].SavedBytes);
X}
X
Xlong StartSetUpReply (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X short replylength;
X
X enterprocedure("StartSetUpReply");
X replylength = IShort(&buf[6]);
X CS[fd].ByteProcessing = FinishSetUpReply;
X CS[fd].NumberofBytesNeeded = n + 4 * replylength;
X debug(8,(stderr, "need %d bytes to finish startup reply\n",
X CS[fd].NumberofBytesNeeded - n));
X return(0);
X}
X
Xlong FinishSetUpReply (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X enterprocedure("FinishSetUpReply");
X PrintSetUpReply(buf);
X CS[fd].ByteProcessing = ServerPacket;
X CS[fd].NumberofBytesNeeded = 32;
X return(n);
X}
X
X/* ************************************************************ */
X
Xlong ErrorPacket (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X fprintf(stdout, "Error: ");
X DecodeError(fd, buf, n);
X CS[fd].ByteProcessing = ServerPacket;
X CS[fd].NumberofBytesNeeded = 32;
X return(n);
X}
X
X
Xlong EventPacket (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X DecodeEvent(fd, buf, n);
X CS[fd].ByteProcessing = ServerPacket;
X CS[fd].NumberofBytesNeeded = 32;
X return(n);
X}
X
X
Xlong ReplyPacket (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X short replylength;
X
X replylength = ILong(&buf[4]);
X
X /*
X Replies may need more bytes, so we compute how many more
X bytes are needed and ask for them, not using any of the bytes
X we were given (return(0) to say that no bytes were used).
X If the replylength is zero (we don't need any more bytes), the
X number of bytes needed will be the same as what we have, and
X so the top-level loop will call the next routine immediately
X with the same buffer of bytes that we were given.
X */
X
X CS[fd].ByteProcessing = FinishReply;
X CS[fd].NumberofBytesNeeded = n + 4 * replylength;
X debug(8,(stderr, "need %d bytes to finish reply\n", (4 * replylength)));
X return(0);
X}
X
Xlong ServerPacket (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X short PacketType;
X enterprocedure("ServerPacket");
X
X PacketType = IByte(&buf[0]);
X if (PacketType == 0)
X return(ErrorPacket(fd, buf, n));
X if (PacketType == 1)
X return(ReplyPacket(fd, buf, n));
X return(EventPacket(fd, buf, n));
X}
X
Xlong FinishReply (fd, buf, n)
X FD fd;
X unsigned char *buf;
X long n;
X{
X enterprocedure("FinishReply");
X DecodeReply(fd, buf, n);
X CS[fd].ByteProcessing = ServerPacket;
X CS[fd].NumberofBytesNeeded = 32;
X return(n);
X}
END_OF_FILE
if test 14093 -ne `wc -c <'server.c'`; then
echo shar: \"'server.c'\" unpacked with wrong size!
fi
# end of 'server.c'
fi
if test -f 'x11.h' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'x11.h'\"
else
echo shar: Extracting \"'x11.h'\" \(13008 characters\)
sed "s/^X//" >'x11.h' <<'END_OF_FILE'
X/* ************************************************************ *
X * *
X * Type definitions and Connection State for the X11 protocol *
X * *
X * James Peterson, 1988 *
X * (c) Copyright MCC, 1988 *
X * *
X * ************************************************************ */
X
X
X/* Some field contents are constants, not just types */
X
X#define CONST1(n) CARD8
X#define CONST2(n) CARD16
X#define CONST4(n) CARD32
X
X/* Some field contents define the components of an expression */
X
X#define DVALUE1(expression) CARD8
X#define DVALUE2(expression) CARD16
X#define DVALUE4(expression) CARD32
X
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* Built-in Types */
X
X#define BYTE 1 /* 8-bit value */
X#define INT8 2 /* 8-bit signed integer */
X#define INT16 3 /* 16-bit signed integer */
X#define INT32 4 /* 32-bit signed integer */
X#define CARD8 5 /* 8-bit unsigned integer */
X#define CARD16 6 /* 16-bit unsigned integer */
X#define CARD32 7 /* 32-bit unsigned integer */
X#define STRING8 8 /* List of CARD8 */
X#define STRING16 9 /* List of CHAR2B */
X#define TEXTITEM8 10 /* STRING8 or Font shift */
X#define TEXTITEM16 11 /* STRING16 or Font shift */
X
X#define WINDOW 12 /* CARD32 plus 0 = None */
X#define WINDOWD 13 /* CARD32 plus 0 = PointerWindow, 1 =
X InputFocus */
X#define WINDOWNR 14 /* CARD32 plus 0 = None, 1 = PointerRoot */
X
X#define PIXMAP 15 /* CARD32 plus 0 = None */
X#define PIXMAPNPR 16 /* CARD32 plus 0 = None, 1 = ParentRelative
X */
X#define PIXMAPC 17 /* CARD32 plus 0 = CopyFromParent */
X
X#define CURSOR 18 /* CARD32 plus 0 = None */
X
X#define FONT 19 /* CARD32 plus 0 = None */
X
X#define GCONTEXT 20 /* CARD32 */
X
X#define COLORMAP 21 /* CARD32 plus 0 = None */
X#define COLORMAPC 22 /* CARD32 plus 0 = CopyFromParent */
X
X#define DRAWABLE 23 /* CARD32 */
X#define FONTABLE 24 /* CARD32 */
X
X#define ATOM 25 /* CARD32 plus 0 = None */
X#define ATOMT 26 /* CARD32 plus 0 = AnyPropertyType */
X
X#define VISUALID 27 /* CARD32 plus 0 = None */
X#define VISUALIDC 28 /* CARD32 plus 0 = CopyFromParent */
X
X#define TIMESTAMP 29 /* CARD32 plus 0 as the current time */
X
X#define RESOURCEID 30 /* CARD32 plus 0 = AllTemporary */
X
X#define KEYSYM 31 /* CARD32 */
X#define KEYCODE 32 /* CARD8 */
X#define KEYCODEA 33 /* CARD8 plus 0 = AnyKey */
X
X#define BUTTON 34 /* CARD8 */
X#define BUTTONA 35 /* CARD8 plus 0 = AnyButton */
X
X#define EVENTFORM 34 /* event format */
X#define CHAR8 35 /* CARD8 interpreted as a character */
X#define STR 36 /* String of CHAR8 with preceding length */
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* Defined types */
X
X#define BITGRAVITY 40
X#define WINGRAVITY 41
X#define BOOL 42
X#define HOSTFAMILY 43
X#define PK_MODE 44
X#define NO_YES 45
X#define WINDOWCLASS 46
X#define BACKSTORE 47
X#define MAPSTATE 48
X#define STACKMODE 49
X#define CIRMODE 50
X#define CHANGEMODE 51
X#define GRABSTAT 52
X#define EVENTMODE 53
X#define FOCUSAGENT 54
X#define DIRECT 55
X#define GCFUNC 56
X#define LINESTYLE 57
X#define CAPSTYLE 58
X#define JOINSTYLE 59
X#define FILLSTYLE 60
X#define FILLRULE 61
X#define SUBWINMODE 62
X#define ARCMODE 63
X#define RECTORDER 64
X#define COORMODE 65
X#define POLYSHAPE 66
X#define IMAGEMODE 67
X#define ALLORNONE 68
X#define OBJECTCLASS 69
X#define OFF_ON 70
X#define INS_DEL 71
X#define DIS_EN 72
X#define CLOSEMODE 73
X#define SAVEMODE 74
X#define RSTATUS 75
X#define MOTIONDETAIL 76
X#define ENTERDETAIL 77
X#define BUTTONMODE 78
X#define SCREENFOCUS 79
X#define VISIBLE 80
X#define CIRSTAT 81
X#define PROPCHANGE 82
X#define CMAPCHANGE 83
X#define MAPOBJECT 84
X#define SETofEVENT 85
X#define SETofPOINTEREVENT 86
X#define SETofDEVICEEVENT 87
X#define SETofKEYBUTMASK 88
X#define SETofKEYMASK 89
X#define WINDOW_BITMASK 90
X#define CONFIGURE_BITMASK 91
X#define GC_BITMASK 92
X#define KEYBOARD_BITMASK 93
X#define COLORMASK 94
X#define CHAR2B 95
X#define POINT 96
X#define RECTANGLE 97
X#define ARC 98
X#define HOST 99
X#define TIMECOORD 100
X#define FONTPROP 101
X#define CHARINFO 102
X#define SEGMENT 103
X#define COLORITEM 104
X#define RGB 105
X#define BYTEMODE 110
X#define BYTEORDER 111
X#define COLORCLASS 112
X#define FORMAT 113
X#define SCREEN 114
X#define DEPTH 115
X#define VISUALTYPE 116
X
X#define REQUEST 117
X#define REPLY 118
X#define ERROR 119
X#define EVENT 120
X
X#define MaxTypes 128
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* declaration of the existance of print routines for the basic types */
X
XPrintINT8();
XPrintINT16();
XPrintINT32();
XPrintCARD8();
XPrintCARD16();
XPrintCARD32();
XPrintBYTE();
XPrintCHAR8();
XPrintSTRING16();
XPrintTEXTITEM8();
XPrintTEXTITEM16();
XPrintSTR();
XPrintWINDOW();
XPrintWINDOWD();
XPrintWINDOWNR();
XPrintPIXMAP();
XPrintPIXMAPNPR();
XPrintPIXMAPC();
XPrintCURSOR();
XPrintFONT();
XPrintGCONTEXT();
XPrintCOLORMAP();
XPrintCOLORMAPC();
XPrintDRAWABLE();
XPrintFONTABLE();
XPrintATOM();
XPrintATOMT();
XPrintVISUALID();
XPrintVISUALIDC();
XPrintTIMESTAMP();
XPrintRESOURCEID();
XPrintKEYSYM();
XPrintKEYCODE();
XPrintKEYCODEA();
XPrintBUTTON();
XPrintBUTTONA();
XPrintEVENTFORM();
XPrintENUMERATED();
XPrintSET();
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* Type Definition Table
X
X Each item in the X11 Protocol has a type. There are about 120
X different types. We need to be able to print each item in a
X format and interpretation which is appropriate for the type of
X that item. To do so, we build a table describing each type.
X Each type has a name, possibly a list of named values and a
X procedure which knows how to print that type.
X*/
X
X/* Types of Types */
X
X#define BUILTIN 1
X#define ENUMERATED 2
X#define SET 3
X#define RECORD 5
X
X
X/* Enumerated and Set types need a list of Named Values */
X
Xstruct ValueListEntry
X{
X struct ValueListEntry *Next;
X char *Name;
X short Type;
X short Length;
X long Value;
X};
X
Xstruct TypeDef
X{
X char *Name;
X short Type /* BUILTIN, ENUMERATED, SET, or RECORD */ ;
X struct ValueListEntry *ValueList;
X int (*PrintProc)();
X};
X
Xtypedef struct TypeDef *TYPE;
X
Xstruct TypeDef TD[MaxTypes];
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* Reply Buffer: Pseudo-buffer used to provide the opcode for the
X request to which this is a reply: Set by DecodeReply
X and used in the PrintField of the Reply procedure */
Xunsigned char RBf[2];
X
X
X/* Sequence Buffer: Pseudo-buffer used to provide the sequence number for a
X request: Set by DecodeReply and used in a PrintField of
X the Request procedure */
Xunsigned char SBf[4];
X
X
X#define PRINTSERVER 5 /* indent output as if it comes from server */
X#define PRINTCLIENT 1 /* indent output as if it comes from client */
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/*
X In general, we are called with a buffer of bytes and are supposed to
X try to make sense of these bytes according to the X11 protocol. There
X are two different types of communication: requests from the client to
X the server and replies/errors/events from the server to the client.
X We must interpret these two differently.
X
X Also, we must consider that the bytes on the communication socket may
X be sent asynchronously in any amount. This means that we must be prepared
X to read in and save some bytes until we get enough to do something with
X them. For example, suppose that we get a buffer from a client. We would
X expect it to be a request. The request may be 24 bytes long. We may find,
X however, that only 16 bytes have actually arrived -- the other 8 are stuck
X in a buffer somewhere. We must be prepared to simply hold the 16 bytes we
X have until more bytes arrive.
X
X In general, we do two things: we wait for some number of bytes, and
X then we interpret this set of bytes. To interpret this data we use
X a modified state machine. We keep two pieces of information:
X
X (1) the number of bytes that we need
X (2) what to do with those bytes.
X
X This last piece of information is the "state" of the interpretation.
X We keep the state as a pointer to the procedure that is to be executed.
X
X
X CLIENTS:
X
X The data going from the client to the x11 server consists of a
X set-up message followed by an infinite stream of variable length
X requests.
X
X Our overall flow is then:
X
X (a) Wait for 12 bytes.
X (b) Interpret these first 12 bytes of the set-up message to get the
X length of the rest of the message.
X (c) Wait for the rest of the set-up message.
X (d) Interpret and print the set-up message.
X
X *** end of set-up phase -- start normal request loop ***
X
X (e) Wait for 4 bytes.
X (f) Interpret these 4 bytes to get the length of the rest of the command.
X (g) Wait for the rest of the command.
X (h) Interpret and print the command.
X (i) Go back to step (e).
X
X SERVERS:
X
X Again, we have a set-up reply followed by an infinite stream of variable
X length replies/errors/events.
X
X Our overall flow is then:
X
X (a) Wait for 8 bytes.
X (b) Interpret the 8 bytes to get the length of the rest of the set-up reply.
X (c) Wait for the rest of the set-up reply.
X (d) Interpret and print the set-up reply.
X
X *** end of set-up phase -- start normal reply/error/event loop ***
X
X We have the following properties of X11 replies, errors, and events:
X
X Replies: 32 bytes plus a variable amount. Byte 0 is 1.
X Bytes 2-3 are a sequence number; bytes 4-7 are length (n). The
X complete length of the reply is 32 + 4 * n.
X
X Errors: 32 bytes. Byte 0 is 0.
X Byte 1 is an error code; bytes 2-3 are a sequence number.
X Bytes 8-9 are a major opcode; byte 10 is a minor opcode.
X
X Events: 32 bytes. Byte 0 is 2, 3, 4, ....
X
X Looking at this we have two choices: wait for one byte and then separately
X wait for replies, errors, and events, or wait for 32 bytes, then separately
X process each type. We may have to wait for more, in the event of a reply.
X This latter seems more effective. It appears reply/error/event formats
X were selected to allow waiting for 32 bytes, and it will allow short packets
X which are only 32 bytes long, to be processed completely in one step.
X
X Thus, For normal reply/error/event processing we have
X
X (e) Wait for 32 bytes.
X (f) Interpret these 32 bytes. If possible, go back to step (e).
X (g) If the packet is a reply with bytes 4-7 non-zero, wait for the
X remainder of the the reply.
X (h) Interpret and print the longer reply. Go back to step (e).
X
X
X The similarity in approach to how both the client and server are handled
X suggests we can use the same control structure to drive the interpretation
X of both types of communication client->server and server->client.
X Accordingly, we package up the relevant variables in a ConnState
X record. The ConnState record contains the buffer of saved bytes (if any),
X the size and length of this buffer, the number of bytes we are waiting for
X and what to do when we get them. A separate ConnState record is kept
X for the client and server.
X
X In addition, we may have several different client or server connections.
X Thus we need an array of all the necessary state for each client or server.
X A client/server is identified with a file descriptor (fd), so we use the
X fd to identify the client/server and use it as an index into an array of
X state variables.
X*/
X
Xstruct ConnState
X{
X unsigned char *SavedBytes;
X long SizeofSavedBytes;
X long NumberofSavedBytes;
X
X long NumberofBytesNeeded;
X long (*ByteProcessing)();
X
X long SequenceNumber;
X};
X
Xstruct ConnState CS[StaticMaxFD];
X
X
X
X
X/* ************************************************************ */
X/* */
X/* */
X/* ************************************************************ */
X
X/* declaraction of the types of some common functions */
X
Xextern unsigned long ILong();
Xextern unsigned short IShort();
Xextern unsigned short IByte();
Xextern Boolean IBool();
X
Xextern long PrintList();
Xextern long PrintListSTR();
Xextern long pad();
END_OF_FILE
if test 13008 -ne `wc -c <'x11.h'`; then
echo shar: \"'x11.h'\" unpacked with wrong size!
fi
# end of 'x11.h'
fi
echo shar: End of archive 4 \(of 4\).
cp /dev/null ark4isdone
MISSING=""
for I in 1 2 3 4 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 4 archives.
rm -f ark[1-9]isdone
else
echo You still need to unpack the following archives:
echo " " ${MISSING}
fi
## End of shell archive.
exit 0
--
Mike Wexler(wyse!mikew) Phone: (408)433-1000 x1330
Moderator of comp.sources.x
More information about the Comp.sources.x
mailing list