Xtranssock.c revision 8a0d9095
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, 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, char *protocol, 600 char *host, 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, char *protocol, 614 char *host, 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, char *protocol, 681 char *host, 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, char *protocol, 720 char *host, 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, 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, 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, char *port, unsigned int flags) 951 952{ 953#if defined(IPv6) && defined(AF_INET6) 954 struct sockaddr_storage sockname; 955#else 956 struct sockaddr_in sockname; 957#endif 958 unsigned short sport; 959 SOCKLEN_T namelen = sizeof(sockname); 960 int status; 961 long tmpport; 962#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 963 _Xgetservbynameparams sparams; 964#endif 965 struct servent *servp; 966 967#ifdef X11_t 968 char portbuf[PORTBUFSIZE]; 969#endif 970 971 prmsg (2, "SocketINETCreateListener(%s)\n", port); 972 973#ifdef X11_t 974 /* 975 * X has a well known port, that is transport dependent. It is easier 976 * to handle it here, than try and come up with a transport independent 977 * representation that can be passed in and resolved the usual way. 978 * 979 * The port that is passed here is really a string containing the idisplay 980 * from ConnectDisplay(). 981 */ 982 983 if (is_numeric (port)) 984 { 985 /* fixup the server port address */ 986 tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10); 987 snprintf (portbuf, sizeof(portbuf), "%lu", tmpport); 988 port = portbuf; 989 } 990#endif 991 992 if (port && *port) 993 { 994 /* Check to see if the port string is just a number (handles X11) */ 995 996 if (!is_numeric (port)) 997 { 998 if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) 999 { 1000 prmsg (1, 1001 "SocketINETCreateListener: Unable to get service for %s\n", 1002 port); 1003 return TRANS_CREATE_LISTENER_FAILED; 1004 } 1005 /* we trust getservbyname to return a valid number */ 1006 sport = servp->s_port; 1007 } 1008 else 1009 { 1010 tmpport = strtol (port, (char**)NULL, 10); 1011 /* 1012 * check that somehow the port address isn't negative or in 1013 * the range of reserved port addresses. This can happen and 1014 * be very bad if the server is suid-root and the user does 1015 * something (dumb) like `X :60049`. 1016 */ 1017 if (tmpport < 1024 || tmpport > USHRT_MAX) 1018 return TRANS_CREATE_LISTENER_FAILED; 1019 1020 sport = (unsigned short) tmpport; 1021 } 1022 } 1023 else 1024 sport = 0; 1025 1026 bzero(&sockname, sizeof(sockname)); 1027#if defined(IPv6) && defined(AF_INET6) 1028 if (Sockettrans2devtab[ciptr->index].family == AF_INET) { 1029 namelen = sizeof (struct sockaddr_in); 1030#ifdef BSD44SOCKETS 1031 ((struct sockaddr_in *)&sockname)->sin_len = namelen; 1032#endif 1033 ((struct sockaddr_in *)&sockname)->sin_family = AF_INET; 1034 ((struct sockaddr_in *)&sockname)->sin_port = htons(sport); 1035 ((struct sockaddr_in *)&sockname)->sin_addr.s_addr = htonl(INADDR_ANY); 1036 } else { 1037 namelen = sizeof (struct sockaddr_in6); 1038#ifdef SIN6_LEN 1039 ((struct sockaddr_in6 *)&sockname)->sin6_len = sizeof(sockname); 1040#endif 1041 ((struct sockaddr_in6 *)&sockname)->sin6_family = AF_INET6; 1042 ((struct sockaddr_in6 *)&sockname)->sin6_port = htons(sport); 1043 ((struct sockaddr_in6 *)&sockname)->sin6_addr = in6addr_any; 1044 } 1045#else 1046#ifdef BSD44SOCKETS 1047 sockname.sin_len = sizeof (sockname); 1048#endif 1049 sockname.sin_family = AF_INET; 1050 sockname.sin_port = htons (sport); 1051 sockname.sin_addr.s_addr = htonl (INADDR_ANY); 1052#endif 1053 1054 if ((status = TRANS(SocketCreateListener) (ciptr, 1055 (struct sockaddr *) &sockname, namelen, flags)) < 0) 1056 { 1057 prmsg (1, 1058 "SocketINETCreateListener: ...SocketCreateListener() failed\n"); 1059 return status; 1060 } 1061 1062 if (TRANS(SocketINETGetAddr) (ciptr) < 0) 1063 { 1064 prmsg (1, 1065 "SocketINETCreateListener: ...SocketINETGetAddr() failed\n"); 1066 return TRANS_CREATE_LISTENER_FAILED; 1067 } 1068 1069 return 0; 1070} 1071 1072#endif /* TCPCONN */ 1073 1074 1075#ifdef UNIXCONN 1076 1077static int 1078TRANS(SocketUNIXCreateListener) (XtransConnInfo ciptr, char *port, 1079 unsigned int flags) 1080 1081{ 1082 struct sockaddr_un sockname; 1083 int namelen; 1084 int oldUmask; 1085 int status; 1086 unsigned int mode; 1087 char tmpport[108]; 1088 1089 int abstract = 0; 1090#ifdef HAVE_ABSTRACT_SOCKETS 1091 abstract = ciptr->transptr->flags & TRANS_ABSTRACT; 1092#endif 1093 1094 prmsg (2, "SocketUNIXCreateListener(%s)\n", 1095 port ? port : "NULL"); 1096 1097 /* Make sure the directory is created */ 1098 1099 oldUmask = umask (0); 1100 1101#ifdef UNIX_DIR 1102#ifdef HAS_STICKY_DIR_BIT 1103 mode = 01777; 1104#else 1105 mode = 0777; 1106#endif 1107 if (!abstract && trans_mkdir(UNIX_DIR, mode) == -1) { 1108 prmsg (1, "SocketUNIXCreateListener: mkdir(%s) failed, errno = %d\n", 1109 UNIX_DIR, errno); 1110 (void) umask (oldUmask); 1111 return TRANS_CREATE_LISTENER_FAILED; 1112 } 1113#endif 1114 1115 memset(&sockname, 0, sizeof(sockname)); 1116 sockname.sun_family = AF_UNIX; 1117 1118 if (!(port && *port)) { 1119 snprintf (tmpport, sizeof(tmpport), "%s%ld", UNIX_PATH, (long)getpid()); 1120 port = tmpport; 1121 } 1122 if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) { 1123 prmsg (1, "SocketUNIXCreateListener: path too long\n"); 1124 return TRANS_CREATE_LISTENER_FAILED; 1125 } 1126 1127#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__)) 1128 sockname.sun_len = strlen(sockname.sun_path); 1129#endif 1130 1131#if defined(BSD44SOCKETS) || defined(SUN_LEN) 1132 namelen = SUN_LEN(&sockname); 1133#else 1134 namelen = strlen(sockname.sun_path) + offsetof(struct sockaddr_un, sun_path); 1135#endif 1136 1137 if (abstract) { 1138 sockname.sun_path[0] = '\0'; 1139 namelen = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&sockname.sun_path[1]); 1140 } 1141 else 1142 unlink (sockname.sun_path); 1143 1144 if ((status = TRANS(SocketCreateListener) (ciptr, 1145 (struct sockaddr *) &sockname, namelen, flags)) < 0) 1146 { 1147 prmsg (1, 1148 "SocketUNIXCreateListener: ...SocketCreateListener() failed\n"); 1149 (void) umask (oldUmask); 1150 return status; 1151 } 1152 1153 /* 1154 * Now that the listener is esablished, create the addr info for 1155 * this connection. getpeername() doesn't work for UNIX Domain Sockets 1156 * on some systems (hpux at least), so we will just do it manually, instead 1157 * of calling something like TRANS(SocketUNIXGetAddr). 1158 */ 1159 1160 namelen = sizeof (sockname); /* this will always make it the same size */ 1161 1162 if ((ciptr->addr = malloc (namelen)) == NULL) 1163 { 1164 prmsg (1, 1165 "SocketUNIXCreateListener: Can't allocate space for the addr\n"); 1166 (void) umask (oldUmask); 1167 return TRANS_CREATE_LISTENER_FAILED; 1168 } 1169 1170 if (abstract) 1171 sockname.sun_path[0] = '@'; 1172 1173 ciptr->family = sockname.sun_family; 1174 ciptr->addrlen = namelen; 1175 memcpy (ciptr->addr, &sockname, ciptr->addrlen); 1176 1177 (void) umask (oldUmask); 1178 1179 return 0; 1180} 1181 1182 1183static int 1184TRANS(SocketUNIXResetListener) (XtransConnInfo ciptr) 1185 1186{ 1187 /* 1188 * See if the unix domain socket has disappeared. If it has, recreate it. 1189 */ 1190 1191 struct sockaddr_un *unsock = (struct sockaddr_un *) ciptr->addr; 1192 struct stat statb; 1193 int status = TRANS_RESET_NOOP; 1194 unsigned int mode; 1195 int abstract = 0; 1196#ifdef HAVE_ABSTRACT_SOCKETS 1197 abstract = ciptr->transptr->flags & TRANS_ABSTRACT; 1198#endif 1199 1200 prmsg (3, "SocketUNIXResetListener(%p,%d)\n", ciptr, ciptr->fd); 1201 1202 if (!abstract && ( 1203 stat (unsock->sun_path, &statb) == -1 || 1204 ((statb.st_mode & S_IFMT) != 1205#if defined(NCR) || defined(SCO325) || !defined(S_IFSOCK) 1206 S_IFIFO 1207#else 1208 S_IFSOCK 1209#endif 1210 ))) 1211 { 1212 int oldUmask = umask (0); 1213 1214#ifdef UNIX_DIR 1215#ifdef HAS_STICKY_DIR_BIT 1216 mode = 01777; 1217#else 1218 mode = 0777; 1219#endif 1220 if (trans_mkdir(UNIX_DIR, mode) == -1) { 1221 prmsg (1, "SocketUNIXResetListener: mkdir(%s) failed, errno = %d\n", 1222 UNIX_DIR, errno); 1223 (void) umask (oldUmask); 1224 return TRANS_RESET_FAILURE; 1225 } 1226#endif 1227 1228 close (ciptr->fd); 1229 unlink (unsock->sun_path); 1230 1231 if ((ciptr->fd = socket (AF_UNIX, SOCK_STREAM, 0)) < 0) 1232 { 1233 TRANS(FreeConnInfo) (ciptr); 1234 (void) umask (oldUmask); 1235 return TRANS_RESET_FAILURE; 1236 } 1237 1238 if (bind (ciptr->fd, (struct sockaddr *) unsock, ciptr->addrlen) < 0) 1239 { 1240 close (ciptr->fd); 1241 TRANS(FreeConnInfo) (ciptr); 1242 return TRANS_RESET_FAILURE; 1243 } 1244 1245 if (listen (ciptr->fd, BACKLOG) < 0) 1246 { 1247 close (ciptr->fd); 1248 TRANS(FreeConnInfo) (ciptr); 1249 (void) umask (oldUmask); 1250 return TRANS_RESET_FAILURE; 1251 } 1252 1253 umask (oldUmask); 1254 1255 status = TRANS_RESET_NEW_FD; 1256 } 1257 1258 return status; 1259} 1260 1261#endif /* UNIXCONN */ 1262 1263 1264#ifdef TCPCONN 1265 1266static XtransConnInfo 1267TRANS(SocketINETAccept) (XtransConnInfo ciptr, int *status) 1268 1269{ 1270 XtransConnInfo newciptr; 1271 struct sockaddr_in sockname; 1272 SOCKLEN_T namelen = sizeof(sockname); 1273 1274 prmsg (2, "SocketINETAccept(%p,%d)\n", ciptr, ciptr->fd); 1275 1276 if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) 1277 { 1278 prmsg (1, "SocketINETAccept: malloc failed\n"); 1279 *status = TRANS_ACCEPT_BAD_MALLOC; 1280 return NULL; 1281 } 1282 1283 if ((newciptr->fd = accept (ciptr->fd, 1284 (struct sockaddr *) &sockname, (void *)&namelen)) < 0) 1285 { 1286#ifdef WIN32 1287 errno = WSAGetLastError(); 1288#endif 1289 prmsg (1, "SocketINETAccept: accept() failed\n"); 1290 free (newciptr); 1291 *status = TRANS_ACCEPT_FAILED; 1292 return NULL; 1293 } 1294 1295#ifdef TCP_NODELAY 1296 { 1297 /* 1298 * turn off TCP coalescence for INET sockets 1299 */ 1300 1301 int tmp = 1; 1302 setsockopt (newciptr->fd, IPPROTO_TCP, TCP_NODELAY, 1303 (char *) &tmp, sizeof (int)); 1304 } 1305#endif 1306 1307 /* 1308 * Get this address again because the transport may give a more 1309 * specific address now that a connection is established. 1310 */ 1311 1312 if (TRANS(SocketINETGetAddr) (newciptr) < 0) 1313 { 1314 prmsg (1, 1315 "SocketINETAccept: ...SocketINETGetAddr() failed:\n"); 1316 close (newciptr->fd); 1317 free (newciptr); 1318 *status = TRANS_ACCEPT_MISC_ERROR; 1319 return NULL; 1320 } 1321 1322 if (TRANS(SocketINETGetPeerAddr) (newciptr) < 0) 1323 { 1324 prmsg (1, 1325 "SocketINETAccept: ...SocketINETGetPeerAddr() failed:\n"); 1326 close (newciptr->fd); 1327 if (newciptr->addr) free (newciptr->addr); 1328 free (newciptr); 1329 *status = TRANS_ACCEPT_MISC_ERROR; 1330 return NULL; 1331 } 1332 1333 *status = 0; 1334 1335 return newciptr; 1336} 1337 1338#endif /* TCPCONN */ 1339 1340 1341#ifdef UNIXCONN 1342static XtransConnInfo 1343TRANS(SocketUNIXAccept) (XtransConnInfo ciptr, int *status) 1344 1345{ 1346 XtransConnInfo newciptr; 1347 struct sockaddr_un sockname; 1348 SOCKLEN_T namelen = sizeof sockname; 1349 1350 prmsg (2, "SocketUNIXAccept(%p,%d)\n", ciptr, ciptr->fd); 1351 1352 if ((newciptr = calloc (1, sizeof(struct _XtransConnInfo))) == NULL) 1353 { 1354 prmsg (1, "SocketUNIXAccept: malloc() failed\n"); 1355 *status = TRANS_ACCEPT_BAD_MALLOC; 1356 return NULL; 1357 } 1358 1359 if ((newciptr->fd = accept (ciptr->fd, 1360 (struct sockaddr *) &sockname, (void *)&namelen)) < 0) 1361 { 1362 prmsg (1, "SocketUNIXAccept: accept() failed\n"); 1363 free (newciptr); 1364 *status = TRANS_ACCEPT_FAILED; 1365 return NULL; 1366 } 1367 1368 ciptr->addrlen = namelen; 1369 /* 1370 * Get the socket name and the peer name from the listener socket, 1371 * since this is unix domain. 1372 */ 1373 1374 if ((newciptr->addr = malloc (ciptr->addrlen)) == NULL) 1375 { 1376 prmsg (1, 1377 "SocketUNIXAccept: Can't allocate space for the addr\n"); 1378 close (newciptr->fd); 1379 free (newciptr); 1380 *status = TRANS_ACCEPT_BAD_MALLOC; 1381 return NULL; 1382 } 1383 1384 /* 1385 * if the socket is abstract, we already modified the address to have a 1386 * @ instead of the initial NUL, so no need to do that again here. 1387 */ 1388 1389 newciptr->addrlen = ciptr->addrlen; 1390 memcpy (newciptr->addr, ciptr->addr, newciptr->addrlen); 1391 1392 if ((newciptr->peeraddr = malloc (ciptr->addrlen)) == NULL) 1393 { 1394 prmsg (1, 1395 "SocketUNIXAccept: Can't allocate space for the addr\n"); 1396 close (newciptr->fd); 1397 if (newciptr->addr) free (newciptr->addr); 1398 free (newciptr); 1399 *status = TRANS_ACCEPT_BAD_MALLOC; 1400 return NULL; 1401 } 1402 1403 newciptr->peeraddrlen = ciptr->addrlen; 1404 memcpy (newciptr->peeraddr, ciptr->addr, newciptr->addrlen); 1405 1406 newciptr->family = AF_UNIX; 1407 1408 *status = 0; 1409 1410 return newciptr; 1411} 1412 1413#endif /* UNIXCONN */ 1414 1415#endif /* TRANS_SERVER */ 1416 1417 1418#ifdef TRANS_CLIENT 1419 1420#ifdef TCPCONN 1421 1422#if defined(IPv6) && defined(AF_INET6) 1423struct addrlist { 1424 struct addrinfo * addr; 1425 struct addrinfo * firstaddr; 1426 char port[PORTBUFSIZE]; 1427 char host[MAXHOSTNAMELEN]; 1428}; 1429static struct addrlist *addrlist = NULL; 1430#endif 1431 1432 1433static int 1434TRANS(SocketINETConnect) (XtransConnInfo ciptr, char *host, char *port) 1435 1436{ 1437 struct sockaddr * socketaddr = NULL; 1438 int socketaddrlen = 0; 1439 int res; 1440#if defined(IPv6) && defined(AF_INET6) 1441 struct addrinfo hints; 1442 char ntopbuf[INET6_ADDRSTRLEN]; 1443 int resetonce = 0; 1444#else 1445 struct sockaddr_in sockname; 1446 struct hostent *hostp; 1447 struct servent *servp; 1448 unsigned long tmpaddr; 1449#endif 1450#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1451 _Xgethostbynameparams hparams; 1452 _Xgetservbynameparams sparams; 1453#endif 1454#ifdef X11_t 1455 char portbuf[PORTBUFSIZE]; 1456#endif 1457 1458 char hostnamebuf[256]; /* tmp space */ 1459 1460 prmsg (2,"SocketINETConnect(%d,%s,%s)\n", ciptr->fd, host, port); 1461 1462 if (!host) 1463 { 1464 hostnamebuf[0] = '\0'; 1465 (void) TRANS(GetHostname) (hostnamebuf, sizeof hostnamebuf); 1466 host = hostnamebuf; 1467 } 1468 1469#ifdef X11_t 1470 /* 1471 * X has a well known port, that is transport dependent. It is easier 1472 * to handle it here, than try and come up with a transport independent 1473 * representation that can be passed in and resolved the usual way. 1474 * 1475 * The port that is passed here is really a string containing the idisplay 1476 * from ConnectDisplay(). 1477 */ 1478 1479 if (is_numeric (port)) 1480 { 1481 long tmpport = X_TCP_PORT + strtol (port, (char**)NULL, 10); 1482 snprintf (portbuf, sizeof(portbuf), "%lu", tmpport); 1483 port = portbuf; 1484 } 1485#endif 1486 1487#if defined(IPv6) && defined(AF_INET6) 1488 { 1489 if (addrlist != NULL) { 1490 if (strcmp(host,addrlist->host) || strcmp(port,addrlist->port)) { 1491 if (addrlist->firstaddr) 1492 freeaddrinfo(addrlist->firstaddr); 1493 addrlist->firstaddr = NULL; 1494 } 1495 } else { 1496 addrlist = malloc(sizeof(struct addrlist)); 1497 addrlist->firstaddr = NULL; 1498 } 1499 1500 if (addrlist->firstaddr == NULL) { 1501 strncpy(addrlist->port, port, sizeof(addrlist->port)); 1502 addrlist->port[sizeof(addrlist->port) - 1] = '\0'; 1503 strncpy(addrlist->host, host, sizeof(addrlist->host)); 1504 addrlist->host[sizeof(addrlist->host) - 1] = '\0'; 1505 1506 bzero(&hints,sizeof(hints)); 1507 hints.ai_socktype = Sockettrans2devtab[ciptr->index].devcotsname; 1508 1509 res = getaddrinfo(host,port,&hints,&addrlist->firstaddr); 1510 if (res != 0) { 1511 prmsg (1, "SocketINETConnect() can't get address " 1512 "for %s:%s: %s\n", host, port, gai_strerror(res)); 1513 ESET(EINVAL); 1514 return TRANS_CONNECT_FAILED; 1515 } 1516 for (res = 0, addrlist->addr = addrlist->firstaddr; 1517 addrlist->addr ; res++) { 1518 addrlist->addr = addrlist->addr->ai_next; 1519 } 1520 prmsg(4,"Got New Address list with %d addresses\n", res); 1521 res = 0; 1522 addrlist->addr = NULL; 1523 } 1524 1525 while (socketaddr == NULL) { 1526 if (addrlist->addr == NULL) { 1527 if (resetonce) { 1528 /* Already checked entire list - no usable addresses */ 1529 prmsg (1, "SocketINETConnect() no usable address " 1530 "for %s:%s\n", host, port); 1531 return TRANS_CONNECT_FAILED; 1532 } else { 1533 /* Go back to beginning of list */ 1534 resetonce = 1; 1535 addrlist->addr = addrlist->firstaddr; 1536 } 1537 } 1538 1539 socketaddr = addrlist->addr->ai_addr; 1540 socketaddrlen = addrlist->addr->ai_addrlen; 1541 1542 if (addrlist->addr->ai_family == AF_INET) { 1543 struct sockaddr_in *sin = (struct sockaddr_in *) socketaddr; 1544 1545 prmsg (4,"SocketINETConnect() sockname.sin_addr = %s\n", 1546 inet_ntop(addrlist->addr->ai_family,&sin->sin_addr, 1547 ntopbuf,sizeof(ntopbuf))); 1548 1549 prmsg (4,"SocketINETConnect() sockname.sin_port = %d\n", 1550 ntohs(sin->sin_port)); 1551 1552 if (Sockettrans2devtab[ciptr->index].family == AF_INET6) { 1553 if (strcmp(Sockettrans2devtab[ciptr->index].transname, 1554 "tcp") == 0) { 1555 XtransConnInfo newciptr; 1556 1557 /* 1558 * Our socket is an IPv6 socket, but the address is 1559 * IPv4. Close it and get an IPv4 socket. This is 1560 * needed for IPv4 connections to work on platforms 1561 * that don't allow IPv4 over IPv6 sockets. 1562 */ 1563 TRANS(SocketINETClose)(ciptr); 1564 newciptr = TRANS(SocketOpenCOTSClientBase)( 1565 "tcp", "tcp", host, port, ciptr->index); 1566 if (newciptr) 1567 ciptr->fd = newciptr->fd; 1568 if (!newciptr || 1569 Sockettrans2devtab[newciptr->index].family != 1570 AF_INET) { 1571 socketaddr = NULL; 1572 prmsg (4,"SocketINETConnect() Cannot get IPv4 " 1573 " socketfor IPv4 address\n"); 1574 } 1575 if (newciptr) 1576 free(newciptr); 1577 } else { 1578 socketaddr = NULL; 1579 prmsg (4,"SocketINETConnect Skipping IPv4 address\n"); 1580 } 1581 } 1582 } else if (addrlist->addr->ai_family == AF_INET6) { 1583 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) socketaddr; 1584 1585 prmsg (4,"SocketINETConnect() sockname.sin6_addr = %s\n", 1586 inet_ntop(addrlist->addr->ai_family, 1587 &sin6->sin6_addr,ntopbuf,sizeof(ntopbuf))); 1588 prmsg (4,"SocketINETConnect() sockname.sin6_port = %d\n", 1589 ntohs(sin6->sin6_port)); 1590 1591 if (Sockettrans2devtab[ciptr->index].family == AF_INET) { 1592 if (strcmp(Sockettrans2devtab[ciptr->index].transname, 1593 "tcp") == 0) { 1594 XtransConnInfo newciptr; 1595 1596 /* 1597 * Close the IPv4 socket and try to open an IPv6 socket. 1598 */ 1599 TRANS(SocketINETClose)(ciptr); 1600 newciptr = TRANS(SocketOpenCOTSClientBase)( 1601 "tcp", "tcp", host, port, -1); 1602 if (newciptr) 1603 ciptr->fd = newciptr->fd; 1604 if (!newciptr || 1605 Sockettrans2devtab[newciptr->index].family != 1606 AF_INET6) { 1607 socketaddr = NULL; 1608 prmsg (4,"SocketINETConnect() Cannot get IPv6 " 1609 "socket for IPv6 address\n"); 1610 } 1611 if (newciptr) 1612 free(newciptr); 1613 } 1614 else 1615 { 1616 socketaddr = NULL; 1617 prmsg (4,"SocketINETConnect() Skipping IPv6 address\n"); 1618 } 1619 } 1620 } else { 1621 socketaddr = NULL; /* Unsupported address type */ 1622 } 1623 if (socketaddr == NULL) { 1624 addrlist->addr = addrlist->addr->ai_next; 1625 } 1626 } 1627 } 1628#else 1629 { 1630 /* 1631 * Build the socket name. 1632 */ 1633 1634#ifdef BSD44SOCKETS 1635 sockname.sin_len = sizeof (struct sockaddr_in); 1636#endif 1637 sockname.sin_family = AF_INET; 1638 1639 /* 1640 * fill in sin_addr 1641 */ 1642 1643#ifndef INADDR_NONE 1644#define INADDR_NONE ((in_addr_t) 0xffffffff) 1645#endif 1646 1647 /* check for ww.xx.yy.zz host string */ 1648 1649 if (isascii (host[0]) && isdigit (host[0])) { 1650 tmpaddr = inet_addr (host); /* returns network byte order */ 1651 } else { 1652 tmpaddr = INADDR_NONE; 1653 } 1654 1655 prmsg (4,"SocketINETConnect() inet_addr(%s) = %x\n", host, tmpaddr); 1656 1657 if (tmpaddr == INADDR_NONE) { 1658 if ((hostp = _XGethostbyname(host,hparams)) == NULL) { 1659 prmsg (1,"SocketINETConnect: Can't get address for %s\n", 1660 host); 1661 ESET(EINVAL); 1662 return TRANS_CONNECT_FAILED; 1663 } 1664 if (hostp->h_addrtype != AF_INET) { /* is IP host? */ 1665 prmsg (1,"SocketINETConnect: not INET host%s\n", host); 1666 ESET(EPROTOTYPE); 1667 return TRANS_CONNECT_FAILED; 1668 } 1669 1670 memcpy ((char *) &sockname.sin_addr, (char *) hostp->h_addr, 1671 sizeof (sockname.sin_addr)); 1672 1673 } else { 1674 sockname.sin_addr.s_addr = tmpaddr; 1675 } 1676 1677 /* 1678 * fill in sin_port 1679 */ 1680 1681 /* Check for number in the port string */ 1682 1683 if (!is_numeric (port)) { 1684 if ((servp = _XGetservbyname (port,"tcp",sparams)) == NULL) { 1685 prmsg (1,"SocketINETConnect: can't get service for %s\n", 1686 port); 1687 return TRANS_CONNECT_FAILED; 1688 } 1689 sockname.sin_port = htons (servp->s_port); 1690 } else { 1691 long tmpport = strtol (port, (char**)NULL, 10); 1692 if (tmpport < 1024 || tmpport > USHRT_MAX) 1693 return TRANS_CONNECT_FAILED; 1694 sockname.sin_port = htons (((unsigned short) tmpport)); 1695 } 1696 1697 prmsg (4,"SocketINETConnect: sockname.sin_port = %d\n", 1698 ntohs(sockname.sin_port)); 1699 socketaddr = (struct sockaddr *) &sockname; 1700 socketaddrlen = sizeof(sockname); 1701 } 1702#endif 1703 1704 /* 1705 * Turn on socket keepalive so the client process will eventually 1706 * be notified with a SIGPIPE signal if the display server fails 1707 * to respond to a periodic transmission of messages 1708 * on the connected socket. 1709 * This is useful to avoid hung application processes when the 1710 * processes are not spawned from the xdm session and 1711 * the display server terminates abnormally. 1712 * (Someone turned off the power switch.) 1713 */ 1714 1715 { 1716 int tmp = 1; 1717 setsockopt (ciptr->fd, SOL_SOCKET, SO_KEEPALIVE, 1718 (char *) &tmp, sizeof (int)); 1719 } 1720 1721 /* 1722 * Do the connect() 1723 */ 1724 1725 if (connect (ciptr->fd, socketaddr, socketaddrlen ) < 0) 1726 { 1727#ifdef WIN32 1728 int olderrno = WSAGetLastError(); 1729#else 1730 int olderrno = errno; 1731#endif 1732 1733 /* 1734 * If the error was ECONNREFUSED, the server may be overloaded 1735 * and we should try again. 1736 * 1737 * If the error was EWOULDBLOCK or EINPROGRESS then the socket 1738 * was non-blocking and we should poll using select 1739 * 1740 * If the error was EINTR, the connect was interrupted and we 1741 * should try again. 1742 * 1743 * If multiple addresses are found for a host then we should 1744 * try to connect again with a different address for a larger 1745 * number of errors that made us quit before, since those 1746 * could be caused by trying to use an IPv6 address to contact 1747 * a machine with an IPv4-only server or other reasons that 1748 * only affect one of a set of addresses. 1749 */ 1750 1751 if (olderrno == ECONNREFUSED || olderrno == EINTR 1752#if defined(IPv6) && defined(AF_INET6) 1753 || (((addrlist->addr->ai_next != NULL) || 1754 (addrlist->addr != addrlist->firstaddr)) && 1755 (olderrno == ENETUNREACH || olderrno == EAFNOSUPPORT || 1756 olderrno == EADDRNOTAVAIL || olderrno == ETIMEDOUT 1757#if defined(EHOSTDOWN) 1758 || olderrno == EHOSTDOWN 1759#endif 1760 )) 1761#endif 1762 ) 1763 res = TRANS_TRY_CONNECT_AGAIN; 1764 else if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS) 1765 res = TRANS_IN_PROGRESS; 1766 else 1767 { 1768 prmsg (2,"SocketINETConnect: Can't connect: errno = %d\n", 1769 olderrno); 1770 1771 res = TRANS_CONNECT_FAILED; 1772 } 1773 } else { 1774 res = 0; 1775 1776 1777 /* 1778 * Sync up the address fields of ciptr. 1779 */ 1780 1781 if (TRANS(SocketINETGetAddr) (ciptr) < 0) 1782 { 1783 prmsg (1, 1784 "SocketINETConnect: ...SocketINETGetAddr() failed:\n"); 1785 res = TRANS_CONNECT_FAILED; 1786 } 1787 1788 else if (TRANS(SocketINETGetPeerAddr) (ciptr) < 0) 1789 { 1790 prmsg (1, 1791 "SocketINETConnect: ...SocketINETGetPeerAddr() failed:\n"); 1792 res = TRANS_CONNECT_FAILED; 1793 } 1794 } 1795 1796#if defined(IPv6) && defined(AF_INET6) 1797 if (res != 0) { 1798 addrlist->addr = addrlist->addr->ai_next; 1799 } 1800#endif 1801 1802 return res; 1803} 1804 1805#endif /* TCPCONN */ 1806 1807 1808 1809#ifdef UNIXCONN 1810 1811/* 1812 * Make sure 'host' is really local. 1813 */ 1814 1815static int 1816UnixHostReallyLocal (char *host) 1817 1818{ 1819 char hostnamebuf[256]; 1820 1821 TRANS(GetHostname) (hostnamebuf, sizeof (hostnamebuf)); 1822 1823 if (strcmp (hostnamebuf, host) == 0) 1824 { 1825 return (1); 1826 } else { 1827#if defined(IPv6) && defined(AF_INET6) 1828 struct addrinfo *localhostaddr; 1829 struct addrinfo *otherhostaddr; 1830 struct addrinfo *i, *j; 1831 int equiv = 0; 1832 1833 if (getaddrinfo(hostnamebuf, NULL, NULL, &localhostaddr) != 0) 1834 return 0; 1835 if (getaddrinfo(host, NULL, NULL, &otherhostaddr) != 0) { 1836 freeaddrinfo(localhostaddr); 1837 return 0; 1838 } 1839 1840 for (i = localhostaddr; i != NULL && equiv == 0; i = i->ai_next) { 1841 for (j = otherhostaddr; j != NULL && equiv == 0; j = j->ai_next) { 1842 if (i->ai_family == j->ai_family) { 1843 if (i->ai_family == AF_INET) { 1844 struct sockaddr_in *sinA 1845 = (struct sockaddr_in *) i->ai_addr; 1846 struct sockaddr_in *sinB 1847 = (struct sockaddr_in *) j->ai_addr; 1848 struct in_addr *A = &sinA->sin_addr; 1849 struct in_addr *B = &sinB->sin_addr; 1850 1851 if (memcmp(A,B,sizeof(struct in_addr)) == 0) { 1852 equiv = 1; 1853 } 1854 } else if (i->ai_family == AF_INET6) { 1855 struct sockaddr_in6 *sinA 1856 = (struct sockaddr_in6 *) i->ai_addr; 1857 struct sockaddr_in6 *sinB 1858 = (struct sockaddr_in6 *) j->ai_addr; 1859 struct in6_addr *A = &sinA->sin6_addr; 1860 struct in6_addr *B = &sinB->sin6_addr; 1861 1862 if (memcmp(A,B,sizeof(struct in6_addr)) == 0) { 1863 equiv = 1; 1864 } 1865 } 1866 } 1867 } 1868 } 1869 1870 freeaddrinfo(localhostaddr); 1871 freeaddrinfo(otherhostaddr); 1872 return equiv; 1873#else 1874 /* 1875 * A host may have more than one network address. If any of the 1876 * network addresses of 'host' (specified to the connect call) 1877 * match any of the network addresses of 'hostname' (determined 1878 * by TRANS(GetHostname)), then the two hostnames are equivalent, 1879 * and we know that 'host' is really a local host. 1880 */ 1881 char specified_local_addr_list[10][4]; 1882 int scount, equiv, i, j; 1883#ifdef XTHREADS_NEEDS_BYNAMEPARAMS 1884 _Xgethostbynameparams hparams; 1885#endif 1886 struct hostent *hostp; 1887 1888 if ((hostp = _XGethostbyname (host,hparams)) == NULL) 1889 return (0); 1890 1891 scount = 0; 1892 while (hostp->h_addr_list[scount] && scount <= 8) 1893 { 1894 /* 1895 * The 2nd call to gethostname() overrides the data 1896 * from the 1st call, so we must save the address list. 1897 */ 1898 1899 specified_local_addr_list[scount][0] = 1900 hostp->h_addr_list[scount][0]; 1901 specified_local_addr_list[scount][1] = 1902 hostp->h_addr_list[scount][1]; 1903 specified_local_addr_list[scount][2] = 1904 hostp->h_addr_list[scount][2]; 1905 specified_local_addr_list[scount][3] = 1906 hostp->h_addr_list[scount][3]; 1907 scount++; 1908 } 1909 if ((hostp = _XGethostbyname (hostnamebuf,hparams)) == NULL) 1910 return (0); 1911 1912 equiv = 0; 1913 i = 0; 1914 1915 while (i < scount && !equiv) 1916 { 1917 j = 0; 1918 1919 while (hostp->h_addr_list[j]) 1920 { 1921 if ((specified_local_addr_list[i][0] == 1922 hostp->h_addr_list[j][0]) && 1923 (specified_local_addr_list[i][1] == 1924 hostp->h_addr_list[j][1]) && 1925 (specified_local_addr_list[i][2] == 1926 hostp->h_addr_list[j][2]) && 1927 (specified_local_addr_list[i][3] == 1928 hostp->h_addr_list[j][3])) 1929 { 1930 /* They're equal, so we're done */ 1931 1932 equiv = 1; 1933 break; 1934 } 1935 1936 j++; 1937 } 1938 1939 i++; 1940 } 1941 return (equiv); 1942#endif 1943 } 1944} 1945 1946static int 1947TRANS(SocketUNIXConnect) (XtransConnInfo ciptr, char *host, char *port) 1948 1949{ 1950 struct sockaddr_un sockname; 1951 SOCKLEN_T namelen; 1952 1953 1954 int abstract = 0; 1955#ifdef HAVE_ABSTRACT_SOCKETS 1956 abstract = ciptr->transptr->flags & TRANS_ABSTRACT; 1957#endif 1958 1959 prmsg (2,"SocketUNIXConnect(%d,%s,%s)\n", ciptr->fd, host, port); 1960 1961 /* 1962 * Make sure 'host' is really local. If not, we return failure. 1963 * The reason we make this check is because a process may advertise 1964 * a "local" network ID for which it can accept connections, but if 1965 * a process on a remote machine tries to connect to this network ID, 1966 * we know for sure it will fail. 1967 */ 1968 1969 if (host && *host && host[0]!='/' && strcmp (host, "unix") != 0 && !UnixHostReallyLocal (host)) 1970 { 1971 prmsg (1, 1972 "SocketUNIXConnect: Cannot connect to non-local host %s\n", 1973 host); 1974 return TRANS_CONNECT_FAILED; 1975 } 1976 1977 1978 /* 1979 * Check the port. 1980 */ 1981 1982 if (!port || !*port) 1983 { 1984 prmsg (1,"SocketUNIXConnect: Missing port specification\n"); 1985 return TRANS_CONNECT_FAILED; 1986 } 1987 1988 /* 1989 * Build the socket name. 1990 */ 1991 1992 sockname.sun_family = AF_UNIX; 1993 1994 if (set_sun_path(port, UNIX_PATH, sockname.sun_path, abstract) != 0) { 1995 prmsg (1, "SocketUNIXConnect: path too long\n"); 1996 return TRANS_CONNECT_FAILED; 1997 } 1998 1999#if (defined(BSD44SOCKETS) || defined(__UNIXWARE__)) 2000 sockname.sun_len = strlen (sockname.sun_path); 2001#endif 2002 2003#if defined(BSD44SOCKETS) || defined(SUN_LEN) 2004 namelen = SUN_LEN (&sockname); 2005#else 2006 namelen = strlen (sockname.sun_path) + offsetof(struct sockaddr_un, sun_path); 2007#endif 2008 2009 2010 2011 /* 2012 * Adjust the socket path if using abstract sockets. 2013 * Done here because otherwise all the strlen() calls above would fail. 2014 */ 2015 2016 if (abstract) { 2017 sockname.sun_path[0] = '\0'; 2018 } 2019 2020 /* 2021 * Do the connect() 2022 */ 2023 2024 if (connect (ciptr->fd, (struct sockaddr *) &sockname, namelen) < 0) 2025 { 2026 int olderrno = errno; 2027 int connected = 0; 2028 2029 if (!connected) 2030 { 2031 errno = olderrno; 2032 2033 /* 2034 * If the error was ENOENT, the server may be starting up; we used 2035 * to suggest to try again in this case with 2036 * TRANS_TRY_CONNECT_AGAIN, but this introduced problems for 2037 * processes still referencing stale sockets in their environment. 2038 * Hence, we now return a hard error, TRANS_CONNECT_FAILED, and it 2039 * is suggested that higher level stacks handle retries on their 2040 * level when they face a slow starting server. 2041 * 2042 * If the error was EWOULDBLOCK or EINPROGRESS then the socket 2043 * was non-blocking and we should poll using select 2044 * 2045 * If the error was EINTR, the connect was interrupted and we 2046 * should try again. 2047 */ 2048 2049 if (olderrno == EWOULDBLOCK || olderrno == EINPROGRESS) 2050 return TRANS_IN_PROGRESS; 2051 else if (olderrno == EINTR) 2052 return TRANS_TRY_CONNECT_AGAIN; 2053 else if (olderrno == ENOENT || olderrno == ECONNREFUSED) { 2054 /* If opening as abstract socket failed, try again normally */ 2055 if (abstract) { 2056 ciptr->transptr->flags &= ~(TRANS_ABSTRACT); 2057 return TRANS_TRY_CONNECT_AGAIN; 2058 } else { 2059 return TRANS_CONNECT_FAILED; 2060 } 2061 } else { 2062 prmsg (2,"SocketUNIXConnect: Can't connect: errno = %d\n", 2063 EGET()); 2064 2065 return TRANS_CONNECT_FAILED; 2066 } 2067 } 2068 } 2069 2070 /* 2071 * Get the socket name and the peer name from the connect socket, 2072 * since this is unix domain. 2073 */ 2074 2075 if ((ciptr->addr = malloc(namelen)) == NULL || 2076 (ciptr->peeraddr = malloc(namelen)) == NULL) 2077 { 2078 prmsg (1, 2079 "SocketUNIXCreateListener: Can't allocate space for the addr\n"); 2080 return TRANS_CONNECT_FAILED; 2081 } 2082 2083 if (abstract) 2084 sockname.sun_path[0] = '@'; 2085 2086 ciptr->family = AF_UNIX; 2087 ciptr->addrlen = namelen; 2088 ciptr->peeraddrlen = namelen; 2089 memcpy (ciptr->addr, &sockname, ciptr->addrlen); 2090 memcpy (ciptr->peeraddr, &sockname, ciptr->peeraddrlen); 2091 2092 return 0; 2093} 2094 2095#endif /* UNIXCONN */ 2096 2097#endif /* TRANS_CLIENT */ 2098 2099 2100static int 2101TRANS(SocketBytesReadable) (XtransConnInfo ciptr, BytesReadable_t *pend) 2102 2103{ 2104 prmsg (2,"SocketBytesReadable(%p,%d,%p)\n", 2105 ciptr, ciptr->fd, pend); 2106#ifdef WIN32 2107 { 2108 int ret = ioctlsocket ((SOCKET) ciptr->fd, FIONREAD, (u_long *) pend); 2109 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2110 return ret; 2111 } 2112#else 2113#if defined(__i386__) && defined(SYSV) && !defined(SCO325) 2114 return ioctl (ciptr->fd, I_NREAD, (char *) pend); 2115#else 2116 return ioctl (ciptr->fd, FIONREAD, (char *) pend); 2117#endif /* __i386__ && SYSV || _SEQUENT_ && _SOCKET_VERSION == 1 */ 2118#endif /* WIN32 */ 2119} 2120 2121#if XTRANS_SEND_FDS 2122 2123static void 2124appendFd(struct _XtransConnFd **prev, int fd, int do_close) 2125{ 2126 struct _XtransConnFd *cf, *new; 2127 2128 new = malloc (sizeof (struct _XtransConnFd)); 2129 if (!new) { 2130 /* XXX mark connection as broken */ 2131 close(fd); 2132 return; 2133 } 2134 new->next = 0; 2135 new->fd = fd; 2136 new->do_close = do_close; 2137 /* search to end of list */ 2138 for (; (cf = *prev); prev = &(cf->next)); 2139 *prev = new; 2140} 2141 2142static int 2143removeFd(struct _XtransConnFd **prev) 2144{ 2145 struct _XtransConnFd *cf; 2146 int fd; 2147 2148 if ((cf = *prev)) { 2149 *prev = cf->next; 2150 fd = cf->fd; 2151 free(cf); 2152 } else 2153 fd = -1; 2154 return fd; 2155} 2156 2157static void 2158discardFd(struct _XtransConnFd **prev, struct _XtransConnFd *upto, int do_close) 2159{ 2160 struct _XtransConnFd *cf, *next; 2161 2162 for (cf = *prev; cf != upto; cf = next) { 2163 next = cf->next; 2164 if (do_close || cf->do_close) 2165 close(cf->fd); 2166 free(cf); 2167 } 2168 *prev = upto; 2169} 2170 2171static void 2172cleanupFds(XtransConnInfo ciptr) 2173{ 2174 /* Clean up the send list but don't close the fds */ 2175 discardFd(&ciptr->send_fds, NULL, 0); 2176 /* Clean up the recv list and *do* close the fds */ 2177 discardFd(&ciptr->recv_fds, NULL, 1); 2178} 2179 2180static int 2181nFd(struct _XtransConnFd **prev) 2182{ 2183 struct _XtransConnFd *cf; 2184 int n = 0; 2185 2186 for (cf = *prev; cf; cf = cf->next) 2187 n++; 2188 return n; 2189} 2190 2191static int 2192TRANS(SocketRecvFd) (XtransConnInfo ciptr) 2193{ 2194 prmsg (2, "SocketRecvFd(%d)\n", ciptr->fd); 2195 return removeFd(&ciptr->recv_fds); 2196} 2197 2198static int 2199TRANS(SocketSendFd) (XtransConnInfo ciptr, int fd, int do_close) 2200{ 2201 appendFd(&ciptr->send_fds, fd, do_close); 2202 return 0; 2203} 2204 2205static int 2206TRANS(SocketRecvFdInvalid)(XtransConnInfo ciptr) 2207{ 2208 errno = EINVAL; 2209 return -1; 2210} 2211 2212static int 2213TRANS(SocketSendFdInvalid)(XtransConnInfo ciptr, int fd, int do_close) 2214{ 2215 errno = EINVAL; 2216 return -1; 2217} 2218 2219#define MAX_FDS 128 2220 2221union fd_pass { 2222 struct cmsghdr cmsghdr; 2223 char buf[CMSG_SPACE(MAX_FDS * sizeof(int))]; 2224}; 2225 2226#endif /* XTRANS_SEND_FDS */ 2227 2228static int 2229TRANS(SocketRead) (XtransConnInfo ciptr, char *buf, int size) 2230 2231{ 2232 prmsg (2,"SocketRead(%d,%p,%d)\n", ciptr->fd, buf, size); 2233 2234#if defined(WIN32) 2235 { 2236 int ret = recv ((SOCKET)ciptr->fd, buf, size, 0); 2237#ifdef WIN32 2238 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2239#endif 2240 return ret; 2241 } 2242#else 2243#if XTRANS_SEND_FDS 2244 { 2245 struct iovec iov = { 2246 .iov_base = buf, 2247 .iov_len = size 2248 }; 2249 union fd_pass cmsgbuf; 2250 struct msghdr msg = { 2251 .msg_name = NULL, 2252 .msg_namelen = 0, 2253 .msg_iov = &iov, 2254 .msg_iovlen = 1, 2255 .msg_control = cmsgbuf.buf, 2256 .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int)) 2257 }; 2258 2259 size = recvmsg(ciptr->fd, &msg, 0); 2260 if (size >= 0) { 2261 struct cmsghdr *hdr; 2262 2263 for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { 2264 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { 2265 int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int); 2266 int i; 2267 int *fd = (int *) CMSG_DATA(hdr); 2268 2269 for (i = 0; i < nfd; i++) 2270 appendFd(&ciptr->recv_fds, fd[i], 0); 2271 } 2272 } 2273 } 2274 return size; 2275 } 2276#else 2277 return read(ciptr->fd, buf, size); 2278#endif /* XTRANS_SEND_FDS */ 2279#endif /* WIN32 */ 2280} 2281 2282static int 2283TRANS(SocketReadv) (XtransConnInfo ciptr, struct iovec *buf, int size) 2284 2285{ 2286 prmsg (2,"SocketReadv(%d,%p,%d)\n", ciptr->fd, buf, size); 2287 2288#if XTRANS_SEND_FDS 2289 { 2290 union fd_pass cmsgbuf; 2291 struct msghdr msg = { 2292 .msg_name = NULL, 2293 .msg_namelen = 0, 2294 .msg_iov = buf, 2295 .msg_iovlen = size, 2296 .msg_control = cmsgbuf.buf, 2297 .msg_controllen = CMSG_LEN(MAX_FDS * sizeof(int)) 2298 }; 2299 2300 size = recvmsg(ciptr->fd, &msg, 0); 2301 if (size >= 0) { 2302 struct cmsghdr *hdr; 2303 2304 for (hdr = CMSG_FIRSTHDR(&msg); hdr; hdr = CMSG_NXTHDR(&msg, hdr)) { 2305 if (hdr->cmsg_level == SOL_SOCKET && hdr->cmsg_type == SCM_RIGHTS) { 2306 int nfd = (hdr->cmsg_len - CMSG_LEN(0)) / sizeof (int); 2307 int i; 2308 int *fd = (int *) CMSG_DATA(hdr); 2309 2310 for (i = 0; i < nfd; i++) 2311 appendFd(&ciptr->recv_fds, fd[i], 0); 2312 } 2313 } 2314 } 2315 return size; 2316 } 2317#else 2318 return READV (ciptr, buf, size); 2319#endif 2320} 2321 2322 2323static int 2324TRANS(SocketWritev) (XtransConnInfo ciptr, struct iovec *buf, int size) 2325 2326{ 2327 prmsg (2,"SocketWritev(%d,%p,%d)\n", ciptr->fd, buf, size); 2328 2329#if XTRANS_SEND_FDS 2330 if (ciptr->send_fds) 2331 { 2332 union fd_pass cmsgbuf; 2333 int nfd = nFd(&ciptr->send_fds); 2334 struct _XtransConnFd *cf = ciptr->send_fds; 2335 struct msghdr msg = { 2336 .msg_name = NULL, 2337 .msg_namelen = 0, 2338 .msg_iov = buf, 2339 .msg_iovlen = size, 2340 .msg_control = cmsgbuf.buf, 2341 .msg_controllen = CMSG_LEN(nfd * sizeof(int)) 2342 }; 2343 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); 2344 int i; 2345 int *fds; 2346 2347 hdr->cmsg_len = msg.msg_controllen; 2348 hdr->cmsg_level = SOL_SOCKET; 2349 hdr->cmsg_type = SCM_RIGHTS; 2350 2351 fds = (int *) CMSG_DATA(hdr); 2352 /* Set up fds */ 2353 for (i = 0; i < nfd; i++) { 2354 fds[i] = cf->fd; 2355 cf = cf->next; 2356 } 2357 2358 i = sendmsg(ciptr->fd, &msg, 0); 2359 if (i > 0) 2360 discardFd(&ciptr->send_fds, cf, 0); 2361 return i; 2362 } 2363#endif 2364 return WRITEV (ciptr, buf, size); 2365} 2366 2367 2368static int 2369TRANS(SocketWrite) (XtransConnInfo ciptr, char *buf, int size) 2370 2371{ 2372 prmsg (2,"SocketWrite(%d,%p,%d)\n", ciptr->fd, buf, size); 2373 2374#if defined(WIN32) 2375 { 2376 int ret = send ((SOCKET)ciptr->fd, buf, size, 0); 2377#ifdef WIN32 2378 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2379#endif 2380 return ret; 2381 } 2382#else 2383#if XTRANS_SEND_FDS 2384 if (ciptr->send_fds) 2385 { 2386 struct iovec iov; 2387 2388 iov.iov_base = buf; 2389 iov.iov_len = size; 2390 return TRANS(SocketWritev)(ciptr, &iov, 1); 2391 } 2392#endif /* XTRANS_SEND_FDS */ 2393 return write (ciptr->fd, buf, size); 2394#endif /* WIN32 */ 2395} 2396 2397static int 2398TRANS(SocketDisconnect) (XtransConnInfo ciptr) 2399 2400{ 2401 prmsg (2,"SocketDisconnect(%p,%d)\n", ciptr, ciptr->fd); 2402 2403#ifdef WIN32 2404 { 2405 int ret = shutdown (ciptr->fd, 2); 2406 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2407 return ret; 2408 } 2409#else 2410 return shutdown (ciptr->fd, 2); /* disallow further sends and receives */ 2411#endif 2412} 2413 2414 2415#ifdef TCPCONN 2416static int 2417TRANS(SocketINETClose) (XtransConnInfo ciptr) 2418 2419{ 2420 prmsg (2,"SocketINETClose(%p,%d)\n", ciptr, ciptr->fd); 2421 2422#ifdef WIN32 2423 { 2424 int ret = close (ciptr->fd); 2425 if (ret == SOCKET_ERROR) errno = WSAGetLastError(); 2426 return ret; 2427 } 2428#else 2429 return close (ciptr->fd); 2430#endif 2431} 2432 2433#endif /* TCPCONN */ 2434 2435 2436#ifdef UNIXCONN 2437static int 2438TRANS(SocketUNIXClose) (XtransConnInfo ciptr) 2439{ 2440 /* 2441 * If this is the server side, then once the socket is closed, 2442 * it must be unlinked to completely close it 2443 */ 2444 2445 struct sockaddr_un *sockname = (struct sockaddr_un *) ciptr->addr; 2446 int ret; 2447 2448 prmsg (2,"SocketUNIXClose(%p,%d)\n", ciptr, ciptr->fd); 2449 2450#if XTRANS_SEND_FDS 2451 cleanupFds(ciptr); 2452#endif 2453 ret = close(ciptr->fd); 2454 2455 if (ciptr->flags 2456 && sockname 2457 && sockname->sun_family == AF_UNIX 2458 && sockname->sun_path[0]) 2459 { 2460 if (!(ciptr->flags & TRANS_NOUNLINK 2461 || ciptr->transptr->flags & TRANS_ABSTRACT)) 2462 unlink (sockname->sun_path); 2463 } 2464 2465 return ret; 2466} 2467 2468static int 2469TRANS(SocketUNIXCloseForCloning) (XtransConnInfo ciptr) 2470 2471{ 2472 /* 2473 * Don't unlink path. 2474 */ 2475 2476 int ret; 2477 2478 prmsg (2,"SocketUNIXCloseForCloning(%p,%d)\n", 2479 ciptr, ciptr->fd); 2480 2481#if XTRANS_SEND_FDS 2482 cleanupFds(ciptr); 2483#endif 2484 ret = close(ciptr->fd); 2485 2486 return ret; 2487} 2488 2489#endif /* UNIXCONN */ 2490 2491 2492#ifdef TCPCONN 2493# ifdef TRANS_SERVER 2494static const char* tcp_nolisten[] = { 2495 "inet", 2496#if defined(IPv6) && defined(AF_INET6) 2497 "inet6", 2498#endif 2499 NULL 2500}; 2501# endif 2502 2503Xtransport TRANS(SocketTCPFuncs) = { 2504 /* Socket Interface */ 2505 "tcp", 2506 TRANS_ALIAS, 2507#ifdef TRANS_CLIENT 2508 TRANS(SocketOpenCOTSClient), 2509#endif /* TRANS_CLIENT */ 2510#ifdef TRANS_SERVER 2511 tcp_nolisten, 2512 TRANS(SocketOpenCOTSServer), 2513#endif /* TRANS_SERVER */ 2514#ifdef TRANS_CLIENT 2515 TRANS(SocketOpenCLTSClient), 2516#endif /* TRANS_CLIENT */ 2517#ifdef TRANS_SERVER 2518 TRANS(SocketOpenCLTSServer), 2519#endif /* TRANS_SERVER */ 2520#ifdef TRANS_REOPEN 2521 TRANS(SocketReopenCOTSServer), 2522 TRANS(SocketReopenCLTSServer), 2523#endif 2524 TRANS(SocketSetOption), 2525#ifdef TRANS_SERVER 2526 TRANS(SocketINETCreateListener), 2527 NULL, /* ResetListener */ 2528 TRANS(SocketINETAccept), 2529#endif /* TRANS_SERVER */ 2530#ifdef TRANS_CLIENT 2531 TRANS(SocketINETConnect), 2532#endif /* TRANS_CLIENT */ 2533 TRANS(SocketBytesReadable), 2534 TRANS(SocketRead), 2535 TRANS(SocketWrite), 2536 TRANS(SocketReadv), 2537 TRANS(SocketWritev), 2538#if XTRANS_SEND_FDS 2539 TRANS(SocketSendFdInvalid), 2540 TRANS(SocketRecvFdInvalid), 2541#endif 2542 TRANS(SocketDisconnect), 2543 TRANS(SocketINETClose), 2544 TRANS(SocketINETClose), 2545 }; 2546 2547Xtransport TRANS(SocketINETFuncs) = { 2548 /* Socket Interface */ 2549 "inet", 2550 0, 2551#ifdef TRANS_CLIENT 2552 TRANS(SocketOpenCOTSClient), 2553#endif /* TRANS_CLIENT */ 2554#ifdef TRANS_SERVER 2555 NULL, 2556 TRANS(SocketOpenCOTSServer), 2557#endif /* TRANS_SERVER */ 2558#ifdef TRANS_CLIENT 2559 TRANS(SocketOpenCLTSClient), 2560#endif /* TRANS_CLIENT */ 2561#ifdef TRANS_SERVER 2562 TRANS(SocketOpenCLTSServer), 2563#endif /* TRANS_SERVER */ 2564#ifdef TRANS_REOPEN 2565 TRANS(SocketReopenCOTSServer), 2566 TRANS(SocketReopenCLTSServer), 2567#endif 2568 TRANS(SocketSetOption), 2569#ifdef TRANS_SERVER 2570 TRANS(SocketINETCreateListener), 2571 NULL, /* ResetListener */ 2572 TRANS(SocketINETAccept), 2573#endif /* TRANS_SERVER */ 2574#ifdef TRANS_CLIENT 2575 TRANS(SocketINETConnect), 2576#endif /* TRANS_CLIENT */ 2577 TRANS(SocketBytesReadable), 2578 TRANS(SocketRead), 2579 TRANS(SocketWrite), 2580 TRANS(SocketReadv), 2581 TRANS(SocketWritev), 2582#if XTRANS_SEND_FDS 2583 TRANS(SocketSendFdInvalid), 2584 TRANS(SocketRecvFdInvalid), 2585#endif 2586 TRANS(SocketDisconnect), 2587 TRANS(SocketINETClose), 2588 TRANS(SocketINETClose), 2589 }; 2590 2591#if defined(IPv6) && defined(AF_INET6) 2592Xtransport TRANS(SocketINET6Funcs) = { 2593 /* Socket Interface */ 2594 "inet6", 2595 0, 2596#ifdef TRANS_CLIENT 2597 TRANS(SocketOpenCOTSClient), 2598#endif /* TRANS_CLIENT */ 2599#ifdef TRANS_SERVER 2600 NULL, 2601 TRANS(SocketOpenCOTSServer), 2602#endif /* TRANS_SERVER */ 2603#ifdef TRANS_CLIENT 2604 TRANS(SocketOpenCLTSClient), 2605#endif /* TRANS_CLIENT */ 2606#ifdef TRANS_SERVER 2607 TRANS(SocketOpenCLTSServer), 2608#endif /* TRANS_SERVER */ 2609#ifdef TRANS_REOPEN 2610 TRANS(SocketReopenCOTSServer), 2611 TRANS(SocketReopenCLTSServer), 2612#endif 2613 TRANS(SocketSetOption), 2614#ifdef TRANS_SERVER 2615 TRANS(SocketINETCreateListener), 2616 NULL, /* ResetListener */ 2617 TRANS(SocketINETAccept), 2618#endif /* TRANS_SERVER */ 2619#ifdef TRANS_CLIENT 2620 TRANS(SocketINETConnect), 2621#endif /* TRANS_CLIENT */ 2622 TRANS(SocketBytesReadable), 2623 TRANS(SocketRead), 2624 TRANS(SocketWrite), 2625 TRANS(SocketReadv), 2626 TRANS(SocketWritev), 2627#if XTRANS_SEND_FDS 2628 TRANS(SocketSendFdInvalid), 2629 TRANS(SocketRecvFdInvalid), 2630#endif 2631 TRANS(SocketDisconnect), 2632 TRANS(SocketINETClose), 2633 TRANS(SocketINETClose), 2634 }; 2635#endif /* IPv6 */ 2636#endif /* TCPCONN */ 2637 2638#ifdef UNIXCONN 2639#if !defined(LOCALCONN) 2640Xtransport TRANS(SocketLocalFuncs) = { 2641 /* Socket Interface */ 2642 "local", 2643#ifdef HAVE_ABSTRACT_SOCKETS 2644 TRANS_ABSTRACT, 2645#else 2646 0, 2647#endif 2648#ifdef TRANS_CLIENT 2649 TRANS(SocketOpenCOTSClient), 2650#endif /* TRANS_CLIENT */ 2651#ifdef TRANS_SERVER 2652 NULL, 2653 TRANS(SocketOpenCOTSServer), 2654#endif /* TRANS_SERVER */ 2655#ifdef TRANS_CLIENT 2656 TRANS(SocketOpenCLTSClient), 2657#endif /* TRANS_CLIENT */ 2658#ifdef TRANS_SERVER 2659 TRANS(SocketOpenCLTSServer), 2660#endif /* TRANS_SERVER */ 2661#ifdef TRANS_REOPEN 2662 TRANS(SocketReopenCOTSServer), 2663 TRANS(SocketReopenCLTSServer), 2664#endif 2665 TRANS(SocketSetOption), 2666#ifdef TRANS_SERVER 2667 TRANS(SocketUNIXCreateListener), 2668 TRANS(SocketUNIXResetListener), 2669 TRANS(SocketUNIXAccept), 2670#endif /* TRANS_SERVER */ 2671#ifdef TRANS_CLIENT 2672 TRANS(SocketUNIXConnect), 2673#endif /* TRANS_CLIENT */ 2674 TRANS(SocketBytesReadable), 2675 TRANS(SocketRead), 2676 TRANS(SocketWrite), 2677 TRANS(SocketReadv), 2678 TRANS(SocketWritev), 2679#if XTRANS_SEND_FDS 2680 TRANS(SocketSendFd), 2681 TRANS(SocketRecvFd), 2682#endif 2683 TRANS(SocketDisconnect), 2684 TRANS(SocketUNIXClose), 2685 TRANS(SocketUNIXCloseForCloning), 2686 }; 2687#endif /* !LOCALCONN */ 2688# ifdef TRANS_SERVER 2689# if !defined(LOCALCONN) 2690static const char* unix_nolisten[] = { "local" , NULL }; 2691# endif 2692# endif 2693 2694Xtransport TRANS(SocketUNIXFuncs) = { 2695 /* Socket Interface */ 2696 "unix", 2697#if !defined(LOCALCONN) && !defined(HAVE_ABSTRACT_SOCKETS) 2698 TRANS_ALIAS, 2699#else 2700 0, 2701#endif 2702#ifdef TRANS_CLIENT 2703 TRANS(SocketOpenCOTSClient), 2704#endif /* TRANS_CLIENT */ 2705#ifdef TRANS_SERVER 2706#if !defined(LOCALCONN) 2707 unix_nolisten, 2708#else 2709 NULL, 2710#endif 2711 TRANS(SocketOpenCOTSServer), 2712#endif /* TRANS_SERVER */ 2713#ifdef TRANS_CLIENT 2714 TRANS(SocketOpenCLTSClient), 2715#endif /* TRANS_CLIENT */ 2716#ifdef TRANS_SERVER 2717 TRANS(SocketOpenCLTSServer), 2718#endif /* TRANS_SERVER */ 2719#ifdef TRANS_REOPEN 2720 TRANS(SocketReopenCOTSServer), 2721 TRANS(SocketReopenCLTSServer), 2722#endif 2723 TRANS(SocketSetOption), 2724#ifdef TRANS_SERVER 2725 TRANS(SocketUNIXCreateListener), 2726 TRANS(SocketUNIXResetListener), 2727 TRANS(SocketUNIXAccept), 2728#endif /* TRANS_SERVER */ 2729#ifdef TRANS_CLIENT 2730 TRANS(SocketUNIXConnect), 2731#endif /* TRANS_CLIENT */ 2732 TRANS(SocketBytesReadable), 2733 TRANS(SocketRead), 2734 TRANS(SocketWrite), 2735 TRANS(SocketReadv), 2736 TRANS(SocketWritev), 2737#if XTRANS_SEND_FDS 2738 TRANS(SocketSendFd), 2739 TRANS(SocketRecvFd), 2740#endif 2741 TRANS(SocketDisconnect), 2742 TRANS(SocketUNIXClose), 2743 TRANS(SocketUNIXCloseForCloning), 2744 }; 2745 2746#endif /* UNIXCONN */ 2747