1 /* $NetBSD: rpc_generic.c,v 1.23 2008/04/25 17:44:44 christos Exp $ */ 2 3 /* 4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 5 * unrestricted use provided that this legend is included on all tape 6 * media and as a part of the software program in whole or part. Users 7 * may copy or modify Sun RPC without charge, but are not authorized 8 * to license or distribute it to anyone else except as part of a product or 9 * program developed by the user. 10 * 11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 14 * 15 * Sun RPC is provided with no support and without any obligation on the 16 * part of Sun Microsystems, Inc. to assist in its use, correction, 17 * modification or enhancement. 18 * 19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 21 * OR ANY PART THEREOF. 22 * 23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 24 * or profits or other special, indirect and consequential damages, even if 25 * Sun has been advised of the possibility of such damages. 26 * 27 * Sun Microsystems, Inc. 28 * 2550 Garcia Avenue 29 * Mountain View, California 94043 30 */ 31 /* 32 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 33 */ 34 35 /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ 36 37 /* 38 * rpc_generic.c, Miscl routines for RPC. 39 * 40 */ 41 42 #include <sys/cdefs.h> 43 #if defined(LIBC_SCCS) && !defined(lint) 44 __RCSID("$NetBSD: rpc_generic.c,v 1.23 2008/04/25 17:44:44 christos Exp $"); 45 #endif 46 47 #include "namespace.h" 48 #include "reentrant.h" 49 #include <sys/types.h> 50 #include <sys/param.h> 51 #include <sys/socket.h> 52 #include <sys/un.h> 53 #include <sys/resource.h> 54 #include <netinet/in.h> 55 #include <netinet/tcp.h> 56 #include <arpa/inet.h> 57 #include <rpc/rpc.h> 58 #include <assert.h> 59 #include <ctype.h> 60 #include <stdio.h> 61 #include <netdb.h> 62 #include <netconfig.h> 63 #include <malloc.h> 64 #include <string.h> 65 #include <syslog.h> 66 #include <rpc/nettype.h> 67 #include "rpc_internal.h" 68 69 #ifdef __weak_alias 70 __weak_alias(taddr2uaddr,_taddr2uaddr) 71 __weak_alias(uaddr2taddr,_uaddr2taddr) 72 #endif 73 74 struct handle { 75 NCONF_HANDLE *nhandle; 76 int nflag; /* Whether NETPATH or NETCONFIG */ 77 int nettype; 78 }; 79 80 static const struct _rpcnettype { 81 const char *name; 82 const int type; 83 } _rpctypelist[] = { 84 { "netpath", _RPC_NETPATH }, 85 { "visible", _RPC_VISIBLE }, 86 { "circuit_v", _RPC_CIRCUIT_V }, 87 { "datagram_v", _RPC_DATAGRAM_V }, 88 { "circuit_n", _RPC_CIRCUIT_N }, 89 { "datagram_n", _RPC_DATAGRAM_N }, 90 { "tcp", _RPC_TCP }, 91 { "udp", _RPC_UDP }, 92 { 0, _RPC_NONE } 93 }; 94 95 struct netid_af { 96 const char *netid; 97 int af; 98 int protocol; 99 }; 100 101 static const struct netid_af na_cvt[] = { 102 { "udp", AF_INET, IPPROTO_UDP }, 103 { "tcp", AF_INET, IPPROTO_TCP }, 104 #ifdef INET6 105 { "udp6", AF_INET6, IPPROTO_UDP }, 106 { "tcp6", AF_INET6, IPPROTO_TCP }, 107 #endif 108 { "local", AF_LOCAL, 0 } 109 }; 110 111 #if 0 112 static char *strlocase __P((char *)); 113 #endif 114 static int getnettype __P((const char *)); 115 116 /* 117 * Cache the result of getrlimit(), so we don't have to do an 118 * expensive call every time. 119 */ 120 int 121 __rpc_dtbsize() 122 { 123 static int tbsize; 124 struct rlimit rl; 125 126 if (tbsize) { 127 return (tbsize); 128 } 129 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 130 return (tbsize = (int)rl.rlim_max); 131 } 132 /* 133 * Something wrong. I'll try to save face by returning a 134 * pessimistic number. 135 */ 136 return (32); 137 } 138 139 140 /* 141 * Find the appropriate buffer size 142 */ 143 u_int 144 /*ARGSUSED*/ 145 __rpc_get_t_size(af, proto, size) 146 int af, proto; 147 int size; /* Size requested */ 148 { 149 int maxsize, defsize; 150 151 maxsize = 256 * 1024; /* XXX */ 152 switch (proto) { 153 case IPPROTO_TCP: 154 defsize = 64 * 1024; /* XXX */ 155 break; 156 case IPPROTO_UDP: 157 defsize = UDPMSGSIZE; 158 break; 159 default: 160 defsize = RPC_MAXDATASIZE; 161 break; 162 } 163 if (size == 0) 164 return defsize; 165 166 /* Check whether the value is within the upper max limit */ 167 return (size > maxsize ? (u_int)maxsize : (u_int)size); 168 } 169 170 /* 171 * Find the appropriate address buffer size 172 */ 173 u_int 174 __rpc_get_a_size(af) 175 int af; 176 { 177 switch (af) { 178 case AF_INET: 179 return sizeof (struct sockaddr_in); 180 #ifdef INET6 181 case AF_INET6: 182 return sizeof (struct sockaddr_in6); 183 #endif 184 case AF_LOCAL: 185 return sizeof (struct sockaddr_un); 186 default: 187 break; 188 } 189 return ((u_int)RPC_MAXADDRSIZE); 190 } 191 192 #if 0 193 static char * 194 strlocase(p) 195 char *p; 196 { 197 char *t = p; 198 199 _DIAGASSERT(p != NULL); 200 201 for (; *p; p++) 202 if (isupper(*p)) 203 *p = tolower(*p); 204 return (t); 205 } 206 #endif 207 208 /* 209 * Returns the type of the network as defined in <rpc/nettype.h> 210 * If nettype is NULL, it defaults to NETPATH. 211 */ 212 static int 213 getnettype(nettype) 214 const char *nettype; 215 { 216 int i; 217 218 if ((nettype == NULL) || (nettype[0] == 0)) { 219 return (_RPC_NETPATH); /* Default */ 220 } 221 222 #if 0 223 nettype = strlocase(nettype); 224 #endif 225 for (i = 0; _rpctypelist[i].name; i++) 226 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 227 return (_rpctypelist[i].type); 228 } 229 return (_rpctypelist[i].type); 230 } 231 232 /* 233 * For the given nettype (tcp or udp only), return the first structure found. 234 * This should be freed by calling freenetconfigent() 235 */ 236 237 #ifdef _REENTRANT 238 static thread_key_t tcp_key, udp_key; 239 static once_t __rpc_getconfigp_once = ONCE_INITIALIZER; 240 241 static void 242 __rpc_getconfigp_setup(void) 243 { 244 245 thr_keycreate(&tcp_key, free); 246 thr_keycreate(&udp_key, free); 247 } 248 #endif 249 250 struct netconfig * 251 __rpc_getconfip(nettype) 252 const char *nettype; 253 { 254 char *netid; 255 char *netid_tcp = NULL; 256 char *netid_udp = NULL; 257 static char *netid_tcp_main; 258 static char *netid_udp_main; 259 struct netconfig *dummy; 260 #ifdef _REENTRANT 261 extern int __isthreaded; 262 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 */ 338 void * 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 */ 384 struct 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 461 void 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 */ 483 void * 484 rpc_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 */ 500 struct 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 516 int 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 */ 555 int 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 578 int 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 591 int 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 610 char * 611 taddr2uaddr(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 623 struct netbuf * 624 uaddr2taddr(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 636 char * 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 686 struct 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 } 776 out: 777 free(addrstr); 778 return ret; 779 } 780 781 int 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 798 int 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 */ 823 int 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 852 int 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 */ 892 int 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