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