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