[comp.sources.x] v02i025: monitor X11 Server/Client communications, Part04/04

mikew@wyse.wyse.com (Mike Wexler) (11/29/88)

Submitted-by: peterson@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@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