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