1 /* $NetBSD: rpc_generic.c,v 1.22 2006/06/22 19:35:34 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.22 2006/06/22 19:35:34 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 = (char *) NULL; 256 char *netid_udp = (char *) 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 #ifdef _REENTRANT 291 if (__isthreaded == 0) 292 netid_tcp_main = netid_tcp; 293 else 294 thr_setspecific(tcp_key, 295 (void *) netid_tcp); 296 #else 297 netid_tcp_main = netid_tcp; 298 #endif 299 } else 300 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 301 netid_udp = strdup(nconf->nc_netid); 302 #ifdef _REENTRANT 303 if (__isthreaded == 0) 304 netid_udp_main = netid_udp; 305 else 306 thr_setspecific(udp_key, 307 (void *) netid_udp); 308 #else 309 netid_udp_main = netid_udp; 310 #endif 311 } 312 } 313 } 314 endnetconfig(confighandle); 315 } 316 if (strcmp(nettype, "udp") == 0) 317 netid = netid_udp; 318 else if (strcmp(nettype, "tcp") == 0) 319 netid = netid_tcp; 320 else { 321 return (NULL); 322 } 323 if ((netid == NULL) || (netid[0] == 0)) { 324 return (NULL); 325 } 326 dummy = getnetconfigent(netid); 327 return (dummy); 328 } 329 330 /* 331 * Returns the type of the nettype, which should then be used with 332 * __rpc_getconf(). 333 */ 334 void * 335 __rpc_setconf(nettype) 336 const char *nettype; 337 { 338 struct handle *handle; 339 340 /* nettype may be NULL; getnettype() supports that */ 341 342 handle = (struct handle *) malloc(sizeof (struct handle)); 343 if (handle == NULL) { 344 return (NULL); 345 } 346 switch (handle->nettype = getnettype(nettype)) { 347 case _RPC_NETPATH: 348 case _RPC_CIRCUIT_N: 349 case _RPC_DATAGRAM_N: 350 if (!(handle->nhandle = setnetpath())) { 351 free(handle); 352 return (NULL); 353 } 354 handle->nflag = TRUE; 355 break; 356 case _RPC_VISIBLE: 357 case _RPC_CIRCUIT_V: 358 case _RPC_DATAGRAM_V: 359 case _RPC_TCP: 360 case _RPC_UDP: 361 if (!(handle->nhandle = setnetconfig())) { 362 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 363 free(handle); 364 return (NULL); 365 } 366 handle->nflag = FALSE; 367 break; 368 default: 369 free(handle); 370 return (NULL); 371 } 372 373 return (handle); 374 } 375 376 /* 377 * Returns the next netconfig struct for the given "net" type. 378 * __rpc_setconf() should have been called previously. 379 */ 380 struct netconfig * 381 __rpc_getconf(vhandle) 382 void *vhandle; 383 { 384 struct handle *handle; 385 struct netconfig *nconf; 386 387 handle = (struct handle *)vhandle; 388 if (handle == NULL) { 389 return (NULL); 390 } 391 for (;;) { 392 if (handle->nflag) 393 nconf = getnetpath(handle->nhandle); 394 else 395 nconf = getnetconfig(handle->nhandle); 396 if (nconf == NULL) 397 break; 398 if ((nconf->nc_semantics != NC_TPI_CLTS) && 399 (nconf->nc_semantics != NC_TPI_COTS) && 400 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 401 continue; 402 switch (handle->nettype) { 403 case _RPC_VISIBLE: 404 if (!(nconf->nc_flag & NC_VISIBLE)) 405 continue; 406 /* FALLTHROUGH */ 407 case _RPC_NETPATH: /* Be happy */ 408 break; 409 case _RPC_CIRCUIT_V: 410 if (!(nconf->nc_flag & NC_VISIBLE)) 411 continue; 412 /* FALLTHROUGH */ 413 case _RPC_CIRCUIT_N: 414 if ((nconf->nc_semantics != NC_TPI_COTS) && 415 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 416 continue; 417 break; 418 case _RPC_DATAGRAM_V: 419 if (!(nconf->nc_flag & NC_VISIBLE)) 420 continue; 421 /* FALLTHROUGH */ 422 case _RPC_DATAGRAM_N: 423 if (nconf->nc_semantics != NC_TPI_CLTS) 424 continue; 425 break; 426 case _RPC_TCP: 427 if (((nconf->nc_semantics != NC_TPI_COTS) && 428 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 429 (strcmp(nconf->nc_protofmly, NC_INET) 430 #ifdef INET6 431 && strcmp(nconf->nc_protofmly, NC_INET6)) 432 #else 433 ) 434 #endif 435 || 436 strcmp(nconf->nc_proto, NC_TCP)) 437 continue; 438 break; 439 case _RPC_UDP: 440 if ((nconf->nc_semantics != NC_TPI_CLTS) || 441 (strcmp(nconf->nc_protofmly, NC_INET) 442 #ifdef INET6 443 && strcmp(nconf->nc_protofmly, NC_INET6)) 444 #else 445 ) 446 #endif 447 || 448 strcmp(nconf->nc_proto, NC_UDP)) 449 continue; 450 break; 451 } 452 break; 453 } 454 return (nconf); 455 } 456 457 void 458 __rpc_endconf(vhandle) 459 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 */ 479 void * 480 rpc_nullproc(clnt) 481 CLIENT *clnt; 482 { 483 struct timeval TIMEOUT = {25, 0}; 484 485 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 486 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 487 return (NULL); 488 } 489 return ((void *) clnt); 490 } 491 492 /* 493 * Try all possible transports until 494 * one succeeds in finding the netconf for the given fd. 495 */ 496 struct netconfig * 497 __rpcgettp(fd) 498 int fd; 499 { 500 const char *netid; 501 struct __rpc_sockinfo si; 502 503 if (!__rpc_fd2sockinfo(fd, &si)) 504 return NULL; 505 506 if (!__rpc_sockinfo2netid(&si, &netid)) 507 return NULL; 508 509 return getnetconfigent(__UNCONST(netid)); 510 } 511 512 int 513 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) 514 { 515 socklen_t len; 516 int type, proto; 517 struct sockaddr_storage ss; 518 519 _DIAGASSERT(sip != NULL); 520 521 len = sizeof ss; 522 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) 523 return 0; 524 sip->si_alen = len; 525 526 len = sizeof type; 527 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) 528 return 0; 529 530 /* XXX */ 531 if (ss.ss_family != AF_LOCAL) { 532 if (type == SOCK_STREAM) 533 proto = IPPROTO_TCP; 534 else if (type == SOCK_DGRAM) 535 proto = IPPROTO_UDP; 536 else 537 return 0; 538 } else 539 proto = 0; 540 541 sip->si_af = ss.ss_family; 542 sip->si_proto = proto; 543 sip->si_socktype = type; 544 545 return 1; 546 } 547 548 /* 549 * Linear search, but the number of entries is small. 550 */ 551 int 552 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 553 { 554 size_t i; 555 556 _DIAGASSERT(nconf != NULL); 557 _DIAGASSERT(sip != NULL); 558 559 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 560 if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) { 561 sip->si_af = na_cvt[i].af; 562 sip->si_proto = na_cvt[i].protocol; 563 sip->si_socktype = 564 __rpc_seman2socktype((int)nconf->nc_semantics); 565 if (sip->si_socktype == -1) 566 return 0; 567 sip->si_alen = __rpc_get_a_size(sip->si_af); 568 return 1; 569 } 570 571 return 0; 572 } 573 574 int 575 __rpc_nconf2fd(const struct netconfig *nconf) 576 { 577 struct __rpc_sockinfo si; 578 579 _DIAGASSERT(nconf != NULL); 580 581 if (!__rpc_nconf2sockinfo(nconf, &si)) 582 return 0; 583 584 return socket(si.si_af, si.si_socktype, si.si_proto); 585 } 586 587 int 588 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) 589 { 590 size_t i; 591 592 _DIAGASSERT(sip != NULL); 593 /* netid may be NULL */ 594 595 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 596 if (na_cvt[i].af == sip->si_af && 597 na_cvt[i].protocol == sip->si_proto) { 598 if (netid) 599 *netid = na_cvt[i].netid; 600 return 1; 601 } 602 603 return 0; 604 } 605 606 char * 607 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 608 { 609 struct __rpc_sockinfo si; 610 611 _DIAGASSERT(nconf != NULL); 612 _DIAGASSERT(nbuf != NULL); 613 614 if (!__rpc_nconf2sockinfo(nconf, &si)) 615 return NULL; 616 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 617 } 618 619 struct netbuf * 620 uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 621 { 622 struct __rpc_sockinfo si; 623 624 _DIAGASSERT(nconf != NULL); 625 _DIAGASSERT(uaddr != NULL); 626 627 if (!__rpc_nconf2sockinfo(nconf, &si)) 628 return NULL; 629 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 630 } 631 632 char * 633 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 634 { 635 char *ret; 636 struct sockaddr_in *sinp; 637 struct sockaddr_un *sun; 638 char namebuf[INET_ADDRSTRLEN]; 639 #ifdef INET6 640 struct sockaddr_in6 *sin6; 641 char namebuf6[INET6_ADDRSTRLEN]; 642 #endif 643 u_int16_t port; 644 645 _DIAGASSERT(nbuf != NULL); 646 647 switch (af) { 648 case AF_INET: 649 sinp = nbuf->buf; 650 if (inet_ntop(af, &sinp->sin_addr, namebuf, sizeof namebuf) 651 == NULL) 652 return NULL; 653 port = ntohs(sinp->sin_port); 654 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, 655 port & 0xff) < 0) 656 return NULL; 657 break; 658 #ifdef INET6 659 case AF_INET6: 660 sin6 = nbuf->buf; 661 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 662 == NULL) 663 return NULL; 664 port = ntohs(sin6->sin6_port); 665 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, 666 port & 0xff) < 0) 667 return NULL; 668 break; 669 #endif 670 case AF_LOCAL: 671 sun = nbuf->buf; 672 sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */ 673 ret = strdup(sun->sun_path); 674 break; 675 default: 676 return NULL; 677 } 678 679 return ret; 680 } 681 682 struct netbuf * 683 __rpc_uaddr2taddr_af(int af, const char *uaddr) 684 { 685 struct netbuf *ret = NULL; 686 char *addrstr, *p; 687 unsigned port, portlo, porthi; 688 struct sockaddr_in *sinp; 689 #ifdef INET6 690 struct sockaddr_in6 *sin6; 691 #endif 692 struct sockaddr_un *sun; 693 694 _DIAGASSERT(uaddr != NULL); 695 696 addrstr = strdup(uaddr); 697 if (addrstr == NULL) 698 return NULL; 699 700 /* 701 * AF_LOCAL addresses are expected to be absolute 702 * pathnames, anything else will be AF_INET or AF_INET6. 703 */ 704 port = 0; 705 if (*addrstr != '/') { 706 p = strrchr(addrstr, '.'); 707 if (p == NULL) 708 goto out; 709 portlo = (unsigned)atoi(p + 1); 710 *p = '\0'; 711 712 p = strrchr(addrstr, '.'); 713 if (p == NULL) 714 goto out; 715 porthi = (unsigned)atoi(p + 1); 716 *p = '\0'; 717 port = (porthi << 8) | portlo; 718 } 719 720 ret = (struct netbuf *)malloc(sizeof *ret); 721 if (ret == NULL) 722 goto out; 723 724 switch (af) { 725 case AF_INET: 726 sinp = (struct sockaddr_in *)malloc(sizeof *sinp); 727 if (sinp == NULL) 728 goto out; 729 memset(sinp, 0, sizeof *sinp); 730 sinp->sin_family = AF_INET; 731 sinp->sin_port = htons(port); 732 if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) { 733 free(sinp); 734 free(ret); 735 ret = NULL; 736 goto out; 737 } 738 sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp; 739 ret->buf = sinp; 740 break; 741 #ifdef INET6 742 case AF_INET6: 743 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6); 744 if (sin6 == NULL) 745 goto out; 746 memset(sin6, 0, sizeof *sin6); 747 sin6->sin6_family = AF_INET6; 748 sin6->sin6_port = htons(port); 749 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 750 free(sin6); 751 free(ret); 752 ret = NULL; 753 goto out; 754 } 755 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 756 ret->buf = sin6; 757 break; 758 #endif 759 case AF_LOCAL: 760 sun = (struct sockaddr_un *)malloc(sizeof *sun); 761 if (sun == NULL) 762 goto out; 763 memset(sun, 0, sizeof *sun); 764 sun->sun_family = AF_LOCAL; 765 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 766 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 767 ret->buf = sun; 768 break; 769 default: 770 break; 771 } 772 out: 773 free(addrstr); 774 return ret; 775 } 776 777 int 778 __rpc_seman2socktype(int semantics) 779 { 780 switch (semantics) { 781 case NC_TPI_CLTS: 782 return SOCK_DGRAM; 783 case NC_TPI_COTS_ORD: 784 return SOCK_STREAM; 785 case NC_TPI_RAW: 786 return SOCK_RAW; 787 default: 788 break; 789 } 790 791 return -1; 792 } 793 794 int 795 __rpc_socktype2seman(int socktype) 796 { 797 switch (socktype) { 798 case SOCK_DGRAM: 799 return NC_TPI_CLTS; 800 case SOCK_STREAM: 801 return NC_TPI_COTS_ORD; 802 case SOCK_RAW: 803 return NC_TPI_RAW; 804 default: 805 break; 806 } 807 808 return -1; 809 } 810 811 /* 812 * XXXX - IPv6 scope IDs can't be handled in universal addresses. 813 * Here, we compare the original server address to that of the RPC 814 * service we just received back from a call to rpcbind on the remote 815 * machine. If they are both "link local" or "site local", copy 816 * the scope id of the server address over to the service address. 817 */ 818 /* ARGSUSED */ 819 int 820 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) 821 { 822 #ifdef INET6 823 struct sockaddr *sa_new, *sa_svc; 824 struct sockaddr_in6 *sin6_new, *sin6_svc; 825 826 _DIAGASSERT(new != NULL); 827 _DIAGASSERT(svc != NULL); 828 829 sa_svc = (struct sockaddr *)svc->buf; 830 sa_new = (struct sockaddr *)new->buf; 831 832 if (sa_new->sa_family == sa_svc->sa_family && 833 sa_new->sa_family == AF_INET6) { 834 sin6_new = (struct sockaddr_in6 *)new->buf; 835 sin6_svc = (struct sockaddr_in6 *)svc->buf; 836 837 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && 838 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || 839 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && 840 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { 841 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; 842 } 843 } 844 #endif 845 return 1; 846 } 847 848 int 849 __rpc_sockisbound(int fd) 850 { 851 struct sockaddr_storage ss; 852 socklen_t slen; 853 854 slen = sizeof (struct sockaddr_storage); 855 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) 856 return 0; 857 858 switch (ss.ss_family) { 859 case AF_INET: 860 return (((struct sockaddr_in *) 861 (void *)&ss)->sin_port != 0); 862 #ifdef INET6 863 case AF_INET6: 864 return (((struct sockaddr_in6 *) 865 (void *)&ss)->sin6_port != 0); 866 #endif 867 case AF_LOCAL: 868 /* XXX check this */ 869 return (((struct sockaddr_un *) 870 (void *)&ss)->sun_path[0] != '\0'); 871 default: 872 break; 873 } 874 875 return 0; 876 } 877 878 /* 879 * For TCP transport, Host Requirements RFCs mandate 880 * Nagle (RFC-896) processing. But for RPC, Nagle 881 * processing adds adds unwanted latency to the last, 882 * partial TCP segment of each RPC message. See: 883 * R. W. Scheifler and J. Gettys, The X Window System, 884 * ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69. 885 * So for TCP transport, disable Nagle via TCP_NODELAY. 886 * XXX: moral equivalent for non-TCP protocols? 887 */ 888 int 889 __rpc_setnodelay(int fd, const struct __rpc_sockinfo *si) 890 { 891 int one = 1; 892 if (si->si_proto != IPPROTO_TCP) 893 return 0; 894 return setsockopt(fd, si->si_proto, TCP_NODELAY, &one, sizeof(one)); 895 } 896