📄 xconndis.c
字号:
/* * $XConsortium: XConnDis.c,v 11.88 91/12/17 17:55:57 rws Exp $ * * Copyright 1989 Massachusetts Institute of Technology * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, provided * that the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of M.I.T. not be used in advertising * or publicity pertaining to distribution of the software without specific, * written prior permission. M.I.T. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL M.I.T. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * * This file contains operating system dependencies. */#define NEED_EVENTS#include <X11/Xlibint.h>#include <X11/Xos.h>#include "Xlibnet.h"#include <X11/Xauth.h>#include <stdio.h>#include <ctype.h>#ifdef DNETCONN#include <netdnet/dn.h>#include <netdnet/dnetdb.h>#endif#ifdef STREAMSCONN#define select _XSelect#endif#ifndef X_CONNECTION_RETRIES /* number retries on ECONNREFUSED */#define X_CONNECTION_RETRIES 5#endif#ifdef DNETCONNstatic int MakeDECnetConnection();#endif#ifdef UNIXCONNstatic int MakeUNIXSocketConnection();#endif#ifdef TCPCONNstatic int MakeTCPConnection();#endif#ifdef STREAMSCONNextern int _XMakeStreamsConnection();#endifstatic void GetAuthorization();static char *copystring (src, len) char *src; int len;{ char *dst = Xmalloc (len + 1); if (dst) { strncpy (dst, src, len); dst[len] = '\0'; } return dst;}/* * Attempts to connect to server, given display name. Returns file descriptor * (network socket) or -1 if connection fails. Display names may be of the * following format: * * [hostname] : [:] displaynumber [.screennumber] * * The second colon indicates a DECnet style name. No hostname is interpretted * as the most efficient local connection to a server on the same machine. * This is usually: * * o shared memory * o local stream * o UNIX domain socket * o TCP to local host */int _XConnectDisplay (display_name, fullnamep, dpynump, screenp, auth_namep, auth_namelenp, auth_datap, auth_datalenp) char *display_name; char **fullnamep; /* RETURN */ int *dpynump; /* RETURN */ int *screenp; /* RETURN */ char **auth_namep; /* RETURN */ int *auth_namelenp; /* RETURN */ char **auth_datap; /* RETURN */ int *auth_datalenp; /* RETURN */{ int family; int saddrlen; char *saddr; char *lastp, *p; /* char pointers */ char *phostname = NULL; /* start of host of display */ char *pdpynum = NULL; /* start of dpynum of display */ char *pscrnum = NULL; /* start of screen of display */ Bool dnet = False; /* if true, then DECnet format */ int idisplay; /* required display number */ int iscreen = 0; /* optional screen number */ int (*connfunc)(); /* method to create connection */ int fd = -1; /* file descriptor to return */ int len; /* length tmp variable */ p = display_name; saddrlen = 0; /* set so that we can clear later */ saddr = NULL; /* * Step 1, find the hostname. This is delimited by the required * first colon. */ for (lastp = p; *p && *p != ':'; p++) ; if (!*p) return -1; /* must have a colon */ if (p != lastp) { /* no hostname given */ phostname = copystring (lastp, p - lastp); if (!phostname) goto bad; /* no memory */ } /* * Step 2, see if this is a DECnet address by looking for the optional * second colon. */ if (p[1] == ':') { /* then DECnet format */ dnet = True; p++; } /* * see if we're allowed to have a DECnet address */#ifndef DNETCONN if (dnet) goto bad;#endif /* * Step 3, find the display number. This field is required and is * delimited either by a nul or a period, depending on whether or not * a screen number is present. */ for (lastp = ++p; *p && isascii(*p) && isdigit(*p); p++) ; if ((p == lastp) || /* required field */ (*p != '\0' && *p != '.') || /* invalid non-digit terminator */ !(pdpynum = copystring (lastp, p - lastp))) /* no memory */ goto bad; idisplay = atoi (pdpynum); /* * Step 4, find the screen number. This field is optional. It is * present only if the display number was followed by a period (which * we've already verified is the only non-nul character). */ if (*p) { for (lastp = ++p; *p && isascii(*p) && isdigit (*p); p++) ; if (*p || /* non-digits */ !(pscrnum = copystring (lastp, p - lastp))) /* no memory */ goto bad; iscreen = atoi (lastp); } /* * At this point, we know the following information: * * phostname hostname string or NULL * idisplay display number * iscreen screen number * dnet DECnet boolean * * We can now decide which transport to use based on the ConnectionFlags * build parameter the hostname string. If phostname is NULL or equals * the string "local", then choose the best transport. If phostname * is "unix", then choose BSD UNIX domain sockets (if configured). * * First, choose default transports: DECnet else (TCP or STREAMS) */#ifdef DNETCONN if (dnet) connfunc = MakeDECnetConnection; else#endif#ifdef TCPCONN connfunc = MakeTCPConnection;#else#ifdef STREAMSCONN connfunc = _XMakeStreamsConnection;#else connfunc = NULL;#endif#endif#ifdef UNIXCONN /* * Now that the defaults have been established, see if we have any * special names that we have to override: * * :N => if UNIXCONN then unix-domain-socket * ::N => if UNIXCONN then unix-domain-socket * unix:N => if UNIXCONN then unix-domain-socket * * Note that if UNIXCONN isn't defined, then we can use the default * transport connection function set above. */ if (!phostname) {#ifdef apollo ; /* Unix domain sockets are *really* bad on apollos */#else connfunc = MakeUNIXSocketConnection;#endif } else if (strcmp (phostname, "unix") == 0) { connfunc = MakeUNIXSocketConnection; }#endif if (!connfunc) goto bad;#ifdef UNIXCONN#define LOCALCONNECTION (!phostname || connfunc == MakeUNIXSocketConnection)#else#define LOCALCONNECTION (!phostname)#endif if (LOCALCONNECTION) { /* * Get the auth info for local hosts so that it doesn't have to be * repeated everywhere; the particular values in these fields are * not part of the protocol. */ char hostnamebuf[256]; int len = _XGetHostname (hostnamebuf, sizeof hostnamebuf); family = FamilyLocal; if (len > 0) { saddr = Xmalloc (len + 1); if (saddr) { strcpy (saddr, hostnamebuf); saddrlen = len; } else { saddrlen = 0; } } }#undef LOCALCONNECTION /* * Make the connection, also need to get the auth address info for * non-local connections. Do retries in case server host has hit its * backlog (which, unfortunately, isn't distinguishable from there not * being a server listening at all, which is why we have to not retry * too many times). */ if ((fd = (*connfunc) (phostname, idisplay, X_CONNECTION_RETRIES, &family, &saddrlen, &saddr)) < 0) goto bad; if (fd >= OPEN_MAX) goto bad; /* * Set close-on-exec so that programs that fork() doesn't get confused. */#ifdef FD_CLOEXEC (void) fcntl (fd, F_SETFD, FD_CLOEXEC);#else (void) fcntl (fd, F_SETFD, 1);#endif /* * Build the expanded display name: * * [host] : [:] dpy . scr \0 */ len = ((phostname ? strlen(phostname) : 0) + 1 + (dnet ? 1 : 0) + strlen(pdpynum) + 1 + (pscrnum ? strlen(pscrnum) : 1) + 1); *fullnamep = (char *) Xmalloc (len); if (!*fullnamep) goto bad; sprintf (*fullnamep, "%s%s%d.%d", (phostname ? phostname : ""), (dnet ? "::" : ":"), idisplay, iscreen); *dpynump = idisplay; *screenp = iscreen; if (phostname) Xfree (phostname); if (pdpynum) Xfree (pdpynum); if (pscrnum) Xfree (pscrnum); GetAuthorization(fd, family, saddr, saddrlen, idisplay, auth_namep, auth_namelenp, auth_datap, auth_datalenp); return fd; /* * error return; make sure everything is cleaned up. */ bad: if (fd >= 0) (void) close (fd); if (saddr) Xfree (saddr); if (phostname) Xfree (phostname); if (pdpynum) Xfree (pdpynum); if (pscrnum) Xfree (pscrnum); return -1;}/***************************************************************************** * * * Make Connection Routines * * * *****************************************************************************/#ifdef DNETCONN /* stupid makedepend */#define NEED_BSDISH#endif#ifdef UNIXCONN#define NEED_BSDISH#endif#ifdef TCPCONN#define NEED_BSDISH#endif#ifdef NEED_BSDISH /* makedepend can't handle #if *//* * 4.2bsd-based systems */#include <sys/socket.h>#ifdef hpux#define NO_TCP_H#endif#ifdef MOTOROLA#ifdef SYSV#define NO_TCP_H#endif#endif#ifndef NO_TCP_H#ifdef __OSF1__#include <sys/param.h>#endif#include <netinet/tcp.h>#endif#endif /* NEED_BSDISH */#ifdef DNETCONNstatic int MakeDECnetConnection (phostname, idisplay, retries, familyp, saddrlenp, saddrp) char *phostname; int idisplay; int retries; int *familyp; /* RETURN */ int *saddrlenp; /* RETURN */ char **saddrp; /* RETURN */{ int fd; char objname[20]; extern int dnet_conn(); struct dn_naddr *dnaddrp, dnaddr; struct nodeent *np; if (!phostname) phostname = "0"; /* * build the target object name. */ sprintf (objname, "X$X%d", idisplay); /* * Attempt to open the DECnet connection, return -1 if fails; ought to * do some retries here.... */ if ((fd = dnet_conn (phostname, objname, SOCK_STREAM, 0, 0, 0, 0)) < 0) { return -1; } *familyp = FamilyDECnet; if (dnaddrp = dnet_addr (phostname)) { /* stolen from xhost */ dnaddr = *dnaddrp; } else { if ((np = getnodebyname (phostname)) == NULL) { (void) close (fd); return -1; } dnaddr.a_len = np->n_length; bcopy (np->n_addr, dnaddr.a_addr, np->n_length); } *saddrlenp = sizeof (struct dn_naddr); *saddrp = Xmalloc (*saddrlenp); if (!*saddrp) { (void) close (fd); return -1; } bcopy ((char *)&dnaddr, *saddrp, *saddrlenp); return fd;}#endif /* DNETCONN */#ifdef UNIXCONN#include <sys/un.h>/*ARGSUSED*/static int MakeUNIXSocketConnection (phostname, idisplay, retries, familyp, saddrlenp, saddrp) char *phostname; int idisplay; int retries; int *familyp; /* RETURN */ int *saddrlenp; /* RETURN */ char **saddrp; /* RETURN */{ struct sockaddr_un unaddr; /* UNIX socket data block */ struct sockaddr *addr; /* generic socket pointer */ int addrlen; /* length of addr */ int fd; /* socket file descriptor */#ifdef hpux /* this is disgusting */ struct sockaddr_un ounaddr; /* UNIX socket data block */ struct sockaddr *oaddr; /* generic socket pointer */ int oaddrlen; /* length of addr */#endif unaddr.sun_family = AF_UNIX; sprintf (unaddr.sun_path, "%s%d", X_UNIX_PATH, idisplay); addr = (struct sockaddr *) &unaddr;#ifdef SUN_LEN addrlen = SUN_LEN(&unaddr);#else addrlen = strlen(unaddr.sun_path) + sizeof(unaddr.sun_family);#endif#ifdef hpux /* this is disgusting */ ounaddr.sun_family = AF_UNIX; sprintf (ounaddr.sun_path, "%s%d", OLD_UNIX_PATH, idisplay); oaddr = (struct sockaddr *) &ounaddr; oaddrlen = strlen(ounaddr.sun_path) + sizeof(ounaddr.sun_family);#endif /* * Open the network connection. */ do { if ((fd = socket ((int) addr->sa_family, SOCK_STREAM, 0)) < 0) { return -1; } if (connect (fd, addr, addrlen) < 0) { int olderrno = errno; (void) close (fd);#ifdef hpux /* this is disgusting */ if (olderrno == ENOENT) { fd = socket ((int) oaddr->sa_family, SOCK_STREAM, 0); if (fd >= 0) { if (connect (fd, oaddr, oaddrlen) >= 0) break; olderrno = errno; (void) close (fd); } }#endif if (olderrno != ENOENT || retries <= 0) { errno = olderrno; return -1; } sleep (1); } else { break; } } while (retries-- > 0); /* * Don't need to get auth info since we're local */ return fd;}#endif /* UNIXCONN */#ifdef TCPCONNstatic int MakeTCPConnection (phostname, idisplay, retries, familyp, saddrlenp, saddrp) char *phostname; int idisplay; int retries; int *familyp; /* RETURN */ int *saddrlenp; /* RETURN */ char **saddrp; /* RETURN */{ char hostnamebuf[256]; /* tmp space */ unsigned long hostinetaddr; /* result of inet_addr of arpa addr */ struct sockaddr_in inaddr; /* IP socket */ struct sockaddr *addr; /* generic socket pointer */ int addrlen; /* length of addr */ struct hostent *hp; /* entry in hosts table */ char *cp; /* character pointer iterator */ int fd; /* file descriptor to return */ int len; /* length tmp variable */#define INVALID_INETADDR ((unsigned long) -1) if (!phostname) { hostnamebuf[0] = '\0'; (void) _XGetHostname (hostnamebuf, sizeof hostnamebuf); phostname = hostnamebuf; } /* * if numeric host name then try to parse it as such; do the number * first because some systems return garbage instead of INVALID_INETADDR */ if (isascii(phostname[0]) && isdigit(phostname[0])) { hostinetaddr = inet_addr (phostname); } else { hostinetaddr = INVALID_INETADDR; } /* * try numeric */ if (hostinetaddr == INVALID_INETADDR) { if ((hp = gethostbyname(phostname)) == NULL) { /* No such host! */ return -1; } if (hp->h_addrtype != AF_INET) { /* is IP host? */ /* Not an Internet host! */ return -1; } /* Set up the socket data. */ inaddr.sin_family = hp->h_addrtype;#if defined(CRAY) && defined(OLDTCP) /* Only Cray UNICOS3 and UNICOS4 will define this */ { long t; bcopy ((char *)hp->h_addr, (char *)&t, sizeof(t)); inaddr.sin_addr = t; }#else bcopy ((char *)hp->h_addr, (char *)&inaddr.sin_addr, sizeof(inaddr.sin_addr));#endif /* CRAY and OLDTCP */ } else {#if defined(CRAY) && defined(OLDTCP) /* Only Cray UNICOS3 and UNICOS4 will define this */ inaddr.sin_addr = hostinetaddr;#else inaddr.sin_addr.s_addr = hostinetaddr;#endif /* CRAY and OLDTCP */ inaddr.sin_family = AF_INET; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -