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