Xtranssock.c revision 81d6fa61
1/* 2 * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 21 * DEALINGS IN THE SOFTWARE. 22 */ 23/* 24 25Copyright 1993, 1994, 1998 The Open Group 26 27Permission to use, copy, modify, distribute, and sell this software and its 28documentation for any purpose is hereby granted without fee, provided that 29the above copyright notice appear in all copies and that both that 30copyright notice and this permission notice appear in supporting 31documentation. 32 33The above copyright notice and this permission notice shall be included 34in all copies or substantial portions of the Software. 35 36THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 37OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 38MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 39IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 40OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 41ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 42OTHER DEALINGS IN THE SOFTWARE. 43 44Except as contained in this notice, the name of the copyright holders shall 45not be used in advertising or otherwise to promote the sale, use or 46other dealings in this Software without prior written authorization 47from the copyright holders. 48 49 * Copyright 1993, 1994 NCR Corporation - Dayton, Ohio, USA 50 * 51 * All Rights Reserved 52 * 53 * Permission to use, copy, modify, and distribute this software and its 54 * documentation for any purpose and without fee is hereby granted, provided 55 * that the above copyright notice appear in all copies and that both that 56 * copyright notice and this permission notice appear in supporting 57 * documentation, and that the name NCR not be used in advertising 58 * or publicity pertaining to distribution of the software without specific, 59 * written prior permission. NCR makes no representations about the 60 * suitability of this software for any purpose. It is provided "as is" 61 * without express or implied warranty. 62 * 63 * NCR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 64 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN 65 * NO EVENT SHALL NCR BE LIABLE FOR ANY SPECIAL, INDIRECT OR 66 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS 67 * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 68 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 69 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 70 */ 71 72#include <ctype.h> 73#ifdef XTHREADS 74#include <X11/Xthreads.h> 75#endif 76 77#ifndef WIN32 78 79#if defined(TCPCONN) || defined(UNIXCONN) 80#include <sys/socket.h> 81#include <netinet/in.h> 82#include <arpa/inet.h> 83#endif 84 85#if defined(TCPCONN) || defined(UNIXCONN) 86#define X_INCLUDE_NETDB_H 87#define XOS_USE_NO_LOCKING 88#include <X11/Xos_r.h> 89#endif 90 91#ifdef UNIXCONN 92#ifndef X_NO_SYS_UN 93#include <sys/un.h> 94#endif 95#include <sys/stat.h> 96#endif 97 98 99#ifndef NO_TCP_H 100#if defined(linux) || defined(__GLIBC__) 101#include <sys/param.h> 102#endif /* osf */ 103#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__DragonFly__) 104#include <sys/param.h> 105#include <machine/endian.h> 106#endif /* __NetBSD__ || __OpenBSD__ || __FreeBSD__ || __DragonFly__ */ 107#include <netinet/tcp.h> 108#endif /* !NO_TCP_H */ 109 110#include <sys/ioctl.h> 111#if defined(SVR4) || defined(__SVR4) 112#include <sys/filio.h> 113#endif 114 115#if (defined(__i386__) && defined(SYSV)) && !defined(SCO325) && !defined(sun) 116#include <net/errno.h> 117#endif 118 119#if defined(__i386__) && defined(SYSV) 120#include <sys/stropts.h> 121#endif 122 123#include <unistd.h> 124 125#else /* !WIN32 */ 126 127#include <X11/Xwinsock.h> 128#include <X11/Xwindows.h> 129#include <X11/Xw32defs.h> 130#undef close 131#define close closesocket 132#define ECONNREFUSED WSAECONNREFUSED 133#define EADDRINUSE WSAEADDRINUSE 134#define EPROTOTYPE WSAEPROTOTYPE 135#undef EWOULDBLOCK 136#define EWOULDBLOCK WSAEWOULDBLOCK 137#define EINPROGRESS WSAEINPROGRESS 138#undef EINTR 139#define EINTR WSAEINTR 140#define X_INCLUDE_NETDB_H 141#define XOS_USE_MTSAFE_NETDBAPI 142#include <X11/Xos_r.h> 143#endif /* WIN32 */ 144 145#if defined(SO_DONTLINGER) && defined(SO_LINGER) 146#undef SO_DONTLINGER 147#endif 148 149/* others don't need this */ 150#define SocketInitOnce() /**/ 151 152#ifdef linux 153#define HAVE_ABSTRACT_SOCKETS 154#endif 155 156#define MIN_BACKLOG 128 157#ifdef SOMAXCONN 158#if SOMAXCONN > MIN_BACKLOG 159#define BACKLOG SOMAXCONN 160#endif 161#endif 162#ifndef BACKLOG 163#define BACKLOG MIN_BACKLOG 164#endif 165 166/* 167 * This is the Socket implementation of the X Transport service layer 168 * 169 * This file contains the implementation for both the UNIX and INET domains, 170 * and can be built for either one, or both. 171 * 172 */ 173 174typedef struct _Sockettrans2dev { 175 const char *transname; 176 int family; 177 int devcotsname; 178 int devcltsname; 179 int protocol; 180} Sockettrans2dev; 181 182static Sockettrans2dev Sockettrans2devtab[] = { 183#ifdef TCPCONN 184 {"inet",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, 185#if !defined(IPv6) || !defined(AF_INET6) 186 {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, 187#else /* IPv6 */ 188 {"tcp",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0}, 189 {"tcp",AF_INET,SOCK_STREAM,SOCK_DGRAM,0}, /* fallback */ 190 {"inet6",AF_INET6,SOCK_STREAM,SOCK_DGRAM,0}, 191#endif 192#endif /* TCPCONN */ 193#ifdef UNIXCONN 194 {"unix",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0}, 195#if !defined(LOCALCONN) 196 {"local",AF_UNIX,SOCK_STREAM,SOCK_DGRAM,0}, 197#endif /* !LOCALCONN */ 198#endif /* UNIXCONN */ 199}; 200 201#define NUMSOCKETFAMILIES (sizeof(Sockettrans2devtab)/sizeof(Sockettrans2dev)) 202 203#ifdef TCPCONN 204static int TRANS(SocketINETClose) (XtransConnInfo ciptr); 205#endif 206 207#ifdef UNIXCONN 208 209 210#if defined(X11_t) 211#define UNIX_PATH "/tmp/.X11-unix/X" 212#define UNIX_DIR "/tmp/.X11-unix" 213#endif /* X11_t */ 214#if defined(XIM_t) 215#define UNIX_PATH "/tmp/.XIM-unix/XIM" 216#define UNIX_DIR "/tmp/.XIM-unix" 217#endif /* XIM_t */ 218#if defined(FS_t) || defined(FONT_t) 219#define UNIX_PATH "/tmp/.font-unix/fs" 220#define UNIX_DIR "/tmp/.font-unix" 221#endif /* FS_t || FONT_t */ 222#if defined(ICE_t) 223#define UNIX_PATH "/tmp/.ICE-unix/" 224#define UNIX_DIR "/tmp/.ICE-unix" 225#endif /* ICE_t */ 226#if defined(TEST_t) 227#define UNIX_PATH "/tmp/.Test-unix/test" 228#define UNIX_DIR "/tmp/.Test-unix" 229#endif 230#if defined(LBXPROXY_t) 231#define UNIX_PATH "/tmp/.X11-unix/X" 232#define UNIX_DIR "/tmp/.X11-unix" 233#endif 234 235 236#endif /* UNIXCONN */ 237 238#define PORTBUFSIZE 32 239 240#ifndef MAXHOSTNAMELEN 241#define MAXHOSTNAMELEN 255 242#endif 243 244#if defined HAVE_SOCKLEN_T || (defined(IPv6) && defined(AF_INET6)) 245# define SOCKLEN_T socklen_t 246#elif defined(SVR4) || defined(__SVR4) || defined(__SCO__) 247# define SOCKLEN_T size_t 248#else 249# define SOCKLEN_T int 250#endif 251 252/* 253 * These are some utility function used by the real interface function below. 254 */ 255 256static int 257TRANS(SocketSelectFamily) (int first, const char *family) 258 259{ 260 int i; 261 262 prmsg (3,"SocketSelectFamily(%s)\n", family); 263 264 for (i = first + 1; i < NUMSOCKETFAMILIES;i++) 265 { 266 if (!strcmp (family, Sockettrans2devtab[i].transname)) 267 return i; 268 } 269 270 return (first == -1 ? -2 : -1); 271} 272 273 274/* 275 * This function gets the local address of the socket and stores it in the 276 * XtransConnInfo structure for the connection. 277 */ 278 279static int 280TRANS(SocketINETGetAddr) (XtransConnInfo ciptr) 281 282{ 283#if defined(IPv6) && defined(AF_INET6) 284 struct sockaddr_storage socknamev6; 285#else 286 struct sockaddr_in socknamev4; 287#endif 288 void *socknamePtr; 289 SOCKLEN_T namelen; 290 291 prmsg (3,"SocketINETGetAddr(%p)\n", ciptr); 292 293#if defined(IPv6) && defined(AF_INET6) 294 namelen = sizeof(socknamev6); 295 socknamePtr = &socknamev6; 296#else 297 namelen = sizeof(socknamev4); 298 socknamePtr = &socknamev4; 299#endif 300 301 bzero(socknamePtr, namelen); 302 303 if (getsockname (ciptr->fd,(struct sockaddr *) socknamePtr, 304 (void *)&namelen) < 0) 305 { 306#ifdef WIN32 307 errno = WSAGetLastError(); 308#endif 309 prmsg (1,"SocketINETGetAddr: getsockname() failed: %d\n", 310 EGET()); 311 return -1; 312 } 313 314 /* 315 * Everything looks good: fill in the XtransConnInfo structure. 316 */ 317 318 if ((ciptr->addr = malloc (namelen)) == NULL) 319 { 320 prmsg (1, 321 "SocketINETGetAddr: Can't allocate space for the addr\n"); 322 return -1; 323 } 324 325#if defined(IPv6) && defined(AF_INET6) 326 ciptr->family = ((struct sockaddr *)socknamePtr)->sa_family; 327#else 328 ciptr->family = socknamev4.sin_family; 329#endif 330 ciptr->addrlen = namelen; 331 memcpy (ciptr->addr, socknamePtr, ciptr->addrlen); 332 333 return 0; 334} 335 336 337/* 338 * This function gets the remote address of the socket and stores it in the 339 * XtransConnInfo structure for the connection. 340 */ 341 342static int 343TRANS(SocketINETGetPeerAddr) (XtransConnInfo ciptr) 344 345{ 346#if defined(IPv6) && defined(AF_INET6) 347 struct sockaddr_storage socknamev6; 348#endif 349 struct sockaddr_in socknamev4; 350 void *socknamePtr; 351 SOCKLEN_T namelen; 352 353#if defined(IPv6) && defined(AF_INET6) 354 if (ciptr->family == AF_INET6) 355 { 356 namelen = sizeof(socknamev6); 357 socknamePtr = &socknamev6; 358 } 359 else 360#endif 361 { 362 namelen = sizeof(socknamev4); 363 socknamePtr = &socknamev4; 364 } 365 366 bzero(socknamePtr, namelen); 367 368 prmsg (3,"SocketINETGetPeerAddr(%p)\n", ciptr); 369 370 if (getpeername (ciptr->fd, (struct sockaddr *) socknamePtr, 371 (void *)&namelen) < 0) 372 { 373#ifdef WIN32 374 errno = WSAGetLastError(); 375#endif 376 prmsg (1,"SocketINETGetPeerAddr: getpeername() failed: %d\n", 377 EGET()); 378 return -1; 379 } 380 381 /* 382 * Everything looks good: fill in the XtransConnInfo structure. 383 */ 384 385 if ((ciptr->peeraddr = malloc (namelen)) == NULL) 386 { 387 prmsg (1, 388 "SocketINETGetPeerAddr: Can't allocate space for the addr\n"); 389 return -1; 390 } 391 392 ciptr->peeraddrlen = namelen; 393 memcpy (ciptr->peeraddr, socknamePtr, ciptr->peeraddrlen); 394 395 return 0; 396} 397 398 399static XtransConnInfo 400TRANS(SocketOpen) (int i, int type) 401 402{ 403 XtransConnInfo ciptr; 404 405 prmsg (3,"SocketOpen(%d,%d)\n", i, type); 406 407 if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) 408 { 409 prmsg (1, "SocketOpen: malloc failed\n"); 410 return NULL; 411 } 412 413 if ((ciptr->fd = socket(Sockettrans2devtab[i].family, type, 414 Sockettrans2devtab[i].protocol)) < 0 415#ifndef WIN32 416#if (defined(X11_t) && !defined(USE_POLL)) || defined(FS_t) || defined(FONT_t) 417 || ciptr->fd >= sysconf(_SC_OPEN_MAX) 418#endif 419#endif 420 ) { 421#ifdef WIN32 422 errno = WSAGetLastError(); 423#endif 424 prmsg (2, "SocketOpen: socket() failed for %s\n", 425 Sockettrans2devtab[i].transname); 426 427 free (ciptr); 428 return NULL; 429 } 430 431#ifdef TCP_NODELAY 432 if (Sockettrans2devtab[i].family == AF_INET 433#if defined(IPv6) && defined(AF_INET6) 434 || Sockettrans2devtab[i].family == AF_INET6 435#endif 436 ) 437 { 438 /* 439 * turn off TCP coalescence for INET sockets 440 */ 441 442 int tmp = 1; 443 setsockopt (ciptr->fd, IPPROTO_TCP, TCP_NODELAY, 444 (char *) &tmp, sizeof (int)); 445 } 446#endif 447 448 /* 449 * Some systems provide a really small default buffer size for 450 * UNIX sockets. Bump it up a bit such that large transfers don't 451 * proceed at glacial speed. 452 */ 453#ifdef SO_SNDBUF 454 if (Sockettrans2devtab[i].family == AF_UNIX) 455 { 456 SOCKLEN_T len = sizeof (int); 457 int val; 458 459 if (getsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF, 460 (char *) &val, &len) == 0 && val < 64 * 1024) 461 { 462 val = 64 * 1024; 463 setsockopt (ciptr->fd, SOL_SOCKET, SO_SNDBUF, 464 (char *) &val, sizeof (int)); 465 } 466 } 467#endif 468 469 return ciptr; 470} 471 472 473#ifdef TRANS_REOPEN 474 475static XtransConnInfo 476TRANS(SocketReopen) (int i _X_UNUSED, int type, int fd, const char *port) 477 478{ 479 XtransConnInfo ciptr; 480 int portlen; 481 struct sockaddr *addr; 482 size_t addrlen; 483 484 prmsg (3,"SocketReopen(%d,%d,%s)\n", type, fd, port); 485 486 if (port == NULL) { 487 prmsg (1, "SocketReopen: port was null!\n"); 488 return NULL; 489 } 490 491 portlen = strlen(port) + 1; // include space for trailing null 492#ifdef SOCK_MAXADDRLEN 493 if (portlen < 0 || portlen > (SOCK_MAXADDRLEN + 2)) { 494 prmsg (1, "SocketReopen: invalid portlen %d\n", portlen); 495 return NULL; 496 } 497 if (portlen < 14) portlen = 14; 498#else 499 if (portlen < 0 || portlen > 14) { 500 prmsg (1, "SocketReopen: invalid portlen %d\n", portlen); 501 return NULL; 502 } 503#endif /*SOCK_MAXADDRLEN*/ 504 505 if ((ciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) 506 { 507 prmsg (1, "SocketReopen: malloc(ciptr) failed\n"); 508 return NULL; 509 } 510 511 ciptr->fd = fd; 512 513 addrlen = portlen + offsetof(struct sockaddr, sa_data); 514 if ((addr = calloc (1, addrlen)) == NULL) { 515 prmsg (1, "SocketReopen: malloc(addr) failed\n"); 516 free (ciptr); 517 return NULL; 518 } 519 ciptr->addr = (char *) addr; 520 ciptr->addrlen = addrlen; 521 522 if ((ciptr->peeraddr = calloc (1, addrlen)) == NULL) { 523 prmsg (1, "SocketReopen: malloc(portaddr) failed\n"); 524 free (addr); 525 free (ciptr); 526 return NULL; 527 } 528 ciptr->peeraddrlen = addrlen; 529 530 /* Initialize ciptr structure as if it were a normally-opened unix socket */ 531 ciptr->flags = TRANS_LOCAL | TRANS_NOUNLINK; 532#ifdef BSD44SOCKETS 533 addr->sa_len = addrlen; 534#endif 535 addr->sa_family = AF_UNIX; 536#ifdef HAS_STRLCPY 537 strlcpy(addr->sa_data, port, portlen); 538#else 539 strncpy(addr->sa_data, port, portlen); 540#endif 541 ciptr->family = AF_UNIX; 542 memcpy(ciptr->peeraddr, ciptr->addr, addrlen); 543 ciptr->port = rindex(addr->sa_data, ':'); 544 if (ciptr->port == NULL) { 545 if (is_numeric(addr->sa_data)) { 546 ciptr->port = addr->sa_data; 547 } 548 } else if (ciptr->port[0] == ':') { 549 ciptr->port++; 550 } 551 /* port should now point to portnum or NULL */ 552 return ciptr; 553} 554 555#endif /* TRANS_REOPEN */ 556 557 558/* 559 * These functions are the interface supplied in the Xtransport structure 560 */ 561 562#ifdef TRANS_CLIENT 563 564static XtransConnInfo 565TRANS(SocketOpenCOTSClientBase) (const char *transname, const char *protocol, 566 const char *host, const char *port, int previndex) 567{ 568 XtransConnInfo ciptr; 569 int i = previndex; 570 571 prmsg (2, "SocketOpenCOTSClient(%s,%s,%s)\n", 572 protocol, host, port); 573 574 SocketInitOnce(); 575 576 while ((i = TRANS(SocketSelectFamily) (i, transname)) >= 0) { 577 if ((ciptr = TRANS(SocketOpen) ( 578 i, Sockettrans2devtab[i].devcotsname)) != NULL) { 579 /* Save the index for later use */ 580 581 ciptr->index = i; 582 break; 583 } 584 } 585 if (i < 0) { 586 if (i == -1) 587 prmsg (1,"SocketOpenCOTSClient: Unable to open socket for %s\n", 588 transname); 589 else 590 prmsg (1,"SocketOpenCOTSClient: Unable to determine socket type for %s\n", 591 transname); 592 return NULL; 593 } 594 595 return ciptr; 596} 597 598static XtransConnInfo 599TRANS(SocketOpenCOTSClient) (Xtransport *thistrans, const char *protocol, 600 const char *host, const char *port) 601{ 602 return TRANS(SocketOpenCOTSClientBase)( 603 thistrans->TransName, protocol, host, port, -1); 604} 605 606 607#endif /* TRANS_CLIENT */ 608 609 610#ifdef TRANS_SERVER 611 612static XtransConnInfo 613TRANS(SocketOpenCOTSServer) (Xtransport *thistrans, const char *protocol, 614 const char *host, const char *port) 615 616{ 617 XtransConnInfo ciptr; 618 int i = -1; 619 620 prmsg (2,"SocketOpenCOTSServer(%s,%s,%s)\n", protocol, host, port); 621 622 SocketInitOnce(); 623 624 while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) { 625 if ((ciptr = TRANS(SocketOpen) ( 626 i, Sockettrans2devtab[i].devcotsname)) != NULL) 627 break; 628 } 629 if (i < 0) { 630 if (i == -1) 631 prmsg (1,"SocketOpenCOTSServer: Unable to open socket for %s\n", 632 thistrans->TransName); 633 else 634 prmsg (1,"SocketOpenCOTSServer: Unable to determine socket type for %s\n", 635 thistrans->TransName); 636 return NULL; 637 } 638 639 /* 640 * Using this prevents the bind() check for an existing server listening 641 * on the same port, but it is required for other reasons. 642 */ 643#ifdef SO_REUSEADDR 644 645 /* 646 * SO_REUSEADDR only applied to AF_INET && AF_INET6 647 */ 648 649 if (Sockettrans2devtab[i].family == AF_INET 650#if defined(IPv6) && defined(AF_INET6) 651 || Sockettrans2devtab[i].family == AF_INET6 652#endif 653 ) 654 { 655 int one = 1; 656 setsockopt (ciptr->fd, SOL_SOCKET, SO_REUSEADDR, 657 (char *) &one, sizeof (int)); 658 } 659#endif 660#ifdef IPV6_V6ONLY 661 if (Sockettrans2devtab[i].family == AF_INET6) 662 { 663 int one = 1; 664 setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int)); 665 } 666#endif 667 /* Save the index for later use */ 668 669 ciptr->index = i; 670 671 return ciptr; 672} 673 674#endif /* TRANS_SERVER */ 675 676 677#ifdef TRANS_CLIENT 678 679static XtransConnInfo 680TRANS(SocketOpenCLTSClient) (Xtransport *thistrans, const char *protocol, 681 const char *host, const char *port) 682 683{ 684 XtransConnInfo ciptr; 685 int i = -1; 686 687 prmsg (2,"SocketOpenCLTSClient(%s,%s,%s)\n", protocol, host, port); 688 689 SocketInitOnce(); 690 691 while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) { 692 if ((ciptr = TRANS(SocketOpen) ( 693 i, Sockettrans2devtab[i].devcotsname)) != NULL) 694 break; 695 } 696 if (i < 0) { 697 if (i == -1) 698 prmsg (1,"SocketOpenCLTSClient: Unable to open socket for %s\n", 699 thistrans->TransName); 700 else 701 prmsg (1,"SocketOpenCLTSClient: Unable to determine socket type for %s\n", 702 thistrans->TransName); 703 return NULL; 704 } 705 706 /* Save the index for later use */ 707 708 ciptr->index = i; 709 710 return ciptr; 711} 712 713#endif /* TRANS_CLIENT */ 714 715 716#ifdef TRANS_SERVER 717 718static XtransConnInfo 719TRANS(SocketOpenCLTSServer) (Xtransport *thistrans, const char *protocol, 720 const char *host, const char *port) 721 722{ 723 XtransConnInfo ciptr; 724 int i = -1; 725 726 prmsg (2,"SocketOpenCLTSServer(%s,%s,%s)\n", protocol, host, port); 727 728 SocketInitOnce(); 729 730 while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) { 731 if ((ciptr = TRANS(SocketOpen) ( 732 i, Sockettrans2devtab[i].devcotsname)) != NULL) 733 break; 734 } 735 if (i < 0) { 736 if (i == -1) 737 prmsg (1,"SocketOpenCLTSServer: Unable to open socket for %s\n", 738 thistrans->TransName); 739 else 740 prmsg (1,"SocketOpenCLTSServer: Unable to determine socket type for %s\n", 741 thistrans->TransName); 742 return NULL; 743 } 744 745#ifdef IPV6_V6ONLY 746 if (Sockettrans2devtab[i].family == AF_INET6) 747 { 748 int one = 1; 749 setsockopt(ciptr->fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(int)); 750 } 751#endif 752 /* Save the index for later use */ 753 754 ciptr->index = i; 755 756 return ciptr; 757} 758 759#endif /* TRANS_SERVER */ 760 761 762#ifdef TRANS_REOPEN 763 764static XtransConnInfo 765TRANS(SocketReopenCOTSServer) (Xtransport *thistrans, int fd, const char *port) 766 767{ 768 XtransConnInfo ciptr; 769 int i = -1; 770 771 prmsg (2, 772 "SocketReopenCOTSServer(%d, %s)\n", fd, port); 773 774 SocketInitOnce(); 775 776 while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) { 777 if ((ciptr = TRANS(SocketReopen) ( 778 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL) 779 break; 780 } 781 if (i < 0) { 782 if (i == -1) 783 prmsg (1,"SocketReopenCOTSServer: Unable to open socket for %s\n", 784 thistrans->TransName); 785 else 786 prmsg (1,"SocketReopenCOTSServer: Unable to determine socket type for %s\n", 787 thistrans->TransName); 788 return NULL; 789 } 790 791 /* Save the index for later use */ 792 793 ciptr->index = i; 794 795 return ciptr; 796} 797 798static XtransConnInfo 799TRANS(SocketReopenCLTSServer) (Xtransport *thistrans, int fd, const char *port) 800 801{ 802 XtransConnInfo ciptr; 803 int i = -1; 804 805 prmsg (2, 806 "SocketReopenCLTSServer(%d, %s)\n", fd, port); 807 808 SocketInitOnce(); 809 810 while ((i = TRANS(SocketSelectFamily) (i, thistrans->TransName)) >= 0) { 811 if ((ciptr = TRANS(SocketReopen) ( 812 i, Sockettrans2devtab[i].devcotsname, fd, port)) != NULL) 813 break; 814 } 815 if (i < 0) { 816 if (i == -1) 817 prmsg (1,"SocketReopenCLTSServer: Unable to open socket for %s\n", 818 thistrans->TransName); 819 else 820 prmsg (1,"SocketReopenCLTSServer: Unable to determine socket type for %s\n", 821 thistrans->TransName); 822 return NULL; 823 } 824 825 /* Save the index for later use */ 826 827 ciptr->index = i; 828 829 return ciptr; 830} 831 832#endif /* TRANS_REOPEN */ 833 834 835static int 836TRANS(SocketSetOption) (XtransConnInfo ciptr, int option, int arg) 837 838{ 839 prmsg (2,"SocketSetOption(%d,%d,%d)\n", ciptr->fd, option, arg); 840 841 return -1; 842} 843 844#ifdef UNIXCONN 845static int 846set_sun_path(const char *port, const char *upath, char *path, int abstract) 847{ 848 struct sockaddr_un s; 849 int maxlen = sizeof(s.sun_path) - 1; 850 const char *at = ""; 851 852 if (!port || !*port || !path) 853 return -1; 854 855#ifdef HAVE_ABSTRACT_SOCKETS 856 if (port[0] == '@') 857 upath = ""; 858 else if (abstract) 859 at = "@"; 860#endif 861 862 if (*port == '/') /* a full pathname */ 863 upath = ""; 864 865 if (strlen(port) + strlen(upath) > maxlen) 866 return -1; 867 snprintf(path, sizeof(s.sun_path), "%s%s%s", at, upath, port); 868 return 0; 869} 870#endif 871 872#ifdef TRANS_SERVER 873 874static int 875TRANS(SocketCreateListener) (XtransConnInfo ciptr, 876 struct sockaddr *sockname, 877 int socknamelen, unsigned int flags) 878 879{ 880 SOCKLEN_T namelen = socknamelen; 881 int fd = ciptr->fd; 882 int retry; 883 884 prmsg (3, "SocketCreateListener(%p,%d)\n", ciptr, fd); 885 886 if (Sockettrans2devtab[ciptr->index].family == AF_INET 887#if defined(IPv6) && defined(AF_INET6) 888 || Sockettrans2devtab[ciptr->index].family == AF_INET6 889#endif 890 ) 891 retry = 20; 892 else 893 retry = 0; 894 895 while (bind (fd, (struct sockaddr *) sockname, namelen) < 0) 896 { 897 if (errno == EADDRINUSE) { 898 if (flags & ADDR_IN_USE_ALLOWED) 899 break; 900 else 901 return TRANS_ADDR_IN_USE; 902 } 903 904 if (retry-- == 0) { 905 prmsg (1, "SocketCreateListener: failed to bind listener\n"); 906 close (fd); 907 return TRANS_CREATE_LISTENER_FAILED; 908 } 909#ifdef SO_REUSEADDR 910 sleep (1); 911#else 912 sleep (10); 913#endif /* SO_REUSEDADDR */ 914 } 915 916 if (Sockettrans2devtab[ciptr->index].family == AF_INET 917#if defined(IPv6) && defined(AF_INET6) 918 || Sockettrans2devtab[ciptr->index].family == AF_INET6 919#endif 920 ) { 921#ifdef SO_DONTLINGER 922 setsockopt (fd, SOL_SOCKET, SO_DONTLINGER, (char *) NULL, 0); 923#else 924#ifdef SO_LINGER 925 { 926 static int linger[2] = { 0, 0 }; 927 setsockopt (fd, SOL_SOCKET, SO_LINGER, 928 (char *) linger, sizeof (linger)); 929 } 930#endif 931#endif 932} 933 934 if (listen (fd, BACKLOG) < 0) 935 { 936 prmsg (1, "SocketCreateListener: listen() failed\n"); 937 close (fd); 938 return TRANS_CREATE_LISTENER_FAILED; 939 } 940 941 /* Set a flag to indicate that this connection is a listener */ 942 943 ciptr->flags = 1 | (ciptr->flags & TRANS_KEEPFLAGS); 944 945 return 0; 946} 947 948#ifdef TCPCONN 949static int 950TRANS(SocketINETCreateListener) (XtransConnInfo ciptr, const char *port, 951 unsigned int flags) 952 953{ 954#if defined(IPv6) && defined(AF_INET6) 955 struct sockaddr_storage sockname; 956#else 957 struct sockaddr_in sockname; 958#endif 959 unsigned short sport; 960 SOCKLEN_T namelen = sizeof(sockname); 961 int status; 962 long tmpport; 963#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 964 _Xgetservbynameparams sparams; 965#endif 966 struct servent *servp; 967 968#ifdef X11_t 969 char portbuf[PORTBUFSIZE]; 970#endif 971 972 prmsg (2, "SocketINETCreateListener(%s)\n", port); 973 974#ifdef X11_t 975 /* 976 * X has a well known port, that is transport dependent. It is easier 977 * to handle it here, than try and come up with a transport independent 978 * representation that can be passed in and resolved the usual way. 979 * 980 * The port that is passed here is really a string containing the idisplay 981 * from ConnectDisplay(). 982 */ 983 984 if (is_numeric (port)) 985 { 986 /* fixup the server port address */ 987 tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10); 988 snprintf (portbuf, sizeof(portbuf), "%lu", tmpport); 989 port = portbuf; 990 } 991#endif 992 993 if (port && *port) 994 { 995 /* Check to see if the port string is just a number (handles X11) */ 996 997 if (!is_numeric (port)) 998 { 999 if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) 1000 { 1001 prmsg (1, 1002 "SocketINETCreateListener: Unable to get service for %s\n", 1003 port); 1004 return TRANS_CREATE_LISTENER_FAILED; 1005 } 1006 /* we trust getservbyname to return a valid number */ 1007 sport = servp->s_port; 1008 } 1009 else 1010 { 1011 tmpport = strtol (port, (char**)NULL, 10); 1012 /* 1013 * check that somehow the port address isn't negative or in 1014 * the range of reserved port addresses. This can happen and 1015 * be very bad if the server is suid-root and the user does 1016 * something (dumb) like `X :60049`. 1017 */ 1018 if (tmpport < 1024 || tmpport > USHRT_MAX) 1019 return TRANS_CREATE_LISTENER_FAILED; 1020 1021 sport = (unsigned short) tmpport; 1022 } 1023 } 1024 else 1025 sport = 0; 1026 1027 bzero(&sockname, sizeof(sockname)); 1028#if defined(IPv6) && defined(AF_INET6) 1029 if (Sockettrans2devtab[ciptr->index].family == AF_INET) { 1030 namelen = sizeof (struct sockaddr_in); 1031#ifdef BSD44SOCKETS 1032 ((struct sockaddr_in *)&sockname)->sin_len = namelen; 1033#endif 1034 ((struct sockaddr_in *)&sockname)->sin_family = AF_INET; 1035 ((struct sockaddr_in *)&sockname)->sin_port = htons(sport); 1036 ((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY); 1037 } else { 1038 namelen = sizeof (struct sockaddr_in6); 1039#ifdef SIN6_LEN 1040 ((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname); 1041#endif 1042 ((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6; 1043 ((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport); 1044 ((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any; 1045 } 1046#else 1047#ifdef BSD44SOCKETS 1048 sockname.sin_len = sizeof (sockname); 1049#endif 1050 sockname.sin_family = AF_INET; 1051 sockname.sin_port = htons (sport); 1052 sockname.sin_addr.s_addr = htonl (INADDR_ANY); 1053#endif 1054 1055 if ((status = TRANS(SocketCreateListener) (ciptr, 1056 (struct sockaddr *) &sockname, namelen, flags)) < 0) 1057 { 1058 prmsg (1, 1059 "SocketINETCreateListener: ...SocketCreateListener() failed\n"); 1060 return status; 1061 } 1062 1063 if (TRANS(SocketINETGetAddr) (ciptr) < 0) 1064 { 1065 prmsg (1, 1066 "SocketINETCreateListener: ...SocketINETGetAddr() failed\n"); 1067 return TRANS_CREATE_LISTENER_FAILED; 1068 } 1069 1070 return 0; 1071} 1072 1073#endif /* TCPCONN */ 1074 1075 1076#ifdef UNIXCONN 1077 1078static int 1079TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, const char *port, 1080 unsigned int flags) 1081 1082{ 1083 struct sockaddr_un sockname; 1084 int namelen; 1085 int oldUmask; 1086 int status; 1087 unsigned int mode; 1088 char tmpport[108]; 1089 1090 int abstract = 0; 1091#ifdef HAVE_ABSTRACT_SOCKETS 1092 abstract = ciptr->transptr->flags & TRANS_ABSTRACT; 1093#endif 1094 1095 prmsg (2, "SocketUNIXCreateListener(%s)\n", 1096 port ? port : "NULL"); 1097 1098 /* Make sure the directory is created */ 1099 1100 oldUmask = umask (0); 1101 1102#ifdef UNIX_DIR 1103#ifdef HAS_STICKY_DIR_BIT 1104 mode = 01777; 1105#else 1106 mode = 0777; 1107#endif 1108 if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) { 1109 prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n", 1110 UNIX_DIR, errno); 1111 (void) umask (oldUmask); 1112 return TRANS_CREATE_LISTENER_FAILED; 1113 } 1114#endif 1115 1116 memset(&sockname, 0, sizeof(sockname)); 1117 sockname.sun_family = AF_UNIX; 1118 1119 if (!(port && *port)) { 1120 snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid()); 1121 port = tmpport; 1122 } 1123 if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) { 1124 prmsg (1, "SocketUNIXCreateListener: path too long\n"); 1125 return TRANS_CREATE_LISTENER_FAILED; 1126 } 1127 1128#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__)) 1129 sockname.sun_len = strlen(sockname.sun_path); 1130#endif 1131 1132#if defined(BSD44SOCKETS) || defined(SUN_LEN) 1133 namelen = SUN_LEN(&sockname); 1134#else 1135 namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path); 1136#endif 1137 1138 if (abstract) { 1139 sockname.sun_path[0] = '\0'; 1140 namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]); 1141 } 1142 else 1143 unlink (sockname.sun_path); 1144 1145 if ((status = TRANS(SocketCreateListener) (ciptr, 1146 (struct sockaddr *) &sockname, namelen, flags)) < 0) 1147 { 1148 prmsg (1, 1149 "SocketUNIXCreateListener: ...SocketCreateListener() failed\n"); 1150 (void) umask (oldUmask); 1151 return status; 1152 } 1153 1154 /* 1155 * Now that the listener is esablished, create the addr info for 1156 * this connection. getpeername() doesn't work for UNIX Domain Sockets 1157 * on some systems (hpux at least), so we will just do it manually, instead 1158 * of calling something like TRANS(SocketUNIXGetAddr). 1159 */ 1160 1161 namelen = sizeof (sockname); /* this will always make it the same size */ 1162 1163 if ((ciptr->addr = malloc (namelen)) == NULL) 1164 { 1165 prmsg (1, 1166 "SocketUNIXCreateListener: Can't allocate space for the addr\n"); 1167 (void) umask (oldUmask); 1168 return TRANS_CREATE_LISTENER_FAILED; 1169 } 1170 1171 if (abstract) 1172 sockname.sun_path[0] = '@'; 1173 1174 ciptr->family = sockname.sun_family; 1175 ciptr->addrlen = namelen; 1176 memcpy (ciptr->addr, &sockname, ciptr->addrlen); 1177 1178 (void) umask (oldUmask); 1179 1180 return 0; 1181} 1182 1183 1184static int 1185TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr) 1186 1187{ 1188 /* 1189 * See if the unix domain socket has disappeared. If it has, recreate it. 1190 */ 1191 1192 struct sockaddr_un *unsock = (struct sockaddr_un *) ciptr->addr; 1193 struct stat statb; 1194 int status = TRANS_RESET_NOOP; 1195 unsigned int mode; 1196 int abstract = 0; 1197#ifdef HAVE_ABSTRACT_SOCKETS 1198 abstract = ciptr->transptr->flags & TRANS_ABSTRACT; 1199#endif 1200 1201 prmsg (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd); 1202 1203 if (!abstract && ( 1204 stat (unsock->sun_path, &statb) == -1 || 1205 ((statb.st_mode & S_IFMT) != 1206#if defined(NCR) || defined(SCO325) || !defined(S_IFSOCK) 1207 S_IFIFO 1208#else 1209 S_IFSOCK 1210#endif 1211 ))) 1212 { 1213 int oldUmask = umask (0); 1214 1215#ifdef UNIX_DIR 1216#ifdef HAS_STICKY_DIR_BIT 1217 mode = 01777; 1218#else 1219 mode = 0777; 1220#endif 1221 if (trans_mkdir(UNIX_DIR, mode) == -1) { 1222 prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n", 1223 UNIX_DIR, errno); 1224 (void) umask (oldUmask); 1225 return TRANS_RESET_FAILURE; 1226 } 1227#endif 1228 1229 close (ciptr->fd); 1230 unlink (unsock->sun_path); 1231 1232 if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) 1233 { 1234 TRANS(FreeConnInfo) (ciptr); 1235 (void) umask (oldUmask); 1236 return TRANS_RESET_FAILURE; 1237 } 1238 1239 if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0) 1240 { 1241 close (ciptr->fd); 1242 TRANS(FreeConnInfo) (ciptr); 1243 return TRANS_RESET_FAILURE; 1244 } 1245 1246 if (listen (ciptr->fd, BACKLOG) < 0) 1247 { 1248 close (ciptr->fd); 1249 TRANS(FreeConnInfo) (ciptr); 1250 (void) umask (oldUmask); 1251 return TRANS_RESET_FAILURE; 1252 } 1253 1254 umask (oldUmask); 1255 1256 status = TRANS_RESET_NEW_FD; 1257 } 1258 1259 return status; 1260} 1261 1262#endif /* UNIXCONN */ 1263 1264 1265#ifdef TCPCONN 1266 1267static XtransConnInfo 1268TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status) 1269 1270{ 1271 XtransConnInfo newciptr; 1272 struct sockaddr_in sockname; 1273 SOCKLEN_T namelen = sizeof(sockname); 1274 1275 prmsg (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd); 1276 1277 if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) 1278 { 1279 prmsg (1, "SocketINETAccept: malloc failed\n"); 1280 *status = TRANS_ACCEPT_BAD_MALLOC; 1281 return NULL; 1282 } 1283 1284 if ((newciptr->fd = accept (ciptr->fd, 1285 (struct sockaddr *) &sockname, (void *)&namelen)) < 0) 1286 { 1287#ifdef WIN32 1288 errno = WSAGetLastError(); 1289#endif 1290 prmsg (1, "SocketINETAccept: accept() failed\n"); 1291 free (newciptr); 1292 *status = TRANS_ACCEPT_FAILED; 1293 return NULL; 1294 } 1295 1296#ifdef TCP_NODELAY 1297 { 1298 /* 1299 * turn off TCP coalescence for INET sockets 1300 */ 1301 1302 int tmp = 1; 1303 setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY, 1304 (char *) &tmp, sizeof (int)); 1305 } 1306#endif 1307 1308 /* 1309 * Get this address again because the transport may give a more 1310 * specific address now that a connection is established. 1311 */ 1312 1313 if (TRANS(SocketINETGetAddr) (newciptr) < 0) 1314 { 1315 prmsg (1, 1316 "SocketINETAccept: ...SocketINETGetAddr() failed:\n"); 1317 close (newciptr->fd); 1318 free (newciptr); 1319 *status = TRANS_ACCEPT_MISC_ERROR; 1320 return NULL; 1321 } 1322 1323 if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0) 1324 { 1325 prmsg (1, 1326 "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n"); 1327 close (newciptr->fd); 1328 if (newciptr->addr) free (newciptr->addr); 1329 free (newciptr); 1330 *status = TRANS_ACCEPT_MISC_ERROR; 1331 return NULL; 1332 } 1333 1334 *status = 0; 1335 1336 return newciptr; 1337} 1338 1339#endif /* TCPCONN */ 1340 1341 1342#ifdef UNIXCONN 1343static XtransConnInfo 1344TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) 1345 1346{ 1347 XtransConnInfo newciptr; 1348 struct sockaddr_un sockname; 1349 SOCKLEN_T namelen = sizeof sockname; 1350 1351 prmsg (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd); 1352 1353 if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) 1354 { 1355 prmsg (1, "SocketUNIXAccept: malloc() failed\n"); 1356 *status = TRANS_ACCEPT_BAD_MALLOC; 1357 return NULL; 1358 } 1359 1360 if ((newciptr->fd = accept (ciptr->fd, 1361 (struct sockaddr *) &sockname, (void *)&namelen)) < 0) 1362 { 1363 prmsg (1, "SocketUNIXAccept: accept() failed\n"); 1364 free (newciptr); 1365 *status = TRANS_ACCEPT_FAILED; 1366 return NULL; 1367 } 1368 1369 ciptr->addrlen = namelen; 1370 /* 1371 * Get the socket name and the peer name from the listener socket, 1372 * since this is unix domain. 1373 */ 1374 1375 if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL) 1376 { 1377 prmsg (1, 1378 "SocketUNIXAccept: Can't allocate space for the addr\n"); 1379 close (newciptr->fd); 1380 free (newciptr); 1381 *status = TRANS_ACCEPT_BAD_MALLOC; 1382 return NULL; 1383 } 1384 1385 /* 1386 * if the socket is abstract, we already modified the address to have a 1387 * @ instead of the initial NUL, so no need to do that again here. 1388 */ 1389 1390 newciptr->addrlen = ciptr->addrlen; 1391 memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen); 1392 1393 if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL) 1394 { 1395 prmsg (1, 1396 "SocketUNIXAccept: Can't allocate space for the addr\n"); 1397 close (newciptr->fd); 1398 if (newciptr->addr) free (newciptr->addr); 1399 free (newciptr); 1400 *status = TRANS_ACCEPT_BAD_MALLOC; 1401 return NULL; 1402 } 1403 1404 newciptr->peeraddrlen = ciptr->addrlen; 1405 memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen); 1406 1407 newciptr->family = AF_UNIX; 1408 1409 *status = 0; 1410 1411 return newciptr; 1412} 1413 1414#endif /* UNIXCONN */ 1415 1416#endif /* TRANS_SERVER */ 1417 1418 1419#ifdef TRANS_CLIENT 1420 1421#ifdef TCPCONN 1422 1423#if defined(IPv6) && defined(AF_INET6) 1424struct addrlist { 1425 struct addrinfo * addr; 1426 struct addrinfo * firstaddr; 1427 char port[PORTBUFSIZE]; 1428 char host[MAXHOSTNAMELEN]; 1429}; 1430static struct addrlist *addrlist = NULL; 1431#endif 1432 1433 1434static int 1435TRANS(SocketINETConnect) (XtransConnInfo ciptr, 1436 const char *host, const char *port) 1437 1438{ 1439 struct sockaddr * socketaddr = NULL; 1440 int socketaddrlen = 0; 1441 int res; 1442#if defined(IPv6) && defined(AF_INET6) 1443 struct addrinfo hints; 1444 char ntopbuf[INET6_ADDRSTRLEN]; 1445 int resetonce = 0; 1446#else 1447 struct sockaddr_in sockname; 1448 struct hostent *hostp; 1449 struct servent *servp; 1450 unsigned long tmpaddr; 1451#endif 1452#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1453 _Xgethostbynameparams hparams; 1454 _Xgetservbynameparams sparams; 1455#endif 1456#ifdef X11_t 1457 char portbuf[PORTBUFSIZE]; 1458#endif 1459 1460 char hostnamebuf[256]; /* tmp space */ 1461 1462 prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port); 1463 1464 if (!host) 1465 { 1466 hostnamebuf[0] = '\0'; 1467 (void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf); 1468 host = hostnamebuf; 1469 } 1470 1471#ifdef X11_t 1472 /* 1473 * X has a well known port, that is transport dependent. It is easier 1474 * to handle it here, than try and come up with a transport independent 1475 * representation that can be passed in and resolved the usual way. 1476 * 1477 * The port that is passed here is really a string containing the idisplay 1478 * from ConnectDisplay(). 1479 */ 1480 1481 if (is_numeric (port)) 1482 { 1483 long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10); 1484 snprintf (portbuf, sizeof(portbuf), "%lu", tmpport); 1485 port = portbuf; 1486 } 1487#endif 1488 1489#if defined(IPv6) && defined(AF_INET6) 1490 { 1491 if (addrlist != NULL) { 1492 if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) { 1493 if (addrlist->firstaddr) 1494 freeaddrinfo(addrlist->firstaddr); 1495 addrlist->firstaddr = NULL; 1496 } 1497 } else { 1498 addrlist = malloc(sizeof(struct addrlist)); 1499 addrlist->firstaddr = NULL; 1500 } 1501 1502 if (addrlist->firstaddr == NULL) { 1503 strncpy(addrlist->port, port, sizeof(addrlist->port)); 1504 addrlist->port[sizeof(addrlist->port) - 1] = '\0'; 1505 strncpy(addrlist->host, host, sizeof(addrlist->host)); 1506 addrlist->host[sizeof(addrlist->host) - 1] = '\0'; 1507 1508 bzero(&hints,sizeof(hints)); 1509 hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname; 1510 1511 res = getaddrinfo(host,port,&hints,&addrlist->firstaddr); 1512 if (res != 0) { 1513 prmsg (1, "SocketINETConnect() can't get address " 1514 "for %s:%s: %s\n", host, port, gai_strerror(res)); 1515 ESET(EINVAL); 1516 return TRANS_CONNECT_FAILED; 1517 } 1518 for (res = 0, addrlist->addr = addrlist->firstaddr; 1519 addrlist->addr ; res++) { 1520 addrlist->addr = addrlist->addr->ai_next; 1521 } 1522 prmsg(4,"Got New Address list with %d addresses\n", res); 1523 res = 0; 1524 addrlist->addr = NULL; 1525 } 1526 1527 while (socketaddr == NULL) { 1528 if (addrlist->addr == NULL) { 1529 if (resetonce) { 1530 /* Already checked entire list - no usable addresses */ 1531 prmsg (1, "SocketINETConnect() no usable address " 1532 "for %s:%s\n", host, port); 1533 return TRANS_CONNECT_FAILED; 1534 } else { 1535 /* Go back to beginning of list */ 1536 resetonce = 1; 1537 addrlist->addr = addrlist->firstaddr; 1538 } 1539 } 1540 1541 socketaddr = addrlist->addr->ai_addr; 1542 socketaddrlen = addrlist->addr->ai_addrlen; 1543 1544 if (addrlist->addr->ai_family == AF_INET) { 1545 struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr; 1546 1547 prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n", 1548 inet_ntop(addrlist->addr->ai_family,&sin->sin_addr, 1549 ntopbuf,sizeof(ntopbuf))); 1550 1551 prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n", 1552 ntohs(sin->sin_port)); 1553 1554 if (Sockettrans2devtab[ciptr->index].family == AF_INET6) { 1555 if (strcmp(Sockettrans2devtab[ciptr->index].transname, 1556 "tcp") == 0) { 1557 XtransConnInfo newciptr; 1558 1559 /* 1560 * Our socket is an IPv6 socket, but the address is 1561 * IPv4. Close it and get an IPv4 socket. This is 1562 * needed for IPv4 connections to work on platforms 1563 * that don't allow IPv4 over IPv6 sockets. 1564 */ 1565 TRANS(SocketINETClose)(ciptr); 1566 newciptr = TRANS(SocketOpenCOTSClientBase)( 1567 "tcp", "tcp", host, port, ciptr->index); 1568 if (newciptr) 1569 ciptr->fd = newciptr->fd; 1570 if (!newciptr || 1571 Sockettrans2devtab[newciptr->index].family != 1572 AF_INET) { 1573 socketaddr = NULL; 1574 prmsg (4,"SocketINETConnect() Cannot get IPv4 " 1575 " socketfor IPv4 address\n"); 1576 } 1577 if (newciptr) 1578 free(newciptr); 1579 } else { 1580 socketaddr = NULL; 1581 prmsg (4,"SocketINETConnect Skipping IPv4 address\n"); 1582 } 1583 } 1584 } else if (addrlist->addr->ai_family == AF_INET6) { 1585 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr; 1586 1587 prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n", 1588 inet_ntop(addrlist->addr->ai_family, 1589 &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf))); 1590 prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n", 1591 ntohs(sin6->sin6_port)); 1592 1593 if (Sockettrans2devtab[ciptr->index].family == AF_INET) { 1594 if (strcmp(Sockettrans2devtab[ciptr->index].transname, 1595 "tcp") == 0) { 1596 XtransConnInfo newciptr; 1597 1598 /* 1599 * Close the IPv4 socket and try to open an IPv6 socket. 1600 */ 1601 TRANS(SocketINETClose)(ciptr); 1602 newciptr = TRANS(SocketOpenCOTSClientBase)( 1603 "tcp", "tcp", host, port, -1); 1604 if (newciptr) 1605 ciptr->fd = newciptr->fd; 1606 if (!newciptr || 1607 Sockettrans2devtab[newciptr->index].family != 1608 AF_INET6) { 1609 socketaddr = NULL; 1610 prmsg (4,"SocketINETConnect() Cannot get IPv6 " 1611 "socket for IPv6 address\n"); 1612 } 1613 if (newciptr) 1614 free(newciptr); 1615 } 1616 else 1617 { 1618 socketaddr = NULL; 1619 prmsg (4,"SocketINETConnect() Skipping IPv6 address\n"); 1620 } 1621 } 1622 } else { 1623 socketaddr = NULL; /* Unsupported address type */ 1624 } 1625 if (socketaddr == NULL) { 1626 addrlist->addr = addrlist->addr->ai_next; 1627 } 1628 } 1629 } 1630#else 1631 { 1632 /* 1633 * Build the socket name. 1634 */ 1635 1636#ifdef BSD44SOCKETS 1637 sockname.sin_len = sizeof (struct sockaddr_in); 1638#endif 1639 sockname.sin_family = AF_INET; 1640 1641 /* 1642 * fill in sin_addr 1643 */ 1644 1645#ifndef INADDR_NONE 1646#define INADDR_NONE ((in_addr_t) 0xffffffff) 1647#endif 1648 1649 /* check for ww.xx.yy.zz host string */ 1650 1651 if (isascii (host[0]) && isdigit (host[0])) { 1652 tmpaddr = inet_addr (host); /* returns network byte order */ 1653 } else { 1654 tmpaddr = INADDR_NONE; 1655 } 1656 1657 prmsg (4,"SocketINETConnect() inet_addr(%s) = %lx\n", host, tmpaddr); 1658 1659 if (tmpaddr == INADDR_NONE) { 1660 if ((hostp = _XGethostbyname(host,hparams)) == NULL) { 1661 prmsg (1,"SocketINETConnect: Can't get address for %s\n", 1662 host); 1663 ESET(EINVAL); 1664 return TRANS_CONNECT_FAILED; 1665 } 1666 if (hostp->h_addrtype != AF_INET) { /* is IP host? */ 1667 prmsg (1,"SocketINETConnect: not INET host%s\n", host); 1668 ESET(EPROTOTYPE); 1669 return TRANS_CONNECT_FAILED; 1670 } 1671 1672 memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr, 1673 sizeof (sockname.sin_addr)); 1674 1675 } else { 1676 sockname.sin_addr.s_addr = tmpaddr; 1677 } 1678 1679 /* 1680 * fill in sin_port 1681 */ 1682 1683 /* Check for number in the port string */ 1684 1685 if (!is_numeric (port)) { 1686 if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) { 1687 prmsg (1,"SocketINETConnect: can't get service for %s\n", 1688 port); 1689 return TRANS_CONNECT_FAILED; 1690 } 1691 sockname.sin_port = htons (servp->s_port); 1692 } else { 1693 long tmpport = strtol (port, (char**)NULL, 10); 1694 if (tmpport < 1024 || tmpport > USHRT_MAX) 1695 return TRANS_CONNECT_FAILED; 1696 sockname.sin_port = htons (((unsigned short) tmpport)); 1697 } 1698 1699 prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n", 1700 ntohs(sockname.sin_port)); 1701 socketaddr = (struct sockaddr *) &sockname; 1702 socketaddrlen = sizeof(sockname); 1703 } 1704#endif 1705 1706 /* 1707 * Turn on socket keepalive so the client process will eventually 1708 * be notified with a SIGPIPE signal if the display server fails 1709 * to respond to a periodic transmission of messages 1710 * on the connected socket. 1711 * This is useful to avoid hung application processes when the 1712 * processes are not spawned from the xdm session and 1713 * the display server terminates abnormally. 1714 * (Someone turned off the power switch.) 1715 */ 1716 1717 { 1718 int tmp = 1; 1719 setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE, 1720 (char *) &tmp, sizeof (int)); 1721 } 1722 1723 /* 1724 * Do the connect() 1725 */ 1726 1727 if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0) 1728 { 1729#ifdef WIN32 1730 int olderrno = WSAGetLastError(); 1731#else 1732 int olderrno = errno; 1733#endif 1734 1735 /* 1736 * If the error was ECONNREFUSED, the server may be overloaded 1737 * and we should try again. 1738 * 1739 * If the error was EWOULDBLOCK or EINPROGRESS then the socket 1740 * was non-blocking and we should poll using select 1741 * 1742 * If the error was EINTR, the connect was interrupted and we 1743 * should try again. 1744 * 1745 * If multiple addresses are found for a host then we should 1746 * try to connect again with a different address for a larger 1747 * number of errors that made us quit before, since those 1748 * could be caused by trying to use an IPv6 address to contact 1749 * a machine with an IPv4-only server or other reasons that 1750 * only affect one of a set of addresses. 1751 */ 1752 1753 if (olderrno == ECONNREFUSED || olderrno == EINTR 1754#if defined(IPv6) && defined(AF_INET6) 1755 || (((addrlist->addr->ai_next != NULL) || 1756 (addrlist->addr != addrlist->firstaddr)) && 1757 (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT || 1758 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT 1759#if defined(EHOSTDOWN) 1760 || olderrno == EHOSTDOWN 1761#endif 1762 )) 1763#endif 1764 ) 1765 res = TRANS_TRY_CONNECT_AGAIN; 1766 else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS) 1767 res = TRANS_IN_PROGRESS; 1768 else 1769 { 1770 prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n", 1771 olderrno); 1772 1773 res = TRANS_CONNECT_FAILED; 1774 } 1775 } else { 1776 res = 0; 1777 1778 1779 /* 1780 * Sync up the address fields of ciptr. 1781 */ 1782 1783 if (TRANS(SocketINETGetAddr) (ciptr) < 0) 1784 { 1785 prmsg (1, 1786 "SocketINETConnect: ...SocketINETGetAddr() failed:\n"); 1787 res = TRANS_CONNECT_FAILED; 1788 } 1789 1790 else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0) 1791 { 1792 prmsg (1, 1793 "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n"); 1794 res = TRANS_CONNECT_FAILED; 1795 } 1796 } 1797 1798#if defined(IPv6) && defined(AF_INET6) 1799 if (res != 0) { 1800 addrlist->addr = addrlist->addr->ai_next; 1801 } 1802#endif 1803 1804 return res; 1805} 1806 1807#endif /* TCPCONN */ 1808 1809 1810 1811#ifdef UNIXCONN 1812 1813/* 1814 * Make sure 'host' is really local. 1815 */ 1816 1817static int 1818UnixHostReallyLocal (const char *host) 1819 1820{ 1821 char hostnamebuf[256]; 1822 1823 TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf)); 1824 1825 if (strcmp (hostnamebuf, host) == 0) 1826 { 1827 return (1); 1828 } else { 1829#if defined(IPv6) && defined(AF_INET6) 1830 struct addrinfo *localhostaddr; 1831 struct addrinfo *otherhostaddr; 1832 struct addrinfo *i, *j; 1833 int equiv = 0; 1834 1835 if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0) 1836 return 0; 1837 if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) { 1838 freeaddrinfo(localhostaddr); 1839 return 0; 1840 } 1841 1842 for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) { 1843 for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) { 1844 if (i->ai_family == j->ai_family) { 1845 if (i->ai_family == AF_INET) { 1846 struct sockaddr_in *sinA 1847 = (struct sockaddr_in *) i->ai_addr; 1848 struct sockaddr_in *sinB 1849 = (struct sockaddr_in *) j->ai_addr; 1850 struct in_addr *A = &sinA->sin_addr; 1851 struct in_addr *B = &sinB->sin_addr; 1852 1853 if (memcmp(A,B,sizeof(struct in_addr)) == 0) { 1854 equiv = 1; 1855 } 1856 } else if (i->ai_family == AF_INET6) { 1857 struct sockaddr_in6 *sinA 1858 = (struct sockaddr_in6 *) i->ai_addr; 1859 struct sockaddr_in6 *sinB 1860 = (struct sockaddr_in6 *) j->ai_addr; 1861 struct in6_addr *A = &sinA->sin6_addr; 1862 struct in6_addr *B = &sinB->sin6_addr; 1863 1864 if (memcmp(A,B,sizeof(struct in6_addr)) == 0) { 1865 equiv = 1; 1866 } 1867 } 1868 } 1869 } 1870 } 1871 1872 freeaddrinfo(localhostaddr); 1873 freeaddrinfo(otherhostaddr); 1874 return equiv; 1875#else 1876 /* 1877 * A host may have more than one network address. If any of the 1878 * network addresses of 'host' (specified to the connect call) 1879 * match any of the network addresses of 'hostname' (determined 1880 * by TRANS(GetHostname)), then the two hostnames are equivalent, 1881 * and we know that 'host' is really a local host. 1882 */ 1883 char specified_local_addr_list[10][4]; 1884 int scount, equiv, i, j; 1885#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1886 _Xgethostbynameparams hparams; 1887#endif 1888 struct hostent *hostp; 1889 1890 if ((hostp = _XGethostbyname (host,hparams)) == NULL) 1891 return (0); 1892 1893 scount = 0; 1894 while (hostp->h_addr_list[scount] && scount <= 8) 1895 { 1896 /* 1897 * The 2nd call to gethostname() overrides the data 1898 * from the 1st call, so we must save the address list. 1899 */ 1900 1901 specified_local_addr_list[scount][0] = 1902 hostp->h_addr_list[scount][0]; 1903 specified_local_addr_list[scount][1] = 1904 hostp->h_addr_list[scount][1]; 1905 specified_local_addr_list[scount][2] = 1906 hostp->h_addr_list[scount][2]; 1907 specified_local_addr_list[scount][3] = 1908 hostp->h_addr_list[scount][3]; 1909 scount++; 1910 } 1911 if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL) 1912 return (0); 1913 1914 equiv = 0; 1915 i = 0; 1916 1917 while (i < scount && !equiv) 1918 { 1919 j = 0; 1920 1921 while (hostp->h_addr_list[j]) 1922 { 1923 if ((specified_local_addr_list[i][0] == 1924 hostp->h_addr_list[j][0]) && 1925 (specified_local_addr_list[i][1] == 1926 hostp->h_addr_list[j][1]) && 1927 (specified_local_addr_list[i][2] == 1928 hostp->h_addr_list[j][2]) && 1929 (specified_local_addr_list[i][3] == 1930 hostp->h_addr_list[j][3])) 1931 { 1932 /* They're equal, so we're done */ 1933 1934 equiv = 1; 1935 break; 1936 } 1937 1938 j++; 1939 } 1940 1941 i++; 1942 } 1943 return (equiv); 1944#endif 1945 } 1946} 1947 1948static int 1949TRANS(SocketUNIXConnect) (XtransConnInfo ciptr, 1950 const char *host, const char *port) 1951 1952{ 1953 struct sockaddr_un sockname; 1954 SOCKLEN_T namelen; 1955 1956 1957 int abstract = 0; 1958#ifdef HAVE_ABSTRACT_SOCKETS 1959 abstract = ciptr->transptr->flags & TRANS_ABSTRACT; 1960#endif 1961 1962 prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port); 1963 1964 /* 1965 * Make sure 'host' is really local. If not, we return failure. 1966 * The reason we make this check is because a process may advertise 1967 * a "local" network ID for which it can accept connections, but if 1968 * a process on a remote machine tries to connect to this network ID, 1969 * we know for sure it will fail. 1970 */ 1971 1972 if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host)) 1973 { 1974 prmsg (1, 1975 "SocketUNIXConnect: Cannot connect to non-local host %s\n", 1976 host); 1977 return TRANS_CONNECT_FAILED; 1978 } 1979 1980 1981 /* 1982 * Check the port. 1983 */ 1984 1985 if (!port || !*port) 1986 { 1987 prmsg (1,"SocketUNIXConnect: Missing port specification\n"); 1988 return TRANS_CONNECT_FAILED; 1989 } 1990 1991 /* 1992 * Build the socket name. 1993 */ 1994 1995 sockname.sun_family = AF_UNIX; 1996 1997 if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) { 1998 prmsg (1, "SocketUNIXConnect: path too long\n"); 1999 return TRANS_CONNECT_FAILED; 2000 } 2001 2002#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__)) 2003 sockname.sun_len = strlen (sockname.sun_path); 2004#endif 2005 2006#if defined(BSD44SOCKETS) || defined(SUN_LEN) 2007 namelen = SUN_LEN (&sockname); 2008#else 2009 namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path); 2010#endif 2011 2012 2013 2014 /* 2015 * Adjust the socket path if using abstract sockets. 2016 * Done here because otherwise all the strlen() calls above would fail. 2017 */ 2018 2019 if (abstract) { 2020 sockname.sun_path[0] = '\0'; 2021 } 2022 2023 /* 2024 * Do the connect() 2025 */ 2026 2027 if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0) 2028 { 2029 int olderrno = errno; 2030 int connected = 0; 2031 2032 if (!connected) 2033 { 2034 errno = olderrno; 2035 2036 /* 2037 * If the error was ENOENT, the server may be starting up; we used 2038 * to suggest to try again in this case with 2039 * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for 2040 * processes still referencing stale sockets in their environment. 2041 * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it 2042 * is suggested that higher level stacks handle retries on their 2043 * level when they face a slow starting server. 2044 * 2045 * If the error was EWOULDBLOCK or EINPROGRESS then the socket 2046 * was non-blocking and we should poll using select 2047 * 2048 * If the error was EINTR, the connect was interrupted and we 2049 * should try again. 2050 */ 2051 2052 if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS) 2053 return TRANS_IN_PROGRESS; 2054 else if (olderrno == EINTR) 2055 return TRANS_TRY_CONNECT_AGAIN; 2056 else if (olderrno == ENOENT || olderrno == ECONNREFUSED) { 2057 /* If opening as abstract socket failed, try again normally */ 2058 if (abstract) { 2059 ciptr->transptr->flags &= ~(TRANS_ABSTRACT); 2060 return TRANS_TRY_CONNECT_AGAIN; 2061 } else { 2062 return TRANS_CONNECT_FAILED; 2063 } 2064 } else { 2065 prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n", 2066 EGET()); 2067 2068 return TRANS_CONNECT_FAILED; 2069 } 2070 } 2071 } 2072 2073 /* 2074 * Get the socket name and the peer name from the connect socket, 2075 * since this is unix domain. 2076 */ 2077 2078 if ((ciptr->addr = malloc(namelen)) == NULL || 2079 (ciptr->peeraddr = malloc(namelen)) == NULL) 2080 { 2081 prmsg (1, 2082 "SocketUNIXCreateListener: Can't allocate space for the addr\n"); 2083 return TRANS_CONNECT_FAILED; 2084 } 2085 2086 if (abstract) 2087 sockname.sun_path[0] = '@'; 2088 2089 ciptr->family = AF_UNIX; 2090 ciptr->addrlen = namelen; 2091 ciptr->peeraddrlen = namelen; 2092 memcpy (ciptr->addr, &sockname, ciptr->addrlen); 2093 memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen); 2094 2095 return 0; 2096} 2097 2098#endif /* UNIXCONN */ 2099 2100#endif /* TRANS_CLIENT */ 2101 2102 2103static int 2104TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend) 2105 2106{ 2107 prmsg (2,"SocketBytesReadable(%p,%d,%p)\n", 2108 ciptr, ciptr->fd, pend); 2109#ifdef WIN32 2110 { 2111 int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend); 2112 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2113 return ret; 2114 } 2115#else 2116#if defined(__i386__) && defined(SYSV) && !defined(SCO325) 2117 return ioctl (ciptr->fd, I_NREAD, (char *) pend); 2118#else 2119 return ioctl (ciptr->fd, FIONREAD, (char *) pend); 2120#endif /* __i386__ && SYSV || _SEQUENT_ && _SOCKET_VERSION == 1 */ 2121#endif /* WIN32 */ 2122} 2123 2124#if XTRANS_SEND_FDS 2125 2126static void 2127appendFd(struct _XtransConnFd **prev, int fd, int do_close) 2128{ 2129 struct _XtransConnFd *cf, *new; 2130 2131 new = malloc (sizeof (struct _XtransConnFd)); 2132 if (!new) { 2133 /* XXX mark connection as broken */ 2134 close(fd); 2135 return; 2136 } 2137 new->next = 0; 2138 new->fd = fd; 2139 new->do_close = do_close; 2140 /* search to end of list */ 2141 for (; (cf = *prev); prev = &(cf->next)); 2142 *prev = new; 2143} 2144 2145static int 2146removeFd(struct _XtransConnFd **prev) 2147{ 2148 struct _XtransConnFd *cf; 2149 int fd; 2150 2151 if ((cf = *prev)) { 2152 *prev = cf->next; 2153 fd = cf->fd; 2154 free(cf); 2155 } else 2156 fd = -1; 2157 return fd; 2158} 2159 2160static void 2161discardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close) 2162{ 2163 struct _XtransConnFd *cf, *next; 2164 2165 for (cf = *prev; cf != upto; cf = next) { 2166 next = cf->next; 2167 if (do_close || cf->do_close) 2168 close(cf->fd); 2169 free(cf); 2170 } 2171 *prev = upto; 2172} 2173 2174static void 2175cleanupFds(XtransConnInfo ciptr) 2176{ 2177 /* Clean up the send list but don't close the fds */ 2178 discardFd(&ciptr->send_fds, NULL, 0); 2179 /* Clean up the recv list and *do* close the fds */ 2180 discardFd(&ciptr->recv_fds, NULL, 1); 2181} 2182 2183static int 2184nFd(struct _XtransConnFd **prev) 2185{ 2186 struct _XtransConnFd *cf; 2187 int n = 0; 2188 2189 for (cf = *prev; cf; cf = cf->next) 2190 n++; 2191 return n; 2192} 2193 2194static int 2195TRANS(SocketRecvFd) (XtransConnInfo ciptr) 2196{ 2197 prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd); 2198 return removeFd(&ciptr->recv_fds); 2199} 2200 2201static int 2202TRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close) 2203{ 2204 appendFd(&ciptr->send_fds, fd, do_close); 2205 return 0; 2206} 2207 2208static int 2209TRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr) 2210{ 2211 errno = EINVAL; 2212 return -1; 2213} 2214 2215static int 2216TRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close) 2217{ 2218 errno = EINVAL; 2219 return -1; 2220} 2221 2222#define MAX_FDS 128 2223 2224union fd_pass { 2225 struct cmsghdr cmsghdr; 2226 char buf[CMSG_SPACE(MAX_FDS * sizeof(int))]; 2227}; 2228 2229#endif /* XTRANS_SEND_FDS */ 2230 2231static int 2232TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size) 2233 2234{ 2235 prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size); 2236 2237#if defined(WIN32) 2238 { 2239 int ret = recv ((SOCKET)ciptr->fd, buf, size, 0); 2240#ifdef WIN32 2241 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2242#endif 2243 return ret; 2244 } 2245#else 2246#if XTRANS_SEND_FDS 2247 { 2248 struct iovec iov = { 2249 .iov_base = buf, 2250 .iov_len = size 2251 }; 2252 union fd_pass cmsgbuf; 2253 struct msghdr msg = { 2254 .msg_name = NULL, 2255 .msg_namelen = 0, 2256 .msg_iov = &iov, 2257 .msg_iovlen = 1, 2258 .msg_control = cmsgbuf.buf, 2259 .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int)) 2260 }; 2261 2262 size = recvmsg(ciptr->fd, &msg, 0); 2263 if (size >= 0) { 2264 struct cmsghdr *hdr; 2265 2266 for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { 2267 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { 2268 int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int); 2269 int i; 2270 int *fd = (int *) CMSG_DATA(hdr); 2271 2272 for (i = 0; i < nfd; i++) 2273 appendFd(&ciptr->recv_fds, fd[i], 0); 2274 } 2275 } 2276 } 2277 return size; 2278 } 2279#else 2280 return read(ciptr->fd, buf, size); 2281#endif /* XTRANS_SEND_FDS */ 2282#endif /* WIN32 */ 2283} 2284 2285static int 2286TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size) 2287 2288{ 2289 prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size); 2290 2291#if XTRANS_SEND_FDS 2292 { 2293 union fd_pass cmsgbuf; 2294 struct msghdr msg = { 2295 .msg_name = NULL, 2296 .msg_namelen = 0, 2297 .msg_iov = buf, 2298 .msg_iovlen = size, 2299 .msg_control = cmsgbuf.buf, 2300 .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int)) 2301 }; 2302 2303 size = recvmsg(ciptr->fd, &msg, 0); 2304 if (size >= 0) { 2305 struct cmsghdr *hdr; 2306 2307 for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { 2308 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { 2309 int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int); 2310 int i; 2311 int *fd = (int *) CMSG_DATA(hdr); 2312 2313 for (i = 0; i < nfd; i++) 2314 appendFd(&ciptr->recv_fds, fd[i], 0); 2315 } 2316 } 2317 } 2318 return size; 2319 } 2320#else 2321 return READV (ciptr, buf, size); 2322#endif 2323} 2324 2325 2326static int 2327TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size) 2328 2329{ 2330 prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size); 2331 2332#if XTRANS_SEND_FDS 2333 if (ciptr->send_fds) 2334 { 2335 union fd_pass cmsgbuf; 2336 int nfd = nFd(&ciptr->send_fds); 2337 struct _XtransConnFd *cf = ciptr->send_fds; 2338 struct msghdr msg = { 2339 .msg_name = NULL, 2340 .msg_namelen = 0, 2341 .msg_iov = buf, 2342 .msg_iovlen = size, 2343 .msg_control = cmsgbuf.buf, 2344 .msg_controllen = CMSG_LEN(nfd * sizeof(int)) 2345 }; 2346 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); 2347 int i; 2348 int *fds; 2349 2350 hdr->cmsg_len = msg.msg_controllen; 2351 hdr->cmsg_level = SOL_SOCKET; 2352 hdr->cmsg_type = SCM_RIGHTS; 2353 2354 fds = (int *) CMSG_DATA(hdr); 2355 /* Set up fds */ 2356 for (i = 0; i < nfd; i++) { 2357 fds[i] = cf->fd; 2358 cf = cf->next; 2359 } 2360 2361 i = sendmsg(ciptr->fd, &msg, 0); 2362 if (i > 0) 2363 discardFd(&ciptr->send_fds, cf, 0); 2364 return i; 2365 } 2366#endif 2367 return WRITEV (ciptr, buf, size); 2368} 2369 2370 2371static int 2372TRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size) 2373 2374{ 2375 prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size); 2376 2377#if defined(WIN32) 2378 { 2379 int ret = send ((SOCKET)ciptr->fd, buf, size, 0); 2380#ifdef WIN32 2381 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2382#endif 2383 return ret; 2384 } 2385#else 2386#if XTRANS_SEND_FDS 2387 if (ciptr->send_fds) 2388 { 2389 struct iovec iov; 2390 2391 iov.iov_base = buf; 2392 iov.iov_len = size; 2393 return TRANS(SocketWritev)(ciptr, &iov, 1); 2394 } 2395#endif /* XTRANS_SEND_FDS */ 2396 return write (ciptr->fd, buf, size); 2397#endif /* WIN32 */ 2398} 2399 2400static int 2401TRANS(SocketDisconnect) (XtransConnInfo ciptr) 2402 2403{ 2404 prmsg (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd); 2405 2406#ifdef WIN32 2407 { 2408 int ret = shutdown (ciptr->fd, 2); 2409 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2410 return ret; 2411 } 2412#else 2413 return shutdown (ciptr->fd, 2); /* disallow further sends and receives */ 2414#endif 2415} 2416 2417 2418#ifdef TCPCONN 2419static int 2420TRANS(SocketINETClose) (XtransConnInfo ciptr) 2421 2422{ 2423 prmsg (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd); 2424 2425#ifdef WIN32 2426 { 2427 int ret = close (ciptr->fd); 2428 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2429 return ret; 2430 } 2431#else 2432 return close (ciptr->fd); 2433#endif 2434} 2435 2436#endif /* TCPCONN */ 2437 2438 2439#ifdef UNIXCONN 2440static int 2441TRANS(SocketUNIXClose) (XtransConnInfo ciptr) 2442{ 2443 /* 2444 * If this is the server side, then once the socket is closed, 2445 * it must be unlinked to completely close it 2446 */ 2447 2448 struct sockaddr_un *sockname = (struct sockaddr_un *) ciptr->addr; 2449 int ret; 2450 2451 prmsg (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd); 2452 2453#if XTRANS_SEND_FDS 2454 cleanupFds(ciptr); 2455#endif 2456 ret = close(ciptr->fd); 2457 2458 if (ciptr->flags 2459 && sockname 2460 && sockname->sun_family == AF_UNIX 2461 && sockname->sun_path[0]) 2462 { 2463 if (!(ciptr->flags & TRANS_NOUNLINK 2464 || ciptr->transptr->flags & TRANS_ABSTRACT)) 2465 unlink (sockname->sun_path); 2466 } 2467 2468 return ret; 2469} 2470 2471static int 2472TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr) 2473 2474{ 2475 /* 2476 * Don't unlink path. 2477 */ 2478 2479 int ret; 2480 2481 prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n", 2482 ciptr, ciptr->fd); 2483 2484#if XTRANS_SEND_FDS 2485 cleanupFds(ciptr); 2486#endif 2487 ret = close(ciptr->fd); 2488 2489 return ret; 2490} 2491 2492#endif /* UNIXCONN */ 2493 2494 2495#ifdef TCPCONN 2496# ifdef TRANS_SERVER 2497static const char* tcp_nolisten[] = { 2498 "inet", 2499#if defined(IPv6) && defined(AF_INET6) 2500 "inet6", 2501#endif 2502 NULL 2503}; 2504# endif 2505 2506Xtransport TRANS(SocketTCPFuncs) = { 2507 /* Socket Interface */ 2508 "tcp", 2509 TRANS_ALIAS, 2510#ifdef TRANS_CLIENT 2511 TRANS(SocketOpenCOTSClient), 2512#endif /* TRANS_CLIENT */ 2513#ifdef TRANS_SERVER 2514 tcp_nolisten, 2515 TRANS(SocketOpenCOTSServer), 2516#endif /* TRANS_SERVER */ 2517#ifdef TRANS_CLIENT 2518 TRANS(SocketOpenCLTSClient), 2519#endif /* TRANS_CLIENT */ 2520#ifdef TRANS_SERVER 2521 TRANS(SocketOpenCLTSServer), 2522#endif /* TRANS_SERVER */ 2523#ifdef TRANS_REOPEN 2524 TRANS(SocketReopenCOTSServer), 2525 TRANS(SocketReopenCLTSServer), 2526#endif 2527 TRANS(SocketSetOption), 2528#ifdef TRANS_SERVER 2529 TRANS(SocketINETCreateListener), 2530 NULL, /* ResetListener */ 2531 TRANS(SocketINETAccept), 2532#endif /* TRANS_SERVER */ 2533#ifdef TRANS_CLIENT 2534 TRANS(SocketINETConnect), 2535#endif /* TRANS_CLIENT */ 2536 TRANS(SocketBytesReadable), 2537 TRANS(SocketRead), 2538 TRANS(SocketWrite), 2539 TRANS(SocketReadv), 2540 TRANS(SocketWritev), 2541#if XTRANS_SEND_FDS 2542 TRANS(SocketSendFdInvalid), 2543 TRANS(SocketRecvFdInvalid), 2544#endif 2545 TRANS(SocketDisconnect), 2546 TRANS(SocketINETClose), 2547 TRANS(SocketINETClose), 2548 }; 2549 2550Xtransport TRANS(SocketINETFuncs) = { 2551 /* Socket Interface */ 2552 "inet", 2553 0, 2554#ifdef TRANS_CLIENT 2555 TRANS(SocketOpenCOTSClient), 2556#endif /* TRANS_CLIENT */ 2557#ifdef TRANS_SERVER 2558 NULL, 2559 TRANS(SocketOpenCOTSServer), 2560#endif /* TRANS_SERVER */ 2561#ifdef TRANS_CLIENT 2562 TRANS(SocketOpenCLTSClient), 2563#endif /* TRANS_CLIENT */ 2564#ifdef TRANS_SERVER 2565 TRANS(SocketOpenCLTSServer), 2566#endif /* TRANS_SERVER */ 2567#ifdef TRANS_REOPEN 2568 TRANS(SocketReopenCOTSServer), 2569 TRANS(SocketReopenCLTSServer), 2570#endif 2571 TRANS(SocketSetOption), 2572#ifdef TRANS_SERVER 2573 TRANS(SocketINETCreateListener), 2574 NULL, /* ResetListener */ 2575 TRANS(SocketINETAccept), 2576#endif /* TRANS_SERVER */ 2577#ifdef TRANS_CLIENT 2578 TRANS(SocketINETConnect), 2579#endif /* TRANS_CLIENT */ 2580 TRANS(SocketBytesReadable), 2581 TRANS(SocketRead), 2582 TRANS(SocketWrite), 2583 TRANS(SocketReadv), 2584 TRANS(SocketWritev), 2585#if XTRANS_SEND_FDS 2586 TRANS(SocketSendFdInvalid), 2587 TRANS(SocketRecvFdInvalid), 2588#endif 2589 TRANS(SocketDisconnect), 2590 TRANS(SocketINETClose), 2591 TRANS(SocketINETClose), 2592 }; 2593 2594#if defined(IPv6) && defined(AF_INET6) 2595Xtransport TRANS(SocketINET6Funcs) = { 2596 /* Socket Interface */ 2597 "inet6", 2598 0, 2599#ifdef TRANS_CLIENT 2600 TRANS(SocketOpenCOTSClient), 2601#endif /* TRANS_CLIENT */ 2602#ifdef TRANS_SERVER 2603 NULL, 2604 TRANS(SocketOpenCOTSServer), 2605#endif /* TRANS_SERVER */ 2606#ifdef TRANS_CLIENT 2607 TRANS(SocketOpenCLTSClient), 2608#endif /* TRANS_CLIENT */ 2609#ifdef TRANS_SERVER 2610 TRANS(SocketOpenCLTSServer), 2611#endif /* TRANS_SERVER */ 2612#ifdef TRANS_REOPEN 2613 TRANS(SocketReopenCOTSServer), 2614 TRANS(SocketReopenCLTSServer), 2615#endif 2616 TRANS(SocketSetOption), 2617#ifdef TRANS_SERVER 2618 TRANS(SocketINETCreateListener), 2619 NULL, /* ResetListener */ 2620 TRANS(SocketINETAccept), 2621#endif /* TRANS_SERVER */ 2622#ifdef TRANS_CLIENT 2623 TRANS(SocketINETConnect), 2624#endif /* TRANS_CLIENT */ 2625 TRANS(SocketBytesReadable), 2626 TRANS(SocketRead), 2627 TRANS(SocketWrite), 2628 TRANS(SocketReadv), 2629 TRANS(SocketWritev), 2630#if XTRANS_SEND_FDS 2631 TRANS(SocketSendFdInvalid), 2632 TRANS(SocketRecvFdInvalid), 2633#endif 2634 TRANS(SocketDisconnect), 2635 TRANS(SocketINETClose), 2636 TRANS(SocketINETClose), 2637 }; 2638#endif /* IPv6 */ 2639#endif /* TCPCONN */ 2640 2641#ifdef UNIXCONN 2642#if !defined(LOCALCONN) 2643Xtransport TRANS(SocketLocalFuncs) = { 2644 /* Socket Interface */ 2645 "local", 2646#ifdef HAVE_ABSTRACT_SOCKETS 2647 TRANS_ABSTRACT, 2648#else 2649 0, 2650#endif 2651#ifdef TRANS_CLIENT 2652 TRANS(SocketOpenCOTSClient), 2653#endif /* TRANS_CLIENT */ 2654#ifdef TRANS_SERVER 2655 NULL, 2656 TRANS(SocketOpenCOTSServer), 2657#endif /* TRANS_SERVER */ 2658#ifdef TRANS_CLIENT 2659 TRANS(SocketOpenCLTSClient), 2660#endif /* TRANS_CLIENT */ 2661#ifdef TRANS_SERVER 2662 TRANS(SocketOpenCLTSServer), 2663#endif /* TRANS_SERVER */ 2664#ifdef TRANS_REOPEN 2665 TRANS(SocketReopenCOTSServer), 2666 TRANS(SocketReopenCLTSServer), 2667#endif 2668 TRANS(SocketSetOption), 2669#ifdef TRANS_SERVER 2670 TRANS(SocketUNIXCreateListener), 2671 TRANS(SocketUNIXResetListener), 2672 TRANS(SocketUNIXAccept), 2673#endif /* TRANS_SERVER */ 2674#ifdef TRANS_CLIENT 2675 TRANS(SocketUNIXConnect), 2676#endif /* TRANS_CLIENT */ 2677 TRANS(SocketBytesReadable), 2678 TRANS(SocketRead), 2679 TRANS(SocketWrite), 2680 TRANS(SocketReadv), 2681 TRANS(SocketWritev), 2682#if XTRANS_SEND_FDS 2683 TRANS(SocketSendFd), 2684 TRANS(SocketRecvFd), 2685#endif 2686 TRANS(SocketDisconnect), 2687 TRANS(SocketUNIXClose), 2688 TRANS(SocketUNIXCloseForCloning), 2689 }; 2690#endif /* !LOCALCONN */ 2691# ifdef TRANS_SERVER 2692# if !defined(LOCALCONN) 2693static const char* unix_nolisten[] = { "local" , NULL }; 2694# endif 2695# endif 2696 2697Xtransport TRANS(SocketUNIXFuncs) = { 2698 /* Socket Interface */ 2699 "unix", 2700#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS) 2701 TRANS_ALIAS, 2702#else 2703 0, 2704#endif 2705#ifdef TRANS_CLIENT 2706 TRANS(SocketOpenCOTSClient), 2707#endif /* TRANS_CLIENT */ 2708#ifdef TRANS_SERVER 2709#if !defined(LOCALCONN) 2710 unix_nolisten, 2711#else 2712 NULL, 2713#endif 2714 TRANS(SocketOpenCOTSServer), 2715#endif /* TRANS_SERVER */ 2716#ifdef TRANS_CLIENT 2717 TRANS(SocketOpenCLTSClient), 2718#endif /* TRANS_CLIENT */ 2719#ifdef TRANS_SERVER 2720 TRANS(SocketOpenCLTSServer), 2721#endif /* TRANS_SERVER */ 2722#ifdef TRANS_REOPEN 2723 TRANS(SocketReopenCOTSServer), 2724 TRANS(SocketReopenCLTSServer), 2725#endif 2726 TRANS(SocketSetOption), 2727#ifdef TRANS_SERVER 2728 TRANS(SocketUNIXCreateListener), 2729 TRANS(SocketUNIXResetListener), 2730 TRANS(SocketUNIXAccept), 2731#endif /* TRANS_SERVER */ 2732#ifdef TRANS_CLIENT 2733 TRANS(SocketUNIXConnect), 2734#endif /* TRANS_CLIENT */ 2735 TRANS(SocketBytesReadable), 2736 TRANS(SocketRead), 2737 TRANS(SocketWrite), 2738 TRANS(SocketReadv), 2739 TRANS(SocketWritev), 2740#if XTRANS_SEND_FDS 2741 TRANS(SocketSendFd), 2742 TRANS(SocketRecvFd), 2743#endif 2744 TRANS(SocketDisconnect), 2745 TRANS(SocketUNIXClose), 2746 TRANS(SocketUNIXCloseForCloning), 2747 }; 2748 2749#endif /* UNIXCONN */ 2750