diff options
Diffstat (limited to 'xc/test/xsuite/xtest/src/libproto/Expect.c')
-rw-r--r-- | xc/test/xsuite/xtest/src/libproto/Expect.c | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/xc/test/xsuite/xtest/src/libproto/Expect.c b/xc/test/xsuite/xtest/src/libproto/Expect.c new file mode 100644 index 000000000..a9d447431 --- /dev/null +++ b/xc/test/xsuite/xtest/src/libproto/Expect.c @@ -0,0 +1,573 @@ +/* + * Copyright 1990, 1991 by the Massachusetts Institute of Technology and + * UniSoft Group Limited. + * + * 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 names of MIT and UniSoft not be + * used in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. MIT and UniSoft + * make no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * $XConsortium$ + */ +/* + * *************************************************************************** + * Copyright 1988 by Sequent Computer Systems, Inc., Portland, Oregon * + * * + * * + * All Rights Reserved * + * * + * Permission to use, copy, modify, and distribute this software and its * + * documentation for any purpose and without fee is hereby granted, * + * provided that the above copyright notice appears in all copies and that * + * both that copyright notice and this permission notice appear in * + * supporting documentation, and that the name of Sequent not be used * + * in advertising or publicity pertaining to distribution or use of the * + * software without specific, written prior permission. * + * * + * SEQUENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING * + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL * + * SEQUENT 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. * + * *************************************************************************** + */ + +/* + * $Header: Expect.c 1.18 89/04/17 $ + */ + +#ifndef lint +static char rcsid[] = "$Header: Expect.c 1.18 89/04/17 $"; +#endif + +#include "XstlibInt.h" + +#define Dont_Log_Twice(cl) do {\ + int *countp = (Get_Test_Type(cl)==SETUP)?(&Xst_delete_count):(&Xst_error_count);\ + if (*countp>0) (*countp)--; } while (0) + +extern int errno; +extern int sys_nerr; +extern char *sys_errlist[]; + +static int max_extra = IBUFSIZE - sizeof (xReply); +static char rbuf[IBUFSIZE]; +static char *rbp; +static char *enames (); +static char wanted[132]; +static char *got; + +static xGenericReply dummy_reply = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static char *expect_names[4] = { + "REPLY", + "ERROR", + "EVENT", + "NOTHING" +}; + +static char emsg[132]; + +static int this_client; + +static void +Timeout_Func () { + Log_Msg ("Expect: wanted %s, got TIMEOUT! (server may be dead)\n", wanted); + Finish (this_client); +} + +static void +Enable_Timeout (client) +int client; +{ + this_client = client; + Set_Timer (EXPECT_TIMER_ID, Xst_timeout_value, Timeout_Func); +} + +static void +Disable_Timeout () { + Stop_Timer (EXPECT_TIMER_ID); +} + +/* + * Routine: Expect_BadAccess() + * Call Expect_Error expecting BadAccess error. + */ +void +Expect_BadAccess(client) +int client; +{ + xError *err; + + if ((err = Expect_Error(client, BadAccess)) == NULL) { + Dont_Log_Twice(client); + Log_Msg("client %d failed to receive Access error\n", client); + Finish(client); + } else { + Log_Trace("client %d received Access error\n", client); + Free_Error(err); + } +} + + +/* + * Routine: Expect_BadValue() + * Call Expect_Error expecting BadValue error. + */ +void +Expect_BadValue(client) +int client; +{ + xError *err; + + if ((err = Expect_Error(client, BadValue)) == NULL) { + Dont_Log_Twice(client); + Log_Msg("client %d failed to recv BadValue error\n", client); + Finish(client); + } else { + Log_Trace("client %d received BadValue error\n", client); + Free_Error(err); + } +} + +/* + * Routine: Expect_BadLength() + * Call Expect_Error expecting BadLength error. + */ +void +Expect_BadLength(client) +int client; +{ + xError *err; + + if ((err = Expect_Error(client, BadLength)) == NULL) { + Dont_Log_Twice(client); + Log_Msg("client %d failed to recv BadLength error\n", client); + Finish(client); + } else { + Log_Trace("client %d received BadLength error\n", client); + Free_Error(err); + } +} + +/* + * Routine: Expect_BadIDChoice() + * Call Expect_Error expecting BadIDChoice error. + */ +void +Expect_BadIDChoice(client) +int client; +{ + xError *err; + + if ((err = Expect_Error(client, BadIDChoice)) == NULL) { + Dont_Log_Twice(client); + Log_Msg("client %d failed to recv BadIDChoice error\n", client); + Finish(client); + } else { + Log_Trace("client %d received BadIDChoice error\n", client); + Free_Error(err); + } +} + +/* + * Routine: Expect - extract a response of the specified type and class + * from the server + * + * Input: client - integer between 0 and MAX_CLIENTS + * class - one of {EXPECT_ERROR, EXPECT_EVENT, EXPECT_REPLY, + * EXPECT_NOTHING} + * type - protocol type preceded by X_, e.g. X_GrabPointer + * + * Output: response if found, else null + * + * Returns: + * + * Globals used: Xst_clients + * + * Side Effects: + * + * Methods: + * + */ +#define THRESHOLD 42 /* number of unexpected, malformed or out + * of sequence replies/events/errors we will + * put up with. + */ + +xReply +* Expect (client, class, type) +int client; /* client number */ +int class; /* expected class, e.g. event, error */ +int type; /* request type */ +{ + XstDisplay * dpy = Get_Display (client); + xReply * rep = (xReply *) Xstmalloc (sizeof (xReply)); + xReply * match = NULL; + int done = 0; + int strange = 0; + int done_reason = EXPECT_NOTHING; + unsigned long extra; + long so_far; + int needswap = Xst_clients[client].cl_swap; + void (*Log_Rtn)(); + + /* use if-else rather than ?: to init. Log_Rtn to avoid Sequent cc bug */ + if (Get_Test_Type(client)==SETUP) + Log_Rtn = Log_Del; + else + Log_Rtn = Log_Err; + + strcpy (wanted, enames (class, type)); +/* + * If a request has gone out since the last poll, need to update + * our notion of "outstanding request" + */ + if (Xst_clients[client].cl_pollout < dpy -> request) { + Xst_clients[client].cl_reqout = dpy -> request; + } +/* + * If we don't have a poll currently outstanding, send a poll + * to ensure that we hear from the server. + */ + if (Xst_clients[client].cl_pollout == 0) { + Poll_Server (client); + } + +/* + * Now cycle through the messages coming back until we get something + * which corresponds explicitly to the last request sent + * (ie. either a reply or an error), or a poll reply. + * + * Replies and errors for PAST or FUTURE requests are + * error-logged and discarded. (ie. sequence number error) + * + * Replies or errors which explicitly correspond to the current + * request (ie. sequence numbers match) cause a return to the caller, + * with success/failure a function of what was "expected." + * + * Events are checked for "expectedness". If an expected event is + * received, it is immediately returned to the caller. If an + * unexpected event is received, it is error-logged and discarded. + * + * Poll replies which respond to polls prior to sending the current + * request are discarded. Poll replies which respond to polls after + * the current request cause a return to caller, with appropriate + * success/failure. + * + * Timeouts on reads are always logged, and the test terminated. + * + * Truncated reads are always logged, and the test terminated. + * + * System errors on reads are always logged, and the test terminated. + * + * Poll replies which appear malformed, or which are errors, are always + * logged, and the test terminated. + * + * Any reply/error/event indicating a length greater than ???? is + * logged, and the test terminated. + * + */ + + while (!done && strange < THRESHOLD) { + + Get_Me_That (client, rbuf, so_far = (long) sizeof (xReply)); +/* + * unpack the constant header + */ + rbp = rbuf; + + rep->generic.type = unpack1(&rbp); + rep->generic.data1 = unpack1(&rbp); + rep->generic.sequenceNumber = unpack2(&rbp,needswap); + rep->generic.length = unpack4(&rbp,needswap); + +/* + * Check for a poll reply + */ + if ((Xst_clients[client].cl_pollout == rep -> generic.sequenceNumber) && + (rep->generic.type == X_Reply)) { +/* + * Looks like a poll reply - check it out in more detail + */ + Rcv_Poll (rep,rbuf, client); + if (Xst_clients[client].cl_pollout < Xst_clients[client].cl_reqout) { + Poll_Server (client); /* response to old poll, send another */ + } + else { + Xst_clients[client].cl_pollout = 0; + done = 1; /* reponse to current poll */ + done_reason = EXPECT_NOTHING; + } + + continue; /* in any case, no further interest in + this */ + } +/* + * check type of reply + */ + + switch (rep -> generic.type) { + case X_Reply: + extra = (rep -> generic.length << 2); + if (extra > 0) {/* more to read */ + if (extra > max_extra) { + Log_Msg ("Expect: too big a reply"); + Show_Rep (rep, UNKNOWN_REQUEST_TYPE, so_far); + Finish (client); + } + so_far = (long) extra + sizeof (xReply); + rep = (xReply *) Xstrealloc ((char *) rep, (unsigned) so_far); + Get_Me_That (client, (char *) rbuf + sizeof (xReply), extra); + } +/* + * Now the whole thing is in, lets look at it + */ + if (!Rcv_Rep(rep,rbuf,Xst_clients[client].cl_reqtype,client)) { + match = NULL; + continue; + } + if (rep -> generic.sequenceNumber < (CARD16) Xst_clients[client].cl_reqout) { + (*Log_Rtn) ("Expect: reply for PAST request\n"); + Show_Rep ((xReply *) rep, UNKNOWN_REQUEST_TYPE, so_far); + strange++; + continue; + } + if (rep -> generic.sequenceNumber > (CARD16)Xst_clients[client].cl_reqout) { + (*Log_Rtn) ("Expect: reply for FUTURE request\n"); + Show_Rep ((xReply *) rep, UNKNOWN_REQUEST_TYPE, so_far); + strange++; + continue; + } +/* + * this is a reply for the outstanding message + */ + Log_Debug("Received reply:"); + Show_Rep(rep,type, so_far); + done = 1; + done_reason = EXPECT_REPLY; + match = rep; + break; + case X_Error: + if(!Rcv_Err(rep,rbuf,client)) { + continue; + } + if (rep -> generic.sequenceNumber < (CARD16)Xst_clients[client].cl_reqout) { + (*Log_Rtn) ("Expect: error for PAST request\n"); + Show_Err ((xError *) rep); + strange++; + continue; + } + if (rep -> generic.sequenceNumber > (CARD16)Xst_clients[client].cl_reqout) { + (*Log_Rtn) ("Expect: error for FUTURE request\n"); + Show_Err ((xError *) rep); + strange++; + continue; + } +/* + * this is an error for the outstanding message + */ + Log_Debug("Received error:"); + Show_Err(rep); + done = 1; + done_reason = EXPECT_ERROR; + match = rep; + break; +/* + * if its not a reply or an error, its an event! + */ + default: + if(!Rcv_Evt(rep,rbuf,client)) { + strange++; + continue; + } + if (real_type(rep -> event.u.u.type) != KeymapNotify) { + if (rep -> generic.sequenceNumber < (CARD16)Xst_clients[client].cl_reqout) { + (*Log_Rtn) ("Expect: event for PAST request\n"); + Show_Evt ((xEvent *) rep); + strange++; + continue; + } + if (rep -> generic.sequenceNumber > (CARD16)Xst_clients[client].cl_reqout) { + (*Log_Rtn) ("Expect: event for FUTURE request\n"); + Show_Evt ((xEvent *) rep); + strange++; + continue; + } + } + Log_Debug("Received event:"); + Show_Evt(rep); + if ((class == EXPECT_EVENT) && + (real_type(rep -> event.u.u.type) == type)) { + done = 1; + done_reason = EXPECT_EVENT; + match = rep; + continue; + } + got = enames (EXPECT_EVENT, (int) real_type(rep -> event.u.u.type)); + (*Log_Rtn) ("Expect: wanted %s, got %s\n", wanted, got); + Show_Evt ((xEvent *) rep); + break; + } + } + if (strange >= THRESHOLD) { + /* we'll have got here with the strange count exceeded, probably + * due to sequence errors or replies to requests we don't think + * think we sent. + */ + (*Log_Rtn) ("Expect: wanted %s but got at least %d unexpected, malformed or out of sequence replies/errors/events.\n", + wanted, strange); + return (NULL); + } + switch (done_reason) { + case EXPECT_REPLY: + if (class == EXPECT_REPLY) { + return (match); /* wanted one, got one */ + } + got = enames (EXPECT_REPLY, Xst_clients[client].cl_reqtype); + (*Log_Rtn) ("Expect: wanted %s, got %s\n", wanted, got); + Show_Rep (rep, UNKNOWN_REQUEST_TYPE, so_far); + return (NULL); + case EXPECT_NOTHING: + if (class == EXPECT_NOTHING) { + return ((xReply *) & dummy_reply); + } + got = enames (EXPECT_NOTHING, 0); + (*Log_Rtn) ("Expect: wanted %s, got %s\n", wanted, got); + return (NULL); + case EXPECT_ERROR: + if (class != EXPECT_ERROR) { + got = enames (EXPECT_ERROR, (int) match -> error.errorCode); + (*Log_Rtn) ("Expect: wanted %s, got %s\n", wanted, got); + Show_Err ((xError *) rep); + return (NULL); + } + if (type != match -> error.errorCode) { + got = enames (EXPECT_ERROR, (int) match -> error.errorCode); + (*Log_Rtn) ("Expect: wanted %s, got %s\n", wanted, got); + Show_Err ((xError *) rep); + return (NULL); + } + return (match); + case EXPECT_EVENT: + /* the only way the "done_reason" would be EXPECT_EVENT is * if + we've already done the match */ + return (match); + default: + break; + } + return ((xReply *) NULL); +} + + +Get_Me_That (client, rbuf, size) +int client; +char * rbuf; +unsigned long size; +{ + XstDisplay * dpy = Get_Display (client); + int this_read; + + Enable_Timeout (client); + while ((this_read = Xst_Read (dpy, (char *) rbuf, size)) < 0) { + if (errno == EINTR) { + continue; + } + else { + if ((errno >= 0) && (errno < sys_nerr)) { + (void) strcpy (emsg, sys_errlist[errno]); + } + else { + sprintf (emsg, "UNKNOWN ERROR - %d", errno); + } + Log_Msg ("Expect: wanted %s, got SYSTEM ERROR - %s\n", wanted, emsg); + Finish (client); + } + } + if (this_read < size) { + Log_Msg ("Expect: wanted %s, got TRUNCATED\n", wanted); + Log_Msg ("Expect: wanted %d additional, got %d\n", + size, this_read); + Show_Rep ((xReply *) rbuf, Xst_clients[client].cl_reqtype, (long)this_read); + Finish (client); + } + Disable_Timeout (); + return; +} + +Poll_Server (client) +int client; +{ + XstDisplay * dpy = Get_Display (client); + xReq * req; + int type; + TestType tt = Get_Test_Type(client); + + switch (tt) { + case BAD_LENGTH: + case JUST_TOO_LONG: + case TOO_LONG: + Set_Test_Type(client, GOOD); + break; + } + req = Make_Req (client, X_GetInputFocus); + _Send_Req (client, req,1); /* tell 'em we're a poll */ + Xst_clients[client].cl_pollout = dpy -> request; + Free_Req (req); + Set_Test_Type(client, tt); +} + +static char + *enames (class, type) +int class; +int type; +{ + static char prtbuf[132]; + char *(*namefunc)(); + extern char *errorname(); + extern char *eventname(); + extern char *protoname(); + + switch (class) { + case EXPECT_REPLY: + namefunc = protoname; + break; + case EXPECT_ERROR: + namefunc = errorname; + break; + case EXPECT_EVENT: + namefunc = eventname; + break; + case EXPECT_NOTHING: + sprintf (prtbuf, "%s", expect_names[class]); + return prtbuf; + /*NOTREACHED*/ + break; + default: + Log_Msg("INTERNAL ERROR: enames(%d,%d) - first arg not one of {%d,%d,%d,%d}\n", + class, type, EXPECT_REPLY, EXPECT_ERROR, EXPECT_EVENT, + EXPECT_NOTHING); + Delete (); + /*NOTREACHED*/ + break; + } + sprintf (prtbuf, "%s - %s ", expect_names[class], (*namefunc)(type)); + return (prtbuf); +} + +int Rcv_Poll (rep, rbuf, client) + xReply * rep; + char rbuf[]; + int client; +{ + return(Rcv_Rep(rep,rbuf, X_GetInputFocus, client)); +} |