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