home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / clisp / src / archive / clisp.src.lha / src / socket.d < prev    next >
Text File  |  1996-04-15  |  17KB  |  536 lines

  1. # Setting up a connection to an X server
  2. # Bruno Haible 19.6.1994
  3. # Marcus Daniels 28.9.1995
  4.  
  5. # This code comes from the X11R5 distribution, file mit/X/XConnDis.c,
  6. # with the following modifications:
  7. # - no support for DNETCONN or STREAMSCONN,
  8. # - display name has already been split into hostname and display number,
  9. # - doesn't return full host&display name and auth info,
  10. # - doesn't depend on the X include files.
  11.  
  12. # mit/X/XConnDis.c carries the following copyright notice:
  13. /*
  14.  * $XConsortium: XConnDis.c,v 11.85 91/07/19 23:07:39 gildea Exp $
  15.  *
  16.  * Copyright 1989 Massachusetts Institute of Technology
  17.  *
  18.  * Permission to use, copy, modify, and distribute this software and its
  19.  * documentation for any purpose and without fee is hereby granted, provided
  20.  * that the above copyright notice appear in all copies and that both that
  21.  * copyright notice and this permission notice appear in supporting
  22.  * documentation, and that the name of M.I.T. not be used in advertising
  23.  * or publicity pertaining to distribution of the software without specific,
  24.  * written prior permission.  M.I.T. makes no representations about the
  25.  * suitability of this software for any purpose.  It is provided "as is"
  26.  * without express or implied warranty.
  27.  *
  28.  * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
  29.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T.
  30.  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  31.  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
  32.  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  33.  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  34.  *
  35.  *
  36.  * This file contains operating system dependencies.
  37.  */
  38.  
  39. # These are the only things we need from lispbibl.c :
  40. #include "config.h"
  41. #define global
  42. #define local static
  43. #define var
  44.  
  45. # We assume that if we have gethostbyname(), we have a networking Unix.
  46. # and have either UNIX domain connections or TCP/IP connections.
  47. #ifdef HAVE_GETHOSTBYNAME
  48.  
  49. #ifdef HAVE_SYS_UN_H  # have <sys/un.h> and Unix domain sockets?
  50.   #define UNIXCONN  # use Unix domain sockets
  51. #endif
  52. #ifdef HAVE_NETINET_IN_H  # have <netinet/in.h> ?
  53.   #define TCPCONN  # use TCP/IP sockets
  54. #endif
  55.  
  56. #ifdef TCPCONN
  57.   #define SOCKET_STREAMS
  58. #endif
  59.  
  60. #include <sys/types.h>
  61. #ifdef HAVE_UNISTD_H
  62. #include <unistd.h> # declares fcntl(), close(), sleep()
  63. #endif
  64.  
  65. #ifdef HAVE_MEMSET
  66.   #include <string.h>
  67.   extern void* memset (void* ptr, int c, size_t len); # siehe MEMORY(3)
  68.   #define bzero(ptr,len)  memset(ptr,0,len)
  69.   #define bcopy(source,dest,len) memcpy(dest,source,len)
  70. #else
  71.   extern void bzero (void* ptr, int len); # siehe BZERO(3)
  72.   extern void bcopy (void *source, void *dest, int len);
  73. #endif
  74.  
  75. #include <errno.h>
  76. extern int errno;
  77. #ifndef ENOSYS
  78.   #define ENOSYS  EINVAL
  79. #endif
  80.  
  81. #include <fcntl.h> # declares fcntl() and defines F_SETFD
  82. #ifdef FCNTL_DOTS
  83.   extern int fcntl (int fd, int cmd, ...);
  84. #else
  85.   extern int fcntl (int fd, int cmd, int arg);
  86. #endif
  87. #ifndef FD_CLOEXEC
  88.   #define FD_CLOEXEC  1
  89. #endif
  90.  
  91. extern int close (int fd);
  92. #define CLOSE(fd)  while ((close(fd) < 0) && (errno == EINTR)) ;
  93.  
  94. #ifdef __CYGWIN32__
  95. struct servent *cygwin32_getservbyport(int port,const char *proto) { abort(); }
  96. unsigned short ntohs(unsigned short netshort) { abort(); }
  97. #endif
  98.  
  99. #if defined(UNIXCONN) || defined(TCPCONN)
  100.  
  101. # include <sys/types.h>
  102. #include <sys/socket.h> # declares socket(), connect(), defines AF_UNIX, AF_INET
  103. extern int socket (int domain, int type, int protocol);
  104. extern int connect (int fd, CONNECT_CONST CONNECT_NAME_T name, int namelen);
  105.  
  106. # A wrapper around the connect() function.
  107.   global int nonintr_connect (int fd, struct sockaddr * name, int namelen);
  108.   global int nonintr_connect(fd,name,namelen)
  109.     var int fd;
  110.     var struct sockaddr * name;
  111.     var int namelen;
  112.     { var int retval;
  113.       do { retval = connect(fd,name,namelen); }
  114.          while ((retval < 0) && (errno == EINTR));
  115.       return retval;
  116.     }
  117.   #define connect nonintr_connect
  118.  
  119. extern unsigned int sleep (unsigned int seconds);
  120.  
  121. #endif
  122.  
  123. #ifdef UNIXCONN
  124.   #include <stdio.h>   # declares sprintf()
  125.   #include <string.h>  # declares strcmp(), strlen()
  126.   #ifdef RETSTRLENTYPE /* unless strlen() is a macro */
  127.     extern RETSTRLENTYPE strlen (STRLEN_CONST char* s);
  128.   #endif
  129.   #include <sys/un.h>  # defines struct sockaddr_un
  130.   # set X_UNIX_PATH and - on hpux only - OLD_UNIX_PATH
  131.   #ifndef X_UNIX_PATH
  132.     #ifndef hpux
  133.       #define X_UNIX_PATH "/tmp/.X11-unix/X"
  134.     #else
  135.       #define X_UNIX_PATH "/usr/spool/sockets/X11/"
  136.       #define OLD_UNIX_PATH "/tmp/.X11-unix/X"
  137.     #endif
  138.   #endif
  139. #endif
  140.  
  141. #ifdef TCPCONN
  142.   #ifdef HAVE_GETHOSTNAME
  143.     extern int gethostname (char* name, GETHOSTNAME_SIZE_T namelen);
  144.   #endif
  145.   #ifdef HAVE_SYS_UTSNAME_H
  146.     #include <sys/utsname.h>
  147.     extern int uname (struct utsname * buf);
  148.   #endif
  149.   #ifdef HAVE_GETHOSTBYNAME
  150.     #include <sys/types.h>
  151.     #ifdef HAVE_NETDB_H
  152.       # include <sys/socket.h>
  153.       #include <netdb.h>
  154.     #else
  155.       #include <sun/netdb.h>
  156.     #endif
  157.     extern struct hostent * gethostbyname (GETHOSTBYNAME_CONST char* name);
  158.   #endif
  159.   #ifndef MAXHOSTNAMELEN
  160.     #define MAXHOSTNAMELEN 64
  161.   #endif
  162.   #include <netinet/in.h> # declares htons(), defines struct sockaddr_in
  163.   #ifdef HAVE_ARPA_INET_H
  164.     #include <arpa/inet.h> # declares inet_addr()
  165.   #endif
  166.   extern RET_INET_ADDR_TYPE inet_addr (INET_ADDR_CONST char* host);
  167.   #ifdef HAVE_NETINET_TCP_H
  168.     #include <netinet/in_systm.h>
  169.     #if defined(__386BSD__) || defined(__NetBSD__)
  170.       #include <machine/endian.h> # needed for <netinet/tcp.h>
  171.     #endif
  172.     #include <netinet/tcp.h> # declares TCP_NODELAY
  173.   #endif
  174.   extern int setsockopt (/* int fd, int level, int optname, char* optval, int optlen */);
  175.   #define X_TCP_PORT  6000  # from <X11/Xproto.h>
  176. #endif
  177.  
  178. # Attempts to connect to server, given host name and display number.
  179. # Returns file descriptor (network socket). Returns -1 and sets errbo
  180. # if connection fails.
  181. # An empty hostname is interpreted as the most efficient local connection to
  182. # a server on the same machine (usually a UNIX domain socket).
  183. # hostname="unix" is interpreted as a UNIX domain connection.
  184.  
  185. global int connect_to_server (char* host, int display);
  186. global int connect_to_server(host,display)
  187.   var char* host;  # host of display
  188.   var int display; # display number (screen number always zero)
  189. { var int fd;      # file descriptor to return
  190.   var int retries = 3; # number of retries on ECONNREFUSED
  191.  
  192.   var int conntype; # type of desired connection
  193.   #define conn_none 0
  194.   #define conn_unix 1
  195.   #define conn_tcp  2
  196.   #ifdef TCPCONN
  197.     conntype = conn_tcp;
  198.   #else
  199.     conntype = conn_none;
  200.   #endif
  201.   #ifdef UNIXCONN
  202.     if (host[0] == '\0')
  203.       {
  204.         #ifndef apollo # Unix domain sockets are *really* bad on apollos
  205.         conntype = conn_unix;
  206.         #endif
  207.       }
  208.     else if (strcmp(host,"unix")==0)
  209.       { conntype = conn_unix; }
  210.   #endif
  211.  
  212.   # Make the connection. Do retries in case server host has hit its
  213.   # backlog (which, unfortunately, isn't distinguishable from there not
  214.   # being a server listening at all, which is why we have to not retry
  215.   # too many times).
  216.  
  217.   #ifdef UNIXCONN
  218.   if (conntype == conn_unix)
  219.     {
  220.       var struct sockaddr_un unaddr;          # UNIX socket data block
  221.       var struct sockaddr * addr;             # generic socket pointer
  222.       var int addrlen;                        # length of addr
  223.       #ifdef hpux /* this is disgusting */
  224.       var struct sockaddr_un ounaddr;         # UNIX socket data block
  225.       var struct sockaddr * oaddr;            # generic socket pointer
  226.       var int oaddrlen;                       # length of addr
  227.       #endif
  228.  
  229.       unaddr.sun_family = AF_UNIX;
  230.       sprintf (unaddr.sun_path, "%s%d", X_UNIX_PATH, display);
  231.       addr = (struct sockaddr *) &unaddr;
  232.       #ifdef HAVE_SOCKADDR_UN_LEN /* this is AIX */
  233.       unaddr.sun_len = strlen(unaddr.sun_path); addrlen = sizeof(unaddr);
  234.       #else
  235.       addrlen = strlen(unaddr.sun_path) + sizeof(unaddr.sun_family);
  236.       #endif
  237.       #ifdef hpux /* this is disgusting */
  238.       ounaddr.sun_family = AF_UNIX;
  239.       sprintf (ounaddr.sun_path, "%s%d", OLD_UNIX_PATH, display);
  240.       oaddr = (struct sockaddr *) &ounaddr;
  241.       #ifdef HAVE_SOCKADDR_UN_LEN /* this is AIX */
  242.       ounaddr.sun_len = strlen(ounaddr.sun_path); oaddrlen = sizeof(ounaddr);
  243.       #else
  244.       oaddrlen = strlen(ounaddr.sun_path) + sizeof(ounaddr.sun_family);
  245.       #endif
  246.       #endif
  247.  
  248.       # Open the network connection.
  249.       do { if ((fd = socket((int) addr->sa_family, SOCK_STREAM, 0)) >= 0)
  250.              { if (connect (fd, addr, addrlen) >= 0)
  251.                  break;
  252.                  else
  253.                  { int olderrno = errno; CLOSE(fd); errno = olderrno; }
  254.              }
  255.            #ifdef hpux /* this is disgusting */
  256.            if (errno == ENOENT)
  257.              { if ((fd = socket((int) oaddr->sa_family, SOCK_STREAM, 0)) >= 0)
  258.                  { if (connect (fd, oaddr, oaddrlen) >= 0)
  259.                      break;
  260.                      else
  261.                      { int olderrno = errno; CLOSE(fd); errno = olderrno; }
  262.              }   }
  263.            #endif
  264.            if (!((errno == ENOENT) && (retries > 0)))
  265.              { return -1; }
  266.            sleep (1);
  267.          }
  268.          while (retries-- > 0);
  269.     }
  270.   else
  271.   #endif
  272.  
  273.   #ifdef TCPCONN
  274.   if (conntype == conn_tcp)
  275.     {
  276.       #if defined(HAVE_GETHOSTNAME)
  277.       var char hostname[MAXHOSTNAMELEN+1];
  278.       #elif defined(HAVE_SYS_UTSNAME_H)
  279.       var struct utsname utsname;
  280.       #endif
  281.       var unsigned long hostinetaddr;       # result of inet_addr of arpa addr
  282.       var struct sockaddr_in inaddr;        # IP socket
  283.       var struct sockaddr * addr;           # generic socket pointer
  284.       var int addrlen;                      # length of addr
  285.       if (host[0] == '\0')
  286.         { # get host name
  287.           #if defined(HAVE_GETHOSTNAME)
  288.           if (gethostname(&!hostname,MAXHOSTNAMELEN) < 0) { return -1; }
  289.           hostname[MAXHOSTNAMELEN] = '\0';
  290.           host = &!hostname;
  291.           #elif defined(HAVE_SYS_UTSNAME_H)
  292.           if (uname(&utsname) < 0) { return -1; }
  293.           host = &!utsname.nodename;
  294.           #else
  295.           ??
  296.           #endif
  297.         }
  298.       # if numeric host name then try to parse it as such; do the number
  299.       # first because some systems return garbage instead of INVALID_INETADDR
  300.       #define INVALID_INETADDR  ((unsigned long) -1)
  301.       if ((host[0] >= '0') && (host[0] <= '9'))
  302.         { hostinetaddr = inet_addr(host) INET_ADDR_SUFFIX ; }
  303.         else
  304.         { hostinetaddr = INVALID_INETADDR; }
  305.       # try numeric
  306.       if (hostinetaddr == INVALID_INETADDR)
  307.         { var struct hostent * host_ptr; # entry in hosts table
  308.           if ((host_ptr = gethostbyname(host)) == NULL)
  309.             { errno = EINVAL; return -1; } # No such host!
  310.           # Check the address type for an internet host.
  311.           if (host_ptr->h_addrtype != AF_INET)
  312.             { errno = EPROTOTYPE; return -1; } # Not an Internet host!
  313.           # Set up the socket data.
  314.           inaddr.sin_family = host_ptr->h_addrtype;
  315.           inaddr.sin_addr = *(struct in_addr *)host_ptr->h_addr;
  316.         }
  317.         else
  318.         { inaddr.sin_family = AF_INET;
  319.           inaddr.sin_addr.s_addr = hostinetaddr;
  320.         }
  321.  
  322.       inaddr.sin_port = X_TCP_PORT + display;
  323.       inaddr.sin_port = htons(inaddr.sin_port);
  324.       addr = (struct sockaddr *) &inaddr;
  325.       addrlen = sizeof(struct sockaddr_in);
  326.  
  327.       # Open the network connection.
  328.       do { if ((fd = socket ((int) addr->sa_family, SOCK_STREAM, 0)) < 0)
  329.              { return -1; }
  330.            #ifdef TCP_NODELAY
  331.            # turn off TCP coalescence
  332.            { int tmp = 1;
  333.              setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &tmp, sizeof(int));
  334.            }
  335.            #endif
  336.            # Connect to the socket.
  337.            # If there is no X server or if the backlog has been reached,
  338.            # then ECONNREFUSED will be returned.
  339.            if (connect (fd, addr, addrlen) >= 0)
  340.              break;
  341.            { int olderrno = errno; CLOSE(fd); errno = olderrno; }
  342.            if (!(
  343.                  #ifdef ECONNREFUSED
  344.                  (errno == ECONNREFUSED) && 
  345.                  #endif
  346.                  (retries > 0)))
  347.              { return -1; }
  348.            sleep (1);
  349.          }
  350.          while (retries-- > 0);
  351.     }
  352.   else
  353.   #endif
  354.  
  355.   # (conntype == conn_none)
  356.     { errno = ENOSYS; return -1; }
  357.  
  358.   # Set close-on-exec so that we won't get confused if we fork().
  359.   fcntl(fd,F_SETFD,FD_CLOEXEC);
  360.  
  361.   return fd;
  362. }
  363.  
  364. #endif # HAVE_GETHOSTBYNAME
  365.  
  366. #if defined(SOCKET_STREAMS)
  367.  
  368. # Creation of sockets on the server side:
  369. # int socket_handle = create_server_socket(port);
  370. #   creates a socket to which other processes can connect.
  371. # int fd = accept_connection(socket_handle);
  372. #   waits for a connection to another process.
  373. #   This can (and should) be done multiple times for the same
  374. #   socket_handle.
  375.  
  376. global int create_server_socket (int port);
  377. global int create_server_socket(port)
  378.   var int port;
  379.   {
  380.     var struct sockaddr_in sa ;
  381.     var int s;
  382.  
  383.     if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  384.       return -1;
  385.     bzero((char *) &sa, sizeof(sa)) ;
  386.     sa.sin_family = AF_INET ;
  387.     sa.sin_addr.s_addr = htonl(INADDR_ANY) ;
  388.     sa.sin_port = htons(port) ;
  389.  
  390.     if (bind(s, (struct sockaddr *) &sa, sizeof(sa)) < 0) 
  391.       return -1 ;
  392.  
  393.     if (listen(s, 1) < 0) 
  394.       return -1;
  395.  
  396.     return s ;
  397.   }
  398.  
  399. global int accept_connection (int socket_handle);
  400. global int accept_connection (socket_handle)
  401.   var int socket_handle;
  402.   {
  403.     var struct sockaddr_in sa;
  404.     var int active_socket;
  405.     var int alen;
  406.   
  407.     alen = sizeof(sa);
  408.     return accept(socket_handle,(struct sockaddr *)&sa,&alen);
  409.   }
  410.  
  411. # Creation of sockets on the client side:
  412. # int fd = create_client_socket(hostname,port);
  413. #   creates a connection to a server (which must be waiting
  414. #   on the specified host and port).
  415.  
  416. global int create_client_socket (char *hostname, int port);
  417. global int create_client_socket(hostname,port)
  418.   var char *hostname;
  419.   var int port;
  420.   {
  421.     var struct sockaddr_in sa;
  422.     var struct hostent *hp;
  423.     var int a;
  424.     var int s;
  425.     var long addr;
  426.  
  427.     bzero(&sa, sizeof(sa));
  428.     if ((addr = inet_addr(hostname)) != -1) 
  429.       {
  430.     # is Internet addr in octet notation
  431.     bcopy(&addr, (char *) &sa.sin_addr, sizeof(addr)) ; # set address
  432.     sa.sin_family = AF_INET;
  433.       } 
  434.     else 
  435.       {
  436.     if ((hp = gethostbyname(hostname)) == NULL)
  437.           return -2;
  438.     bcopy(hp->h_addr, (char *) &sa.sin_addr, hp->h_length);
  439.     sa.sin_family = hp->h_addrtype;
  440.       }
  441.  
  442.     sa.sin_port = htons((u_short) port);
  443.  
  444.     if ((s = socket(sa.sin_family, SOCK_STREAM, 0)) < 0)
  445.       return -1;
  446.     if (connect(s, (CONNECT_CONST CONNECT_NAME_T)&sa, sizeof(sa)) < 0)
  447.       { close(s);
  448.     return -1;
  449.       }
  450.     return s;
  451.   }
  452.  
  453. # Auxiliary function:
  454. # port = resolve_service("name_or_number",&name);
  455. # parses the "name_or_number" and returns data about the
  456. # specified TCP service: its name and its port number.
  457.  
  458. local int is_number (char *s);
  459. local int is_number(s)
  460.   var char *s;
  461.   {
  462.     while (*s)
  463.       {
  464.         if (*s < '0' || *s > '9')
  465.           return 0 ;
  466.         s++ ;
  467.       }
  468.     return 1 ;
  469.   }
  470.  
  471. global int resolve_service (char *name_or_number, char **name);
  472. global int resolve_service (name_or_number,name)
  473.   char *name_or_number ;
  474.   char **name ;
  475.   {
  476.     struct servent *servent ;
  477.     int port;
  478.     extern int atoi();
  479.  
  480.     if (is_number(name_or_number)) 
  481.       {    port = atoi(name_or_number);
  482.     if (name != NULL) 
  483.           { servent = getservbyport(htons(port), "tcp");
  484.         if (servent != NULL)
  485.           *name = servent->s_name;
  486.         else
  487.           *name = NULL;
  488.           }
  489.     return port;
  490.       }
  491.     else
  492.       {
  493.     servent = getservbyname(name_or_number, "tcp");
  494.     if (servent == NULL) 
  495.           return -1;
  496.     if (name != NULL)
  497.           *name = servent->s_name;
  498.     return ntohs(servent->s_port);
  499.       }
  500.   }
  501.  
  502. # Auxiliary function:
  503. # socket_getpeername(fd)
  504. # returns the name of the host to which IP socket fd is connected.
  505. # Return value: A pointer to a statically allocated string!
  506.  
  507. global char *socket_getpeername (int socket_handle);
  508. global char *socket_getpeername(socket_handle)
  509.   var int socket_handle;
  510.   {
  511.     var struct hostent *hostent; 
  512.     var struct sockaddr_in addr_in;
  513.     var int len=sizeof(addr_in);
  514.     var long norder;
  515.  
  516.     # Get host's IP address.
  517.     if (getpeername(socket_handle,&addr_in,&len) == -1) return NULL;
  518.     norder = htonl(addr_in.sin_addr.s_addr) ;
  519.  
  520.     # Convert it to an ASCII host name.
  521.     hostent=gethostbyaddr(&norder,sizeof(norder),AF_INET);
  522.     if (hostent == NULL) 
  523.       {
  524.         static char dotted[20] ;
  525.         sprintf(dotted, "%d.%d.%d.%d",
  526.                 (norder >> 24) & 0xff,
  527.                 (norder >> 16) & 0xff,
  528.                 (norder >>  8) & 0xff,
  529.                 norder & 0xff) ;
  530.         return dotted;
  531.       }
  532.     return hostent->h_name;
  533.   }
  534.  
  535. #endif # SOCKET_STREAMS
  536.