home *** CD-ROM | disk | FTP | other *** search
/ Encyclopedia of Graphics File Formats Companion / GFF_CD.ISO / software / unix / saoimage / sao1_07.tar / ctrlcntn.c < prev    next >
C/C++ Source or Header  |  1991-05-15  |  15KB  |  476 lines

  1. #ifndef lint
  2. static char SccsId[] = "%W%  %G%";
  3. #endif
  4.  
  5. /* Module:    ctrlcntn.c (Control Connection)
  6.  * Purpose:    Handle all IO with remote independent processes
  7.  * Subroutine:    init_connections()        returns: void
  8.  * Subroutine:    open_connection()        returns: int
  9.  * Subroutine:    close_connection()        returns: void
  10.  * Subroutine:    flush_connection()        returns: void
  11.  * Subroutine:    respond_to_connection()        returns: void
  12.  * Subroutine:    read_connection()        returns: int
  13.  * Subroutine:    write_connection()        returns: int
  14.  * Copyright:    1990 Smithsonian Astrophysical Observatory
  15.  *        You may do anything you like with this file except remove
  16.  *        this copyright.  The Smithsonian Astrophysical Observatory
  17.  *        makes no representations about the suitability of this
  18.  *        software for any purpose.  It is provided "as is" without
  19.  *        express or implied warranty.
  20.  * Modified:    {0} M. VanHilst    initial version            10 March 1990
  21.  *        {n} <who> -- <does what> -- <when>
  22.  */
  23.  
  24. #include <stdio.h>        /* stderr, NULL, etc. */
  25. #include <X11/Xlib.h>        /* X window stuff */ 
  26. #include "hfiles/control.h"    /* declare control structure types */
  27. extern struct controlRec control;
  28. extern Display *display;
  29.  
  30. #define IOP_socket_listener 777
  31. #define IOP_socket_acceptee 555
  32.  
  33. /*
  34.  * Subroutine:    init_connections
  35.  * Purpose:    set up connections after display connection has been opened
  36.  * Note:    necessary since parser precedes display connection
  37.  */
  38. void init_connections ()
  39. {
  40.   if( control.IRAF_in.open == 1 ) {
  41.     control.IRAF_in.open = 0;
  42.     if( control.IRAF_in.func != NULL )
  43.       (*control.IRAF_in.func)();
  44.   }
  45.   if( control.AIPS_in.open == 1 ) {
  46.     control.AIPS_in.open = 0;
  47.     if( control.AIPS_in.func != NULL )
  48.       (*control.AIPS_in.func)();
  49.   }
  50.   if( control.aux_in.open == 1 ) {
  51.     control.aux_in.open = 0;
  52.     if( control.aux_in.func != NULL )
  53.       (*control.aux_in.func)();
  54.   }
  55. }
  56.  
  57. /*
  58.  * Subroutine:    open_connection
  59.  * Purpose:    Open a connection to a remote process and update event handlers
  60.  * Returns:    -1 on failure, else IPC number
  61.  */
  62. int open_connection ( connection )
  63.      struct connectRec *connection;
  64. {
  65.   int ipc, flush_flag;
  66. #ifdef VMS
  67.   extern int open_mailbox();
  68. #else
  69.   extern int ButtonSelectMask(), open_pipe();
  70.   extern int open_socket_listener();
  71.   extern struct connectRec *accept_socket_connection();
  72.   static void init_select();
  73. #endif
  74.  
  75. #ifdef NOPIPEFLUSH
  76.   flush_flag = 0;
  77. #else
  78.   flush_flag = 1;
  79. #endif
  80.  
  81.   if( ((connection->type != IOP_socket) &&
  82.        (connection->name == NULL)) ||
  83.       ((connection->type == IOP_socket) &&
  84.        (connection->address <= 0)) ) {
  85.     if( connection->direction == IOP_Write )
  86.       (void)fprintf(stderr,"Error: output device not defined\n");
  87.     else
  88.       (void)fprintf(stderr,"Error: input device not defined\n");
  89.     return( -1 );
  90.   }
  91.   if( (connection->type != IOP_socket_listener) &&
  92.       (connection->open && (connection->fd >= 0)) ) {
  93.     (void)fprintf(stderr, "Warning: connection already open: %s\n",
  94.           connection->name);
  95.     return(connection->fd);
  96.   }
  97. #ifdef VMS
  98.   if( connection->type == IOP_mailbox ) {
  99.     ipc = open_mailbox(connection->name, connection->direction, 1);
  100.   }
  101. #else
  102.   if( connection->type == IOP_pipe ) {
  103.     ipc = open_pipe(connection->name, connection->direction, flush_flag);
  104.   } else if( connection->type == IOP_socket ) {
  105.     ipc = open_socket_listener(&(connection->name), connection->address);
  106.   } else if( connection->type == IOP_socket_listener ) {
  107.     struct connectRec *temp;
  108.  
  109.     if( (temp = accept_socket_connection(connection)) != NULL ) {
  110.       connection = temp;
  111.       ipc = connection->fd;
  112.       connection->type = IOP_socket_acceptee;
  113.     } else
  114.       ipc = -1;
  115.   }
  116. #endif
  117.   if( ipc < 0 ) {
  118.     if( connection->direction == IOP_Write )
  119.       (void)fprintf(stderr,"Error: No remote output possible.\n");
  120.     else
  121.       (void)fprintf(stderr,"Error: No remote input possible.\n");
  122.     connection->fd = -1;
  123.     connection->open = 0;
  124.     return( -1 );
  125.   } else {
  126.     connection->fd = ipc;
  127.     connection->open = 1;
  128. #ifdef VMS
  129.     {
  130.       extern int  XZ_efn;
  131.       extern void XZ_ast();
  132.  
  133.       ZSelectAsyncInput(ipc, XZ_ast, XZ_efn);
  134.     }
  135. #else
  136.     if( (control.select_size <= 0) || (control.Xserver.open != 1) )
  137.       init_select();
  138.     /* compute IPC channel's select mask and set up event handling */
  139.     if( ipc < 32 ) {
  140.       connection->mask[0] = (1 << ipc);
  141.       connection->mask[1] = 0;
  142.       connection->mask[2] = 0;
  143.       connection->mask[3] = 0;
  144.     } else if( ipc < 64 ) {
  145.       connection->mask[0] = 0;
  146.       connection->mask[1] = (1 << (ipc - 32));
  147.       connection->mask[2] = 0;
  148.       connection->mask[3] = 0;
  149.     } else if( ipc < 96 ) {
  150.       connection->mask[0] = 0;
  151.       connection->mask[1] = 0;
  152.       connection->mask[2] = (1 << (ipc - 64));
  153.       connection->mask[3] = 0;
  154.     } else if( ipc < 128 ) {
  155.       connection->mask[0] = 0;
  156.       connection->mask[1] = 0;
  157.       connection->mask[2] = 0;
  158.       connection->mask[3] = (1 << (ipc - 96));
  159.     } else {
  160.       (void)fprintf(stderr, "device channel out of range\n");
  161.       return 0;
  162.     }
  163. #endif
  164.     if( (connection->direction != IOP_Write) ||
  165.         (connection->type == IOP_socket) ) {
  166.       /* if connnection used to read, add it to event accepting list */
  167.       connection->next = control.Xserver.next;
  168.       control.Xserver.next = connection;
  169.       ++control.remote_connected;
  170. #ifndef VMS
  171.       /* add bits to client's mask and adjust client's mask size */
  172.       control.select_mask[0] |= connection->mask[0];
  173.       control.select_mask[1] |= connection->mask[1];
  174.       control.select_mask[2] |= connection->mask[2];
  175.       control.select_mask[4] |= connection->mask[3];
  176.       /* inform the event handler in buttonlib about our ipc messages */
  177.       if( ButtonSelectMask(display, connection->mask,
  178.                control.select_size, 1) != 1 )
  179.     (void)fprintf(stderr,"Warning: error setting button event mask\n");
  180. #endif
  181.     }
  182.   }
  183.   return ipc;
  184. }
  185.  
  186. /*
  187.  * Subroutine:    close_connection
  188.  * Purpose:    Close the remote process connection and update event handlers
  189.  */
  190. void close_connection ( connection )
  191.      struct connectRec *connection;
  192. {
  193. #ifdef VMS
  194.   extern int close_mailbox();
  195. #else
  196.   extern int ButtonSelectMask();
  197.   extern void close_pipe(), close_socket();
  198. #endif
  199.  
  200.   if( connection->open ) {
  201. #ifdef VMS
  202.     if( connection->type == IOP_mailbox )
  203.       (void)close_mailbox(connection->fd, connection->name);
  204. #else
  205.     if( connection->type == IOP_pipe ) {
  206.       close_pipe(connection->fd, connection->name);
  207.     } else if( (connection->type == IOP_socket) ||
  208.            (connection->type == IOP_socket_listener) ||
  209.            (connection->type == IOP_socket_acceptee) ) {
  210.       close_socket(connection->fd, connection->name);
  211.     }
  212. #endif
  213.     connection->fd = -1;
  214.     connection->open = 0;
  215.     if( (connection->type == IOP_socket_listener) ||
  216.     (connection->type == IOP_socket) ||
  217.     (connection->direction != IOP_Write) ) {
  218.       struct connectRec *port = &control.Xserver;
  219.  
  220.       /* remove connection from event servicing queue */
  221.       while( (port != NULL) && (port->next != connection) )
  222.     port = port->next;
  223.       if( (port != NULL) && (port->next == connection) ) {
  224.     port->next = connection->next;
  225.     connection->next = NULL;
  226.     --control.remote_connected;
  227.       }
  228. #ifdef VMS
  229.     }
  230. #else
  231.       /* remove connection from UNIX select event servicing masks */
  232.       if( (connection->mask[0] & control.select_mask[0]) ||
  233.       (connection->mask[1] & control.select_mask[1]) || 
  234.       (connection->mask[1] & control.select_mask[1]) ||
  235.       (connection->mask[1] & control.select_mask[1]) ) {
  236.     if( ButtonSelectMask((Display *)NULL, connection->mask,
  237.                  control.select_size, 0) )
  238.       (void)fprintf(stderr, "Warning: error clearing button event mask\n");
  239.     if( (connection->mask[0] != 0) &&
  240.         (connection->mask[0] != control.Xserver.mask[0]) ) {
  241.       control.select_mask[0] &= (~(connection->mask[0]));
  242.           connection->mask[0] = 0;
  243.         }
  244.     if( (connection->mask[1] != 0) &&
  245.         (connection->mask[1] != control.Xserver.mask[1]) ) {
  246.       control.select_mask[1] &= (~(connection->mask[1]));
  247.       connection->mask[1] = 0;
  248.     }
  249.     if( (connection->mask[2] != 0) &&
  250.         (connection->mask[2] != control.Xserver.mask[1]) ) {
  251.       control.select_mask[2] &= (~(connection->mask[1]));
  252.       connection->mask[2] = 0;
  253.     }
  254.     if( (connection->mask[3] != 0) &&
  255.         (connection->mask[3] != control.Xserver.mask[1]) ) {
  256.       control.select_mask[3] &= (~(connection->mask[1]));
  257.       connection->mask[3] = 0;
  258.     }
  259.       }
  260.       /* if only X connections are sought, turn off remote connection flag */
  261.       if( (control.select_mask[0] == control.Xserver.mask[0]) &&
  262.       (control.select_mask[1] == control.Xserver.mask[1]) &&
  263.       (control.select_mask[2] == control.Xserver.mask[2]) &&
  264.       (control.select_mask[3] == control.Xserver.mask[3]) )
  265.         control.remote_connected = 0;
  266.     }
  267.     connection->mask[0] = 0;
  268.     connection->mask[1] = 0;
  269.     connection->mask[2] = 0;
  270.     connection->mask[3] = 0;
  271.     /* coordinate sockets reader and listener */
  272.     if( connection->type == IOP_socket_acceptee ) {
  273.       /* closing a connection reopens its listener */
  274.       connection->affiliate->type = IOP_socket;
  275.       connection->affiliate->affiliate = NULL;
  276.       (void)open_connection(connection->affiliate);
  277.       /* acceptees are malloc'd space */
  278.       free(connection);
  279.     }
  280.   } else if( (connection->type == IOP_socket_listener) &&
  281.          (connection->affiliate != NULL) &&
  282.          connection->affiliate->open ) {
  283.     /* if closing an inactive listener, close its affiliate connection */
  284.     if( connection->affiliate->direction == IOP_Write ) {
  285.       close_socket(connection->affiliate);
  286.     } else {
  287.       /* clear up event descritor if not write-only */
  288.       connection->affiliate->type = IOP_socket;
  289.       close_connection(connection->affiliate);
  290.     }
  291.     free(connection->affiliate);
  292.     connection->affiliate = NULL;
  293. #endif
  294.   }
  295. }
  296.  
  297. /*
  298.  * Subroutine:    flush_connection
  299.  * Purpose:    Suck all bytes out of a pipe open for reading
  300.  */
  301. void flush_connection ( connection )
  302.      struct connectRec *connection;
  303. {
  304. #ifdef VMS
  305.   extern void flush_mailbox();
  306. #else
  307.   extern void flush_pipe(), flush_socket();
  308. #endif
  309.  
  310. #ifdef VMS
  311.   if( connection->type == IOP_mailbox )
  312.     flush_mailbox(connection->fd, connection->name);
  313. #else
  314.   if( connection->type == IOP_pipe )
  315.     flush_pipe(connection->fd, connection->name);
  316.   else if( connection->type == IOP_socket_acceptee )
  317.     flush_socket(connection->fd, connection->name);
  318. #endif
  319. }
  320.  
  321. /*
  322.  * Subroutine:    respond_to_connection
  323.  * Purpose:    call the function for this connection event
  324.  */
  325. void respond_to_connection ( id )
  326.      int *id;    /* call identifier (UNIX bit mask or VMS mailbox number) */
  327. {
  328.   int i;
  329.   struct connectRec *port;
  330.  
  331.   port = control.Xserver.next;
  332.   /* loop has redundant terminations which should coincide */
  333.   for( i=0; (port != NULL) && (i<control.remote_connected); i++ ) {
  334. #ifdef VMS
  335.     if( *id == port->fd )
  336. #else
  337.     if( (id[0] & port->mask[0]) || (id[1] & port->mask[1]) ||
  338.         (id[2] & port->mask[2]) || (id[3] & port->mask[3]) )
  339. #endif
  340.       continue;
  341.     port = port->next;
  342.   }
  343.   if( port != NULL ) {
  344. #ifndef VMS
  345.     if( port->type == IOP_socket ) {
  346.       /* event on open listener means open socket acceptee, close listener */
  347.       port->type = IOP_socket_listener;
  348.       /* open on redefined listener creates the acceptee */
  349.       if( open_connection(port) < 0 )
  350.         port->type = IOP_socket;
  351.       else {
  352.     close_connection(port);
  353.     /* set the file descriptor, in case somebody tries to write to it */
  354.         port->fd = port->affiliate->fd;
  355.       }
  356.     } else 
  357. #endif
  358.       if( port->func != NULL )
  359.     /* execute the connection's response function */
  360.         (*port->func)(port);
  361. #ifdef DEBUG
  362.   } else
  363.     (void)fprintf(stderr, "Unrecognized select or mailbox event\n");
  364. #else
  365.   }
  366. #endif
  367. }
  368.  
  369. /*
  370.  * Subroutine:    read_connection
  371.  * Purpose:    read specified number of bytes from connection into buf
  372.  */
  373. int read_connection ( connection, buf, bytes )
  374.      struct connectRec *connection;
  375.      char *buf;
  376.      int bytes;
  377. {
  378.   int status;
  379. #ifdef VMS
  380.   extern int read_mailbox();
  381.  
  382.   if( connection->type == IOP_mailbox )
  383.     status = read_mailbox(connection->fd, buf, bytes, 1, connection->name,
  384.               "mailbox input");
  385. #else
  386.   extern int read_disk();
  387.  
  388.   if( (connection->type == IOP_pipe) ||
  389.       (connection->type == IOP_socket_acceptee) )
  390.     status = read_disk(connection->fd, buf, bytes, 1, connection->name,
  391.                "remote input");
  392. #endif
  393.   else
  394.     status = -1;
  395.   return( status );
  396. }
  397.  
  398. /*
  399.  * Subroutine:    write_connection
  400.  * Purpose:    write specified number of bytes to connection from buf
  401.  */
  402. int write_connection ( connection, buf, bytes )
  403.      struct connectRec *connection;
  404.      char *buf;
  405.      int bytes;
  406. {
  407.   int status;
  408. #ifdef VMS
  409.   extern int write_mailbox();
  410.  
  411.   if( connection->type == IOP_mailbox )
  412.     status = write_mailbox(connection->fd, buf, bytes, connection->name);
  413. #else
  414.   extern int write_disk();
  415.  
  416.   if( (connection->type == IOP_pipe) ||
  417.       (connection->type == IOP_socket_acceptee) )
  418.     status = write_disk(connection->fd, buf, bytes, connection->name);
  419.   else if( connection->type == IOP_socket_listener )
  420.     status = write_disk(connection->affiliate->fd, buf, bytes,
  421.             connection->name);
  422. #endif
  423.   else
  424.     status = -1;
  425.   return( status );
  426. }
  427.  
  428. #ifndef VMS
  429. /*
  430.  * Subroutine:    init_select
  431.  * Purpose:    Initialize event handler parameters
  432.  * Note:    SYSV machines don't have an easy way to get the number of
  433.  *        device bits in the select mask.  Most have 64.  Under BSD,
  434.  *        Sun uses 32 (1 int), Apollo uses 128 (4 ints).
  435.  */
  436. static void init_select ()
  437. {
  438.   int server_chan;
  439.  
  440. #ifdef SYSV
  441.   control.select_size = 64;
  442. #else
  443.   control.select_size = getdtablesize();
  444. #endif
  445.   /* get the x window server channel and compute its mask */
  446.   server_chan = ConnectionNumber(display);
  447.   if( server_chan < 32 ) {
  448.     control.Xserver.mask[0] = (1 << server_chan);
  449.     control.Xserver.mask[1] = 0;
  450.     control.Xserver.mask[2] = 0;
  451.     control.Xserver.mask[3] = 0;
  452.   } else if( server_chan < 64 ) {
  453.     control.Xserver.mask[0] = 0;
  454.     control.Xserver.mask[1] = (1 << (server_chan - 32));
  455.     control.Xserver.mask[2] = 0;
  456.     control.Xserver.mask[3] = 0;
  457.   } else if( server_chan < 96 ) {
  458.     control.Xserver.mask[0] = 0;
  459.     control.Xserver.mask[1] = 0;
  460.     control.Xserver.mask[2] = (1 << (server_chan - 64));
  461.     control.Xserver.mask[3] = 0;
  462.   } else if( server_chan < 64 ) {
  463.     control.Xserver.mask[0] = 0;
  464.     control.Xserver.mask[1] = 0;
  465.     control.Xserver.mask[2] = 0;
  466.     control.Xserver.mask[3] = (1 << (server_chan - 96));
  467.   }
  468.   /* initialize combined mask and open new pipe */
  469.   control.select_mask[0] = control.Xserver.mask[0];
  470.   control.select_mask[1] = control.Xserver.mask[1];
  471.   control.select_mask[2] = control.Xserver.mask[2];
  472.   control.select_mask[3] = control.Xserver.mask[3];
  473.   control.Xserver.open = 1;
  474. }
  475. #endif
  476.