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