home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / x / volume2 / xmonitor / part02 / scope.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-28  |  14.6 KB  |  627 lines

  1. /* ******************************************************
  2.  *                                  *
  3.  *  A spy program to reveal X11  traffic            *
  4.  *                                  *
  5.  *    James Peterson, 1988                       *
  6.  *    (c) Copyright MCC, 1988             *
  7.  *                            *
  8.  ***************************************************** */
  9.  
  10. #include "scope.h"
  11.  
  12.  
  13. /* ********************************************** */
  14. /*                                                */
  15. /* ********************************************** */
  16.  
  17. #define DefaultPort 6000
  18.  
  19. char    ServerHostName[255];
  20. long    ServerBasePort = DefaultPort;
  21. long    ServerInPort = 1;
  22. long    ServerOutPort = 0;
  23. long    ServerDisplay = 0;
  24.  
  25.  
  26. /* ********************************************** */
  27. /*                                                */
  28. /*                                                */
  29. /* ********************************************** */
  30.  
  31. short     GetServerport ()
  32. {
  33.   short     port;
  34.  
  35.   enterprocedure("GetServerport");
  36.  
  37.   port = ServerBasePort + ServerOutPort + ServerDisplay;
  38.   debug(4,(stderr, "Server service is on port %d\n", port));
  39.   return(port);
  40. }
  41.  
  42. short     GetScopePort ()
  43. {
  44.   short     port;
  45.  
  46.   enterprocedure("GetScopePort");
  47.  
  48.   port = ServerBasePort + ServerInPort + ServerDisplay;
  49.   debug(4,(stderr, "scope service is on port %d\n", port));
  50.   return(port);
  51. }
  52.  
  53. /* ********************************************** */
  54. /*                                                */
  55. /* ********************************************** */
  56.  
  57. Usage()
  58. {
  59.   fprintf(stderr, "Usage: xscope\n");
  60.   fprintf(stderr, "              [-h<server-host>]\n");
  61.   fprintf(stderr, "              [-i<in-port>]\n");
  62.   fprintf(stderr, "              [-o<out-port>]\n");
  63.   fprintf(stderr, "              [-d<display-number>]\n");
  64.   fprintf(stderr, "              [-v<n>]  -- verbose output\n");
  65.   fprintf(stderr, "              [-q]  -- quiet output\n");
  66.   fprintf(stderr, "              [-D<debug-level>]\n");
  67.   exit(1);
  68. }
  69.  
  70.  
  71. char *OfficialName()  /* forward type declaration */;
  72.  
  73. ScanArgs(argc, argv)
  74.      int     argc;
  75.      char  **argv;
  76. {
  77.   Verbose = 1 /* default verbose-ness level */;
  78.  
  79.   /* Scan argument list */
  80.   while (--argc > 0)
  81.     {
  82.       ++argv;
  83.       if (**argv == '-')
  84.     switch (*++*argv)
  85.       {
  86.         /*
  87.           debug levels:
  88.               2 - trace each procedure entry
  89.               4 - I/O, connections
  90.               8 - Scope internals
  91.               16 - Message protocol
  92.         32 - 64 - malloc
  93.         128 - 256 - really low level
  94.         */
  95.       case 'D':
  96.         debuglevel = atoi(++*argv);
  97.         if (debuglevel == 0)
  98.           debuglevel = 255;
  99.         debuglevel |= 1;
  100.         Verbose = 7;
  101.         debug(1,(stderr, "debuglevel = %d\n", debuglevel));
  102.         break;
  103.  
  104.       case 'q': /* quiet mode */
  105.         Verbose = 0;
  106.         debug(1,(stderr, "Verbose = %d\n", Verbose));
  107.         break;
  108.  
  109.       case 'v': /* verbose mode */
  110.         Verbose = atoi(++*argv);
  111.         debug(1,(stderr, "Verbose = %d\n", Verbose));
  112.         break;
  113.  
  114.       case 'o':
  115.         ServerOutPort = atoi(++*argv);
  116.         if (ServerOutPort <= 0)
  117.           ServerOutPort = 0;
  118.         debug(1,(stderr, "ServerOutPort = %d\n", ServerOutPort));
  119.         break;
  120.  
  121.       case 'd':
  122.         ServerDisplay = atoi(++*argv);
  123.         if (ServerDisplay <= 0)
  124.           ServerDisplay = 0;
  125.         debug(1,(stderr, "ServerDisplay=%d\n", ServerDisplay));
  126.         break;
  127.  
  128.       case 'i':
  129.         ServerInPort = atoi(++*argv);
  130.         if (ServerInPort <= 0)
  131.           ServerInPort = 0;
  132.         debug(1,(stderr, "ServerInPort = %d\n", ServerInPort));
  133.         break;
  134.  
  135.       case 'h':
  136.         if (++*argv != NULL && **argv != '\0')
  137.           strcpy(ServerHostName, OfficialName(*argv));
  138.         debug(1,(stderr, "ServerHostName=%s\n", ServerHostName));
  139.         break;
  140.  
  141.       default:
  142.         fprintf(stderr, "Unknown option %c\n", **argv);
  143.         Usage();
  144.         break;
  145.  
  146.       }
  147.       else
  148.     {
  149.       /* file argument to scope -- error */
  150.       Usage();
  151.     }
  152.     }
  153.  
  154.   /* check for different port numbers or different machines */
  155.   if (ServerInPort == ServerOutPort)
  156.     if (ServerHostName[0] == '\0')
  157.       {
  158.     fprintf(stderr, "Can't have xscope on same port as server (%d)\n",
  159.         ServerInPort);
  160.     Usage();
  161.       }
  162.  
  163. }
  164.  
  165.  
  166. /* ********************************************** */
  167. /*                                                */
  168. /* ********************************************** */
  169.  
  170. main(argc, argv)
  171.      int     argc;
  172.      char  **argv;
  173. {
  174.   ScanArgs(argc, argv);
  175.   InitializeFD();
  176.   InitializeX11();
  177.   SetUpStdin();
  178.   SetUpConnectionSocket(GetScopePort());
  179.   SetSignalHandling();
  180.  
  181.   MainLoop();
  182. }
  183.  
  184. TimerExpired()
  185. {
  186.   debug(16,(stderr, "Timer tick\n"));
  187. }
  188.  
  189. /* ********************************************** */
  190. /*                                                */
  191. /* ********************************************** */
  192.  
  193. /*
  194.   here is where we would add code to allow control from
  195.   the keyboard.  We would want to read a command and
  196.   interpret it.  Possibilties:
  197.  
  198.   (a) verbose level setting
  199.   (b) reset time
  200.   (c) save X requests to a file.
  201.   (d) replay X requests from a file.
  202.   (e) allow fake events, errors to be generated.
  203. */
  204.  
  205. ReadStdin(fd)
  206.      FD fd;
  207. {
  208.   char    buf[2048];
  209.   long    n;
  210.  
  211.   enterprocedure("ReadStdin");
  212.   n = read(fd, buf, 2048);
  213.   debug(4,(stderr, "read %d bytes from stdin\n", n));
  214. }
  215.  
  216. SetUpStdin()
  217. {
  218.   enterprocedure("SetUpStdin");
  219.   UsingFD(fileno(stdin), ReadStdin);
  220. }
  221.  
  222. /* ************************************************************ */
  223. /*                                */
  224. /*                                */
  225. /* ************************************************************ */
  226.  
  227. /*
  228.   xscope is really meant to look at one client at a time.  However,
  229.   it can easily handle multiple clients and servers.  To do so,
  230.   we need to have a pair of FDs: one for the client and one for the
  231.   server for that client.  If either goes away, so does the other.
  232.   We need to be able to identify the other FD of a pair, so that if
  233.   we get input from one, we can write it to the other.
  234. */
  235.  
  236. struct fdinfo
  237. {
  238.   Boolean Server;
  239.   long    ClientNumber;
  240.   FD pair;
  241. };
  242.  
  243. static long ClientNumber = 0;
  244. struct fdinfo   FDinfo[StaticMaxFD];
  245.  
  246. SetUpPair(client, server)
  247.      FD client;
  248.      FD server;
  249. {
  250.   if (client >= 0)
  251.     {
  252.       ClientNumber += 1;
  253.       FDinfo[client].Server = false;
  254.       FDinfo[client].pair = server;
  255.       FDinfo[client].ClientNumber = ClientNumber;
  256.       if (server >= 0)
  257.     {
  258.       FDinfo[server].Server = true;
  259.       FDinfo[server].pair = client;
  260.       FDinfo[server].ClientNumber = FDinfo[client].ClientNumber;
  261.     }
  262.     }
  263.   else if (server >= 0)
  264.       {
  265.     close(server);
  266.     NotUsingFD(server);
  267.       }
  268. }
  269.  
  270.  
  271. CloseConnection(fd)
  272.      FD fd;
  273. {
  274.   debug(4,(stderr, "close %d and %d\n", fd, FDPair(fd)));
  275.   StopClientConnection(ServerHalf(fd));
  276.   StopServerConnection(ClientHalf(fd));
  277.  
  278.   close(fd);
  279.   NotUsingFD(fd);
  280.   close(FDPair(fd));
  281.   NotUsingFD(FDPair(fd));
  282. }
  283.  
  284. /* ************************************************************ */
  285.  
  286. FD FDPair(fd)
  287.      FD fd;
  288. {
  289.   return(FDinfo[fd].pair);
  290. }
  291.  
  292. FD ClientHalf(fd)
  293.      FD fd;
  294. {
  295.   if (FDinfo[fd].Server)
  296.     return(FDinfo[fd].pair);
  297.   return(fd);
  298. }
  299.  
  300. FD ServerHalf(fd)
  301.      FD fd;
  302. {
  303.   if (FDinfo[fd].Server)
  304.     return(fd);
  305.   return(FDinfo[fd].pair);
  306. }
  307.  
  308. char   *ClientName (fd)
  309.      FD fd;
  310. {
  311.   static char name[12];
  312.  
  313.   if (ClientNumber <= 1)
  314.     return("");
  315.   sprintf(name, " %d", FDinfo[fd].ClientNumber);
  316.   return(name);
  317. }
  318.  
  319.  
  320. /* ********************************************** */
  321. /*                                                */
  322. /* ********************************************** */
  323.  
  324. /* when we get data from a client, we read it in, copy it to the
  325.    server for this client, then dump it to the client. Note, we don't
  326.    have to have a server, if there isn't one. */
  327.  
  328. DataFromClient(fd)
  329.      FD fd;
  330. {
  331.   unsigned char    buf[2048];
  332.   long    n;
  333.   FD ServerFD;
  334.  
  335.   enterprocedure("DataFromClient");
  336.   n = read(fd, (char *)buf, 2048);
  337.   debug(4,(stderr, "read %d bytes from Client%s\n", n, ClientName(fd)));
  338.   if (n < 0)
  339.     {
  340.       PrintTime();
  341.       perror("Client --> read error:");
  342.       CloseConnection(fd);
  343.       return;
  344.     }
  345.   if (n == 0)
  346.     {
  347.       PrintTime();
  348.       fprintf(stdout, "Client%s --> EOF\n", ClientName(fd));
  349.       CloseConnection(fd);
  350.       return;
  351.     }
  352.  
  353.   ServerFD = FDPair(fd);
  354.   if (ServerFD < 0)
  355.     {
  356.       ServerFD = ConnectToServer(false);
  357.       SetUpPair(fd, ServerFD);
  358.     }
  359.  
  360.   /* write bytes from client to server, allow for server to fail */
  361.   if (ServerFD >= 0)
  362.     {
  363.       long    BytesToWrite = n;
  364.       unsigned char   *p = buf;
  365.  
  366.       while (BytesToWrite > 0)
  367.     {
  368.       int     n1 = write (ServerFD, (char *)p, (int)BytesToWrite);
  369.       debug(4,(stderr, "write %d bytes to Server%s\n", n1, ClientName(fd)));
  370.       if (n1 > 0)
  371.         {
  372.           BytesToWrite -= n1;
  373.           p += n1;
  374.         }
  375.       else
  376.         {
  377.                 perror("Error on write to Server");
  378.           CloseConnection(fd);
  379.           BytesToWrite = 0;
  380.         }
  381.     }
  382.     }
  383.  
  384.   /* also report the bytes to standard out */
  385.   ReportFromClient(fd, buf, n);
  386. }
  387.  
  388. /* ********************************************** */
  389. /*                                                */
  390. /* ********************************************** */
  391.  
  392. /* similar situation for the server, but note that if there is no client,
  393.    we close the connection down -- don't need a server with no client. */
  394.  
  395. DataFromServer(fd)
  396.      FD fd;
  397. {
  398.   unsigned char    buf[2048];
  399.   long    n;
  400.   FD ClientFD;
  401.  
  402.   enterprocedure("DataFromServer");
  403.   n = read(fd, (char *)buf, 2048);
  404.   debug(4,(stderr, "read %d bytes from Server%s\n", n, ClientName(fd)));
  405.   if (n < 0)
  406.     {
  407.       PrintTime();
  408.       perror("read error <- Server");
  409.       CloseConnection(fd);
  410.       return;
  411.     }
  412.   if (n == 0)
  413.     {
  414.       PrintTime();
  415.       fprintf(stdout, "EOF <-- Server%s\n", ClientName(fd));
  416.       CloseConnection(fd);
  417.       return;
  418.     }
  419.  
  420.   ClientFD = FDPair(fd);
  421.   if (ClientFD < 0)
  422.     {
  423.       CloseConnection(fd);
  424.       return;
  425.     }
  426.  
  427.   /* write bytes from server to client, allow for client to fail */
  428.   {
  429.     long    BytesToWrite = n;
  430.     unsigned char   *p = buf;
  431.     while (BytesToWrite > 0)
  432.       {
  433.     int     n1 = write (ClientFD, (char *)p, (int)BytesToWrite);
  434.     debug(4,(stderr, "write %d bytes to Client%s\n", n1, ClientName(fd)));
  435.     if (n1 > 0)
  436.       {
  437.         BytesToWrite -= n1;
  438.         p += n1;
  439.       }
  440.     else
  441.       {
  442.             perror("Error on write to Client");
  443.         CloseConnection(fd);
  444.         BytesToWrite = 0;
  445.       }
  446.       }
  447.   }
  448.  
  449.   /* also report the bytes to standard out */
  450.   ReportFromServer(fd, buf, n);
  451. }
  452.  
  453.  
  454.  
  455. /* ************************************************************ */
  456. /*                                */
  457. /*     Create New Connection to a client program and to Server  */
  458. /*                                */
  459. /* ************************************************************ */
  460.  
  461. #include <sys/types.h>           /* needed by sys/socket.h and netinet/in.h */
  462. #include <sys/uio.h>           /* for struct iovec, used by socket.h */
  463. #include <sys/socket.h>           /* for AF_INET, SOCK_STREAM, ... */
  464. #include <sys/ioctl.h>           /* for FIONCLEX, FIONBIO, ... */
  465. #include <netinet/in.h>           /* struct sockaddr_in */
  466. #include <netdb.h>           /* struct servent * and struct hostent * */
  467. #include <errno.h>           /* for EINTR, EADDRINUSE, ... */
  468. extern int  errno;
  469.  
  470. static int  ON = 1 /* used in ioctl */ ;
  471.  
  472. NewConnection(fd)
  473.      FD fd;
  474. {
  475.   FD ServerFD = -1;
  476.   FD ClientFD = -1;
  477.  
  478.   ClientFD = ConnectToClient(fd);
  479.   ServerFD = ConnectToServer(true);
  480.   SetUpPair(ClientFD, ServerFD);
  481. }
  482.  
  483.  
  484. /* ************************************************************ */
  485.  
  486. FD ConnectToClient(ConnectionSocket)
  487.      FD ConnectionSocket;
  488. {
  489.   FD ClientFD;
  490.   struct sockaddr_in  from;
  491.   int    len = sizeof (from);
  492.  
  493.   enterprocedure("ConnectToClient");
  494.  
  495.   ClientFD = accept(ConnectionSocket, (struct sockaddr *)&from, &len);
  496.   debug(4,(stderr, "Connect To Client: FD %d\n", ClientFD));
  497.   if (ClientFD < 0 && errno == EWOULDBLOCK)
  498.     {
  499.       debug(4,(stderr, "Almost blocked accepting FD %d\n", ClientFD));
  500.       panic("Can't connect to Client");
  501.     }
  502.   if (ClientFD < 0)
  503.     {
  504.       debug(4,(stderr, "NewConnection: error %d\n", errno));
  505.       panic("Can't connect to Client");
  506.     }
  507.  
  508.   UsingFD(ClientFD, DataFromClient);
  509.   ioctl(ClientFD, FIOCLEX, 0);
  510.   ioctl(ClientFD, FIONBIO, &ON);
  511.   StartClientConnection(ClientFD);
  512.   return(ClientFD);
  513. }
  514.  
  515.  
  516.  
  517. /* ************************************************************ */
  518. /*                                */
  519. /*                                */
  520. /* ************************************************************ */
  521.  
  522.  
  523.  
  524. FD ConnectToServer(report)
  525.      Boolean report;
  526. {
  527.   FD ServerFD;
  528.   struct sockaddr_in  sin;
  529.   struct hostent *hp;
  530.  
  531.   enterprocedure("ConnectToServer");
  532.  
  533.   /* establish a socket to the name server for this host */
  534.   bzero((char *)&sin, sizeof(sin));
  535.   ServerFD = socket(AF_INET, SOCK_STREAM, 0);
  536.   if (ServerFD < 0)
  537.     {
  538.       perror("socket() to Server failed");
  539.       debug(1,(stderr, "socket failed\n"));
  540.       panic("Can't open connection to Server");
  541.     }
  542.   (void) setsockopt(ServerFD, SOL_SOCKET, SO_REUSEADDR,  (char *) NULL, 0);
  543.   (void) setsockopt(ServerFD, SOL_SOCKET, SO_USELOOPBACK,(char *) NULL, 0);
  544.   (void) setsockopt(ServerFD, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0);
  545.  
  546.   /* determine the host machine for this process */
  547.   if (ServerHostName[0] == '\0')
  548.     (void) gethostname(ServerHostName, sizeof (ServerHostName));
  549.   debug(4,(stderr, "try to connect on %s\n", ServerHostName));
  550.  
  551.   hp = gethostbyname(ServerHostName);
  552.   if (hp == 0)
  553.     {
  554.       perror("gethostbyname failed");
  555.       debug(1,(stderr, "gethostbyname failed for %s\n", ServerHostName));
  556.       panic("Can't open connection to Server");
  557.     }
  558.  
  559.   sin.sin_family = AF_INET;
  560.   bcopy((char *)hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
  561.   sin.sin_port = GetServerport();
  562.  
  563.   if ((sin.sin_port == ScopePort) 
  564.       && strcmp(ServerHostName, ScopeHost) == 0)
  565.     {
  566.       char error_message[100];
  567.       sprintf(error_message, "Trying to attach to myself: %s,%d\n",
  568.           ServerHostName, sin.sin_port);
  569.       panic(error_message);
  570.     }
  571.  
  572.   /* ******************************************************** */
  573.   /* try to connect to Server */
  574.  
  575.   if (connect(ServerFD, (struct sockaddr *)&sin, sizeof(sin)) < 0)
  576.     {
  577.       debug(4,(stderr, "connect returns errno of %d\n", errno));
  578.       if (errno != 0)
  579.     if (report)
  580.       perror("connect");
  581.       switch (errno)
  582.     {
  583.     case ECONNREFUSED:
  584.       /* experience says this is because there is no Server
  585.          to connect to */
  586.       close(ServerFD);
  587.       debug(1,(stderr, "No Server\n"));
  588.       if (report)
  589.         warn("Can't open connection to Server");
  590.       return(-1);
  591.  
  592.     default:
  593.       close(ServerFD);
  594.       panic("Can't open connection to Server");
  595.     }
  596.     }
  597.  
  598.   debug(4,(stderr, "Connect To Server: FD %d\n", ServerFD));
  599.   if (ServerFD >= 0)
  600.     {
  601.       UsingFD(ServerFD, DataFromServer);
  602.       StartServerConnection(ServerFD);
  603.     }
  604.   return(ServerFD);
  605. }
  606.  
  607.  
  608. /* ********************************************** */
  609. /*                                                */
  610. /* ********************************************** */
  611.  
  612. char *OfficialName(name)
  613. char *name;
  614. {
  615.   struct hostent *HostEntry;
  616.  
  617.   HostEntry = gethostbyname(name);
  618.   if (HostEntry == NULL)
  619.     {
  620.       perror("gethostbyname");
  621.       exit(-1);
  622.     }
  623.   debug(4,(stderr, "Official name of %s is %s\n", name, HostEntry->h_name));
  624.   return(HostEntry->h_name);
  625. }
  626.  
  627.