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