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