home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / fonts / lib / fs / FSConnServ.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  13.3 KB  |  532 lines

  1. /* $XConsortium: FSConnServ.c,v 1.14 91/09/09 18:55:13 rws Exp $ */
  2.  
  3. /* @(#)FSConnServ.c    4.1    91/05/02
  4.  * Copyright 1990 Network Computing Devices;
  5.  * Portions Copyright 1987 by Digital Equipment Corporation and the
  6.  * Massachusetts Institute of Technology
  7.  *
  8.  * Permission to use, copy, modify, and distribute this protoype software
  9.  * and its documentation to Members and Affiliates of the MIT X Consortium
  10.  * any purpose and without fee is hereby granted, provided
  11.  * that the above copyright notice appear in all copies and that both that
  12.  * copyright notice and this permission notice appear in supporting
  13.  * documentation, and that the names of Network Computing Devices, Digital or
  14.  * MIT not be used in advertising or publicity pertaining to distribution of
  15.  * the software without specific, written prior permission.
  16.  *
  17.  * NETWORK COMPUTING DEVICES, DIGITAL AND MIT DISCLAIM ALL WARRANTIES WITH
  18.  * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  19.  * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, DIGITAL OR MIT BE
  20.  * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  21.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  22.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  23.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  24.  */
  25.  
  26. #include    <stdio.h>
  27. #include    <X11/Xos.h>
  28. #include    "FSlibint.h"
  29. #include    <sys/socket.h>
  30. #ifdef NCD
  31. #include    <fcntl.h>
  32. #endif
  33.  
  34. /* font server does not actually support unix domain yet */
  35. #ifdef UNIXCONN
  36. #undef UNIXCONN
  37. #endif
  38.  
  39. #ifdef DNETCONN
  40. #include <netdnet/dn.h>
  41. #include <netdnet/dnetdb.h>
  42. #endif /* DNETCONN */
  43.  
  44. #ifndef hpux
  45.  
  46. #ifndef apollo            /* nest ifndefs because makedepend is broken */
  47. #include <netinet/tcp.h>
  48. #endif
  49.  
  50. #endif
  51.  
  52. #define FamilyLocal (256)
  53. #define FamilyWild  (65535)
  54.  
  55.  
  56. /*
  57.  * Attempts to connect to server, given server name. Returns file descriptor
  58.  * (network socket) or -1 if connection fails. The expanded server name
  59.  * of the form hostname:number.screen ("::" if DECnet) is returned in a result
  60.  * parameter. The screen number to use is also returned.
  61.  */
  62. int
  63. _FSConnectServer(server_name, expanded_name)
  64.     char       *server_name;
  65.     char       *expanded_name;    /* return */
  66. {
  67.     char        serverbuf[256];    /* Server string buffer */
  68.     register char *server_ptr;    /* Server string buffer pointer */
  69.     register char *numbuf_ptr;    /* Server number buffer pointer */
  70.     int         server_num;    /* Server number */
  71.     struct sockaddr_in inaddr;    /* INET socket address. */
  72.     unsigned long hostinetaddr;    /* result of inet_addr of arpa addr */
  73.  
  74. #ifdef UNIXCONN
  75.     struct sockaddr_un unaddr;    /* UNIX socket address. */
  76.  
  77. #endif
  78.     struct sockaddr *addr;    /* address to connect to */
  79.     struct hostent *host_ptr;
  80.     int         addrlen;    /* length of address */
  81. #ifdef    X_NOT_STDC_ENV
  82.     extern char *getenv();
  83. #endif
  84.     int         fd;        /* Network socket */
  85.  
  86. #ifdef DNETCONN
  87.     int         dnet = 0;
  88.     char        objname[20];
  89.     extern int  dnet_conn();
  90.  
  91. #endif
  92.     int         tmp_svr_numlen = 0;
  93.     char       *tmp_svr_num = NULL;
  94.     int         tmp_server_addrlen = 0;
  95.     char       *tmp_server_addr = NULL;
  96.  
  97.     /*
  98.      * Find the ':' seperator and extract the hostname and the server number.
  99.      * NOTE - if DECnet is to be used, the server name is formatted as
  100.      * "host::number"
  101.      */
  102.     (void) strncpy(serverbuf, server_name, sizeof(serverbuf));
  103.     if ((server_ptr = SearchString(serverbuf, ':')) == NULL)
  104.     return (-1);
  105.  
  106. #ifdef DNETCONN
  107.     if (*(server_ptr + 1) == ':') {
  108.     dnet++;
  109.     *(server_ptr++) = '\0';
  110.     }
  111. #endif
  112.  
  113.     *(server_ptr++) = '\0';
  114.  
  115.     /*
  116.      * serverbuf now contains only a null-terminated host name, and server_ptr
  117.      * points to the server number. If the server number is missing there is
  118.      * an error.
  119.      */
  120.  
  121.     if (*server_ptr == '\0')
  122.     return (-1);
  123.  
  124.     tmp_server_addrlen = 0;
  125.     tmp_server_addr = NULL;
  126.  
  127.     /*
  128.      * Convert the server number string to an integer.
  129.      */
  130.     server_num = atoi(server_ptr);
  131.     tmp_svr_numlen = strlen(server_ptr);
  132.     tmp_svr_num = FSmalloc(tmp_svr_numlen + 1);
  133.     if (!tmp_svr_num) {
  134.     return (-1);
  135.     }
  136.     strcpy(tmp_svr_num, server_ptr);
  137.  
  138.     /*
  139.      * If the server name is missing, use current host.
  140.      */
  141.     if (serverbuf[0] == '\0')
  142.  
  143. #ifdef DNETCONN
  144.     if (dnet)
  145.         (void) strcpy(serverbuf, "0");
  146.     else
  147. #endif
  148.  
  149. #ifdef UNIXCONN
  150.         ;            /* Do nothing if UNIX DOMAIN. Will be handled
  151.                  * below. */
  152. #else
  153.         (void) _FSGetHostname(serverbuf, sizeof serverbuf);
  154. #endif                /* UNIXCONN else TCPCONN (assumed) */
  155.  
  156. #ifdef DNETCONN
  157.     if (dnet) {
  158.     struct dn_naddr *dnaddrp,
  159.                 dnaddr;
  160.     struct nodeent *np;
  161.  
  162.     /*
  163.      * build the target object name.
  164.      */
  165.     sprintf(objname, "X$X%d", server_num);
  166.     /*
  167.      * Attempt to open the DECnet connection, return -1 if fails.
  168.      */
  169.     if ((fd = dnet_conn(serverbuf,
  170.                 objname, SOCK_STREAM, 0, 0, 0, 0)) < 0 ||
  171.         fd >= OPEN_MAX) {
  172.         if (tmp_svr_num)
  173.         FSfree(tmp_svr_num);
  174.         return (-1);    /* errno set by dnet_conn. */
  175.     }
  176.     if (dnaddrp = dnet_addr(serverbuf)) {    /* stolen from xhost */
  177.         dnaddr = *dnaddrp;
  178.     } else {
  179.         if ((np = getnodebyname(serverbuf)) == NULL) {
  180.         (void) close(fd);
  181.         if (tmp_svr_num)
  182.             FSfree(tmp_svr_num);
  183.         return (-1);
  184.         }
  185.         dnaddr.a_len = np->n_length;
  186.         bcopy(np->n_addr, dnaddr.a_addr, np->n_length);
  187.     }
  188.     tmp_server_addrlen = sizeof(struct dn_naddr);
  189.     tmp_server_addr = FSmalloc(tmp_server_addrlen);
  190.     if (!tmp_server_addr) {
  191.         (void) close(fd);
  192.         if (tmp_svr_num)
  193.         FSfree(tmp_svr_num);
  194.         return (-1);
  195.     }
  196.     bcopy((char *) &dnaddr, tmp_server_addr, tmp_server_addrlen);
  197.     } else
  198. #endif
  199.  
  200.     {
  201.  
  202. #ifdef UNIXCONN
  203.     if ((serverbuf[0] == '\0') ||
  204.         (strcmp("unix", serverbuf) == 0)) {
  205.         /* Connect locally using Unix domain. */
  206.         unaddr.sun_family = AF_UNIX;
  207.         (void) strcpy(unaddr.sun_path, X_UNIX_PATH);
  208.         strcat(unaddr.sun_path, server_ptr);
  209.         addr = (struct sockaddr *) & unaddr;
  210.         addrlen = strlen(unaddr.sun_path) + 2;
  211.         /*
  212.          * Open the network connection.
  213.          */
  214.         if ((fd = socket((int) addr->sa_family, SOCK_STREAM, 0)) < 0 ||
  215.             fd >= OPEN_MAX) {
  216.         if (tmp_svr_num)
  217.             FSfree(tmp_svr_num);
  218.         return (-1);    /* errno set by system call. */
  219.         }
  220.         /*
  221.          * This is a hack and is not part of the protocol
  222.          */
  223.         {
  224.         char        tmpbuf[1024];
  225.  
  226.         tmp_server_addrlen = _FSGetHostname(tmpbuf, sizeof tmpbuf);
  227.         tmp_server_addr = FSmalloc(tmp_server_addrlen + 1);
  228.         if (!tmp_server_addr) {
  229.             if (tmp_svr_num)
  230.             FSfree(tmp_svr_num);
  231.             (void) close(fd);
  232.             return (-1);
  233.         }
  234.         strcpy(tmp_server_addr, tmpbuf);
  235.         }
  236.     } else
  237. #endif
  238.  
  239.     {
  240.         char    *sp = serverbuf;
  241.  
  242.         /* ignore a leading "tcp/" */
  243.         if (strncmp(sp, "tcp/", 4) == 0)
  244.             sp += 4;
  245.  
  246.         /* Get the statistics on the specified host. */
  247.         hostinetaddr = inet_addr(sp);
  248.         if (hostinetaddr == -1) {
  249.         if ((host_ptr = gethostbyname(sp)) == NULL) {
  250.             /* No such host! */
  251.             errno = EINVAL;
  252.             if (tmp_svr_num)
  253.             FSfree(tmp_svr_num);
  254.             return (-1);
  255.         }
  256.         /* Check the address type for an internet host. */
  257.         if (host_ptr->h_addrtype != AF_INET) {
  258.             /* Not an Internet host! */
  259.             errno = EPROTOTYPE;
  260.             if (tmp_svr_num)
  261.             FSfree(tmp_svr_num);
  262.             return (-1);
  263.         }
  264.         /* Set up the socket data. */
  265.         inaddr.sin_family = host_ptr->h_addrtype;
  266.  
  267. #if defined(CRAY) && defined(OLDTCP)
  268.         /* Only Cray UNICOS3 and UNICOS4 will define this */
  269.         {
  270.             long        t;
  271.  
  272.             bcopy((char *) host_ptr->h_addr,
  273.               (char *) &t,
  274.               sizeof(inaddr.sin_addr));
  275.             inaddr.sin_addr = t;
  276.         }
  277. #else
  278.         bcopy((char *) host_ptr->h_addr,
  279.               (char *) &inaddr.sin_addr,
  280.               sizeof(inaddr.sin_addr));
  281. #endif                /* CRAY and OLDTCP */
  282.         } else {
  283.  
  284. #if defined(CRAY) && defined(OLDTCP)
  285.         /* Only Cray UNICOS3 and UNICOS4 will define this */
  286.         inaddr.sin_addr = hostinetaddr;
  287. #else
  288.         inaddr.sin_addr.s_addr = hostinetaddr;
  289. #endif                /* CRAY and OLDTCP */
  290.  
  291.         inaddr.sin_family = AF_INET;
  292.         }
  293.         addr = (struct sockaddr *) & inaddr;
  294.         addrlen = sizeof(struct sockaddr_in);
  295.         inaddr.sin_port = server_num;
  296.         inaddr.sin_port = htons(inaddr.sin_port);
  297.         /*
  298.          * Open the network connection.
  299.          */
  300.  
  301.         if ((fd = socket((int) addr->sa_family, SOCK_STREAM, 0)) < 0 ||
  302.         fd >= OPEN_MAX) {
  303.         if (tmp_svr_num)
  304.             FSfree(tmp_svr_num);
  305.         return (-1);    /* errno set by system call. */
  306.         }
  307.         /* save address information */
  308.         {
  309.         char       *cp;
  310.         char        tmpbuf[1024];
  311.  
  312. #ifdef CRAY
  313. #ifdef OLDTCP
  314.         tmp_server_addrlen = sizeof(inaddr.sin_addr);
  315. #else
  316.         tmp_server_addrlen = SIZEOF_in_addr;
  317. #endif
  318.         cp = (char *) &inaddr.sin_addr;
  319. #else
  320.         tmp_server_addrlen = sizeof(inaddr.sin_addr.s_addr);
  321.         cp = (char *) &inaddr.sin_addr.s_addr;
  322. #endif /* CRAY */
  323.  
  324.         if ((tmp_server_addrlen == 4) &&
  325.             (cp[0] == 127) && (cp[1] == 0) &&
  326.             (cp[2] == 0) && (cp[3] == 1)) {
  327.             /*
  328.              * We are special casing the BSD hack localhost address
  329.              * 127.0.0.1, since this address shouldn't be copied to
  330.              * other machines.  So, we convert it to FamilyLocal. This
  331.              * is a hack and is not part of the protocol
  332.              */
  333.             tmp_server_addrlen = _FSGetHostname(tmpbuf, sizeof tmpbuf);
  334.             cp = tmpbuf;
  335.         }
  336.         tmp_server_addr = FSmalloc(tmp_server_addrlen);
  337.         if (!tmp_server_addr) {
  338.             (void) close(fd);
  339.             if (tmp_svr_num)
  340.             FSfree(tmp_svr_num);
  341.             return (-1);
  342.         }
  343.         bcopy(cp, tmp_server_addr, tmp_server_addrlen);
  344.         }
  345.  
  346.         /* make sure to turn off TCP coalescence */
  347.  
  348. #ifdef TCP_NODELAY
  349.         {
  350.         int         mi = 1;
  351.  
  352.         setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &mi, sizeof(int));
  353.         }
  354. #endif
  355.     }
  356.  
  357.  
  358.     if (connect(fd, addr, addrlen) == -1) {
  359.         (void) close(fd);
  360.         if (tmp_svr_num)
  361.         FSfree(tmp_svr_num);
  362.         if (tmp_server_addr)
  363.         FSfree(tmp_server_addr);
  364.         return (-1);    /* errno set by system call. */
  365.     }
  366.     }
  367.     /*
  368.      * set it non-blocking.  This is so we can read data when blocked for
  369.      * writing in the library.
  370.      */
  371.  
  372.     /* ultrix reads hang on Unix sockets, hpux reads fail */
  373. #if defined(O_NONBLOCK) && (!defined(ultrix) && !defined(hpux) && !defined(AIXV3))
  374.     (void) fcntl (fd, F_SETFL, O_NONBLOCK);
  375. #else
  376. #ifdef FIOSNBIO
  377.     {
  378.     int arg = 1;
  379.     ioctl (fd, FIOSNBIO, &arg);
  380.     }
  381. #else
  382. #if defined(AIXV3) && defined(FIONBIO)
  383.     {
  384.     int arg;
  385.     arg = 1;
  386.     ioctl(fd, FIONBIO, &arg);
  387.     }
  388. #else
  389.     (void) fcntl (fd, F_SETFL, FNDELAY);
  390. #endif
  391. #endif
  392. #endif
  393.  
  394.     /*
  395.      * Return the id if the connection succeeded. Rebuild the expanded spec
  396.      * and return it in the result parameter.
  397.      */
  398.     server_ptr = serverbuf - 1;
  399.     while (*(++server_ptr) != '\0');
  400.     *(server_ptr++) = ':';
  401.  
  402. #ifdef DNETCONN
  403.     if (dnet)
  404.     *(server_ptr++) = ':';
  405. #endif
  406.  
  407.     numbuf_ptr = tmp_svr_num;
  408.     while (*numbuf_ptr != '\0')
  409.     *(server_ptr++) = *(numbuf_ptr++);
  410.     *server_ptr = '\0';
  411.     (void) strcpy(expanded_name, serverbuf);
  412.     return (fd);
  413.  
  414. }
  415.  
  416. /*
  417.  * Disconnect from server.
  418.  */
  419.  
  420. int
  421. _FSDisconnectServer(server)
  422.     int         server;
  423.  
  424. {
  425.     (void) close(server);
  426. }
  427.  
  428. #undef NULL
  429. #define NULL ((char *) 0)
  430. /*
  431.  * This is an OS dependent routine which:
  432.  * 1) returns as soon as the connection can be written on....
  433.  * 2) if the connection can be read, must enqueue events and handle errors,
  434.  * until the connection is writable.
  435.  */
  436. _FSWaitForWritable(svr)
  437.     FSServer     *svr;
  438. {
  439.     unsigned long r_mask[MSKCNT];
  440.     unsigned long w_mask[MSKCNT];
  441.     int         nfound;
  442.  
  443.     CLEARBITS(r_mask);
  444.     CLEARBITS(w_mask);
  445.  
  446.     while (1) {
  447.     BITSET(r_mask, svr->fd);
  448.     BITSET(w_mask, svr->fd);
  449.  
  450.     do {
  451.         nfound = select(svr->fd + 1, r_mask, w_mask, NULL, NULL);
  452.         if (nfound < 0 && errno != EINTR)
  453.         (*_FSIOErrorFunction) (svr);
  454.     } while (nfound <= 0);
  455.  
  456.     if (_FSANYSET(r_mask)) {
  457.         char        buf[BUFSIZE];
  458.         long        pend_not_register;
  459.         register long pend;
  460.         register fsEvent *ev;
  461.  
  462.         /* find out how much data can be read */
  463.         if (BytesReadable(svr->fd, (char *) &pend_not_register) < 0)
  464.         (*_FSIOErrorFunction) (svr);
  465.         pend = pend_not_register;
  466.  
  467.         /*
  468.          * must read at least one fsEvent; if none is pending, then we'll
  469.          * just block waiting for it
  470.          */
  471.         if (pend < SIZEOF(fsEvent))
  472.         pend = SIZEOF(fsEvent);
  473.  
  474.         /* but we won't read more than the max buffer size */
  475.         if (pend > BUFSIZE)
  476.         pend = BUFSIZE;
  477.  
  478.         /* round down to an integral number of FSReps */
  479.         pend = (pend / SIZEOF(fsEvent)) * SIZEOF(fsEvent);
  480.  
  481.         _FSRead(svr, buf, pend);
  482.  
  483.         /* no space between comma and type or else macro will die */
  484.         STARTITERATE(ev, fsEvent, buf, (pend > 0),
  485.              (pend -= SIZEOF(fsEvent))) {
  486.         if (ev->type == FS_Error)
  487.             _FSError(svr, (fsError *) ev);
  488.         else        /* it's an event packet; enqueue it */
  489.             _FSEnq(svr, ev);
  490.         }
  491.         ENDITERATE
  492.     }
  493.     if (_FSANYSET(w_mask))
  494.         return;
  495.     }
  496. }
  497.  
  498.  
  499. _FSWaitForReadable(svr)
  500.     FSServer     *svr;
  501. {
  502.     unsigned long r_mask[MSKCNT];
  503.     int         result;
  504.  
  505.     CLEARBITS(r_mask);
  506.     do {
  507.     BITSET(r_mask, svr->fd);
  508.     result = select(svr->fd + 1, r_mask, NULL, NULL, NULL);
  509.     if (result == -1 && errno != EINTR)
  510.         (*_FSIOErrorFunction) (svr);
  511.     } while (result <= 0);
  512. }
  513.  
  514. _FSSendClientPrefix(svr, client)
  515.     FSServer     *svr;
  516.     fsConnClientPrefix *client;
  517. {
  518.     struct iovec iovarray[5],
  519.                *iov = iovarray;
  520.     int         niov = 0;
  521.  
  522. #define add_to_iov(b,l) \
  523.       { iov->iov_base = (b); iov->iov_len = (l); iov++, niov++; }
  524.  
  525.     add_to_iov((caddr_t) client, SIZEOF(fsConnClientPrefix));
  526.  
  527. #undef add_to_iov
  528.  
  529.     (void) WritevToServer(svr->fd, iovarray, niov);
  530.     return;
  531. }
  532.