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