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
85ac57ed83Smrg#if defined(IPv6) && !defined(AF_INET6)
86ac57ed83Smrg#error "Cannot build IPv6 support without AF_INET6"
87ac57ed83Smrg#endif
8873143b9aSmrg
8973143b9aSmrgstatic
9073143b9aSmrgXtransport_table Xtransports[] = {
9173143b9aSmrg#if defined(TCPCONN)
9273143b9aSmrg    { &TRANS(SocketTCPFuncs),	TRANS_SOCKET_TCP_INDEX },
93ac57ed83Smrg#if defined(IPv6)
9473143b9aSmrg    { &TRANS(SocketINET6Funcs),	TRANS_SOCKET_INET6_INDEX },
9573143b9aSmrg#endif /* IPv6 */
9673143b9aSmrg    { &TRANS(SocketINETFuncs),	TRANS_SOCKET_INET_INDEX },
9773143b9aSmrg#endif /* TCPCONN */
9873143b9aSmrg#if defined(UNIXCONN)
9973143b9aSmrg#if !defined(LOCALCONN)
10073143b9aSmrg    { &TRANS(SocketLocalFuncs),	TRANS_SOCKET_LOCAL_INDEX },
10173143b9aSmrg#endif /* !LOCALCONN */
10273143b9aSmrg    { &TRANS(SocketUNIXFuncs),	TRANS_SOCKET_UNIX_INDEX },
10373143b9aSmrg#endif /* UNIXCONN */
10473143b9aSmrg#if defined(LOCALCONN)
10573143b9aSmrg    { &TRANS(LocalFuncs),	TRANS_LOCAL_LOCAL_INDEX },
106e8a71cdfSmrg#if defined(SVR4) || defined(__SVR4)
10773143b9aSmrg    { &TRANS(NAMEDFuncs),	TRANS_LOCAL_NAMED_INDEX },
10873143b9aSmrg#endif
1093d2ed3e3Smrg#ifdef __sun
11073143b9aSmrg    { &TRANS(PIPEFuncs),	TRANS_LOCAL_PIPE_INDEX },
1113d2ed3e3Smrg#endif /* __sun */
11273143b9aSmrg#endif /* LOCALCONN */
11373143b9aSmrg};
11473143b9aSmrg
11573143b9aSmrg#define NUMTRANS	(sizeof(Xtransports)/sizeof(Xtransport_table))
11673143b9aSmrg
11773143b9aSmrg
11873143b9aSmrg#ifdef WIN32
11973143b9aSmrg#define ioctl ioctlsocket
12073143b9aSmrg#endif
12173143b9aSmrg
12273143b9aSmrg
12373143b9aSmrg
12473143b9aSmrg/*
12573143b9aSmrg * These are a few utility function used by the public interface functions.
12673143b9aSmrg */
12773143b9aSmrg
12873143b9aSmrgvoid
12973143b9aSmrgTRANS(FreeConnInfo) (XtransConnInfo ciptr)
13073143b9aSmrg
13173143b9aSmrg{
132ac57ed83Smrg    prmsg (3,"FreeConnInfo(%p)\n", (void *) ciptr);
13373143b9aSmrg
13473143b9aSmrg    if (ciptr->addr)
135fe567363Smrg	free (ciptr->addr);
13673143b9aSmrg
13773143b9aSmrg    if (ciptr->peeraddr)
138fe567363Smrg	free (ciptr->peeraddr);
13973143b9aSmrg
14073143b9aSmrg    if (ciptr->port)
141fe567363Smrg	free (ciptr->port);
14273143b9aSmrg
143fe567363Smrg    free (ciptr);
14473143b9aSmrg}
14573143b9aSmrg
14673143b9aSmrg
14773143b9aSmrg#define PROTOBUFSIZE	20
14873143b9aSmrg
14973143b9aSmrgstatic Xtransport *
150fe567363SmrgTRANS(SelectTransport) (const char *protocol)
15173143b9aSmrg
15273143b9aSmrg{
1533d2ed3e3Smrg#ifndef HAVE_STRCASECMP
15473143b9aSmrg    char 	protobuf[PROTOBUFSIZE];
1553d2ed3e3Smrg#endif
15673143b9aSmrg
157fe567363Smrg    prmsg (3,"SelectTransport(%s)\n", protocol);
15873143b9aSmrg
1593d2ed3e3Smrg#ifndef HAVE_STRCASECMP
16073143b9aSmrg    /*
16173143b9aSmrg     * Force Protocol to be lowercase as a way of doing
16273143b9aSmrg     * a case insensitive match.
16373143b9aSmrg     */
16473143b9aSmrg
16573143b9aSmrg    strncpy (protobuf, protocol, PROTOBUFSIZE - 1);
16673143b9aSmrg    protobuf[PROTOBUFSIZE-1] = '\0';
16773143b9aSmrg
16894f982dbSmrg    for (unsigned int i = 0; i < PROTOBUFSIZE && protobuf[i] != '\0'; i++)
1698a0d9095Smrg	if (isupper ((unsigned char)protobuf[i]))
1708a0d9095Smrg	    protobuf[i] = tolower ((unsigned char)protobuf[i]);
1713d2ed3e3Smrg#endif
17273143b9aSmrg
17373143b9aSmrg    /* Look at all of the configured protocols */
17473143b9aSmrg
17594f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
17673143b9aSmrg    {
1773d2ed3e3Smrg#ifndef HAVE_STRCASECMP
17873143b9aSmrg	if (!strcmp (protobuf, Xtransports[i].transport->TransName))
1793d2ed3e3Smrg#else
1803d2ed3e3Smrg	if (!strcasecmp (protocol, Xtransports[i].transport->TransName))
1813d2ed3e3Smrg#endif
18273143b9aSmrg	    return Xtransports[i].transport;
18373143b9aSmrg    }
18473143b9aSmrg
18573143b9aSmrg    return NULL;
18673143b9aSmrg}
18773143b9aSmrg
188e45ace2bSmrgstatic int
1896a3641a6SsnjTRANS(ParseAddress) (const char *address,
1906a3641a6Ssnj                     char **protocol, char **host, char **port)
19173143b9aSmrg
19273143b9aSmrg{
19373143b9aSmrg    /*
19473143b9aSmrg     * For the font library, the address is a string formatted
19573143b9aSmrg     * as "protocol/host:port[/catalogue]".  Note that the catologue
19673143b9aSmrg     * is optional.  At this time, the catologue info is ignored, but
19773143b9aSmrg     * we have to parse it anyways.
19873143b9aSmrg     *
19973143b9aSmrg     * Other than fontlib, the address is a string formatted
20073143b9aSmrg     * as "protocol/host:port".
20173143b9aSmrg     *
20273143b9aSmrg     * If the protocol part is missing, then assume TCP.
20373143b9aSmrg     * If the protocol part and host part are missing, then assume local.
20473143b9aSmrg     * If a "::" is found then assume DNET.
20573143b9aSmrg     */
20673143b9aSmrg
207e45ace2bSmrg    char	*mybuf, *tmpptr = NULL;
208e45ace2bSmrg    const char	*_protocol = NULL;
20994f982dbSmrg    const char	*_host, *_port;
21073143b9aSmrg    char	hostnamebuf[256];
21194f982dbSmrg    char	*_host_buf;
21273143b9aSmrg    int		_host_len;
21373143b9aSmrg
214fe567363Smrg    prmsg (3,"ParseAddress(%s)\n", address);
21573143b9aSmrg
216e45ace2bSmrg    /* First, check for AF_UNIX socket paths */
217e45ace2bSmrg    if (address[0] == '/') {
218e45ace2bSmrg        _protocol = "local";
219e45ace2bSmrg        _host = "";
220e45ace2bSmrg        _port = address;
221e45ace2bSmrg    } else
222e45ace2bSmrg#ifdef HAVE_LAUNCHD
223e45ace2bSmrg    /* launchd sockets will look like 'local//tmp/launch-XgkNns/:0' */
224e45ace2bSmrg    if(!strncmp(address,"local//",7)) {
225e45ace2bSmrg        _protocol="local";
226e45ace2bSmrg        _host="";
227e45ace2bSmrg        _port=address+6;
228e45ace2bSmrg    } else
229e45ace2bSmrg#endif
230e45ace2bSmrg    if (!strncmp(address, "unix:", 5)) {
231e45ace2bSmrg        _protocol = "local";
232e45ace2bSmrg        _host = "";
233e45ace2bSmrg        _port = address + 5;
234e45ace2bSmrg    }
235e45ace2bSmrg    if (_protocol)
236e45ace2bSmrg        goto done_parsing;
237e45ace2bSmrg
23873143b9aSmrg    /* Copy the string so it can be changed */
23973143b9aSmrg
240fe567363Smrg    tmpptr = mybuf = strdup (address);
24173143b9aSmrg
24273143b9aSmrg    /* Parse the string to get each component */
243fe567363Smrg
24473143b9aSmrg    /* Get the protocol part */
24573143b9aSmrg
24673143b9aSmrg    _protocol = mybuf;
24773143b9aSmrg
24873143b9aSmrg
24994f982dbSmrg    if ((mybuf == NULL) ||
25094f982dbSmrg        ( ((mybuf = strchr (mybuf, '/')) == NULL) &&
25194f982dbSmrg          ((mybuf = strrchr (tmpptr, ':')) == NULL) ) )
25294f982dbSmrg    {
25373143b9aSmrg	/* address is in a bad format */
25473143b9aSmrg	*protocol = NULL;
25573143b9aSmrg	*host = NULL;
25673143b9aSmrg	*port = NULL;
257fe567363Smrg	free (tmpptr);
25873143b9aSmrg	return 0;
25973143b9aSmrg    }
26073143b9aSmrg
26173143b9aSmrg    if (*mybuf == ':')
26273143b9aSmrg    {
26373143b9aSmrg	/*
26473143b9aSmrg	 * If there is a hostname, then assume tcp, otherwise
26573143b9aSmrg	 * it must be local.
26673143b9aSmrg	 */
26773143b9aSmrg	if (mybuf == tmpptr)
26873143b9aSmrg	{
26973143b9aSmrg	    /* There is neither a protocol or host specified */
27073143b9aSmrg	    _protocol = "local";
27173143b9aSmrg	}
27273143b9aSmrg	else
27373143b9aSmrg	{
27473143b9aSmrg	    /* There is a hostname specified */
27573143b9aSmrg	    _protocol = "tcp";
276e45ace2bSmrg	    mybuf = tmpptr;	/* reset to the beginning of the host ptr */
27773143b9aSmrg	}
27873143b9aSmrg    }
27973143b9aSmrg    else
28073143b9aSmrg    {
28173143b9aSmrg	/* *mybuf == '/' */
28273143b9aSmrg
28373143b9aSmrg	*mybuf ++= '\0'; /* put a null at the end of the protocol */
28473143b9aSmrg
28573143b9aSmrg	if (strlen(_protocol) == 0)
28673143b9aSmrg	{
28773143b9aSmrg	    /*
28873143b9aSmrg	     * If there is a hostname, then assume tcp, otherwise
28973143b9aSmrg	     * it must be local.
29073143b9aSmrg	     */
29173143b9aSmrg	    if (*mybuf != ':')
29273143b9aSmrg		_protocol = "tcp";
29373143b9aSmrg	    else
29473143b9aSmrg		_protocol = "local";
29573143b9aSmrg	}
29673143b9aSmrg    }
29773143b9aSmrg
29873143b9aSmrg    /* Get the host part */
29973143b9aSmrg
30094f982dbSmrg    _host = _host_buf = mybuf;
30173143b9aSmrg
30273143b9aSmrg    if ((mybuf = strrchr (mybuf,':')) == NULL)
30373143b9aSmrg    {
30473143b9aSmrg	*protocol = NULL;
30573143b9aSmrg	*host = NULL;
30673143b9aSmrg	*port = NULL;
307fe567363Smrg	free (tmpptr);
30873143b9aSmrg	return 0;
30973143b9aSmrg    }
31073143b9aSmrg
31173143b9aSmrg    *mybuf ++= '\0';
31273143b9aSmrg
31373143b9aSmrg    _host_len = strlen(_host);
31473143b9aSmrg    if (_host_len == 0)
31573143b9aSmrg    {
31673143b9aSmrg	TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
31773143b9aSmrg	_host = hostnamebuf;
31873143b9aSmrg    }
319ac57ed83Smrg#ifdef IPv6
32073143b9aSmrg    /* hostname in IPv6 [numeric_addr]:0 form? */
321fe567363Smrg    else if ( (_host_len > 3) &&
32273143b9aSmrg      ((strcmp(_protocol, "tcp") == 0) || (strcmp(_protocol, "inet6") == 0))
32394f982dbSmrg      && (_host_buf[0] == '[') && (_host_buf[_host_len - 1] == ']') ) {
32473143b9aSmrg	struct sockaddr_in6 sin6;
32573143b9aSmrg
32694f982dbSmrg	_host_buf[_host_len - 1] = '\0';
32773143b9aSmrg
32873143b9aSmrg	/* Verify address is valid IPv6 numeric form */
32973143b9aSmrg	if (inet_pton(AF_INET6, _host + 1, &sin6) == 1) {
33073143b9aSmrg	    /* It is. Use it as such. */
33173143b9aSmrg	    _host++;
33273143b9aSmrg	    _protocol = "inet6";
33373143b9aSmrg	} else {
33473143b9aSmrg	    /* It's not, restore it just in case some other code can use it. */
33594f982dbSmrg	    _host_buf[_host_len - 1] = ']';
33673143b9aSmrg	}
33773143b9aSmrg    }
33873143b9aSmrg#endif
33973143b9aSmrg
34073143b9aSmrg
34173143b9aSmrg    /* Get the port */
34273143b9aSmrg
34373143b9aSmrg    _port = mybuf;
34473143b9aSmrg
34573143b9aSmrg#if defined(FONT_t) || defined(FS_t)
34673143b9aSmrg    /*
34773143b9aSmrg     * Is there an optional catalogue list?
34873143b9aSmrg     */
34973143b9aSmrg
35073143b9aSmrg    if ((mybuf = strchr (mybuf,'/')) != NULL)
35173143b9aSmrg	*mybuf ++= '\0';
35273143b9aSmrg
35373143b9aSmrg    /*
35473143b9aSmrg     * The rest, if any, is the (currently unused) catalogue list.
35573143b9aSmrg     *
35673143b9aSmrg     * _catalogue = mybuf;
35773143b9aSmrg     */
35873143b9aSmrg#endif
35973143b9aSmrg
360e45ace2bSmrgdone_parsing:
36173143b9aSmrg    /*
36273143b9aSmrg     * Now that we have all of the components, allocate new
36373143b9aSmrg     * string space for them.
36473143b9aSmrg     */
36573143b9aSmrg
366fe567363Smrg    if ((*protocol = strdup (_protocol)) == NULL)
36773143b9aSmrg    {
36873143b9aSmrg	/* Malloc failed */
36973143b9aSmrg	*port = NULL;
37073143b9aSmrg	*host = NULL;
37173143b9aSmrg	*protocol = NULL;
372fe567363Smrg	free (tmpptr);
37373143b9aSmrg	return 0;
37473143b9aSmrg    }
37573143b9aSmrg
376fe567363Smrg    if ((*host = strdup (_host)) == NULL)
37773143b9aSmrg    {
37873143b9aSmrg	/* Malloc failed */
37973143b9aSmrg	*port = NULL;
38073143b9aSmrg	*host = NULL;
381fe567363Smrg	free (*protocol);
38273143b9aSmrg	*protocol = NULL;
383fe567363Smrg	free (tmpptr);
38473143b9aSmrg	return 0;
385fe567363Smrg    }
38673143b9aSmrg
387fe567363Smrg    if ((*port = strdup (_port)) == NULL)
38873143b9aSmrg    {
38973143b9aSmrg	/* Malloc failed */
39073143b9aSmrg	*port = NULL;
391fe567363Smrg	free (*host);
39273143b9aSmrg	*host = NULL;
393fe567363Smrg	free (*protocol);
39473143b9aSmrg	*protocol = NULL;
395fe567363Smrg	free (tmpptr);
39673143b9aSmrg	return 0;
39773143b9aSmrg    }
39873143b9aSmrg
399fe567363Smrg    free (tmpptr);
40073143b9aSmrg
40173143b9aSmrg    return 1;
40273143b9aSmrg}
40373143b9aSmrg
40473143b9aSmrg
40573143b9aSmrg/*
40673143b9aSmrg * TRANS(Open) does all of the real work opening a connection. The only
40773143b9aSmrg * funny part about this is the type parameter which is used to decide which
40873143b9aSmrg * type of open to perform.
40973143b9aSmrg */
41073143b9aSmrg
41173143b9aSmrgstatic XtransConnInfo
4126a3641a6SsnjTRANS(Open) (int type, const char *address)
41373143b9aSmrg
41473143b9aSmrg{
41573143b9aSmrg    char 		*protocol = NULL, *host = NULL, *port = NULL;
41673143b9aSmrg    XtransConnInfo	ciptr = NULL;
41773143b9aSmrg    Xtransport		*thistrans;
41873143b9aSmrg
419fe567363Smrg    prmsg (2,"Open(%d,%s)\n", type, address);
42073143b9aSmrg
421fe567363Smrg#if defined(WIN32) && defined(TCPCONN)
42273143b9aSmrg    if (TRANS(WSAStartup)())
42373143b9aSmrg    {
424fe567363Smrg	prmsg (1,"Open: WSAStartup failed\n");
42573143b9aSmrg	return NULL;
42673143b9aSmrg    }
42773143b9aSmrg#endif
42873143b9aSmrg
42973143b9aSmrg    /* Parse the Address */
43073143b9aSmrg
43173143b9aSmrg    if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
43273143b9aSmrg    {
433fe567363Smrg	prmsg (1,"Open: Unable to Parse address %s\n", address);
43473143b9aSmrg	return NULL;
43573143b9aSmrg    }
43673143b9aSmrg
43773143b9aSmrg    /* Determine the transport type */
43873143b9aSmrg
43973143b9aSmrg    if ((thistrans = TRANS(SelectTransport) (protocol)) == NULL)
44073143b9aSmrg    {
441fe567363Smrg	prmsg (1,"Open: Unable to find transport for %s\n",
442fe567363Smrg	       protocol);
44373143b9aSmrg
444fe567363Smrg	free (protocol);
445fe567363Smrg	free (host);
446fe567363Smrg	free (port);
44773143b9aSmrg	return NULL;
44873143b9aSmrg    }
44973143b9aSmrg
45073143b9aSmrg    /* Open the transport */
45173143b9aSmrg
45273143b9aSmrg    switch (type)
45373143b9aSmrg    {
45473143b9aSmrg    case XTRANS_OPEN_COTS_CLIENT:
45573143b9aSmrg#ifdef TRANS_CLIENT
45673143b9aSmrg	ciptr = thistrans->OpenCOTSClient(thistrans, protocol, host, port);
45773143b9aSmrg#endif /* TRANS_CLIENT */
45873143b9aSmrg	break;
45973143b9aSmrg    case XTRANS_OPEN_COTS_SERVER:
46073143b9aSmrg#ifdef TRANS_SERVER
46173143b9aSmrg	ciptr = thistrans->OpenCOTSServer(thistrans, protocol, host, port);
46273143b9aSmrg#endif /* TRANS_SERVER */
46373143b9aSmrg	break;
46473143b9aSmrg    default:
465fe567363Smrg	prmsg (1,"Open: Unknown Open type %d\n", type);
46673143b9aSmrg    }
46773143b9aSmrg
46873143b9aSmrg    if (ciptr == NULL)
46973143b9aSmrg    {
470fe567363Smrg	if (!(thistrans->flags & TRANS_DISABLED))
47173143b9aSmrg	{
472fe567363Smrg	    prmsg (1,"Open: transport open failed for %s/%s:%s\n",
47373143b9aSmrg	           protocol, host, port);
47473143b9aSmrg	}
475fe567363Smrg	free (protocol);
476fe567363Smrg	free (host);
477fe567363Smrg	free (port);
47873143b9aSmrg	return NULL;
47973143b9aSmrg    }
48073143b9aSmrg
48173143b9aSmrg    ciptr->transptr = thistrans;
48273143b9aSmrg    ciptr->port = port;			/* We need this for TRANS(Reopen) */
48373143b9aSmrg
484fe567363Smrg    free (protocol);
485fe567363Smrg    free (host);
48673143b9aSmrg
48773143b9aSmrg    return ciptr;
48873143b9aSmrg}
48973143b9aSmrg
49073143b9aSmrg
49173143b9aSmrg#ifdef TRANS_REOPEN
49273143b9aSmrg
49373143b9aSmrg/*
49473143b9aSmrg * We might want to create an XtransConnInfo object based on a previously
49573143b9aSmrg * opened connection.  For example, the font server may clone itself and
49673143b9aSmrg * pass file descriptors to the parent.
49773143b9aSmrg */
49873143b9aSmrg
49973143b9aSmrgstatic XtransConnInfo
5006a3641a6SsnjTRANS(Reopen) (int type, int trans_id, int fd, const char *port)
50173143b9aSmrg
50273143b9aSmrg{
50373143b9aSmrg    XtransConnInfo	ciptr = NULL;
50473143b9aSmrg    Xtransport		*thistrans = NULL;
50573143b9aSmrg    char		*save_port;
50673143b9aSmrg
507fe567363Smrg    prmsg (2,"Reopen(%d,%d,%s)\n", trans_id, fd, port);
50873143b9aSmrg
50973143b9aSmrg    /* Determine the transport type */
51073143b9aSmrg
51194f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
51294f982dbSmrg    {
51373143b9aSmrg	if (Xtransports[i].transport_id == trans_id)
51473143b9aSmrg	{
51573143b9aSmrg	    thistrans = Xtransports[i].transport;
51673143b9aSmrg	    break;
51773143b9aSmrg	}
51894f982dbSmrg    }
51973143b9aSmrg
52073143b9aSmrg    if (thistrans == NULL)
52173143b9aSmrg    {
522fe567363Smrg	prmsg (1,"Reopen: Unable to find transport id %d\n",
523fe567363Smrg	       trans_id);
52473143b9aSmrg
52573143b9aSmrg	return NULL;
52673143b9aSmrg    }
52773143b9aSmrg
528fe567363Smrg    if ((save_port = strdup (port)) == NULL)
52973143b9aSmrg    {
530fe567363Smrg	prmsg (1,"Reopen: Unable to malloc port string\n");
53173143b9aSmrg
53273143b9aSmrg	return NULL;
53373143b9aSmrg    }
53473143b9aSmrg
53573143b9aSmrg    /* Get a new XtransConnInfo object */
53673143b9aSmrg
53773143b9aSmrg    switch (type)
53873143b9aSmrg    {
53973143b9aSmrg    case XTRANS_OPEN_COTS_SERVER:
54073143b9aSmrg	ciptr = thistrans->ReopenCOTSServer(thistrans, fd, port);
54173143b9aSmrg	break;
54273143b9aSmrg    default:
543fe567363Smrg	prmsg (1,"Reopen: Bad Open type %d\n", type);
54473143b9aSmrg    }
54573143b9aSmrg
54673143b9aSmrg    if (ciptr == NULL)
54773143b9aSmrg    {
548fe567363Smrg	prmsg (1,"Reopen: transport open failed\n");
549fe567363Smrg	free (save_port);
55073143b9aSmrg	return NULL;
55173143b9aSmrg    }
55273143b9aSmrg
55373143b9aSmrg    ciptr->transptr = thistrans;
55473143b9aSmrg    ciptr->port = save_port;
55573143b9aSmrg
55673143b9aSmrg    return ciptr;
55773143b9aSmrg}
55873143b9aSmrg
55973143b9aSmrg#endif /* TRANS_REOPEN */
56073143b9aSmrg
56173143b9aSmrg
56273143b9aSmrg
56373143b9aSmrg/*
56473143b9aSmrg * These are the public interfaces to this Transport interface.
56573143b9aSmrg * These are the only functions that should have knowledge of the transport
56673143b9aSmrg * table.
56773143b9aSmrg */
56873143b9aSmrg
56973143b9aSmrg#ifdef TRANS_CLIENT
57073143b9aSmrg
57173143b9aSmrgXtransConnInfo
5726a3641a6SsnjTRANS(OpenCOTSClient) (const char *address)
57373143b9aSmrg
57473143b9aSmrg{
575fe567363Smrg    prmsg (2,"OpenCOTSClient(%s)\n", address);
57673143b9aSmrg    return TRANS(Open) (XTRANS_OPEN_COTS_CLIENT, address);
57773143b9aSmrg}
57873143b9aSmrg
57973143b9aSmrg#endif /* TRANS_CLIENT */
58073143b9aSmrg
58173143b9aSmrg
58273143b9aSmrg#ifdef TRANS_SERVER
58373143b9aSmrg
58473143b9aSmrgXtransConnInfo
5856a3641a6SsnjTRANS(OpenCOTSServer) (const char *address)
58673143b9aSmrg
58773143b9aSmrg{
588fe567363Smrg    prmsg (2,"OpenCOTSServer(%s)\n", address);
58973143b9aSmrg    return TRANS(Open) (XTRANS_OPEN_COTS_SERVER, address);
59073143b9aSmrg}
59173143b9aSmrg
59273143b9aSmrg#endif /* TRANS_SERVER */
59373143b9aSmrg
59473143b9aSmrg
59573143b9aSmrg#ifdef TRANS_REOPEN
59673143b9aSmrg
59773143b9aSmrgXtransConnInfo
5986a3641a6SsnjTRANS(ReopenCOTSServer) (int trans_id, int fd, const char *port)
59973143b9aSmrg
60073143b9aSmrg{
601fe567363Smrg    prmsg (2,"ReopenCOTSServer(%d, %d, %s)\n", trans_id, fd, port);
60273143b9aSmrg    return TRANS(Reopen) (XTRANS_OPEN_COTS_SERVER, trans_id, fd, port);
60373143b9aSmrg}
60473143b9aSmrg
60573143b9aSmrgint
606fe567363SmrgTRANS(GetReopenInfo) (XtransConnInfo ciptr,
60773143b9aSmrg		      int *trans_id, int *fd, char **port)
60873143b9aSmrg
60973143b9aSmrg{
61094f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
61194f982dbSmrg    {
61273143b9aSmrg	if (Xtransports[i].transport == ciptr->transptr)
61373143b9aSmrg	{
61473143b9aSmrg	    *trans_id = Xtransports[i].transport_id;
61573143b9aSmrg	    *fd = ciptr->fd;
61673143b9aSmrg
617fe567363Smrg	    if ((*port = strdup (ciptr->port)) == NULL)
61873143b9aSmrg		return 0;
61973143b9aSmrg	    else
62073143b9aSmrg		return 1;
62173143b9aSmrg	}
62294f982dbSmrg    }
62373143b9aSmrg
62473143b9aSmrg    return 0;
62573143b9aSmrg}
62673143b9aSmrg
62773143b9aSmrg#endif /* TRANS_REOPEN */
62873143b9aSmrg
62973143b9aSmrg
63073143b9aSmrgint
63173143b9aSmrgTRANS(SetOption) (XtransConnInfo ciptr, int option, int arg)
63273143b9aSmrg
63373143b9aSmrg{
63473143b9aSmrg    int	fd = ciptr->fd;
63573143b9aSmrg    int	ret = 0;
63673143b9aSmrg
637fe567363Smrg    prmsg (2,"SetOption(%d,%d,%d)\n", fd, option, arg);
63873143b9aSmrg
63973143b9aSmrg    /*
64073143b9aSmrg     * For now, all transport type use the same stuff for setting options.
64173143b9aSmrg     * As long as this is true, we can put the common code here. Once a more
64273143b9aSmrg     * complicated transport such as shared memory or an OSI implementation
64373143b9aSmrg     * that uses the session and application libraries is implemented, this
64473143b9aSmrg     * code may have to move to a transport dependent function.
64573143b9aSmrg     *
64673143b9aSmrg     * ret = ciptr->transptr->SetOption (ciptr, option, arg);
64773143b9aSmrg     */
64873143b9aSmrg
64973143b9aSmrg    switch (option)
65073143b9aSmrg    {
65173143b9aSmrg    case TRANS_NONBLOCKING:
65273143b9aSmrg	switch (arg)
65373143b9aSmrg	{
65473143b9aSmrg	case 0:
65573143b9aSmrg	    /* Set to blocking mode */
65673143b9aSmrg	    break;
65773143b9aSmrg	case 1: /* Set to non-blocking mode */
65873143b9aSmrg
659e45ace2bSmrg#if defined(O_NONBLOCK)
66073143b9aSmrg	    ret = fcntl (fd, F_GETFL, 0);
66173143b9aSmrg	    if (ret != -1)
66273143b9aSmrg		ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK);
66373143b9aSmrg#else
66473143b9aSmrg#ifdef FIOSNBIO
66573143b9aSmrg	{
66673143b9aSmrg	    int arg;
66773143b9aSmrg	    arg = 1;
66873143b9aSmrg	    ret = ioctl (fd, FIOSNBIO, &arg);
66973143b9aSmrg	}
67073143b9aSmrg#else
671fe567363Smrg#if defined(WIN32)
67273143b9aSmrg	{
67373143b9aSmrg#ifdef WIN32
67473143b9aSmrg	    u_long arg;
67573143b9aSmrg#else
67673143b9aSmrg	    int arg;
67773143b9aSmrg#endif
67873143b9aSmrg	    arg = 1;
67973143b9aSmrg/* IBM TCP/IP understands this option too well: it causes TRANS(Read) to fail
68073143b9aSmrg * eventually with EWOULDBLOCK */
68173143b9aSmrg	    ret = ioctl (fd, FIONBIO, &arg);
68273143b9aSmrg	}
68373143b9aSmrg#else
68473143b9aSmrg	    ret = fcntl (fd, F_GETFL, 0);
68573143b9aSmrg#ifdef FNDELAY
68673143b9aSmrg	    ret = fcntl (fd, F_SETFL, ret | FNDELAY);
68773143b9aSmrg#else
68873143b9aSmrg	    ret = fcntl (fd, F_SETFL, ret | O_NDELAY);
68973143b9aSmrg#endif
69073143b9aSmrg#endif /* AIXV3  || uniosu */
69173143b9aSmrg#endif /* FIOSNBIO */
69273143b9aSmrg#endif /* O_NONBLOCK */
69373143b9aSmrg	    break;
69473143b9aSmrg	default:
69573143b9aSmrg	    /* Unknown option */
69673143b9aSmrg	    break;
69773143b9aSmrg	}
69873143b9aSmrg	break;
69973143b9aSmrg    case TRANS_CLOSEONEXEC:
70073143b9aSmrg#ifdef F_SETFD
70173143b9aSmrg#ifdef FD_CLOEXEC
70273143b9aSmrg	ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
70373143b9aSmrg#else
70473143b9aSmrg	ret = fcntl (fd, F_SETFD, 1);
70573143b9aSmrg#endif /* FD_CLOEXEC */
70673143b9aSmrg#endif /* F_SETFD */
70773143b9aSmrg	break;
70873143b9aSmrg    }
709fe567363Smrg
71073143b9aSmrg    return ret;
71173143b9aSmrg}
71273143b9aSmrg
71373143b9aSmrg#ifdef TRANS_SERVER
71473143b9aSmrg
71573143b9aSmrgint
7166a3641a6SsnjTRANS(CreateListener) (XtransConnInfo ciptr, const char *port, unsigned int flags)
71773143b9aSmrg
71873143b9aSmrg{
71973143b9aSmrg    return ciptr->transptr->CreateListener (ciptr, port, flags);
72073143b9aSmrg}
72173143b9aSmrg
72275ebec6dSmrgint
72375ebec6dSmrgTRANS(Received) (const char * protocol)
72475ebec6dSmrg
72575ebec6dSmrg{
72675ebec6dSmrg   Xtransport *trans;
72775ebec6dSmrg   int i = 0, ret = 0;
72875ebec6dSmrg
72975ebec6dSmrg   prmsg (5, "Received(%s)\n", protocol);
73075ebec6dSmrg
73175ebec6dSmrg   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
73275ebec6dSmrg   {
73375ebec6dSmrg	prmsg (1,"Received: unable to find transport: %s\n",
73475ebec6dSmrg	       protocol);
73575ebec6dSmrg
73675ebec6dSmrg	return -1;
73775ebec6dSmrg   }
73875ebec6dSmrg   if (trans->flags & TRANS_ALIAS) {
73975ebec6dSmrg       if (trans->nolisten)
74075ebec6dSmrg	   while (trans->nolisten[i]) {
74175ebec6dSmrg	       ret |= TRANS(Received)(trans->nolisten[i]);
74275ebec6dSmrg	       i++;
74375ebec6dSmrg       }
74475ebec6dSmrg   }
74575ebec6dSmrg
74675ebec6dSmrg   trans->flags |= TRANS_RECEIVED;
74775ebec6dSmrg   return ret;
74875ebec6dSmrg}
74975ebec6dSmrg
75073143b9aSmrgint
751fe567363SmrgTRANS(NoListen) (const char * protocol)
752fe567363Smrg
75373143b9aSmrg{
75473143b9aSmrg   Xtransport *trans;
75573143b9aSmrg   int i = 0, ret = 0;
756fe567363Smrg
757fe567363Smrg   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
75873143b9aSmrg   {
759fe567363Smrg	prmsg (1,"TransNoListen: unable to find transport: %s\n",
760fe567363Smrg	       protocol);
76173143b9aSmrg
76273143b9aSmrg	return -1;
76373143b9aSmrg   }
76473143b9aSmrg   if (trans->flags & TRANS_ALIAS) {
76573143b9aSmrg       if (trans->nolisten)
76673143b9aSmrg	   while (trans->nolisten[i]) {
76773143b9aSmrg	       ret |= TRANS(NoListen)(trans->nolisten[i]);
76873143b9aSmrg	       i++;
76973143b9aSmrg       }
77073143b9aSmrg   }
77173143b9aSmrg
77273143b9aSmrg   trans->flags |= TRANS_NOLISTEN;
77373143b9aSmrg   return ret;
77473143b9aSmrg}
77573143b9aSmrg
7766a3641a6Ssnjint
7776a3641a6SsnjTRANS(Listen) (const char * protocol)
7786a3641a6Ssnj{
7796a3641a6Ssnj   Xtransport *trans;
7806a3641a6Ssnj   int i = 0, ret = 0;
7816a3641a6Ssnj
7826a3641a6Ssnj   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
7836a3641a6Ssnj   {
7846a3641a6Ssnj	prmsg (1,"TransListen: unable to find transport: %s\n",
7856a3641a6Ssnj	       protocol);
7866a3641a6Ssnj
7876a3641a6Ssnj	return -1;
7886a3641a6Ssnj   }
7896a3641a6Ssnj   if (trans->flags & TRANS_ALIAS) {
7906a3641a6Ssnj       if (trans->nolisten)
7916a3641a6Ssnj	   while (trans->nolisten[i]) {
7926a3641a6Ssnj	       ret |= TRANS(Listen)(trans->nolisten[i]);
7936a3641a6Ssnj	       i++;
7946a3641a6Ssnj       }
7956a3641a6Ssnj   }
7966a3641a6Ssnj
7976a3641a6Ssnj   trans->flags &= ~TRANS_NOLISTEN;
7986a3641a6Ssnj   return ret;
7996a3641a6Ssnj}
8006a3641a6Ssnj
80175ebec6dSmrgint
80275ebec6dSmrgTRANS(IsListening) (const char * protocol)
80375ebec6dSmrg{
80475ebec6dSmrg   Xtransport *trans;
80575ebec6dSmrg
80675ebec6dSmrg   if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
80775ebec6dSmrg   {
80875ebec6dSmrg	prmsg (1,"TransIsListening: unable to find transport: %s\n",
80975ebec6dSmrg	       protocol);
81075ebec6dSmrg
81175ebec6dSmrg	return 0;
81275ebec6dSmrg   }
81375ebec6dSmrg
81475ebec6dSmrg   return !(trans->flags & TRANS_NOLISTEN);
81575ebec6dSmrg}
81675ebec6dSmrg
81773143b9aSmrgint
81873143b9aSmrgTRANS(ResetListener) (XtransConnInfo ciptr)
81973143b9aSmrg
82073143b9aSmrg{
82173143b9aSmrg    if (ciptr->transptr->ResetListener)
82273143b9aSmrg	return ciptr->transptr->ResetListener (ciptr);
82373143b9aSmrg    else
82473143b9aSmrg	return TRANS_RESET_NOOP;
82573143b9aSmrg}
82673143b9aSmrg
82773143b9aSmrg
82873143b9aSmrgXtransConnInfo
82973143b9aSmrgTRANS(Accept) (XtransConnInfo ciptr, int *status)
83073143b9aSmrg
83173143b9aSmrg{
83273143b9aSmrg    XtransConnInfo	newciptr;
83373143b9aSmrg
834fe567363Smrg    prmsg (2,"Accept(%d)\n", ciptr->fd);
83573143b9aSmrg
83673143b9aSmrg    newciptr = ciptr->transptr->Accept (ciptr, status);
83773143b9aSmrg
83873143b9aSmrg    if (newciptr)
83973143b9aSmrg	newciptr->transptr = ciptr->transptr;
84073143b9aSmrg
84173143b9aSmrg    return newciptr;
84273143b9aSmrg}
84373143b9aSmrg
84473143b9aSmrg#endif /* TRANS_SERVER */
84573143b9aSmrg
84673143b9aSmrg
84773143b9aSmrg#ifdef TRANS_CLIENT
84873143b9aSmrg
84973143b9aSmrgint
8506a3641a6SsnjTRANS(Connect) (XtransConnInfo ciptr, const char *address)
85173143b9aSmrg
85273143b9aSmrg{
85373143b9aSmrg    char	*protocol;
85473143b9aSmrg    char	*host;
85573143b9aSmrg    char	*port;
85673143b9aSmrg    int		ret;
85773143b9aSmrg
858fe567363Smrg    prmsg (2,"Connect(%d,%s)\n", ciptr->fd, address);
85973143b9aSmrg
86073143b9aSmrg    if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
86173143b9aSmrg    {
862fe567363Smrg	prmsg (1,"Connect: Unable to Parse address %s\n",
863fe567363Smrg	       address);
86473143b9aSmrg	return -1;
86573143b9aSmrg    }
86673143b9aSmrg
86773143b9aSmrg#ifdef HAVE_LAUNCHD
8688d4c0f7bSmrg    if (!host) host=strdup("");
86973143b9aSmrg#endif
87073143b9aSmrg
87173143b9aSmrg    if (!port || !*port)
87273143b9aSmrg    {
873fe567363Smrg	prmsg (1,"Connect: Missing port specification in %s\n",
874fe567363Smrg	      address);
875fe567363Smrg	if (protocol) free (protocol);
876fe567363Smrg	if (host) free (host);
87773143b9aSmrg	return -1;
87873143b9aSmrg    }
87973143b9aSmrg
88073143b9aSmrg    ret = ciptr->transptr->Connect (ciptr, host, port);
88173143b9aSmrg
882fe567363Smrg    if (protocol) free (protocol);
883fe567363Smrg    if (host) free (host);
884fe567363Smrg    if (port) free (port);
885fe567363Smrg
88673143b9aSmrg    return ret;
88773143b9aSmrg}
88873143b9aSmrg
88973143b9aSmrg#endif /* TRANS_CLIENT */
89073143b9aSmrg
89173143b9aSmrg
89273143b9aSmrgint
89373143b9aSmrgTRANS(BytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
89473143b9aSmrg
89573143b9aSmrg{
89673143b9aSmrg    return ciptr->transptr->BytesReadable (ciptr, pend);
89773143b9aSmrg}
89873143b9aSmrg
89973143b9aSmrgint
90073143b9aSmrgTRANS(Read) (XtransConnInfo ciptr, char *buf, int size)
90173143b9aSmrg
90273143b9aSmrg{
90373143b9aSmrg    return ciptr->transptr->Read (ciptr, buf, size);
90473143b9aSmrg}
90573143b9aSmrg
90673143b9aSmrgint
907ac57ed83SmrgTRANS(Write) (XtransConnInfo ciptr, const char *buf, int size)
90873143b9aSmrg
90973143b9aSmrg{
91073143b9aSmrg    return ciptr->transptr->Write (ciptr, buf, size);
91173143b9aSmrg}
91273143b9aSmrg
91373143b9aSmrgint
91473143b9aSmrgTRANS(Readv) (XtransConnInfo ciptr, struct iovec *buf, int size)
91573143b9aSmrg
91673143b9aSmrg{
91773143b9aSmrg    return ciptr->transptr->Readv (ciptr, buf, size);
91873143b9aSmrg}
91973143b9aSmrg
92073143b9aSmrgint
92173143b9aSmrgTRANS(Writev) (XtransConnInfo ciptr, struct iovec *buf, int size)
92273143b9aSmrg
92373143b9aSmrg{
92473143b9aSmrg    return ciptr->transptr->Writev (ciptr, buf, size);
92573143b9aSmrg}
92673143b9aSmrg
92775ebec6dSmrg#if XTRANS_SEND_FDS
92875ebec6dSmrgint
92975ebec6dSmrgTRANS(SendFd) (XtransConnInfo ciptr, int fd, int do_close)
93075ebec6dSmrg{
93175ebec6dSmrg    return ciptr->transptr->SendFd(ciptr, fd, do_close);
93275ebec6dSmrg}
93375ebec6dSmrg
93475ebec6dSmrgint
93575ebec6dSmrgTRANS(RecvFd) (XtransConnInfo ciptr)
93675ebec6dSmrg{
93775ebec6dSmrg    return ciptr->transptr->RecvFd(ciptr);
93875ebec6dSmrg}
93975ebec6dSmrg#endif
94075ebec6dSmrg
94173143b9aSmrgint
94273143b9aSmrgTRANS(Disconnect) (XtransConnInfo ciptr)
94373143b9aSmrg
94473143b9aSmrg{
94573143b9aSmrg    return ciptr->transptr->Disconnect (ciptr);
94673143b9aSmrg}
94773143b9aSmrg
94873143b9aSmrgint
94973143b9aSmrgTRANS(Close) (XtransConnInfo ciptr)
95073143b9aSmrg
95173143b9aSmrg{
95273143b9aSmrg    int ret;
95373143b9aSmrg
954fe567363Smrg    prmsg (2,"Close(%d)\n", ciptr->fd);
95573143b9aSmrg
95673143b9aSmrg    ret = ciptr->transptr->Close (ciptr);
95773143b9aSmrg
95873143b9aSmrg    TRANS(FreeConnInfo) (ciptr);
95973143b9aSmrg
96073143b9aSmrg    return ret;
96173143b9aSmrg}
96273143b9aSmrg
96373143b9aSmrgint
96473143b9aSmrgTRANS(CloseForCloning) (XtransConnInfo ciptr)
96573143b9aSmrg
96673143b9aSmrg{
96773143b9aSmrg    int ret;
96873143b9aSmrg
969fe567363Smrg    prmsg (2,"CloseForCloning(%d)\n", ciptr->fd);
97073143b9aSmrg
97173143b9aSmrg    ret = ciptr->transptr->CloseForCloning (ciptr);
97273143b9aSmrg
97373143b9aSmrg    TRANS(FreeConnInfo) (ciptr);
97473143b9aSmrg
97573143b9aSmrg    return ret;
97673143b9aSmrg}
97773143b9aSmrg
97873143b9aSmrgint
97973143b9aSmrgTRANS(IsLocal) (XtransConnInfo ciptr)
98073143b9aSmrg
98173143b9aSmrg{
98273143b9aSmrg    return (ciptr->family == AF_UNIX);
98373143b9aSmrg}
98473143b9aSmrg
98573143b9aSmrgint
986fe567363SmrgTRANS(GetPeerAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
98773143b9aSmrg		    Xtransaddr **addrp)
98873143b9aSmrg
98973143b9aSmrg{
990fe567363Smrg    prmsg (2,"GetPeerAddr(%d)\n", ciptr->fd);
99173143b9aSmrg
99273143b9aSmrg    *familyp = ciptr->family;
99373143b9aSmrg    *addrlenp = ciptr->peeraddrlen;
99473143b9aSmrg
995fe567363Smrg    if ((*addrp = malloc (ciptr->peeraddrlen)) == NULL)
99673143b9aSmrg    {
997fe567363Smrg	prmsg (1,"GetPeerAddr: malloc failed\n");
99873143b9aSmrg	return -1;
99973143b9aSmrg    }
100073143b9aSmrg    memcpy(*addrp, ciptr->peeraddr, ciptr->peeraddrlen);
100173143b9aSmrg
100273143b9aSmrg    return 0;
100373143b9aSmrg}
100473143b9aSmrg
100573143b9aSmrg
100673143b9aSmrgint
100773143b9aSmrgTRANS(GetConnectionNumber) (XtransConnInfo ciptr)
100873143b9aSmrg
100973143b9aSmrg{
101073143b9aSmrg    return ciptr->fd;
101173143b9aSmrg}
101273143b9aSmrg
101373143b9aSmrg
101473143b9aSmrg/*
101573143b9aSmrg * These functions are really utility functions, but they require knowledge
101673143b9aSmrg * of the internal data structures, so they have to be part of the Transport
1017e45ace2bSmrg * Independent API.
101873143b9aSmrg */
101973143b9aSmrg
102073143b9aSmrg#ifdef TRANS_SERVER
102173143b9aSmrg
102273143b9aSmrgstatic int
102373143b9aSmrgcomplete_network_count (void)
102473143b9aSmrg
102573143b9aSmrg{
102673143b9aSmrg    int count = 0;
102773143b9aSmrg    int found_local = 0;
102873143b9aSmrg
102973143b9aSmrg    /*
103073143b9aSmrg     * For a complete network, we only need one LOCALCONN transport to work
103173143b9aSmrg     */
103273143b9aSmrg
103394f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
103473143b9aSmrg    {
103573143b9aSmrg	if (Xtransports[i].transport->flags & TRANS_ALIAS
103673143b9aSmrg   	 || Xtransports[i].transport->flags & TRANS_NOLISTEN)
103773143b9aSmrg	    continue;
103873143b9aSmrg
103973143b9aSmrg	if (Xtransports[i].transport->flags & TRANS_LOCAL)
104073143b9aSmrg	    found_local = 1;
104173143b9aSmrg	else
104273143b9aSmrg	    count++;
104373143b9aSmrg    }
104473143b9aSmrg
104573143b9aSmrg    return (count + found_local);
104673143b9aSmrg}
104773143b9aSmrg
104873143b9aSmrg
104975ebec6dSmrgstatic int
10506a3641a6Ssnjreceive_listening_fds(const char* port, XtransConnInfo* temp_ciptrs,
10516a3641a6Ssnj                      int* count_ret)
105275ebec6dSmrg
105375ebec6dSmrg{
105475ebec6dSmrg#ifdef HAVE_SYSTEMD_DAEMON
105575ebec6dSmrg    XtransConnInfo ciptr;
105675ebec6dSmrg    int i, systemd_listen_fds;
105775ebec6dSmrg
105875ebec6dSmrg    systemd_listen_fds = sd_listen_fds(1);
105975ebec6dSmrg    if (systemd_listen_fds < 0)
106075ebec6dSmrg    {
106175ebec6dSmrg        prmsg (1, "receive_listening_fds: sd_listen_fds error: %s\n",
106275ebec6dSmrg               strerror(-systemd_listen_fds));
106375ebec6dSmrg        return -1;
106475ebec6dSmrg    }
106575ebec6dSmrg
106694f982dbSmrg    for (i = 0; i < systemd_listen_fds && *count_ret < (int)NUMTRANS; i++)
106775ebec6dSmrg    {
106875ebec6dSmrg        struct sockaddr_storage a;
106975ebec6dSmrg        int ti;
107075ebec6dSmrg        const char* tn;
107175ebec6dSmrg        socklen_t al;
107275ebec6dSmrg
107375ebec6dSmrg        al = sizeof(a);
107475ebec6dSmrg        if (getsockname(i + SD_LISTEN_FDS_START, (struct sockaddr*)&a, &al) < 0) {
107575ebec6dSmrg            prmsg (1, "receive_listening_fds: getsockname error: %s\n",
107675ebec6dSmrg                   strerror(errno));
107775ebec6dSmrg            return -1;
107875ebec6dSmrg        }
107975ebec6dSmrg
108075ebec6dSmrg        switch (a.ss_family)
108175ebec6dSmrg        {
108275ebec6dSmrg        case AF_UNIX:
108375ebec6dSmrg            ti = TRANS_SOCKET_UNIX_INDEX;
108475ebec6dSmrg            if (*((struct sockaddr_un*)&a)->sun_path == '\0' &&
108575ebec6dSmrg                al > sizeof(sa_family_t))
108675ebec6dSmrg                tn = "local";
108775ebec6dSmrg            else
108875ebec6dSmrg                tn = "unix";
108975ebec6dSmrg            break;
109075ebec6dSmrg        case AF_INET:
109175ebec6dSmrg            ti = TRANS_SOCKET_INET_INDEX;
109275ebec6dSmrg            tn = "inet";
109375ebec6dSmrg            break;
1094ac57ed83Smrg#ifdef IPv6
109575ebec6dSmrg        case AF_INET6:
109675ebec6dSmrg            ti = TRANS_SOCKET_INET6_INDEX;
109775ebec6dSmrg            tn = "inet6";
109875ebec6dSmrg            break;
109975ebec6dSmrg#endif /* IPv6 */
110075ebec6dSmrg        default:
110175ebec6dSmrg            prmsg (1, "receive_listening_fds:"
110275ebec6dSmrg                   "Got unknown socket address family\n");
110375ebec6dSmrg            return -1;
110475ebec6dSmrg        }
110575ebec6dSmrg
110675ebec6dSmrg        ciptr = TRANS(ReopenCOTSServer)(ti, i + SD_LISTEN_FDS_START, port);
110775ebec6dSmrg        if (!ciptr)
110875ebec6dSmrg        {
110975ebec6dSmrg            prmsg (1, "receive_listening_fds:"
111075ebec6dSmrg                   "Got NULL while trying to reopen socket received from systemd.\n");
111175ebec6dSmrg            return -1;
111275ebec6dSmrg        }
111375ebec6dSmrg
111475ebec6dSmrg        prmsg (5, "receive_listening_fds: received listener for %s, %d\n",
111575ebec6dSmrg               tn, ciptr->fd);
111675ebec6dSmrg        temp_ciptrs[(*count_ret)++] = ciptr;
111775ebec6dSmrg        TRANS(Received)(tn);
111875ebec6dSmrg    }
111975ebec6dSmrg#endif /* HAVE_SYSTEMD_DAEMON */
112075ebec6dSmrg    return 0;
112175ebec6dSmrg}
112275ebec6dSmrg
11238d4c0f7bSmrg#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
11248d4c0f7bSmrgextern int xquartz_launchd_fd;
11258d4c0f7bSmrg#endif
112673143b9aSmrg
112773143b9aSmrgint
11286a3641a6SsnjTRANS(MakeAllCOTSServerListeners) (const char *port, int *partial,
11296a3641a6Ssnj                                   int *count_ret, XtransConnInfo **ciptrs_ret)
113073143b9aSmrg
113173143b9aSmrg{
113273143b9aSmrg    char		buffer[256]; /* ??? What size ?? */
113394f982dbSmrg    XtransConnInfo	ciptr, temp_ciptrs[NUMTRANS] = { NULL };
113494f982dbSmrg    int			status, j;
113573143b9aSmrg
1136ac57ed83Smrg#ifdef IPv6
113773143b9aSmrg    int		ipv6_succ = 0;
113873143b9aSmrg#endif
1139fe567363Smrg    prmsg (2,"MakeAllCOTSServerListeners(%s,%p)\n",
1140ac57ed83Smrg	   port ? port : "NULL", (void *) ciptrs_ret);
114173143b9aSmrg
114273143b9aSmrg    *count_ret = 0;
114373143b9aSmrg
11448d4c0f7bSmrg#ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
11458d4c0f7bSmrg    fprintf(stderr, "Launchd socket fd: %d\n", xquartz_launchd_fd);
11468d4c0f7bSmrg    if(xquartz_launchd_fd != -1) {
11478d4c0f7bSmrg        if((ciptr = TRANS(ReopenCOTSServer(TRANS_SOCKET_LOCAL_INDEX,
11488d4c0f7bSmrg                                           xquartz_launchd_fd, getenv("DISPLAY"))))==NULL)
11498d4c0f7bSmrg            fprintf(stderr,"Got NULL while trying to Reopen launchd port\n");
1150fe567363Smrg        else
11518d4c0f7bSmrg            temp_ciptrs[(*count_ret)++] = ciptr;
11528d4c0f7bSmrg    }
115373143b9aSmrg#endif
115473143b9aSmrg
115575ebec6dSmrg    if (receive_listening_fds(port, temp_ciptrs, count_ret) < 0)
115675ebec6dSmrg	return -1;
115775ebec6dSmrg
115894f982dbSmrg    for (unsigned int i = 0; i < NUMTRANS; i++)
115973143b9aSmrg    {
116073143b9aSmrg	Xtransport *trans = Xtransports[i].transport;
116173143b9aSmrg	unsigned int flags = 0;
116273143b9aSmrg
116375ebec6dSmrg	if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN ||
116475ebec6dSmrg	    trans->flags&TRANS_RECEIVED)
116573143b9aSmrg	    continue;
116673143b9aSmrg
116773143b9aSmrg	snprintf(buffer, sizeof(buffer), "%s/:%s",
116873143b9aSmrg		 trans->TransName, port ? port : "");
116973143b9aSmrg
1170fe567363Smrg	prmsg (5,"MakeAllCOTSServerListeners: opening %s\n",
1171fe567363Smrg	       buffer);
117273143b9aSmrg
117373143b9aSmrg	if ((ciptr = TRANS(OpenCOTSServer(buffer))) == NULL)
117473143b9aSmrg	{
117573143b9aSmrg	    if (trans->flags & TRANS_DISABLED)
117673143b9aSmrg		continue;
117773143b9aSmrg
1178fe567363Smrg	    prmsg (1,
117973143b9aSmrg	  "MakeAllCOTSServerListeners: failed to open listener for %s\n",
1180fe567363Smrg		  trans->TransName);
118173143b9aSmrg	    continue;
118273143b9aSmrg	}
1183ac57ed83Smrg#ifdef IPv6
118473143b9aSmrg		if ((Xtransports[i].transport_id == TRANS_SOCKET_INET_INDEX
118573143b9aSmrg		     && ipv6_succ))
118673143b9aSmrg		    flags |= ADDR_IN_USE_ALLOWED;
118773143b9aSmrg#endif
118873143b9aSmrg
118973143b9aSmrg	if ((status = TRANS(CreateListener (ciptr, port, flags))) < 0)
119073143b9aSmrg	{
1191e45ace2bSmrg            if (*partial != 0)
1192e45ace2bSmrg		continue;
1193e45ace2bSmrg
119473143b9aSmrg	    if (status == TRANS_ADDR_IN_USE)
119573143b9aSmrg	    {
119673143b9aSmrg		/*
119773143b9aSmrg		 * We failed to bind to the specified address because the
119873143b9aSmrg		 * address is in use.  It must be that a server is already
119973143b9aSmrg		 * running at this address, and this function should fail.
120073143b9aSmrg		 */
120173143b9aSmrg
1202fe567363Smrg		prmsg (1,
1203fe567363Smrg		"MakeAllCOTSServerListeners: server already running\n");
120473143b9aSmrg
120573143b9aSmrg		for (j = 0; j < *count_ret; j++)
120694f982dbSmrg		    if (temp_ciptrs[j] != NULL)
120794f982dbSmrg			TRANS(Close) (temp_ciptrs[j]);
120873143b9aSmrg
120973143b9aSmrg		*count_ret = 0;
121073143b9aSmrg		*ciptrs_ret = NULL;
121173143b9aSmrg		*partial = 0;
121273143b9aSmrg		return -1;
121373143b9aSmrg	    }
121473143b9aSmrg	    else
121573143b9aSmrg	    {
1216fe567363Smrg		prmsg (1,
121773143b9aSmrg	"MakeAllCOTSServerListeners: failed to create listener for %s\n",
1218fe567363Smrg		  trans->TransName);
121973143b9aSmrg
122073143b9aSmrg		continue;
122173143b9aSmrg	    }
122273143b9aSmrg	}
122373143b9aSmrg
1224ac57ed83Smrg#ifdef IPv6
122573143b9aSmrg	if (Xtransports[i].transport_id == TRANS_SOCKET_INET6_INDEX)
122673143b9aSmrg	    ipv6_succ = 1;
122773143b9aSmrg#endif
1228fe567363Smrg
1229fe567363Smrg	prmsg (5,
123073143b9aSmrg	      "MakeAllCOTSServerListeners: opened listener for %s, %d\n",
1231fe567363Smrg	      trans->TransName, ciptr->fd);
123273143b9aSmrg
123373143b9aSmrg	temp_ciptrs[*count_ret] = ciptr;
123473143b9aSmrg	(*count_ret)++;
123573143b9aSmrg    }
123673143b9aSmrg
123773143b9aSmrg    *partial = (*count_ret < complete_network_count());
123873143b9aSmrg
1239fe567363Smrg    prmsg (5,
124073143b9aSmrg     "MakeAllCOTSServerListeners: partial=%d, actual=%d, complete=%d \n",
124173143b9aSmrg	*partial, *count_ret, complete_network_count());
124273143b9aSmrg
124373143b9aSmrg    if (*count_ret > 0)
124473143b9aSmrg    {
1245fe567363Smrg	if ((*ciptrs_ret = malloc (
124673143b9aSmrg	    *count_ret * sizeof (XtransConnInfo))) == NULL)
124773143b9aSmrg	{
124873143b9aSmrg	    return -1;
124973143b9aSmrg	}
125073143b9aSmrg
125194f982dbSmrg	for (int i = 0; i < *count_ret; i++)
125273143b9aSmrg	{
125373143b9aSmrg	    (*ciptrs_ret)[i] = temp_ciptrs[i];
125473143b9aSmrg	}
125573143b9aSmrg    }
125673143b9aSmrg    else
125773143b9aSmrg	*ciptrs_ret = NULL;
1258fe567363Smrg
125973143b9aSmrg    return 0;
126073143b9aSmrg}
126173143b9aSmrg
126273143b9aSmrg#endif /* TRANS_SERVER */
126373143b9aSmrg
126473143b9aSmrg
126573143b9aSmrg
126673143b9aSmrg/*
126773143b9aSmrg * These routines are not part of the X Transport Interface, but they
126873143b9aSmrg * may be used by it.
126973143b9aSmrg */
127073143b9aSmrg
127173143b9aSmrg
12723d2ed3e3Smrg#ifdef WIN32
127373143b9aSmrg
127473143b9aSmrg/*
127573143b9aSmrg * emulate readv
127673143b9aSmrg */
127773143b9aSmrg
127873143b9aSmrgstatic int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
127973143b9aSmrg
128073143b9aSmrg{
128173143b9aSmrg    int i, len, total;
128273143b9aSmrg    char *base;
128373143b9aSmrg
128473143b9aSmrg    ESET(0);
128573143b9aSmrg    for (i = 0, total = 0;  i < iovcnt;  i++, iov++) {
128673143b9aSmrg	len = iov->iov_len;
128773143b9aSmrg	base = iov->iov_base;
128873143b9aSmrg	while (len > 0) {
128973143b9aSmrg	    register int nbytes;
129073143b9aSmrg	    nbytes = TRANS(Read) (ciptr, base, len);
129173143b9aSmrg	    if (nbytes < 0 && total == 0)  return -1;
129273143b9aSmrg	    if (nbytes <= 0)  return total;
129373143b9aSmrg	    ESET(0);
129473143b9aSmrg	    len   -= nbytes;
129573143b9aSmrg	    total += nbytes;
129673143b9aSmrg	    base  += nbytes;
129773143b9aSmrg	}
129873143b9aSmrg    }
129973143b9aSmrg    return total;
130073143b9aSmrg}
130173143b9aSmrg
130273143b9aSmrg
130373143b9aSmrg/*
130473143b9aSmrg * emulate writev
130573143b9aSmrg */
130673143b9aSmrg
130773143b9aSmrgstatic int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
130873143b9aSmrg
130973143b9aSmrg{
131073143b9aSmrg    int i, len, total;
131173143b9aSmrg    char *base;
131273143b9aSmrg
131373143b9aSmrg    ESET(0);
131473143b9aSmrg    for (i = 0, total = 0;  i < iovcnt;  i++, iov++) {
131573143b9aSmrg	len = iov->iov_len;
131673143b9aSmrg	base = iov->iov_base;
131773143b9aSmrg	while (len > 0) {
131873143b9aSmrg	    register int nbytes;
131973143b9aSmrg	    nbytes = TRANS(Write) (ciptr, base, len);
132073143b9aSmrg	    if (nbytes < 0 && total == 0)  return -1;
132173143b9aSmrg	    if (nbytes <= 0)  return total;
132273143b9aSmrg	    ESET(0);
132373143b9aSmrg	    len   -= nbytes;
132473143b9aSmrg	    total += nbytes;
132573143b9aSmrg	    base  += nbytes;
132673143b9aSmrg	}
132773143b9aSmrg    }
132873143b9aSmrg    return total;
132973143b9aSmrg}
133073143b9aSmrg
13313d2ed3e3Smrg#endif /* WIN32 */
133273143b9aSmrg
133373143b9aSmrg
1334e45ace2bSmrg#if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__SVR4)
133573143b9aSmrg#ifndef NEED_UTSNAME
133673143b9aSmrg#define NEED_UTSNAME
133773143b9aSmrg#endif
133873143b9aSmrg#include <sys/utsname.h>
133973143b9aSmrg#endif
134073143b9aSmrg
134173143b9aSmrg/*
134273143b9aSmrg * TRANS(GetHostname) - similar to gethostname but allows special processing.
134373143b9aSmrg */
134473143b9aSmrg
134573143b9aSmrgint TRANS(GetHostname) (char *buf, int maxlen)
134673143b9aSmrg
134773143b9aSmrg{
134873143b9aSmrg    int len;
134973143b9aSmrg
135073143b9aSmrg#ifdef NEED_UTSNAME
135173143b9aSmrg    struct utsname name;
135273143b9aSmrg
135373143b9aSmrg    uname (&name);
135473143b9aSmrg    len = strlen (name.nodename);
135573143b9aSmrg    if (len >= maxlen) len = maxlen - 1;
135694f982dbSmrg    memcpy (buf, name.nodename, len);
135773143b9aSmrg    buf[len] = '\0';
135873143b9aSmrg#else
135973143b9aSmrg    buf[0] = '\0';
136073143b9aSmrg    (void) gethostname (buf, maxlen);
136173143b9aSmrg    buf [maxlen - 1] = '\0';
136273143b9aSmrg    len = strlen(buf);
136373143b9aSmrg#endif /* NEED_UTSNAME */
136473143b9aSmrg    return len;
136573143b9aSmrg}
1366