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