DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T s

⟦fead70b0a⟧ TextFile

    Length: 16981 (0x4255)
    Types: TextFile
    Names: »scope.c«

Derivation

└─⟦8648bda34⟧ Bits:30007244 EUUGD5_II: X11R5
    └─⟦b23e377d7⟧ »./contrib-2/contrib-2.00« 
        └─⟦0ed22c3ba⟧ 
            └─⟦this⟧ »contrib/lib/Xpex/clients/Xpex/pexscope/scope.c« 

TextFile

/* $Header: scope.c,v 2.2 91/09/11 15:52:34 sinyaw Exp $ */
#ifndef lint
static char     sccsid[] = "@(#)scope.c 1.5 90/04/05 MIT/SMI";
#endif

/***********************************************************
Copyright 1990 by Sun Microsystems, Inc. and the X Consortium.

                        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 appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the names of Sun Microsystems,
the X Consortium, and MIT not be used in advertising or publicity 
pertaining to distribution of the software without specific, written 
prior permission.  

SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT 
SHALL SUN MICROSYSTEMS 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.

******************************************************************/

/* ******************************************************
 *						      	*
 *  A spy program to reveal X11  traffic	    	*
 *						      	*
 *	James Peterson, 1988	       			*
 *	(c) Copyright MCC, 1988 			*
 *							*
 ***************************************************** */

#include "scope.h"

#include <sys/types.h>	       /* needed by sys/socket.h and netinet/in.h */
#include <sys/uio.h>	       /* for struct iovec, used by socket.h */
#include <sys/socket.h>	       /* for AF_INET, SOCK_STREAM, ... */
#if defined(SYSV) || defined(SYSTYPE_SYSV) || defined(SVR4)
#include <sys/filio.h>			/* for FIOCLEX, FIONBIO, ... */
#else /* SYSV */ 
#include <sys/ioctl.h>	       /* for FIONCLEX, FIONBIO, ... */
#endif /* SYSV */
#include <netinet/in.h>	       /* struct sockaddr_in */
#include <netdb.h>	       /* struct servent * and struct hostent * */
#include <errno.h>	       /* for EINTR, EADDRINUSE, ... */
extern int  errno;

extern InitializePEX();
/* ********************************************** */
/*                                                */
/* ********************************************** */

#define DefaultPort 6000

char    ServerHostName[255];
long    ServerBasePort = DefaultPort;
long    ServerInPort = 1;
long    ServerOutPort = 0;
long    ServerDisplay = 0;
char    ScopeEnabled = 1;
char    HandleSIGUSR1 = 0;

/* ********************************************** */
/*                                                */
/*                                                */
/* ********************************************** */

short     GetServerport ()
{
  short     port;

  enterprocedure("GetServerport");

  port = ServerBasePort + ServerOutPort + ServerDisplay;
  debug(4,(stderr, "Server service is on port %d\n", port));
  return(port);
}

short     GetScopePort ()
{
  short     port;

  enterprocedure("GetScopePort");

  port = ServerBasePort + ServerInPort + ServerDisplay;
  debug(4,(stderr, "scope service is on port %d\n", port));
  return(port);
}

/* ********************************************** */
/*                                                */
/* ********************************************** */

Usage()
{
  fprintf(stderr, "Usage: xscope\n");
  fprintf(stderr, "              [-h<server-host>]\n");
  fprintf(stderr, "              [-i<in-port>]\n");
  fprintf(stderr, "              [-o<out-port>]\n");
  fprintf(stderr, "              [-d<display-number>]\n");
  fprintf(stderr, "              [-v<n>]  -- verbose output\n");
  fprintf(stderr, "              [-q]  -- quiet output\n");
  fprintf(stderr, "              [-D<debug-level>]\n");
  fprintf(stderr, "              [-S<n>] -- start/stop on SIGUSR1\n");
  exit(1);
}


char *OfficialName();  /* forward type declaration */

ScanArgs(argc, argv)
     int     argc;
     char  **argv;
{
  Verbose = 1 /* default verbose-ness level */;

  /* Scan argument list */
  while (--argc > 0)
    {
      ++argv;
      if (**argv == '-')
	switch (*++*argv)
	  {
	    /*
	      debug levels:
	      	2 - trace each procedure entry
	      	4 - I/O, connections
	      	8 - Scope internals
	      	16 - Message protocol
		32 - 64 - malloc
		128 - 256 - really low level
	    */
	  case 'D':
	    debuglevel = atoi(++*argv);
	    if (debuglevel == 0)
	      debuglevel = 255;
	    debuglevel |= 1;
	    Verbose = 7;
	    debug(1,(stderr, "debuglevel = %d\n", debuglevel));
	    break;

	  case 'S':
	    HandleSIGUSR1 = 1;
	    ScopeEnabled = atoi(++*argv);
	    break;

	  case 'q': /* quiet mode */
	    Verbose = 0;
	    debug(1,(stderr, "Verbose = %d\n", Verbose));
	    break;

	  case 'v': /* verbose mode */
	    Verbose = atoi(++*argv);
	    debug(1,(stderr, "Verbose = %d\n", Verbose));
	    break;

	  case 'o':
	    ServerOutPort = atoi(++*argv);
	    if (ServerOutPort <= 0)
	      ServerOutPort = 0;
	    debug(1,(stderr, "ServerOutPort = %d\n", ServerOutPort));
	    break;

	  case 'd':
	    ServerDisplay = atoi(++*argv);
	    if (ServerDisplay <= 0)
	      ServerDisplay = 0;
	    debug(1,(stderr, "ServerDisplay=%d\n", ServerDisplay));
	    break;

	  case 'i':
	    ServerInPort = atoi(++*argv);
	    if (ServerInPort <= 0)
	      ServerInPort = 0;
	    debug(1,(stderr, "ServerInPort = %d\n", ServerInPort));
	    break;

	  case 'h':
	    if (++*argv != NULL && **argv != '\0')
	      (void)strcpy(ServerHostName, OfficialName(*argv));
	    debug(1,(stderr, "ServerHostName=%s\n", ServerHostName));
	    break;

	  default:
	    fprintf(stderr, "Unknown option %c\n", **argv);
	    Usage();
	    break;

	  }
      else
	{
	  /* file argument to scope -- error */
	  Usage();
	}
    }

  /* check for different port numbers or different machines */
  if (ServerInPort == ServerOutPort)
    if (ServerHostName[0] == '\0')
      {
	fprintf(stderr, "Can't have xscope on same port as server (%d)\n",
		ServerInPort);
	Usage();
      }

}


/* ********************************************** */
/*                                                */
/* ********************************************** */

main(argc, argv)
     int     argc;
     char  **argv;
{
  ScanArgs(argc, argv);
  InitializeFD();
  InitializeX11();
  InitializePEX();
  SetUpStdin();
  SetUpConnectionSocket(GetScopePort());
  SetSignalHandling();

  MainLoop();
}

TimerExpired()
{
  debug(16,(stderr, "Timer tick\n"));
}

/* ********************************************** */
/*                                                */
/* ********************************************** */

/*
  here is where we would add code to allow control from
  the keyboard.  We would want to read a command and
  interpret it.  Possibilties:

  (a) verbose level setting
  (b) reset time
  (c) save X requests to a file.
  (d) replay X requests from a file.
  (e) allow fake events, errors to be generated.
*/

ReadStdin(fd)
     FD fd;
{
  char    buf[2048];
  long    n;

  enterprocedure("ReadStdin");
  n = read(fd, buf, 2048);
  debug(4,(stderr, "read %d bytes from stdin\n", n));
}

SetUpStdin()
{
  enterprocedure("SetUpStdin");
  UsingFD(fileno(stdin), ReadStdin);
}

/* ************************************************************ */
/*								*/
/*								*/
/* ************************************************************ */

/*
  xscope is really meant to look at one client at a time.  However,
  it can easily handle multiple clients and servers.  To do so,
  we need to have a pair of FDs: one for the client and one for the
  server for that client.  If either goes away, so does the other.
  We need to be able to identify the other FD of a pair, so that if
  we get input from one, we can write it to the other.
*/

struct fdinfo
{
  Boolean Server;
  long    ClientNumber;
  FD pair;
};

static long ClientNumber = 0;
struct fdinfo   FDinfo[StaticMaxFD];

SetUpPair(client, server)
     FD client;
     FD server;
{
  if (client >= 0)
    {
      ClientNumber += 1;
      FDinfo[client].Server = false;
      FDinfo[client].pair = server;
      FDinfo[client].ClientNumber = ClientNumber;
      if (server >= 0)
	{
	  FDinfo[server].Server = true;
	  FDinfo[server].pair = client;
	  FDinfo[server].ClientNumber = FDinfo[client].ClientNumber;
	}
    }
  else if (server >= 0)
      {
	(void)close(server);
	NotUsingFD(server);
      }
}


CloseConnection(fd)
     FD fd;
{
  debug(4,(stderr, "close %d and %d\n", fd, FDPair(fd)));
  StopClientConnection(ServerHalf(fd));
  StopServerConnection(ClientHalf(fd));

  (void)close(fd);
  NotUsingFD(fd);
  (void)close(FDPair(fd));
  NotUsingFD(FDPair(fd));
}

/* ************************************************************ */

FD FDPair(fd)
     FD fd;
{
  return(FDinfo[fd].pair);
}

FD ClientHalf(fd)
     FD fd;
{
  if (FDinfo[fd].Server)
    return(FDinfo[fd].pair);
  return(fd);
}

FD ServerHalf(fd)
     FD fd;
{
  if (FDinfo[fd].Server)
    return(fd);
  return(FDinfo[fd].pair);
}

char   *ClientName (fd)
     FD fd;
{
  static char name[12];

  if (ClientNumber <= 1)
    return("");
  (void)sprintf(name, " %d", FDinfo[fd].ClientNumber);
  return(name);
}


/* ********************************************** */
/*                                                */
/* ********************************************** */

/* when we get data from a client, we read it in, copy it to the
   server for this client, then dump it to the client. Note, we don't
   have to have a server, if there isn't one. */

DataFromClient(fd)
     FD fd;
{
  unsigned char    buf[2048];
  long    n;
  FD ServerFD;

  enterprocedure("DataFromClient");
  n = read(fd, (char *)buf, 2048);
  debug(4,(stderr, "read %d bytes from Client%s\n", n, ClientName(fd)));
  if (n < 0)
    {
      PrintTime();
      perror("Client --> read error:");
      CloseConnection(fd);
      return;
    }
  if (n == 0)
    {
      PrintTime();
      fprintf(stdout, "Client%s --> EOF\n", ClientName(fd));
      CloseConnection(fd);
      return;
    }

  ServerFD = FDPair(fd);
  if (ServerFD < 0)
    {
      ServerFD = ConnectToServer(false);
      SetUpPair(fd, ServerFD);
    }

  /* write bytes from client to server, allow for server to fail */
  if (ServerFD >= 0)
    {
      long    BytesToWrite = n;
      unsigned char   *p = buf;

      while (BytesToWrite > 0)
	{
	  int     n1 = write (ServerFD, (char *)p, (int)BytesToWrite);
	  debug(4,(stderr, "write %d bytes to Server%s\n", n1, ClientName(fd)));
	  if (n1 > 0)
	    {
	      BytesToWrite -= n1;
	      p += n1;
	    }
	  else
	    {
			    perror("Error on write to Server");
	      CloseConnection(fd);
	      BytesToWrite = 0;
	    }
	}
    }

  /* also report the bytes to standard out */
  ReportFromClient(fd, buf, n);
}

/* ********************************************** */
/*                                                */
/* ********************************************** */

/* similar situation for the server, but note that if there is no client,
   we close the connection down -- don't need a server with no client. */

DataFromServer(fd)
     FD fd;
{
  unsigned char    buf[2048];
  long    n;
  FD ClientFD;

  enterprocedure("DataFromServer");
  n = read(fd, (char *)buf, 2048);
  debug(4,(stderr, "read %d bytes from Server%s\n", n, ClientName(fd)));
  if (n < 0)
    {
      PrintTime();
      perror("read error <- Server");
      CloseConnection(fd);
      return;
    }
  if (n == 0)
    {
      PrintTime();
      fprintf(stdout, "EOF <-- Server%s\n", ClientName(fd));
      CloseConnection(fd);
      return;
    }

  ClientFD = FDPair(fd);
  if (ClientFD < 0)
    {
      CloseConnection(fd);
      return;
    }

  /* write bytes from server to client, allow for client to fail */
  {
    long    BytesToWrite = n;
    unsigned char   *p = buf;
    while (BytesToWrite > 0)
      {
	int     n1 = write (ClientFD, (char *)p, (int)BytesToWrite);
	debug(4,(stderr, "write %d bytes to Client%s\n", n1, ClientName(fd)));
	if (n1 > 0)
	  {
	    BytesToWrite -= n1;
	    p += n1;
	  }
	else
	  {
			perror("Error on write to Client");
	    CloseConnection(fd);
	    BytesToWrite = 0;
	  }
      }
  }

  /* also report the bytes to standard out */
  ReportFromServer(fd, buf, n);
}



/* ************************************************************ */
/*								*/
/*     Create New Connection to a client program and to Server  */
/*								*/
/* ************************************************************ */

static int  ON = 1 /* used in ioctl */ ;

NewConnection(fd)
     FD fd;
{
  FD ServerFD = -1;
  FD ClientFD = -1;

  ClientFD = ConnectToClient(fd);
  ServerFD = ConnectToServer(true);
  SetUpPair(ClientFD, ServerFD);
}


/* ************************************************************ */

FD ConnectToClient(ConnectionSocket)
     FD ConnectionSocket;
{
  FD ClientFD;
  struct sockaddr_in  from;
  int    len = sizeof (from);

  enterprocedure("ConnectToClient");

  ClientFD = accept(ConnectionSocket, (struct sockaddr *)&from, &len);
  debug(4,(stderr, "Connect To Client: FD %d\n", ClientFD));
  if (ClientFD < 0 && errno == EWOULDBLOCK)
    {
      debug(4,(stderr, "Almost blocked accepting FD %d\n", ClientFD));
      panic("Can't connect to Client");
    }
  if (ClientFD < 0)
    {
      debug(4,(stderr, "NewConnection: error %d\n", errno));
      panic("Can't connect to Client");
    }

  UsingFD(ClientFD, DataFromClient);
  (void)ioctl(ClientFD, FIOCLEX, 0);
  (void)ioctl(ClientFD, FIONBIO, &ON);
  StartClientConnection(ClientFD);
  return(ClientFD);
}



/* ************************************************************ */
/*								*/
/*								*/
/* ************************************************************ */



FD ConnectToServer(report)
     Boolean report;
{
  FD ServerFD;
  struct sockaddr_in  sin;
  struct hostent *hp;
#ifndef	SO_DONTLINGER
  struct linger linger;
#endif	SO_DONTLINGER

  enterprocedure("ConnectToServer");

  /* establish a socket to the name server for this host */
  bzero((char *)&sin, sizeof(sin));
  ServerFD = socket(AF_INET, SOCK_STREAM, 0);
  if (ServerFD < 0)
    {
      perror("socket() to Server failed");
      debug(1,(stderr, "socket failed\n"));
      panic("Can't open connection to Server");
    }
  (void) setsockopt(ServerFD, SOL_SOCKET, SO_REUSEADDR,  (char *) NULL, 0);
  (void) setsockopt(ServerFD, SOL_SOCKET, SO_USELOOPBACK,(char *) NULL, 0);
#ifdef	SO_DONTLINGER
  (void) setsockopt(ServerFD, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
#else	SO_DONTLINGER
  linger.l_onoff = 0;
  linger.l_linger = 0;
  (void) setsockopt(ServerFD, SOL_SOCKET, SO_LINGER, (char *)&linger,
sizeof linger);
#endif	SO_DONTLINGER

  /* determine the host machine for this process */
  if (ServerHostName[0] == '\0')
    (void) gethostname(ServerHostName, sizeof (ServerHostName));
  debug(4,(stderr, "try to connect on %s\n", ServerHostName));

  hp = gethostbyname(ServerHostName);
  if (hp == 0)
    {
      perror("gethostbyname failed");
      debug(1,(stderr, "gethostbyname failed for %s\n", ServerHostName));
      panic("Can't open connection to Server");
    }

  sin.sin_family = AF_INET;
  bcopy((char *)hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
  sin.sin_port = GetServerport();

  if ((sin.sin_port == ScopePort) 
      && strcmp(ServerHostName, ScopeHost) == 0)
    {
      char error_message[100];
      (void)sprintf(error_message, "Trying to attach to myself: %s,%d\n",
	      ServerHostName, sin.sin_port);
      panic(error_message);
    }

  /* ******************************************************** */
  /* try to connect to Server */

  if (connect(ServerFD, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
      debug(4,(stderr, "connect returns errno of %d\n", errno));
      if (errno != 0)
	if (report)
	  perror("connect");
      switch (errno)
	{
	case ECONNREFUSED:
	  /* experience says this is because there is no Server
	     to connect to */
	  (void)close(ServerFD);
	  debug(1,(stderr, "No Server\n"));
	  if (report)
	    warn("Can't open connection to Server");
	  return(-1);

	default:
	  (void)close(ServerFD);
	  panic("Can't open connection to Server");
	}
    }

  debug(4,(stderr, "Connect To Server: FD %d\n", ServerFD));
  if (ServerFD >= 0)
    {
      UsingFD(ServerFD, DataFromServer);
      StartServerConnection(ServerFD);
    }
  return(ServerFD);
}


/* ********************************************** */
/*                                                */
/* ********************************************** */

char *OfficialName(name)
char *name;
{
  struct hostent *HostEntry;

  HostEntry = gethostbyname(name);
  if (HostEntry == NULL)
    {
      perror("gethostbyname");
      exit(-1);
    }
  debug(4,(stderr, "Official name of %s is %s\n", name, HostEntry->h_name));
  return(HostEntry->h_name);
}