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