rpc_generic.c revision 92905
1/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */ 2/* $FreeBSD: head/lib/libc/rpc/rpc_generic.c 92905 2002-03-21 22:49:10Z obrien $ */ 3 4/* 5 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for 6 * unrestricted use provided that this legend is included on all tape 7 * media and as a part of the software program in whole or part. Users 8 * may copy or modify Sun RPC without charge, but are not authorized 9 * to license or distribute it to anyone else except as part of a product or 10 * program developed by the user. 11 * 12 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE 13 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR 14 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. 15 * 16 * Sun RPC is provided with no support and without any obligation on the 17 * part of Sun Microsystems, Inc. to assist in its use, correction, 18 * modification or enhancement. 19 * 20 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE 21 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC 22 * OR ANY PART THEREOF. 23 * 24 * In no event will Sun Microsystems, Inc. be liable for any lost revenue 25 * or profits or other special, indirect and consequential damages, even if 26 * Sun has been advised of the possibility of such damages. 27 * 28 * Sun Microsystems, Inc. 29 * 2550 Garcia Avenue 30 * Mountain View, California 94043 31 */ 32/* 33 * Copyright (c) 1986-1991 by Sun Microsystems Inc. 34 */ 35 36/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */ 37 38/* 39 * rpc_generic.c, Miscl routines for RPC. 40 * 41 */ 42 43#include "namespace.h" 44#include "reentrant.h" 45#include <sys/types.h> 46#include <sys/param.h> 47#include <sys/socket.h> 48#include <sys/time.h> 49#include <sys/un.h> 50#include <sys/resource.h> 51#include <netinet/in.h> 52#include <arpa/inet.h> 53#include <rpc/rpc.h> 54#include <ctype.h> 55#include <stddef.h> 56#include <stdio.h> 57#include <netdb.h> 58#include <netconfig.h> 59#include <stdlib.h> 60#include <string.h> 61#include <syslog.h> 62#include <rpc/nettype.h> 63#include "un-namespace.h" 64#include "rpc_com.h" 65 66struct handle { 67 NCONF_HANDLE *nhandle; 68 int nflag; /* Whether NETPATH or NETCONFIG */ 69 int nettype; 70}; 71 72static const struct _rpcnettype { 73 const char *name; 74 const int type; 75} _rpctypelist[] = { 76 { "netpath", _RPC_NETPATH }, 77 { "visible", _RPC_VISIBLE }, 78 { "circuit_v", _RPC_CIRCUIT_V }, 79 { "datagram_v", _RPC_DATAGRAM_V }, 80 { "circuit_n", _RPC_CIRCUIT_N }, 81 { "datagram_n", _RPC_DATAGRAM_N }, 82 { "tcp", _RPC_TCP }, 83 { "udp", _RPC_UDP }, 84 { 0, _RPC_NONE } 85}; 86 87struct netid_af { 88 const char *netid; 89 int af; 90 int protocol; 91}; 92 93static const struct netid_af na_cvt[] = { 94 { "udp", AF_INET, IPPROTO_UDP }, 95 { "tcp", AF_INET, IPPROTO_TCP }, 96#ifdef INET6 97 { "udp6", AF_INET6, IPPROTO_UDP }, 98 { "tcp6", AF_INET6, IPPROTO_TCP }, 99#endif 100 { "unix", AF_LOCAL, 0 } 101}; 102 103#if 0 104static char *strlocase(char *); 105#endif 106static int getnettype(const char *); 107 108/* 109 * Cache the result of getrlimit(), so we don't have to do an 110 * expensive call every time. 111 */ 112int 113__rpc_dtbsize() 114{ 115 static int tbsize; 116 struct rlimit rl; 117 118 if (tbsize) { 119 return (tbsize); 120 } 121 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 122 return (tbsize = (int)rl.rlim_max); 123 } 124 /* 125 * Something wrong. I'll try to save face by returning a 126 * pessimistic number. 127 */ 128 return (32); 129} 130 131 132/* 133 * Find the appropriate buffer size 134 */ 135u_int 136/*ARGSUSED*/ 137__rpc_get_t_size(af, proto, size) 138 int af, proto; 139 int size; /* Size requested */ 140{ 141 int maxsize, defsize; 142 143 maxsize = 256 * 1024; /* XXX */ 144 switch (proto) { 145 case IPPROTO_TCP: 146 defsize = 64 * 1024; /* XXX */ 147 break; 148 case IPPROTO_UDP: 149 defsize = UDPMSGSIZE; 150 break; 151 default: 152 defsize = RPC_MAXDATASIZE; 153 break; 154 } 155 if (size == 0) 156 return defsize; 157 158 /* Check whether the value is within the upper max limit */ 159 return (size > maxsize ? (u_int)maxsize : (u_int)size); 160} 161 162/* 163 * Find the appropriate address buffer size 164 */ 165u_int 166__rpc_get_a_size(af) 167 int af; 168{ 169 switch (af) { 170 case AF_INET: 171 return sizeof (struct sockaddr_in); 172#ifdef INET6 173 case AF_INET6: 174 return sizeof (struct sockaddr_in6); 175#endif 176 case AF_LOCAL: 177 return sizeof (struct sockaddr_un); 178 default: 179 break; 180 } 181 return ((u_int)RPC_MAXADDRSIZE); 182} 183 184#if 0 185static char * 186strlocase(p) 187 char *p; 188{ 189 char *t = p; 190 191 for (; *p; p++) 192 if (isupper(*p)) 193 *p = tolower(*p); 194 return (t); 195} 196#endif 197 198/* 199 * Returns the type of the network as defined in <rpc/nettype.h> 200 * If nettype is NULL, it defaults to NETPATH. 201 */ 202static int 203getnettype(nettype) 204 const char *nettype; 205{ 206 int i; 207 208 if ((nettype == NULL) || (nettype[0] == NULL)) { 209 return (_RPC_NETPATH); /* Default */ 210 } 211 212#if 0 213 nettype = strlocase(nettype); 214#endif 215 for (i = 0; _rpctypelist[i].name; i++) 216 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) { 217 return (_rpctypelist[i].type); 218 } 219 return (_rpctypelist[i].type); 220} 221 222/* 223 * For the given nettype (tcp or udp only), return the first structure found. 224 * This should be freed by calling freenetconfigent() 225 */ 226struct netconfig * 227__rpc_getconfip(nettype) 228 const char *nettype; 229{ 230 char *netid; 231 char *netid_tcp = (char *) NULL; 232 char *netid_udp = (char *) NULL; 233 static char *netid_tcp_main; 234 static char *netid_udp_main; 235 struct netconfig *dummy; 236 int main_thread; 237 static thread_key_t tcp_key, udp_key; 238 extern mutex_t tsd_lock; 239 240 if ((main_thread = thr_main())) { 241 netid_udp = netid_udp_main; 242 netid_tcp = netid_tcp_main; 243 } else { 244 if (tcp_key == 0) { 245 mutex_lock(&tsd_lock); 246 if (tcp_key == 0) 247 thr_keycreate(&tcp_key, free); 248 mutex_unlock(&tsd_lock); 249 } 250 netid_tcp = (char *)thr_getspecific(tcp_key); 251 if (udp_key == 0) { 252 mutex_lock(&tsd_lock); 253 if (udp_key == 0) 254 thr_keycreate(&udp_key, free); 255 mutex_unlock(&tsd_lock); 256 } 257 netid_udp = (char *)thr_getspecific(udp_key); 258 } 259 if (!netid_udp && !netid_tcp) { 260 struct netconfig *nconf; 261 void *confighandle; 262 263 if (!(confighandle = setnetconfig())) { 264 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 265 return (NULL); 266 } 267 while ((nconf = getnetconfig(confighandle)) != NULL) { 268 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { 269 if (strcmp(nconf->nc_proto, NC_TCP) == 0) { 270 netid_tcp = strdup(nconf->nc_netid); 271 if (main_thread) 272 netid_tcp_main = netid_tcp; 273 else 274 thr_setspecific(tcp_key, 275 (void *) netid_tcp); 276 } else 277 if (strcmp(nconf->nc_proto, NC_UDP) == 0) { 278 netid_udp = strdup(nconf->nc_netid); 279 if (main_thread) 280 netid_udp_main = netid_udp; 281 else 282 thr_setspecific(udp_key, 283 (void *) netid_udp); 284 } 285 } 286 } 287 endnetconfig(confighandle); 288 } 289 if (strcmp(nettype, "udp") == 0) 290 netid = netid_udp; 291 else if (strcmp(nettype, "tcp") == 0) 292 netid = netid_tcp; 293 else { 294 return (NULL); 295 } 296 if ((netid == NULL) || (netid[0] == NULL)) { 297 return (NULL); 298 } 299 dummy = getnetconfigent(netid); 300 return (dummy); 301} 302 303/* 304 * Returns the type of the nettype, which should then be used with 305 * __rpc_getconf(). 306 */ 307void * 308__rpc_setconf(nettype) 309 const char *nettype; 310{ 311 struct handle *handle; 312 313 handle = (struct handle *) malloc(sizeof (struct handle)); 314 if (handle == NULL) { 315 return (NULL); 316 } 317 switch (handle->nettype = getnettype(nettype)) { 318 case _RPC_NETPATH: 319 case _RPC_CIRCUIT_N: 320 case _RPC_DATAGRAM_N: 321 if (!(handle->nhandle = setnetpath())) { 322 free(handle); 323 return (NULL); 324 } 325 handle->nflag = TRUE; 326 break; 327 case _RPC_VISIBLE: 328 case _RPC_CIRCUIT_V: 329 case _RPC_DATAGRAM_V: 330 case _RPC_TCP: 331 case _RPC_UDP: 332 if (!(handle->nhandle = setnetconfig())) { 333 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG); 334 free(handle); 335 return (NULL); 336 } 337 handle->nflag = FALSE; 338 break; 339 default: 340 return (NULL); 341 } 342 343 return (handle); 344} 345 346/* 347 * Returns the next netconfig struct for the given "net" type. 348 * __rpc_setconf() should have been called previously. 349 */ 350struct netconfig * 351__rpc_getconf(vhandle) 352 void *vhandle; 353{ 354 struct handle *handle; 355 struct netconfig *nconf; 356 357 handle = (struct handle *)vhandle; 358 if (handle == NULL) { 359 return (NULL); 360 } 361 for (;;) { 362 if (handle->nflag) 363 nconf = getnetpath(handle->nhandle); 364 else 365 nconf = getnetconfig(handle->nhandle); 366 if (nconf == NULL) 367 break; 368 if ((nconf->nc_semantics != NC_TPI_CLTS) && 369 (nconf->nc_semantics != NC_TPI_COTS) && 370 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 371 continue; 372 switch (handle->nettype) { 373 case _RPC_VISIBLE: 374 if (!(nconf->nc_flag & NC_VISIBLE)) 375 continue; 376 /* FALLTHROUGH */ 377 case _RPC_NETPATH: /* Be happy */ 378 break; 379 case _RPC_CIRCUIT_V: 380 if (!(nconf->nc_flag & NC_VISIBLE)) 381 continue; 382 /* FALLTHROUGH */ 383 case _RPC_CIRCUIT_N: 384 if ((nconf->nc_semantics != NC_TPI_COTS) && 385 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 386 continue; 387 break; 388 case _RPC_DATAGRAM_V: 389 if (!(nconf->nc_flag & NC_VISIBLE)) 390 continue; 391 /* FALLTHROUGH */ 392 case _RPC_DATAGRAM_N: 393 if (nconf->nc_semantics != NC_TPI_CLTS) 394 continue; 395 break; 396 case _RPC_TCP: 397 if (((nconf->nc_semantics != NC_TPI_COTS) && 398 (nconf->nc_semantics != NC_TPI_COTS_ORD)) || 399 (strcmp(nconf->nc_protofmly, NC_INET) 400#ifdef INET6 401 && strcmp(nconf->nc_protofmly, NC_INET6)) 402#else 403 ) 404#endif 405 || 406 strcmp(nconf->nc_proto, NC_TCP)) 407 continue; 408 break; 409 case _RPC_UDP: 410 if ((nconf->nc_semantics != NC_TPI_CLTS) || 411 (strcmp(nconf->nc_protofmly, NC_INET) 412#ifdef INET6 413 && strcmp(nconf->nc_protofmly, NC_INET6)) 414#else 415 ) 416#endif 417 || 418 strcmp(nconf->nc_proto, NC_UDP)) 419 continue; 420 break; 421 } 422 break; 423 } 424 return (nconf); 425} 426 427void 428__rpc_endconf(vhandle) 429 void * vhandle; 430{ 431 struct handle *handle; 432 433 handle = (struct handle *) vhandle; 434 if (handle == NULL) { 435 return; 436 } 437 if (handle->nflag) { 438 endnetpath(handle->nhandle); 439 } else { 440 endnetconfig(handle->nhandle); 441 } 442 free(handle); 443} 444 445/* 446 * Used to ping the NULL procedure for clnt handle. 447 * Returns NULL if fails, else a non-NULL pointer. 448 */ 449void * 450rpc_nullproc(clnt) 451 CLIENT *clnt; 452{ 453 struct timeval TIMEOUT = {25, 0}; 454 455 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL, 456 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) { 457 return (NULL); 458 } 459 return ((void *) clnt); 460} 461 462/* 463 * Try all possible transports until 464 * one succeeds in finding the netconf for the given fd. 465 */ 466struct netconfig * 467__rpcgettp(fd) 468 int fd; 469{ 470 const char *netid; 471 struct __rpc_sockinfo si; 472 473 if (!__rpc_fd2sockinfo(fd, &si)) 474 return NULL; 475 476 if (!__rpc_sockinfo2netid(&si, &netid)) 477 return NULL; 478 479 /*LINTED const castaway*/ 480 return getnetconfigent((char *)netid); 481} 482 483int 484__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip) 485{ 486 socklen_t len; 487 int type, proto; 488 struct sockaddr_storage ss; 489 490 len = sizeof ss; 491 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0) 492 return 0; 493 sip->si_alen = len; 494 495 len = sizeof type; 496 if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0) 497 return 0; 498 499 /* XXX */ 500 if (ss.ss_family != AF_LOCAL) { 501 if (type == SOCK_STREAM) 502 proto = IPPROTO_TCP; 503 else if (type == SOCK_DGRAM) 504 proto = IPPROTO_UDP; 505 else 506 return 0; 507 } else 508 proto = 0; 509 510 sip->si_af = ss.ss_family; 511 sip->si_proto = proto; 512 sip->si_socktype = type; 513 514 return 1; 515} 516 517/* 518 * Linear search, but the number of entries is small. 519 */ 520int 521__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip) 522{ 523 int i; 524 525 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 526 if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) { 527 sip->si_af = na_cvt[i].af; 528 sip->si_proto = na_cvt[i].protocol; 529 sip->si_socktype = 530 __rpc_seman2socktype((int)nconf->nc_semantics); 531 if (sip->si_socktype == -1) 532 return 0; 533 sip->si_alen = __rpc_get_a_size(sip->si_af); 534 return 1; 535 } 536 537 return 0; 538} 539 540int 541__rpc_nconf2fd(const struct netconfig *nconf) 542{ 543 struct __rpc_sockinfo si; 544 545 if (!__rpc_nconf2sockinfo(nconf, &si)) 546 return 0; 547 548 return _socket(si.si_af, si.si_socktype, si.si_proto); 549} 550 551int 552__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid) 553{ 554 int i; 555 556 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) 557 if (na_cvt[i].af == sip->si_af && 558 na_cvt[i].protocol == sip->si_proto) { 559 if (netid) 560 *netid = na_cvt[i].netid; 561 return 1; 562 } 563 564 return 0; 565} 566 567char * 568taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf) 569{ 570 struct __rpc_sockinfo si; 571 572 if (!__rpc_nconf2sockinfo(nconf, &si)) 573 return NULL; 574 return __rpc_taddr2uaddr_af(si.si_af, nbuf); 575} 576 577struct netbuf * 578uaddr2taddr(const struct netconfig *nconf, const char *uaddr) 579{ 580 struct __rpc_sockinfo si; 581 582 if (!__rpc_nconf2sockinfo(nconf, &si)) 583 return NULL; 584 return __rpc_uaddr2taddr_af(si.si_af, uaddr); 585} 586 587char * 588__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf) 589{ 590 char *ret; 591 struct sockaddr_in *sin; 592 struct sockaddr_un *sun; 593 char namebuf[INET_ADDRSTRLEN]; 594#ifdef INET6 595 struct sockaddr_in6 *sin6; 596 char namebuf6[INET6_ADDRSTRLEN]; 597#endif 598 u_int16_t port; 599 600 switch (af) { 601 case AF_INET: 602 sin = nbuf->buf; 603 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf) 604 == NULL) 605 return NULL; 606 port = ntohs(sin->sin_port); 607 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8, 608 port & 0xff) < 0) 609 return NULL; 610 break; 611#ifdef INET6 612 case AF_INET6: 613 sin6 = nbuf->buf; 614 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6) 615 == NULL) 616 return NULL; 617 port = ntohs(sin6->sin6_port); 618 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8, 619 port & 0xff) < 0) 620 return NULL; 621 break; 622#endif 623 case AF_LOCAL: 624 sun = nbuf->buf; 625 if (asprintf(&ret, "%.*s", (int)(sun->sun_len - 626 offsetof(struct sockaddr_un, sun_path)), 627 sun->sun_path) < 0) 628 return (NULL); 629 break; 630 default: 631 return NULL; 632 } 633 634 return ret; 635} 636 637struct netbuf * 638__rpc_uaddr2taddr_af(int af, const char *uaddr) 639{ 640 struct netbuf *ret = NULL; 641 char *addrstr, *p; 642 unsigned port, portlo, porthi; 643 struct sockaddr_in *sin; 644#ifdef INET6 645 struct sockaddr_in6 *sin6; 646#endif 647 struct sockaddr_un *sun; 648 649 port = 0; 650 sin = NULL; 651 addrstr = strdup(uaddr); 652 if (addrstr == NULL) 653 return NULL; 654 655 /* 656 * AF_LOCAL addresses are expected to be absolute 657 * pathnames, anything else will be AF_INET or AF_INET6. 658 */ 659 if (*addrstr != '/') { 660 p = strrchr(addrstr, '.'); 661 if (p == NULL) 662 goto out; 663 portlo = (unsigned)atoi(p + 1); 664 *p = '\0'; 665 666 p = strrchr(addrstr, '.'); 667 if (p == NULL) 668 goto out; 669 porthi = (unsigned)atoi(p + 1); 670 *p = '\0'; 671 port = (porthi << 8) | portlo; 672 } 673 674 ret = (struct netbuf *)malloc(sizeof *ret); 675 676 switch (af) { 677 case AF_INET: 678 sin = (struct sockaddr_in *)malloc(sizeof *sin); 679 if (sin == NULL) 680 goto out; 681 memset(sin, 0, sizeof *sin); 682 sin->sin_family = AF_INET; 683 sin->sin_port = htons(port); 684 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) { 685 free(sin); 686 free(ret); 687 ret = NULL; 688 goto out; 689 } 690 sin->sin_len = ret->maxlen = ret->len = sizeof *sin; 691 ret->buf = sin; 692 break; 693#ifdef INET6 694 case AF_INET6: 695 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6); 696 if (sin6 == NULL) 697 goto out; 698 memset(sin6, 0, sizeof *sin6); 699 sin6->sin6_family = AF_INET6; 700 sin6->sin6_port = htons(port); 701 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) { 702 free(sin); 703 free(ret); 704 ret = NULL; 705 goto out; 706 } 707 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6; 708 ret->buf = sin6; 709 break; 710#endif 711 case AF_LOCAL: 712 sun = (struct sockaddr_un *)malloc(sizeof *sun); 713 if (sun == NULL) 714 goto out; 715 memset(sun, 0, sizeof *sun); 716 sun->sun_family = AF_LOCAL; 717 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1); 718 ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun); 719 ret->buf = sun; 720 break; 721 default: 722 break; 723 } 724out: 725 free(addrstr); 726 return ret; 727} 728 729int 730__rpc_seman2socktype(int semantics) 731{ 732 switch (semantics) { 733 case NC_TPI_CLTS: 734 return SOCK_DGRAM; 735 case NC_TPI_COTS_ORD: 736 return SOCK_STREAM; 737 case NC_TPI_RAW: 738 return SOCK_RAW; 739 default: 740 break; 741 } 742 743 return -1; 744} 745 746int 747__rpc_socktype2seman(int socktype) 748{ 749 switch (socktype) { 750 case SOCK_DGRAM: 751 return NC_TPI_CLTS; 752 case SOCK_STREAM: 753 return NC_TPI_COTS_ORD; 754 case SOCK_RAW: 755 return NC_TPI_RAW; 756 default: 757 break; 758 } 759 760 return -1; 761} 762 763/* 764 * XXXX - IPv6 scope IDs can't be handled in universal addresses. 765 * Here, we compare the original server address to that of the RPC 766 * service we just received back from a call to rpcbind on the remote 767 * machine. If they are both "link local" or "site local", copy 768 * the scope id of the server address over to the service address. 769 */ 770int 771__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc) 772{ 773#ifdef INET6 774 struct sockaddr *sa_new, *sa_svc; 775 struct sockaddr_in6 *sin6_new, *sin6_svc; 776 777 sa_svc = (struct sockaddr *)svc->buf; 778 sa_new = (struct sockaddr *)new->buf; 779 780 if (sa_new->sa_family == sa_svc->sa_family && 781 sa_new->sa_family == AF_INET6) { 782 sin6_new = (struct sockaddr_in6 *)new->buf; 783 sin6_svc = (struct sockaddr_in6 *)svc->buf; 784 785 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) && 786 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) || 787 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) && 788 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) { 789 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id; 790 } 791 } 792#endif 793 return 1; 794} 795 796int 797__rpc_sockisbound(int fd) 798{ 799 struct sockaddr_storage ss; 800 socklen_t slen; 801 802 slen = sizeof (struct sockaddr_storage); 803 if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) 804 return 0; 805 806 switch (ss.ss_family) { 807 case AF_INET: 808 return (((struct sockaddr_in *) 809 (void *)&ss)->sin_port != 0); 810#ifdef INET6 811 case AF_INET6: 812 return (((struct sockaddr_in6 *) 813 (void *)&ss)->sin6_port != 0); 814#endif 815 case AF_LOCAL: 816 /* XXX check this */ 817 return (((struct sockaddr_un *) 818 (void *)&ss)->sun_path[0] != '\0'); 819 default: 820 break; 821 } 822 823 return 0; 824} 825