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