Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2 
      3 Copyright 1993, 1994, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included
     12 in all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 OTHER DEALINGS IN THE SOFTWARE.
     21 
     22 Except as contained in this notice, the name of The Open Group shall
     23 not be used in advertising or otherwise to promote the sale, use or
     24 other dealings in this Software without prior written authorization
     25 from The Open Group.
     26 
     27  * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA
     28  *
     29  * All Rights Reserved
     30  *
     31  * Permission to use, copy, modify, and distribute this software and its
     32  * documentation for any purpose and without fee is hereby granted, provided
     33  * that the above copyright notice appear in all copies and that both that
     34  * copyright notice and this permission notice appear in supporting
     35  * documentation, and that the name NCR not be used in advertising
     36  * or publicity pertaining to distribution of the software without specific,
     37  * written prior permission.  NCR makes no representations about the
     38  * suitability of this software for any purpose.  It is provided "as is"
     39  * without express or implied warranty.
     40  *
     41  * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
     42  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
     43  * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
     44  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
     45  * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
     46  * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
     47  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     48  */
     49 
     50 #include <ctype.h>
     51 #include <stdlib.h>
     52 #include <string.h>
     53 #ifdef HAVE_SYSTEMD_DAEMON
     54 #include <systemd/sd-daemon.h>
     55 #endif
     56 
     57 /*
     58  * The transport table contains a definition for every transport (protocol)
     59  * family. All operations that can be made on the transport go through this
     60  * table.
     61  *
     62  * Each transport is assigned a unique transport id.
     63  *
     64  * New transports can be added by adding an entry in this table.
     65  * For compatibility, the transport ids should never be renumbered.
     66  * Always add to the end of the list.
     67  */
     68 
     69 #define TRANS_TLI_INET_INDEX		1
     70 #define TRANS_TLI_TCP_INDEX		2
     71 #define TRANS_TLI_TLI_INDEX		3
     72 #define TRANS_SOCKET_UNIX_INDEX		4
     73 #define TRANS_SOCKET_LOCAL_INDEX	5
     74 #define TRANS_SOCKET_INET_INDEX		6
     75 #define TRANS_SOCKET_TCP_INDEX		7
     76 #define TRANS_DNET_INDEX		8
     77 #define TRANS_LOCAL_LOCAL_INDEX		9
     78 /* 10 used to be PTS, but that's gone. */
     79 #define TRANS_LOCAL_NAMED_INDEX		11
     80 /* 12 used to be ISC, but that's gone. */
     81 /* 13 used to be SCO, but that's gone. */
     82 #define TRANS_SOCKET_INET6_INDEX	14
     83 #define TRANS_LOCAL_PIPE_INDEX		15
     84 
     85 #if defined(IPv6) && !defined(AF_INET6)
     86 #error "Cannot build IPv6 support without AF_INET6"
     87 #endif
     88 
     89 static
     90 Xtransport_table Xtransports[] = {
     91 #if defined(TCPCONN)
     92     { &TRANS(SocketTCPFuncs),	TRANS_SOCKET_TCP_INDEX },
     93 #if defined(IPv6)
     94     { &TRANS(SocketINET6Funcs),	TRANS_SOCKET_INET6_INDEX },
     95 #endif /* IPv6 */
     96     { &TRANS(SocketINETFuncs),	TRANS_SOCKET_INET_INDEX },
     97 #endif /* TCPCONN */
     98 #if defined(UNIXCONN)
     99 #if !defined(LOCALCONN)
    100     { &TRANS(SocketLocalFuncs),	TRANS_SOCKET_LOCAL_INDEX },
    101 #endif /* !LOCALCONN */
    102     { &TRANS(SocketUNIXFuncs),	TRANS_SOCKET_UNIX_INDEX },
    103 #endif /* UNIXCONN */
    104 #if defined(LOCALCONN)
    105     { &TRANS(LocalFuncs),	TRANS_LOCAL_LOCAL_INDEX },
    106 #if defined(SVR4) || defined(__SVR4)
    107     { &TRANS(NAMEDFuncs),	TRANS_LOCAL_NAMED_INDEX },
    108 #endif
    109 #ifdef __sun
    110     { &TRANS(PIPEFuncs),	TRANS_LOCAL_PIPE_INDEX },
    111 #endif /* __sun */
    112 #endif /* LOCALCONN */
    113 };
    114 
    115 #define NUMTRANS	(sizeof(Xtransports)/sizeof(Xtransport_table))
    116 
    117 
    118 #ifdef WIN32
    119 #define ioctl ioctlsocket
    120 #endif
    121 
    122 
    123 
    124 /*
    126  * These are a few utility function used by the public interface functions.
    127  */
    128 
    129 void
    130 TRANS(FreeConnInfo) (XtransConnInfo ciptr)
    131 
    132 {
    133     prmsg (3,"FreeConnInfo(%p)\n", (void *) ciptr);
    134 
    135     if (ciptr->addr)
    136 	free (ciptr->addr);
    137 
    138     if (ciptr->peeraddr)
    139 	free (ciptr->peeraddr);
    140 
    141     if (ciptr->port)
    142 	free (ciptr->port);
    143 
    144     free (ciptr);
    145 }
    146 
    147 
    148 #define PROTOBUFSIZE	20
    149 
    150 static Xtransport *
    151 TRANS(SelectTransport) (const char *protocol)
    152 
    153 {
    154 #ifndef HAVE_STRCASECMP
    155     char 	protobuf[PROTOBUFSIZE];
    156 #endif
    157 
    158     prmsg (3,"SelectTransport(%s)\n", protocol);
    159 
    160 #ifndef HAVE_STRCASECMP
    161     /*
    162      * Force Protocol to be lowercase as a way of doing
    163      * a case insensitive match.
    164      */
    165 
    166     strncpy (protobuf, protocol, PROTOBUFSIZE - 1);
    167     protobuf[PROTOBUFSIZE-1] = '\0';
    168 
    169     for (unsigned int i = 0; i < PROTOBUFSIZE && protobuf[i] != '\0'; i++)
    170 	if (isupper ((unsigned char)protobuf[i]))
    171 	    protobuf[i] = tolower ((unsigned char)protobuf[i]);
    172 #endif
    173 
    174     /* Look at all of the configured protocols */
    175 
    176     for (unsigned int i = 0; i < NUMTRANS; i++)
    177     {
    178 #ifndef HAVE_STRCASECMP
    179 	if (!strcmp (protobuf, Xtransports[i].transport->TransName))
    180 #else
    181 	if (!strcasecmp (protocol, Xtransports[i].transport->TransName))
    182 #endif
    183 	    return Xtransports[i].transport;
    184     }
    185 
    186     return NULL;
    187 }
    188 
    189 static int
    190 TRANS(ParseAddress) (const char *address,
    191                      char **protocol, char **host, char **port)
    192 
    193 {
    194     /*
    195      * For the font library, the address is a string formatted
    196      * as "protocol/host:port[/catalogue]".  Note that the catologue
    197      * is optional.  At this time, the catologue info is ignored, but
    198      * we have to parse it anyways.
    199      *
    200      * Other than fontlib, the address is a string formatted
    201      * as "protocol/host:port".
    202      *
    203      * If the protocol part is missing, then assume TCP.
    204      * If the protocol part and host part are missing, then assume local.
    205      * If a "::" is found then assume DNET.
    206      */
    207 
    208     char	*mybuf, *tmpptr = NULL;
    209     const char	*_protocol = NULL;
    210     const char	*_host, *_port;
    211     char	hostnamebuf[256];
    212     char	*_host_buf;
    213     int		_host_len;
    214 
    215     prmsg (3,"ParseAddress(%s)\n", address);
    216 
    217     /* First, check for AF_UNIX socket paths */
    218     if (address[0] == '/') {
    219         _protocol = "local";
    220         _host = "";
    221         _port = address;
    222     } else
    223 #ifdef HAVE_LAUNCHD
    224     /* launchd sockets will look like 'local//tmp/launch-XgkNns/:0' */
    225     if(!strncmp(address,"local//",7)) {
    226         _protocol="local";
    227         _host="";
    228         _port=address+6;
    229     } else
    230 #endif
    231     if (!strncmp(address, "unix:", 5)) {
    232         _protocol = "local";
    233         _host = "";
    234         _port = address + 5;
    235     }
    236     if (_protocol)
    237         goto done_parsing;
    238 
    239     /* Copy the string so it can be changed */
    240 
    241     tmpptr = mybuf = strdup (address);
    242 
    243     /* Parse the string to get each component */
    244 
    245     /* Get the protocol part */
    246 
    247     _protocol = mybuf;
    248 
    249 
    250     if ((mybuf == NULL) ||
    251         ( ((mybuf = strchr (mybuf, '/')) == NULL) &&
    252           ((mybuf = strrchr (tmpptr, ':')) == NULL) ) )
    253     {
    254 	/* address is in a bad format */
    255 	*protocol = NULL;
    256 	*host = NULL;
    257 	*port = NULL;
    258 	free (tmpptr);
    259 	return 0;
    260     }
    261 
    262     if (*mybuf == ':')
    263     {
    264 	/*
    265 	 * If there is a hostname, then assume tcp, otherwise
    266 	 * it must be local.
    267 	 */
    268 	if (mybuf == tmpptr)
    269 	{
    270 	    /* There is neither a protocol or host specified */
    271 	    _protocol = "local";
    272 	}
    273 	else
    274 	{
    275 	    /* There is a hostname specified */
    276 	    _protocol = "tcp";
    277 	    mybuf = tmpptr;	/* reset to the beginning of the host ptr */
    278 	}
    279     }
    280     else
    281     {
    282 	/* *mybuf == '/' */
    283 
    284 	*mybuf ++= '\0'; /* put a null at the end of the protocol */
    285 
    286 	if (strlen(_protocol) == 0)
    287 	{
    288 	    /*
    289 	     * If there is a hostname, then assume tcp, otherwise
    290 	     * it must be local.
    291 	     */
    292 	    if (*mybuf != ':')
    293 		_protocol = "tcp";
    294 	    else
    295 		_protocol = "local";
    296 	}
    297     }
    298 
    299     /* Get the host part */
    300 
    301     _host = _host_buf = mybuf;
    302 
    303     if ((mybuf = strrchr (mybuf,':')) == NULL)
    304     {
    305 	*protocol = NULL;
    306 	*host = NULL;
    307 	*port = NULL;
    308 	free (tmpptr);
    309 	return 0;
    310     }
    311 
    312     *mybuf ++= '\0';
    313 
    314     _host_len = strlen(_host);
    315     if (_host_len == 0)
    316     {
    317 	TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf));
    318 	_host = hostnamebuf;
    319     }
    320 #ifdef IPv6
    321     /* hostname in IPv6 [numeric_addr]:0 form? */
    322     else if ( (_host_len > 3) &&
    323       ((strcmp(_protocol, "tcp") == 0) || (strcmp(_protocol, "inet6") == 0))
    324       && (_host_buf[0] == '[') && (_host_buf[_host_len - 1] == ']') ) {
    325 	struct sockaddr_in6 sin6;
    326 
    327 	_host_buf[_host_len - 1] = '\0';
    328 
    329 	/* Verify address is valid IPv6 numeric form */
    330 	if (inet_pton(AF_INET6, _host + 1, &sin6) == 1) {
    331 	    /* It is. Use it as such. */
    332 	    _host++;
    333 	    _protocol = "inet6";
    334 	} else {
    335 	    /* It's not, restore it just in case some other code can use it. */
    336 	    _host_buf[_host_len - 1] = ']';
    337 	}
    338     }
    339 #endif
    340 
    341 
    342     /* Get the port */
    343 
    344     _port = mybuf;
    345 
    346 #if defined(FONT_t) || defined(FS_t)
    347     /*
    348      * Is there an optional catalogue list?
    349      */
    350 
    351     if ((mybuf = strchr (mybuf,'/')) != NULL)
    352 	*mybuf ++= '\0';
    353 
    354     /*
    355      * The rest, if any, is the (currently unused) catalogue list.
    356      *
    357      * _catalogue = mybuf;
    358      */
    359 #endif
    360 
    361 done_parsing:
    362     /*
    363      * Now that we have all of the components, allocate new
    364      * string space for them.
    365      */
    366 
    367     if ((*protocol = strdup (_protocol)) == NULL)
    368     {
    369 	/* Malloc failed */
    370 	*port = NULL;
    371 	*host = NULL;
    372 	*protocol = NULL;
    373 	free (tmpptr);
    374 	return 0;
    375     }
    376 
    377     if ((*host = strdup (_host)) == NULL)
    378     {
    379 	/* Malloc failed */
    380 	*port = NULL;
    381 	*host = NULL;
    382 	free (*protocol);
    383 	*protocol = NULL;
    384 	free (tmpptr);
    385 	return 0;
    386     }
    387 
    388     if ((*port = strdup (_port)) == NULL)
    389     {
    390 	/* Malloc failed */
    391 	*port = NULL;
    392 	free (*host);
    393 	*host = NULL;
    394 	free (*protocol);
    395 	*protocol = NULL;
    396 	free (tmpptr);
    397 	return 0;
    398     }
    399 
    400     free (tmpptr);
    401 
    402     return 1;
    403 }
    404 
    405 
    406 /*
    407  * TRANS(Open) does all of the real work opening a connection. The only
    408  * funny part about this is the type parameter which is used to decide which
    409  * type of open to perform.
    410  */
    411 
    412 static XtransConnInfo
    413 TRANS(Open) (int type, const char *address)
    414 
    415 {
    416     char 		*protocol = NULL, *host = NULL, *port = NULL;
    417     XtransConnInfo	ciptr = NULL;
    418     Xtransport		*thistrans;
    419 
    420     prmsg (2,"Open(%d,%s)\n", type, address);
    421 
    422 #if defined(WIN32) && defined(TCPCONN)
    423     if (TRANS(WSAStartup)())
    424     {
    425 	prmsg (1,"Open: WSAStartup failed\n");
    426 	return NULL;
    427     }
    428 #endif
    429 
    430     /* Parse the Address */
    431 
    432     if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
    433     {
    434 	prmsg (1,"Open: Unable to Parse address %s\n", address);
    435 	return NULL;
    436     }
    437 
    438     /* Determine the transport type */
    439 
    440     if ((thistrans = TRANS(SelectTransport) (protocol)) == NULL)
    441     {
    442 	prmsg (1,"Open: Unable to find transport for %s\n",
    443 	       protocol);
    444 
    445 	free (protocol);
    446 	free (host);
    447 	free (port);
    448 	return NULL;
    449     }
    450 
    451     /* Open the transport */
    452 
    453     switch (type)
    454     {
    455     case XTRANS_OPEN_COTS_CLIENT:
    456 #ifdef TRANS_CLIENT
    457 	ciptr = thistrans->OpenCOTSClient(thistrans, protocol, host, port);
    458 #endif /* TRANS_CLIENT */
    459 	break;
    460     case XTRANS_OPEN_COTS_SERVER:
    461 #ifdef TRANS_SERVER
    462 	ciptr = thistrans->OpenCOTSServer(thistrans, protocol, host, port);
    463 #endif /* TRANS_SERVER */
    464 	break;
    465     default:
    466 	prmsg (1,"Open: Unknown Open type %d\n", type);
    467     }
    468 
    469     if (ciptr == NULL)
    470     {
    471 	if (!(thistrans->flags & TRANS_DISABLED))
    472 	{
    473 	    prmsg (1,"Open: transport open failed for %s/%s:%s\n",
    474 	           protocol, host, port);
    475 	}
    476 	free (protocol);
    477 	free (host);
    478 	free (port);
    479 	return NULL;
    480     }
    481 
    482     ciptr->transptr = thistrans;
    483     ciptr->port = port;			/* We need this for TRANS(Reopen) */
    484 
    485     free (protocol);
    486     free (host);
    487 
    488     return ciptr;
    489 }
    490 
    491 
    492 #ifdef TRANS_REOPEN
    493 
    494 /*
    495  * We might want to create an XtransConnInfo object based on a previously
    496  * opened connection.  For example, the font server may clone itself and
    497  * pass file descriptors to the parent.
    498  */
    499 
    500 static XtransConnInfo
    501 TRANS(Reopen) (int type, int trans_id, int fd, const char *port)
    502 
    503 {
    504     XtransConnInfo	ciptr = NULL;
    505     Xtransport		*thistrans = NULL;
    506     char		*save_port;
    507 
    508     prmsg (2,"Reopen(%d,%d,%s)\n", trans_id, fd, port);
    509 
    510     /* Determine the transport type */
    511 
    512     for (unsigned int i = 0; i < NUMTRANS; i++)
    513     {
    514 	if (Xtransports[i].transport_id == trans_id)
    515 	{
    516 	    thistrans = Xtransports[i].transport;
    517 	    break;
    518 	}
    519     }
    520 
    521     if (thistrans == NULL)
    522     {
    523 	prmsg (1,"Reopen: Unable to find transport id %d\n",
    524 	       trans_id);
    525 
    526 	return NULL;
    527     }
    528 
    529     if ((save_port = strdup (port)) == NULL)
    530     {
    531 	prmsg (1,"Reopen: Unable to malloc port string\n");
    532 
    533 	return NULL;
    534     }
    535 
    536     /* Get a new XtransConnInfo object */
    537 
    538     switch (type)
    539     {
    540     case XTRANS_OPEN_COTS_SERVER:
    541 	ciptr = thistrans->ReopenCOTSServer(thistrans, fd, port);
    542 	break;
    543     default:
    544 	prmsg (1,"Reopen: Bad Open type %d\n", type);
    545     }
    546 
    547     if (ciptr == NULL)
    548     {
    549 	prmsg (1,"Reopen: transport open failed\n");
    550 	free (save_port);
    551 	return NULL;
    552     }
    553 
    554     ciptr->transptr = thistrans;
    555     ciptr->port = save_port;
    556 
    557     return ciptr;
    558 }
    559 
    560 #endif /* TRANS_REOPEN */
    561 
    562 
    563 
    564 /*
    566  * These are the public interfaces to this Transport interface.
    567  * These are the only functions that should have knowledge of the transport
    568  * table.
    569  */
    570 
    571 #ifdef TRANS_CLIENT
    572 
    573 XtransConnInfo
    574 TRANS(OpenCOTSClient) (const char *address)
    575 
    576 {
    577     prmsg (2,"OpenCOTSClient(%s)\n", address);
    578     return TRANS(Open) (XTRANS_OPEN_COTS_CLIENT, address);
    579 }
    580 
    581 #endif /* TRANS_CLIENT */
    582 
    583 
    584 #ifdef TRANS_SERVER
    585 
    586 XtransConnInfo
    587 TRANS(OpenCOTSServer) (const char *address)
    588 
    589 {
    590     prmsg (2,"OpenCOTSServer(%s)\n", address);
    591     return TRANS(Open) (XTRANS_OPEN_COTS_SERVER, address);
    592 }
    593 
    594 #endif /* TRANS_SERVER */
    595 
    596 
    597 #ifdef TRANS_REOPEN
    598 
    599 XtransConnInfo
    600 TRANS(ReopenCOTSServer) (int trans_id, int fd, const char *port)
    601 
    602 {
    603     prmsg (2,"ReopenCOTSServer(%d, %d, %s)\n", trans_id, fd, port);
    604     return TRANS(Reopen) (XTRANS_OPEN_COTS_SERVER, trans_id, fd, port);
    605 }
    606 
    607 int
    608 TRANS(GetReopenInfo) (XtransConnInfo ciptr,
    609 		      int *trans_id, int *fd, char **port)
    610 
    611 {
    612     for (unsigned int i = 0; i < NUMTRANS; i++)
    613     {
    614 	if (Xtransports[i].transport == ciptr->transptr)
    615 	{
    616 	    *trans_id = Xtransports[i].transport_id;
    617 	    *fd = ciptr->fd;
    618 
    619 	    if ((*port = strdup (ciptr->port)) == NULL)
    620 		return 0;
    621 	    else
    622 		return 1;
    623 	}
    624     }
    625 
    626     return 0;
    627 }
    628 
    629 #endif /* TRANS_REOPEN */
    630 
    631 
    632 int
    633 TRANS(SetOption) (XtransConnInfo ciptr, int option, int arg)
    634 
    635 {
    636     int	fd = ciptr->fd;
    637     int	ret = 0;
    638 
    639     prmsg (2,"SetOption(%d,%d,%d)\n", fd, option, arg);
    640 
    641     /*
    642      * For now, all transport type use the same stuff for setting options.
    643      * As long as this is true, we can put the common code here. Once a more
    644      * complicated transport such as shared memory or an OSI implementation
    645      * that uses the session and application libraries is implemented, this
    646      * code may have to move to a transport dependent function.
    647      *
    648      * ret = ciptr->transptr->SetOption (ciptr, option, arg);
    649      */
    650 
    651     switch (option)
    652     {
    653     case TRANS_NONBLOCKING:
    654 	switch (arg)
    655 	{
    656 	case 0:
    657 	    /* Set to blocking mode */
    658 	    break;
    659 	case 1: /* Set to non-blocking mode */
    660 
    661 #if defined(O_NONBLOCK)
    662 	    ret = fcntl (fd, F_GETFL, 0);
    663 	    if (ret != -1)
    664 		ret = fcntl (fd, F_SETFL, ret | O_NONBLOCK);
    665 #else
    666 #ifdef FIOSNBIO
    667 	{
    668 	    int arg;
    669 	    arg = 1;
    670 	    ret = ioctl (fd, FIOSNBIO, &arg);
    671 	}
    672 #else
    673 #if defined(WIN32)
    674 	{
    675 #ifdef WIN32
    676 	    u_long arg;
    677 #else
    678 	    int arg;
    679 #endif
    680 	    arg = 1;
    681 /* IBM TCP/IP understands this option too well: it causes TRANS(Read) to fail
    682  * eventually with EWOULDBLOCK */
    683 	    ret = ioctl (fd, FIONBIO, &arg);
    684 	}
    685 #else
    686 	    ret = fcntl (fd, F_GETFL, 0);
    687 #ifdef FNDELAY
    688 	    ret = fcntl (fd, F_SETFL, ret | FNDELAY);
    689 #else
    690 	    ret = fcntl (fd, F_SETFL, ret | O_NDELAY);
    691 #endif
    692 #endif /* AIXV3  || uniosu */
    693 #endif /* FIOSNBIO */
    694 #endif /* O_NONBLOCK */
    695 	    break;
    696 	default:
    697 	    /* Unknown option */
    698 	    break;
    699 	}
    700 	break;
    701     case TRANS_CLOSEONEXEC:
    702 #ifdef F_SETFD
    703 #ifdef FD_CLOEXEC
    704 	ret = fcntl (fd, F_SETFD, FD_CLOEXEC);
    705 #else
    706 	ret = fcntl (fd, F_SETFD, 1);
    707 #endif /* FD_CLOEXEC */
    708 #endif /* F_SETFD */
    709 	break;
    710     }
    711 
    712     return ret;
    713 }
    714 
    715 #ifdef TRANS_SERVER
    716 
    717 int
    718 TRANS(CreateListener) (XtransConnInfo ciptr, const char *port, unsigned int flags)
    719 
    720 {
    721     return ciptr->transptr->CreateListener (ciptr, port, flags);
    722 }
    723 
    724 int
    725 TRANS(Received) (const char * protocol)
    726 
    727 {
    728    Xtransport *trans;
    729    int i = 0, ret = 0;
    730 
    731    prmsg (5, "Received(%s)\n", protocol);
    732 
    733    if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
    734    {
    735 	prmsg (1,"Received: unable to find transport: %s\n",
    736 	       protocol);
    737 
    738 	return -1;
    739    }
    740    if (trans->flags & TRANS_ALIAS) {
    741        if (trans->nolisten)
    742 	   while (trans->nolisten[i]) {
    743 	       ret |= TRANS(Received)(trans->nolisten[i]);
    744 	       i++;
    745        }
    746    }
    747 
    748    trans->flags |= TRANS_RECEIVED;
    749    return ret;
    750 }
    751 
    752 int
    753 TRANS(NoListen) (const char * protocol)
    754 
    755 {
    756    Xtransport *trans;
    757    int i = 0, ret = 0;
    758 
    759    if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
    760    {
    761 	prmsg (1,"TransNoListen: unable to find transport: %s\n",
    762 	       protocol);
    763 
    764 	return -1;
    765    }
    766    if (trans->flags & TRANS_ALIAS) {
    767        if (trans->nolisten)
    768 	   while (trans->nolisten[i]) {
    769 	       ret |= TRANS(NoListen)(trans->nolisten[i]);
    770 	       i++;
    771        }
    772    }
    773 
    774    trans->flags |= TRANS_NOLISTEN;
    775    return ret;
    776 }
    777 
    778 int
    779 TRANS(Listen) (const char * protocol)
    780 {
    781    Xtransport *trans;
    782    int i = 0, ret = 0;
    783 
    784    if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
    785    {
    786 	prmsg (1,"TransListen: unable to find transport: %s\n",
    787 	       protocol);
    788 
    789 	return -1;
    790    }
    791    if (trans->flags & TRANS_ALIAS) {
    792        if (trans->nolisten)
    793 	   while (trans->nolisten[i]) {
    794 	       ret |= TRANS(Listen)(trans->nolisten[i]);
    795 	       i++;
    796        }
    797    }
    798 
    799    trans->flags &= ~TRANS_NOLISTEN;
    800    return ret;
    801 }
    802 
    803 int
    804 TRANS(IsListening) (const char * protocol)
    805 {
    806    Xtransport *trans;
    807 
    808    if ((trans = TRANS(SelectTransport)(protocol)) == NULL)
    809    {
    810 	prmsg (1,"TransIsListening: unable to find transport: %s\n",
    811 	       protocol);
    812 
    813 	return 0;
    814    }
    815 
    816    return !(trans->flags & TRANS_NOLISTEN);
    817 }
    818 
    819 int
    820 TRANS(ResetListener) (XtransConnInfo ciptr)
    821 
    822 {
    823     if (ciptr->transptr->ResetListener)
    824 	return ciptr->transptr->ResetListener (ciptr);
    825     else
    826 	return TRANS_RESET_NOOP;
    827 }
    828 
    829 
    830 XtransConnInfo
    831 TRANS(Accept) (XtransConnInfo ciptr, int *status)
    832 
    833 {
    834     XtransConnInfo	newciptr;
    835 
    836     prmsg (2,"Accept(%d)\n", ciptr->fd);
    837 
    838     newciptr = ciptr->transptr->Accept (ciptr, status);
    839 
    840     if (newciptr)
    841 	newciptr->transptr = ciptr->transptr;
    842 
    843     return newciptr;
    844 }
    845 
    846 #endif /* TRANS_SERVER */
    847 
    848 
    849 #ifdef TRANS_CLIENT
    850 
    851 int
    852 TRANS(Connect) (XtransConnInfo ciptr, const char *address)
    853 
    854 {
    855     char	*protocol;
    856     char	*host;
    857     char	*port;
    858     int		ret;
    859 
    860     prmsg (2,"Connect(%d,%s)\n", ciptr->fd, address);
    861 
    862     if (TRANS(ParseAddress) (address, &protocol, &host, &port) == 0)
    863     {
    864 	prmsg (1,"Connect: Unable to Parse address %s\n",
    865 	       address);
    866 	return -1;
    867     }
    868 
    869 #ifdef HAVE_LAUNCHD
    870     if (!host) host=strdup("");
    871 #endif
    872 
    873     if (!port || !*port)
    874     {
    875 	prmsg (1,"Connect: Missing port specification in %s\n",
    876 	      address);
    877 	if (protocol) free (protocol);
    878 	if (host) free (host);
    879 	return -1;
    880     }
    881 
    882     ret = ciptr->transptr->Connect (ciptr, host, port);
    883 
    884     if (protocol) free (protocol);
    885     if (host) free (host);
    886     if (port) free (port);
    887 
    888     return ret;
    889 }
    890 
    891 #endif /* TRANS_CLIENT */
    892 
    893 
    894 int
    895 TRANS(BytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend)
    896 
    897 {
    898     return ciptr->transptr->BytesReadable (ciptr, pend);
    899 }
    900 
    901 int
    902 TRANS(Read) (XtransConnInfo ciptr, char *buf, int size)
    903 
    904 {
    905     return ciptr->transptr->Read (ciptr, buf, size);
    906 }
    907 
    908 int
    909 TRANS(Write) (XtransConnInfo ciptr, const char *buf, int size)
    910 
    911 {
    912     return ciptr->transptr->Write (ciptr, buf, size);
    913 }
    914 
    915 int
    916 TRANS(Readv) (XtransConnInfo ciptr, struct iovec *buf, int size)
    917 
    918 {
    919     return ciptr->transptr->Readv (ciptr, buf, size);
    920 }
    921 
    922 int
    923 TRANS(Writev) (XtransConnInfo ciptr, struct iovec *buf, int size)
    924 
    925 {
    926     return ciptr->transptr->Writev (ciptr, buf, size);
    927 }
    928 
    929 #if XTRANS_SEND_FDS
    930 int
    931 TRANS(SendFd) (XtransConnInfo ciptr, int fd, int do_close)
    932 {
    933     return ciptr->transptr->SendFd(ciptr, fd, do_close);
    934 }
    935 
    936 int
    937 TRANS(RecvFd) (XtransConnInfo ciptr)
    938 {
    939     return ciptr->transptr->RecvFd(ciptr);
    940 }
    941 #endif
    942 
    943 int
    944 TRANS(Disconnect) (XtransConnInfo ciptr)
    945 
    946 {
    947     return ciptr->transptr->Disconnect (ciptr);
    948 }
    949 
    950 int
    951 TRANS(Close) (XtransConnInfo ciptr)
    952 
    953 {
    954     int ret;
    955 
    956     prmsg (2,"Close(%d)\n", ciptr->fd);
    957 
    958     ret = ciptr->transptr->Close (ciptr);
    959 
    960     TRANS(FreeConnInfo) (ciptr);
    961 
    962     return ret;
    963 }
    964 
    965 int
    966 TRANS(CloseForCloning) (XtransConnInfo ciptr)
    967 
    968 {
    969     int ret;
    970 
    971     prmsg (2,"CloseForCloning(%d)\n", ciptr->fd);
    972 
    973     ret = ciptr->transptr->CloseForCloning (ciptr);
    974 
    975     TRANS(FreeConnInfo) (ciptr);
    976 
    977     return ret;
    978 }
    979 
    980 int
    981 TRANS(IsLocal) (XtransConnInfo ciptr)
    982 
    983 {
    984     return (ciptr->family == AF_UNIX);
    985 }
    986 
    987 int
    988 TRANS(GetPeerAddr) (XtransConnInfo ciptr, int *familyp, int *addrlenp,
    989 		    Xtransaddr **addrp)
    990 
    991 {
    992     prmsg (2,"GetPeerAddr(%d)\n", ciptr->fd);
    993 
    994     *familyp = ciptr->family;
    995     *addrlenp = ciptr->peeraddrlen;
    996 
    997     if ((*addrp = malloc (ciptr->peeraddrlen)) == NULL)
    998     {
    999 	prmsg (1,"GetPeerAddr: malloc failed\n");
   1000 	return -1;
   1001     }
   1002     memcpy(*addrp, ciptr->peeraddr, ciptr->peeraddrlen);
   1003 
   1004     return 0;
   1005 }
   1006 
   1007 
   1008 int
   1009 TRANS(GetConnectionNumber) (XtransConnInfo ciptr)
   1010 
   1011 {
   1012     return ciptr->fd;
   1013 }
   1014 
   1015 
   1016 /*
   1018  * These functions are really utility functions, but they require knowledge
   1019  * of the internal data structures, so they have to be part of the Transport
   1020  * Independent API.
   1021  */
   1022 
   1023 #ifdef TRANS_SERVER
   1024 
   1025 static int
   1026 complete_network_count (void)
   1027 
   1028 {
   1029     int count = 0;
   1030     int found_local = 0;
   1031 
   1032     /*
   1033      * For a complete network, we only need one LOCALCONN transport to work
   1034      */
   1035 
   1036     for (unsigned int i = 0; i < NUMTRANS; i++)
   1037     {
   1038 	if (Xtransports[i].transport->flags & TRANS_ALIAS
   1039    	 || Xtransports[i].transport->flags & TRANS_NOLISTEN)
   1040 	    continue;
   1041 
   1042 	if (Xtransports[i].transport->flags & TRANS_LOCAL)
   1043 	    found_local = 1;
   1044 	else
   1045 	    count++;
   1046     }
   1047 
   1048     return (count + found_local);
   1049 }
   1050 
   1051 
   1052 static int
   1053 receive_listening_fds(const char* port, XtransConnInfo* temp_ciptrs,
   1054                       int* count_ret)
   1055 
   1056 {
   1057 #ifdef HAVE_SYSTEMD_DAEMON
   1058     XtransConnInfo ciptr;
   1059     int i, systemd_listen_fds;
   1060 
   1061     systemd_listen_fds = sd_listen_fds(1);
   1062     if (systemd_listen_fds < 0)
   1063     {
   1064         prmsg (1, "receive_listening_fds: sd_listen_fds error: %s\n",
   1065                strerror(-systemd_listen_fds));
   1066         return -1;
   1067     }
   1068 
   1069     for (i = 0; i < systemd_listen_fds && *count_ret < (int)NUMTRANS; i++)
   1070     {
   1071         struct sockaddr_storage a;
   1072         int ti;
   1073         const char* tn;
   1074         socklen_t al;
   1075 
   1076         al = sizeof(a);
   1077         if (getsockname(i + SD_LISTEN_FDS_START, (struct sockaddr*)&a, &al) < 0) {
   1078             prmsg (1, "receive_listening_fds: getsockname error: %s\n",
   1079                    strerror(errno));
   1080             return -1;
   1081         }
   1082 
   1083         switch (a.ss_family)
   1084         {
   1085         case AF_UNIX:
   1086             ti = TRANS_SOCKET_UNIX_INDEX;
   1087             if (*((struct sockaddr_un*)&a)->sun_path == '\0' &&
   1088                 al > sizeof(sa_family_t))
   1089                 tn = "local";
   1090             else
   1091                 tn = "unix";
   1092             break;
   1093         case AF_INET:
   1094             ti = TRANS_SOCKET_INET_INDEX;
   1095             tn = "inet";
   1096             break;
   1097 #ifdef IPv6
   1098         case AF_INET6:
   1099             ti = TRANS_SOCKET_INET6_INDEX;
   1100             tn = "inet6";
   1101             break;
   1102 #endif /* IPv6 */
   1103         default:
   1104             prmsg (1, "receive_listening_fds:"
   1105                    "Got unknown socket address family\n");
   1106             return -1;
   1107         }
   1108 
   1109         ciptr = TRANS(ReopenCOTSServer)(ti, i + SD_LISTEN_FDS_START, port);
   1110         if (!ciptr)
   1111         {
   1112             prmsg (1, "receive_listening_fds:"
   1113                    "Got NULL while trying to reopen socket received from systemd.\n");
   1114             return -1;
   1115         }
   1116 
   1117         prmsg (5, "receive_listening_fds: received listener for %s, %d\n",
   1118                tn, ciptr->fd);
   1119         temp_ciptrs[(*count_ret)++] = ciptr;
   1120         TRANS(Received)(tn);
   1121     }
   1122 #endif /* HAVE_SYSTEMD_DAEMON */
   1123     return 0;
   1124 }
   1125 
   1126 #ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
   1127 extern int xquartz_launchd_fd;
   1128 #endif
   1129 
   1130 int
   1131 TRANS(MakeAllCOTSServerListeners) (const char *port, int *partial,
   1132                                    int *count_ret, XtransConnInfo **ciptrs_ret)
   1133 
   1134 {
   1135     char		buffer[256]; /* ??? What size ?? */
   1136     XtransConnInfo	ciptr, temp_ciptrs[NUMTRANS] = { NULL };
   1137     int			status, j;
   1138 
   1139 #ifdef IPv6
   1140     int		ipv6_succ = 0;
   1141 #endif
   1142     prmsg (2,"MakeAllCOTSServerListeners(%s,%p)\n",
   1143 	   port ? port : "NULL", (void *) ciptrs_ret);
   1144 
   1145     *count_ret = 0;
   1146 
   1147 #ifdef XQUARTZ_EXPORTS_LAUNCHD_FD
   1148     fprintf(stderr, "Launchd socket fd: %d\n", xquartz_launchd_fd);
   1149     if(xquartz_launchd_fd != -1) {
   1150         if((ciptr = TRANS(ReopenCOTSServer(TRANS_SOCKET_LOCAL_INDEX,
   1151                                            xquartz_launchd_fd, getenv("DISPLAY"))))==NULL)
   1152             fprintf(stderr,"Got NULL while trying to Reopen launchd port\n");
   1153         else
   1154             temp_ciptrs[(*count_ret)++] = ciptr;
   1155     }
   1156 #endif
   1157 
   1158     if (receive_listening_fds(port, temp_ciptrs, count_ret) < 0)
   1159 	return -1;
   1160 
   1161     for (unsigned int i = 0; i < NUMTRANS; i++)
   1162     {
   1163 	Xtransport *trans = Xtransports[i].transport;
   1164 	unsigned int flags = 0;
   1165 
   1166 	if (trans->flags&TRANS_ALIAS || trans->flags&TRANS_NOLISTEN ||
   1167 	    trans->flags&TRANS_RECEIVED)
   1168 	    continue;
   1169 
   1170 	snprintf(buffer, sizeof(buffer), "%s/:%s",
   1171 		 trans->TransName, port ? port : "");
   1172 
   1173 	prmsg (5,"MakeAllCOTSServerListeners: opening %s\n",
   1174 	       buffer);
   1175 
   1176 	if ((ciptr = TRANS(OpenCOTSServer(buffer))) == NULL)
   1177 	{
   1178 	    if (trans->flags & TRANS_DISABLED)
   1179 		continue;
   1180 
   1181 	    prmsg (1,
   1182 	  "MakeAllCOTSServerListeners: failed to open listener for %s\n",
   1183 		  trans->TransName);
   1184 	    continue;
   1185 	}
   1186 #ifdef IPv6
   1187 		if ((Xtransports[i].transport_id == TRANS_SOCKET_INET_INDEX
   1188 		     && ipv6_succ))
   1189 		    flags |= ADDR_IN_USE_ALLOWED;
   1190 #endif
   1191 
   1192 	if ((status = TRANS(CreateListener (ciptr, port, flags))) < 0)
   1193 	{
   1194             if (*partial != 0)
   1195 		continue;
   1196 
   1197 	    if (status == TRANS_ADDR_IN_USE)
   1198 	    {
   1199 		/*
   1200 		 * We failed to bind to the specified address because the
   1201 		 * address is in use.  It must be that a server is already
   1202 		 * running at this address, and this function should fail.
   1203 		 */
   1204 
   1205 		prmsg (1,
   1206 		"MakeAllCOTSServerListeners: server already running\n");
   1207 
   1208 		for (j = 0; j < *count_ret; j++)
   1209 		    if (temp_ciptrs[j] != NULL)
   1210 			TRANS(Close) (temp_ciptrs[j]);
   1211 
   1212 		*count_ret = 0;
   1213 		*ciptrs_ret = NULL;
   1214 		*partial = 0;
   1215 		return -1;
   1216 	    }
   1217 	    else
   1218 	    {
   1219 		prmsg (1,
   1220 	"MakeAllCOTSServerListeners: failed to create listener for %s\n",
   1221 		  trans->TransName);
   1222 
   1223 		continue;
   1224 	    }
   1225 	}
   1226 
   1227 #ifdef IPv6
   1228 	if (Xtransports[i].transport_id == TRANS_SOCKET_INET6_INDEX)
   1229 	    ipv6_succ = 1;
   1230 #endif
   1231 
   1232 	prmsg (5,
   1233 	      "MakeAllCOTSServerListeners: opened listener for %s, %d\n",
   1234 	      trans->TransName, ciptr->fd);
   1235 
   1236 	temp_ciptrs[*count_ret] = ciptr;
   1237 	(*count_ret)++;
   1238     }
   1239 
   1240     *partial = (*count_ret < complete_network_count());
   1241 
   1242     prmsg (5,
   1243      "MakeAllCOTSServerListeners: partial=%d, actual=%d, complete=%d \n",
   1244 	*partial, *count_ret, complete_network_count());
   1245 
   1246     if (*count_ret > 0)
   1247     {
   1248 	if ((*ciptrs_ret = malloc (
   1249 	    *count_ret * sizeof (XtransConnInfo))) == NULL)
   1250 	{
   1251 	    return -1;
   1252 	}
   1253 
   1254 	for (int i = 0; i < *count_ret; i++)
   1255 	{
   1256 	    (*ciptrs_ret)[i] = temp_ciptrs[i];
   1257 	}
   1258     }
   1259     else
   1260 	*ciptrs_ret = NULL;
   1261 
   1262     return 0;
   1263 }
   1264 
   1265 #endif /* TRANS_SERVER */
   1266 
   1267 
   1268 
   1269 /*
   1271  * These routines are not part of the X Transport Interface, but they
   1272  * may be used by it.
   1273  */
   1274 
   1275 
   1276 #ifdef WIN32
   1277 
   1278 /*
   1279  * emulate readv
   1280  */
   1281 
   1282 static int TRANS(ReadV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
   1283 
   1284 {
   1285     int i, len, total;
   1286     char *base;
   1287 
   1288     ESET(0);
   1289     for (i = 0, total = 0;  i < iovcnt;  i++, iov++) {
   1290 	len = iov->iov_len;
   1291 	base = iov->iov_base;
   1292 	while (len > 0) {
   1293 	    register int nbytes;
   1294 	    nbytes = TRANS(Read) (ciptr, base, len);
   1295 	    if (nbytes < 0 && total == 0)  return -1;
   1296 	    if (nbytes <= 0)  return total;
   1297 	    ESET(0);
   1298 	    len   -= nbytes;
   1299 	    total += nbytes;
   1300 	    base  += nbytes;
   1301 	}
   1302     }
   1303     return total;
   1304 }
   1305 
   1306 
   1307 /*
   1308  * emulate writev
   1309  */
   1310 
   1311 static int TRANS(WriteV) (XtransConnInfo ciptr, struct iovec *iov, int iovcnt)
   1312 
   1313 {
   1314     int i, len, total;
   1315     char *base;
   1316 
   1317     ESET(0);
   1318     for (i = 0, total = 0;  i < iovcnt;  i++, iov++) {
   1319 	len = iov->iov_len;
   1320 	base = iov->iov_base;
   1321 	while (len > 0) {
   1322 	    register int nbytes;
   1323 	    nbytes = TRANS(Write) (ciptr, base, len);
   1324 	    if (nbytes < 0 && total == 0)  return -1;
   1325 	    if (nbytes <= 0)  return total;
   1326 	    ESET(0);
   1327 	    len   -= nbytes;
   1328 	    total += nbytes;
   1329 	    base  += nbytes;
   1330 	}
   1331     }
   1332     return total;
   1333 }
   1334 
   1335 #endif /* WIN32 */
   1336 
   1337 
   1338 #if defined(_POSIX_SOURCE) || defined(SVR4) || defined(__SVR4)
   1339 #ifndef NEED_UTSNAME
   1340 #define NEED_UTSNAME
   1341 #endif
   1342 #include <sys/utsname.h>
   1343 #endif
   1344 
   1345 /*
   1346  * TRANS(GetHostname) - similar to gethostname but allows special processing.
   1347  */
   1348 
   1349 int TRANS(GetHostname) (char *buf, int maxlen)
   1350 
   1351 {
   1352     int len;
   1353 
   1354 #ifdef NEED_UTSNAME
   1355     struct utsname name;
   1356 
   1357     uname (&name);
   1358     len = strlen (name.nodename);
   1359     if (len >= maxlen) len = maxlen - 1;
   1360     memcpy (buf, name.nodename, len);
   1361     buf[len] = '\0';
   1362 #else
   1363     buf[0] = '\0';
   1364     (void) gethostname (buf, maxlen);
   1365     buf [maxlen - 1] = '\0';
   1366     len = strlen(buf);
   1367 #endif /* NEED_UTSNAME */
   1368     return len;
   1369 }
   1370