summaryrefslogtreecommitdiff
path: root/server.c
diff options
context:
space:
mode:
authorAlan Coopersmith <alan.coopersmith@sun.com>2008-09-11 16:45:45 -0700
committerAlan Coopersmith <alan.coopersmith@sun.com>2008-09-11 16:45:45 -0700
commit306057f2475b216fb73686bcb0003355cf88944a (patch)
tree976f2c58fe49db3584f3cff02513d58e95407b16 /server.c
downloadxscope-306057f2475b216fb73686bcb0003355cf88944a.tar.gz
Import initial version from James Peterson
Diffstat (limited to 'server.c')
-rw-r--r--server.c632
1 files changed, 632 insertions, 0 deletions
diff --git a/server.c b/server.c
new file mode 100644
index 0000000..ba8b7cb
--- /dev/null
+++ b/server.c
@@ -0,0 +1,632 @@
+/* ************************************************** *
+ * *
+ * Code to decode and print X11 protocol *
+ * *
+ * James Peterson, 1988 *
+ * Copyright (C) 1988 MCC
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of MCC not be used in
+ * advertising or publicity pertaining to distribution of the software without
+ * specific, written prior permission. MCC makes no
+ * representations about the suitability of this software for any purpose. It
+ * is provided "as is" without express or implied warranty.
+ *
+ * MCC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL MCC BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ * *
+ * ************************************************** */
+
+#include "scope.h"
+#include "x11.h"
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+ReportFromClient(fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ PrintTime();
+ fprintf(stdout, "%s --> %4d %s\n",
+ ClientName(fd), n, (n == 1 ? "byte" : "bytes"));
+ ProcessBuffer(fd, buf, n);
+}
+
+ReportFromServer(fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ PrintTime();
+ fprintf(stdout, "\t\t\t\t\t%4d %s <-- X11 %s\n",
+ n, (n == 1 ? "byte" : "bytes"), ClientName(fd));
+ ProcessBuffer(fd, buf, n);
+}
+
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+#include <sys/time.h> /* for struct timeval * */
+static long ZeroTime1 = -1;
+static long ZeroTime2 = -1;
+static struct timeval tp;
+
+/* print the time since we started in hundredths (1/100) of seconds */
+
+PrintTime()
+{
+ static long lastsec = 0;
+ long sec /* seconds */ ;
+ long hsec /* hundredths of a second */ ;
+
+ (void)gettimeofday(&tp, (struct timezone *)NULL);
+ if (ZeroTime1 == -1 || (tp.tv_sec - lastsec) >= 1000)
+ {
+ ZeroTime1 = tp.tv_sec;
+ ZeroTime2 = tp.tv_usec / 10000;
+ }
+
+ lastsec = tp.tv_sec;
+ sec = tp.tv_sec - ZeroTime1;
+ hsec = tp.tv_usec / 10000 - ZeroTime2;
+ if (hsec < 0)
+ {
+ hsec += 100;
+ sec -= 1;
+ }
+ fprintf(stdout, "%2d.%02ld: ", sec, hsec);
+}
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+/* we will need to be able to interpret the values stored in the
+ requests as various built-in types. The following routines
+ support the types built into X11 */
+
+long pad (n)
+ long n;
+{
+ /* round up to next multiple of 4 */
+ return((n + 3) & ~0x3);
+}
+
+
+static Boolean byteswap = false;
+void SetByteSwapping(int how)
+{
+ byteswap = (how == 0x6c);
+}
+
+unsigned long ILong (buf)
+ unsigned char buf[];
+{
+ unsigned short a,b,c,d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ /* check for byte-swapping */
+
+ if (byteswap)
+ return((((((d << 8) | c) << 8) | b) << 8) | a);
+ else
+ return((((((a << 8) | b) << 8) | c) << 8) | d);
+}
+
+unsigned short IShort (buf)
+unsigned char buf[];
+{
+ unsigned short a,b,c,d;
+
+ a = buf[0];
+ b = buf[1];
+
+ /* check for byte-swapping */
+
+ if (byteswap)
+ return((b << 8) | a);
+ else
+ return((a << 8) | b);
+}
+
+unsigned short IChar2B (buf)
+unsigned char buf[];
+{
+ /* CHAR2B is like an IShort, but not byte-swapped */
+ return((buf[0] << 8) | buf[1]);
+}
+
+unsigned short IByte (buf)
+unsigned char buf[];
+{
+ return(buf[0]);
+}
+
+Boolean IBool(buf)
+ unsigned char buf[];
+{
+ if (buf[0] != 0)
+ return(true);
+ else
+ return(false);
+}
+
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+/* we will need to save bytes until we get a complete request to
+ interpret. The following procedures provide this ability */
+
+SaveBytes(fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ /* check if there is enough space to hold the bytes we want */
+ if (CS[fd].NumberofSavedBytes + n > CS[fd].SizeofSavedBytes)
+ {
+ /* not enough room so far; malloc more space and copy */
+ long SizeofNewBytes = (CS[fd].NumberofSavedBytes + n + 1);
+ unsigned char *NewBytes = (unsigned char *)Malloc (SizeofNewBytes);
+ if (CS[fd].NumberofSavedBytes > 0)
+ {
+ bcopy(/* from */(char *)CS[fd].SavedBytes,
+ /* to */(char *)NewBytes,
+ /* count */(int)CS[fd].NumberofSavedBytes);
+ Free((char *)CS[fd].SavedBytes);
+ }
+ CS[fd].SavedBytes = NewBytes;
+ CS[fd].SizeofSavedBytes = SizeofNewBytes;
+ }
+
+ /* now copy the new bytes onto the end of the old bytes */
+ bcopy(/* from */(char *)buf,
+ /* to */(char *)(CS[fd].SavedBytes + CS[fd].NumberofSavedBytes),
+ /* count */(int)n);
+ CS[fd].NumberofSavedBytes += n;
+}
+
+RemoveSavedBytes(fd, n)
+ FD fd;
+ long n;
+{
+ /* check if all bytes are being removed -- easiest case */
+ if (CS[fd].NumberofSavedBytes <= n)
+ CS[fd].NumberofSavedBytes = 0;
+ else if (n == 0)
+ return;
+ else
+ {
+ /* not all bytes are being removed -- shift the remaining ones down */
+ register unsigned char *p = CS[fd].SavedBytes;
+ register unsigned char *q = CS[fd].SavedBytes + n;
+ register long i = CS[fd].NumberofSavedBytes - n;
+ while (i-- > 0)
+ *p++ = *q++;
+ CS[fd].NumberofSavedBytes -= n;
+ }
+}
+
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+
+/* following are the possible values for ByteProcessing */
+/* forward declarations */
+long StartSetUpMessage ();
+long FinishSetUpMessage ();
+long StartRequest ();
+long FinishRequest ();
+
+long StartSetUpReply ();
+long FinishSetUpReply ();
+long ServerPacket ();
+long FinishReply ();
+
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+ProcessBuffer(fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ unsigned char *BytesToProcess;
+ long NumberofUsedBytes;
+
+ /* as long as we have enough bytes to do anything -- do it */
+
+ while (CS[fd].NumberofSavedBytes + n >= CS[fd].NumberofBytesNeeded)
+ {
+ /*
+ we have enough bytes to do something. We want the bytes to be
+ grouped together into one contiguous block of bytes. We have three
+ cases:
+
+ (1) NumberofSavedBytes = 0; so all needed bytes are in the
+ read buffer, buf.
+
+ (2) NumberofSavedBytes >= NumberofBytesNeeded; in this case we
+ will not need to copy any extra bytes into the save buffer.
+
+ (3) 0 < NumberofSavedBytes < NumberofBytesNeeded; so
+ some bytes are in the save buffer and others are in the read
+ buffer. In this case we need to copy some of the bytes from the
+ read buffer to the save buffer to get as many bytes as we need,
+ then use these bytes.
+ */
+
+ if (CS[fd].NumberofSavedBytes == 0)
+ {
+ /* no saved bytes, so just process the first bytes in the
+ read buffer */
+ BytesToProcess = buf /* address of request bytes */;
+ }
+ else
+ {
+ if (CS[fd].NumberofSavedBytes < CS[fd].NumberofBytesNeeded)
+ {
+ /* first determine the number of bytes we need to
+ transfer; then transfer them and remove them from
+ the read buffer. (there may be additional requests
+ in the read buffer) */
+ long m;
+ m = CS[fd].NumberofBytesNeeded - CS[fd].NumberofSavedBytes;
+ SaveBytes(fd, buf, m);
+ buf += m;
+ n -= m;
+ }
+ BytesToProcess = CS[fd].SavedBytes /* address of request bytes */;
+ }
+
+ /*
+ BytesToProcess points to a contiguous block of NumberofBytesNeeded
+ bytes that we should process. The type of processing depends upon
+ the state we are in. The processing routine should return the
+ number of bytes that it actually used.
+ */
+ NumberofUsedBytes = (*CS[fd].ByteProcessing)
+ (fd, BytesToProcess, CS[fd].NumberofBytesNeeded);
+
+ /* the number of bytes that were actually used is normally (but not
+ always) the number of bytes needed. Discard the bytes that were
+ actually used, not the bytes that were needed. The number of used
+ bytes must be less than or equal to the number of needed bytes. */
+
+ if (NumberofUsedBytes > 0)
+ {
+ if (CS[fd].NumberofSavedBytes > 0)
+ RemoveSavedBytes(fd, NumberofUsedBytes);
+ else
+ {
+ /* there are no saved bytes, so the bytes that were
+ used must have been in the read buffer */
+ buf += NumberofUsedBytes;
+ n -= NumberofUsedBytes;
+ }
+ }
+ } /* end of while (NumberofSavedBytes + n >= NumberofBytesNeeded) */
+
+ /* not enough bytes -- just save the new bytes for more later */
+ if (n > 0)
+ SaveBytes(fd, buf, n);
+ return;
+}
+
+
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+/*
+ Byte Processing Routines. Each routine MUST set NumberofBytesNeeded
+ and ByteProcessing. It probably needs to do some computation first.
+*/
+
+
+StartClientConnection(fd)
+ FD fd;
+{
+ enterprocedure("StartClientConnection");
+ /* when a new connection is started, we have no saved bytes */
+ CS[fd].SavedBytes = NULL;
+ CS[fd].SizeofSavedBytes = 0;
+ CS[fd].NumberofSavedBytes = 0;
+
+ /* when a new connection is started, we have no reply Queue */
+ FlushReplyQ(fd);
+
+ /* each new connection gets a request sequence number */
+ CS[fd].SequenceNumber = 0;
+
+ /* we need 12 bytes to start a SetUp message */
+ CS[fd].ByteProcessing = StartSetUpMessage;
+ CS[fd].NumberofBytesNeeded = 12;
+}
+
+StopClientConnection(fd)
+ FD fd;
+{
+ enterprocedure("StopClientConnection");
+ /* when a new connection is stopped, discard the old buffer */
+
+ if (CS[fd].SizeofSavedBytes > 0)
+ Free((char*)CS[fd].SavedBytes);
+}
+
+long StartSetUpMessage (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ short namelength;
+ short datalength;
+
+ enterprocedure("StartSetUpMessage");
+ /*
+ we need the first 12 bytes to be able to determine if, and how many,
+ additional bytes we need for name and data authorization. However, we
+ can't process the first 12 bytes until we get all of them, so
+ return zero bytes used, and increase the number of bytes needed
+ */
+
+ namelength = IShort(&buf[6]);
+ datalength = IShort(&buf[8]);
+ CS[fd].ByteProcessing = FinishSetUpMessage;
+ CS[fd].NumberofBytesNeeded = n
+ + pad((long)namelength) + pad((long)datalength);
+ debug(8,(stderr, "need %d bytes to finish startup\n",
+ CS[fd].NumberofBytesNeeded - n));
+ return(0);
+}
+
+long FinishSetUpMessage (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ enterprocedure("FinishSetUpMessage");
+ PrintSetUpMessage(buf);
+ if (RequestSync) SendToServer(fd,buf,n);
+
+ /* after a set-up message, we expect a string of requests */
+ CS[fd].ByteProcessing = StartRequest;
+ CS[fd].NumberofBytesNeeded = 4;
+ return(n);
+}
+
+
+long StartRequest (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ short requestlength;
+ enterprocedure("StartRequest");
+
+ /* bytes 0,1 are ignored now; bytes 2,3 tell us the request length */
+ requestlength = IShort(&buf[2]);
+ CS[fd].ByteProcessing = FinishRequest;
+ CS[fd].NumberofBytesNeeded = 4 * requestlength;
+ debug(8,(stderr, "need %d more bytes to finish request\n",
+ CS[fd].NumberofBytesNeeded - n));
+ return(0);
+}
+
+
+long FinishRequest (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ enterprocedure("FinishRequest");
+ DecodeRequest(fd, buf, n);
+ if (RequestSync) SendToServer(fd,buf,n);
+
+ CS[fd].ByteProcessing = StartRequest;
+ CS[fd].NumberofBytesNeeded = 4;
+ return(n);
+}
+
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+SendToServer (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ FD Server;
+
+ enterprocedure("SendToServer");
+ /*
+ We are in RequestSync mode. These means that each request is
+ separately sent to the server and we wait until it is done before
+ proceeding to the next request. This is useful when a client
+ request causes the server to crash. In this case, if we batch
+ up 100 requests and send them to the server all at once, we will
+ have no idea which was the last one processed, and hence which
+ was the one that caused the server to crash.
+
+ We first write the buffer to the server, then flush it. Then we
+ check if the server has input available, and if so process it
+ before returning to finish the rest of the client buffer.
+ */
+
+ Server = ServerHalf(fd);
+ WriteBytes(Server, buf, n);
+
+ if (InputAvailable(Server))
+ HandleInput(Server);
+}
+/* ************************************************************ */
+/* */
+/* */
+/* ************************************************************ */
+
+StartServerConnection(fd)
+ FD fd;
+{
+ enterprocedure("StartServerConnection");
+ /* when a new connection is started, we have no saved bytes */
+ CS[fd].SavedBytes = NULL;
+ CS[fd].SizeofSavedBytes = 0;
+ CS[fd].NumberofSavedBytes = 0;
+
+ /* when a new connection is started, we have no reply Queue */
+ FlushReplyQ(fd);
+
+ /* we need 8 bytes to start a SetUp reply */
+ CS[fd].ByteProcessing = StartSetUpReply;
+ CS[fd].NumberofBytesNeeded = 8;
+}
+
+StopServerConnection(fd)
+ FD fd;
+{
+ enterprocedure("StopServerConnection");
+ /* when a new connection is stopped, discard the old buffer */
+
+ if (CS[fd].SizeofSavedBytes > 0)
+ Free((char *)CS[fd].SavedBytes);
+}
+
+long StartSetUpReply (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ short replylength;
+
+ enterprocedure("StartSetUpReply");
+ replylength = IShort(&buf[6]);
+ CS[fd].ByteProcessing = FinishSetUpReply;
+ CS[fd].NumberofBytesNeeded = n + 4 * replylength;
+ debug(8,(stderr, "need %d bytes to finish startup reply\n",
+ CS[fd].NumberofBytesNeeded - n));
+ return(0);
+}
+
+long FinishSetUpReply (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ enterprocedure("FinishSetUpReply");
+ PrintSetUpReply(buf);
+ CS[fd].ByteProcessing = ServerPacket;
+ CS[fd].NumberofBytesNeeded = 32;
+ return(n);
+}
+
+/* ************************************************************ */
+
+long ErrorPacket (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ fprintf(stdout, "Error: ");
+ DecodeError(fd, buf, n);
+ CS[fd].ByteProcessing = ServerPacket;
+ CS[fd].NumberofBytesNeeded = 32;
+ return(n);
+}
+
+
+long EventPacket (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ DecodeEvent(fd, buf, n);
+ CS[fd].ByteProcessing = ServerPacket;
+ CS[fd].NumberofBytesNeeded = 32;
+ return(n);
+}
+
+
+long ReplyPacket (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ short replylength;
+
+ replylength = ILong(&buf[4]);
+
+ /*
+ Replies may need more bytes, so we compute how many more
+ bytes are needed and ask for them, not using any of the bytes
+ we were given (return(0) to say that no bytes were used).
+ If the replylength is zero (we don't need any more bytes), the
+ number of bytes needed will be the same as what we have, and
+ so the top-level loop will call the next routine immediately
+ with the same buffer of bytes that we were given.
+ */
+
+ CS[fd].ByteProcessing = FinishReply;
+ CS[fd].NumberofBytesNeeded = n + 4 * replylength;
+ debug(8,(stderr, "need %d bytes to finish reply\n", (4 * replylength)));
+ return(0);
+}
+
+long ServerPacket (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ short PacketType;
+ enterprocedure("ServerPacket");
+
+ PacketType = IByte(&buf[0]);
+ if (PacketType == 0)
+ return(ErrorPacket(fd, buf, n));
+ if (PacketType == 1)
+ return(ReplyPacket(fd, buf, n));
+ return(EventPacket(fd, buf, n));
+}
+
+long FinishReply (fd, buf, n)
+ FD fd;
+ unsigned char *buf;
+ long n;
+{
+ enterprocedure("FinishReply");
+ DecodeReply(fd, buf, n);
+ CS[fd].ByteProcessing = ServerPacket;
+ CS[fd].NumberofBytesNeeded = 32;
+ return(n);
+}