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