1/* $NetBSD: rpc_generic.c,v 1.30 2017/05/03 21:39:27 christos Exp $ */ 2 3/* 4 * Copyright (c) 2010, Oracle America, Inc. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are 8 * met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above 13 * copyright notice, this list of conditions and the following 14 * disclaimer in the documentation and/or other materials 15 * provided with the distribution. 16 * * Neither the name of the "Oracle America, Inc." nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33/* 34 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 35 */ 36 37/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ 38 39/* 40 * rpc_generic.c, Miscl routines for RPC. 41 * 42 */ 43 44#include <sys/cdefs.h> 45#if defined(LIBC_SCCS) && !defined(lint) 46__RCSID("$NetBSD: rpc_generic.c,v 1.30 2017/05/03 21:39:27 christos Exp $"); 47#endif 48 49#include "namespace.h" 50#include "reentrant.h" 51#include <sys/types.h> 52#include <sys/param.h> 53#include <sys/socket.h> 54#include <sys/un.h> 55#include <sys/resource.h> 56#include <netinet/in.h> 57#include <netinet/tcp.h> 58#include <arpa/inet.h> 59#include <rpc/rpc.h> 60#include <assert.h> 61#include <ctype.h> 62#include <stdio.h> 63#include <netdb.h> 64#include <netconfig.h> 65#include <stdlib.h> 66#include <string.h> 67#include <syslog.h> 68#include <rpc/nettype.h> 69 70#include "svc_fdset.h" 71#include "rpc_internal.h" 72 73#ifdef __weak_alias 74__weak_alias(taddr2uaddr,_taddr2uaddr) 75__weak_alias(uaddr2taddr,_uaddr2taddr) 76#endif 77 78struct handle { 79 NCONF_HANDLE *nhandle; 80 int nflag; /* Whether NETPATH or NETCONFIG */ 81 int nettype; 82}; 83 84static const struct _rpcnettype { 85 const char *name; 86 const int type; 87} _rpctypelist[] = { 88 { "netpath", _RPC_NETPATH }, 89 { "visible", _RPC_VISIBLE }, 90 { "circuit_v", _RPC_CIRCUIT_V }, 91 { "datagram_v", _RPC_DATAGRAM_V }, 92 { "circuit_n", _RPC_CIRCUIT_N }, 93 { "datagram_n", _RPC_DATAGRAM_N }, 94 { "tcp", _RPC_TCP }, 95 { "udp", _RPC_UDP }, 96 { 0, _RPC_NONE } 97}; 98 99struct netid_af { 100 const char *netid; 101 int af; 102 int protocol; 103}; 104 105static const struct netid_af na_cvt[] = { 106 { "udp", AF_INET, IPPROTO_UDP }, 107 { "tcp", AF_INET, IPPROTO_TCP }, 108#ifdef INET6 109 { "udp6", AF_INET6, IPPROTO_UDP }, 110 { "tcp6", AF_INET6, IPPROTO_TCP }, 111#endif 112 { "local", AF_LOCAL, 0 } 113}; 114 115#if 0 116static char *strlocase(char *); 117#endif 118static int getnettype(const char *); 119 120/* 121 * Cache the result of getrlimit(), so we don't have to do an 122 * expensive call every time. 123 */ 124int 125__rpc_dtbsize(void) 126{ 127 static int tbsize; 128 struct rlimit rl; 129 130 if (tbsize) { 131 return (tbsize); 132 } 133 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 134 return (tbsize = (int)rl.rlim_max); 135 } 136 /* 137 * Something wrong. I'll try to save face by returning a 138 * pessimistic number. 139 */ 140 return (32); 141} 142 143 144/* 145 * Find the appropriate buffer size 146 */ 147u_int 148/*ARGSUSED*/ 149__rpc_get_t_size( 150 int af, 151 int proto, 152 int size) /* Size requested */ 153{ 154 int maxsize, defsize; 155 156 maxsize = 256 * 1024; /* XXX */ 157 switch (proto) { 158 case IPPROTO_TCP: 159 defsize = 64 * 1024; /* XXX */ 160 break; 161 case IPPROTO_UDP: 162 defsize = UDPMSGSIZE; 163 break; 164 default: 165 defsize = RPC_MAXDATASIZE; 166 break; 167 } 168 if (size == 0) 169 return defsize; 170 171 /* Check whether the value is within the upper max limit */ 172 return (size > maxsize ? (u_int)maxsize : (u_int)size); 173} 174 175/* 176 * Find the appropriate address buffer size 177 */ 178u_int 179__rpc_get_a_size(int af) 180{ 181 switch (af) { 182 case AF_INET: 183 return sizeof (struct sockaddr_in); 184#ifdef INET6 185 case AF_INET6: 186 return sizeof (struct sockaddr_in6); 187#endif 188 case AF_LOCAL: 189 return sizeof (struct sockaddr_un); 190 default: 191 break; 192 } 193 return ((u_int)RPC_MAXADDRSIZE); 194} 195 196#if 0 197static char * 198strlocase(char *p) 199{ 200 char *t = p; 201 202 _DIAGASSERT(p != NULL); 203 204 for (; *p; p++) 205 if (isupper(*p)) 206 *p = tolower(*p); 207 return (t); 208} 209#endif 210 211/* 212 * Returns the type of the network as defined in <rpc/nettype.h> 213 * If nettype is NULL, it defaults to NETPATH. 214 */ 215static int 216getnettype(const char *nettype) 217{ 218 int i; 219 220 if ((nettype == NULL) || (nettype[0] == 0)) { 221 return (_RPC_NETPATH); /* Default */ 222 } 223 224#if 0 225 nettype = strlocase(nettype); 226#endif 227 for (i = 0; _rpctypelist[i].name; i++) 228 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 229 return (_rpctypelist[i].type); 230 } 231 return (_rpctypelist[i].type); 232} 233 234/* 235 * For the given nettype (tcp or udp only), return the first structure found. 236 * This should be freed by calling freenetconfigent() 237 */ 238 239#ifdef _REENTRANT 240static thread_key_t tcp_key, udp_key; 241static once_t __rpc_getconfigp_once = ONCE_INITIALIZER; 242 243static void 244__rpc_getconfigp_setup(void) 245{ 246 247 thr_keycreate(&tcp_key, free); 248 thr_keycreate(&udp_key, free); 249} 250#endif 251 252struct netconfig * 253__rpc_getconfip(const char *nettype) 254{ 255 char *netid; 256 char *netid_tcp = NULL; 257 char *netid_udp = NULL; 258 static char *netid_tcp_main; 259 static char *netid_udp_main; 260 struct netconfig *dummy; 261#ifdef _REENTRANT 262 if (__isthreaded == 0) { 263 netid_udp = netid_udp_main; 264 netid_tcp = netid_tcp_main; 265 } else { 266 thr_once(&__rpc_getconfigp_once, __rpc_getconfigp_setup); 267 netid_tcp = thr_getspecific(tcp_key); 268 netid_udp = thr_getspecific(udp_key); 269 } 270#else 271 netid_udp = netid_udp_main; 272 netid_tcp = netid_tcp_main; 273#endif 274 275 _DIAGASSERT(nettype != NULL); 276 277 if (!netid_udp && !netid_tcp) { 278 struct netconfig *nconf; 279 void *confighandle; 280 281 if (!(confighandle = setnetconfig())) { 282 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 283 return (NULL); 284 } 285 while ((nconf = getnetconfig(confighandle)) != NULL) { 286 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 287 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 288 netid_tcp = strdup(nconf->nc_netid); 289 if (netid_tcp == NULL) 290 return NULL; 291#ifdef _REENTRANT 292 if (__isthreaded == 0) 293 netid_tcp_main = netid_tcp; 294 else 295 thr_setspecific(tcp_key, 296 (void *) netid_tcp); 297#else 298 netid_tcp_main = netid_tcp; 299#endif 300 } else 301 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 302 netid_udp = strdup(nconf->nc_netid); 303 if (netid_udp == NULL) 304 return NULL; 305#ifdef _REENTRANT 306 if (__isthreaded == 0) 307 netid_udp_main = netid_udp; 308 else 309 thr_setspecific(udp_key, 310 (void *) netid_udp); 311#else 312 netid_udp_main = netid_udp; 313#endif 314 } 315 } 316 } 317 endnetconfig(confighandle); 318 } 319 if (strcmp(nettype, "udp") == 0) 320 netid = netid_udp; 321 else if (strcmp(nettype, "tcp") == 0) 322 netid = netid_tcp; 323 else { 324 return (NULL); 325 } 326 if ((netid == NULL) || (netid[0] == 0)) { 327 return (NULL); 328 } 329 dummy = getnetconfigent(netid); 330 return (dummy); 331} 332 333/* 334 * Returns the type of the nettype, which should then be used with 335 * __rpc_getconf(). 336 */ 337void * 338__rpc_setconf(const char *nettype) 339{ 340 struct handle *handle; 341 342 /* nettype may be NULL; getnettype() supports that */ 343 344 handle = malloc(sizeof(*handle)); 345 if (handle == NULL) { 346 return (NULL); 347 } 348 switch (handle->nettype = getnettype(nettype)) { 349 case _RPC_NETPATH: 350 case _RPC_CIRCUIT_N: 351 case _RPC_DATAGRAM_N: 352 if (!(handle->nhandle = setnetpath())) { 353 free(handle); 354 return (NULL); 355 } 356 handle->nflag = TRUE; 357 break; 358 case _RPC_VISIBLE: 359 case _RPC_CIRCUIT_V: 360 case _RPC_DATAGRAM_V: 361 case _RPC_TCP: 362 case _RPC_UDP: 363 if (!(handle->nhandle = setnetconfig())) { 364 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 365 free(handle); 366 return (NULL); 367 } 368 handle->nflag = FALSE; 369 break; 370 default: 371 free(handle); 372 return (NULL); 373 } 374 375 return (handle); 376} 377 378/* 379 * Returns the next netconfig struct for the given "net" type. 380 * __rpc_setconf() should have been called previously. 381 */ 382struct netconfig * 383__rpc_getconf(void *vhandle) 384{ 385 struct handle *handle; 386 struct netconfig *nconf; 387 388 handle = (struct handle *)vhandle; 389 if (handle == NULL) { 390 return (NULL); 391 } 392 for (;;) { 393 if (handle->nflag) 394 nconf = getnetpath(handle->nhandle); 395 else 396 nconf = getnetconfig(handle->nhandle); 397 if (nconf == NULL) 398 break; 399 if ((nconf->nc_semantics != NC_TPI_CLTS) && 400 (nconf->nc_semantics != NC_TPI_COTS) && 401 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 402 continue; 403 switch (handle->nettype) { 404 case _RPC_VISIBLE: 405 if (!(nconf->nc_flag & NC_VISIBLE)) 406 continue; 407 /* FALLTHROUGH */ 408 case _RPC_NETPATH: /* Be happy */ 409 break; 410 case _RPC_CIRCUIT_V: 411 if (!(nconf->nc_flag & NC_VISIBLE)) 412 continue; 413 /* FALLTHROUGH */ 414 case _RPC_CIRCUIT_N: 415 if ((nconf->nc_semantics != NC_TPI_COTS) && 416 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 417 continue; 418 break; 419 case _RPC_DATAGRAM_V: 420 if (!(nconf->nc_flag & NC_VISIBLE)) 421 continue; 422 /* FALLTHROUGH */ 423 case _RPC_DATAGRAM_N: 424 if (nconf->nc_semantics != NC_TPI_CLTS) 425 continue; 426 break; 427 case _RPC_TCP: 428 if (((nconf->nc_semantics != NC_TPI_COTS) && 429 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 430 (strcmp(nconf->nc_protofmly, NC_INET) 431#ifdef INET6 432 && strcmp(nconf->nc_protofmly, NC_INET6)) 433#else 434 ) 435#endif 436 || 437 strcmp(nconf->nc_proto, NC_TCP)) 438 continue; 439 break; 440 case _RPC_UDP: 441 if ((nconf->nc_semantics != NC_TPI_CLTS) || 442 (strcmp(nconf->nc_protofmly, NC_INET) 443#ifdef INET6 444 && strcmp(nconf->nc_protofmly, NC_INET6)) 445#else 446 ) 447#endif 448 || 449 strcmp(nconf->nc_proto, NC_UDP)) 450 continue; 451 break; 452 } 453 break; 454 } 455 return (nconf); 456} 457 458void 459__rpc_endconf(void *vhandle) 460{ 461 struct handle *handle; 462 463 handle = (struct handle *) vhandle; 464 if (handle == NULL) { 465 return; 466 } 467 if (handle->nflag) { 468 endnetpath(handle->nhandle); 469 } else { 470 endnetconfig(handle->nhandle); 471 } 472 free(handle); 473} 474 475/* 476 * Used to ping the NULL procedure for clnt handle. 477 * Returns NULL if fails, else a non-NULL pointer. 478 */ 479void * 480rpc_nullproc(CLIENT *clnt) 481{ 482 struct timeval TIMEOUT = {25, 0}; 483 484 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 485 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 486 return (NULL); 487 } 488 return ((void *) clnt); 489} 490 491/* 492 * Try all possible transports until 493 * one succeeds in finding the netconf for the given fd. 494 */ 495struct netconfig * 496__rpcgettp(int fd) 497{ 498 const char *netid; 499 struct __rpc_sockinfo si; 500 501 if (!__rpc_fd2sockinfo(fd, &si)) 502 return NULL; 503 504 if (!__rpc_sockinfo2netid(&si, &netid)) 505 return NULL; 506 507 return getnetconfigent(__UNCONST(netid)); 508} 509 510int 511__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) 512{ 513 socklen_t len; 514 int type, proto; 515 struct sockaddr_storage ss; 516 517 _DIAGASSERT(sip != NULL); 518 519 len = sizeof ss; 520 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) 521 return 0; 522 sip->si_alen = len; 523 524 len = sizeof type; 525 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) 526 return 0; 527 528 /* XXX */ 529 if (ss.ss_family != AF_LOCAL) { 530 if (type == SOCK_STREAM) 531 proto = IPPROTO_TCP; 532 else if (type == SOCK_DGRAM) 533 proto = IPPROTO_UDP; 534 else 535 return 0; 536 } else 537 proto = 0; 538 539 sip->si_af = ss.ss_family; 540 sip->si_proto = proto; 541 sip->si_socktype = type; 542 543 return 1; 544} 545 546/* 547 * Linear search, but the number of entries is small. 548 */ 549int 550__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 551{ 552 size_t i; 553 554 _DIAGASSERT(nconf != NULL); 555 _DIAGASSERT(sip != NULL); 556 557 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 558 if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) { 559 sip->si_af = na_cvt[i].af; 560 sip->si_proto = na_cvt[i].protocol; 561 sip->si_socktype = 562 __rpc_seman2socktype((int)nconf->nc_semantics); 563 if (sip->si_socktype == -1) 564 return 0; 565 sip->si_alen = __rpc_get_a_size(sip->si_af); 566 return 1; 567 } 568 569 return 0; 570} 571 572int 573__rpc_nconf2fd(const struct netconfig *nconf) 574{ 575 struct __rpc_sockinfo si; 576 577 _DIAGASSERT(nconf != NULL); 578 579 if (!__rpc_nconf2sockinfo(nconf, &si)) 580 return 0; 581 582 return socket(si.si_af, si.si_socktype, si.si_proto); 583} 584 585int 586__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) 587{ 588 size_t i; 589 590 _DIAGASSERT(sip != NULL); 591 /* netid may be NULL */ 592 593 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 594 if (na_cvt[i].af == sip->si_af && 595 na_cvt[i].protocol == sip->si_proto) { 596 if (netid) 597 *netid = na_cvt[i].netid; 598 return 1; 599 } 600 601 return 0; 602} 603 604char * 605taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 606{ 607 struct __rpc_sockinfo si; 608 609 _DIAGASSERT(nconf != NULL); 610 _DIAGASSERT(nbuf != NULL); 611 612 if (!__rpc_nconf2sockinfo(nconf, &si)) 613 return NULL; 614 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 615} 616 617struct netbuf * 618uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 619{ 620 struct __rpc_sockinfo si; 621 622 _DIAGASSERT(nconf != NULL); 623 _DIAGASSERT(uaddr != NULL); 624 625 if (!__rpc_nconf2sockinfo(nconf, &si)) 626 return NULL; 627 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 628} 629 630char * 631__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 632{ 633 char *ret; 634 struct sockaddr_in *sinp; 635 struct sockaddr_un *sun; 636 char namebuf[INET_ADDRSTRLEN]; 637#ifdef INET6 638 struct sockaddr_in6 *sin6; 639 char namebuf6[INET6_ADDRSTRLEN]; 640#endif 641 u_int16_t port; 642 643 _DIAGASSERT(nbuf != NULL); 644 645 switch (af) { 646 case AF_INET: 647 if (nbuf->len < sizeof(*sinp)) { 648 return NULL; 649 } 650 sinp = nbuf->buf; 651 if (inet_ntop(af, &sinp->sin_addr, namebuf, 652 (socklen_t)sizeof namebuf) == NULL) 653 return NULL; 654 port = ntohs(sinp->sin_port); 655 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, 656 port & 0xff) < 0) 657 return NULL; 658 break; 659#ifdef INET6 660 case AF_INET6: 661 if (nbuf->len < sizeof(*sin6)) { 662 return NULL; 663 } 664 sin6 = nbuf->buf; 665 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, 666 (socklen_t)sizeof namebuf6) == NULL) 667 return NULL; 668 port = ntohs(sin6->sin6_port); 669 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, 670 port & 0xff) < 0) 671 return NULL; 672 break; 673#endif 674 case AF_LOCAL: 675 sun = nbuf->buf; 676 sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */ 677 ret = strdup(sun->sun_path); 678 break; 679 default: 680 return NULL; 681 } 682 683 return ret; 684} 685 686struct netbuf * 687__rpc_uaddr2taddr_af(int af, const char *uaddr) 688{ 689 struct netbuf *ret = NULL; 690 char *addrstr, *p; 691 unsigned port, portlo, porthi; 692 size_t len; 693 struct sockaddr_in *sinp; 694#ifdef INET6 695 struct sockaddr_in6 *sin6; 696#endif 697 struct sockaddr_un *sun; 698 699 if (uaddr == NULL) 700 return NULL; 701 702 addrstr = strdup(uaddr); 703 if (addrstr == NULL) 704 return NULL; 705 706 /* 707 * AF_LOCAL addresses are expected to be absolute 708 * pathnames, anything else will be AF_INET or AF_INET6. 709 */ 710 port = 0; 711 if (*addrstr != '/') { 712 p = strrchr(addrstr, '.'); 713 if (p == NULL) 714 goto out; 715 portlo = (unsigned)atoi(p + 1); 716 *p = '\0'; 717 718 p = strrchr(addrstr, '.'); 719 if (p == NULL) 720 goto out; 721 porthi = (unsigned)atoi(p + 1); 722 *p = '\0'; 723 port = (porthi << 8) | portlo; 724 } 725 726 ret = malloc(sizeof(*ret)); 727 if (ret == NULL) 728 goto out; 729 730 switch (af) { 731 case AF_INET: 732 sinp = malloc(sizeof(*sinp)); 733 if (sinp == NULL) 734 goto out; 735 memset(sinp, 0, sizeof *sinp); 736 sinp->sin_family = AF_INET; 737 sinp->sin_port = htons(port); 738 if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) { 739 free(sinp); 740 free(ret); 741 ret = NULL; 742 goto out; 743 } 744 sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp; 745 ret->buf = sinp; 746 break; 747#ifdef INET6 748 case AF_INET6: 749 sin6 = malloc(sizeof(*sin6)); 750 if (sin6 == NULL) 751 goto out; 752 memset(sin6, 0, sizeof *sin6); 753 sin6->sin6_family = AF_INET6; 754 sin6->sin6_port = htons(port); 755 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 756 free(sin6); 757 free(ret); 758 ret = NULL; 759 goto out; 760 } 761 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 762 ret->buf = sin6; 763 break; 764#endif 765 case AF_LOCAL: 766 sun = malloc(sizeof(*sun)); 767 if (sun == NULL) 768 goto out; 769 memset(sun, 0, sizeof *sun); 770 sun->sun_family = AF_LOCAL; 771 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 772 len = SUN_LEN(sun); 773 _DIAGASSERT(__type_fit(uint8_t, len)); 774 ret->len = ret->maxlen = sun->sun_len = (uint8_t)len; 775 ret->buf = sun; 776 break; 777 default: 778 break; 779 } 780out: 781 free(addrstr); 782 return ret; 783} 784 785int 786__rpc_seman2socktype(int semantics) 787{ 788 switch (semantics) { 789 case NC_TPI_CLTS: 790 return SOCK_DGRAM; 791 case NC_TPI_COTS_ORD: 792 return SOCK_STREAM; 793 case NC_TPI_RAW: 794 return SOCK_RAW; 795 default: 796 break; 797 } 798 799 return -1; 800} 801 802int 803__rpc_socktype2seman(int socktype) 804{ 805 switch (socktype) { 806 case SOCK_DGRAM: 807 return NC_TPI_CLTS; 808 case SOCK_STREAM: 809 return NC_TPI_COTS_ORD; 810 case SOCK_RAW: 811 return NC_TPI_RAW; 812 default: 813 break; 814 } 815 816 return -1; 817} 818 819/* 820 * XXXX - IPv6 scope IDs can't be handled in universal addresses. 821 * Here, we compare the original server address to that of the RPC 822 * service we just received back from a call to rpcbind on the remote 823 * machine. If they are both "link local" or "site local", copy 824 * the scope id of the server address over to the service address. 825 */ 826/* ARGSUSED */ 827int 828__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) 829{ 830#ifdef INET6 831 struct sockaddr *sa_new, *sa_svc; 832 struct sockaddr_in6 *sin6_new, *sin6_svc; 833 834 _DIAGASSERT(new != NULL); 835 _DIAGASSERT(svc != NULL); 836 837 sa_svc = (struct sockaddr *)svc->buf; 838 sa_new = (struct sockaddr *)new->buf; 839 840 if (sa_new->sa_family == sa_svc->sa_family && 841 sa_new->sa_family == AF_INET6) { 842 sin6_new = (struct sockaddr_in6 *)new->buf; 843 sin6_svc = (struct sockaddr_in6 *)svc->buf; 844 845 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && 846 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || 847 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && 848 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { 849 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; 850 } 851 } 852#endif 853 return 1; 854} 855 856int 857__rpc_sockisbound(int fd) 858{ 859 struct sockaddr_storage ss; 860 socklen_t slen; 861 862 slen = sizeof (struct sockaddr_storage); 863 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) 864 return 0; 865 866 switch (ss.ss_family) { 867 case AF_INET: 868 return (((struct sockaddr_in *) 869 (void *)&ss)->sin_port != 0); 870#ifdef INET6 871 case AF_INET6: 872 return (((struct sockaddr_in6 *) 873 (void *)&ss)->sin6_port != 0); 874#endif 875 case AF_LOCAL: 876 /* XXX check this */ 877 return (((struct sockaddr_un *) 878 (void *)&ss)->sun_path[0] != '\0'); 879 default: 880 break; 881 } 882 883 return 0; 884} 885 886/* 887 * For TCP transport, Host Requirements RFCs mandate 888 * Nagle (RFC-896) processing. But for RPC, Nagle 889 * processing adds adds unwanted latency to the last, 890 * partial TCP segment of each RPC message. See: 891 * R. W. Scheifler and J. Gettys, The X Window System, 892 * ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69. 893 * So for TCP transport, disable Nagle via TCP_NODELAY. 894 * XXX: moral equivalent for non-TCP protocols? 895 */ 896int 897__rpc_setnodelay(int fd, const struct __rpc_sockinfo *si) 898{ 899 int one = 1; 900 if (si->si_proto != IPPROTO_TCP) 901 return 0; 902 return setsockopt(fd, si->si_proto, TCP_NODELAY, &one, 903 (socklen_t)sizeof(one)); 904} 905