"SfR Fresh" - the SfR Freeware/Shareware Archive

Member "xlab-0.8.3/scope.c" of archive xlab-0.8.3.tar.gz:


As a special service "SfR Fresh" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. That can be also achieved for any archive member file by clicking within an archive contents listing on the first character of the file(path) respectively on the according byte size field.
    1 /*
    2  * $Id: scope.c,v 1.4 1998/07/24 11:59:17 marc Exp $
    3  *
    4  *  A script program to store and replay X input events
    5  *
    6  *  Adapted from "xscope"
    7  *      James Peterson, 1988
    8  *      (c) Copyright MCC, 1988
    9  *      (c) Copyright Oliver Jones, 1993
   10  *      (c) Copyright Marc Vertes 1996, 1997, 1998
   11  *
   12  */
   13 #include <stdio.h>
   14 #include <stdlib.h>
   15 #include <sys/uio.h>		/* for struct iovec, used by socket.h */
   16 #include <sys/socket.h>		/* for AF_INET, SOCK_STREAM, ... */
   17 #include <sys/ioctl.h>		/* for FIONCLEX, FIONBIO, ... */
   18 #ifdef SVR4
   19 #include <sys/filio.h>
   20 #endif
   21 #include <fcntl.h>
   22 #include <netinet/in.h>		/* struct sockaddr_in */
   23 #include <netdb.h>		/* struct servent * and struct hostent * */
   24 #include <errno.h>		/* for EINTR, EADDRINUSE, ... */
   25 extern int errno;
   26 
   27 typedef struct TypeDef *TYPE;
   28 
   29 #include "scope.h"
   30 #include "table11.h"
   31 #include "common.h"
   32 #include "server.h"
   33 #include "record.h"
   34 #include "y.tab.h"
   35 
   36 /*
   37  * we need a local X display connection to the server-under-test
   38  * to allow various queries to go through.
   39  * Hence, include the X definitions.
   40  */
   41 #include <X11/Xlib.h>
   42 #include <X11/Xutil.h>
   43 
   44 short debuglevel;
   45 short Verbose;			/* quiet (0) or increasingly verbose  ( > 0) */
   46 int ScopePort;
   47 char *ScopeHost;
   48 
   49 /* path name of file to record, if any */
   50 char RecordFileName[MAXPATHLEN];
   51 
   52 /* FILE id of file name to record, if any */
   53 FILE *RecordFile = 0;
   54 
   55 /* path name of file to play back, if any */
   56 char PlaybackFileName[MAXPATHLEN];
   57 
   58 /* FILE id of file name to play back, if any */
   59 FILE *PlaybackFile = 0;
   60 
   61 /* user requested playback */
   62 #define PLAYBACK_INACTIVE 0
   63 #define PLAYBACK_PENDING 1
   64 #define PLAYBACK_ACTIVE 2
   65 #define PLAYBACK_COMPLETE 3
   66 long Playback = PLAYBACK_INACTIVE;
   67 
   68 /* non-zero if user requested recording  */
   69 /* Record and Playback cannot both be nonzero */
   70 long Record = 0;
   71 
   72 /* number of seconds to wait after starting program to start playback */
   73 long Wait = 15;
   74 
   75 /* time dilation in percentage ... 200 means speed up x2 */
   76 long TimeDilation = 100;
   77 
   78 /* double click time in milliseconds */
   79 long DoubleClickTime = 250;
   80 
   81 /* grab timeout in seconds */
   82 unsigned long int GrabTimeout = 30;
   83 
   84 /* display connection */
   85 Display *Dpy = 0;
   86 
   87 /* playback error count */
   88 unsigned long int Errorcount = 0;
   89 
   90 #define DefaultPort 6000
   91 
   92 char ServerHostName[255];
   93 long ServerBasePort = DefaultPort;
   94 long ServerInPort = 1;
   95 long ServerOutPort = 0;
   96 long ServerDisplay = 0;
   97 char ScopeEnabled = 0;
   98 char HandleSIGUSR1 = 0;
   99 
  100 /*----------------------------------------------------------------------*/
  101 short GetServerport()
  102 {
  103     short port;
  104 
  105     enterprocedure("GetServerport");
  106 
  107     port = ServerBasePort + ServerOutPort + ServerDisplay;
  108     debug(4, (stderr, "Server service is on port %d\n", port));
  109     return (port);
  110 }
  111 
  112 /*----------------------------------------------------------------------*/
  113 short GetScopePort()
  114 {
  115     short port;
  116 
  117     enterprocedure("GetScopePort");
  118 
  119     port = ServerBasePort + ServerInPort + ServerDisplay;
  120     debug(4, (stderr, "scope service is on port %d\n", port));
  121     return (port);
  122 }
  123 
  124 /*----------------------------------------------------------------------*/
  125 void Usage(xscript)
  126     char *xscript;
  127 {
  128     fprintf(stderr, "Usage: %s [-r<script-file-to-record>]\n", xscript);
  129     fprintf(stderr, "               [-p<script-file-to-play-back>]\n");
  130     fprintf(stderr, "               [-w<seconds-to-wait-before-playback>]\n");
  131     fprintf(stderr, "               [-c<double-click-time>]\n");
  132     fprintf(stderr, "               [-t<time-contraction-percentage>]\n");
  133     fprintf(stderr, "               [-h<server-host>]\n");
  134     fprintf(stderr, "               [-i<in-port>]\n");
  135     fprintf(stderr, "               [-o<out-port>]\n");
  136     fprintf(stderr, "               [-d<display-number>]\n");
  137     fprintf(stderr, "               [-v<n>]  -- verbose output\n");
  138     fprintf(stderr, "               [-q]  -- quiet output\n");
  139     fprintf(stderr, "               [-D<debug-level>]\n");
  140     fprintf(stderr, "               [-S<n>] -- start/stop on SIGUSR1\n");
  141     fprintf(stderr, "               [-G<timeout>] -- grab timeout in seconds\n");
  142 
  143     fprintf(stderr, "To record a session, do this:\n");
  144     fprintf(stderr, "    (1)  setenv DISPLAY `hostname`:0\n");
  145     fprintf(stderr, "    (2)  %s -rscript-file&\n", xscript);
  146     fprintf(stderr, "    (3)  setenv DISPLAY `hostname`:1\n");
  147     fprintf(stderr, "    (4)  run the program under test, and operate it.\n");
  148     fprintf(stderr, "To play back a session at 50%% speed, do this:\n");
  149     fprintf(stderr, "    (1)  setenv DISPLAY `hostname`:0\n");
  150     fprintf(stderr, "    (2)  %s -t50 -pscript-file&\n", xscript);
  151     fprintf(stderr, "    (3)  setenv DISPLAY `hostname`:1\n");
  152     fprintf(stderr, "    (4)  run the program under test, sit back, and watch.\n");
  153     exit(1);
  154 }
  155 
  156 
  157 /*----------------------------------------------------------------------*/
  158 static char *xscript = NULL;
  159 
  160 void ScanArgs(argc, argv)
  161     int argc;
  162     char **argv;
  163 {
  164     xscript = argv[0];
  165 
  166     Verbose = 0 /* default verbose-ness level */ ;
  167 
  168     /* Scan argument list */
  169     while (--argc > 0) {
  170 	++argv;
  171 	if (**argv == '-')
  172 	    switch (*++*argv) {
  173 		/*
  174 		 * debug levels:
  175 		 *  2 - trace each procedure entry
  176 		 *  4 - I/O, connections
  177 		 *  8 - Scope internals
  178 		 *  16 - Message protocol
  179 		 *  32 - 64 - malloc
  180 		 *  128 - 256 - really low level
  181 		 */
  182 	    case 'D':
  183 		debuglevel = atoi(++*argv);
  184 		if (debuglevel == 0)
  185 		    debuglevel = 255;
  186 		debuglevel |= 1;
  187 		Verbose = 7;
  188 		debug(1, (stderr, "debuglevel = %d\n", debuglevel));
  189 		break;
  190 
  191 	    case 'S':
  192 		HandleSIGUSR1 = 1;
  193 		ScopeEnabled = atoi(++*argv);
  194 		break;
  195 
  196 	    case 'G':
  197 		GrabTimeout = atoi(++*argv);
  198 		if (GrabTimeout == 0)
  199 		    GrabTimeout = 30;
  200 		break;
  201 
  202 	    case 'q':		/* quiet mode */
  203 		Verbose = 0;
  204 		debug(1, (stderr, "Verbose = %d\n", Verbose));
  205 		break;
  206 
  207 	    case 'v':		/* verbose mode */
  208 		Verbose = atoi(++*argv);
  209 		debug(1, (stderr, "Verbose = %d\n", Verbose));
  210 		break;
  211 
  212 	    case 'o':
  213 		ServerOutPort = atoi(++*argv);
  214 		if (ServerOutPort <= 0)
  215 		    ServerOutPort = 0;
  216 		debug(1, (stderr, "ServerOutPort = %ld\n", ServerOutPort));
  217 		break;
  218 
  219 	    case 'd':
  220 		ServerDisplay = atoi(++*argv);
  221 		if (ServerDisplay <= 0)
  222 		    ServerDisplay = 0;
  223 		debug(1, (stderr, "ServerDisplay=%ld\n", ServerDisplay));
  224 		break;
  225 
  226 	    case 'i':
  227 		ServerInPort = atoi(++*argv);
  228 		if (ServerInPort <= 0)
  229 		    ServerInPort = 0;
  230 		debug(1, (stderr, "ServerInPort = %ld\n", ServerInPort));
  231 		break;
  232 
  233 	    case 'h':
  234 		if (++*argv != NULL && **argv != '\0') {
  235 		    (void) strcpy(ServerHostName, OfficialName(*argv));
  236 		    debug(1, (stderr, "ServerHostName=%s\n", ServerHostName));
  237 		} else {
  238 		    /* -h by itself means print usage message */
  239 		    Usage(xscript);
  240 		}
  241 		break;
  242 
  243 	    case 'r':
  244 		if (Playback != PLAYBACK_INACTIVE) {
  245 		    fprintf(stderr, "Cannot record and play back in same session.\n");
  246 		    Usage(xscript);
  247 		}
  248 		if (++*argv != NULL && **argv != '\0')
  249 		    (void) strcpy(RecordFileName, *argv);
  250 		debug(1, (stderr, "RecordFileName=%s\n", RecordFileName));
  251 
  252 		/* ensure we can open record file correctly */
  253 		RecordFile = fopen(RecordFileName, "w");
  254 		if (RecordFile == 0) {
  255 		    perror(RecordFileName);
  256 		    exit(1);
  257 		}
  258 		fclose(RecordFile);
  259 		RecordFile = 0;
  260 		Record = 1;
  261 		break;
  262 
  263 	    case 'p':
  264 		if (Record) {
  265 		    fprintf(stderr, "Cannot record and play back in same session.\n");
  266 		    Usage(xscript);
  267 		}
  268 		if (++*argv != NULL && **argv != '\0')
  269 		    (void) strcpy(PlaybackFileName, *argv);
  270 		debug(1, (stderr, "PlaybackFile<Name=%s\n", PlaybackFileName));
  271 
  272 		/* ensure we can open playback file correctly */
  273 		PlaybackFile = fopen(PlaybackFileName, "r");
  274 		if (PlaybackFile == 0) {
  275 		    perror(PlaybackFileName);
  276 		    exit(1);
  277 		}
  278 		fclose(PlaybackFile);
  279 		PlaybackFile = 0;
  280 		Playback = PLAYBACK_PENDING;
  281 		/* read playbackfile to to extract Windows info */
  282 		LoadWtab("PlaybackFileName");
  283 		break;
  284 
  285 	    case 'w':
  286 		Wait = atoi(++*argv);
  287 		if (Wait <= 0)
  288 		    Wait = 10;
  289 		debug(1, (stderr, "Wait = %ld\n", Wait));
  290 		break;
  291 
  292 	    case 't':
  293 		TimeDilation = atoi(++*argv);
  294 		if (TimeDilation <= 0)
  295 		    TimeDilation = 100;
  296 		debug(1, (stderr, "TimeDilation = %ld\n", TimeDilation));
  297 		break;
  298 
  299 	    case 'c':
  300 		DoubleClickTime = atoi(++*argv);
  301 		if (DoubleClickTime <= 0)
  302 		    DoubleClickTime = 250;
  303 		debug(1, (stderr, "DoubleClickTime = %ld\n", DoubleClickTime));
  304 		break;
  305 
  306 	    default:
  307 		fprintf(stderr, "Unknown option %c\n", **argv);
  308 		Usage(xscript);
  309 		break;
  310 
  311 	} else {
  312 	    /* file argument to scope -- error */
  313 	    Usage(xscript);
  314 	}
  315     }
  316 
  317     /* check for different port numbers or different machines */
  318     if (ServerInPort == ServerOutPort)
  319 	if (ServerHostName[0] == '\0') {
  320 	    fprintf(stderr, "Can't have xlab on same port as server (%ld)\n",
  321 		    ServerInPort);
  322 	    Usage(xscript);
  323 	}
  324 }
  325 
  326 
  327 /*----------------------------------------------------------------------*/
  328 int main(argc, argv)
  329     int argc;
  330     char **argv;
  331 {
  332     /* grab input args */
  333     ScanArgs(argc, argv);
  334 
  335     /* initialize cross table of FDinfo */
  336     initFDbynum();
  337 
  338     /* initialize the file-descriptor-handling system */
  339     InitializeFD();
  340 
  341     /* initialize the symbol tables, etc, for X */
  342     InitializeX11();
  343 
  344     /* set up input stuff */
  345     SetUpStdin();
  346     SetUpXDisplay();
  347     SetUpConnectionSocket(GetScopePort());
  348     SetSignalHandling();
  349 
  350     MainLoop();
  351     return (0);
  352 }
  353 
  354 
  355 /*----------------------------------------------------------------------*/
  356 char *mystring;
  357 
  358 void ReadStdin(fd)
  359     FD fd;
  360 {
  361     long n;
  362     char in_buf[2048];
  363     extern FILE *yyin;
  364     extern int yyparse();
  365     extern int yyrestart();
  366 
  367     enterprocedure("ReadStdin");
  368     n = read(fd, in_buf, 2048);
  369     in_buf[n] = 0;
  370     debug(4, (stderr, "read %ld bytes from stdin\n", n));
  371     if (n == 0) {
  372 	NotUsingFD(fileno(stdin));
  373 	CreateTimer(2000, (void (*)()) SetUpStdin, (void *) fd);
  374 	return;
  375     }
  376     mystring = in_buf;
  377     yyparse();
  378     yyrestart(yyin);
  379 }
  380 
  381 /*----------------------------------------------------------------------*/
  382 void SetUpStdin()
  383 {
  384     enterprocedure("SetUpStdin");
  385     UsingFD(fileno(stdin), (int (*)()) ReadStdin);
  386 }
  387 
  388 /*----------------------------------------------------------------------*/
  389 void ReportAndExit()
  390 {
  391 
  392     if (Errorcount > 0 && Playback != PLAYBACK_INACTIVE) {
  393 	fprintf(stderr, "xlab: Playback summary\n");
  394 	fprintf(stderr, "  %ld errors encountered during playback\n", Errorcount);
  395 	exit(2);
  396     }
  397     exit(0);
  398 }
  399 
  400 /*----------------------------------------------------------------------*/
  401 /*
  402    here is where we would add code to allow control from
  403    the keyboard.  We would want to read a command and
  404    interpret it.  Possibilties:
  405 
  406    (a) verbose level setting
  407    (b) reset time
  408    (c) save X requests to a file.
  409    (d) replay X requests from a file.
  410    (e) allow fake events, errors to be generated.
  411  */
  412 
  413 /*
  414    xscope is really meant to look at one client at a time.  However,
  415    it can easily handle multiple clients and servers.  To do so,
  416    we need to have a pair of FDs: one for the client and one for the
  417    server for that client.  If either goes away, so does the other.
  418    We need to be able to identify the other FD of a pair, so that if
  419    we get input from one, we can write it to the other.
  420  */
  421 
  422 struct fdinfo {
  423     Boolean Server;
  424     long ClientNumber;
  425     FD pair;
  426 };
  427 
  428 static long ClientNumber = 0;
  429 static long ClientsConnected = 0;
  430 struct fdinfo FDinfo[StaticMaxFD];
  431 
  432 /* table to retrieve the client from the ClientNumber field of FDinfo */
  433 FD FDbynum[StaticMaxFD];
  434 
  435 /*----------------------------------------------------------------------*/
  436 void SetUpPair(client, server)
  437     FD client;
  438     FD server;
  439 {
  440     if (client >= 0) {
  441 	ClientNumber += 1;
  442 	ClientsConnected += 1;
  443 	FDinfo[client].Server = false;
  444 	FDinfo[client].pair = server;
  445 	FDinfo[client].ClientNumber = ClientNumber;
  446 	if (server >= 0) {
  447 	    FDinfo[server].Server = true;
  448 	    FDinfo[server].pair = client;
  449 	    FDinfo[server].ClientNumber = FDinfo[client].ClientNumber;
  450 	    FDbynum[ClientNumber] = server;
  451 	}
  452     } else if (server >= 0) {
  453 	(void) close(server);
  454 	NotUsingFD(server);
  455     }
  456 }
  457 
  458 /*----------------------------------------------------------------------*/
  459 void CloseConnection(fd)
  460     FD fd;
  461 {
  462     debug(4, (stderr, "close %d and %d\n", fd, FDPair(fd)));
  463     StopClientConnection(ServerHalf(fd));
  464     StopServerConnection(ClientHalf(fd));
  465 
  466     (void) close(fd);
  467     NotUsingFD(fd);
  468     (void) close(FDPair(fd));
  469     NotUsingFD(FDPair(fd));
  470     ClientsConnected -= 1;
  471 }
  472 
  473 /*----------------------------------------------------------------------*/
  474 FD FDPair(fd)
  475     FD fd;
  476 {
  477     return (FDinfo[fd].pair);
  478 }
  479 
  480 /*----------------------------------------------------------------------*/
  481 FD ClientHalf(fd)
  482     FD fd;
  483 {
  484     if (FDinfo[fd].Server)
  485 	return (FDinfo[fd].pair);
  486     return (fd);
  487 }
  488 
  489 /*----------------------------------------------------------------------*/
  490 FD ServerHalf(fd)
  491     FD fd;
  492 {
  493     if (FDinfo[fd].Server)
  494 	return (fd);
  495     return (FDinfo[fd].pair);
  496 }
  497 
  498 /*----------------------------------------------------------------------*/
  499 char *ClientName(fd)
  500     FD fd;
  501 {
  502     static char name[12];
  503 
  504     (void) sprintf(name, " %ld", FDinfo[fd].ClientNumber);
  505     return (name);
  506 }
  507 
  508 /*----------------------------------------------------------------------*/
  509 void initFDbynum()
  510 {
  511     long i;
  512     for (i = 0; i < StaticMaxFD; i++)
  513 	FDbynum[i] = -1;
  514 }
  515 
  516 /*----------------------------------------------------------------------*/
  517 extern struct WinTab wintab[MAXWTAB];
  518 extern struct WinAlias winalias[MAXWTAB];
  519 
  520 void initwintab()
  521 {
  522     int i;
  523 
  524     for (i = 0; i < MAXWTAB; i++) {
  525 	wintab[i].wid = 0;
  526 	wintab[i].parent = 0;
  527 	wintab[i].newid = 0;
  528 	wintab[i].newpar = 0;
  529 	wintab[i].x = -1;
  530 	wintab[i].y = -1;
  531 	wintab[i].width = -1;
  532 	wintab[i].height = -1;
  533 	wintab[i].delflag = 0;
  534 	winalias[i].wid = 0;
  535 	winalias[i].alias = 0;
  536     }
  537 }
  538 
  539 /*----------------------------------------------------------------------*/
  540 FD FDClientFromNumber(clientNb)
  541     long clientNb;
  542 {
  543     return FDbynum[clientNb];
  544     /*
  545        long i;
  546 
  547        for (i = 0; i < StaticMaxFD; i++) {
  548        if ((FDinfo[i].ClientNumber == clientNb) && (FDinfo[i].Server == false))
  549        return i;
  550        }
  551        return -1;
  552      */
  553 }
  554 
  555 /*----------------------------------------------------------------------*/
  556 long NumberFD(fd)
  557     FD fd;
  558 {
  559     return FDinfo[fd].ClientNumber;
  560 }
  561 
  562 
  563 /*----------------------------------------------------------------------*/
  564 /* It's possible for a write syscall to fail with
  565    EWOULDBLOCK.  In this case, we want to do a select
  566    until the file descriptor is writeable once again  */
  567 
  568 static void WaitUntilWriteable(fd)
  569     FD fd;
  570 {
  571     long int rfds, wfds, xfds;
  572     short int nfds;
  573     /* assert (fd < 32); */
  574     rfds = 0;
  575     wfds = 1 << fd;
  576     xfds = 0;
  577     debug(128, (stderr, "select %d, wfds = 0%lo\n", fd + 1, wfds));
  578     nfds = select(fd + 1, (fd_set *) & rfds, (fd_set *) & wfds, (fd_set *) & xfds,
  579 		  (struct timeval *) NULL);
  580     debug(128, (stderr, "select nfds = 0%o, wfds 0%lo\n", nfds, wfds));
  581 }
  582 
  583 
  584 /*----------------------------------------------------------------------*/
  585 /* when we get data from a client, we read it in, copy it to the
  586  * server for this client, then dump it to the client. Note, we don't
  587  * have to have a server, if there isn't one.
  588  */
  589 void DataFromClient(fd)
  590     FD fd;
  591 {
  592     unsigned char buf[2048];
  593     long n;
  594     FD ServerFD;
  595 
  596     /*MV enterprocedure("DataFromClient"); */
  597     n = read(fd, (char *) buf, 2048);
  598     debug(4, (stderr, "read %ld bytes from Client%s\n", n, ClientName(fd)));
  599     if (n < 0 && errno == ECONNRESET)
  600 	n = 0;
  601     if (n < 0) {
  602 	PrintTime();
  603 	perror("Client --> read error:");
  604 	CloseConnection(fd);
  605 	return;
  606     }
  607     if (n == 0) {
  608 	if (ScopeEnabled) {
  609 	    PrintTime();
  610 	    fprintf(stdout, "Client%s --> EOF\n", ClientName(fd));
  611 	}
  612 	if (RecordFile) {
  613 	    fflush(RecordFile);
  614 	    if (ClientsConnected == 0) {
  615 		fclose(RecordFile);
  616 		RecordFile = 0;
  617 	    }
  618 	}
  619 	CloseConnection(fd);
  620 
  621 /*
  622    if ((Record || (Playback != PLAYBACK_INACTIVE)) && (ClientsConnected == 0))
  623    ReportAndExit ();
  624  */
  625 	return;
  626     }
  627     ServerFD = FDPair(fd);
  628     if (ServerFD < 0) {
  629 	ServerFD = ConnectToServer(false);
  630 	SetUpPair(fd, ServerFD);
  631     }
  632     /* write bytes from client to server, allow for server to fail */
  633     if (ServerFD >= 0) {
  634 	long BytesToWrite = n;
  635 	unsigned char *p = buf;
  636 
  637 	while (BytesToWrite > 0) {
  638 	    int n1 = write(ServerFD, (char *) p, (int) BytesToWrite);
  639 	    debug(4, (stderr, "write %d bytes to Server%s\n", n1, ClientName(fd)));
  640 	    if (n1 < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
  641 		if (errno == EAGAIN)
  642 		    sleep(1);
  643 		WaitUntilWriteable(ServerFD);
  644 		n1 = 0;
  645 	    }
  646 	    if (n1 >= 0) {
  647 		BytesToWrite -= n1;
  648 		p += n1;
  649 	    } else {
  650 		perror("Error on write to Server");
  651 		CloseConnection(fd);
  652 		BytesToWrite = 0;
  653 	    }
  654 	}
  655     }
  656     /* also report the bytes to standard out */
  657     ReportFromClient(fd, buf, n);
  658 }
  659 
  660 /*----------------------------------------------------------------------*/
  661 /* push bytes from server out to client */
  662 void WriteToClient(fd, buf, n)
  663     FD fd;
  664     unsigned char *buf;
  665     int n;
  666 {
  667     FD ClientFD = FDPair(fd);
  668     long BytesToWrite = n;
  669     unsigned char *p = buf;
  670 
  671     while (BytesToWrite > 0) {
  672 	int n1 = write(ClientFD, (char *) p, (int) BytesToWrite);
  673 	debug(4, (stderr, "write %d bytes to Client%s\n", n1, ClientName(fd)));
  674 
  675 	if (n1 < 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) {
  676 	    if (errno == EAGAIN)
  677 		sleep(1);
  678 	    WaitUntilWriteable(ClientFD);
  679 	    n1 = 0;
  680 	}
  681 	if (n1 >= 0) {
  682 	    BytesToWrite -= n1;
  683 	    p += n1;
  684 	} else {
  685 	    perror("Error on write to Client");
  686 	    CloseConnection(fd);
  687 	    BytesToWrite = 0;
  688 	}
  689     }
  690 }
  691 
  692 /*----------------------------------------------------------------------*/
  693 /* similar situation for the server, but note that if there is no client,
  694  *  we close the connection down -- don't need a server with no client.
  695  */
  696 void DataFromServer(fd)
  697     FD fd;
  698 {
  699     unsigned char buf[2048];
  700     long n;
  701     FD ClientFD;
  702 
  703     /*MV enterprocedure("DataFromServer"); */
  704     n = read(fd, (char *) buf, 2048);
  705     debug(4, (stderr, "read %ld bytes from Server%s\n", n, ClientName(fd)));
  706     if (n < 0) {
  707 	PrintTime();
  708 	perror("read error <- Server");
  709 	CloseConnection(fd);
  710 	return;
  711     }
  712     if (n == 0) {
  713 	if (ScopeEnabled) {
  714 	    PrintTime();
  715 	    fprintf(stdout, "EOF <-- Server%s\n", ClientName(fd));
  716 	}
  717 	if (RecordFile) {
  718 	    fflush(RecordFile);
  719 	    if (ClientsConnected == 0) {
  720 		fclose(RecordFile);
  721 		RecordFile = 0;
  722 	    }
  723 	}
  724 	CloseConnection(fd);
  725 
  726 /*
  727    if ((Record || (Playback != PLAYBACK_INACTIVE)) && (ClientsConnected == 0))
  728    ReportAndExit ();
  729  */
  730 	return;
  731     }
  732     ClientFD = FDPair(fd);
  733     if (ClientFD < 0) {
  734 	CloseConnection(fd);
  735 	return;
  736     }
  737     if (Playback == PLAYBACK_INACTIVE) {
  738 	/*
  739 	 * if we're not playing stuff back from a file,
  740 	 * write bytes from server to client, allow for client to fail.
  741 	 * Note...if we ARE playing server stuff back, we need to
  742 	 *   crack the protocol first, because we don't pass throug
  743 	 *   all events from the server; only those which don't
  744 	 *   come from the playback file.
  745 	 */
  746 	WriteToClient(fd, buf, n);
  747     }
  748     /* also report the bytes to standard out */
  749     ReportFromServer(fd, buf, n);
  750 }
  751 
  752 
  753 
  754 /*----------------------------------------------------------------------*/
  755 /*     Create New Connection to a client program and to Server  */
  756 
  757 #ifndef linux
  758 static int ON = 1 /* used in ioctl */ ;
  759 #endif
  760 
  761 void NewConnection(fd)
  762     FD fd;
  763 {
  764     FD ServerFD = -1;
  765     FD ClientFD = -1;
  766 
  767     ClientFD = ConnectToClient(fd);
  768     ServerFD = ConnectToServer(true);
  769     SetUpPair(ClientFD, ServerFD);
  770 }
  771 
  772 /*----------------------------------------------------------------------*/
  773 FD ConnectToClient(ConnectionSocket)
  774     FD ConnectionSocket;
  775 {
  776     FD ClientFD;
  777     struct sockaddr_in from;
  778     int len = sizeof(from);
  779 
  780     enterprocedure("ConnectToClient");
  781 
  782     ClientFD = accept(ConnectionSocket, (struct sockaddr *) &from, &len);
  783     debug(4, (stderr, "Connect To Client: FD %d\n", ClientFD));
  784     if (ClientFD < 0 && errno == EWOULDBLOCK) {
  785 	debug(4, (stderr, "Almost blocked accepting FD %d\n", ClientFD));
  786 	panic("Can't connect to Client");
  787     }
  788     if (ClientFD < 0) {
  789 	debug(4, (stderr, "NewConnection: error %d\n", errno));
  790 	panic("Can't connect to Client");
  791     }
  792     UsingFD(ClientFD, (int (*)()) DataFromClient);
  793 #ifdef FD_CLOEXEC
  794     (void) fcntl(ClientFD, F_SETFD, FD_CLOEXEC);
  795 #else
  796     (void) ioctl(ClientFD, FIOCLEX, 0);
  797 #endif
  798     /* ultrix reads hang on Unix sockets, hpux reads fail */
  799 #if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux))
  800     (void) fcntl(ClientFD, F_SETFL, O_NONBLOCK);
  801 #else
  802 #ifdef FIOSNBIO
  803     ioctl(ClientFD, FIOSNBIO, &ON);
  804 #else
  805     (void) fcntl(ClientFD, F_SETFL, FNDELAY);
  806 #endif
  807 #endif
  808     StartClientConnection(ClientFD);
  809     return (ClientFD);
  810 }
  811 
  812 /*----------------------------------------------------------------------*/
  813 FD ConnectToServer(report)
  814     Boolean report;
  815 {
  816     FD ServerFD;
  817     struct sockaddr_in sin;
  818     struct hostent *hp;
  819     short port;
  820     int reuse_addr = 1;
  821 #ifndef	SO_DONTLINGER
  822     struct linger linger;
  823 #endif				/* SO_DONTLINGER */
  824 
  825     enterprocedure("ConnectToServer");
  826 
  827     /* establish a socket to the name server for this host */
  828     bzero((char *) &sin, sizeof(sin));
  829     ServerFD = socket(AF_INET, SOCK_STREAM, 0);
  830     if (ServerFD < 0) {
  831 	perror("socket() to Server failed");
  832 	debug(1, (stderr, "socket failed\n"));
  833 	panic("Can't open connection to Server");
  834     }
  835     (void) setsockopt(ServerFD, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, 0);
  836 #ifndef linux
  837     (void) setsockopt(ServerFD, SOL_SOCKET, SO_USELOOPBACK, (char *) NULL, 0);
  838 #endif
  839 #ifdef	SO_DONTLINGER
  840     (void) setsockopt(ServerFD, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
  841 #else				/* SO_DONTLINGER */
  842     linger.l_onoff = 0;
  843     linger.l_linger = 0;
  844     (void) setsockopt(ServerFD, SOL_SOCKET, SO_LINGER, (char *) &linger, sizeof linger);
  845 #endif				/* SO_DONTLINGER */
  846 
  847     /* determine the host machine for this process */
  848     if (ServerHostName[0] == '\0')
  849 	(void) gethostname(ServerHostName, sizeof(ServerHostName));
  850     debug(4, (stderr, "try to connect on %s\n", ServerHostName));
  851 
  852     hp = gethostbyname(ServerHostName);
  853     if (hp == 0) {
  854 	perror("gethostbyname failed");
  855 	debug(1, (stderr, "gethostbyname failed for %s\n", ServerHostName));
  856 	panic("Can't open connection to Server");
  857     }
  858     sin.sin_family = AF_INET;
  859     bcopy((char *) hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
  860     port = GetServerport();
  861 
  862     if (port == ScopePort
  863 	&& strcmp(ServerHostName, ScopeHost) == 0) {
  864 	char error_message[100];
  865 	(void) sprintf(error_message, "Trying to attach to myself: %s,%d\n",
  866 		       ServerHostName, sin.sin_port);
  867 	panic(error_message);
  868     }
  869     sin.sin_port = htons(port);
  870 
  871     /* ******************************************************** */
  872     /* try to connect to Server */
  873 
  874     if (connect(ServerFD, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
  875 	debug(4, (stderr, "connect returns errno of %d\n", errno));
  876 	if (errno != 0)
  877 	    if (report)
  878 		perror("connect");
  879 	switch (errno) {
  880 	case ECONNREFUSED:
  881 	    /* experience says this is because there is no Server
  882 	       to connect to */
  883 	    (void) close(ServerFD);
  884 	    debug(1, (stderr, "No Server\n"));
  885 	    if (report)
  886 		warn("Can't open connection to Server");
  887 	    return (-1);
  888 
  889 	default:
  890 	    (void) close(ServerFD);
  891 	    panic("Can't open connection to Server");
  892 	}
  893     }
  894     debug(4, (stderr, "Connect To Server: FD %d\n", ServerFD));
  895     if (ServerFD >= 0) {
  896 	UsingFD(ServerFD, (int (*)()) DataFromServer);
  897 	StartServerConnection(ServerFD);
  898     }
  899     return (ServerFD);
  900 }