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