diff --git a/.appveyor.yml b/.appveyor.yml index c023790cf..a925a84b7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -64,8 +64,7 @@ font-util,\ khronos-opengl-registry,\ python38-lxml,\ xkbcomp-devel,\ -xkeyboard-config,\ -xtrans" +xkeyboard-config" - echo Install done - "%CYGWIN_ROOT%\\%SETUP% -qnNdO -R %CYGWIN_ROOT% -s %CYGWIN_MIRROR% -l %CACHE% -g" cache: diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f208bd119..c6420f9c1 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -108,7 +108,7 @@ stages: FDO_DISTRIBUTION_TAG: '$XORG_FREEBSD_TAG' FDO_DISTRIBUTION_VERSION: '$XORG_FREEBSD_VERSION' FDO_DISTRIBUTION_EXEC: '' - FDO_DISTRIBUTION_PACKAGES: 'git gcc pkgconf autoconf automake libtool xorg-macros xorgproto bash meson ninja pixman xtrans libXau libXdmcp libXfont2 libxkbfile libxcvt libpciaccess font-util libepoll-shim libxvmc xcb-util xcb-util-wm' + FDO_DISTRIBUTION_PACKAGES: 'git gcc pkgconf autoconf automake libtool xorg-macros xorgproto bash meson ninja pixman libXau libXdmcp libXfont2 libxkbfile libxcvt libpciaccess font-util libepoll-shim libxvmc xcb-util xcb-util-wm' FDO_IMAGE_SIZE: '30G' debian-bullseye: diff --git a/.gitlab-ci/cross-prereqs-build.sh b/.gitlab-ci/cross-prereqs-build.sh index fb788895b..2c1f3464a 100755 --- a/.gitlab-ci/cross-prereqs-build.sh +++ b/.gitlab-ci/cross-prereqs-build.sh @@ -53,7 +53,6 @@ build 'https://gitlab.freedesktop.org/xorg/proto/xorgproto.git' 'xorgproto-2024. build 'https://gitlab.freedesktop.org/xorg/lib/libXau.git' 'libXau-1.0.9' build 'https://gitlab.freedesktop.org/xorg/proto/xcbproto.git' 'xcb-proto-1.14.1' build 'https://gitlab.freedesktop.org/xorg/lib/libxcb.git' 'libxcb-1.14' -build 'https://gitlab.freedesktop.org/xorg/lib/libxtrans.git' 'xtrans-1.4.0' # the default value of keysymdefdir is taken from the includedir variable for # xproto, which isn't adjusted by pkg-config for the sysroot # Using -fcommon to address build failure when cross-compiling for windows. diff --git a/.gitlab-ci/debian-install.sh b/.gitlab-ci/debian-install.sh index ff4f62eb2..b505d45a1 100644 --- a/.gitlab-ci/debian-install.sh +++ b/.gitlab-ci/debian-install.sh @@ -122,7 +122,6 @@ apt-get install -y \ x11-xkb-utils \ xfonts-utils \ xkb-data \ - xtrans-dev \ xutils-dev .gitlab-ci/cross-prereqs-build.sh i686-w64-mingw32 diff --git a/hw/xwin/windisplay.c b/hw/xwin/windisplay.c index 52ece1d88..c1c02f581 100644 --- a/hw/xwin/windisplay.c +++ b/hw/xwin/windisplay.c @@ -35,9 +35,7 @@ #include "windisplay.h" #include "winmsg.h" -#define XSERV_t -#define TRANS_SERVER -#include +#include "os/Xtrans.h" /* Generate a display name string referring to the display of this server, diff --git a/meson.build b/meson.build index 1b901c65b..bd11c401a 100644 --- a/meson.build +++ b/meson.build @@ -83,7 +83,6 @@ damageproto_dep = dependency('damageproto', version: '>= 1.1', fallback: ['xorgp xcmiscproto_dep = dependency('xcmiscproto', version: '>= 1.2.0', fallback: ['xorgproto', 'ext_xorgproto']) bigreqsproto_dep = dependency('bigreqsproto', version: '>= 1.1.0', fallback: ['xorgproto', 'ext_xorgproto']) presentproto_dep = dependency('presentproto', version: '>= 1.4', fallback: ['xorgproto', 'ext_xorgproto']) -xtrans_dep = dependency('xtrans', version: '>= 1.3.5') videoproto_dep = dependency('videoproto', fallback: ['xorgproto', 'ext_xorgproto']) compositeproto_dep = dependency('compositeproto', version: '>= 0.4', fallback: ['xorgproto', 'ext_xorgproto']) @@ -578,7 +577,6 @@ common_dep = [ xcmiscproto_dep, bigreqsproto_dep, presentproto_dep, - xtrans_dep, libsystemd_daemon_dep, videoproto_dep, diff --git a/os/Xtrans.c b/os/Xtrans.c new file mode 100644 index 000000000..0433d08a4 --- /dev/null +++ b/os/Xtrans.c @@ -0,0 +1,1170 @@ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA + * + * All Rights Reserved + * + * 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 NCR not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. NCR makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NCR 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. + */ + +#include +#include +#include +#ifdef HAVE_SYSTEMD_DAEMON +#include +#endif +#include + +/* + * The transport table contains a definition for every transport (protocol) + * family. All operations that can be made on the transport go through this + * table. + * + * Each transport is assigned a unique transport id. + * + * New transports can be added by adding an entry in this table. + * For compatibility, the transport ids should never be renumbered. + * Always add to the end of the list. + */ + +#define TRANS_TLI_INET_INDEX 1 +#define TRANS_TLI_TCP_INDEX 2 +#define TRANS_TLI_TLI_INDEX 3 +#define TRANS_SOCKET_UNIX_INDEX 4 +#define TRANS_SOCKET_LOCAL_INDEX 5 +#define TRANS_SOCKET_INET_INDEX 6 +#define TRANS_SOCKET_TCP_INDEX 7 +#define TRANS_DNET_INDEX 8 +#define TRANS_LOCAL_LOCAL_INDEX 9 +/* 10 used to be PTS, but that's gone. */ +#define TRANS_LOCAL_NAMED_INDEX 11 +/* 12 used to be ISC, but that's gone. */ +/* 13 used to be SCO, but that's gone. */ +#define TRANS_SOCKET_INET6_INDEX 14 +#define TRANS_LOCAL_PIPE_INDEX 15 + +#if defined(IPv6) && !defined(AF_INET6) +#error "Cannot build IPv6 support without AF_INET6" +#endif + +static +Xtransport_table Xtransports[] = { +#if defined(TCPCONN) + { &_XSERVTransSocketTCPFuncs, TRANS_SOCKET_TCP_INDEX }, +#if defined(IPv6) + { &_XSERVTransSocketINET6Funcs, TRANS_SOCKET_INET6_INDEX }, +#endif /* IPv6 */ + { &_XSERVTransSocketINETFuncs, TRANS_SOCKET_INET_INDEX }, +#endif /* TCPCONN */ +#if defined(UNIXCONN) +#if !defined(LOCALCONN) + { &_XSERVTransSocketLocalFuncs, TRANS_SOCKET_LOCAL_INDEX }, +#endif /* !LOCALCONN */ + { &_XSERVTransSocketUNIXFuncs, TRANS_SOCKET_UNIX_INDEX }, +#endif /* UNIXCONN */ +#if defined(LOCALCONN) + { &_XSERVTransLocalFuncs, TRANS_LOCAL_LOCAL_INDEX }, +#if defined(SVR4) || defined(__SVR4) + { &_XSERVTransNAMEDFuncs, TRANS_LOCAL_NAMED_INDEX }, +#endif +#ifdef __sun + { &_XSERVTransPIPEFuncs, TRANS_LOCAL_PIPE_INDEX }, +#endif /* __sun */ +#endif /* LOCALCONN */ +}; + +#define NUMTRANS (sizeof(Xtransports)/sizeof(Xtransport_table)) + + +#ifdef WIN32 +#define ioctl ioctlsocket +#endif + + + +/* + * These are a few utility function used by the public interface functions. + */ +void _XSERVTransFreeConnInfo (XtransConnInfo ciptr) + +{ + prmsg (3,"FreeConnInfo(%p)\n", (void *) ciptr); + + if (ciptr->addr) + free (ciptr->addr); + + if (ciptr->peeraddr) + free (ciptr->peeraddr); + + if (ciptr->port) + free (ciptr->port); + + free (ciptr); +} + + +#define PROTOBUFSIZE 20 + +static Xtransport * +_XSERVTransSelectTransport (const char *protocol) + +{ +#ifndef HAVE_STRCASECMP + char protobuf[PROTOBUFSIZE]; +#endif + + prmsg (3,"SelectTransport(%s)\n", protocol); + +#ifndef HAVE_STRCASECMP + /* + * Force Protocol to be lowercase as a way of doing + * a case insensitive match. + */ + + strncpy (protobuf, protocol, PROTOBUFSIZE - 1); + protobuf[PROTOBUFSIZE-1] = '\0'; + + for (unsigned int i = 0; i < PROTOBUFSIZE && protobuf[i] != '\0'; i++) + if (isupper ((unsigned char)protobuf[i])) + protobuf[i] = tolower ((unsigned char)protobuf[i]); +#endif + + /* Look at all of the configured protocols */ + + for (unsigned int i = 0; i < NUMTRANS; i++) + { +#ifndef HAVE_STRCASECMP + if (!strcmp (protobuf, Xtransports[i].transport->TransName)) +#else + if (!strcasecmp (protocol, Xtransports[i].transport->TransName)) +#endif + return Xtransports[i].transport; + } + + return NULL; +} + +static int +_XSERVTransParseAddress (const char *address, + char **protocol, char **host, char **port) + +{ + /* + * For the font library, the address is a string formatted + * as "protocol/host:port[/catalogue]". Note that the catologue + * is optional. At this time, the catologue info is ignored, but + * we have to parse it anyways. + * + * Other than fontlib, the address is a string formatted + * as "protocol/host:port". + * + * If the protocol part is missing, then assume TCP. + * If the protocol part and host part are missing, then assume local. + * If a "::" is found then assume DNET. + */ + + char *mybuf, *tmpptr = NULL; + const char *_protocol = NULL; + const char *_host, *_port; + char hostnamebuf[256]; + char *_host_buf; + int _host_len; + + prmsg (3,"ParseAddress(%s)\n", address); + + /* First, check for AF_UNIX socket paths */ + if (address[0] == '/') { + _protocol = "local"; + _host = ""; + _port = address; + } else +#ifdef HAVE_LAUNCHD + /* launchd sockets will look like 'local//tmp/launch-XgkNns/:0' */ + if(!strncmp(address,"local//",7)) { + _protocol="local"; + _host=""; + _port=address+6; + } else +#endif + if (!strncmp(address, "unix:", 5)) { + _protocol = "local"; + _host = ""; + _port = address + 5; + } + if (_protocol) + goto done_parsing; + + /* Copy the string so it can be changed */ + + tmpptr = mybuf = strdup (address); + + /* Parse the string to get each component */ + + /* Get the protocol part */ + + _protocol = mybuf; + + + if ((mybuf == NULL) || + ( ((mybuf = strchr (mybuf, '/')) == NULL) && + ((mybuf = strrchr (tmpptr, ':')) == NULL) ) ) + { + /* address is in a bad format */ + *protocol = NULL; + *host = NULL; + *port = NULL; + free (tmpptr); + return 0; + } + + if (*mybuf == ':') + { + /* + * If there is a hostname, then assume tcp, otherwise + * it must be local. + */ + if (mybuf == tmpptr) + { + /* There is neither a protocol or host specified */ + _protocol = "local"; + } + else + { + /* There is a hostname specified */ + _protocol = "tcp"; + mybuf = tmpptr; /* reset to the beginning of the host ptr */ + } + } + else + { + /* *mybuf == '/' */ + + *mybuf ++= '\0'; /* put a null at the end of the protocol */ + + if (strlen(_protocol) == 0) + { + /* + * If there is a hostname, then assume tcp, otherwise + * it must be local. + */ + if (*mybuf != ':') + _protocol = "tcp"; + else + _protocol = "local"; + } + } + + /* Get the host part */ + + _host = _host_buf = mybuf; + + if ((mybuf = strrchr (mybuf,':')) == NULL) + { + *protocol = NULL; + *host = NULL; + *port = NULL; + free (tmpptr); + return 0; + } + + *mybuf ++= '\0'; + + _host_len = strlen(_host); + if (_host_len == 0) + { + _XSERVTransGetHostname (hostnamebuf, sizeof (hostnamebuf)); + _host = hostnamebuf; + } +#ifdef IPv6 + /* hostname in IPv6 [numeric_addr]:0 form? */ + else if ( (_host_len > 3) && + ((strcmp(_protocol, "tcp") == 0) || (strcmp(_protocol, "inet6") == 0)) + && (_host_buf[0] == '[') && (_host_buf[_host_len - 1] == ']') ) { + struct sockaddr_in6 sin6; + + _host_buf[_host_len - 1] = '\0'; + + /* Verify address is valid IPv6 numeric form */ + if (inet_pton(AF_INET6, _host + 1, &sin6) == 1) { + /* It is. Use it as such. */ + _host++; + _protocol = "inet6"; + } else { + /* It's not, restore it just in case some other code can use it. */ + _host_buf[_host_len - 1] = ']'; + } + } +#endif + + + /* Get the port */ + + _port = mybuf; + +done_parsing: + /* + * Now that we have all of the components, allocate new + * string space for them. + */ + + if ((*protocol = strdup (_protocol)) == NULL) + { + /* Malloc failed */ + *port = NULL; + *host = NULL; + *protocol = NULL; + free (tmpptr); + return 0; + } + + if ((*host = strdup (_host)) == NULL) + { + /* Malloc failed */ + *port = NULL; + *host = NULL; + free (*protocol); + *protocol = NULL; + free (tmpptr); + return 0; + } + + if ((*port = strdup (_port)) == NULL) + { + /* Malloc failed */ + *port = NULL; + free (*host); + *host = NULL; + free (*protocol); + *protocol = NULL; + free (tmpptr); + return 0; + } + + free (tmpptr); + + return 1; +} + + +/* + * _XSERVTransOpen does all of the real work opening a connection. The only + * funny part about this is the type parameter which is used to decide which + * type of open to perform. + */ + +static XtransConnInfo +_XSERVTransOpen (int type, const char *address) + +{ + char *protocol = NULL, *host = NULL, *port = NULL; + XtransConnInfo ciptr = NULL; + Xtransport *thistrans; + + prmsg (2,"Open(%d,%s)\n", type, address); + +#if defined(WIN32) && defined(TCPCONN) + if (_XSERVTransWSAStartup()) + { + prmsg (1,"Open: WSAStartup failed\n"); + return NULL; + } +#endif + + /* Parse the Address */ + + if (_XSERVTransParseAddress (address, &protocol, &host, &port) == 0) + { + prmsg (1,"Open: Unable to Parse address %s\n", address); + return NULL; + } + + /* Determine the transport type */ + + if ((thistrans = _XSERVTransSelectTransport (protocol)) == NULL) + { + prmsg (1,"Open: Unable to find transport for %s\n", + protocol); + + free (protocol); + free (host); + free (port); + return NULL; + } + + /* Open the transport */ + + switch (type) + { + case XTRANS_OPEN_COTS_CLIENT: + break; + case XTRANS_OPEN_COTS_SERVER: + ciptr = thistrans->OpenCOTSServer(thistrans, protocol, host, port); + break; + default: + prmsg (1,"Open: Unknown Open type %d\n", type); + } + + if (ciptr == NULL) + { + if (!(thistrans->flags & TRANS_DISABLED)) + { + prmsg (1,"Open: transport open failed for %s/%s:%s\n", + protocol, host, port); + } + free (protocol); + free (host); + free (port); + return NULL; + } + + ciptr->transptr = thistrans; + ciptr->port = port; /* We need this for _XSERVTransReopen */ + + free (protocol); + free (host); + + return ciptr; +} + +/* + * We might want to create an XtransConnInfo object based on a previously + * opened connection. For example, the font server may clone itself and + * pass file descriptors to the parent. + */ + +static XtransConnInfo +_XSERVTransReopen (int type, int trans_id, int fd, const char *port) + +{ + XtransConnInfo ciptr = NULL; + Xtransport *thistrans = NULL; + char *save_port; + + prmsg (2,"Reopen(%d,%d,%s)\n", trans_id, fd, port); + + /* Determine the transport type */ + + for (unsigned int i = 0; i < NUMTRANS; i++) + { + if (Xtransports[i].transport_id == trans_id) + { + thistrans = Xtransports[i].transport; + break; + } + } + + if (thistrans == NULL) + { + prmsg (1,"Reopen: Unable to find transport id %d\n", + trans_id); + + return NULL; + } + + if ((save_port = strdup (port)) == NULL) + { + prmsg (1,"Reopen: Unable to malloc port string\n"); + + return NULL; + } + + /* Get a new XtransConnInfo object */ + + switch (type) + { + case XTRANS_OPEN_COTS_SERVER: + ciptr = thistrans->ReopenCOTSServer(thistrans, fd, port); + break; + default: + prmsg (1,"Reopen: Bad Open type %d\n", type); + } + + if (ciptr == NULL) + { + prmsg (1,"Reopen: transport open failed\n"); + free (save_port); + return NULL; + } + + ciptr->transptr = thistrans; + ciptr->port = save_port; + + return ciptr; +} + +/* + * These are the public interfaces to this Transport interface. + * These are the only functions that should have knowledge of the transport + * table. + */ + +XtransConnInfo +_XSERVTransOpenCOTSServer (const char *address) + +{ + prmsg (2,"OpenCOTSServer(%s)\n", address); + return _XSERVTransOpen (XTRANS_OPEN_COTS_SERVER, address); +} + +XtransConnInfo +_XSERVTransReopenCOTSServer (int trans_id, int fd, const char *port) + +{ + prmsg (2,"ReopenCOTSServer(%d, %d, %s)\n", trans_id, fd, port); + return _XSERVTransReopen (XTRANS_OPEN_COTS_SERVER, trans_id, fd, port); +} + +int _XSERVTransSetOption (XtransConnInfo ciptr, int option, int arg) + +{ + int fd = ciptr->fd; + int ret = 0; + + prmsg (2,"SetOption(%d,%d,%d)\n", fd, option, arg); + + /* + * For now, all transport type use the same stuff for setting options. + * As long as this is true, we can put the common code here. Once a more + * complicated transport such as shared memory or an OSI implementation + * that uses the session and application libraries is implemented, this + * code may have to move to a transport dependent function. + * + * ret = ciptr->transptr->SetOption (ciptr, option, arg); + */ + + switch (option) + { + case TRANS_NONBLOCKING: + switch (arg) + { + case 0: + /* Set to blocking mode */ + break; + case 1: /* Set to non-blocking mode */ + +#if defined(O_NONBLOCK) + ret = fcntl (fd, F_GETFL, 0); + if (ret != -1) + ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK); +#else +#ifdef FIOSNBIO + { + int arg; + arg = 1; + ret = ioctl (fd, FIOSNBIO, &arg); + } +#else +#if defined(WIN32) + { +#ifdef WIN32 + u_long arg; +#else + int arg; +#endif + arg = 1; +/* IBM TCP/IP understands this option too well: it causes _XSERVTransRead to fail + * eventually with EWOULDBLOCK */ + ret = ioctl (fd, FIONBIO, &arg); + } +#else + ret = fcntl (fd, F_GETFL, 0); +#ifdef FNDELAY + ret = fcntl (fd, F_SETFL, ret | FNDELAY); +#else + ret = fcntl (fd, F_SETFL, ret | O_NDELAY); +#endif +#endif /* AIXV3 || uniosu */ +#endif /* FIOSNBIO */ +#endif /* O_NONBLOCK */ + break; + default: + /* Unknown option */ + break; + } + break; + case TRANS_CLOSEONEXEC: +#ifdef F_SETFD +#ifdef FD_CLOEXEC + ret = fcntl (fd, F_SETFD, FD_CLOEXEC); +#else + ret = fcntl (fd, F_SETFD, 1); +#endif /* FD_CLOEXEC */ +#endif /* F_SETFD */ + break; + } + + return ret; +} + +int _XSERVTransCreateListener (XtransConnInfo ciptr, const char *port, unsigned int flags) +{ + return ciptr->transptr->CreateListener (ciptr, port, flags); +} + +int _XSERVTransReceived (const char * protocol) +{ + Xtransport *trans; + int i = 0, ret = 0; + + prmsg (5, "Received(%s)\n", protocol); + + if ((trans = _XSERVTransSelectTransport(protocol)) == NULL) + { + prmsg (1,"Received: unable to find transport: %s\n", + protocol); + + return -1; + } + if (trans->flags & TRANS_ALIAS) { + if (trans->nolisten) + while (trans->nolisten[i]) { + ret |= _XSERVTransReceived(trans->nolisten[i]); + i++; + } + } + + trans->flags |= TRANS_RECEIVED; + return ret; +} + +int _XSERVTransNoListen (const char * protocol) +{ + Xtransport *trans; + int i = 0, ret = 0; + + if ((trans = _XSERVTransSelectTransport(protocol)) == NULL) + { + prmsg (1,"TransNoListen: unable to find transport: %s\n", + protocol); + + return -1; + } + if (trans->flags & TRANS_ALIAS) { + if (trans->nolisten) + while (trans->nolisten[i]) { + ret |= _XSERVTransNoListen(trans->nolisten[i]); + i++; + } + } + + trans->flags |= TRANS_NOLISTEN; + return ret; +} + +int _XSERVTransListen (const char * protocol) +{ + Xtransport *trans; + int i = 0, ret = 0; + + if ((trans = _XSERVTransSelectTransport(protocol)) == NULL) + { + prmsg (1,"TransListen: unable to find transport: %s\n", + protocol); + + return -1; + } + if (trans->flags & TRANS_ALIAS) { + if (trans->nolisten) + while (trans->nolisten[i]) { + ret |= _XSERVTransListen(trans->nolisten[i]); + i++; + } + } + + trans->flags &= ~TRANS_NOLISTEN; + return ret; +} + +int _XSERVTransIsListening (const char * protocol) +{ + Xtransport *trans; + + if ((trans = _XSERVTransSelectTransport(protocol)) == NULL) + { + prmsg (1,"TransIsListening: unable to find transport: %s\n", + protocol); + + return 0; + } + + return !(trans->flags & TRANS_NOLISTEN); +} + +int _XSERVTransResetListener (XtransConnInfo ciptr) +{ + if (ciptr->transptr->ResetListener) + return ciptr->transptr->ResetListener (ciptr); + else + return TRANS_RESET_NOOP; +} + +XtransConnInfo _XSERVTransAccept (XtransConnInfo ciptr, int *status) +{ + XtransConnInfo newciptr; + + prmsg (2,"Accept(%d)\n", ciptr->fd); + + newciptr = ciptr->transptr->Accept (ciptr, status); + + if (newciptr) + newciptr->transptr = ciptr->transptr; + + return newciptr; +} + +int _XSERVTransBytesReadable (XtransConnInfo ciptr, BytesReadable_t *pend) +{ + return ciptr->transptr->BytesReadable (ciptr, pend); +} + +int _XSERVTransRead (XtransConnInfo ciptr, char *buf, int size) +{ + return ciptr->transptr->Read (ciptr, buf, size); +} + +int _XSERVTransWrite (XtransConnInfo ciptr, const char *buf, int size) +{ + return ciptr->transptr->Write (ciptr, buf, size); +} + +int _XSERVTransReadv (XtransConnInfo ciptr, struct iovec *buf, int size) +{ + return ciptr->transptr->Readv (ciptr, buf, size); +} + +int _XSERVTransWritev (XtransConnInfo ciptr, struct iovec *buf, int size) +{ + return ciptr->transptr->Writev (ciptr, buf, size); +} + +#if XTRANS_SEND_FDS +int _XSERVTransSendFd (XtransConnInfo ciptr, int fd, int do_close) +{ + return ciptr->transptr->SendFd(ciptr, fd, do_close); +} + +int _XSERVTransRecvFd (XtransConnInfo ciptr) +{ + return ciptr->transptr->RecvFd(ciptr); +} +#endif + +int _XSERVTransDisconnect (XtransConnInfo ciptr) +{ + return ciptr->transptr->Disconnect (ciptr); +} + +int _XSERVTransClose (XtransConnInfo ciptr) +{ + int ret; + + prmsg (2,"Close(%d)\n", ciptr->fd); + + ret = ciptr->transptr->Close (ciptr); + + _XSERVTransFreeConnInfo (ciptr); + + return ret; +} + +int _XSERVTransCloseForCloning (XtransConnInfo ciptr) +{ + int ret; + + prmsg (2,"CloseForCloning(%d)\n", ciptr->fd); + + ret = ciptr->transptr->CloseForCloning (ciptr); + + _XSERVTransFreeConnInfo (ciptr); + + return ret; +} + +int _XSERVTransIsLocal (XtransConnInfo ciptr) +{ + return (ciptr->family == AF_UNIX); +} + +int _XSERVTransGetPeerAddr (XtransConnInfo ciptr, int *familyp, int *addrlenp, + Xtransaddr **addrp) +{ + prmsg (2,"GetPeerAddr(%d)\n", ciptr->fd); + + *familyp = ciptr->family; + *addrlenp = ciptr->peeraddrlen; + + if ((*addrp = malloc (ciptr->peeraddrlen)) == NULL) + { + prmsg (1,"GetPeerAddr: malloc failed\n"); + return -1; + } + memcpy(*addrp, ciptr->peeraddr, ciptr->peeraddrlen); + + return 0; +} + +int _XSERVTransGetConnectionNumber (XtransConnInfo ciptr) +{ + return ciptr->fd; +} + +/* + * These functions are really utility functions, but they require knowledge + * of the internal data structures, so they have to be part of the Transport + * Independent API. + */ +static int +complete_network_count (void) +{ + int count = 0; + int found_local = 0; + + /* + * For a complete network, we only need one LOCALCONN transport to work + */ + + for (unsigned int i = 0; i < NUMTRANS; i++) + { + if (Xtransports[i].transport->flags & TRANS_ALIAS + || Xtransports[i].transport->flags & TRANS_NOLISTEN) + continue; + + if (Xtransports[i].transport->flags & TRANS_LOCAL) + found_local = 1; + else + count++; + } + + return (count + found_local); +} + + +static int +receive_listening_fds(const char* port, XtransConnInfo* temp_ciptrs, + uint32_t* count_ret) + +{ +#ifdef HAVE_SYSTEMD_DAEMON + XtransConnInfo ciptr; + int i, systemd_listen_fds; + + systemd_listen_fds = sd_listen_fds(1); + if (systemd_listen_fds < 0) + { + prmsg (1, "receive_listening_fds: sd_listen_fds error: %s\n", + strerror(-systemd_listen_fds)); + return -1; + } + + for (i = 0; i < systemd_listen_fds && *count_ret < (int)NUMTRANS; i++) + { + struct sockaddr_storage a; + int ti; + const char* tn; + socklen_t al; + + al = sizeof(a); + if (getsockname(i + SD_LISTEN_FDS_START, (struct sockaddr*)&a, &al) < 0) { + prmsg (1, "receive_listening_fds: getsockname error: %s\n", + strerror(errno)); + return -1; + } + + switch (a.ss_family) + { + case AF_UNIX: + ti = TRANS_SOCKET_UNIX_INDEX; + if (*((struct sockaddr_un*)&a)->sun_path == '\0' && + al > sizeof(sa_family_t)) + tn = "local"; + else + tn = "unix"; + break; + case AF_INET: + ti = TRANS_SOCKET_INET_INDEX; + tn = "inet"; + break; +#ifdef IPv6 + case AF_INET6: + ti = TRANS_SOCKET_INET6_INDEX; + tn = "inet6"; + break; +#endif /* IPv6 */ + default: + prmsg (1, "receive_listening_fds:" + "Got unknown socket address family\n"); + return -1; + } + + ciptr = _XSERVTransReopenCOTSServer(ti, i + SD_LISTEN_FDS_START, port); + if (!ciptr) + { + prmsg (1, "receive_listening_fds:" + "Got NULL while trying to reopen socket received from systemd.\n"); + return -1; + } + + prmsg (5, "receive_listening_fds: received listener for %s, %d\n", + tn, ciptr->fd); + temp_ciptrs[(*count_ret)++] = ciptr; + _XSERVTransReceived(tn); + } +#endif /* HAVE_SYSTEMD_DAEMON */ + return 0; +} + +#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD +extern int xquartz_launchd_fd; +#endif + +int _XSERVTransMakeAllCOTSServerListeners (const char *port, int *partial, + uint32_t *count_ret, XtransConnInfo **ciptrs_ret) +{ + char buffer[256]; /* ??? What size ?? */ + XtransConnInfo ciptr, temp_ciptrs[NUMTRANS] = { NULL }; + int status, j; + +#ifdef IPv6 + int ipv6_succ = 0; +#endif + prmsg (2,"MakeAllCOTSServerListeners(%s,%p)\n", + port ? port : "NULL", (void *) ciptrs_ret); + + *count_ret = 0; + +#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD + fprintf(stderr, "Launchd socket fd: %d\n", xquartz_launchd_fd); + if(xquartz_launchd_fd != -1) { + if((ciptr = _XSERVTransReopenCOTSServer(TRANS_SOCKET_LOCAL_INDEX, + xquartz_launchd_fd, getenv("DISPLAY"))))==NULL) + fprintf(stderr,"Got NULL while trying to Reopen launchd port\n"); + else + temp_ciptrs[(*count_ret)++] = ciptr; + } +#endif + + if (receive_listening_fds(port, temp_ciptrs, count_ret) < 0) + return -1; + + for (unsigned int i = 0; i < NUMTRANS; i++) + { + Xtransport *trans = Xtransports[i].transport; + unsigned int flags = 0; + + if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN || + trans->flags&TRANS_RECEIVED) + continue; + + snprintf(buffer, sizeof(buffer), "%s/:%s", + trans->TransName, port ? port : ""); + + prmsg (5,"MakeAllCOTSServerListeners: opening %s\n", + buffer); + + if ((ciptr = _XSERVTransOpenCOTSServer(buffer)) == NULL) + { + if (trans->flags & TRANS_DISABLED) + continue; + + prmsg (1, + "MakeAllCOTSServerListeners: failed to open listener for %s\n", + trans->TransName); + continue; + } +#ifdef IPv6 + if ((Xtransports[i].transport_id == TRANS_SOCKET_INET_INDEX + && ipv6_succ)) + flags |= ADDR_IN_USE_ALLOWED; +#endif + + if ((status = _XSERVTransCreateListener (ciptr, port, flags)) < 0) + { + if (*partial != 0) + continue; + + if (status == TRANS_ADDR_IN_USE) + { + /* + * We failed to bind to the specified address because the + * address is in use. It must be that a server is already + * running at this address, and this function should fail. + */ + + prmsg (1, + "MakeAllCOTSServerListeners: server already running\n"); + + for (j = 0; j < *count_ret; j++) + if (temp_ciptrs[j] != NULL) + _XSERVTransClose (temp_ciptrs[j]); + + *count_ret = 0; + *ciptrs_ret = NULL; + *partial = 0; + return -1; + } + else + { + prmsg (1, + "MakeAllCOTSServerListeners: failed to create listener for %s\n", + trans->TransName); + + continue; + } + } + +#ifdef IPv6 + if (Xtransports[i].transport_id == TRANS_SOCKET_INET6_INDEX) + ipv6_succ = 1; +#endif + + prmsg (5, + "MakeAllCOTSServerListeners: opened listener for %s, %d\n", + trans->TransName, ciptr->fd); + + temp_ciptrs[*count_ret] = ciptr; + (*count_ret)++; + } + + *partial = (*count_ret < complete_network_count()); + + prmsg (5, + "MakeAllCOTSServerListeners: partial=%d, actual=%d, complete=%d \n", + *partial, *count_ret, complete_network_count()); + + if (*count_ret > 0) + { + if ((*ciptrs_ret = malloc ( + *count_ret * sizeof (XtransConnInfo))) == NULL) + { + return -1; + } + + for (int i = 0; i < *count_ret; i++) + { + (*ciptrs_ret)[i] = temp_ciptrs[i]; + } + } + else + *ciptrs_ret = NULL; + + return 0; +} + +/* + * These routines are not part of the X Transport Interface, but they + * may be used by it. + */ + + +#ifdef WIN32 + +/* + * emulate readv + */ +static int _XSERVTransReadV (XtransConnInfo ciptr, struct iovec *iov, int iovcnt) +{ + int i, len, total; + char *base; + + ESET(0); + for (i = 0, total = 0; i < iovcnt; i++, iov++) { + len = iov->iov_len; + base = iov->iov_base; + while (len > 0) { + register int nbytes; + nbytes = _XSERVTransRead (ciptr, base, len); + if (nbytes < 0 && total == 0) return -1; + if (nbytes <= 0) return total; + ESET(0); + len -= nbytes; + total += nbytes; + base += nbytes; + } + } + return total; +} + + +/* + * emulate writev + */ +static int _XSERVTransWriteV (XtransConnInfo ciptr, struct iovec *iov, int iovcnt) +{ + int i, len, total; + char *base; + + ESET(0); + for (i = 0, total = 0; i < iovcnt; i++, iov++) { + len = iov->iov_len; + base = iov->iov_base; + while (len > 0) { + register int nbytes; + nbytes = _XSERVTransWrite (ciptr, base, len); + if (nbytes < 0 && total == 0) return -1; + if (nbytes <= 0) return total; + ESET(0); + len -= nbytes; + total += nbytes; + base += nbytes; + } + } + return total; +} + +#endif /* WIN32 */ + + +/* + * _XSERVTransGetHostname - similar to gethostname but allows special processing. + */ +int _XSERVTransGetHostname (char *buf, int maxlen) +{ + struct utsname name; + uname (&name); + + int len = strlen (name.nodename); + if (len >= maxlen) len = maxlen - 1; + memcpy (buf, name.nodename, len); + buf[len] = '\0'; + return len; +} diff --git a/os/Xtrans.h b/os/Xtrans.h new file mode 100644 index 000000000..fb7ceaadd --- /dev/null +++ b/os/Xtrans.h @@ -0,0 +1,317 @@ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA + * + * All Rights Reserved + * + * 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 NCR not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. NCR makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NCR 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. + */ + +#ifndef _XTRANS_H_ +#define _XTRANS_H_ + +#include + +#include +#include +#include + +#ifndef WIN32 +#include +#endif + +#ifdef __clang__ +/* Not all clients make use of all provided statics */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +/* + * Set the functions names according to where this code is being compiled. + */ + +#ifdef XTRANSDEBUG +static const char *__xtransname = "_XSERVTrans"; +#endif + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +/* + * Create a single address structure that can be used wherever + * an address structure is needed. struct sockaddr is not big enough + * to hold a sockadd_un, so we create this definition to have a single + * structure that is big enough for all the structures we might need. + * + * This structure needs to be independent of the socket/TLI interface used. + */ + +/* Temporary workaround for consumers whose configure scripts were + generated with pre-1.6 versions of xtrans.m4 */ +#if defined(IPv6) && !defined(HAVE_STRUCT_SOCKADDR_STORAGE) +#define HAVE_STRUCT_SOCKADDR_STORAGE +#endif + +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE +typedef struct sockaddr_storage Xtransaddr; +#else +#define XTRANS_MAX_ADDR_LEN 128 /* large enough to hold sun_path */ + +typedef struct { + unsigned char addr[XTRANS_MAX_ADDR_LEN]; +} Xtransaddr; +#endif + +#ifdef LONG64 +typedef int BytesReadable_t; +#else +typedef long BytesReadable_t; +#endif + + +#if defined(WIN32) + +/* + * _XSERVTransReadv and _XSERVTransWritev use struct iovec, normally found + * in Berkeley systems in . See the readv(2) and writev(2) + * manual pages for details. + */ + +struct iovec { + caddr_t iov_base; + int iov_len; +}; + +#else +#include +#endif + +typedef struct _XtransConnInfo *XtransConnInfo; + + +/* + * Transport Option definitions + */ + +#define TRANS_NONBLOCKING 1 +#define TRANS_CLOSEONEXEC 2 + + +/* + * Return values of Connect (0 is success) + */ + +#define TRANS_CONNECT_FAILED -1 +#define TRANS_TRY_CONNECT_AGAIN -2 +#define TRANS_IN_PROGRESS -3 + + +/* + * Return values of CreateListener (0 is success) + */ + +#define TRANS_CREATE_LISTENER_FAILED -1 +#define TRANS_ADDR_IN_USE -2 + + +/* + * Return values of Accept (0 is success) + */ + +#define TRANS_ACCEPT_BAD_MALLOC -1 +#define TRANS_ACCEPT_FAILED -2 +#define TRANS_ACCEPT_MISC_ERROR -3 + + +/* + * ResetListener return values + */ + +#define TRANS_RESET_NOOP 1 +#define TRANS_RESET_NEW_FD 2 +#define TRANS_RESET_FAILURE 3 + + +/* + * Function prototypes for the exposed interface + */ + +void _XSERVTransFreeConnInfo ( + XtransConnInfo /* ciptr */ +); + +XtransConnInfo _XSERVTransOpenCOTSServer( + const char * /* address */ +); + +XtransConnInfo _XSERVTransReopenCOTSServer( + int, /* trans_id */ + int, /* fd */ + const char * /* port */ +); + +int _XSERVTransSetOption( + XtransConnInfo, /* ciptr */ + int, /* option */ + int /* arg */ +); + +int _XSERVTransCreateListener( + XtransConnInfo, /* ciptr */ + const char *, /* port */ + unsigned int /* flags */ +); + +int _XSERVTransReceived ( + const char* /* protocol*/ +); + +int _XSERVTransNoListen ( + const char* /* protocol*/ +); + +int _XSERVTransListen ( + const char* /* protocol*/ +); + +int _XSERVTransIsListening ( + const char* /* protocol*/ +); + +int _XSERVTransResetListener ( + XtransConnInfo /* ciptr */ +); + +XtransConnInfo _XSERVTransAccept ( + XtransConnInfo, /* ciptr */ + int * /* status */ +); + +int _XSERVTransBytesReadable ( + XtransConnInfo, /* ciptr */ + BytesReadable_t * /* pend */ +); + +int _XSERVTransRead ( + XtransConnInfo, /* ciptr */ + char *, /* buf */ + int /* size */ +); + +int _XSERVTransWrite ( + XtransConnInfo, /* ciptr */ + const char *, /* buf */ + int /* size */ +); + +int _XSERVTransReadv ( + XtransConnInfo, /* ciptr */ + struct iovec *, /* buf */ + int /* size */ +); + +int _XSERVTransWritev ( + XtransConnInfo, /* ciptr */ + struct iovec *, /* buf */ + int /* size */ +); + +int _XSERVTransSendFd (XtransConnInfo ciptr, int fd, int do_close); + +int _XSERVTransRecvFd (XtransConnInfo ciptr); + +int _XSERVTransDisconnect ( + XtransConnInfo /* ciptr */ +); + +int _XSERVTransClose ( + XtransConnInfo /* ciptr */ +); + +int _XSERVTransCloseForCloning ( + XtransConnInfo /* ciptr */ +); + +int _XSERVTransIsLocal ( + XtransConnInfo /* ciptr */ +); + +int _XSERVTransGetPeerAddr ( + XtransConnInfo, /* ciptr */ + int *, /* familyp */ + int *, /* addrlenp */ + Xtransaddr ** /* addrp */ +); + +int _XSERVTransGetConnectionNumber ( + XtransConnInfo /* ciptr */ +); + +int _XSERVTransMakeAllCOTSServerListeners ( + const char *, /* port */ + int *, /* partial */ + uint32_t *, /* count_ret */ + XtransConnInfo ** /* ciptrs_ret */ +); + +/* + * Function Prototypes for Utility Functions. + */ + +int _XSERVTransConvertAddress ( + int *, /* familyp */ + int *, /* addrlenp */ + Xtransaddr ** /* addrp */ +); + +int _XSERVTransGetHostname ( + char * /* buf */, + int /* maxlen */ +); + +#if defined(WIN32) && defined(TCPCONN) +int _XSERVTransWSAStartup(); +#endif + +#endif /* _XTRANS_H_ */ diff --git a/os/Xtransint.h b/os/Xtransint.h new file mode 100644 index 000000000..16778b2e4 --- /dev/null +++ b/os/Xtransint.h @@ -0,0 +1,348 @@ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA + * + * All Rights Reserved + * + * 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 NCR not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. NCR makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NCR 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. + */ + +#ifndef _XTRANSINT_H_ +#define _XTRANSINT_H_ + +/* + * XTRANSDEBUG will enable the PRMSG() macros used in the X Transport + * Interface code. Each use of the PRMSG macro has a level associated with + * it. XTRANSDEBUG is defined to be a level. If the invocation level is =< + * the value of XTRANSDEBUG, then the message will be printed out to stderr. + * Recommended levels are: + * + * XTRANSDEBUG=1 Error messages + * XTRANSDEBUG=2 API Function Tracing + * XTRANSDEBUG=3 All Function Tracing + * XTRANSDEBUG=4 printing of intermediate values + * XTRANSDEBUG=5 really detailed stuff +#define XTRANSDEBUG 2 + * + * Defining XTRANSDEBUGTIMESTAMP will cause printing timestamps with each + * message. + */ + +#if !defined(XTRANSDEBUG) && defined(XTRANS_TRANSPORT_C) +# define XTRANSDEBUG 1 +#endif + +#include "os/Xtrans.h" + +#ifdef XTRANSDEBUG +# include +#endif /* XTRANSDEBUG */ + +#include + +#ifndef WIN32 +# include +# include +# include +# define ESET(val) errno = val +# define EGET() errno + +#else /* WIN32 */ + +# include /* for USHRT_MAX */ + +# define ESET(val) WSASetLastError(val) +# define EGET() WSAGetLastError() + +#endif /* WIN32 */ + +#include + +#define X_TCP_PORT 6000 + +#if XTRANS_SEND_FDS + +struct _XtransConnFd { + struct _XtransConnFd *next; + int fd; + int do_close; +}; + +#endif + +struct _XtransConnInfo { + struct _Xtransport *transptr; + int index; + char *priv; + int flags; + int fd; + char *port; + int family; + char *addr; + int addrlen; + char *peeraddr; + int peeraddrlen; + struct _XtransConnFd *recv_fds; + struct _XtransConnFd *send_fds; +}; + +#define XTRANS_OPEN_COTS_CLIENT 1 +#define XTRANS_OPEN_COTS_SERVER 2 + +typedef struct _Xtransport { + const char *TransName; + int flags; + const char ** nolisten; + XtransConnInfo (*OpenCOTSServer)( + struct _Xtransport *, /* transport */ + const char *, /* protocol */ + const char *, /* host */ + const char * /* port */ + ); + + XtransConnInfo (*ReopenCOTSServer)( + struct _Xtransport *, /* transport */ + int, /* fd */ + const char * /* port */ + ); + + int (*SetOption)( + XtransConnInfo, /* connection */ + int, /* option */ + int /* arg */ + ); + +/* Flags */ +# define ADDR_IN_USE_ALLOWED 1 + + int (*CreateListener)( + XtransConnInfo, /* connection */ + const char *, /* port */ + unsigned int /* flags */ + ); + + int (*ResetListener)( + XtransConnInfo /* connection */ + ); + + XtransConnInfo (*Accept)( + XtransConnInfo, /* connection */ + int * /* status */ + ); + + int (*BytesReadable)( + XtransConnInfo, /* connection */ + BytesReadable_t * /* pend */ + ); + + int (*Read)( + XtransConnInfo, /* connection */ + char *, /* buf */ + int /* size */ + ); + + int (*Write)( + XtransConnInfo, /* connection */ + const char *, /* buf */ + int /* size */ + ); + + int (*Readv)( + XtransConnInfo, /* connection */ + struct iovec *, /* buf */ + int /* size */ + ); + + int (*Writev)( + XtransConnInfo, /* connection */ + struct iovec *, /* buf */ + int /* size */ + ); + +#if XTRANS_SEND_FDS + int (*SendFd)( + XtransConnInfo, /* connection */ + int, /* fd */ + int /* do_close */ + ); + + int (*RecvFd)( + XtransConnInfo /* connection */ + ); +#endif + + int (*Disconnect)( + XtransConnInfo /* connection */ + ); + + int (*Close)( + XtransConnInfo /* connection */ + ); + + int (*CloseForCloning)( + XtransConnInfo /* connection */ + ); + +} Xtransport; + + +typedef struct _Xtransport_table { + Xtransport *transport; + int transport_id; +} Xtransport_table; + + +/* + * Flags for the flags member of Xtransport. + */ + +#define TRANS_ALIAS (1<<0) /* record is an alias, don't create server */ +#define TRANS_LOCAL (1<<1) /* local transport */ +#define TRANS_DISABLED (1<<2) /* Don't open this one */ +#define TRANS_NOLISTEN (1<<3) /* Don't listen on this one */ +#define TRANS_NOUNLINK (1<<4) /* Don't unlink transport endpoints */ +#define TRANS_ABSTRACT (1<<5) /* This previously meant that abstract sockets should be used available. For security + * reasons, this is now a no-op on the client side, but it is still supported for servers. + */ +#define TRANS_NOXAUTH (1<<6) /* Don't verify authentication (because it's secure some other way at the OS layer) */ +#define TRANS_RECEIVED (1<<7) /* The fd for this has already been opened by someone else. */ + +/* Flags to preserve when setting others */ +#define TRANS_KEEPFLAGS (TRANS_NOUNLINK|TRANS_ABSTRACT) + +#ifdef XTRANS_TRANSPORT_C /* only provide static function prototypes when + building the transport.c file that has them in */ + +#ifdef __clang__ +/* Not all clients make use of all provided statics */ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-function" +#endif + +/* + * readv() and writev() don't exist or don't work correctly on some + * systems, so they may be emulated. + */ + +#ifdef WIN32 + +#define READV(ciptr, iov, iovcnt) _XSERVTransReadV(ciptr, iov, iovcnt) + +static int _XSERVTransReadV( + XtransConnInfo, /* ciptr */ + struct iovec *, /* iov */ + int /* iovcnt */ +); + +#else + +#define READV(ciptr, iov, iovcnt) readv(ciptr->fd, iov, iovcnt) + +#endif /* WIN32 */ + + +#ifdef WIN32 + +#define WRITEV(ciptr, iov, iovcnt) _XSERVTransWriteV(ciptr, iov, iovcnt) + +static int _XSERVTransWriteV( + XtransConnInfo, /* ciptr */ + struct iovec *, /* iov */ + int /* iovcnt */ +); + +#else + +#define WRITEV(ciptr, iov, iovcnt) writev(ciptr->fd, iov, iovcnt) + +#endif /* WIN32 */ + +static int trans_mkdir ( + const char *, /* path */ + int /* mode */ +); + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif + +/* + * Some XTRANSDEBUG stuff + */ + +#ifdef XTRANSDEBUG +#include + +#include "os.h" +#endif /* XTRANSDEBUG */ + +static inline void _X_ATTRIBUTE_PRINTF(2, 3) +prmsg(int lvl, const char *f, ...) +{ +#ifdef XTRANSDEBUG + va_list args; + + va_start(args, f); + if (lvl <= XTRANSDEBUG) { + int saveerrno = errno; + + ErrorF("%s", __xtransname); + VErrorF(f, args); + +# ifdef XTRANSDEBUGTIMESTAMP + { + struct timeval tp; + gettimeofday(&tp, 0); + ErrorF("timestamp (ms): %d\n", + tp.tv_sec * 1000 + tp.tv_usec / 1000); + } +# endif + errno = saveerrno; + } + va_end(args); +#endif /* XTRANSDEBUG */ +} + +#endif /* XTRANS_TRANSPORT_C */ + +#endif /* _XTRANSINT_H_ */ diff --git a/os/Xtranslcl.c b/os/Xtranslcl.c new file mode 100644 index 000000000..6ddd7f7d0 --- /dev/null +++ b/os/Xtranslcl.c @@ -0,0 +1,911 @@ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA + * + * All Rights Reserved + * + * 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 NCR not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. NCR makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NCR 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. + */ + +/* + * + * The connection code/ideas in lib/X and server/os for SVR4/Intel + * environments was contributed by the following companies/groups: + * + * MetroLink Inc + * NCR + * Pittsburgh Powercomputing Corporation (PPc)/Quarterdeck Office Systems + * SGCS + * Unix System Laboratories (USL) / Novell + * XFree86 + * + * The goal is to have common connection code among all SVR4/Intel vendors. + * + * ALL THE ABOVE COMPANIES DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS + * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, + * IN NO EVENT SHALL THESE COMPANIES * 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. + */ + +#include +#include +#include +#include +#include +#if defined(SVR4) || defined(__SVR4) +#include +#endif +# include +#include +#include + +/* + * The local transports should be treated the same as a UNIX domain socket + * wrt authentication, etc. Because of this, we will use struct sockaddr_un + * for the address format. This will simplify the code in other places like + * The X Server. + */ + +#include +#include + + +/* Types of local connections supported: + * - PTS + * - named pipes + */ +#if defined(SVR4) || defined(__SVR4) +# define LOCAL_TRANS_NAMED +#endif + +static int _XSERVTransLocalClose(XtransConnInfo ciptr); + +/* + * These functions actually implement the local connection mechanisms. + */ + +/* Type Not Supported */ + +static int _XSERVTransOpenFail(XtransConnInfo ciptr _X_UNUSED, const char *port _X_UNUSED) +{ + return -1; +} + +static int ReopenFail(XtransConnInfo ciptr _X_UNUSED, int fd _X_UNUSED, + const char *port _X_UNUSED) +{ + return 0; +} + +#if XTRANS_SEND_FDS +static int _XSERVTransLocalRecvFdInvalid(XtransConnInfo ciptr) +{ + errno = EINVAL; + return -1; +} + +static int LocalSendFdInvalid(XtransConnInfo ciptr, int fd, int do_close) +{ + errno = EINVAL; + return -1; +} +#endif + + +static int _XSERVTransFillAddrInfo(XtransConnInfo ciptr, + const char *sun_path, const char *peer_sun_path) +{ + struct sockaddr_un *sunaddr; + struct sockaddr_un *p_sunaddr; + + ciptr->family = AF_UNIX; + ciptr->addrlen = sizeof (struct sockaddr_un); + + if ((sunaddr = malloc (ciptr->addrlen)) == NULL) + { + prmsg(1,"FillAddrInfo: failed to allocate memory for addr\n"); + return 0; + } + + sunaddr->sun_family = AF_UNIX; + + if (strlen(sun_path) > sizeof(sunaddr->sun_path) - 1) { + prmsg(1, "FillAddrInfo: path too long\n"); + free((char *) sunaddr); + return 0; + } + strcpy (sunaddr->sun_path, sun_path); +#if defined(BSD44SOCKETS) + sunaddr->sun_len = strlen (sunaddr->sun_path); +#endif + + ciptr->addr = (char *) sunaddr; + + ciptr->peeraddrlen = sizeof (struct sockaddr_un); + + if ((p_sunaddr = malloc (ciptr->peeraddrlen)) == NULL) + { + prmsg(1, + "FillAddrInfo: failed to allocate memory for peer addr\n"); + free (sunaddr); + ciptr->addr = NULL; + + return 0; + } + + p_sunaddr->sun_family = AF_UNIX; + + if (strlen(peer_sun_path) > sizeof(p_sunaddr->sun_path) - 1) { + prmsg(1, "FillAddrInfo: peer path too long\n"); + free((char *) p_sunaddr); + return 0; + } + strcpy (p_sunaddr->sun_path, peer_sun_path); +#if defined(BSD44SOCKETS) + p_sunaddr->sun_len = strlen (p_sunaddr->sun_path); +#endif + + ciptr->peeraddr = (char *) p_sunaddr; + + return 1; +} + + +#define X_STREAMS_DIR "/tmp/.X11-pipe" + +#define NAMEDNODENAME "/tmp/.X11-pipe/X" + +#ifdef LOCAL_TRANS_NAMED + +/* NAMED */ + +static int _XSERVTransNAMEDOpenPipe(const char *server_path) +{ + int fd, pipefd[2]; + struct stat sbuf; + int mode; + + prmsg(2,"NAMEDOpenPipe(%s)\n", server_path); + +#ifdef HAS_STICKY_DIR_BIT + mode = 01777; +#else + mode = 0777; +#endif + if (trans_mkdir(X_STREAMS_DIR, mode) == -1) { + prmsg (1, "NAMEDOpenPipe: mkdir(%s) failed, errno = %d\n", + X_STREAMS_DIR, errno); + return(-1); + } + + if(stat(server_path, &sbuf) != 0) { + if (errno == ENOENT) { + if ((fd = creat(server_path, (mode_t)0666)) == -1) { + prmsg(1, "NAMEDOpenPipe: Can't open %s\n", server_path); + return(-1); + } + if (fchmod(fd, (mode_t)0666) < 0) { + prmsg(1, "NAMEDOpenPipe: Can't chmod %s\n", server_path); + close(fd); + return(-1); + } + close(fd); + } else { + prmsg(1, "NAMEDOpenPipe: stat on %s failed\n", server_path); + return(-1); + } + } + + if( pipe(pipefd) != 0) { + prmsg(1, "NAMEDOpenPipe: pipe() failed, errno=%d\n",errno); + return(-1); + } + + if( ioctl(pipefd[0], I_PUSH, "connld") != 0) { + prmsg(1, "NAMEDOpenPipe: ioctl(I_PUSH,\"connld\") failed, errno=%d\n",errno); + close(pipefd[0]); + close(pipefd[1]); + return(-1); + } + + if( fattach(pipefd[0], server_path) != 0) { + prmsg(1, "NAMEDOpenPipe: fattach(%s) failed, errno=%d\n", server_path,errno); + close(pipefd[0]); + close(pipefd[1]); + return(-1); + } + + return(pipefd[1]); +} + +static int NAMEDOpenServer(XtransConnInfo ciptr, const char *port) +{ + int fd; + char server_path[64]; + + prmsg(2,"NAMEDOpenServer(%s)\n", port); + + if ( port && *port ) { + if( *port == '/' ) { /* A full pathname */ + (void) snprintf(server_path, sizeof(server_path), "%s", port); + } else { + (void) snprintf(server_path, sizeof(server_path), "%s%s", + NAMEDNODENAME, port); + } + } else { + (void) snprintf(server_path, sizeof(server_path), "%s%ld", + NAMEDNODENAME, (long)getpid()); + } + + fd = _XSERVTransNAMEDOpenPipe(server_path); + if (fd < 0) { + return -1; + } + + /* + * Everything looks good: fill in the XtransConnInfo structure. + */ + + if (_XSERVTransFillAddrInfo (ciptr, server_path, server_path) == 0) + { + prmsg(1,"NAMEDOpenServer: failed to fill in addr info\n"); + _XSERVTransLocalClose(ciptr); + return -1; + } + + return fd; +} + +static int NAMEDResetListener (XtransConnInfo ciptr) + +{ + struct sockaddr_un *sockname=(struct sockaddr_un *) ciptr->addr; + struct stat statb; + + prmsg(2,"NAMEDResetListener(%p, %d)\n", (void *) ciptr, ciptr->fd); + + if (ciptr->fd != -1) { + /* + * see if the pipe has disappeared + */ + + if (stat (sockname->sun_path, &statb) == -1 || + (statb.st_mode & S_IFMT) != S_IFIFO) { + prmsg(3, "Pipe %s trashed, recreating\n", sockname->sun_path); + _XSERVTransLocalClose(ciptr); + ciptr->fd = _XSERVTransNAMEDOpenPipe(sockname->sun_path); + if (ciptr->fd >= 0) + return TRANS_RESET_NEW_FD; + else + return TRANS_CREATE_LISTENER_FAILED; + } + } + return TRANS_RESET_NOOP; +} + +static int _XSERVTransNAMEDAccept( + XtransConnInfo ciptr, XtransConnInfo newciptr, int *status) +{ + struct strrecvfd str; + + prmsg(2,"NAMEDAccept(%p->%d)\n", (void *) ciptr, ciptr->fd); + + if( ioctl(ciptr->fd, I_RECVFD, &str ) < 0 ) { + prmsg(1, "NAMEDAccept: ioctl(I_RECVFD) failed, errno=%d\n", errno); + *status = TRANS_ACCEPT_MISC_ERROR; + return(-1); + } + + /* + * Everything looks good: fill in the XtransConnInfo structure. + */ + newciptr->family=ciptr->family; + newciptr->addrlen=ciptr->addrlen; + if( (newciptr->addr = malloc(newciptr->addrlen)) == NULL ) { + prmsg(1, + "NAMEDAccept: failed to allocate memory for pipe addr\n"); + close(str.fd); + *status = TRANS_ACCEPT_BAD_MALLOC; + return -1; + } + + memcpy(newciptr->addr,ciptr->addr,newciptr->addrlen); + + newciptr->peeraddrlen=newciptr->addrlen; + if( (newciptr->peeraddr = malloc(newciptr->peeraddrlen)) == NULL ) { + prmsg(1, + "NAMEDAccept: failed to allocate memory for peer addr\n"); + free(newciptr->addr); + close(str.fd); + *status = TRANS_ACCEPT_BAD_MALLOC; + return -1; + } + + memcpy(newciptr->peeraddr,newciptr->addr,newciptr->peeraddrlen); + + *status = 0; + + return str.fd; +} + +#endif /* LOCAL_TRANS_NAMED */ + +#ifdef LOCAL_TRANS_NAMED + +static int _XSERVTransNAMEDReopenServer( + XtransConnInfo ciptr, int fd _X_UNUSED, const char *port) +{ + char server_path[64]; + + prmsg(2,"NAMEDReopenServer(%s)\n", port); + + if ( port && *port ) { + if( *port == '/' ) { /* A full pathname */ + snprintf(server_path, sizeof(server_path),"%s", port); + } else { + snprintf(server_path, sizeof(server_path), "%s%s", + NAMEDNODENAME, port); + } + } else { + snprintf(server_path, sizeof(server_path), "%s%ld", + NAMEDNODENAME, (long)getpid()); + } + + if (_XSERVTransFillAddrInfo) (ciptr, server_path, server_path) == 0) + { + prmsg(1,"NAMEDReopenServer: failed to fill in addr info\n"); + return 0; + } + + return 1; +} + +#endif /* LOCAL_TRANS_NAMED */ + +/* + * This table contains all of the entry points for the different local + * connection mechanisms. + */ + +typedef struct _LOCALtrans2dev { + const char *transname; + int (*devcotsopenserver)( + XtransConnInfo, const char * /*port*/ +); + int (*devcltsopenserver)( + XtransConnInfo, const char * /*port*/ +); + + int (*devcotsreopenserver)( + XtransConnInfo, + int, /* fd */ + const char * /* port */ +); + + int (*devcltsreopenserver)( + XtransConnInfo, + int, /* fd */ + const char * /* port */ +); + + int (*devreset)( + XtransConnInfo /* ciptr */ +); + + int (*devaccept)( + XtransConnInfo, XtransConnInfo, int * +); + +} LOCALtrans2dev; + +static LOCALtrans2dev LOCALtrans2devtab[] = { +{ + "", + _XSERVTransNAMEDOpenServer, + _XSERVTransOpenFail, + _XSERVTransNAMEDReopenServer, + _XSERVTransReopenFail, + _XSERVTransNAMEDResetListener, + _XSERVTransNAMEDAccept +}, +{ + "local", + _XSERVTransNAMEDOpenServer, + _XSERVTransOpenFail, + _XSERVTransNAMEDReopenServer, + _XSERVTransReopenFail, + _XSERVTrans_NAMEDResetListener, + _XSERVTransNAMEDAccept +}, +#ifdef LOCAL_TRANS_NAMED +{ + "named", + _XSERVTransNAMEDOpenServer, + _XSERVTransOpenFail, + _XSERVTransNAMEDReopenServer, + _XSERVTransReopenFail, + _XSERVTransNAMEDResetListener, + _XSERVTransNAMEDAccept +}, +{ + "pipe", + _XSERVTransNAMEDOpenServer, + _XSERVTransOpenFail, + _XSERVTransNAMEDReopenServer, + _XSERVTransReopenFail, + _XSERVTransNAMEDResetListener, + _XSERVTransNAMEDAccept +}, +#endif /* LOCAL_TRANS_NAMED */ + + +}; + +#define NUMTRANSPORTS (sizeof(LOCALtrans2devtab)/sizeof(LOCALtrans2dev)) + +static const char *XLOCAL=NULL; +static char *workingXLOCAL=NULL; +static char *freeXLOCAL=NULL; + +#define DEF_XLOCAL "UNIX:NAMED" + +static void _XSERVTransLocalInitTransports(const char *protocol) +{ + prmsg(3,"LocalInitTransports(%s)\n", protocol); + + if( strcmp(protocol,"local") && strcmp(protocol,"LOCAL") ) + { + workingXLOCAL = freeXLOCAL = strdup (protocol); + } + else { + XLOCAL = getenv("XLOCAL"); + if(XLOCAL==NULL) + XLOCAL=DEF_XLOCAL; + workingXLOCAL = freeXLOCAL = strdup (XLOCAL); + } +} + +static void _XSERVTransLocalEndTransports(void) +{ + prmsg(3,"LocalEndTransports()\n"); + free(freeXLOCAL); + freeXLOCAL = NULL; +} + +#define TYPEBUFSIZE 32 + +static XtransConnInfo _XSERVTransLocalOpenServer( + int type, const char *protocol, + const char *host _X_UNUSED, const char *port) +{ + XtransConnInfo ciptr; + + prmsg(2,"LocalOpenServer(%d,%s,%s)\n", type, protocol, port); + + /* + * For X11, the port will be in the format xserverN where N is the + * display number. All of the local connections just need to know + * the display number because they don't do any name resolution on + * the port. This just truncates port to the display portion. + */ + + if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL ) + { + prmsg(1,"LocalOpenServer: calloc(1,%lu) failed\n", + sizeof(struct _XtransConnInfo)); + return NULL; + } + + for (unsigned int i = 1; i < NUMTRANSPORTS; i++) + { + if( strcmp(protocol,LOCALtrans2devtab[i].transname) != 0 ) + continue; + switch( type ) + { + case XTRANS_OPEN_COTS_CLIENT: + prmsg(1, + "LocalOpenServer: Should not be opening a client with this function\n"); + break; + case XTRANS_OPEN_COTS_SERVER: + ciptr->fd=LOCALtrans2devtab[i].devcotsopenserver(ciptr,port); + break; + default: + prmsg(1,"LocalOpenServer: Unknown Open type %d\n", + type ); + } + if( ciptr->fd >= 0 ) { + ciptr->priv=(char *)&LOCALtrans2devtab[i]; + ciptr->index=i; + ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS); + return ciptr; + } + } + + free(ciptr); + return NULL; +} + +static XtransConnInfo _XSERVTransLocalReopenServer(int type, int index, + int fd, const char *port) +{ + XtransConnInfo ciptr; + int stat = 0; + + prmsg(2,"LocalReopenServer(%d,%d,%d)\n", type, index, fd); + + if( (ciptr = calloc(1,sizeof(struct _XtransConnInfo))) == NULL ) + { + prmsg(1,"LocalReopenServer: calloc(1,%lu) failed\n", + sizeof(struct _XtransConnInfo)); + return NULL; + } + + ciptr->fd = fd; + + switch( type ) + { + case XTRANS_OPEN_COTS_SERVER: + stat = LOCALtrans2devtab[index].devcotsreopenserver(ciptr,fd,port); + break; + default: + prmsg(1,"LocalReopenServer: Unknown Open type %d\n", + type ); + } + + if( stat > 0 ) { + ciptr->priv=(char *)&LOCALtrans2devtab[index]; + ciptr->index=index; + ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS); + return ciptr; + } + + free(ciptr); + return NULL; +} + +/* + * This is the Local implementation of the X Transport service layer + */ + +static XtransConnInfo _XSERVTransLocalOpenCOTSServer( + Xtransport *thistrans, const char *protocol, + const char *host, const char *port) +{ + char *typetocheck = NULL; + int found = 0; + + prmsg(2,"LocalOpenCOTSServer(%s,%s,%s)\n",protocol,host,port); + + /* Check if this local type is in the XLOCAL list */ + _XSERVTransLocalInitTransports("local"); + typetocheck = workingXLOCAL; + while (typetocheck && !found) { +#ifndef HAVE_STRCASECMP + int j; + char typebuf[TYPEBUFSIZE]; +#endif + + workingXLOCAL = strchr(workingXLOCAL, ':'); + if (workingXLOCAL && *workingXLOCAL) + *workingXLOCAL++ = '\0'; +#ifndef HAVE_STRCASECMP + strncpy(typebuf, typetocheck, TYPEBUFSIZE); + for (j = 0; j < TYPEBUFSIZE; j++) + if (isupper(typebuf[j])) + typebuf[j] = tolower(typebuf[j]); + if (!strcmp(thistrans->TransName, typebuf)) +#else + if (!strcasecmp(thistrans->TransName, typetocheck)) +#endif + found = 1; + typetocheck = workingXLOCAL; + } + _XSERVTransLocalEndTransports(); + + if (!found) { + prmsg(3,"LocalOpenCOTSServer: disabling %s\n",thistrans->TransName); + thistrans->flags |= TRANS_DISABLED; + return NULL; + } + + return _XSERVTransLocalOpenServer(XTRANS_OPEN_COTS_SERVER, protocol, host, port); +} + +static XtransConnInfo _XSERVTransLocalReopenCOTSServer( + Xtransport *thistrans, int fd, const char *port) +{ + unsigned int index; + + prmsg(2,"LocalReopenCOTSServer(%d,%s)\n", fd, port); + + for(index=1;indexTransName, + LOCALtrans2devtab[index].transname) == 0 ) + break; + } + + if (index >= NUMTRANSPORTS) + { + return (NULL); + } + + return _XSERVTransLocalReopenServer(XTRANS_OPEN_COTS_SERVER, + index, fd, port); +} + +static int _XSERVTransLocalSetOption(XtransConnInfo ciptr, int option, int arg) +{ + prmsg(2,"LocalSetOption(%d,%d,%d)\n",ciptr->fd,option,arg); + + return -1; +} + +static int _XSERVTransLocalCreateListener( + XtransConnInfo ciptr, const char *port, unsigned int flags _X_UNUSED) +{ + prmsg(2,"LocalCreateListener(%p->%d,%s)\n", (void *) ciptr, ciptr->fd, port); + + return 0; +} + +static int _XSERVTransLocalResetListener(XtransConnInfo ciptr) +{ + LOCALtrans2dev *transptr; + + prmsg(2,"LocalResetListener(%p)\n", (void *) ciptr); + + transptr=(LOCALtrans2dev *)ciptr->priv; + if (transptr->devreset != NULL) { + return transptr->devreset(ciptr); + } + return TRANS_RESET_NOOP; +} + + +static XtransConnInfo _XSERVTransLocalAccept(XtransConnInfo ciptr, int *status) +{ + XtransConnInfo newciptr; + LOCALtrans2dev *transptr; + + prmsg(2,"LocalAccept(%p->%d)\n", (void *) ciptr, ciptr->fd); + + transptr=(LOCALtrans2dev *)ciptr->priv; + + if( (newciptr = calloc(1,sizeof(struct _XtransConnInfo)))==NULL ) + { + prmsg(1,"LocalAccept: calloc(1,%lu) failed\n", + sizeof(struct _XtransConnInfo)); + *status = TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + + newciptr->fd=transptr->devaccept(ciptr,newciptr,status); + + if( newciptr->fd < 0 ) + { + free(newciptr); + return NULL; + } + + newciptr->priv=(char *)transptr; + newciptr->index = ciptr->index; + + *status = 0; + + return newciptr; +} + +static int _XSERVTransLocalBytesReadable(XtransConnInfo ciptr, BytesReadable_t *pend ) +{ + prmsg(2,"LocalBytesReadable(%p->%d,%p)\n", + (void *) ciptr, ciptr->fd, (void *) pend); + + return ioctl(ciptr->fd, FIONREAD, (char *)pend); +} + +static int _XSERVTransLocalRead(XtransConnInfo ciptr, char *buf, int size) +{ + prmsg(2,"LocalRead(%d,%p,%d)\n", ciptr->fd, (void *) buf, size ); + + return read(ciptr->fd,buf,size); +} + +static int _XSERVTransLocalWrite(XtransConnInfo ciptr, const char *buf, int size) +{ + prmsg(2,"LocalWrite(%d,%p,%d)\n", ciptr->fd, (const void *) buf, size ); + + return write(ciptr->fd,buf,size); +} + +static int _XSERVTransLocalReadv(XtransConnInfo ciptr, struct iovec *buf, int size) +{ + prmsg(2,"LocalReadv(%d,%p,%d)\n", ciptr->fd, (void *) buf, size ); + + return READV(ciptr,buf,size); +} + +static int _XSERVTransLocalWritev(XtransConnInfo ciptr, struct iovec *buf, int size) +{ + prmsg(2,"LocalWritev(%d,%p,%d)\n", ciptr->fd, (const void *) buf, size ); + + return WRITEV(ciptr,buf,size); +} + +static int _XSERVTransLocalDisconnect(XtransConnInfo ciptr) +{ + prmsg(2,"LocalDisconnect(%p->%d)\n", (void *) ciptr, ciptr->fd); + + return 0; +} + +static int _XSERVTransLocalClose(XtransConnInfo ciptr) +{ + struct sockaddr_un *sockname=(struct sockaddr_un *) ciptr->addr; + int ret; + + prmsg(2,"LocalClose(%p->%d)\n", (void *) ciptr, ciptr->fd ); + + ret=close(ciptr->fd); + + if(ciptr->flags + && sockname + && sockname->sun_family == AF_UNIX + && sockname->sun_path[0] ) + { + if (!(ciptr->flags & TRANS_NOUNLINK)) + unlink(sockname->sun_path); + } + + return ret; +} + +static int _XSERVTransLocalCloseForCloning(XtransConnInfo ciptr) +{ + int ret; + + prmsg(2,"LocalCloseForCloning(%p->%d)\n", (void *) ciptr, ciptr->fd ); + + /* Don't unlink path */ + + ret=close(ciptr->fd); + + return ret; +} + + +/* + * MakeAllCOTSServerListeners() will go through the entire Xtransports[] + * array defined in Xtrans.c and try to OpenCOTSServer() for each entry. + * We will add duplicate entries to that table so that the OpenCOTSServer() + * function will get called once for each type of local transport. + * + * The TransName is in lowercase, so it will never match during a normal + * call to SelectTransport() in Xtrans.c. + */ +static const char * local_aliases[] = { + "named", + "pipe", /* compatibility with Solaris Xlib */ + NULL }; + +static Xtransport _XSERVTransLocalFuncs = { + /* Local Interface */ + "local", + TRANS_ALIAS | TRANS_LOCAL, + local_aliases, + _XSERVTransLocalOpenCOTSServer, + _XSERVTransLocalReopenCOTSServer, + _XSERVTransLocalSetOption, + _XSERVTransLocalCreateListener, + _XSERVTransLocalResetListener, + _XSERVTransLocalAccept, + _XSERVTransLocalBytesReadable, + _XSERVTransLocalRead, + _XSERVTransLocalWrite, + _XSERVTransLocalReadv, + _XSERVTransLocalWritev, +#if XTRANS_SEND_FDS + _XSERVTransLocalSendFdInvalid, + _XSERVTransLocalRecvFdInvalid, +#endif + _XSERVTransLocalDisconnect, + _XSERVTransLocalClose, + _XSERVTransLocalCloseForCloning, +}; + + +#ifdef LOCAL_TRANS_NAMED + +static Xtransport _XSERVTransNAMEDFuncs = { + /* Local Interface */ + "named", + TRANS_LOCAL, + NULL, + _XSERVTransLocalOpenCOTSServer, + _XSERVTransLocalReopenCOTSServer, + _XSERVTransLocalSetOption, + _XSERVTransLocalCreateListener, + _XSERVTransLocalResetListener, + _XSERVTransLocalAccept, + _XSERVTransLocalBytesReadable, + _XSERVTransLocalRead, + _XSERVTransLocalWrite, + _XSERVTransLocalReadv, + _XSERVTransLocalWritev, +#if XTRANS_SEND_FDS + _XSERVTransLocalSendFdInvalid, + _XSERVTransLocalRecvFdInvalid, +#endif + _XSERVTransLocalDisconnect, + _XSERVTransLocalClose, + _XSERVTransLocalCloseForCloning, +}; + +static Xtransport _XSERVTransPIPEFuncs = { + /* Local Interface */ + "pipe", + TRANS_ALIAS | TRANS_LOCAL, + NULL, + _XSERVTransLocalOpenCOTSServer, + _XSERVTransLocalReopenCOTSServer, + _XSERVTransLocalSetOption, + _XSERVTransLocalCreateListener, + _XSERVTransLocalResetListener, + _XSERVTransLocalAccept, + _XSERVTransLocalBytesReadable, + _XSERVTransLocalRead, + _XSERVTransLocalWrite, + _XSERVTransLocalReadv, + _XSERVTransLocalWritev, +#if XTRANS_SEND_FDS + _XSERVTransLocalSendFdInvalid, + _XSERVTransLocalRecvFdInvalid, +#endif + _XSERVTransLocalDisconnect, + _XSERVTransLocalClose, + _XSERVTransLocalCloseForCloning, +}; +#endif /* LOCAL_TRANS_NAMED */ diff --git a/os/Xtranssock.c b/os/Xtranssock.c new file mode 100644 index 000000000..88b09ddf1 --- /dev/null +++ b/os/Xtranssock.c @@ -0,0 +1,1712 @@ +/* + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of the copyright holders shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from the copyright holders. + + * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA + * + * All Rights Reserved + * + * 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 NCR not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. NCR makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NCR 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. + */ + +#include +#ifdef XTHREADS +#include +#endif + +#ifndef WIN32 + +#if defined(TCPCONN) || defined(UNIXCONN) +#include +#include +#include +#endif + +#if defined(TCPCONN) || defined(UNIXCONN) +#define X_INCLUDE_NETDB_H +#define XOS_USE_NO_LOCKING +#include +#endif + +#ifdef UNIXCONN +#include +#include +#endif + + +#ifndef NO_TCP_H +#if defined(linux) || defined(__GLIBC__) +#include +#endif /* osf */ +#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) +#include +#include +#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __DragonFly__ */ +#include +#endif /* !NO_TCP_H */ + +#include +#if defined(SVR4) || defined(__SVR4) +#include +#endif + +#include + +#else /* !WIN32 */ + +#include +#include +#include +#undef close +#define close closesocket +#define ECONNREFUSED WSAECONNREFUSED +#define EADDRINUSE WSAEADDRINUSE +#define EPROTOTYPE WSAEPROTOTYPE +#undef EWOULDBLOCK +#define EWOULDBLOCK WSAEWOULDBLOCK +#define EINPROGRESS WSAEINPROGRESS +#undef EINTR +#define EINTR WSAEINTR +#define X_INCLUDE_NETDB_H +#define XOS_USE_MTSAFE_NETDBAPI +#include +#endif /* WIN32 */ + +#if defined(SO_DONTLINGER) && defined(SO_LINGER) +#undef SO_DONTLINGER +#endif + +/* others don't need this */ +#define SocketInitOnce() /**/ + +#ifdef __linux__ +#define HAVE_ABSTRACT_SOCKETS +#endif + +#define MIN_BACKLOG 128 +#ifdef SOMAXCONN +#if SOMAXCONN > MIN_BACKLOG +#define BACKLOG SOMAXCONN +#endif +#endif +#ifndef BACKLOG +#define BACKLOG MIN_BACKLOG +#endif + +#if defined(IPv6) && !defined(AF_INET6) +#error "Cannot build IPv6 support without AF_INET6" +#endif + +/* Temporary workaround for consumers whose configure scripts were + generated with pre-1.6 versions of xtrans.m4 */ +#if defined(IPv6) && !defined(HAVE_GETADDRINFO) +#define HAVE_GETADDRINFO +#endif + +/* + * This is the Socket implementation of the X Transport service layer + * + * This file contains the implementation for both the UNIX and INET domains, + * and can be built for either one, or both. + * + */ + +typedef struct _Sockettrans2dev { + const char *transname; + int family; + int devcotsname; + int devcltsname; + int protocol; +} Sockettrans2dev; + +/* As documented in the X(7) man page: + * tcp TCP over IPv4 or IPv6 + * inet TCP over IPv4 only + * inet6 TCP over IPv6 only + * unix UNIX Domain Sockets (same host only) + * local Platform preferred local connection method + */ +static Sockettrans2dev Sockettrans2devtab[] = { +#ifdef TCPCONN + {"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, +#ifndef IPv6 + {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, +#else /* IPv6 */ + {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0}, + {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */ + {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0}, +#endif +#endif /* TCPCONN */ +#ifdef UNIXCONN + {"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0}, +#if !defined(LOCALCONN) + {"local",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0}, +#endif /* !LOCALCONN */ +#endif /* UNIXCONN */ +}; + +#define NUMSOCKETFAMILIES (sizeof(Sockettrans2devtab)/sizeof(Sockettrans2dev)) + +#ifdef TCPCONN +static int _XSERVTransSocketINETClose (XtransConnInfo ciptr); +#endif + +static int +is_numeric (const char *str) +{ + int i; + + for (i = 0; i < (int) strlen (str); i++) + if (!isdigit (str[i])) + return (0); + + return (1); +} + +#ifdef UNIXCONN + + +#define UNIX_PATH "/tmp/.X11-unix/X" +#define UNIX_DIR "/tmp/.X11-unix" + +#endif /* UNIXCONN */ + +#define PORTBUFSIZE 32 + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN 255 +#endif + +#if defined(HAVE_SOCKLEN_T) || defined(IPv6) +# define SOCKLEN_T socklen_t +#elif defined(SVR4) || defined(__SVR4) +# define SOCKLEN_T size_t +#else +# define SOCKLEN_T int +#endif + +/* + * These are some utility function used by the real interface function below. + */ + +static int _XSERVTransSocketSelectFamily (int first, const char *family) +{ + int i; + + prmsg (3,"SocketSelectFamily(%s)\n", family); + + for (i = first + 1; i < (int)NUMSOCKETFAMILIES; i++) + { + if (!strcmp (family, Sockettrans2devtab[i].transname)) + return i; + } + + return (first == -1 ? -2 : -1); +} + + +/* + * This function gets the local address of the socket and stores it in the + * XtransConnInfo structure for the connection. + */ + +static int _XSERVTransSocketINETGetAddr (XtransConnInfo ciptr) +{ +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE + struct sockaddr_storage sockname; +#else + struct sockaddr_in sockname; +#endif + void *socknamePtr = &sockname; + SOCKLEN_T namelen = sizeof(sockname); + + prmsg (3,"SocketINETGetAddr(%p)\n", (void *) ciptr); + + memset(socknamePtr, 0, namelen); + + if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr, + (void *)&namelen) < 0) + { +#ifdef WIN32 + errno = WSAGetLastError(); +#endif + prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n", + EGET()); + return -1; + } + + /* + * Everything looks good: fill in the XtransConnInfo structure. + */ + + if ((ciptr->addr = malloc (namelen)) == NULL) + { + prmsg (1, + "SocketINETGetAddr: Can't allocate space for the addr\n"); + return -1; + } + + ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family; + ciptr->addrlen = namelen; + memcpy (ciptr->addr, socknamePtr, ciptr->addrlen); + + return 0; +} + + +/* + * This function gets the remote address of the socket and stores it in the + * XtransConnInfo structure for the connection. + */ + +static int _XSERVTransSocketINETGetPeerAddr (XtransConnInfo ciptr) +{ +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE + struct sockaddr_storage sockname; +#else + struct sockaddr_in sockname; +#endif + void *socknamePtr = &sockname; + SOCKLEN_T namelen = sizeof(sockname); + + memset(socknamePtr, 0, namelen); + + prmsg (3,"SocketINETGetPeerAddr(%p)\n", (void *) ciptr); + + if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr, + (void *)&namelen) < 0) + { +#ifdef WIN32 + errno = WSAGetLastError(); +#endif + prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n", + EGET()); + return -1; + } + + /* + * Everything looks good: fill in the XtransConnInfo structure. + */ + + if ((ciptr->peeraddr = malloc (namelen)) == NULL) + { + prmsg (1, + "SocketINETGetPeerAddr: Can't allocate space for the addr\n"); + return -1; + } + + ciptr->peeraddrlen = namelen; + memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen); + + return 0; +} + + +static XtransConnInfo _XSERVTransSocketOpen (int i, int type) +{ + XtransConnInfo ciptr; + + prmsg (3,"SocketOpen(%d,%d)\n", i, type); + + if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) + { + prmsg (1, "SocketOpen: malloc failed\n"); + return NULL; + } + + ciptr->fd = socket(Sockettrans2devtab[i].family, type, + Sockettrans2devtab[i].protocol); + +#ifndef WIN32 +#if !defined(USE_POLL) + if (ciptr->fd >= sysconf(_SC_OPEN_MAX)) + { + prmsg (2, "SocketOpen: socket() returned out of range fd %d\n", + ciptr->fd); + close (ciptr->fd); + ciptr->fd = -1; + } +#endif +#endif + + if (ciptr->fd < 0) { +#ifdef WIN32 + errno = WSAGetLastError(); +#endif + prmsg (2, "SocketOpen: socket() failed for %s\n", + Sockettrans2devtab[i].transname); + + free (ciptr); + return NULL; + } + +#ifdef TCP_NODELAY + if (Sockettrans2devtab[i].family == AF_INET +#ifdef IPv6 + || Sockettrans2devtab[i].family == AF_INET6 +#endif + ) + { + /* + * turn off TCP coalescence for INET sockets + */ + + int tmp = 1; + setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY, + (char *) &tmp, sizeof (int)); + } +#endif + + /* + * Some systems provide a really small default buffer size for + * UNIX sockets. Bump it up a bit such that large transfers don't + * proceed at glacial speed. + */ +#ifdef SO_SNDBUF + if (Sockettrans2devtab[i].family == AF_UNIX) + { + SOCKLEN_T len = sizeof (int); + int val; + + if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF, + (char *) &val, &len) == 0 && val < 64 * 1024) + { + val = 64 * 1024; + setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF, + (char *) &val, sizeof (int)); + } + } +#endif + + return ciptr; +} + +static XtransConnInfo _XSERVTransSocketReopen ( + int i _X_UNUSED, int type, int fd, const char *port) +{ + XtransConnInfo ciptr; + int portlen; + struct sockaddr *addr; + size_t addrlen; + + prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port); + + if (port == NULL) { + prmsg (1, "SocketReopen: port was null!\n"); + return NULL; + } + + portlen = strlen(port) + 1; // include space for trailing null +#ifdef SOCK_MAXADDRLEN + if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) { + prmsg (1, "SocketReopen: invalid portlen %d\n", portlen); + return NULL; + } + if (portlen < 14) portlen = 14; +#else + if (portlen < 0 || portlen > 14) { + prmsg (1, "SocketReopen: invalid portlen %d\n", portlen); + return NULL; + } +#endif /*SOCK_MAXADDRLEN*/ + + if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) + { + prmsg (1, "SocketReopen: malloc(ciptr) failed\n"); + return NULL; + } + + ciptr->fd = fd; + + addrlen = portlen + offsetof(struct sockaddr, sa_data); + if ((addr = calloc (1, addrlen)) == NULL) { + prmsg (1, "SocketReopen: malloc(addr) failed\n"); + free (ciptr); + return NULL; + } + ciptr->addr = (char *) addr; + ciptr->addrlen = addrlen; + + if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) { + prmsg (1, "SocketReopen: malloc(portaddr) failed\n"); + free (addr); + free (ciptr); + return NULL; + } + ciptr->peeraddrlen = addrlen; + + /* Initialize ciptr structure as if it were a normally-opened unix socket */ + ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK; +#ifdef BSD44SOCKETS + addr->sa_len = addrlen; +#endif + addr->sa_family = AF_UNIX; +#if defined(HAVE_STRLCPY) || defined(HAS_STRLCPY) + strlcpy(addr->sa_data, port, portlen); +#else + strncpy(addr->sa_data, port, portlen); +#endif + ciptr->family = AF_UNIX; + memcpy(ciptr->peeraddr, ciptr->addr, addrlen); + ciptr->port = rindex(addr->sa_data, ':'); + if (ciptr->port == NULL) { + if (is_numeric(addr->sa_data)) { + ciptr->port = addr->sa_data; + } + } else if (ciptr->port[0] == ':') { + ciptr->port++; + } + /* port should now point to portnum or NULL */ + return ciptr; +} + +/* + * These functions are the interface supplied in the Xtransport structure + */ + +static XtransConnInfo _XSERVTransSocketOpenCOTSServer ( + Xtransport *thistrans, const char *protocol, const char *host, const char *port) +{ + XtransConnInfo ciptr = NULL; + int i = -1; + + prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port); + + SocketInitOnce(); + + while ((i = _XSERVTransSocketSelectFamily (i, thistrans->TransName)) >= 0) { + if ((ciptr = _XSERVTransSocketOpen ( + i, Sockettrans2devtab[i].devcotsname)) != NULL) + break; + } + if (i < 0) { + if (i == -1) { + if (errno == EAFNOSUPPORT) { + thistrans->flags |= TRANS_NOLISTEN; + prmsg (1,"SocketOpenCOTSServer: Socket for %s unsupported on this system.\n", + thistrans->TransName); + } else { + prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n", + thistrans->TransName); + } + } else { + prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n", + thistrans->TransName); + } + return NULL; + } + + /* + * Using this prevents the bind() check for an existing server listening + * on the same port, but it is required for other reasons. + */ +#ifdef SO_REUSEADDR + + /* + * SO_REUSEADDR only applied to AF_INET && AF_INET6 + */ + + if (Sockettrans2devtab[i].family == AF_INET +#ifdef IPv6 + || Sockettrans2devtab[i].family == AF_INET6 +#endif + ) + { + int one = 1; + setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR, + (char *) &one, sizeof (int)); + } +#endif +#ifdef IPV6_V6ONLY + if (Sockettrans2devtab[i].family == AF_INET6) + { + int one = 1; + setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int)); + } +#endif + /* Save the index for later use */ + + ciptr->index = i; + + return ciptr; +} + +static XtransConnInfo _XSERVTransSocketReopenCOTSServer ( + Xtransport *thistrans, int fd, const char *port) +{ + XtransConnInfo ciptr; + int i = -1; + + prmsg (2, + "SocketReopenCOTSServer(%d, %s)\n", fd, port); + + SocketInitOnce(); + + while ((i = _XSERVTransSocketSelectFamily (i, thistrans->TransName)) >= 0) { + if ((ciptr = _XSERVTransSocketReopen ( + i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL) + break; + } + if (i < 0) { + if (i == -1) + prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n", + thistrans->TransName); + else + prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n", + thistrans->TransName); + return NULL; + } + + /* Save the index for later use */ + + ciptr->index = i; + + return ciptr; +} + +static int _XSERVTransSocketSetOption (XtransConnInfo ciptr, int option, int arg) +{ + prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg); + return -1; +} + +#ifdef UNIXCONN +static int +set_sun_path(const char *port, const char *upath, char *path, int abstract) +{ + struct sockaddr_un s; + ssize_t maxlen = sizeof(s.sun_path) - 1; + const char *at = ""; + + if (!port || !*port || !path) + return -1; + +#ifdef HAVE_ABSTRACT_SOCKETS + if (port[0] == '@') + upath = ""; + else if (abstract) + at = "@"; +#endif + + if (*port == '/') /* a full pathname */ + upath = ""; + + if ((ssize_t)(strlen(at) + strlen(upath) + strlen(port)) > maxlen) + return -1; + snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port); + return 0; +} +#endif + +static int _XSERVTransSocketCreateListener (XtransConnInfo ciptr, + struct sockaddr *sockname, + int socknamelen, unsigned int flags) +{ + SOCKLEN_T namelen = socknamelen; + int fd = ciptr->fd; + int retry; + + prmsg (3, "SocketCreateListener(%p,%d)\n", (void *) ciptr, fd); + + if (Sockettrans2devtab[ciptr->index].family == AF_INET +#ifdef IPv6 + || Sockettrans2devtab[ciptr->index].family == AF_INET6 +#endif + ) + retry = 20; + else + retry = 0; + + while (bind (fd, sockname, namelen) < 0) + { + if (errno == EADDRINUSE) { + if (flags & ADDR_IN_USE_ALLOWED) + break; + else + return TRANS_ADDR_IN_USE; + } + + if (retry-- == 0) { + prmsg (1, "SocketCreateListener: failed to bind listener\n"); + close (fd); + return TRANS_CREATE_LISTENER_FAILED; + } +#ifdef SO_REUSEADDR + sleep (1); +#else + sleep (10); +#endif /* SO_REUSEDADDR */ + } + + if (Sockettrans2devtab[ciptr->index].family == AF_INET +#ifdef IPv6 + || Sockettrans2devtab[ciptr->index].family == AF_INET6 +#endif + ) { +#ifdef SO_DONTLINGER + setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0); +#else +#ifdef SO_LINGER + { + static int linger[2] = { 0, 0 }; + setsockopt (fd, SOL_SOCKET, SO_LINGER, + (char *) linger, sizeof (linger)); + } +#endif +#endif +} + + if (listen (fd, BACKLOG) < 0) + { + prmsg (1, "SocketCreateListener: listen() failed\n"); + close (fd); + return TRANS_CREATE_LISTENER_FAILED; + } + + /* Set a flag to indicate that this connection is a listener */ + + ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS); + + return 0; +} + +#ifdef TCPCONN +static int _XSERVTransSocketINETCreateListener ( + XtransConnInfo ciptr, const char *port, unsigned int flags) +{ +#ifdef HAVE_STRUCT_SOCKADDR_STORAGE + struct sockaddr_storage sockname; +#else + struct sockaddr_in sockname; +#endif + unsigned short sport; + SOCKLEN_T namelen = sizeof(sockname); + int status; + long tmpport; +#ifdef XTHREADS_NEEDS_BYNAMEPARAMS + _Xgetservbynameparams sparams; +#endif + struct servent *servp; + + char portbuf[PORTBUFSIZE]; + + prmsg (2, "SocketINETCreateListener(%s)\n", port); + + /* + * X has a well known port, that is transport dependent. It is easier + * to handle it here, than try and come up with a transport independent + * representation that can be passed in and resolved the usual way. + * + * The port that is passed here is really a string containing the idisplay + * from ConnectDisplay(). + */ + + if (is_numeric (port)) + { + /* fixup the server port address */ + tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10); + snprintf (portbuf, sizeof(portbuf), "%lu", tmpport); + port = portbuf; + } + + if (port && *port) + { + /* Check to see if the port string is just a number (handles X11) */ + + if (!is_numeric (port)) + { + if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) + { + prmsg (1, + "SocketINETCreateListener: Unable to get service for %s\n", + port); + return TRANS_CREATE_LISTENER_FAILED; + } + /* we trust getservbyname to return a valid number */ + sport = servp->s_port; + } + else + { + tmpport = strtol (port, (char**)NULL, 10); + /* + * check that somehow the port address isn't negative or in + * the range of reserved port addresses. This can happen and + * be very bad if the server is suid-root and the user does + * something (dumb) like `X :60049`. + */ + if (tmpport < 1024 || tmpport > USHRT_MAX) + return TRANS_CREATE_LISTENER_FAILED; + + sport = (unsigned short) tmpport; + } + } + else + sport = 0; + + memset(&sockname, 0, sizeof(sockname)); + if (Sockettrans2devtab[ciptr->index].family == AF_INET) { + namelen = sizeof (struct sockaddr_in); +#ifdef BSD44SOCKETS + ((struct sockaddr_in *)&sockname)->sin_len = namelen; +#endif + ((struct sockaddr_in *)&sockname)->sin_family = AF_INET; + ((struct sockaddr_in *)&sockname)->sin_port = htons(sport); + ((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY); + } else { +#ifdef IPv6 + namelen = sizeof (struct sockaddr_in6); +#ifdef SIN6_LEN + ((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname); +#endif + ((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6; + ((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport); + ((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any; +#else + prmsg (1, + "SocketINETCreateListener: unsupported address family %d\n", + Sockettrans2devtab[ciptr->index].family); + return TRANS_CREATE_LISTENER_FAILED; +#endif + } + + if ((status = _XSERVTransSocketCreateListener (ciptr, + (struct sockaddr *) &sockname, namelen, flags)) < 0) + { + prmsg (1, + "SocketINETCreateListener: ...SocketCreateListener() failed\n"); + return status; + } + + if (_XSERVTransSocketINETGetAddr (ciptr) < 0) + { + prmsg (1, + "SocketINETCreateListener: ...SocketINETGetAddr() failed\n"); + return TRANS_CREATE_LISTENER_FAILED; + } + + return 0; +} + +#endif /* TCPCONN */ + + +#ifdef UNIXCONN + +static int _XSERVTransSocketUNIXCreateListener ( + XtransConnInfo ciptr, const char *port, unsigned int flags) +{ + struct sockaddr_un sockname; + int namelen; + int oldUmask; + int status; + unsigned int mode; + char tmpport[108]; + + int abstract = 0; +#ifdef HAVE_ABSTRACT_SOCKETS + abstract = ciptr->transptr->flags & TRANS_ABSTRACT; +#endif + + prmsg (2, "SocketUNIXCreateListener(%s)\n", + port ? port : "NULL"); + + /* Make sure the directory is created */ + + oldUmask = umask (0); + +#ifdef UNIX_DIR +#ifdef HAS_STICKY_DIR_BIT + mode = 01777; +#else + mode = 0777; +#endif + if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) { + prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n", + UNIX_DIR, errno); + (void) umask (oldUmask); + return TRANS_CREATE_LISTENER_FAILED; + } +#endif + + memset(&sockname, 0, sizeof(sockname)); + sockname.sun_family = AF_UNIX; + + if (!(port && *port)) { + snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid()); + port = tmpport; + } + if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) { + prmsg (1, "SocketUNIXCreateListener: path too long\n"); + return TRANS_CREATE_LISTENER_FAILED; + } + +#if defined(BSD44SOCKETS) + sockname.sun_len = strlen(sockname.sun_path); +#endif + +#if defined(BSD44SOCKETS) || defined(SUN_LEN) + namelen = SUN_LEN(&sockname); +#else + namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path); +#endif + + if (abstract) { + sockname.sun_path[0] = '\0'; + namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]); + } + else + unlink (sockname.sun_path); + + if ((status = _XSERVTransSocketCreateListener (ciptr, + (struct sockaddr *) &sockname, namelen, flags)) < 0) + { + prmsg (1, + "SocketUNIXCreateListener: ...SocketCreateListener() failed\n"); + (void) umask (oldUmask); + return status; + } + + /* + * Now that the listener is esablished, create the addr info for + * this connection. getpeername() doesn't work for UNIX Domain Sockets + * on some systems (hpux at least), so we will just do it manually, instead + * of calling something like _XSERVTransSocketUNIXGetAddr. + */ + + namelen = sizeof (sockname); /* this will always make it the same size */ + + if ((ciptr->addr = malloc (namelen)) == NULL) + { + prmsg (1, + "SocketUNIXCreateListener: Can't allocate space for the addr\n"); + (void) umask (oldUmask); + return TRANS_CREATE_LISTENER_FAILED; + } + + if (abstract) + sockname.sun_path[0] = '@'; + + ciptr->family = sockname.sun_family; + ciptr->addrlen = namelen; + memcpy (ciptr->addr, &sockname, ciptr->addrlen); + + (void) umask (oldUmask); + + return 0; +} + + +static int _XSERVTransSocketUNIXResetListener (XtransConnInfo ciptr) +{ + /* + * See if the unix domain socket has disappeared. If it has, recreate it. + */ + + struct sockaddr_un *unsock = (struct sockaddr_un *) ciptr->addr; + struct stat statb; + int status = TRANS_RESET_NOOP; + unsigned int mode; + int abstract = 0; +#ifdef HAVE_ABSTRACT_SOCKETS + abstract = ciptr->transptr->flags & TRANS_ABSTRACT; +#endif + + prmsg (3, "SocketUNIXResetListener(%p,%d)\n", (void *) ciptr, ciptr->fd); + + if (!abstract && ( + stat (unsock->sun_path, &statb) == -1 || + ((statb.st_mode & S_IFMT) != +#if !defined(S_IFSOCK) + S_IFIFO +#else + S_IFSOCK +#endif + ))) + { + int oldUmask = umask (0); + +#ifdef UNIX_DIR +#ifdef HAS_STICKY_DIR_BIT + mode = 01777; +#else + mode = 0777; +#endif + if (trans_mkdir(UNIX_DIR, mode) == -1) { + prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n", + UNIX_DIR, errno); + (void) umask (oldUmask); + return TRANS_RESET_FAILURE; + } +#endif + + close (ciptr->fd); + unlink (unsock->sun_path); + + if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) + { + _XSERVTransFreeConnInfo (ciptr); + (void) umask (oldUmask); + return TRANS_RESET_FAILURE; + } + + if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0) + { + close (ciptr->fd); + _XSERVTransFreeConnInfo (ciptr); + return TRANS_RESET_FAILURE; + } + + if (listen (ciptr->fd, BACKLOG) < 0) + { + close (ciptr->fd); + _XSERVTransFreeConnInfo (ciptr); + (void) umask (oldUmask); + return TRANS_RESET_FAILURE; + } + + umask (oldUmask); + + status = TRANS_RESET_NEW_FD; + } + + return status; +} + +#endif /* UNIXCONN */ + + +#ifdef TCPCONN + +static XtransConnInfo _XSERVTransSocketINETAccept ( + XtransConnInfo ciptr, int *status) +{ + XtransConnInfo newciptr; + struct sockaddr_in sockname; + SOCKLEN_T namelen = sizeof(sockname); + + prmsg (2, "SocketINETAccept(%p,%d)\n", (void *) ciptr, ciptr->fd); + + if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) + { + prmsg (1, "SocketINETAccept: malloc failed\n"); + *status = TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + + if ((newciptr->fd = accept (ciptr->fd, + (struct sockaddr *) &sockname, (void *)&namelen)) < 0) + { +#ifdef WIN32 + errno = WSAGetLastError(); +#endif + prmsg (1, "SocketINETAccept: accept() failed\n"); + free (newciptr); + *status = TRANS_ACCEPT_FAILED; + return NULL; + } + +#ifdef TCP_NODELAY + { + /* + * turn off TCP coalescence for INET sockets + */ + + int tmp = 1; + setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY, + (char *) &tmp, sizeof (int)); + } +#endif + + /* + * Get this address again because the transport may give a more + * specific address now that a connection is established. + */ + + if (_XSERVTransSocketINETGetAddr (newciptr) < 0) + { + prmsg (1, + "SocketINETAccept: ...SocketINETGetAddr() failed:\n"); + close (newciptr->fd); + free (newciptr); + *status = TRANS_ACCEPT_MISC_ERROR; + return NULL; + } + + if (_XSERVTransSocketINETGetPeerAddr (newciptr) < 0) + { + prmsg (1, + "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n"); + close (newciptr->fd); + if (newciptr->addr) free (newciptr->addr); + free (newciptr); + *status = TRANS_ACCEPT_MISC_ERROR; + return NULL; + } + + *status = 0; + + return newciptr; +} + +#endif /* TCPCONN */ + + +#ifdef UNIXCONN +static XtransConnInfo _XSERVTransSocketUNIXAccept ( + XtransConnInfo ciptr, int *status) +{ + XtransConnInfo newciptr; + struct sockaddr_un sockname; + SOCKLEN_T namelen = sizeof sockname; + + prmsg (2, "SocketUNIXAccept(%p,%d)\n", (void *) ciptr, ciptr->fd); + + if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) + { + prmsg (1, "SocketUNIXAccept: malloc() failed\n"); + *status = TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + + if ((newciptr->fd = accept (ciptr->fd, + (struct sockaddr *) &sockname, (void *)&namelen)) < 0) + { + prmsg (1, "SocketUNIXAccept: accept() failed\n"); + free (newciptr); + *status = TRANS_ACCEPT_FAILED; + return NULL; + } + + ciptr->addrlen = namelen; + /* + * Get the socket name and the peer name from the listener socket, + * since this is unix domain. + */ + + if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL) + { + prmsg (1, + "SocketUNIXAccept: Can't allocate space for the addr\n"); + close (newciptr->fd); + free (newciptr); + *status = TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + + /* + * if the socket is abstract, we already modified the address to have a + * @ instead of the initial NUL, so no need to do that again here. + */ + + newciptr->addrlen = ciptr->addrlen; + memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen); + + if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL) + { + prmsg (1, + "SocketUNIXAccept: Can't allocate space for the addr\n"); + close (newciptr->fd); + if (newciptr->addr) free (newciptr->addr); + free (newciptr); + *status = TRANS_ACCEPT_BAD_MALLOC; + return NULL; + } + + newciptr->peeraddrlen = ciptr->addrlen; + memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen); + + newciptr->family = AF_UNIX; + + *status = 0; + + return newciptr; +} + +#endif /* UNIXCONN */ + +static int _XSERVTransSocketBytesReadable ( + XtransConnInfo ciptr, BytesReadable_t *pend) +{ + prmsg (2,"SocketBytesReadable(%p,%d,%p)\n", + (void *) ciptr, ciptr->fd, (void *) pend); +#ifdef WIN32 + { + int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend); + if (ret == SOCKET_ERROR) errno = WSAGetLastError(); + return ret; + } +#else + return ioctl (ciptr->fd, FIONREAD, (char *) pend); +#endif /* WIN32 */ +} + +#if XTRANS_SEND_FDS + +static void +appendFd(struct _XtransConnFd **prev, int fd, int do_close) +{ + struct _XtransConnFd *cf, *new; + + new = malloc (sizeof (struct _XtransConnFd)); + if (!new) { + /* XXX mark connection as broken */ + close(fd); + return; + } + new->next = 0; + new->fd = fd; + new->do_close = do_close; + /* search to end of list */ + for (; (cf = *prev); prev = &(cf->next)); + *prev = new; +} + +static int +removeFd(struct _XtransConnFd **prev) +{ + struct _XtransConnFd *cf; + int fd; + + if ((cf = *prev)) { + *prev = cf->next; + fd = cf->fd; + free(cf); + } else + fd = -1; + return fd; +} + +static void +discardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close) +{ + struct _XtransConnFd *cf, *next; + + for (cf = *prev; cf != upto; cf = next) { + next = cf->next; + if (do_close || cf->do_close) + close(cf->fd); + free(cf); + } + *prev = upto; +} + +static void +cleanupFds(XtransConnInfo ciptr) +{ + /* Clean up the send list but don't close the fds */ + discardFd(&ciptr->send_fds, NULL, 0); + /* Clean up the recv list and *do* close the fds */ + discardFd(&ciptr->recv_fds, NULL, 1); +} + +static int +nFd(struct _XtransConnFd **prev) +{ + struct _XtransConnFd *cf; + int n = 0; + + for (cf = *prev; cf; cf = cf->next) + n++; + return n; +} + +static int _XSERVTransSocketRecvFd (XtransConnInfo ciptr) +{ + prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd); + return removeFd(&ciptr->recv_fds); +} + +static int _XSERVTransSocketSendFd ( + XtransConnInfo ciptr, int fd, int do_close) +{ + appendFd(&ciptr->send_fds, fd, do_close); + return 0; +} + +static int _XSERVTransSocketRecvFdInvalid(XtransConnInfo ciptr) +{ + errno = EINVAL; + return -1; +} + +static int _XSERVTransSocketSendFdInvalid( + XtransConnInfo ciptr, int fd, int do_close) +{ + errno = EINVAL; + return -1; +} + +#define MAX_FDS 128 + +union fd_pass { + struct cmsghdr cmsghdr; + char buf[CMSG_SPACE(MAX_FDS * sizeof(int))]; +}; + +#endif /* XTRANS_SEND_FDS */ + +static int _XSERVTransSocketRead ( + XtransConnInfo ciptr, char *buf, int size) +{ + prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, (void *) buf, size); + +#if defined(WIN32) + { + int ret = recv ((SOCKET)ciptr->fd, buf, size, 0); +#ifdef WIN32 + if (ret == SOCKET_ERROR) errno = WSAGetLastError(); +#endif + return ret; + } +#else +#if XTRANS_SEND_FDS + { + struct iovec iov = { + .iov_base = buf, + .iov_len = size + }; + union fd_pass cmsgbuf; + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = &iov, + .msg_iovlen = 1, + .msg_control = cmsgbuf.buf, + .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int)) + }; + + size = recvmsg(ciptr->fd, &msg, 0); + if (size >= 0) { + struct cmsghdr *hdr; + + for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { + if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { + int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int); + int i; + int *fd = (int *) CMSG_DATA(hdr); + + for (i = 0; i < nfd; i++) + appendFd(&ciptr->recv_fds, fd[i], 0); + } + } + } + return size; + } +#else + return read(ciptr->fd, buf, size); +#endif /* XTRANS_SEND_FDS */ +#endif /* WIN32 */ +} + +static int _XSERVTransSocketReadv ( + XtransConnInfo ciptr, struct iovec *buf, int size) +{ + prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, (void *) buf, size); + +#if XTRANS_SEND_FDS + { + union fd_pass cmsgbuf; + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = buf, + .msg_iovlen = size, + .msg_control = cmsgbuf.buf, + .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int)) + }; + + size = recvmsg(ciptr->fd, &msg, 0); + if (size >= 0) { + struct cmsghdr *hdr; + + for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { + if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { + int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int); + int i; + int *fd = (int *) CMSG_DATA(hdr); + + for (i = 0; i < nfd; i++) + appendFd(&ciptr->recv_fds, fd[i], 0); + } + } + } + return size; + } +#else + return READV (ciptr, buf, size); +#endif +} + +static int _XSERVTransSocketWritev ( + XtransConnInfo ciptr, struct iovec *buf, int size) +{ + prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, (void *) buf, size); + +#if XTRANS_SEND_FDS + if (ciptr->send_fds) + { + union fd_pass cmsgbuf; + int nfd = nFd(&ciptr->send_fds); + struct _XtransConnFd *cf = ciptr->send_fds; + struct msghdr msg = { + .msg_name = NULL, + .msg_namelen = 0, + .msg_iov = buf, + .msg_iovlen = size, + .msg_control = cmsgbuf.buf, + .msg_controllen = CMSG_LEN(nfd * sizeof(int)) + }; + struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); + int i; + int *fds; + + hdr->cmsg_len = msg.msg_controllen; + hdr->cmsg_level = SOL_SOCKET; + hdr->cmsg_type = SCM_RIGHTS; + + fds = (int *) CMSG_DATA(hdr); + /* Set up fds */ + for (i = 0; i < nfd; i++) { + fds[i] = cf->fd; + cf = cf->next; + } + + i = sendmsg(ciptr->fd, &msg, 0); + if (i > 0) + discardFd(&ciptr->send_fds, cf, 0); + return i; + } +#endif + return WRITEV (ciptr, buf, size); +} + +static int _XSERVTransSocketWrite ( + XtransConnInfo ciptr, const char *buf, int size) +{ + prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, (const void *) buf, size); + +#if defined(WIN32) + { + int ret = send ((SOCKET)ciptr->fd, buf, size, 0); +#ifdef WIN32 + if (ret == SOCKET_ERROR) errno = WSAGetLastError(); +#endif + return ret; + } +#else +#if XTRANS_SEND_FDS + if (ciptr->send_fds) + { + struct iovec iov; + + iov.iov_base = (void *) buf; + iov.iov_len = size; + return _XSERVTransSocketWritev(ciptr, &iov, 1); + } +#endif /* XTRANS_SEND_FDS */ + return write (ciptr->fd, buf, size); +#endif /* WIN32 */ +} + +static int _XSERVTransSocketDisconnect (XtransConnInfo ciptr) +{ + prmsg (2,"SocketDisconnect(%p,%d)\n", (void *) ciptr, ciptr->fd); + +#ifdef WIN32 + { + int ret = shutdown (ciptr->fd, 2); + if (ret == SOCKET_ERROR) errno = WSAGetLastError(); + return ret; + } +#else + return shutdown (ciptr->fd, 2); /* disallow further sends and receives */ +#endif +} + +#ifdef TCPCONN +static int _XSERVTransSocketINETClose (XtransConnInfo ciptr) +{ + prmsg (2,"SocketINETClose(%p,%d)\n", (void *) ciptr, ciptr->fd); + +#ifdef WIN32 + { + int ret = close (ciptr->fd); + if (ret == SOCKET_ERROR) errno = WSAGetLastError(); + return ret; + } +#else + return close (ciptr->fd); +#endif +} + +#endif /* TCPCONN */ + +#ifdef UNIXCONN +static int _XSERVTransSocketUNIXClose (XtransConnInfo ciptr) +{ + /* + * If this is the server side, then once the socket is closed, + * it must be unlinked to completely close it + */ + + struct sockaddr_un *sockname = (struct sockaddr_un *) ciptr->addr; + int ret; + + prmsg (2,"SocketUNIXClose(%p,%d)\n", (void *) ciptr, ciptr->fd); + +#if XTRANS_SEND_FDS + cleanupFds(ciptr); +#endif + ret = close(ciptr->fd); + + if (ciptr->flags + && sockname + && sockname->sun_family == AF_UNIX + && sockname->sun_path[0]) + { + if (!(ciptr->flags & TRANS_NOUNLINK + || ciptr->transptr->flags & TRANS_ABSTRACT)) + unlink (sockname->sun_path); + } + + return ret; +} + +static int _XSERVTransSocketUNIXCloseForCloning (XtransConnInfo ciptr) +{ + /* + * Don't unlink path. + */ + + int ret; + + prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n", + (void *) ciptr, ciptr->fd); + +#if XTRANS_SEND_FDS + cleanupFds(ciptr); +#endif + ret = close(ciptr->fd); + + return ret; +} + +#endif /* UNIXCONN */ + + +#ifdef TCPCONN +static const char* tcp_nolisten[] = { + "inet", +#ifdef IPv6 + "inet6", +#endif + NULL +}; + +static Xtransport _XSERVTransSocketTCPFuncs = { + /* Socket Interface */ + "tcp", + TRANS_ALIAS, + tcp_nolisten, + _XSERVTransSocketOpenCOTSServer, + _XSERVTransSocketReopenCOTSServer, + _XSERVTransSocketSetOption, + _XSERVTransSocketINETCreateListener, + NULL, /* ResetListener */ + _XSERVTransSocketINETAccept, + _XSERVTransSocketBytesReadable, + _XSERVTransSocketRead, + _XSERVTransSocketWrite, + _XSERVTransSocketReadv, + _XSERVTransSocketWritev, +#if XTRANS_SEND_FDS + _XSERVTransSocketSendFdInvalid, + _XSERVTransSocketRecvFdInvalid, +#endif + _XSERVTransSocketDisconnect, + _XSERVTransSocketINETClose, + _XSERVTransSocketINETClose, +}; + +static Xtransport _XSERVTransSocketINETFuncs = { + /* Socket Interface */ + "inet", + 0, + NULL, + _XSERVTransSocketOpenCOTSServer, + _XSERVTransSocketReopenCOTSServer, + _XSERVTransSocketSetOption, + _XSERVTransSocketINETCreateListener, + NULL, /* ResetListener */ + _XSERVTransSocketINETAccept, + _XSERVTransSocketBytesReadable, + _XSERVTransSocketRead, + _XSERVTransSocketWrite, + _XSERVTransSocketReadv, + _XSERVTransSocketWritev, +#if XTRANS_SEND_FDS + _XSERVTransSocketSendFdInvalid, + _XSERVTransSocketRecvFdInvalid, +#endif + _XSERVTransSocketDisconnect, + _XSERVTransSocketINETClose, + _XSERVTransSocketINETClose, +}; + +#ifdef IPv6 +static Xtransport _XSERVTransSocketINET6Funcs = { + /* Socket Interface */ + "inet6", + 0, + NULL, + _XSERVTransSocketOpenCOTSServer, + _XSERVTransSocketReopenCOTSServer, + _XSERVTransSocketSetOption, + _XSERVTransSocketINETCreateListener, + NULL, /* ResetListener */ + _XSERVTransSocketINETAccept, + _XSERVTransSocketBytesReadable, + _XSERVTransSocketRead, + _XSERVTransSocketWrite, + _XSERVTransSocketReadv, + _XSERVTransSocketWritev, +#if XTRANS_SEND_FDS + _XSERVTransSocketSendFdInvalid, + _XSERVTransSocketRecvFdInvalid, +#endif + _XSERVTransSocketDisconnect, + _XSERVTransSocketINETClose, + _XSERVTransSocketINETClose, +}; +#endif /* IPv6 */ +#endif /* TCPCONN */ + +#ifdef UNIXCONN +#if !defined(LOCALCONN) +static Xtransport _XSERVTransSocketLocalFuncs = { + /* Socket Interface */ + "local", +#ifdef HAVE_ABSTRACT_SOCKETS + TRANS_ABSTRACT, +#else + 0, +#endif + NULL, + _XSERVTransSocketOpenCOTSServer, + _XSERVTransSocketReopenCOTSServer, + _XSERVTransSocketSetOption, + _XSERVTransSocketUNIXCreateListener, + _XSERVTransSocketUNIXResetListener, + _XSERVTransSocketUNIXAccept, + _XSERVTransSocketBytesReadable, + _XSERVTransSocketRead, + _XSERVTransSocketWrite, + _XSERVTransSocketReadv, + _XSERVTransSocketWritev, +#if XTRANS_SEND_FDS + _XSERVTransSocketSendFd, + _XSERVTransSocketRecvFd, +#endif + _XSERVTransSocketDisconnect, + _XSERVTransSocketUNIXClose, + _XSERVTransSocketUNIXCloseForCloning, +}; +#endif /* !LOCALCONN */ +# if !defined(LOCALCONN) +static const char* unix_nolisten[] = { "local" , NULL }; +# endif + +static Xtransport _XSERVTransSocketUNIXFuncs = { + /* Socket Interface */ + "unix", +#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS) + TRANS_ALIAS, +#else + 0, +#endif +#if !defined(LOCALCONN) + unix_nolisten, +#else + NULL, +#endif + _XSERVTransSocketOpenCOTSServer, + _XSERVTransSocketReopenCOTSServer, + _XSERVTransSocketSetOption, + _XSERVTransSocketUNIXCreateListener, + _XSERVTransSocketUNIXResetListener, + _XSERVTransSocketUNIXAccept, + _XSERVTransSocketBytesReadable, + _XSERVTransSocketRead, + _XSERVTransSocketWrite, + _XSERVTransSocketReadv, + _XSERVTransSocketWritev, +#if XTRANS_SEND_FDS + _XSERVTransSocketSendFd, + _XSERVTransSocketRecvFd, +#endif + _XSERVTransSocketDisconnect, + _XSERVTransSocketUNIXClose, + _XSERVTransSocketUNIXCloseForCloning, +}; + +#endif /* UNIXCONN */ diff --git a/os/Xtransutil.c b/os/Xtransutil.c new file mode 100644 index 000000000..8d7849f60 --- /dev/null +++ b/os/Xtransutil.c @@ -0,0 +1,420 @@ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA + * + * All Rights Reserved + * + * 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 NCR not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. NCR makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * NCRS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NCR 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. + */ + +/* + * These are some utility functions created for convenience or to provide + * an interface that is similar to an existing interface. These are built + * only using the Transport Independent API, and have no knowledge of + * the internal implementation. + */ + +#ifdef XTHREADS +#include +#endif +#ifdef WIN32 +#include +#include +#endif + +#if defined(IPv6) && !defined(AF_INET6) +#error "Cannot build IPv6 support without AF_INET6" +#endif + +/* Temporary workaround for consumers whose configure scripts were + generated with pre-1.6 versions of xtrans.m4 */ +#if defined(IPv6) && !defined(HAVE_INET_NTOP) +#define HAVE_INET_NTOP +#endif + +/* + * These values come from X.h and Xauth.h, and MUST match them. Some + * of these values are also defined by the ChangeHost protocol message. + */ + +#define FamilyInternet 0 /* IPv4 */ +#define FamilyDECnet 1 +#define FamilyChaos 2 +#define FamilyInternet6 6 +#define FamilyAmoeba 33 +#define FamilyLocalHost 252 +#define FamilyKrb5Principal 253 +#define FamilyNetname 254 +#define FamilyLocal 256 +#define FamilyWild 65535 + +/* + * _XSERVTransConvertAddress converts a sockaddr based address to an + * X authorization based address. Some of this is defined as part of + * the ChangeHost protocol. The rest is just done in a consistent manner. + */ + +int _XSERVTransConvertAddress(int *familyp, int *addrlenp, Xtransaddr **addrp) +{ + prmsg(2,"ConvertAddress(%d,%d,%p)\n",*familyp,*addrlenp,*addrp); + + switch( *familyp ) + { +#if defined(TCPCONN) + case AF_INET: + { + /* + * Check for the BSD hack localhost address 127.0.0.1. + * In this case, we are really FamilyLocal. + */ + + struct sockaddr_in saddr; + int len = sizeof(saddr.sin_addr.s_addr); + char *cp = (char *) &saddr.sin_addr.s_addr; + + memcpy (&saddr, *addrp, sizeof (struct sockaddr_in)); + + if ((len == 4) && (cp[0] == 127) && (cp[1] == 0) && + (cp[2] == 0) && (cp[3] == 1)) + { + *familyp=FamilyLocal; + } + else + { + *familyp=FamilyInternet; + *addrlenp=len; + memcpy(*addrp,&saddr.sin_addr,len); + } + break; + } + +#ifdef IPv6 + case AF_INET6: + { + struct sockaddr_in6 saddr6; + + memcpy (&saddr6, *addrp, sizeof (struct sockaddr_in6)); + + if (IN6_IS_ADDR_LOOPBACK(&saddr6.sin6_addr)) + { + *familyp=FamilyLocal; + } + else if (IN6_IS_ADDR_V4MAPPED(&(saddr6.sin6_addr))) { + char *cp = (char *) &saddr6.sin6_addr.s6_addr[12]; + + if ((cp[0] == 127) && (cp[1] == 0) && + (cp[2] == 0) && (cp[3] == 1)) + { + *familyp=FamilyLocal; + } + else + { + *familyp=FamilyInternet; + *addrlenp = sizeof (struct in_addr); + memcpy(*addrp,cp,*addrlenp); + } + } + else + { + *familyp=FamilyInternet6; + *addrlenp=sizeof(saddr6.sin6_addr); + memcpy(*addrp,&saddr6.sin6_addr,sizeof(saddr6.sin6_addr)); + } + break; + } +#endif /* IPv6 */ +#endif /* defined(TCPCONN) */ + + +#if defined(UNIXCONN) || defined(LOCALCONN) + case AF_UNIX: + { + *familyp=FamilyLocal; + break; + } +#endif /* defined(UNIXCONN) || defined(LOCALCONN) */ + + + default: + prmsg(1,"ConvertAddress: Unknown family type %d\n", + *familyp); + return -1; + } + + + if (*familyp == FamilyLocal) + { + /* + * In the case of a local connection, we need to get the + * host name for authentication. + */ + + char hostnamebuf[256]; + int len = _XSERVTransGetHostname (hostnamebuf, sizeof hostnamebuf); + + if (len > 0) { + if (*addrp && *addrlenp < (len + 1)) + { + free (*addrp); + *addrp = NULL; + } + if (!*addrp) + *addrp = malloc (len + 1); + if (*addrp) { + strcpy ((char *) *addrp, hostnamebuf); + *addrlenp = len; + } else { + *addrlenp = 0; + } + } + else + { + if (*addrp) + free (*addrp); + *addrp = NULL; + *addrlenp = 0; + } + } + + return 0; +} + +#if defined(WIN32) && defined(TCPCONN) +int _XSERVTransWSAStartup (void) +{ + static WSADATA wsadata; + + prmsg (2,"WSAStartup()\n"); + + if (!wsadata.wVersion && WSAStartup(MAKEWORD(2,2), &wsadata)) + return 1; + return 0; +} +#endif + +#include +#include +#include + +#if !defined(S_IFLNK) && !defined(S_ISLNK) +#undef lstat +#define lstat(a,b) stat(a,b) +#endif + +#define FAIL_IF_NOMODE 1 +#define FAIL_IF_NOT_ROOT 2 +#define WARN_NO_ACCESS 4 + +/* + * We make the assumption that when the 'sticky' (t) bit is requested + * it's not save if the directory has non-root ownership or the sticky + * bit cannot be set and fail. + */ +static int +trans_mkdir(const char *path, int mode) +{ + struct stat buf; + + if (lstat(path, &buf) != 0) { + if (errno != ENOENT) { + prmsg(1, "mkdir: ERROR: (l)stat failed for %s (%d)\n", + path, errno); + return -1; + } + /* Dir doesn't exist. Try to create it */ + +#if !defined(WIN32) && !defined(__CYGWIN__) + /* + * 'sticky' bit requested: assume application makes + * certain security implications. If effective user ID + * is != 0: fail as we may not be able to meet them. + */ + if (geteuid() != 0) { + if (mode & 01000) { + prmsg(1, "mkdir: ERROR: euid != 0," + "directory %s will not be created.\n", + path); +#ifdef FAIL_HARD + return -1; +#endif + } else { + prmsg(1, "mkdir: Cannot create %s with root ownership\n", + path); + } + } +#endif + +#ifndef WIN32 + if (mkdir(path, mode) == 0) { + if (chmod(path, mode)) { + prmsg(1, "mkdir: ERROR: Mode of %s should be set to %04o\n", + path, mode); +#ifdef FAIL_HARD + return -1; +#endif + } +#else + if (mkdir(path) == 0) { +#endif + } else { + prmsg(1, "mkdir: ERROR: Cannot create %s\n", + path); + return -1; + } + + return 0; + + } else { + if (S_ISDIR(buf.st_mode)) { + int updateOwner = 0; + int updateMode = 0; + int updatedOwner = 0; + int updatedMode = 0; + int status = 0; + /* Check if the directory's ownership is OK. */ + if (buf.st_uid != 0) + updateOwner = 1; + + /* + * Check if the directory's mode is OK. An exact match isn't + * required, just a mode that isn't more permissive than the + * one requested. + */ + if ((~mode) & 0077 & buf.st_mode) + updateMode = 1; + + /* + * If the directory is not writeable not everybody may + * be able to create sockets. Therefore warn if mode + * cannot be fixed. + */ + if ((~buf.st_mode) & 0022 & mode) { + updateMode = 1; + status |= WARN_NO_ACCESS; + } + + /* + * If 'sticky' bit is requested fail if owner isn't root + * as we assume the caller makes certain security implications + */ + if (mode & 01000) { + status |= FAIL_IF_NOT_ROOT; + if (!(buf.st_mode & 01000)) { + status |= FAIL_IF_NOMODE; + updateMode = 1; + } + } + +#ifdef HAS_FCHOWN + /* + * If fchown(2) and fchmod(2) are available, try to correct the + * directory's owner and mode. Otherwise it isn't safe to attempt + * to do this. + */ + if (updateMode || updateOwner) { + int fd = -1; + struct stat fbuf; + if ((fd = open(path, O_RDONLY)) != -1) { + if (fstat(fd, &fbuf) == -1) { + prmsg(1, "mkdir: ERROR: fstat failed for %s (%d)\n", + path, errno); + close(fd); + return -1; + } + /* + * Verify that we've opened the same directory as was + * checked above. + */ + if (!S_ISDIR(fbuf.st_mode) || + buf.st_dev != fbuf.st_dev || + buf.st_ino != fbuf.st_ino) { + prmsg(1, "mkdir: ERROR: inode for %s changed\n", + path); + close(fd); + return -1; + } + if (updateOwner && fchown(fd, 0, 0) == 0) + updatedOwner = 1; + if (updateMode && fchmod(fd, mode) == 0) + updatedMode = 1; + close(fd); + } + } +#endif + + if (updateOwner && !updatedOwner) { +#ifdef FAIL_HARD + if (status & FAIL_IF_NOT_ROOT) { + prmsg(1, "mkdir: ERROR: Owner of %s must be set to root\n", + path); + return -1; + } +#endif +#if !defined(__APPLE_CC__) && !defined(__CYGWIN__) + prmsg(1, "mkdir: Owner of %s should be set to root\n", + path); +#endif + } + + if (updateMode && !updatedMode) { +#ifdef FAIL_HARD + if (status & FAIL_IF_NOMODE) { + prmsg(1, "mkdir: ERROR: Mode of %s must be set to %04o\n", + path, mode); + return -1; + } +#endif + prmsg(1, "mkdir: Mode of %s should be set to %04o\n", + path, mode); + if (status & WARN_NO_ACCESS) { + prmsg(1, "mkdir: this may cause subsequent errors\n"); + } + } + return 0; + } + return -1; + } + + /* In all other cases, fail */ + return -1; +} diff --git a/os/access.c b/os/access.c index 34d735bfa..fd9fa91ef 100644 --- a/os/access.c +++ b/os/access.c @@ -84,10 +84,7 @@ SOFTWARE. #include #include -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include +#include "os/Xtrans.h" #include #include #include diff --git a/os/connection.c b/os/connection.c index 64245af6b..dec7a340b 100644 --- a/os/connection.c +++ b/os/connection.c @@ -67,11 +67,8 @@ SOFTWARE. #endif #include #include -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include -#include +#include "os/Xtrans.h" +#include "os/Xtransint.h" #include #include #include @@ -147,7 +144,7 @@ set_poll_clients(void); static XtransConnInfo *ListenTransConns = NULL; static int *ListenTransFds = NULL; -static int ListenTransCount; +static uint32_t ListenTransCount = 0; static void ErrorConnMax(XtransConnInfo /* trans_conn */ ); @@ -1061,7 +1058,7 @@ ListenOnOpenFD(int fd, int noxauth) ListenTransCount++; } -/* based on TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) */ +/* based on _XSERVTransSocketUNIXAccept (XtransConnInfo ciptr, int *status) */ Bool AddClientOnOpenFD(int fd) { diff --git a/os/io.c b/os/io.c index 948660996..f61f6bb9c 100644 --- a/os/io.c +++ b/os/io.c @@ -61,10 +61,7 @@ SOFTWARE. #include #endif #include -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include +#include "os/Xtrans.h" #include #include #if !defined(WIN32) diff --git a/os/transport.c b/os/transport.c new file mode 100644 index 000000000..b62fc7b64 --- /dev/null +++ b/os/transport.c @@ -0,0 +1,74 @@ +/* + +Copyright 1993, 1994, 1998 The Open Group + +Permission to use, copy, modify, distribute, and sell this software and its +documentation for any purpose is hereby granted without fee, provided that +the above copyright notice appear in all copies and that both that +copyright notice and this permission notice appear in supporting +documentation. + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Except as contained in this notice, the name of The Open Group shall +not be used in advertising or otherwise to promote the sale, use or +other dealings in this Software without prior written authorization +from The Open Group. + + * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA + * + * All Rights Reserved + * + * 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 NCR not be used in advertising + * or publicity pertaining to distribution of the software without specific, + * written prior permission. NCR makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN + * NO EVENT SHALL NCR 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. + */ + +#include + +#define XTRANS_TRANSPORT_C /* used to flag Xtransint.h that it's being used + here, not just #included in another file */ + +#include "Xtransint.h" + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wformat-nonliteral" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#endif + +#ifdef LOCALCONN +#include "Xtranslcl.c" +#endif +#if defined(TCPCONN) || defined(UNIXCONN) +#include "Xtranssock.c" +#endif +#include "Xtrans.c" +#include "Xtransutil.c" + +#ifdef __clang__ +#pragma clang diagnostic pop +#endif diff --git a/os/utils.c b/os/utils.c index 00c6ebb3e..9ec93f39c 100644 --- a/os/utils.c +++ b/os/utils.c @@ -62,10 +62,7 @@ OR PERFORMANCE OF THIS SOFTWARE. #endif #include "misc.h" #include -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include +#include "os/Xtrans.h" #include diff --git a/os/xdmauth.c b/os/xdmauth.c index fc5cbe5c5..1ff7ab75c 100644 --- a/os/xdmauth.c +++ b/os/xdmauth.c @@ -37,12 +37,9 @@ from The Open Group. #include #include -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include #include "os/auth.h" +#include "os/Xtrans.h" #include "os.h" #include "osdep.h" diff --git a/os/xdmcp.c b/os/xdmcp.c index 550979e51..a4cb3e2dc 100644 --- a/os/xdmcp.c +++ b/os/xdmcp.c @@ -17,10 +17,7 @@ #ifdef WIN32 #include -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include +#include "os/Xtrans.h" #endif #include @@ -48,10 +45,7 @@ #include "input.h" #include "dixstruct.h" -#define XSERV_t -#define TRANS_SERVER -#define TRANS_REOPEN -#include +#include "os/Xtrans.h" #ifdef XDMCP #undef REQUEST diff --git a/os/xstrans.c b/os/xstrans.c index c9363db71..889dec329 100644 --- a/os/xstrans.c +++ b/os/xstrans.c @@ -2,7 +2,4 @@ #include -#define TRANS_REOPEN -#define TRANS_SERVER -#define XSERV_t -#include +#include "os/transport.c"