rpc_generic.c revision 239963
1122397Sharti/*	$NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $	*/
2122397Sharti
3122397Sharti/*
4122397Sharti * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5122397Sharti * unrestricted use provided that this legend is included on all tape
6122397Sharti * media and as a part of the software program in whole or part.  Users
7122397Sharti * may copy or modify Sun RPC without charge, but are not authorized
8122397Sharti * to license or distribute it to anyone else except as part of a product or
9122397Sharti * program developed by the user.
10122397Sharti *
11122397Sharti * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12122397Sharti * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13122397Sharti * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14122397Sharti *
15122397Sharti * Sun RPC is provided with no support and without any obligation on the
16122397Sharti * part of Sun Microsystems, Inc. to assist in its use, correction,
17122397Sharti * modification or enhancement.
18122397Sharti *
19122397Sharti * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20125012Sharti * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21122397Sharti * OR ANY PART THEREOF.
22122397Sharti *
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#include <sys/cdefs.h>
37__FBSDID("$FreeBSD: head/lib/libc/rpc/rpc_generic.c 239963 2012-09-01 02:56:17Z pfg $");
38
39/*
40 * rpc_generic.c, Miscl routines for RPC.
41 *
42 */
43
44#include "namespace.h"
45#include "reentrant.h"
46#include <sys/types.h>
47#include <sys/param.h>
48#include <sys/socket.h>
49#include <sys/time.h>
50#include <sys/un.h>
51#include <sys/resource.h>
52#include <netinet/in.h>
53#include <arpa/inet.h>
54#include <rpc/rpc.h>
55#include <ctype.h>
56#include <stddef.h>
57#include <stdio.h>
58#include <netdb.h>
59#include <netconfig.h>
60#include <stdlib.h>
61#include <string.h>
62#include <syslog.h>
63#include <rpc/nettype.h>
64#include "un-namespace.h"
65#include "rpc_com.h"
66#include "mt_misc.h"
67
68struct handle {
69	NCONF_HANDLE *nhandle;
70	int nflag;		/* Whether NETPATH or NETCONFIG */
71	int nettype;
72};
73
74static const struct _rpcnettype {
75	const char *name;
76	const int type;
77} _rpctypelist[] = {
78	{ "netpath", _RPC_NETPATH },
79	{ "visible", _RPC_VISIBLE },
80	{ "circuit_v", _RPC_CIRCUIT_V },
81	{ "datagram_v", _RPC_DATAGRAM_V },
82	{ "circuit_n", _RPC_CIRCUIT_N },
83	{ "datagram_n", _RPC_DATAGRAM_N },
84	{ "tcp", _RPC_TCP },
85	{ "udp", _RPC_UDP },
86	{ 0, _RPC_NONE }
87};
88
89struct netid_af {
90	const char	*netid;
91	int		af;
92	int		protocol;
93};
94
95static const struct netid_af na_cvt[] = {
96	{ "udp",  AF_INET,  IPPROTO_UDP },
97	{ "tcp",  AF_INET,  IPPROTO_TCP },
98#ifdef INET6
99	{ "udp6", AF_INET6, IPPROTO_UDP },
100	{ "tcp6", AF_INET6, IPPROTO_TCP },
101#endif
102	{ "local", AF_LOCAL, 0 }
103};
104
105#if 0
106static char *strlocase(char *);
107#endif
108static int getnettype(const char *);
109
110/*
111 * Cache the result of getrlimit(), so we don't have to do an
112 * expensive call every time.
113 */
114int
115__rpc_dtbsize()
116{
117	static int tbsize;
118	struct rlimit rl;
119
120	if (tbsize) {
121		return (tbsize);
122	}
123	if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
124		return (tbsize = (int)rl.rlim_max);
125	}
126	/*
127	 * Something wrong.  I'll try to save face by returning a
128	 * pessimistic number.
129	 */
130	return (32);
131}
132
133
134/*
135 * Find the appropriate buffer size
136 */
137u_int
138/*ARGSUSED*/
139__rpc_get_t_size(af, proto, size)
140	int af, proto;
141	int size;	/* Size requested */
142{
143	int maxsize, defsize;
144
145	maxsize = 256 * 1024;	/* XXX */
146	switch (proto) {
147	case IPPROTO_TCP:
148		defsize = 64 * 1024;	/* XXX */
149		break;
150	case IPPROTO_UDP:
151		defsize = UDPMSGSIZE;
152		break;
153	default:
154		defsize = RPC_MAXDATASIZE;
155		break;
156	}
157	if (size == 0)
158		return defsize;
159
160	/* Check whether the value is within the upper max limit */
161	return (size > maxsize ? (u_int)maxsize : (u_int)size);
162}
163
164/*
165 * Find the appropriate address buffer size
166 */
167u_int
168__rpc_get_a_size(af)
169	int af;
170{
171	switch (af) {
172	case AF_INET:
173		return sizeof (struct sockaddr_in);
174#ifdef INET6
175	case AF_INET6:
176		return sizeof (struct sockaddr_in6);
177#endif
178	case AF_LOCAL:
179		return sizeof (struct sockaddr_un);
180	default:
181		break;
182	}
183	return ((u_int)RPC_MAXADDRSIZE);
184}
185
186#if 0
187static char *
188strlocase(p)
189	char *p;
190{
191	char *t = p;
192
193	for (; *p; p++)
194		if (isupper(*p))
195			*p = tolower(*p);
196	return (t);
197}
198#endif
199
200/*
201 * Returns the type of the network as defined in <rpc/nettype.h>
202 * If nettype is NULL, it defaults to NETPATH.
203 */
204static int
205getnettype(nettype)
206	const char *nettype;
207{
208	int i;
209
210	if ((nettype == NULL) || (nettype[0] == 0)) {
211		return (_RPC_NETPATH);	/* Default */
212	}
213
214#if 0
215	nettype = strlocase(nettype);
216#endif
217	for (i = 0; _rpctypelist[i].name; i++)
218		if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
219			return (_rpctypelist[i].type);
220		}
221	return (_rpctypelist[i].type);
222}
223
224static thread_key_t tcp_key, udp_key;
225static once_t keys_once = ONCE_INITIALIZER;
226static int tcp_key_error, udp_key_error;
227
228static void
229keys_init(void)
230{
231
232	tcp_key_error = thr_keycreate(&tcp_key, free);
233	udp_key_error = thr_keycreate(&udp_key, free);
234}
235
236/*
237 * For the given nettype (tcp or udp only), return the first structure found.
238 * This should be freed by calling freenetconfigent()
239 */
240struct netconfig *
241__rpc_getconfip(nettype)
242	const char *nettype;
243{
244	char *netid;
245	char *netid_tcp = (char *) NULL;
246	char *netid_udp = (char *) NULL;
247	static char *netid_tcp_main;
248	static char *netid_udp_main;
249	struct netconfig *dummy;
250	int main_thread;
251
252	if ((main_thread = thr_main())) {
253		netid_udp = netid_udp_main;
254		netid_tcp = netid_tcp_main;
255	} else {
256		if (thr_once(&keys_once, keys_init) != 0 ||
257		    tcp_key_error != 0 || udp_key_error != 0)
258			return (NULL);
259		netid_tcp = (char *)thr_getspecific(tcp_key);
260		netid_udp = (char *)thr_getspecific(udp_key);
261	}
262	if (!netid_udp && !netid_tcp) {
263		struct netconfig *nconf;
264		void *confighandle;
265
266		if (!(confighandle = setnetconfig())) {
267			syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
268			return (NULL);
269		}
270		while ((nconf = getnetconfig(confighandle)) != NULL) {
271			if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
272				if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
273				    netid_tcp == NULL) {
274					netid_tcp = strdup(nconf->nc_netid);
275					if (main_thread)
276						netid_tcp_main = netid_tcp;
277					else
278						thr_setspecific(tcp_key,
279							(void *) netid_tcp);
280				} else
281				if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
282				   netid_udp == NULL) {
283					netid_udp = strdup(nconf->nc_netid);
284					if (main_thread)
285						netid_udp_main = netid_udp;
286					else
287						thr_setspecific(udp_key,
288						(void *) netid_udp);
289				}
290			}
291		}
292		endnetconfig(confighandle);
293	}
294	if (strcmp(nettype, "udp") == 0)
295		netid = netid_udp;
296	else if (strcmp(nettype, "tcp") == 0)
297		netid = netid_tcp;
298	else {
299		return (NULL);
300	}
301	if ((netid == NULL) || (netid[0] == 0)) {
302		return (NULL);
303	}
304	dummy = getnetconfigent(netid);
305	return (dummy);
306}
307
308/*
309 * Returns the type of the nettype, which should then be used with
310 * __rpc_getconf().
311 */
312void *
313__rpc_setconf(nettype)
314	const char *nettype;
315{
316	struct handle *handle;
317
318	handle = (struct handle *) malloc(sizeof (struct handle));
319	if (handle == NULL) {
320		return (NULL);
321	}
322	switch (handle->nettype = getnettype(nettype)) {
323	case _RPC_NETPATH:
324	case _RPC_CIRCUIT_N:
325	case _RPC_DATAGRAM_N:
326		if (!(handle->nhandle = setnetpath()))
327			goto failed;
328		handle->nflag = TRUE;
329		break;
330	case _RPC_VISIBLE:
331	case _RPC_CIRCUIT_V:
332	case _RPC_DATAGRAM_V:
333	case _RPC_TCP:
334	case _RPC_UDP:
335		if (!(handle->nhandle = setnetconfig())) {
336		        syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
337			goto failed;
338		}
339		handle->nflag = FALSE;
340		break;
341	default:
342		goto failed;
343	}
344
345	return (handle);
346
347failed:
348	free(handle);
349	return (NULL);
350}
351
352/*
353 * Returns the next netconfig struct for the given "net" type.
354 * __rpc_setconf() should have been called previously.
355 */
356struct 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
433void
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 */
455void *
456rpc_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 */
472struct 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
489int
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 */
526int
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) == 0 || (
533		    strcmp(nconf->nc_netid, "unix") == 0 &&
534		    strcmp(na_cvt[i].netid, "local") == 0)) {
535			sip->si_af = na_cvt[i].af;
536			sip->si_proto = na_cvt[i].protocol;
537			sip->si_socktype =
538			    __rpc_seman2socktype((int)nconf->nc_semantics);
539			if (sip->si_socktype == -1)
540				return 0;
541			sip->si_alen = __rpc_get_a_size(sip->si_af);
542			return 1;
543		}
544
545	return 0;
546}
547
548int
549__rpc_nconf2fd(const struct netconfig *nconf)
550{
551	struct __rpc_sockinfo si;
552
553	if (!__rpc_nconf2sockinfo(nconf, &si))
554		return 0;
555
556	return _socket(si.si_af, si.si_socktype, si.si_proto);
557}
558
559int
560__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
561{
562	int i;
563	struct netconfig *nconf;
564
565	nconf = getnetconfigent("local");
566
567	for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
568		if (na_cvt[i].af == sip->si_af &&
569		    na_cvt[i].protocol == sip->si_proto) {
570			if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
571				if (netid)
572					*netid = "unix";
573			} else {
574				if (netid)
575					*netid = na_cvt[i].netid;
576			}
577			if (nconf != NULL)
578				freenetconfigent(nconf);
579			return 1;
580		}
581	}
582	if (nconf != NULL)
583		freenetconfigent(nconf);
584
585	return 0;
586}
587
588char *
589taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
590{
591	struct __rpc_sockinfo si;
592
593	if (!__rpc_nconf2sockinfo(nconf, &si))
594		return NULL;
595	return __rpc_taddr2uaddr_af(si.si_af, nbuf);
596}
597
598struct netbuf *
599uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
600{
601	struct __rpc_sockinfo si;
602
603	if (!__rpc_nconf2sockinfo(nconf, &si))
604		return NULL;
605	return __rpc_uaddr2taddr_af(si.si_af, uaddr);
606}
607
608char *
609__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
610{
611	char *ret;
612	struct sockaddr_in *sin;
613	struct sockaddr_un *sun;
614	char namebuf[INET_ADDRSTRLEN];
615#ifdef INET6
616	struct sockaddr_in6 *sin6;
617	char namebuf6[INET6_ADDRSTRLEN];
618#endif
619	u_int16_t port;
620
621	if (nbuf->len <= 0)
622		return NULL;
623
624	switch (af) {
625	case AF_INET:
626		sin = nbuf->buf;
627		if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
628		    == NULL)
629			return NULL;
630		port = ntohs(sin->sin_port);
631		if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
632		    port & 0xff) < 0)
633			return NULL;
634		break;
635#ifdef INET6
636	case AF_INET6:
637		sin6 = nbuf->buf;
638		if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
639		    == NULL)
640			return NULL;
641		port = ntohs(sin6->sin6_port);
642		if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
643		    port & 0xff) < 0)
644			return NULL;
645		break;
646#endif
647	case AF_LOCAL:
648		sun = nbuf->buf;
649		if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
650		    offsetof(struct sockaddr_un, sun_path)),
651		    sun->sun_path) < 0)
652			return (NULL);
653		break;
654	default:
655		return NULL;
656	}
657
658	return ret;
659}
660
661struct netbuf *
662__rpc_uaddr2taddr_af(int af, const char *uaddr)
663{
664	struct netbuf *ret = NULL;
665	char *addrstr, *p;
666	unsigned port, portlo, porthi;
667	struct sockaddr_in *sin;
668#ifdef INET6
669	struct sockaddr_in6 *sin6;
670#endif
671	struct sockaddr_un *sun;
672
673	port = 0;
674	sin = NULL;
675	addrstr = strdup(uaddr);
676	if (addrstr == NULL)
677		return NULL;
678
679	/*
680	 * AF_LOCAL addresses are expected to be absolute
681	 * pathnames, anything else will be AF_INET or AF_INET6.
682	 */
683	if (*addrstr != '/') {
684		p = strrchr(addrstr, '.');
685		if (p == NULL)
686			goto out;
687		portlo = (unsigned)atoi(p + 1);
688		*p = '\0';
689
690		p = strrchr(addrstr, '.');
691		if (p == NULL)
692			goto out;
693		porthi = (unsigned)atoi(p + 1);
694		*p = '\0';
695		port = (porthi << 8) | portlo;
696	}
697
698	ret = (struct netbuf *)malloc(sizeof *ret);
699	if (ret == NULL)
700		goto out;
701
702	switch (af) {
703	case AF_INET:
704		sin = (struct sockaddr_in *)malloc(sizeof *sin);
705		if (sin == NULL)
706			goto out;
707		memset(sin, 0, sizeof *sin);
708		sin->sin_family = AF_INET;
709		sin->sin_port = htons(port);
710		if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
711			free(sin);
712			free(ret);
713			ret = NULL;
714			goto out;
715		}
716		sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
717		ret->buf = sin;
718		break;
719#ifdef INET6
720	case AF_INET6:
721		sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
722		if (sin6 == NULL)
723			goto out;
724		memset(sin6, 0, sizeof *sin6);
725		sin6->sin6_family = AF_INET6;
726		sin6->sin6_port = htons(port);
727		if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
728			free(sin6);
729			free(ret);
730			ret = NULL;
731			goto out;
732		}
733		sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
734		ret->buf = sin6;
735		break;
736#endif
737	case AF_LOCAL:
738		sun = (struct sockaddr_un *)malloc(sizeof *sun);
739		if (sun == NULL)
740			goto out;
741		memset(sun, 0, sizeof *sun);
742		sun->sun_family = AF_LOCAL;
743		strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
744		ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
745		ret->buf = sun;
746		break;
747	default:
748		break;
749	}
750out:
751	free(addrstr);
752	return ret;
753}
754
755int
756__rpc_seman2socktype(int semantics)
757{
758	switch (semantics) {
759	case NC_TPI_CLTS:
760		return SOCK_DGRAM;
761	case NC_TPI_COTS_ORD:
762		return SOCK_STREAM;
763	case NC_TPI_RAW:
764		return SOCK_RAW;
765	default:
766		break;
767	}
768
769	return -1;
770}
771
772int
773__rpc_socktype2seman(int socktype)
774{
775	switch (socktype) {
776	case SOCK_DGRAM:
777		return NC_TPI_CLTS;
778	case SOCK_STREAM:
779		return NC_TPI_COTS_ORD;
780	case SOCK_RAW:
781		return NC_TPI_RAW;
782	default:
783		break;
784	}
785
786	return -1;
787}
788
789/*
790 * XXXX - IPv6 scope IDs can't be handled in universal addresses.
791 * Here, we compare the original server address to that of the RPC
792 * service we just received back from a call to rpcbind on the remote
793 * machine. If they are both "link local" or "site local", copy
794 * the scope id of the server address over to the service address.
795 */
796int
797__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
798{
799#ifdef INET6
800	struct sockaddr *sa_new, *sa_svc;
801	struct sockaddr_in6 *sin6_new, *sin6_svc;
802
803	sa_svc = (struct sockaddr *)svc->buf;
804	sa_new = (struct sockaddr *)new->buf;
805
806	if (sa_new->sa_family == sa_svc->sa_family &&
807	    sa_new->sa_family == AF_INET6) {
808		sin6_new = (struct sockaddr_in6 *)new->buf;
809		sin6_svc = (struct sockaddr_in6 *)svc->buf;
810
811		if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
812		     IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
813		    (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
814		     IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
815			sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
816		}
817	}
818#endif
819	return 1;
820}
821
822int
823__rpc_sockisbound(int fd)
824{
825	struct sockaddr_storage ss;
826	socklen_t slen;
827
828	slen = sizeof (struct sockaddr_storage);
829	if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
830		return 0;
831
832	switch (ss.ss_family) {
833		case AF_INET:
834			return (((struct sockaddr_in *)
835			    (void *)&ss)->sin_port != 0);
836#ifdef INET6
837		case AF_INET6:
838			return (((struct sockaddr_in6 *)
839			    (void *)&ss)->sin6_port != 0);
840#endif
841		case AF_LOCAL:
842			/* XXX check this */
843			return (((struct sockaddr_un *)
844			    (void *)&ss)->sun_path[0] != '\0');
845		default:
846			break;
847	}
848
849	return 0;
850}
851