Blame sysdeps/common/gnuslib.c

Packit d37888
/* -*-C-*-
Packit d37888
 * Common library code for the GNU Emacs server and client.
Packit d37888
 *
Packit d37888
 * This file is part of GNU Emacs.
Packit d37888
 *
Packit d37888
 * Copying is permitted under those conditions described by the GNU
Packit d37888
 * General Public License.
Packit d37888
 *
Packit d37888
 * Copyright (C) 1989 Free Software Foundation, Inc.
Packit d37888
 *
Packit d37888
 * Author: Andy Norman (ange@hplb.hpl.hp.com), based on
Packit d37888
 * 'etc/server.c' and 'etc/emacsclient.c' from the 18.52 GNU
Packit d37888
 * Emacs distribution.
Packit d37888
 *
Packit d37888
 * Please mail bugs and suggestions to the author at the above address.
Packit d37888
 */
Packit d37888
Packit d37888
/* HISTORY
Packit d37888
 * 11-Nov-1990                bristor@simba
Packit d37888
 *    Added EOT stuff.
Packit d37888
 */
Packit d37888
Packit d37888
/*
Packit d37888
 * This file incorporates new features added by Bob Weiner <weiner@mot.com>,
Packit d37888
 * Darrell Kindred <dkindred@cmu.edu> and Arup Mukherjee <arup@cmu.edu>.
Packit d37888
 * Please see the note at the end of the README file for details.
Packit d37888
 *
Packit d37888
 * (If gnuserv came bundled with your emacs, the README file is probably
Packit d37888
 * ../etc/gnuserv.README relative to the directory containing this file)
Packit d37888
 */
Packit d37888
Packit d37888
#include <config.h>
Packit d37888
#include <glibtop.h>
Packit d37888
#include <glibtop/error.h>
Packit d37888
#include <glibtop/gnuserv.h>
Packit d37888
Packit d37888
#include <fcntl.h>
Packit d37888
Packit d37888
#ifdef UNIX_DOMAIN_SOCKETS
Packit d37888
static int connect_to_unix_server (void);
Packit d37888
#endif
Packit d37888
Packit d37888
#ifdef INTERNET_DOMAIN_SOCKETS
Packit d37888
static int connect_to_internet_server (const char *serverhost, u_short port);
Packit d37888
#endif
Packit d37888
Packit d37888
/* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */
Packit d37888
#ifdef HAVE_BROKEN_INET_ADDR
Packit d37888
#define IN_ADDR struct in_addr
Packit d37888
#define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == 0xffffffff)
Packit d37888
#else
Packit d37888
#if (LONGBITS > 32)
Packit d37888
#define IN_ADDR unsigned int
Packit d37888
#else
Packit d37888
#define IN_ADDR unsigned long
Packit d37888
#endif
Packit d37888
#define NUMERIC_ADDR_ERROR (numeric_addr == (IN_ADDR) 0xffffffff)
Packit d37888
#endif
Packit d37888
Packit d37888
#include <arpa/inet.h>
Packit d37888
Packit d37888
int
Packit d37888
glibtop_make_connection (const char *hostarg, int portarg, int *s)
Packit d37888
{
Packit d37888
#ifdef INTERNET_DOMAIN_SOCKETS
Packit d37888
	char *ptr;
Packit d37888
Packit d37888
	if (hostarg == NULL)
Packit d37888
		hostarg = getenv ("LIBGTOP_HOST");
Packit d37888
	if (portarg == 0 && (ptr = getenv ("LIBGTOP_PORT")) != NULL)
Packit d37888
		portarg = atoi (ptr);
Packit d37888
#endif
Packit d37888
Packit d37888
	if (hostarg != NULL) {
Packit d37888
		/* hostname was given explicitly, via cmd line arg or
Packit d37888
		 * LIBGTOP_HOST,  * so obey it. */
Packit d37888
#ifdef UNIX_DOMAIN_SOCKETS
Packit d37888
		if (!strcmp (hostarg, "unix")) {
Packit d37888
			*s = connect_to_unix_server ();
Packit d37888
			return (int) CONN_UNIX;
Packit d37888
		}
Packit d37888
#endif /* UNIX_DOMAIN_SOCKETS */
Packit d37888
#ifdef INTERNET_DOMAIN_SOCKETS
Packit d37888
		*s = connect_to_internet_server (hostarg, portarg);
Packit d37888
		return (int) CONN_INTERNET;
Packit d37888
#endif
Packit d37888
	} else {
Packit d37888
		/* no hostname given.  Use unix-domain/sysv-ipc, or *
Packit d37888
		 * internet-domain connection to local host if they're not
Packit d37888
		 * available. */
Packit d37888
#if   defined(UNIX_DOMAIN_SOCKETS)
Packit d37888
		*s = connect_to_unix_server ();
Packit d37888
		return (int) CONN_UNIX;
Packit d37888
#elif defined(INTERNET_DOMAIN_SOCKETS)
Packit d37888
		{
Packit d37888
			char localhost[HOSTNAMSZ];
Packit d37888
Packit d37888
			gethostname (localhost, HOSTNAMSZ);	/* use this
Packit d37888
								 * host by
Packit d37888
								 * default */
Packit d37888
			*s = connect_to_internet_server (localhost, portarg);
Packit d37888
			return (int) CONN_INTERNET;
Packit d37888
		}
Packit d37888
#endif /* IPC type */
Packit d37888
	}
Packit d37888
}
Packit d37888
Packit d37888
#if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
Packit d37888
/*
Packit d37888
 * send_string -- send string to socket.
Packit d37888
 */
Packit d37888
#if 0
Packit d37888
static void
Packit d37888
send_string (s, msg)
Packit d37888
     int s;
Packit d37888
     const char *msg;
Packit d37888
{
Packit d37888
#if 0
Packit d37888
	if (send (s, msg, strlen (msg), 0) < 0) {
Packit d37888
		perror (progname);
Packit d37888
		fprintf (stderr, "%s: unable to send\n", progname);
Packit d37888
		exit (1);
Packit d37888
	};			/* if */
Packit d37888
#else
Packit d37888
	int len, left = strlen (msg);
Packit d37888
Packit d37888
	while (left > 0) {
Packit d37888
		if ((len = write (s, msg, min2 (left, GSERV_BUFSZ))) < 0) {
Packit d37888
			/* XEmacs addition: robertl@arnet.com */
Packit d37888
			if (errno == EPIPE) {
Packit d37888
				return;
Packit d37888
			}
Packit d37888
			perror (progname);
Packit d37888
			fprintf (stderr, "%s: unable to send\n", progname);
Packit d37888
			exit (1);
Packit d37888
		};		/* if */
Packit d37888
		left -= len;
Packit d37888
		msg += len;
Packit d37888
	};			/* while */
Packit d37888
#endif
Packit d37888
}				/* send_string */
Packit d37888
Packit d37888
/*
Packit d37888
 * read_line -- read a \n terminated line from a socket
Packit d37888
 */
Packit d37888
static int
Packit d37888
read_line (int s, char *dest)
Packit d37888
{
Packit d37888
	int length;
Packit d37888
	int offset = 0;
Packit d37888
	char buffer[GSERV_BUFSZ + 1];
Packit d37888
Packit d37888
	while ((length = read (s, buffer + offset, 1) > 0) && buffer[offset] != '\n'
Packit d37888
	       && buffer[offset] != EOT_CHR) {
Packit d37888
		offset += length;
Packit d37888
		if (offset >= GSERV_BUFSZ)
Packit d37888
			break;
Packit d37888
	}
Packit d37888
	buffer[offset] = '\0';
Packit d37888
	strcpy (dest, buffer);
Packit d37888
	return 1;
Packit d37888
}				/* read_line */
Packit d37888
#endif
Packit d37888
#endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */
Packit d37888
Packit d37888
Packit d37888
#ifdef UNIX_DOMAIN_SOCKETS
Packit d37888
/*
Packit d37888
 * connect_to_unix_server -- establish connection with server process via a unix-
Packit d37888
 * domain socket. Returns socket descriptor for server
Packit d37888
 * if successful.
Packit d37888
 */
Packit d37888
static int
Packit d37888
connect_to_unix_server (void)
Packit d37888
{
Packit d37888
	int s;			/* connected socket descriptor */
Packit d37888
	struct sockaddr_un server;	/* for unix connections */
Packit d37888
Packit d37888
	if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
Packit d37888
		glibtop_error_io ("unable to create socket");
Packit d37888
Packit d37888
	server.sun_family = AF_UNIX;
Packit d37888
#ifdef HIDE_UNIX_SOCKET
Packit d37888
	sprintf (server.sun_path, "/tmp/lgtddir%d/lgtd", (int) geteuid ());
Packit d37888
#else /* HIDE_UNIX_SOCKET */
Packit d37888
	sprintf (server.sun_path, "/tmp/lgtd%d", (int) geteuid ());
Packit d37888
#endif /* HIDE_UNIX_SOCKET */
Packit d37888
	if (connect (s, (struct sockaddr *)&server, strlen (server.sun_path) + 2) < 0)
Packit d37888
		glibtop_error_io ("unable to connect to local");
Packit d37888
Packit d37888
	return (s);
Packit d37888
Packit d37888
}				/* connect_to_unix_server */
Packit d37888
#endif /* UNIX_DOMAIN_SOCKETS */
Packit d37888
Packit d37888
Packit d37888
#ifdef INTERNET_DOMAIN_SOCKETS
Packit d37888
/*
Packit d37888
 * internet_addr -- return the internet addr of the hostname or
Packit d37888
 * internet address passed. Return -1 on error.
Packit d37888
 */
Packit d37888
long
Packit d37888
glibtop_internet_addr (const char *host)
Packit d37888
{
Packit d37888
	struct hostent *hp;	/* pointer to host info for remote host */
Packit d37888
	IN_ADDR numeric_addr;	/* host address */
Packit d37888
Packit d37888
	numeric_addr = inet_addr (host);
Packit d37888
	if (!NUMERIC_ADDR_ERROR)
Packit d37888
		return numeric_addr;
Packit d37888
	else if ((hp = gethostbyname (host)) != NULL)
Packit d37888
		return ((struct in_addr *) (hp->h_addr))->s_addr;
Packit d37888
	else {
Packit d37888
		glibtop_warn_io ("gethostbyname (%s)", host);
Packit d37888
		return -1;
Packit d37888
	}
Packit d37888
Packit d37888
}				/* glibtop_internet_addr  */
Packit d37888
Packit d37888
#ifdef AUTH_MAGIC_COOKIE
Packit d37888
#include <X11/X.h>
Packit d37888
#include <X11/Xauth.h>
Packit d37888
Packit d37888
static Xauth *server_xauth = NULL;
Packit d37888
Packit d37888
#endif
Packit d37888
Packit d37888
/*
Packit d37888
 * connect_to_internet_server -- establish connection with server process via
Packit d37888
 * an internet domain socket. Returns socket
Packit d37888
 * descriptor for server if successful.
Packit d37888
 */
Packit d37888
static int
Packit d37888
connect_to_internet_server (const char *serverhost, u_short port)
Packit d37888
{
Packit d37888
	int s;			/* connected socket descriptor */
Packit d37888
	struct servent *sp;	/* pointer to service information */
Packit d37888
	struct sockaddr_in peeraddr_in;		/* for peer socket address */
Packit d37888
	char buf[512];		/* temporary buffer */
Packit d37888
Packit d37888
	/* clear out address structures */
Packit d37888
	memset (&peeraddr_in, 0, sizeof (struct sockaddr_in));
Packit d37888
Packit d37888
	/* Set up the peer address to which we will connect. */
Packit d37888
	peeraddr_in.sin_family = AF_INET;
Packit d37888
Packit d37888
	/* look up the server host's internet address */
Packit d37888
	peeraddr_in.sin_addr.s_addr = glibtop_internet_addr (serverhost);
Packit d37888
	if ((long) peeraddr_in.sin_addr.s_addr == -1)
Packit d37888
		glibtop_error ("unable to find %s in /etc/hosts or from YP", serverhost);
Packit d37888
Packit d37888
	if (port == 0) {
Packit d37888
		if ((sp = getservbyname ("gtopd", "tcp")) == NULL)
Packit d37888
			peeraddr_in.sin_port = htons (DEFAULT_PORT + getuid ());
Packit d37888
		else
Packit d37888
			peeraddr_in.sin_port = sp->s_port;
Packit d37888
	}
Packit d37888
	/* if */
Packit d37888
	else
Packit d37888
		peeraddr_in.sin_port = htons (port);
Packit d37888
Packit d37888
	/* Create the socket. */
Packit d37888
	if ((s = socket (AF_INET, SOCK_STREAM, 0)) == -1)
Packit d37888
		glibtop_error_io ("unable to create socket");
Packit d37888
Packit d37888
	/* Try to connect to the remote server at the address * which was
Packit d37888
	 * just built into peeraddr. */
Packit d37888
	if (connect (s, (struct sockaddr *) &peeraddr_in,
Packit d37888
		     sizeof (struct sockaddr_in)) == -1)
Packit d37888
		  glibtop_error_io ("unable to connect to remote");
Packit d37888
Packit d37888
#ifdef AUTH_MAGIC_COOKIE
Packit d37888
Packit d37888
	/* send credentials using MIT-MAGIC-COOKIE-1 protocol */
Packit d37888
Packit d37888
	sprintf (buf, "%d", port);
Packit d37888
Packit d37888
	server_xauth =
Packit d37888
		XauGetAuthByAddr (FamilyInternet,
Packit d37888
				  sizeof (peeraddr_in.sin_addr.s_addr),
Packit d37888
				  (char *) &peeraddr_in.sin_addr.s_addr,
Packit d37888
				  strlen (buf), buf,
Packit d37888
				  strlen (MCOOKIE_X_NAME), MCOOKIE_X_NAME);
Packit d37888
Packit d37888
	if (server_xauth && server_xauth->data) {
Packit d37888
		sprintf (buf, "%s\n%d\n", MCOOKIE_NAME, server_xauth->data_length);
Packit d37888
		write (s, buf, strlen (buf));
Packit d37888
		write (s, server_xauth->data, server_xauth->data_length);
Packit d37888
Packit d37888
		return (s);
Packit d37888
	}
Packit d37888
#endif /* AUTH_MAGIC_COOKIE */
Packit d37888
Packit d37888
	sprintf (buf, "%s\n", DEFAUTH_NAME);
Packit d37888
	write (s, buf, strlen (buf));
Packit d37888
Packit d37888
	return (s);
Packit d37888
Packit d37888
}				/* connect_to_internet_server */
Packit d37888
#endif /* INTERNET_DOMAIN_SOCKETS */
Packit d37888
Packit d37888
Packit d37888
#if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS)
Packit d37888
/*
Packit d37888
 * disconnect_from_server -- inform the server that sending has finished, and wait for
Packit d37888
 * its reply.
Packit d37888
 */
Packit d37888
#if 0
Packit d37888
static void
Packit d37888
disconnect_from_server (s, echo)
Packit d37888
     int s;
Packit d37888
     int echo;
Packit d37888
{
Packit d37888
#if 0
Packit d37888
	char buffer[REPLYSIZ + 1];
Packit d37888
Packit d37888
#else
Packit d37888
	char buffer[GSERV_BUFSZ + 1];
Packit d37888
Packit d37888
#endif
Packit d37888
	int add_newline = 1;
Packit d37888
	int length;
Packit d37888
Packit d37888
	send_string (s, EOT_STR);	/* make sure server gets string */
Packit d37888
Packit d37888
#if !defined (linux)  && !defined (_SCO_DS)
Packit d37888
	/*
Packit d37888
	 * shutdown is completely hozed under linux. If s is a unix domain socket,
Packit d37888
	 * you'll get EOPNOTSUPP back from it. If s is an internet socket, you get
Packit d37888
	 * a broken pipe when you try to read a bit later. The latter
Packit d37888
	 * problem is fixed for linux versions >= 1.1.46, but the problem
Packit d37888
	 * with unix sockets persists. Sigh.
Packit d37888
	 */
Packit d37888
Packit d37888
	if (shutdown (s, 1) == -1) {
Packit d37888
		perror (progname);
Packit d37888
		fprintf (stderr, "%s: unable to shutdown socket\n", progname);
Packit d37888
		exit (1);
Packit d37888
	};			/* if */
Packit d37888
#endif
Packit d37888
Packit d37888
#if 0
Packit d37888
	while ((length = recv (s, buffer, REPLYSIZ, 0)) > 0) {
Packit d37888
		buffer[length] = '\0';
Packit d37888
		if (echo)
Packit d37888
			fputs (buffer, stdout);
Packit d37888
		add_newline = (buffer[length - 1] != '\n');
Packit d37888
	};			/* while */
Packit d37888
#else
Packit d37888
	while ((length = read (s, buffer, GSERV_BUFSZ)) > 0 ||
Packit d37888
	       (length == -1 && errno == EINTR)) {
Packit d37888
		if (length) {
Packit d37888
			buffer[length] = '\0';
Packit d37888
			if (echo) {
Packit d37888
				fputs (buffer, stdout);
Packit d37888
				add_newline = (buffer[length - 1] != '\n');
Packit d37888
			};	/* if */
Packit d37888
		};		/* if */
Packit d37888
	};			/* while */
Packit d37888
#endif
Packit d37888
Packit d37888
	if (echo && add_newline)
Packit d37888
		putchar ('\n');
Packit d37888
Packit d37888
	if (length < 0) {
Packit d37888
		perror (progname);
Packit d37888
		fprintf (stderr, "%s: unable to read the reply from the server\n", progname);
Packit d37888
		exit (1);
Packit d37888
	};			/* if */
Packit d37888
Packit d37888
}				/* disconnect_from_server */
Packit d37888
#endif
Packit d37888
#endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */