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