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