Remove building with NOCRYPTO option
[minix3.git] / lib / libc / rpc / rpc_generic.c
blob6912eafbc2adf8ae600b9e746a4a5983be649d61
1 /* $NetBSD: rpc_generic.c,v 1.29 2013/04/05 03:17:38 dholland Exp $ */
3 /*
4 * Copyright (c) 2010, Oracle America, Inc.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
16 * * Neither the name of the "Oracle America, Inc." nor the names of its
17 * contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
27 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 * Copyright (c) 1986-1991 by Sun Microsystems Inc.
37 /* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */
40 * rpc_generic.c, Miscl routines for RPC.
44 #include <sys/cdefs.h>
45 #if defined(LIBC_SCCS) && !defined(lint)
46 __RCSID("$NetBSD: rpc_generic.c,v 1.29 2013/04/05 03:17:38 dholland Exp $");
47 #endif
49 #include "namespace.h"
50 #include "reentrant.h"
51 #include <sys/types.h>
52 #include <sys/param.h>
53 #include <sys/socket.h>
54 #include <sys/un.h>
55 #include <sys/resource.h>
56 #include <netinet/in.h>
57 #include <netinet/tcp.h>
58 #include <arpa/inet.h>
59 #include <rpc/rpc.h>
60 #include <assert.h>
61 #include <ctype.h>
62 #include <stdio.h>
63 #include <netdb.h>
64 #include <netconfig.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <syslog.h>
68 #include <rpc/nettype.h>
70 #include "svc_fdset.h"
71 #include "rpc_internal.h"
73 #ifdef __weak_alias
74 __weak_alias(taddr2uaddr,_taddr2uaddr)
75 __weak_alias(uaddr2taddr,_uaddr2taddr)
76 #endif
78 struct handle {
79 NCONF_HANDLE *nhandle;
80 int nflag; /* Whether NETPATH or NETCONFIG */
81 int nettype;
84 static const struct _rpcnettype {
85 const char *name;
86 const int type;
87 } _rpctypelist[] = {
88 { "netpath", _RPC_NETPATH },
89 { "visible", _RPC_VISIBLE },
90 { "circuit_v", _RPC_CIRCUIT_V },
91 { "datagram_v", _RPC_DATAGRAM_V },
92 { "circuit_n", _RPC_CIRCUIT_N },
93 { "datagram_n", _RPC_DATAGRAM_N },
94 { "tcp", _RPC_TCP },
95 { "udp", _RPC_UDP },
96 { 0, _RPC_NONE }
99 struct netid_af {
100 const char *netid;
101 int af;
102 int protocol;
105 static const struct netid_af na_cvt[] = {
106 { "udp", AF_INET, IPPROTO_UDP },
107 { "tcp", AF_INET, IPPROTO_TCP },
108 #ifdef INET6
109 { "udp6", AF_INET6, IPPROTO_UDP },
110 { "tcp6", AF_INET6, IPPROTO_TCP },
111 #endif
112 { "local", AF_LOCAL, 0 }
115 #if 0
116 static char *strlocase(char *);
117 #endif
118 static int getnettype(const char *);
121 * Cache the result of getrlimit(), so we don't have to do an
122 * expensive call every time.
125 __rpc_dtbsize(void)
127 static int tbsize;
128 struct rlimit rl;
130 if (tbsize) {
131 return (tbsize);
133 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
134 return (tbsize = (int)rl.rlim_max);
137 * Something wrong. I'll try to save face by returning a
138 * pessimistic number.
140 return (32);
145 * Find the appropriate buffer size
147 u_int
148 /*ARGSUSED*/
149 __rpc_get_t_size(
150 int af,
151 int proto,
152 int size) /* Size requested */
154 int maxsize, defsize;
156 maxsize = 256 * 1024; /* XXX */
157 switch (proto) {
158 case IPPROTO_TCP:
159 defsize = 64 * 1024; /* XXX */
160 break;
161 case IPPROTO_UDP:
162 defsize = UDPMSGSIZE;
163 break;
164 default:
165 defsize = RPC_MAXDATASIZE;
166 break;
168 if (size == 0)
169 return defsize;
171 /* Check whether the value is within the upper max limit */
172 return (size > maxsize ? (u_int)maxsize : (u_int)size);
176 * Find the appropriate address buffer size
178 u_int
179 __rpc_get_a_size(int af)
181 switch (af) {
182 case AF_INET:
183 return sizeof (struct sockaddr_in);
184 #ifdef INET6
185 case AF_INET6:
186 return sizeof (struct sockaddr_in6);
187 #endif
188 case AF_LOCAL:
189 return sizeof (struct sockaddr_un);
190 default:
191 break;
193 return ((u_int)RPC_MAXADDRSIZE);
196 #if 0
197 static char *
198 strlocase(char *p)
200 char *t = p;
202 _DIAGASSERT(p != NULL);
204 for (; *p; p++)
205 if (isupper(*p))
206 *p = tolower(*p);
207 return (t);
209 #endif
212 * Returns the type of the network as defined in <rpc/nettype.h>
213 * If nettype is NULL, it defaults to NETPATH.
215 static int
216 getnettype(const char *nettype)
218 int i;
220 if ((nettype == NULL) || (nettype[0] == 0)) {
221 return (_RPC_NETPATH); /* Default */
224 #if 0
225 nettype = strlocase(nettype);
226 #endif
227 for (i = 0; _rpctypelist[i].name; i++)
228 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
229 return (_rpctypelist[i].type);
231 return (_rpctypelist[i].type);
235 * For the given nettype (tcp or udp only), return the first structure found.
236 * This should be freed by calling freenetconfigent()
239 #ifdef _REENTRANT
240 static thread_key_t tcp_key, udp_key;
241 static once_t __rpc_getconfigp_once = ONCE_INITIALIZER;
243 static void
244 __rpc_getconfigp_setup(void)
247 thr_keycreate(&tcp_key, free);
248 thr_keycreate(&udp_key, free);
250 #endif
252 struct netconfig *
253 __rpc_getconfip(const char *nettype)
255 char *netid;
256 char *netid_tcp = NULL;
257 char *netid_udp = NULL;
258 static char *netid_tcp_main;
259 static char *netid_udp_main;
260 struct netconfig *dummy;
261 #ifdef _REENTRANT
262 if (__isthreaded == 0) {
263 netid_udp = netid_udp_main;
264 netid_tcp = netid_tcp_main;
265 } else {
266 thr_once(&__rpc_getconfigp_once, __rpc_getconfigp_setup);
267 netid_tcp = thr_getspecific(tcp_key);
268 netid_udp = thr_getspecific(udp_key);
270 #else
271 netid_udp = netid_udp_main;
272 netid_tcp = netid_tcp_main;
273 #endif
275 _DIAGASSERT(nettype != NULL);
277 if (!netid_udp && !netid_tcp) {
278 struct netconfig *nconf;
279 void *confighandle;
281 if (!(confighandle = setnetconfig())) {
282 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
283 return (NULL);
285 while ((nconf = getnetconfig(confighandle)) != NULL) {
286 if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
287 if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
288 netid_tcp = strdup(nconf->nc_netid);
289 if (netid_tcp == NULL)
290 return NULL;
291 #ifdef _REENTRANT
292 if (__isthreaded == 0)
293 netid_tcp_main = netid_tcp;
294 else
295 thr_setspecific(tcp_key,
296 (void *) netid_tcp);
297 #else
298 netid_tcp_main = netid_tcp;
299 #endif
300 } else
301 if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
302 netid_udp = strdup(nconf->nc_netid);
303 if (netid_udp == NULL)
304 return NULL;
305 #ifdef _REENTRANT
306 if (__isthreaded == 0)
307 netid_udp_main = netid_udp;
308 else
309 thr_setspecific(udp_key,
310 (void *) netid_udp);
311 #else
312 netid_udp_main = netid_udp;
313 #endif
317 endnetconfig(confighandle);
319 if (strcmp(nettype, "udp") == 0)
320 netid = netid_udp;
321 else if (strcmp(nettype, "tcp") == 0)
322 netid = netid_tcp;
323 else {
324 return (NULL);
326 if ((netid == NULL) || (netid[0] == 0)) {
327 return (NULL);
329 dummy = getnetconfigent(netid);
330 return (dummy);
334 * Returns the type of the nettype, which should then be used with
335 * __rpc_getconf().
337 void *
338 __rpc_setconf(const char *nettype)
340 struct handle *handle;
342 /* nettype may be NULL; getnettype() supports that */
344 handle = malloc(sizeof(*handle));
345 if (handle == NULL) {
346 return (NULL);
348 switch (handle->nettype = getnettype(nettype)) {
349 case _RPC_NETPATH:
350 case _RPC_CIRCUIT_N:
351 case _RPC_DATAGRAM_N:
352 if (!(handle->nhandle = setnetpath())) {
353 free(handle);
354 return (NULL);
356 handle->nflag = TRUE;
357 break;
358 case _RPC_VISIBLE:
359 case _RPC_CIRCUIT_V:
360 case _RPC_DATAGRAM_V:
361 case _RPC_TCP:
362 case _RPC_UDP:
363 if (!(handle->nhandle = setnetconfig())) {
364 syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
365 free(handle);
366 return (NULL);
368 handle->nflag = FALSE;
369 break;
370 default:
371 free(handle);
372 return (NULL);
375 return (handle);
379 * Returns the next netconfig struct for the given "net" type.
380 * __rpc_setconf() should have been called previously.
382 struct netconfig *
383 __rpc_getconf(void *vhandle)
385 struct handle *handle;
386 struct netconfig *nconf;
388 handle = (struct handle *)vhandle;
389 if (handle == NULL) {
390 return (NULL);
392 for (;;) {
393 if (handle->nflag)
394 nconf = getnetpath(handle->nhandle);
395 else
396 nconf = getnetconfig(handle->nhandle);
397 if (nconf == NULL)
398 break;
399 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
400 (nconf->nc_semantics != NC_TPI_COTS) &&
401 (nconf->nc_semantics != NC_TPI_COTS_ORD))
402 continue;
403 switch (handle->nettype) {
404 case _RPC_VISIBLE:
405 if (!(nconf->nc_flag & NC_VISIBLE))
406 continue;
407 /* FALLTHROUGH */
408 case _RPC_NETPATH: /* Be happy */
409 break;
410 case _RPC_CIRCUIT_V:
411 if (!(nconf->nc_flag & NC_VISIBLE))
412 continue;
413 /* FALLTHROUGH */
414 case _RPC_CIRCUIT_N:
415 if ((nconf->nc_semantics != NC_TPI_COTS) &&
416 (nconf->nc_semantics != NC_TPI_COTS_ORD))
417 continue;
418 break;
419 case _RPC_DATAGRAM_V:
420 if (!(nconf->nc_flag & NC_VISIBLE))
421 continue;
422 /* FALLTHROUGH */
423 case _RPC_DATAGRAM_N:
424 if (nconf->nc_semantics != NC_TPI_CLTS)
425 continue;
426 break;
427 case _RPC_TCP:
428 if (((nconf->nc_semantics != NC_TPI_COTS) &&
429 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
430 (strcmp(nconf->nc_protofmly, NC_INET)
431 #ifdef INET6
432 && strcmp(nconf->nc_protofmly, NC_INET6))
433 #else
435 #endif
437 strcmp(nconf->nc_proto, NC_TCP))
438 continue;
439 break;
440 case _RPC_UDP:
441 if ((nconf->nc_semantics != NC_TPI_CLTS) ||
442 (strcmp(nconf->nc_protofmly, NC_INET)
443 #ifdef INET6
444 && strcmp(nconf->nc_protofmly, NC_INET6))
445 #else
447 #endif
449 strcmp(nconf->nc_proto, NC_UDP))
450 continue;
451 break;
453 break;
455 return (nconf);
458 void
459 __rpc_endconf(void *vhandle)
461 struct handle *handle;
463 handle = (struct handle *) vhandle;
464 if (handle == NULL) {
465 return;
467 if (handle->nflag) {
468 endnetpath(handle->nhandle);
469 } else {
470 endnetconfig(handle->nhandle);
472 free(handle);
476 * Used to ping the NULL procedure for clnt handle.
477 * Returns NULL if fails, else a non-NULL pointer.
479 void *
480 rpc_nullproc(CLIENT *clnt)
482 struct timeval TIMEOUT = {25, 0};
484 if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
485 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
486 return (NULL);
488 return ((void *) clnt);
492 * Try all possible transports until
493 * one succeeds in finding the netconf for the given fd.
495 struct netconfig *
496 __rpcgettp(int fd)
498 const char *netid;
499 struct __rpc_sockinfo si;
501 if (!__rpc_fd2sockinfo(fd, &si))
502 return NULL;
504 if (!__rpc_sockinfo2netid(&si, &netid))
505 return NULL;
507 return getnetconfigent(__UNCONST(netid));
511 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
513 socklen_t len;
514 int type, proto;
515 struct sockaddr_storage ss;
517 _DIAGASSERT(sip != NULL);
519 len = sizeof ss;
520 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
521 return 0;
522 sip->si_alen = len;
524 len = sizeof type;
525 if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
526 return 0;
528 /* XXX */
529 if (ss.ss_family != AF_LOCAL) {
530 if (type == SOCK_STREAM)
531 proto = IPPROTO_TCP;
532 else if (type == SOCK_DGRAM)
533 proto = IPPROTO_UDP;
534 else
535 return 0;
536 } else
537 proto = 0;
539 sip->si_af = ss.ss_family;
540 sip->si_proto = proto;
541 sip->si_socktype = type;
543 return 1;
547 * Linear search, but the number of entries is small.
550 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
552 size_t i;
554 _DIAGASSERT(nconf != NULL);
555 _DIAGASSERT(sip != NULL);
557 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
558 if (!strcmp(na_cvt[i].netid, nconf->nc_netid)) {
559 sip->si_af = na_cvt[i].af;
560 sip->si_proto = na_cvt[i].protocol;
561 sip->si_socktype =
562 __rpc_seman2socktype((int)nconf->nc_semantics);
563 if (sip->si_socktype == -1)
564 return 0;
565 sip->si_alen = __rpc_get_a_size(sip->si_af);
566 return 1;
569 return 0;
573 __rpc_nconf2fd(const struct netconfig *nconf)
575 struct __rpc_sockinfo si;
577 _DIAGASSERT(nconf != NULL);
579 if (!__rpc_nconf2sockinfo(nconf, &si))
580 return 0;
582 return socket(si.si_af, si.si_socktype, si.si_proto);
586 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
588 size_t i;
590 _DIAGASSERT(sip != NULL);
591 /* netid may be NULL */
593 for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
594 if (na_cvt[i].af == sip->si_af &&
595 na_cvt[i].protocol == sip->si_proto) {
596 if (netid)
597 *netid = na_cvt[i].netid;
598 return 1;
601 return 0;
604 char *
605 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
607 struct __rpc_sockinfo si;
609 _DIAGASSERT(nconf != NULL);
610 _DIAGASSERT(nbuf != NULL);
612 if (!__rpc_nconf2sockinfo(nconf, &si))
613 return NULL;
614 return __rpc_taddr2uaddr_af(si.si_af, nbuf);
617 struct netbuf *
618 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
620 struct __rpc_sockinfo si;
622 _DIAGASSERT(nconf != NULL);
623 _DIAGASSERT(uaddr != NULL);
625 if (!__rpc_nconf2sockinfo(nconf, &si))
626 return NULL;
627 return __rpc_uaddr2taddr_af(si.si_af, uaddr);
630 char *
631 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
633 char *ret;
634 struct sockaddr_in *sinp;
635 struct sockaddr_un *sun;
636 char namebuf[INET_ADDRSTRLEN];
637 #ifdef INET6
638 struct sockaddr_in6 *sin6;
639 char namebuf6[INET6_ADDRSTRLEN];
640 #endif
641 u_int16_t port;
643 _DIAGASSERT(nbuf != NULL);
645 switch (af) {
646 case AF_INET:
647 sinp = nbuf->buf;
648 if (inet_ntop(af, &sinp->sin_addr, namebuf,
649 (socklen_t)sizeof namebuf) == NULL)
650 return NULL;
651 port = ntohs(sinp->sin_port);
652 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
653 port & 0xff) < 0)
654 return NULL;
655 break;
656 #ifdef INET6
657 case AF_INET6:
658 sin6 = nbuf->buf;
659 if (inet_ntop(af, &sin6->sin6_addr, namebuf6,
660 (socklen_t)sizeof namebuf6) == NULL)
661 return NULL;
662 port = ntohs(sin6->sin6_port);
663 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
664 port & 0xff) < 0)
665 return NULL;
666 break;
667 #endif
668 case AF_LOCAL:
669 sun = nbuf->buf;
670 sun->sun_path[sizeof(sun->sun_path) - 1] = '\0'; /* safety */
671 ret = strdup(sun->sun_path);
672 break;
673 default:
674 return NULL;
677 return ret;
680 struct netbuf *
681 __rpc_uaddr2taddr_af(int af, const char *uaddr)
683 struct netbuf *ret = NULL;
684 char *addrstr, *p;
685 unsigned port, portlo, porthi;
686 size_t len;
687 struct sockaddr_in *sinp;
688 #ifdef INET6
689 struct sockaddr_in6 *sin6;
690 #endif
691 struct sockaddr_un *sun;
693 _DIAGASSERT(uaddr != NULL);
695 addrstr = strdup(uaddr);
696 if (addrstr == NULL)
697 return NULL;
700 * AF_LOCAL addresses are expected to be absolute
701 * pathnames, anything else will be AF_INET or AF_INET6.
703 port = 0;
704 if (*addrstr != '/') {
705 p = strrchr(addrstr, '.');
706 if (p == NULL)
707 goto out;
708 portlo = (unsigned)atoi(p + 1);
709 *p = '\0';
711 p = strrchr(addrstr, '.');
712 if (p == NULL)
713 goto out;
714 porthi = (unsigned)atoi(p + 1);
715 *p = '\0';
716 port = (porthi << 8) | portlo;
719 ret = malloc(sizeof(*ret));
720 if (ret == NULL)
721 goto out;
723 switch (af) {
724 case AF_INET:
725 sinp = malloc(sizeof(*sinp));
726 if (sinp == NULL)
727 goto out;
728 memset(sinp, 0, sizeof *sinp);
729 sinp->sin_family = AF_INET;
730 sinp->sin_port = htons(port);
731 if (inet_pton(AF_INET, addrstr, &sinp->sin_addr) <= 0) {
732 free(sinp);
733 free(ret);
734 ret = NULL;
735 goto out;
737 sinp->sin_len = ret->maxlen = ret->len = sizeof *sinp;
738 ret->buf = sinp;
739 break;
740 #ifdef INET6
741 case AF_INET6:
742 sin6 = malloc(sizeof(*sin6));
743 if (sin6 == NULL)
744 goto out;
745 memset(sin6, 0, sizeof *sin6);
746 sin6->sin6_family = AF_INET6;
747 sin6->sin6_port = htons(port);
748 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
749 free(sin6);
750 free(ret);
751 ret = NULL;
752 goto out;
754 sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
755 ret->buf = sin6;
756 break;
757 #endif
758 case AF_LOCAL:
759 sun = malloc(sizeof(*sun));
760 if (sun == NULL)
761 goto out;
762 memset(sun, 0, sizeof *sun);
763 sun->sun_family = AF_LOCAL;
764 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
765 len = SUN_LEN(sun);
766 _DIAGASSERT(__type_fit(uint8_t, len));
767 ret->len = ret->maxlen = sun->sun_len = (uint8_t)len;
768 ret->buf = sun;
769 break;
770 default:
771 break;
773 out:
774 free(addrstr);
775 return ret;
779 __rpc_seman2socktype(int semantics)
781 switch (semantics) {
782 case NC_TPI_CLTS:
783 return SOCK_DGRAM;
784 case NC_TPI_COTS_ORD:
785 return SOCK_STREAM;
786 case NC_TPI_RAW:
787 return SOCK_RAW;
788 default:
789 break;
792 return -1;
796 __rpc_socktype2seman(int socktype)
798 switch (socktype) {
799 case SOCK_DGRAM:
800 return NC_TPI_CLTS;
801 case SOCK_STREAM:
802 return NC_TPI_COTS_ORD;
803 case SOCK_RAW:
804 return NC_TPI_RAW;
805 default:
806 break;
809 return -1;
813 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
814 * Here, we compare the original server address to that of the RPC
815 * service we just received back from a call to rpcbind on the remote
816 * machine. If they are both "link local" or "site local", copy
817 * the scope id of the server address over to the service address.
819 /* ARGSUSED */
821 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
823 #ifdef INET6
824 struct sockaddr *sa_new, *sa_svc;
825 struct sockaddr_in6 *sin6_new, *sin6_svc;
827 _DIAGASSERT(new != NULL);
828 _DIAGASSERT(svc != NULL);
830 sa_svc = (struct sockaddr *)svc->buf;
831 sa_new = (struct sockaddr *)new->buf;
833 if (sa_new->sa_family == sa_svc->sa_family &&
834 sa_new->sa_family == AF_INET6) {
835 sin6_new = (struct sockaddr_in6 *)new->buf;
836 sin6_svc = (struct sockaddr_in6 *)svc->buf;
838 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
839 IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
840 (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
841 IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
842 sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
845 #endif
846 return 1;
850 __rpc_sockisbound(int fd)
852 struct sockaddr_storage ss;
853 socklen_t slen;
855 slen = sizeof (struct sockaddr_storage);
856 if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
857 return 0;
859 switch (ss.ss_family) {
860 case AF_INET:
861 return (((struct sockaddr_in *)
862 (void *)&ss)->sin_port != 0);
863 #ifdef INET6
864 case AF_INET6:
865 return (((struct sockaddr_in6 *)
866 (void *)&ss)->sin6_port != 0);
867 #endif
868 case AF_LOCAL:
869 /* XXX check this */
870 return (((struct sockaddr_un *)
871 (void *)&ss)->sun_path[0] != '\0');
872 default:
873 break;
876 return 0;
880 * For TCP transport, Host Requirements RFCs mandate
881 * Nagle (RFC-896) processing. But for RPC, Nagle
882 * processing adds adds unwanted latency to the last,
883 * partial TCP segment of each RPC message. See:
884 * R. W. Scheifler and J. Gettys, The X Window System,
885 * ACM Transactions on Graphics 16:8 (Aug. 1983), pp. 57-69.
886 * So for TCP transport, disable Nagle via TCP_NODELAY.
887 * XXX: moral equivalent for non-TCP protocols?
890 __rpc_setnodelay(int fd, const struct __rpc_sockinfo *si)
892 int one = 1;
893 if (si->si_proto != IPPROTO_TCP)
894 return 0;
895 return setsockopt(fd, si->si_proto, TCP_NODELAY, &one,
896 (socklen_t)sizeof(one));