home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnusrvr2.zip / gnuslib.c < prev    next >
C/C++ Source or Header  |  1997-05-13  |  12KB  |  414 lines

  1. /* -*-C-*-
  2.  Common library code for the GNU Emacs server and client.
  3.  
  4.  This file is part of GNU Emacs.
  5.  
  6.  Copying is permitted under those conditions described by the GNU
  7.  General Public License.
  8.  
  9.  Copyright (C) 1989 Free Software Foundation, Inc.
  10.  
  11.  Author: Andy Norman (ange@hplb.hpl.hp.com), based on 
  12.          'etc/server.c' and 'etc/emacsclient.c' from the 18.52 GNU
  13.          Emacs distribution.
  14.  
  15.  Please mail bugs and suggestions to the author at the above address.
  16. */
  17.  
  18. /* HISTORY 
  19.  * 11-Nov-1990        bristor@simba    
  20.  *    Added EOT stuff.
  21.  */
  22.  
  23. /*
  24.  * This file incorporates new features added by Bob Weiner <weiner@mot.com>,
  25.  * Darrell Kindred <dkindred@cmu.edu> and Arup Mukherjee <arup@cmu.edu>.
  26.  * Please see the note at the end of the README file for details.
  27.  *
  28.  * (If gnuserv came bundled with your emacs, the README file is probably
  29.  * ../etc/gnuserv.README relative to the directory containing this file)
  30.  */
  31.  
  32. static char rcsid [] = "$Header: gnuslib.c,v 2.4 95/02/16 11:57:37 arup alpha $";
  33.  
  34. #include "gnuserv.h"
  35.  
  36. #ifdef SYSV_IPC
  37. static int connect_to_ipc_server();
  38. #endif
  39. #ifdef UNIX_DOMAIN_SOCKETS
  40. static int connect_to_unix_server();
  41. #endif
  42. #ifdef INTERNET_DOMAIN_SOCKETS
  43. static int connect_to_internet_server();
  44. #endif
  45.  
  46. /* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */
  47. #ifdef HAVE_BROKEN_INET_ADDR
  48. # define IN_ADDR struct in_addr
  49. # define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1)
  50. #else
  51. # if (LONGBITS > 32)
  52. #  define IN_ADDR unsigned int
  53. # else
  54. #  define IN_ADDR unsigned long
  55. # endif
  56. # define NUMERIC_ADDR_ERROR (numeric_addr == (IN_ADDR) -1)
  57. #endif
  58.  
  59. char *progname = NULL;
  60.  
  61. int make_connection(hostarg, portarg, s)
  62.      char *hostarg;
  63.      int portarg;
  64.      int *s;
  65. {
  66. #ifdef INTERNET_DOMAIN_SOCKETS
  67.   char localhost[HOSTNAMSZ];
  68.   char *ptr;
  69.   if (hostarg == NULL)
  70.     hostarg = getenv("GNU_HOST");
  71.   if (portarg == 0 && (ptr=getenv("GNU_PORT")) != NULL)
  72.     portarg = atoi(ptr);
  73. #endif
  74.  
  75.   if (hostarg != NULL) {
  76.     /* hostname was given explicitly, via cmd line arg or GNU_HOST, 
  77.      * so obey it. */
  78. #ifdef UNIX_DOMAIN_SOCKETS
  79.     if (!strcmp(hostarg, "unix")) {
  80.       *s = connect_to_unix_server();
  81.       return (int) CONN_UNIX;
  82.     } 
  83. #endif /* UNIX_DOMAIN_SOCKETS */
  84. #ifdef INTERNET_DOMAIN_SOCKETS
  85.     *s = connect_to_internet_server(hostarg, portarg);
  86.     return (int) CONN_INTERNET;
  87. #endif
  88. #ifdef SYSV_IPC
  89.     return -1;              /* hostarg should always be NULL for SYSV_IPC */
  90. #endif
  91.   } else {
  92.     /* no hostname given.  Use unix-domain/sysv-ipc, or
  93.      * internet-domain connection to local host if they're not available. */
  94. #ifdef UNIX_DOMAIN_SOCKETS
  95.     *s = connect_to_unix_server();
  96.     return (int) CONN_UNIX;
  97. #endif
  98. #ifdef SYSV_IPC
  99.     *s = connect_to_ipc_server();
  100.     return (int) CONN_IPC;
  101. #endif
  102. #ifdef INTERNET_DOMAIN_SOCKETS
  103.     gethostname(localhost,HOSTNAMSZ);      /* use this host by default */    
  104.     *s = connect_to_internet_server(localhost, portarg);
  105.     return (int) CONN_INTERNET;
  106. #endif      
  107.   }
  108. }
  109.  
  110. #ifdef SYSV_IPC
  111. /*
  112.   connect_to_ipc_server -- establish connection with server process via SYSV IPC
  113.                  Returns msqid for server if successful.
  114. */
  115. static int connect_to_ipc_server()
  116. {
  117.   int s;            /* connected msqid */
  118.   key_t key;            /* message key */
  119.   char buf[GSERV_BUFSZ+1];        /* buffer for filename */
  120.  
  121.   sprintf(buf,"/tmp/gsrv%d",(int)geteuid());
  122.   creat(buf,0600);
  123.   if ((key = ftok(buf,1)) == -1) {
  124.     perror(progname);
  125.     fprintf(stderr, "%s: unable to get ipc key from %s\n",
  126.         progname, buf);
  127.     exit(1);
  128.   }
  129.  
  130.   if ((s = msgget(key,0600)) == -1) {
  131.     perror(progname);
  132.     fprintf(stderr,"%s: unable to access msg queue\n",progname);
  133.     exit(1);
  134.   }; /* if */
  135.  
  136.   return(s);
  137.  
  138. } /* connect_to_ipc_server */
  139.  
  140.  
  141. /*
  142.   disconnect_from_ipc_server -- inform the server that sending has finished,
  143.                                 and wait for its reply.
  144. */
  145. void disconnect_from_ipc_server(s,msgp,echo)
  146.      int s;
  147.      struct msgbuf *msgp;
  148.      int echo;
  149. {
  150.   int len;            /* length of received message */
  151.  
  152.   send_string(s,EOT_STR);    /* EOT terminates this message */
  153.   msgp->mtype = 1;
  154.  
  155.   if(msgsnd(s,msgp,strlen(msgp->mtext)+1,0) < 0) {
  156.     perror(progname);
  157.     fprintf(stderr,"%s: unable to send message to server\n",progname);
  158.     exit(1);
  159.   }; /* if */
  160.   
  161.   if((len = msgrcv(s,msgp,GSERV_BUFSZ,getpid(),0)) < 0) {
  162.     perror(progname);
  163.     fprintf(stderr,"%s: unable to receive message from server\n",progname);
  164.     exit(1);
  165.   }; /* if */
  166.  
  167.   if (echo) {
  168.     msgp->mtext[len] = '\0';    /* string terminate message */
  169.     fputs(msgp->mtext, stdout);
  170.     if (msgp->mtext[len-1] != '\n') putchar ('\n');
  171.   }; /* if */
  172.  
  173. } /* disconnect_from_ipc_server */  
  174. #endif /* SYSV_IPC */
  175.  
  176.  
  177. #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
  178. /*
  179.   send_string -- send string to socket.
  180. */
  181. void send_string(s,msg)
  182.      int s;
  183.      char *msg;
  184. {
  185. #if 0
  186.   if (send(s,msg,strlen(msg),0) < 0) {
  187.     perror(progname);
  188.     fprintf(stderr,"%s: unable to send\n",progname);
  189.     exit(1);
  190.   }; /* if */ 
  191. #else  
  192.   int len, left=strlen(msg);
  193.   while (left > 0) {
  194.     if ((len=write(s,msg,min2(left,GSERV_BUFSZ))) < 0) {
  195.       perror(progname);
  196.       fprintf(stderr,"%s: unable to send\n",progname);
  197.       exit(1);
  198.     }; /* if */
  199.     left -= len;
  200.     msg += len;
  201.   }; /* while */ 
  202. #endif
  203. } /* send_string */
  204. #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */
  205.  
  206.  
  207. #ifdef UNIX_DOMAIN_SOCKETS
  208. /*
  209.   connect_to_unix_server -- establish connection with server process via a unix-
  210.                   domain socket. Returns socket descriptor for server
  211.                 if successful.
  212. */
  213. static int connect_to_unix_server()
  214. {
  215.   int s;            /* connected socket descriptor */
  216.   struct sockaddr_un server;     /* for unix connections */
  217.  
  218.   if ((s = socket(AF_UNIX,SOCK_STREAM,0)) < 0) {
  219.     perror(progname);
  220.     fprintf(stderr,"%s: unable to create socket\n",progname);
  221.     exit(1);
  222.   }; /* if */
  223.   
  224.   server.sun_family = AF_UNIX;
  225. #ifdef HIDE_UNIX_SOCKET
  226.   sprintf(server.sun_path,"/tmp/gsrvdir%d/gsrv",(int)geteuid());
  227. #else  /* HIDE_UNIX_SOCKET */
  228.   sprintf(server.sun_path,"/tmp/gsrv%d",(int)geteuid());
  229. #endif /* HIDE_UNIX_SOCKET */
  230.   if (connect(s,(struct sockaddr *)&server,strlen(server.sun_path)+2) < 0) {
  231.     perror(progname);
  232.     fprintf(stderr,"%s: unable to connect to local\n",progname);
  233.     exit(1);
  234.   }; /* if */
  235.  
  236.   return(s);
  237.  
  238. } /* connect_to_unix_server */
  239. #endif /* UNIX_DOMAIN_SOCKETS */
  240.  
  241.  
  242. #ifdef INTERNET_DOMAIN_SOCKETS
  243. /*
  244.   internet_addr -- return the internet addr of the hostname or
  245.                    internet address passed. Return -1 on error.
  246. */
  247. int internet_addr(host)
  248.      char *host;
  249. {
  250.   struct hostent *hp;        /* pointer to host info for remote host */
  251.   IN_ADDR numeric_addr;        /* host address */
  252.  
  253.   numeric_addr = inet_addr(host);
  254.   if (!NUMERIC_ADDR_ERROR)
  255.     return numeric_addr;
  256.   else if ((hp = gethostbyname(host)) != NULL)
  257.     return ((struct in_addr *)(hp->h_addr))->s_addr;
  258.   else
  259.     return -1;
  260.  
  261. } /* internet_addr */
  262.  
  263. #ifdef AUTH_MAGIC_COOKIE
  264. # include <X11/X.h>
  265. # include <X11/Xauth.h>
  266.  
  267. static Xauth *server_xauth = NULL;
  268. #endif
  269.  
  270. /*
  271.   connect_to_internet_server -- establish connection with server process via 
  272.                   an internet domain socket. Returns socket
  273.                 descriptor for server if successful.
  274. */
  275. static int connect_to_internet_server(serverhost,port)
  276.      char *serverhost;
  277.      u_short port;
  278. {
  279.   int s;                /* connected socket descriptor */
  280.   struct servent *sp;            /* pointer to service information */
  281.   struct sockaddr_in peeraddr_in;    /* for peer socket address */
  282.   char buf[512];                        /* temporary buffer */
  283.  
  284.   /* clear out address structures */
  285.   bzero((char *)&peeraddr_in,sizeof(struct sockaddr_in));
  286.   
  287.   /* Set up the peer address to which we will connect. */
  288.   peeraddr_in.sin_family = AF_INET;
  289.  
  290.   /* look up the server host's internet address */
  291.   if ((peeraddr_in.sin_addr.s_addr = internet_addr(serverhost)) == -1) {
  292.     fprintf(stderr,"%s: unable to find %s in /etc/hosts or from YP\n",
  293.         progname,serverhost);
  294.     exit(1);
  295.   }; /* if */
  296.   
  297.   if (port == 0) {
  298.     if ((sp = getservbyname ("gnuserv","tcp")) == NULL)
  299.       peeraddr_in.sin_port = htons(DEFAULT_PORT+getuid());
  300.     else
  301.       peeraddr_in.sin_port = sp->s_port;
  302.   } /* if */
  303.   else
  304.     peeraddr_in.sin_port = htons(port);
  305.   
  306.   /* Create the socket. */
  307.   if ((s = socket (AF_INET,SOCK_STREAM, 0))== -1) {
  308.     perror(progname);
  309.     fprintf(stderr,"%s: unable to create socket\n",progname);
  310.     exit(1);
  311.   }; /* if */
  312.   
  313.   /* Try to connect to the remote server at the address
  314.    * which was just built into peeraddr.
  315.    */
  316.   if (connect(s, (struct sockaddr *)&peeraddr_in,
  317.           sizeof(struct sockaddr_in)) == -1) {
  318.     perror(progname);
  319.     fprintf(stderr, "%s: unable to connect to remote\n",progname);
  320.     exit(1);
  321.   }; /* if */
  322.  
  323. #ifdef AUTH_MAGIC_COOKIE
  324.  
  325.   /* send credentials using MIT-MAGIC-COOKIE-1 protocol */
  326.   
  327.   server_xauth = 
  328.     XauGetAuthByAddr(FamilyInternet, 
  329.              sizeof(peeraddr_in.sin_addr.s_addr), 
  330.              (char *) &peeraddr_in.sin_addr.s_addr,
  331.              strlen(MCOOKIE_SCREEN), MCOOKIE_SCREEN,
  332.              strlen(MCOOKIE_X_NAME), MCOOKIE_X_NAME);
  333.  
  334.   if (server_xauth && server_xauth->data) {
  335.     sprintf(buf, "%s\n%d\n", MCOOKIE_NAME, server_xauth->data_length);
  336.     write (s, buf, strlen(buf));
  337.     write (s, server_xauth->data, server_xauth->data_length);
  338.  
  339.     return (s);
  340.   }
  341.  
  342. #endif /* AUTH_MAGIC_COOKIE */
  343.  
  344.   sprintf (buf, "%s\n", DEFAUTH_NAME);
  345.   write (s, buf, strlen(buf));
  346.  
  347.   return(s);
  348.  
  349. } /* connect_to_internet_server */
  350. #endif /* INTERNET_DOMAIN_SOCKETS */
  351.  
  352.  
  353. #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
  354. /*
  355.   disconnect_from_server -- inform the server that sending has finished, and wait for
  356.                             its reply.
  357. */
  358. void disconnect_from_server(s,echo)
  359.      int s;
  360.      int echo;
  361. {
  362. #if 0
  363.   char buffer[REPLYSIZ+1];
  364. #else
  365.   char buffer[GSERV_BUFSZ+1];
  366. #endif
  367.   int add_newline = 1;
  368.   int length;
  369.  
  370.   send_string(s,EOT_STR);        /* make sure server gets string */
  371.  
  372. #ifndef linux
  373.   /*
  374.    * shutdown is completely hozed under linux. If s is a unix domain socket,
  375.    * you'll get EOPNOTSUPP back from it. If s is an internet socket, you get
  376.    * a broken pipe when you try to read a bit later. The latter
  377.    * problem is fixed for linux versions >= 1.1.46, but the problem
  378.    * with unix sockets persists. Sigh.
  379.    */
  380.  
  381.   if (shutdown(s,1) == -1) {
  382.      perror(progname);
  383.      fprintf(stderr, "%s: unable to shutdown socket\n",progname);
  384.      exit(1);
  385.   }; /* if */
  386. #endif
  387.  
  388. #if 0
  389.   while((length = recv(s,buffer,REPLYSIZ,0)) > 0) {
  390.     buffer[length] = '\0';
  391.     if (echo) fputs(buffer,stdout);
  392.     add_newline = (buffer[length-1] != '\n');
  393.   }; /* while */
  394. #else
  395.   while ((length = read(s,buffer,GSERV_BUFSZ)) > 0) {
  396.     buffer[length] = '\0';
  397.     if (echo) {
  398.       fputs(buffer,stdout);
  399.       add_newline = (buffer[length-1] != '\n');
  400.     }; /* if */
  401.   }; /* while */
  402. #endif
  403.   
  404.   if (echo && add_newline) putchar('\n');
  405.  
  406.   if(length < 0) {
  407.     perror(progname);
  408.     fprintf(stderr,"%s: unable to read the reply from the server\n",progname);
  409.     exit(1);
  410.   }; /* if */
  411.  
  412. } /* disconnect_from_server */  
  413. #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */
  414.