Xtrans.c revision 94f982db
173143b9aSmrg/*
273143b9aSmrg
373143b9aSmrgCopyright 1993, 1994, 1998  The Open Group
473143b9aSmrg
573143b9aSmrgPermission to use, copy, modify, distribute, and sell this software and its
673143b9aSmrgdocumentation for any purpose is hereby granted without fee, provided that
773143b9aSmrgthe above copyright notice appear in all copies and that both that
873143b9aSmrgcopyright notice and this permission notice appear in supporting
973143b9aSmrgdocumentation.
1073143b9aSmrg
1173143b9aSmrgThe above copyright notice and this permission notice shall be included
1273143b9aSmrgin all copies or substantial portions of the Software.
1373143b9aSmrg
1473143b9aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1573143b9aSmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1673143b9aSmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1773143b9aSmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
1873143b9aSmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
1973143b9aSmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
2073143b9aSmrgOTHER DEALINGS IN THE SOFTWARE.
2173143b9aSmrg
2273143b9aSmrgExcept as contained in this notice, the name of The Open Group shall
2373143b9aSmrgnot be used in advertising or otherwise to promote the sale, use or
2473143b9aSmrgother dealings in this Software without prior written authorization
2573143b9aSmrgfrom The Open Group.
2673143b9aSmrg
2773143b9aSmrg * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
2873143b9aSmrg *
2973143b9aSmrg * All Rights Reserved
3073143b9aSmrg *
3173143b9aSmrg * Permission to use, copy, modify, and distribute this software and its
3273143b9aSmrg * documentation for any purpose and without fee is hereby granted, provided
3373143b9aSmrg * that the above copyright notice appear in all copies and that both that
3473143b9aSmrg * copyright notice and this permission notice appear in supporting
3573143b9aSmrg * documentation, and that the name NCR not be used in advertising
3673143b9aSmrg * or publicity pertaining to distribution of the software without specific,
3773143b9aSmrg * written prior permission.  NCR makes no representations about the
3873143b9aSmrg * suitability of this software for any purpose.  It is provided "as is"
3973143b9aSmrg * without express or implied warranty.
4073143b9aSmrg *
4173143b9aSmrg * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
4273143b9aSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
4373143b9aSmrg * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
4473143b9aSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
4573143b9aSmrg * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
4673143b9aSmrg * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
4773143b9aSmrg * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
4873143b9aSmrg */
4973143b9aSmrg
5073143b9aSmrg#include <ctype.h>
518a0d9095Smrg#include <stdlib.h>
5275ebec6dSmrg#include <string.h>
538a0d9095Smrg#ifdef HAVE_SYSTEMD_DAEMON
5475ebec6dSmrg#include <systemd/sd-daemon.h>
5575ebec6dSmrg#endif
5673143b9aSmrg
5773143b9aSmrg/*
5873143b9aSmrg * The transport table contains a definition for every transport (protocol)
5973143b9aSmrg * family. All operations that can be made on the transport go through this
6073143b9aSmrg * table.
6173143b9aSmrg *
6273143b9aSmrg * Each transport is assigned a unique transport id.
6373143b9aSmrg *
6473143b9aSmrg * New transports can be added by adding an entry in this table.
65e45ace2bSmrg * For compatibility, the transport ids should never be renumbered.
6673143b9aSmrg * Always add to the end of the list.
6773143b9aSmrg */
6873143b9aSmrg
6973143b9aSmrg#define TRANS_TLI_INET_INDEX		1
7073143b9aSmrg#define TRANS_TLI_TCP_INDEX		2
7173143b9aSmrg#define TRANS_TLI_TLI_INDEX		3
7273143b9aSmrg#define TRANS_SOCKET_UNIX_INDEX		4
7373143b9aSmrg#define TRANS_SOCKET_LOCAL_INDEX	5
7473143b9aSmrg#define TRANS_SOCKET_INET_INDEX		6
7573143b9aSmrg#define TRANS_SOCKET_TCP_INDEX		7
7673143b9aSmrg#define TRANS_DNET_INDEX		8
7773143b9aSmrg#define TRANS_LOCAL_LOCAL_INDEX		9
78e45ace2bSmrg/* 10 used to be PTS, but that's gone. */
7973143b9aSmrg#define TRANS_LOCAL_NAMED_INDEX		11
80af928962Smrg/* 12 used to be ISC, but that's gone. */
81e45ace2bSmrg/* 13 used to be SCO, but that's gone. */
8273143b9aSmrg#define TRANS_SOCKET_INET6_INDEX	14
8373143b9aSmrg#define TRANS_LOCAL_PIPE_INDEX		15
8473143b9aSmrg
8573143b9aSmrg
8673143b9aSmrgstatic
8773143b9aSmrgXtransport_table Xtransports[] = {
8873143b9aSmrg#if defined(TCPCONN)
8973143b9aSmrg    { &TRANS(SocketTCPFuncs),	TRANS_SOCKET_TCP_INDEX },
9073143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
9173143b9aSmrg    { &TRANS(SocketINET6Funcs),	TRANS_SOCKET_INET6_INDEX },
9273143b9aSmrg#endif /* IPv6 */
9373143b9aSmrg    { &TRANS(SocketINETFuncs),	TRANS_SOCKET_INET_INDEX },
9473143b9aSmrg#endif /* TCPCONN */
9573143b9aSmrg#if defined(UNIXCONN)
9673143b9aSmrg#if !defined(LOCALCONN)
9773143b9aSmrg    { &TRANS(SocketLocalFuncs),	TRANS_SOCKET_LOCAL_INDEX },
9873143b9aSmrg#endif /* !LOCALCONN */
9973143b9aSmrg    { &TRANS(SocketUNIXFuncs),	TRANS_SOCKET_UNIX_INDEX },
10073143b9aSmrg#endif /* UNIXCONN */
10173143b9aSmrg#if defined(LOCALCONN)
10273143b9aSmrg    { &TRANS(LocalFuncs),	TRANS_LOCAL_LOCAL_INDEX },
103e8a71cdfSmrg#if defined(SVR4) || defined(__SVR4)
10473143b9aSmrg    { &TRANS(NAMEDFuncs),	TRANS_LOCAL_NAMED_INDEX },
10573143b9aSmrg#endif
1063d2ed3e3Smrg#ifdef __sun
10773143b9aSmrg    { &TRANS(PIPEFuncs),	TRANS_LOCAL_PIPE_INDEX },
1083d2ed3e3Smrg#endif /* __sun */
10973143b9aSmrg#endif /* LOCALCONN */
11073143b9aSmrg};
11173143b9aSmrg
11273143b9aSmrg#define NUMTRANS	(sizeof(Xtransports)/sizeof(Xtransport_table))
11373143b9aSmrg
11473143b9aSmrg
11573143b9aSmrg#ifdef WIN32
11673143b9aSmrg#define ioctl ioctlsocket
11773143b9aSmrg#endif
11873143b9aSmrg
11973143b9aSmrg
12073143b9aSmrg
12173143b9aSmrg/*
12273143b9aSmrg * These are a few utility function used by the public interface functions.
12373143b9aSmrg */
12473143b9aSmrg
12573143b9aSmrgvoid
12673143b9aSmrgTRANS(FreeConnInfo) (XtransConnInfo ciptr)
12773143b9aSmrg
12873143b9aSmrg{
129fe567363Smrg    prmsg (3,"FreeConnInfo(%p)\n", ciptr);
13073143b9aSmrg
13173143b9aSmrg    if (ciptr->addr)
132fe567363Smrg	free (ciptr->addr);
13373143b9aSmrg
13473143b9aSmrg    if (ciptr->peeraddr)
135fe567363Smrg	free (ciptr->peeraddr);
13673143b9aSmrg
13773143b9aSmrg    if (ciptr->port)
138fe567363Smrg	free (ciptr->port);
13973143b9aSmrg
140fe567363Smrg    free (ciptr);
14173143b9aSmrg}
14273143b9aSmrg
14373143b9aSmrg
14473143b9aSmrg#define PROTOBUFSIZE	20
14573143b9aSmrg
14673143b9aSmrgstatic Xtransport *
147fe567363SmrgTRANS(SelectTransport) (const char *protocol)
14873143b9aSmrg
14973143b9aSmrg{
1503d2ed3e3Smrg#ifndef HAVE_STRCASECMP
15173143b9aSmrg    char 	protobuf[PROTOBUFSIZE];
1523d2ed3e3Smrg#endif
15373143b9aSmrg
154fe567363Smrg    prmsg (3,"SelectTransport(%s)\n", protocol);
15573143b9aSmrg
1563d2ed3e3Smrg#ifndef HAVE_STRCASECMP
15773143b9aSmrg    /*
15873143b9aSmrg     * Force Protocol to be lowercase as a way of doing
15973143b9aSmrg     * a case insensitive match.
16073143b9aSmrg     */
16173143b9aSmrg
16273143b9aSmrg    strncpy (protobuf, protocol, PROTOBUFSIZE - 1);
16373143b9aSmrg    protobuf[PROTOBUFSIZE-1] = '\0';
16473143b9aSmrg
16594f982dbSmrg    for (unsigned int i = 0; i < PROTOBUFSIZE && protobuf[i] != '\0'; i++)
1668a0d9095Smrg	if (isupper ((unsigned char)protobuf[i]))
1678a0d9095Smrg	    protobuf[i] = tolower ((unsigned char)protobuf[i]);
1683d2ed3e3Smrg#endif
16973143b9aSmrg
17073143b9aSmrg    /* Look at all of the configured protocols */
17173143b9aSmrg
17294f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
17373143b9aSmrg    {
1743d2ed3e3Smrg#ifndef HAVE_STRCASECMP
17573143b9aSmrg	if (!strcmp (protobuf, Xtransports[i].transport->TransName))
1763d2ed3e3Smrg#else
1773d2ed3e3Smrg	if (!strcasecmp (protocol, Xtransports[i].transport->TransName))
1783d2ed3e3Smrg#endif
17973143b9aSmrg	    return Xtransports[i].transport;
18073143b9aSmrg    }
18173143b9aSmrg
18273143b9aSmrg    return NULL;
18373143b9aSmrg}
18473143b9aSmrg
185e45ace2bSmrgstatic int
1866a3641a6SsnjTRANS(ParseAddress) (const char *address,
1876a3641a6Ssnj                     char **protocol, char **host, char **port)
18873143b9aSmrg
18973143b9aSmrg{
19073143b9aSmrg    /*
19173143b9aSmrg     * For the font library, the address is a string formatted
19273143b9aSmrg     * as "protocol/host:port[/catalogue]".  Note that the catologue
19373143b9aSmrg     * is optional.  At this time, the catologue info is ignored, but
19473143b9aSmrg     * we have to parse it anyways.
19573143b9aSmrg     *
19673143b9aSmrg     * Other than fontlib, the address is a string formatted
19773143b9aSmrg     * as "protocol/host:port".
19873143b9aSmrg     *
19973143b9aSmrg     * If the protocol part is missing, then assume TCP.
20073143b9aSmrg     * If the protocol part and host part are missing, then assume local.
20173143b9aSmrg     * If a "::" is found then assume DNET.
20273143b9aSmrg     */
20373143b9aSmrg
204e45ace2bSmrg    char	*mybuf, *tmpptr = NULL;
205e45ace2bSmrg    const char	*_protocol = NULL;
20694f982dbSmrg    const char	*_host, *_port;
20773143b9aSmrg    char	hostnamebuf[256];
20894f982dbSmrg    char	*_host_buf;
20973143b9aSmrg    int		_host_len;
21073143b9aSmrg
211fe567363Smrg    prmsg (3,"ParseAddress(%s)\n", address);
21273143b9aSmrg
213e45ace2bSmrg    /* First, check for AF_UNIX socket paths */
214e45ace2bSmrg    if (address[0] == '/') {
215e45ace2bSmrg        _protocol = "local";
216e45ace2bSmrg        _host = "";
217e45ace2bSmrg        _port = address;
218e45ace2bSmrg    } else
219e45ace2bSmrg#ifdef HAVE_LAUNCHD
220e45ace2bSmrg    /* launchd sockets will look like 'local//tmp/launch-XgkNns/:0' */
221e45ace2bSmrg    if(!strncmp(address,"local//",7)) {
222e45ace2bSmrg        _protocol="local";
223e45ace2bSmrg        _host="";
224e45ace2bSmrg        _port=address+6;
225e45ace2bSmrg    } else
226e45ace2bSmrg#endif
227e45ace2bSmrg    if (!strncmp(address, "unix:", 5)) {
228e45ace2bSmrg        _protocol = "local";
229e45ace2bSmrg        _host = "";
230e45ace2bSmrg        _port = address + 5;
231e45ace2bSmrg    }
232e45ace2bSmrg    if (_protocol)
233e45ace2bSmrg        goto done_parsing;
234e45ace2bSmrg
23573143b9aSmrg    /* Copy the string so it can be changed */
23673143b9aSmrg
237fe567363Smrg    tmpptr = mybuf = strdup (address);
23873143b9aSmrg
23973143b9aSmrg    /* Parse the string to get each component */
240fe567363Smrg
24173143b9aSmrg    /* Get the protocol part */
24273143b9aSmrg
24373143b9aSmrg    _protocol = mybuf;
24473143b9aSmrg
24573143b9aSmrg
24694f982dbSmrg    if ((mybuf == NULL) ||
24794f982dbSmrg        ( ((mybuf = strchr (mybuf, '/')) == NULL) &&
24894f982dbSmrg          ((mybuf = strrchr (tmpptr, ':')) == NULL) ) )
24994f982dbSmrg    {
25073143b9aSmrg	/* address is in a bad format */
25173143b9aSmrg	*protocol = NULL;
25273143b9aSmrg	*host = NULL;
25373143b9aSmrg	*port = NULL;
254fe567363Smrg	free (tmpptr);
25573143b9aSmrg	return 0;
25673143b9aSmrg    }
25773143b9aSmrg
25873143b9aSmrg    if (*mybuf == ':')
25973143b9aSmrg    {
26073143b9aSmrg	/*
26173143b9aSmrg	 * If there is a hostname, then assume tcp, otherwise
26273143b9aSmrg	 * it must be local.
26373143b9aSmrg	 */
26473143b9aSmrg	if (mybuf == tmpptr)
26573143b9aSmrg	{
26673143b9aSmrg	    /* There is neither a protocol or host specified */
26773143b9aSmrg	    _protocol = "local";
26873143b9aSmrg	}
26973143b9aSmrg	else
27073143b9aSmrg	{
27173143b9aSmrg	    /* There is a hostname specified */
27273143b9aSmrg	    _protocol = "tcp";
273e45ace2bSmrg	    mybuf = tmpptr;	/* reset to the beginning of the host ptr */
27473143b9aSmrg	}
27573143b9aSmrg    }
27673143b9aSmrg    else
27773143b9aSmrg    {
27873143b9aSmrg	/* *mybuf == '/' */
27973143b9aSmrg
28073143b9aSmrg	*mybuf ++= '\0'; /* put a null at the end of the protocol */
28173143b9aSmrg
28273143b9aSmrg	if (strlen(_protocol) == 0)
28373143b9aSmrg	{
28473143b9aSmrg	    /*
28573143b9aSmrg	     * If there is a hostname, then assume tcp, otherwise
28673143b9aSmrg	     * it must be local.
28773143b9aSmrg	     */
28873143b9aSmrg	    if (*mybuf != ':')
28973143b9aSmrg		_protocol = "tcp";
29073143b9aSmrg	    else
29173143b9aSmrg		_protocol = "local";
29273143b9aSmrg	}
29373143b9aSmrg    }
29473143b9aSmrg
29573143b9aSmrg    /* Get the host part */
29673143b9aSmrg
29794f982dbSmrg    _host = _host_buf = mybuf;
29873143b9aSmrg
29973143b9aSmrg    if ((mybuf = strrchr (mybuf,':')) == NULL)
30073143b9aSmrg    {
30173143b9aSmrg	*protocol = NULL;
30273143b9aSmrg	*host = NULL;
30373143b9aSmrg	*port = NULL;
304fe567363Smrg	free (tmpptr);
30573143b9aSmrg	return 0;
30673143b9aSmrg    }
30773143b9aSmrg
30873143b9aSmrg    *mybuf ++= '\0';
30973143b9aSmrg
31073143b9aSmrg    _host_len = strlen(_host);
31173143b9aSmrg    if (_host_len == 0)
31273143b9aSmrg    {
31373143b9aSmrg	TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
31473143b9aSmrg	_host = hostnamebuf;
31573143b9aSmrg    }
31673143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
31773143b9aSmrg    /* hostname in IPv6 [numeric_addr]:0 form? */
318fe567363Smrg    else if ( (_host_len > 3) &&
31973143b9aSmrg      ((strcmp(_protocol, "tcp") == 0) || (strcmp(_protocol, "inet6") == 0))
32094f982dbSmrg      && (_host_buf[0] == '[') && (_host_buf[_host_len - 1] == ']') ) {
32173143b9aSmrg	struct sockaddr_in6 sin6;
32273143b9aSmrg
32394f982dbSmrg	_host_buf[_host_len - 1] = '\0';
32473143b9aSmrg
32573143b9aSmrg	/* Verify address is valid IPv6 numeric form */
32673143b9aSmrg	if (inet_pton(AF_INET6, _host + 1, &sin6) == 1) {
32773143b9aSmrg	    /* It is. Use it as such. */
32873143b9aSmrg	    _host++;
32973143b9aSmrg	    _protocol = "inet6";
33073143b9aSmrg	} else {
33173143b9aSmrg	    /* It's not, restore it just in case some other code can use it. */
33294f982dbSmrg	    _host_buf[_host_len - 1] = ']';
33373143b9aSmrg	}
33473143b9aSmrg    }
33573143b9aSmrg#endif
33673143b9aSmrg
33773143b9aSmrg
33873143b9aSmrg    /* Get the port */
33973143b9aSmrg
34073143b9aSmrg    _port = mybuf;
34173143b9aSmrg
34273143b9aSmrg#if defined(FONT_t) || defined(FS_t)
34373143b9aSmrg    /*
34473143b9aSmrg     * Is there an optional catalogue list?
34573143b9aSmrg     */
34673143b9aSmrg
34773143b9aSmrg    if ((mybuf = strchr (mybuf,'/')) != NULL)
34873143b9aSmrg	*mybuf ++= '\0';
34973143b9aSmrg
35073143b9aSmrg    /*
35173143b9aSmrg     * The rest, if any, is the (currently unused) catalogue list.
35273143b9aSmrg     *
35373143b9aSmrg     * _catalogue = mybuf;
35473143b9aSmrg     */
35573143b9aSmrg#endif
35673143b9aSmrg
357e45ace2bSmrgdone_parsing:
35873143b9aSmrg    /*
35973143b9aSmrg     * Now that we have all of the components, allocate new
36073143b9aSmrg     * string space for them.
36173143b9aSmrg     */
36273143b9aSmrg
363fe567363Smrg    if ((*protocol = strdup (_protocol)) == NULL)
36473143b9aSmrg    {
36573143b9aSmrg	/* Malloc failed */
36673143b9aSmrg	*port = NULL;
36773143b9aSmrg	*host = NULL;
36873143b9aSmrg	*protocol = NULL;
369fe567363Smrg	free (tmpptr);
37073143b9aSmrg	return 0;
37173143b9aSmrg    }
37273143b9aSmrg
373fe567363Smrg    if ((*host = strdup (_host)) == NULL)
37473143b9aSmrg    {
37573143b9aSmrg	/* Malloc failed */
37673143b9aSmrg	*port = NULL;
37773143b9aSmrg	*host = NULL;
378fe567363Smrg	free (*protocol);
37973143b9aSmrg	*protocol = NULL;
380fe567363Smrg	free (tmpptr);
38173143b9aSmrg	return 0;
382fe567363Smrg    }
38373143b9aSmrg
384fe567363Smrg    if ((*port = strdup (_port)) == NULL)
38573143b9aSmrg    {
38673143b9aSmrg	/* Malloc failed */
38773143b9aSmrg	*port = NULL;
388fe567363Smrg	free (*host);
38973143b9aSmrg	*host = NULL;
390fe567363Smrg	free (*protocol);
39173143b9aSmrg	*protocol = NULL;
392fe567363Smrg	free (tmpptr);
39373143b9aSmrg	return 0;
39473143b9aSmrg    }
39573143b9aSmrg
396fe567363Smrg    free (tmpptr);
39773143b9aSmrg
39873143b9aSmrg    return 1;
39973143b9aSmrg}
40073143b9aSmrg
40173143b9aSmrg
40273143b9aSmrg/*
40373143b9aSmrg * TRANS(Open) does all of the real work opening a connection. The only
40473143b9aSmrg * funny part about this is the type parameter which is used to decide which
40573143b9aSmrg * type of open to perform.
40673143b9aSmrg */
40773143b9aSmrg
40873143b9aSmrgstatic XtransConnInfo
4096a3641a6SsnjTRANS(Open) (int type, const char *address)
41073143b9aSmrg
41173143b9aSmrg{
41273143b9aSmrg    char 		*protocol = NULL, *host = NULL, *port = NULL;
41373143b9aSmrg    XtransConnInfo	ciptr = NULL;
41473143b9aSmrg    Xtransport		*thistrans;
41573143b9aSmrg
416fe567363Smrg    prmsg (2,"Open(%d,%s)\n", type, address);
41773143b9aSmrg
418fe567363Smrg#if defined(WIN32) && defined(TCPCONN)
41973143b9aSmrg    if (TRANS(WSAStartup)())
42073143b9aSmrg    {
421fe567363Smrg	prmsg (1,"Open: WSAStartup failed\n");
42273143b9aSmrg	return NULL;
42373143b9aSmrg    }
42473143b9aSmrg#endif
42573143b9aSmrg
42673143b9aSmrg    /* Parse the Address */
42773143b9aSmrg
42873143b9aSmrg    if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
42973143b9aSmrg    {
430fe567363Smrg	prmsg (1,"Open: Unable to Parse address %s\n", address);
43173143b9aSmrg	return NULL;
43273143b9aSmrg    }
43373143b9aSmrg
43473143b9aSmrg    /* Determine the transport type */
43573143b9aSmrg
43673143b9aSmrg    if ((thistrans = TRANS(SelectTransport) (protocol)) == NULL)
43773143b9aSmrg    {
438fe567363Smrg	prmsg (1,"Open: Unable to find transport for %s\n",
439fe567363Smrg	       protocol);
44073143b9aSmrg
441fe567363Smrg	free (protocol);
442fe567363Smrg	free (host);
443fe567363Smrg	free (port);
44473143b9aSmrg	return NULL;
44573143b9aSmrg    }
44673143b9aSmrg
44773143b9aSmrg    /* Open the transport */
44873143b9aSmrg
44973143b9aSmrg    switch (type)
45073143b9aSmrg    {
45173143b9aSmrg    case XTRANS_OPEN_COTS_CLIENT:
45273143b9aSmrg#ifdef TRANS_CLIENT
45373143b9aSmrg	ciptr = thistrans->OpenCOTSClient(thistrans, protocol, host, port);
45473143b9aSmrg#endif /* TRANS_CLIENT */
45573143b9aSmrg	break;
45673143b9aSmrg    case XTRANS_OPEN_COTS_SERVER:
45773143b9aSmrg#ifdef TRANS_SERVER
45873143b9aSmrg	ciptr = thistrans->OpenCOTSServer(thistrans, protocol, host, port);
45973143b9aSmrg#endif /* TRANS_SERVER */
46073143b9aSmrg	break;
46173143b9aSmrg    default:
462fe567363Smrg	prmsg (1,"Open: Unknown Open type %d\n", type);
46373143b9aSmrg    }
46473143b9aSmrg
46573143b9aSmrg    if (ciptr == NULL)
46673143b9aSmrg    {
467fe567363Smrg	if (!(thistrans->flags & TRANS_DISABLED))
46873143b9aSmrg	{
469fe567363Smrg	    prmsg (1,"Open: transport open failed for %s/%s:%s\n",
47073143b9aSmrg	           protocol, host, port);
47173143b9aSmrg	}
472fe567363Smrg	free (protocol);
473fe567363Smrg	free (host);
474fe567363Smrg	free (port);
47573143b9aSmrg	return NULL;
47673143b9aSmrg    }
47773143b9aSmrg
47873143b9aSmrg    ciptr->transptr = thistrans;
47973143b9aSmrg    ciptr->port = port;			/* We need this for TRANS(Reopen) */
48073143b9aSmrg
481fe567363Smrg    free (protocol);
482fe567363Smrg    free (host);
48373143b9aSmrg
48473143b9aSmrg    return ciptr;
48573143b9aSmrg}
48673143b9aSmrg
48773143b9aSmrg
48873143b9aSmrg#ifdef TRANS_REOPEN
48973143b9aSmrg
49073143b9aSmrg/*
49173143b9aSmrg * We might want to create an XtransConnInfo object based on a previously
49273143b9aSmrg * opened connection.  For example, the font server may clone itself and
49373143b9aSmrg * pass file descriptors to the parent.
49473143b9aSmrg */
49573143b9aSmrg
49673143b9aSmrgstatic XtransConnInfo
4976a3641a6SsnjTRANS(Reopen) (int type, int trans_id, int fd, const char *port)
49873143b9aSmrg
49973143b9aSmrg{
50073143b9aSmrg    XtransConnInfo	ciptr = NULL;
50173143b9aSmrg    Xtransport		*thistrans = NULL;
50273143b9aSmrg    char		*save_port;
50373143b9aSmrg
504fe567363Smrg    prmsg (2,"Reopen(%d,%d,%s)\n", trans_id, fd, port);
50573143b9aSmrg
50673143b9aSmrg    /* Determine the transport type */
50773143b9aSmrg
50894f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
50994f982dbSmrg    {
51073143b9aSmrg	if (Xtransports[i].transport_id == trans_id)
51173143b9aSmrg	{
51273143b9aSmrg	    thistrans = Xtransports[i].transport;
51373143b9aSmrg	    break;
51473143b9aSmrg	}
51594f982dbSmrg    }
51673143b9aSmrg
51773143b9aSmrg    if (thistrans == NULL)
51873143b9aSmrg    {
519fe567363Smrg	prmsg (1,"Reopen: Unable to find transport id %d\n",
520fe567363Smrg	       trans_id);
52173143b9aSmrg
52273143b9aSmrg	return NULL;
52373143b9aSmrg    }
52473143b9aSmrg
525fe567363Smrg    if ((save_port = strdup (port)) == NULL)
52673143b9aSmrg    {
527fe567363Smrg	prmsg (1,"Reopen: Unable to malloc port string\n");
52873143b9aSmrg
52973143b9aSmrg	return NULL;
53073143b9aSmrg    }
53173143b9aSmrg
53273143b9aSmrg    /* Get a new XtransConnInfo object */
53373143b9aSmrg
53473143b9aSmrg    switch (type)
53573143b9aSmrg    {
53673143b9aSmrg    case XTRANS_OPEN_COTS_SERVER:
53773143b9aSmrg	ciptr = thistrans->ReopenCOTSServer(thistrans, fd, port);
53873143b9aSmrg	break;
53973143b9aSmrg    default:
540fe567363Smrg	prmsg (1,"Reopen: Bad Open type %d\n", type);
54173143b9aSmrg    }
54273143b9aSmrg
54373143b9aSmrg    if (ciptr == NULL)
54473143b9aSmrg    {
545fe567363Smrg	prmsg (1,"Reopen: transport open failed\n");
546fe567363Smrg	free (save_port);
54773143b9aSmrg	return NULL;
54873143b9aSmrg    }
54973143b9aSmrg
55073143b9aSmrg    ciptr->transptr = thistrans;
55173143b9aSmrg    ciptr->port = save_port;
55273143b9aSmrg
55373143b9aSmrg    return ciptr;
55473143b9aSmrg}
55573143b9aSmrg
55673143b9aSmrg#endif /* TRANS_REOPEN */
55773143b9aSmrg
55873143b9aSmrg
55973143b9aSmrg
56073143b9aSmrg/*
56173143b9aSmrg * These are the public interfaces to this Transport interface.
56273143b9aSmrg * These are the only functions that should have knowledge of the transport
56373143b9aSmrg * table.
56473143b9aSmrg */
56573143b9aSmrg
56673143b9aSmrg#ifdef TRANS_CLIENT
56773143b9aSmrg
56873143b9aSmrgXtransConnInfo
5696a3641a6SsnjTRANS(OpenCOTSClient) (const char *address)
57073143b9aSmrg
57173143b9aSmrg{
572fe567363Smrg    prmsg (2,"OpenCOTSClient(%s)\n", address);
57373143b9aSmrg    return TRANS(Open) (XTRANS_OPEN_COTS_CLIENT, address);
57473143b9aSmrg}
57573143b9aSmrg
57673143b9aSmrg#endif /* TRANS_CLIENT */
57773143b9aSmrg
57873143b9aSmrg
57973143b9aSmrg#ifdef TRANS_SERVER
58073143b9aSmrg
58173143b9aSmrgXtransConnInfo
5826a3641a6SsnjTRANS(OpenCOTSServer) (const char *address)
58373143b9aSmrg
58473143b9aSmrg{
585fe567363Smrg    prmsg (2,"OpenCOTSServer(%s)\n", address);
58673143b9aSmrg    return TRANS(Open) (XTRANS_OPEN_COTS_SERVER, address);
58773143b9aSmrg}
58873143b9aSmrg
58973143b9aSmrg#endif /* TRANS_SERVER */
59073143b9aSmrg
59173143b9aSmrg
59273143b9aSmrg#ifdef TRANS_REOPEN
59373143b9aSmrg
59473143b9aSmrgXtransConnInfo
5956a3641a6SsnjTRANS(ReopenCOTSServer) (int trans_id, int fd, const char *port)
59673143b9aSmrg
59773143b9aSmrg{
598fe567363Smrg    prmsg (2,"ReopenCOTSServer(%d, %d, %s)\n", trans_id, fd, port);
59973143b9aSmrg    return TRANS(Reopen) (XTRANS_OPEN_COTS_SERVER, trans_id, fd, port);
60073143b9aSmrg}
60173143b9aSmrg
60273143b9aSmrgint
603fe567363SmrgTRANS(GetReopenInfo) (XtransConnInfo ciptr,
60473143b9aSmrg		      int *trans_id, int *fd, char **port)
60573143b9aSmrg
60673143b9aSmrg{
60794f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
60894f982dbSmrg    {
60973143b9aSmrg	if (Xtransports[i].transport == ciptr->transptr)
61073143b9aSmrg	{
61173143b9aSmrg	    *trans_id = Xtransports[i].transport_id;
61273143b9aSmrg	    *fd = ciptr->fd;
61373143b9aSmrg
614fe567363Smrg	    if ((*port = strdup (ciptr->port)) == NULL)
61573143b9aSmrg		return 0;
61673143b9aSmrg	    else
61773143b9aSmrg		return 1;
61873143b9aSmrg	}
61994f982dbSmrg    }
62073143b9aSmrg
62173143b9aSmrg    return 0;
62273143b9aSmrg}
62373143b9aSmrg
62473143b9aSmrg#endif /* TRANS_REOPEN */
62573143b9aSmrg
62673143b9aSmrg
62773143b9aSmrgint
62873143b9aSmrgTRANS(SetOption) (XtransConnInfo ciptr, int option, int arg)
62973143b9aSmrg
63073143b9aSmrg{
63173143b9aSmrg    int	fd = ciptr->fd;
63273143b9aSmrg    int	ret = 0;
63373143b9aSmrg
634fe567363Smrg    prmsg (2,"SetOption(%d,%d,%d)\n", fd, option, arg);
63573143b9aSmrg
63673143b9aSmrg    /*
63773143b9aSmrg     * For now, all transport type use the same stuff for setting options.
63873143b9aSmrg     * As long as this is true, we can put the common code here. Once a more
63973143b9aSmrg     * complicated transport such as shared memory or an OSI implementation
64073143b9aSmrg     * that uses the session and application libraries is implemented, this
64173143b9aSmrg     * code may have to move to a transport dependent function.
64273143b9aSmrg     *
64373143b9aSmrg     * ret = ciptr->transptr->SetOption (ciptr, option, arg);
64473143b9aSmrg     */
64573143b9aSmrg
64673143b9aSmrg    switch (option)
64773143b9aSmrg    {
64873143b9aSmrg    case TRANS_NONBLOCKING:
64973143b9aSmrg	switch (arg)
65073143b9aSmrg	{
65173143b9aSmrg	case 0:
65273143b9aSmrg	    /* Set to blocking mode */
65373143b9aSmrg	    break;
65473143b9aSmrg	case 1: /* Set to non-blocking mode */
65573143b9aSmrg
656e45ace2bSmrg#if defined(O_NONBLOCK)
65773143b9aSmrg	    ret = fcntl (fd, F_GETFL, 0);
65873143b9aSmrg	    if (ret != -1)
65973143b9aSmrg		ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK);
66073143b9aSmrg#else
66173143b9aSmrg#ifdef FIOSNBIO
66273143b9aSmrg	{
66373143b9aSmrg	    int arg;
66473143b9aSmrg	    arg = 1;
66573143b9aSmrg	    ret = ioctl (fd, FIOSNBIO, &arg);
66673143b9aSmrg	}
66773143b9aSmrg#else
668fe567363Smrg#if defined(WIN32)
66973143b9aSmrg	{
67073143b9aSmrg#ifdef WIN32
67173143b9aSmrg	    u_long arg;
67273143b9aSmrg#else
67373143b9aSmrg	    int arg;
67473143b9aSmrg#endif
67573143b9aSmrg	    arg = 1;
67673143b9aSmrg/* IBM TCP/IP understands this option too well: it causes TRANS(Read) to fail
67773143b9aSmrg * eventually with EWOULDBLOCK */
67873143b9aSmrg	    ret = ioctl (fd, FIONBIO, &arg);
67973143b9aSmrg	}
68073143b9aSmrg#else
68173143b9aSmrg	    ret = fcntl (fd, F_GETFL, 0);
68273143b9aSmrg#ifdef FNDELAY
68373143b9aSmrg	    ret = fcntl (fd, F_SETFL, ret | FNDELAY);
68473143b9aSmrg#else
68573143b9aSmrg	    ret = fcntl (fd, F_SETFL, ret | O_NDELAY);
68673143b9aSmrg#endif
68773143b9aSmrg#endif /* AIXV3  || uniosu */
68873143b9aSmrg#endif /* FIOSNBIO */
68973143b9aSmrg#endif /* O_NONBLOCK */
69073143b9aSmrg	    break;
69173143b9aSmrg	default:
69273143b9aSmrg	    /* Unknown option */
69373143b9aSmrg	    break;
69473143b9aSmrg	}
69573143b9aSmrg	break;
69673143b9aSmrg    case TRANS_CLOSEONEXEC:
69773143b9aSmrg#ifdef F_SETFD
69873143b9aSmrg#ifdef FD_CLOEXEC
69973143b9aSmrg	ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
70073143b9aSmrg#else
70173143b9aSmrg	ret = fcntl (fd, F_SETFD, 1);
70273143b9aSmrg#endif /* FD_CLOEXEC */
70373143b9aSmrg#endif /* F_SETFD */
70473143b9aSmrg	break;
70573143b9aSmrg    }
706fe567363Smrg
70773143b9aSmrg    return ret;
70873143b9aSmrg}
70973143b9aSmrg
71073143b9aSmrg#ifdef TRANS_SERVER
71173143b9aSmrg
71273143b9aSmrgint
7136a3641a6SsnjTRANS(CreateListener) (XtransConnInfo ciptr, const char *port, unsigned int flags)
71473143b9aSmrg
71573143b9aSmrg{
71673143b9aSmrg    return ciptr->transptr->CreateListener (ciptr, port, flags);
71773143b9aSmrg}
71873143b9aSmrg
71975ebec6dSmrgint
72075ebec6dSmrgTRANS(Received) (const char * protocol)
72175ebec6dSmrg
72275ebec6dSmrg{
72375ebec6dSmrg   Xtransport *trans;
72475ebec6dSmrg   int i = 0, ret = 0;
72575ebec6dSmrg
72675ebec6dSmrg   prmsg (5, "Received(%s)\n", protocol);
72775ebec6dSmrg
72875ebec6dSmrg   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
72975ebec6dSmrg   {
73075ebec6dSmrg	prmsg (1,"Received: unable to find transport: %s\n",
73175ebec6dSmrg	       protocol);
73275ebec6dSmrg
73375ebec6dSmrg	return -1;
73475ebec6dSmrg   }
73575ebec6dSmrg   if (trans->flags & TRANS_ALIAS) {
73675ebec6dSmrg       if (trans->nolisten)
73775ebec6dSmrg	   while (trans->nolisten[i]) {
73875ebec6dSmrg	       ret |= TRANS(Received)(trans->nolisten[i]);
73975ebec6dSmrg	       i++;
74075ebec6dSmrg       }
74175ebec6dSmrg   }
74275ebec6dSmrg
74375ebec6dSmrg   trans->flags |= TRANS_RECEIVED;
74475ebec6dSmrg   return ret;
74575ebec6dSmrg}
74675ebec6dSmrg
74773143b9aSmrgint
748fe567363SmrgTRANS(NoListen) (const char * protocol)
749fe567363Smrg
75073143b9aSmrg{
75173143b9aSmrg   Xtransport *trans;
75273143b9aSmrg   int i = 0, ret = 0;
753fe567363Smrg
754fe567363Smrg   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
75573143b9aSmrg   {
756fe567363Smrg	prmsg (1,"TransNoListen: unable to find transport: %s\n",
757fe567363Smrg	       protocol);
75873143b9aSmrg
75973143b9aSmrg	return -1;
76073143b9aSmrg   }
76173143b9aSmrg   if (trans->flags & TRANS_ALIAS) {
76273143b9aSmrg       if (trans->nolisten)
76373143b9aSmrg	   while (trans->nolisten[i]) {
76473143b9aSmrg	       ret |= TRANS(NoListen)(trans->nolisten[i]);
76573143b9aSmrg	       i++;
76673143b9aSmrg       }
76773143b9aSmrg   }
76873143b9aSmrg
76973143b9aSmrg   trans->flags |= TRANS_NOLISTEN;
77073143b9aSmrg   return ret;
77173143b9aSmrg}
77273143b9aSmrg
7736a3641a6Ssnjint
7746a3641a6SsnjTRANS(Listen) (const char * protocol)
7756a3641a6Ssnj{
7766a3641a6Ssnj   Xtransport *trans;
7776a3641a6Ssnj   int i = 0, ret = 0;
7786a3641a6Ssnj
7796a3641a6Ssnj   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
7806a3641a6Ssnj   {
7816a3641a6Ssnj	prmsg (1,"TransListen: unable to find transport: %s\n",
7826a3641a6Ssnj	       protocol);
7836a3641a6Ssnj
7846a3641a6Ssnj	return -1;
7856a3641a6Ssnj   }
7866a3641a6Ssnj   if (trans->flags & TRANS_ALIAS) {
7876a3641a6Ssnj       if (trans->nolisten)
7886a3641a6Ssnj	   while (trans->nolisten[i]) {
7896a3641a6Ssnj	       ret |= TRANS(Listen)(trans->nolisten[i]);
7906a3641a6Ssnj	       i++;
7916a3641a6Ssnj       }
7926a3641a6Ssnj   }
7936a3641a6Ssnj
7946a3641a6Ssnj   trans->flags &= ~TRANS_NOLISTEN;
7956a3641a6Ssnj   return ret;
7966a3641a6Ssnj}
7976a3641a6Ssnj
79875ebec6dSmrgint
79975ebec6dSmrgTRANS(IsListening) (const char * protocol)
80075ebec6dSmrg{
80175ebec6dSmrg   Xtransport *trans;
80275ebec6dSmrg
80375ebec6dSmrg   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
80475ebec6dSmrg   {
80575ebec6dSmrg	prmsg (1,"TransIsListening: unable to find transport: %s\n",
80675ebec6dSmrg	       protocol);
80775ebec6dSmrg
80875ebec6dSmrg	return 0;
80975ebec6dSmrg   }
81075ebec6dSmrg
81175ebec6dSmrg   return !(trans->flags & TRANS_NOLISTEN);
81275ebec6dSmrg}
81375ebec6dSmrg
81473143b9aSmrgint
81573143b9aSmrgTRANS(ResetListener) (XtransConnInfo ciptr)
81673143b9aSmrg
81773143b9aSmrg{
81873143b9aSmrg    if (ciptr->transptr->ResetListener)
81973143b9aSmrg	return ciptr->transptr->ResetListener (ciptr);
82073143b9aSmrg    else
82173143b9aSmrg	return TRANS_RESET_NOOP;
82273143b9aSmrg}
82373143b9aSmrg
82473143b9aSmrg
82573143b9aSmrgXtransConnInfo
82673143b9aSmrgTRANS(Accept) (XtransConnInfo ciptr, int *status)
82773143b9aSmrg
82873143b9aSmrg{
82973143b9aSmrg    XtransConnInfo	newciptr;
83073143b9aSmrg
831fe567363Smrg    prmsg (2,"Accept(%d)\n", ciptr->fd);
83273143b9aSmrg
83373143b9aSmrg    newciptr = ciptr->transptr->Accept (ciptr, status);
83473143b9aSmrg
83573143b9aSmrg    if (newciptr)
83673143b9aSmrg	newciptr->transptr = ciptr->transptr;
83773143b9aSmrg
83873143b9aSmrg    return newciptr;
83973143b9aSmrg}
84073143b9aSmrg
84173143b9aSmrg#endif /* TRANS_SERVER */
84273143b9aSmrg
84373143b9aSmrg
84473143b9aSmrg#ifdef TRANS_CLIENT
84573143b9aSmrg
84673143b9aSmrgint
8476a3641a6SsnjTRANS(Connect) (XtransConnInfo ciptr, const char *address)
84873143b9aSmrg
84973143b9aSmrg{
85073143b9aSmrg    char	*protocol;
85173143b9aSmrg    char	*host;
85273143b9aSmrg    char	*port;
85373143b9aSmrg    int		ret;
85473143b9aSmrg
855fe567363Smrg    prmsg (2,"Connect(%d,%s)\n", ciptr->fd, address);
85673143b9aSmrg
85773143b9aSmrg    if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
85873143b9aSmrg    {
859fe567363Smrg	prmsg (1,"Connect: Unable to Parse address %s\n",
860fe567363Smrg	       address);
86173143b9aSmrg	return -1;
86273143b9aSmrg    }
86373143b9aSmrg
86473143b9aSmrg#ifdef HAVE_LAUNCHD
8658d4c0f7bSmrg    if (!host) host=strdup("");
86673143b9aSmrg#endif
86773143b9aSmrg
86873143b9aSmrg    if (!port || !*port)
86973143b9aSmrg    {
870fe567363Smrg	prmsg (1,"Connect: Missing port specification in %s\n",
871fe567363Smrg	      address);
872fe567363Smrg	if (protocol) free (protocol);
873fe567363Smrg	if (host) free (host);
87473143b9aSmrg	return -1;
87573143b9aSmrg    }
87673143b9aSmrg
87773143b9aSmrg    ret = ciptr->transptr->Connect (ciptr, host, port);
87873143b9aSmrg
879fe567363Smrg    if (protocol) free (protocol);
880fe567363Smrg    if (host) free (host);
881fe567363Smrg    if (port) free (port);
882fe567363Smrg
88373143b9aSmrg    return ret;
88473143b9aSmrg}
88573143b9aSmrg
88673143b9aSmrg#endif /* TRANS_CLIENT */
88773143b9aSmrg
88873143b9aSmrg
88973143b9aSmrgint
89073143b9aSmrgTRANS(BytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
89173143b9aSmrg
89273143b9aSmrg{
89373143b9aSmrg    return ciptr->transptr->BytesReadable (ciptr, pend);
89473143b9aSmrg}
89573143b9aSmrg
89673143b9aSmrgint
89773143b9aSmrgTRANS(Read) (XtransConnInfo ciptr, char *buf, int size)
89873143b9aSmrg
89973143b9aSmrg{
90073143b9aSmrg    return ciptr->transptr->Read (ciptr, buf, size);
90173143b9aSmrg}
90273143b9aSmrg
90373143b9aSmrgint
90473143b9aSmrgTRANS(Write) (XtransConnInfo ciptr, char *buf, int size)
90573143b9aSmrg
90673143b9aSmrg{
90773143b9aSmrg    return ciptr->transptr->Write (ciptr, buf, size);
90873143b9aSmrg}
90973143b9aSmrg
91073143b9aSmrgint
91173143b9aSmrgTRANS(Readv) (XtransConnInfo ciptr, struct iovec *buf, int size)
91273143b9aSmrg
91373143b9aSmrg{
91473143b9aSmrg    return ciptr->transptr->Readv (ciptr, buf, size);
91573143b9aSmrg}
91673143b9aSmrg
91773143b9aSmrgint
91873143b9aSmrgTRANS(Writev) (XtransConnInfo ciptr, struct iovec *buf, int size)
91973143b9aSmrg
92073143b9aSmrg{
92173143b9aSmrg    return ciptr->transptr->Writev (ciptr, buf, size);
92273143b9aSmrg}
92373143b9aSmrg
92475ebec6dSmrg#if XTRANS_SEND_FDS
92575ebec6dSmrgint
92675ebec6dSmrgTRANS(SendFd) (XtransConnInfo ciptr, int fd, int do_close)
92775ebec6dSmrg{
92875ebec6dSmrg    return ciptr->transptr->SendFd(ciptr, fd, do_close);
92975ebec6dSmrg}
93075ebec6dSmrg
93175ebec6dSmrgint
93275ebec6dSmrgTRANS(RecvFd) (XtransConnInfo ciptr)
93375ebec6dSmrg{
93475ebec6dSmrg    return ciptr->transptr->RecvFd(ciptr);
93575ebec6dSmrg}
93675ebec6dSmrg#endif
93775ebec6dSmrg
93873143b9aSmrgint
93973143b9aSmrgTRANS(Disconnect) (XtransConnInfo ciptr)
94073143b9aSmrg
94173143b9aSmrg{
94273143b9aSmrg    return ciptr->transptr->Disconnect (ciptr);
94373143b9aSmrg}
94473143b9aSmrg
94573143b9aSmrgint
94673143b9aSmrgTRANS(Close) (XtransConnInfo ciptr)
94773143b9aSmrg
94873143b9aSmrg{
94973143b9aSmrg    int ret;
95073143b9aSmrg
951fe567363Smrg    prmsg (2,"Close(%d)\n", ciptr->fd);
95273143b9aSmrg
95373143b9aSmrg    ret = ciptr->transptr->Close (ciptr);
95473143b9aSmrg
95573143b9aSmrg    TRANS(FreeConnInfo) (ciptr);
95673143b9aSmrg
95773143b9aSmrg    return ret;
95873143b9aSmrg}
95973143b9aSmrg
96073143b9aSmrgint
96173143b9aSmrgTRANS(CloseForCloning) (XtransConnInfo ciptr)
96273143b9aSmrg
96373143b9aSmrg{
96473143b9aSmrg    int ret;
96573143b9aSmrg
966fe567363Smrg    prmsg (2,"CloseForCloning(%d)\n", ciptr->fd);
96773143b9aSmrg
96873143b9aSmrg    ret = ciptr->transptr->CloseForCloning (ciptr);
96973143b9aSmrg
97073143b9aSmrg    TRANS(FreeConnInfo) (ciptr);
97173143b9aSmrg
97273143b9aSmrg    return ret;
97373143b9aSmrg}
97473143b9aSmrg
97573143b9aSmrgint
97673143b9aSmrgTRANS(IsLocal) (XtransConnInfo ciptr)
97773143b9aSmrg
97873143b9aSmrg{
97973143b9aSmrg    return (ciptr->family == AF_UNIX);
98073143b9aSmrg}
98173143b9aSmrg
98273143b9aSmrgint
983fe567363SmrgTRANS(GetPeerAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
98473143b9aSmrg		    Xtransaddr **addrp)
98573143b9aSmrg
98673143b9aSmrg{
987fe567363Smrg    prmsg (2,"GetPeerAddr(%d)\n", ciptr->fd);
98873143b9aSmrg
98973143b9aSmrg    *familyp = ciptr->family;
99073143b9aSmrg    *addrlenp = ciptr->peeraddrlen;
99173143b9aSmrg
992fe567363Smrg    if ((*addrp = malloc (ciptr->peeraddrlen)) == NULL)
99373143b9aSmrg    {
994fe567363Smrg	prmsg (1,"GetPeerAddr: malloc failed\n");
99573143b9aSmrg	return -1;
99673143b9aSmrg    }
99773143b9aSmrg    memcpy(*addrp, ciptr->peeraddr, ciptr->peeraddrlen);
99873143b9aSmrg
99973143b9aSmrg    return 0;
100073143b9aSmrg}
100173143b9aSmrg
100273143b9aSmrg
100373143b9aSmrgint
100473143b9aSmrgTRANS(GetConnectionNumber) (XtransConnInfo ciptr)
100573143b9aSmrg
100673143b9aSmrg{
100773143b9aSmrg    return ciptr->fd;
100873143b9aSmrg}
100973143b9aSmrg
101073143b9aSmrg
101173143b9aSmrg/*
101273143b9aSmrg * These functions are really utility functions, but they require knowledge
101373143b9aSmrg * of the internal data structures, so they have to be part of the Transport
1014e45ace2bSmrg * Independent API.
101573143b9aSmrg */
101673143b9aSmrg
101773143b9aSmrg#ifdef TRANS_SERVER
101873143b9aSmrg
101973143b9aSmrgstatic int
102073143b9aSmrgcomplete_network_count (void)
102173143b9aSmrg
102273143b9aSmrg{
102373143b9aSmrg    int count = 0;
102473143b9aSmrg    int found_local = 0;
102573143b9aSmrg
102673143b9aSmrg    /*
102773143b9aSmrg     * For a complete network, we only need one LOCALCONN transport to work
102873143b9aSmrg     */
102973143b9aSmrg
103094f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
103173143b9aSmrg    {
103273143b9aSmrg	if (Xtransports[i].transport->flags & TRANS_ALIAS
103373143b9aSmrg   	 || Xtransports[i].transport->flags & TRANS_NOLISTEN)
103473143b9aSmrg	    continue;
103573143b9aSmrg
103673143b9aSmrg	if (Xtransports[i].transport->flags & TRANS_LOCAL)
103773143b9aSmrg	    found_local = 1;
103873143b9aSmrg	else
103973143b9aSmrg	    count++;
104073143b9aSmrg    }
104173143b9aSmrg
104273143b9aSmrg    return (count + found_local);
104373143b9aSmrg}
104473143b9aSmrg
104573143b9aSmrg
104675ebec6dSmrgstatic int
10476a3641a6Ssnjreceive_listening_fds(const char* port, XtransConnInfo* temp_ciptrs,
10486a3641a6Ssnj                      int* count_ret)
104975ebec6dSmrg
105075ebec6dSmrg{
105175ebec6dSmrg#ifdef HAVE_SYSTEMD_DAEMON
105275ebec6dSmrg    XtransConnInfo ciptr;
105375ebec6dSmrg    int i, systemd_listen_fds;
105475ebec6dSmrg
105575ebec6dSmrg    systemd_listen_fds = sd_listen_fds(1);
105675ebec6dSmrg    if (systemd_listen_fds < 0)
105775ebec6dSmrg    {
105875ebec6dSmrg        prmsg (1, "receive_listening_fds: sd_listen_fds error: %s\n",
105975ebec6dSmrg               strerror(-systemd_listen_fds));
106075ebec6dSmrg        return -1;
106175ebec6dSmrg    }
106275ebec6dSmrg
106394f982dbSmrg    for (i = 0; i < systemd_listen_fds && *count_ret < (int)NUMTRANS; i++)
106475ebec6dSmrg    {
106575ebec6dSmrg        struct sockaddr_storage a;
106675ebec6dSmrg        int ti;
106775ebec6dSmrg        const char* tn;
106875ebec6dSmrg        socklen_t al;
106975ebec6dSmrg
107075ebec6dSmrg        al = sizeof(a);
107175ebec6dSmrg        if (getsockname(i + SD_LISTEN_FDS_START, (struct sockaddr*)&a, &al) < 0) {
107275ebec6dSmrg            prmsg (1, "receive_listening_fds: getsockname error: %s\n",
107375ebec6dSmrg                   strerror(errno));
107475ebec6dSmrg            return -1;
107575ebec6dSmrg        }
107675ebec6dSmrg
107775ebec6dSmrg        switch (a.ss_family)
107875ebec6dSmrg        {
107975ebec6dSmrg        case AF_UNIX:
108075ebec6dSmrg            ti = TRANS_SOCKET_UNIX_INDEX;
108175ebec6dSmrg            if (*((struct sockaddr_un*)&a)->sun_path == '\0' &&
108275ebec6dSmrg                al > sizeof(sa_family_t))
108375ebec6dSmrg                tn = "local";
108475ebec6dSmrg            else
108575ebec6dSmrg                tn = "unix";
108675ebec6dSmrg            break;
108775ebec6dSmrg        case AF_INET:
108875ebec6dSmrg            ti = TRANS_SOCKET_INET_INDEX;
108975ebec6dSmrg            tn = "inet";
109075ebec6dSmrg            break;
109175ebec6dSmrg#if defined(IPv6) && defined(AF_INET6)
109275ebec6dSmrg        case AF_INET6:
109375ebec6dSmrg            ti = TRANS_SOCKET_INET6_INDEX;
109475ebec6dSmrg            tn = "inet6";
109575ebec6dSmrg            break;
109675ebec6dSmrg#endif /* IPv6 */
109775ebec6dSmrg        default:
109875ebec6dSmrg            prmsg (1, "receive_listening_fds:"
109975ebec6dSmrg                   "Got unknown socket address family\n");
110075ebec6dSmrg            return -1;
110175ebec6dSmrg        }
110275ebec6dSmrg
110375ebec6dSmrg        ciptr = TRANS(ReopenCOTSServer)(ti, i + SD_LISTEN_FDS_START, port);
110475ebec6dSmrg        if (!ciptr)
110575ebec6dSmrg        {
110675ebec6dSmrg            prmsg (1, "receive_listening_fds:"
110775ebec6dSmrg                   "Got NULL while trying to reopen socket received from systemd.\n");
110875ebec6dSmrg            return -1;
110975ebec6dSmrg        }
111075ebec6dSmrg
111175ebec6dSmrg        prmsg (5, "receive_listening_fds: received listener for %s, %d\n",
111275ebec6dSmrg               tn, ciptr->fd);
111375ebec6dSmrg        temp_ciptrs[(*count_ret)++] = ciptr;
111475ebec6dSmrg        TRANS(Received)(tn);
111575ebec6dSmrg    }
111675ebec6dSmrg#endif /* HAVE_SYSTEMD_DAEMON */
111775ebec6dSmrg    return 0;
111875ebec6dSmrg}
111975ebec6dSmrg
11208d4c0f7bSmrg#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
11218d4c0f7bSmrgextern int xquartz_launchd_fd;
11228d4c0f7bSmrg#endif
112373143b9aSmrg
112473143b9aSmrgint
11256a3641a6SsnjTRANS(MakeAllCOTSServerListeners) (const char *port, int *partial,
11266a3641a6Ssnj                                   int *count_ret, XtransConnInfo **ciptrs_ret)
112773143b9aSmrg
112873143b9aSmrg{
112973143b9aSmrg    char		buffer[256]; /* ??? What size ?? */
113094f982dbSmrg    XtransConnInfo	ciptr, temp_ciptrs[NUMTRANS] = { NULL };
113194f982dbSmrg    int			status, j;
113273143b9aSmrg
113373143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
113473143b9aSmrg    int		ipv6_succ = 0;
113573143b9aSmrg#endif
1136fe567363Smrg    prmsg (2,"MakeAllCOTSServerListeners(%s,%p)\n",
1137fe567363Smrg	   port ? port : "NULL", ciptrs_ret);
113873143b9aSmrg
113973143b9aSmrg    *count_ret = 0;
114073143b9aSmrg
11418d4c0f7bSmrg#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
11428d4c0f7bSmrg    fprintf(stderr, "Launchd socket fd: %d\n", xquartz_launchd_fd);
11438d4c0f7bSmrg    if(xquartz_launchd_fd != -1) {
11448d4c0f7bSmrg        if((ciptr = TRANS(ReopenCOTSServer(TRANS_SOCKET_LOCAL_INDEX,
11458d4c0f7bSmrg                                           xquartz_launchd_fd, getenv("DISPLAY"))))==NULL)
11468d4c0f7bSmrg            fprintf(stderr,"Got NULL while trying to Reopen launchd port\n");
1147fe567363Smrg        else
11488d4c0f7bSmrg            temp_ciptrs[(*count_ret)++] = ciptr;
11498d4c0f7bSmrg    }
115073143b9aSmrg#endif
115173143b9aSmrg
115275ebec6dSmrg    if (receive_listening_fds(port, temp_ciptrs, count_ret) < 0)
115375ebec6dSmrg	return -1;
115475ebec6dSmrg
115594f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
115673143b9aSmrg    {
115773143b9aSmrg	Xtransport *trans = Xtransports[i].transport;
115873143b9aSmrg	unsigned int flags = 0;
115973143b9aSmrg
116075ebec6dSmrg	if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN ||
116175ebec6dSmrg	    trans->flags&TRANS_RECEIVED)
116273143b9aSmrg	    continue;
116373143b9aSmrg
116473143b9aSmrg	snprintf(buffer, sizeof(buffer), "%s/:%s",
116573143b9aSmrg		 trans->TransName, port ? port : "");
116673143b9aSmrg
1167fe567363Smrg	prmsg (5,"MakeAllCOTSServerListeners: opening %s\n",
1168fe567363Smrg	       buffer);
116973143b9aSmrg
117073143b9aSmrg	if ((ciptr = TRANS(OpenCOTSServer(buffer))) == NULL)
117173143b9aSmrg	{
117273143b9aSmrg	    if (trans->flags & TRANS_DISABLED)
117373143b9aSmrg		continue;
117473143b9aSmrg
1175fe567363Smrg	    prmsg (1,
117673143b9aSmrg	  "MakeAllCOTSServerListeners: failed to open listener for %s\n",
1177fe567363Smrg		  trans->TransName);
117873143b9aSmrg	    continue;
117973143b9aSmrg	}
118073143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
118173143b9aSmrg		if ((Xtransports[i].transport_id == TRANS_SOCKET_INET_INDEX
118273143b9aSmrg		     && ipv6_succ))
118373143b9aSmrg		    flags |= ADDR_IN_USE_ALLOWED;
118473143b9aSmrg#endif
118573143b9aSmrg
118673143b9aSmrg	if ((status = TRANS(CreateListener (ciptr, port, flags))) < 0)
118773143b9aSmrg	{
1188e45ace2bSmrg            if (*partial != 0)
1189e45ace2bSmrg		continue;
1190e45ace2bSmrg
119173143b9aSmrg	    if (status == TRANS_ADDR_IN_USE)
119273143b9aSmrg	    {
119373143b9aSmrg		/*
119473143b9aSmrg		 * We failed to bind to the specified address because the
119573143b9aSmrg		 * address is in use.  It must be that a server is already
119673143b9aSmrg		 * running at this address, and this function should fail.
119773143b9aSmrg		 */
119873143b9aSmrg
1199fe567363Smrg		prmsg (1,
1200fe567363Smrg		"MakeAllCOTSServerListeners: server already running\n");
120173143b9aSmrg
120273143b9aSmrg		for (j = 0; j < *count_ret; j++)
120394f982dbSmrg		    if (temp_ciptrs[j] != NULL)
120494f982dbSmrg			TRANS(Close) (temp_ciptrs[j]);
120573143b9aSmrg
120673143b9aSmrg		*count_ret = 0;
120773143b9aSmrg		*ciptrs_ret = NULL;
120873143b9aSmrg		*partial = 0;
120973143b9aSmrg		return -1;
121073143b9aSmrg	    }
121173143b9aSmrg	    else
121273143b9aSmrg	    {
1213fe567363Smrg		prmsg (1,
121473143b9aSmrg	"MakeAllCOTSServerListeners: failed to create listener for %s\n",
1215fe567363Smrg		  trans->TransName);
121673143b9aSmrg
121773143b9aSmrg		continue;
121873143b9aSmrg	    }
121973143b9aSmrg	}
122073143b9aSmrg
122173143b9aSmrg#if defined(IPv6) && defined(AF_INET6)
122273143b9aSmrg	if (Xtransports[i].transport_id == TRANS_SOCKET_INET6_INDEX)
122373143b9aSmrg	    ipv6_succ = 1;
122473143b9aSmrg#endif
1225fe567363Smrg
1226fe567363Smrg	prmsg (5,
122773143b9aSmrg	      "MakeAllCOTSServerListeners: opened listener for %s, %d\n",
1228fe567363Smrg	      trans->TransName, ciptr->fd);
122973143b9aSmrg
123073143b9aSmrg	temp_ciptrs[*count_ret] = ciptr;
123173143b9aSmrg	(*count_ret)++;
123273143b9aSmrg    }
123373143b9aSmrg
123473143b9aSmrg    *partial = (*count_ret < complete_network_count());
123573143b9aSmrg
1236fe567363Smrg    prmsg (5,
123773143b9aSmrg     "MakeAllCOTSServerListeners: partial=%d, actual=%d, complete=%d \n",
123873143b9aSmrg	*partial, *count_ret, complete_network_count());
123973143b9aSmrg
124073143b9aSmrg    if (*count_ret > 0)
124173143b9aSmrg    {
1242fe567363Smrg	if ((*ciptrs_ret = malloc (
124373143b9aSmrg	    *count_ret * sizeof (XtransConnInfo))) == NULL)
124473143b9aSmrg	{
124573143b9aSmrg	    return -1;
124673143b9aSmrg	}
124773143b9aSmrg
124894f982dbSmrg	for (int i = 0; i < *count_ret; i++)
124973143b9aSmrg	{
125073143b9aSmrg	    (*ciptrs_ret)[i] = temp_ciptrs[i];
125173143b9aSmrg	}
125273143b9aSmrg    }
125373143b9aSmrg    else
125473143b9aSmrg	*ciptrs_ret = NULL;
1255fe567363Smrg
125673143b9aSmrg    return 0;
125773143b9aSmrg}
125873143b9aSmrg
125973143b9aSmrg#endif /* TRANS_SERVER */
126073143b9aSmrg
126173143b9aSmrg
126273143b9aSmrg
126373143b9aSmrg/*
126473143b9aSmrg * These routines are not part of the X Transport Interface, but they
126573143b9aSmrg * may be used by it.
126673143b9aSmrg */
126773143b9aSmrg
126873143b9aSmrg
12693d2ed3e3Smrg#ifdef WIN32
127073143b9aSmrg
127173143b9aSmrg/*
127273143b9aSmrg * emulate readv
127373143b9aSmrg */
127473143b9aSmrg
127573143b9aSmrgstatic int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
127673143b9aSmrg
127773143b9aSmrg{
127873143b9aSmrg    int i, len, total;
127973143b9aSmrg    char *base;
128073143b9aSmrg
128173143b9aSmrg    ESET(0);
128273143b9aSmrg    for (i = 0, total = 0;  i < iovcnt;  i++, iov++) {
128373143b9aSmrg	len = iov->iov_len;
128473143b9aSmrg	base = iov->iov_base;
128573143b9aSmrg	while (len > 0) {
128673143b9aSmrg	    register int nbytes;
128773143b9aSmrg	    nbytes = TRANS(Read) (ciptr, base, len);
128873143b9aSmrg	    if (nbytes < 0 && total == 0)  return -1;
128973143b9aSmrg	    if (nbytes <= 0)  return total;
129073143b9aSmrg	    ESET(0);
129173143b9aSmrg	    len   -= nbytes;
129273143b9aSmrg	    total += nbytes;
129373143b9aSmrg	    base  += nbytes;
129473143b9aSmrg	}
129573143b9aSmrg    }
129673143b9aSmrg    return total;
129773143b9aSmrg}
129873143b9aSmrg
129973143b9aSmrg
130073143b9aSmrg/*
130173143b9aSmrg * emulate writev
130273143b9aSmrg */
130373143b9aSmrg
130473143b9aSmrgstatic int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
130573143b9aSmrg
130673143b9aSmrg{
130773143b9aSmrg    int i, len, total;
130873143b9aSmrg    char *base;
130973143b9aSmrg
131073143b9aSmrg    ESET(0);
131173143b9aSmrg    for (i = 0, total = 0;  i < iovcnt;  i++, iov++) {
131273143b9aSmrg	len = iov->iov_len;
131373143b9aSmrg	base = iov->iov_base;
131473143b9aSmrg	while (len > 0) {
131573143b9aSmrg	    register int nbytes;
131673143b9aSmrg	    nbytes = TRANS(Write) (ciptr, base, len);
131773143b9aSmrg	    if (nbytes < 0 && total == 0)  return -1;
131873143b9aSmrg	    if (nbytes <= 0)  return total;
131973143b9aSmrg	    ESET(0);
132073143b9aSmrg	    len   -= nbytes;
132173143b9aSmrg	    total += nbytes;
132273143b9aSmrg	    base  += nbytes;
132373143b9aSmrg	}
132473143b9aSmrg    }
132573143b9aSmrg    return total;
132673143b9aSmrg}
132773143b9aSmrg
13283d2ed3e3Smrg#endif /* WIN32 */
132973143b9aSmrg
133073143b9aSmrg
1331e45ace2bSmrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__SVR4)
133273143b9aSmrg#ifndef NEED_UTSNAME
133373143b9aSmrg#define NEED_UTSNAME
133473143b9aSmrg#endif
133573143b9aSmrg#include <sys/utsname.h>
133673143b9aSmrg#endif
133773143b9aSmrg
133873143b9aSmrg/*
133973143b9aSmrg * TRANS(GetHostname) - similar to gethostname but allows special processing.
134073143b9aSmrg */
134173143b9aSmrg
134273143b9aSmrgint TRANS(GetHostname) (char *buf, int maxlen)
134373143b9aSmrg
134473143b9aSmrg{
134573143b9aSmrg    int len;
134673143b9aSmrg
134773143b9aSmrg#ifdef NEED_UTSNAME
134873143b9aSmrg    struct utsname name;
134973143b9aSmrg
135073143b9aSmrg    uname (&name);
135173143b9aSmrg    len = strlen (name.nodename);
135273143b9aSmrg    if (len >= maxlen) len = maxlen - 1;
135394f982dbSmrg    memcpy (buf, name.nodename, len);
135473143b9aSmrg    buf[len] = '\0';
135573143b9aSmrg#else
135673143b9aSmrg    buf[0] = '\0';
135773143b9aSmrg    (void) gethostname (buf, maxlen);
135873143b9aSmrg    buf [maxlen - 1] = '\0';
135973143b9aSmrg    len = strlen(buf);
136073143b9aSmrg#endif /* NEED_UTSNAME */
136173143b9aSmrg    return len;
136273143b9aSmrg}
1363