Imported Upstream version 0.2.5
[platform/upstream/libtirpc.git] / src / rpc_generic.c
1 /*
2  * Copyright (c) 2009, Sun Microsystems, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * - Redistributions of source code must retain the above copyright notice,
8  *   this list of conditions and the following disclaimer.
9  * - Redistributions in binary form must reproduce the above copyright notice,
10  *   this list of conditions and the following disclaimer in the documentation
11  *   and/or other materials provided with the distribution.
12  * - Neither the name of Sun Microsystems, Inc. nor the names of its
13  *   contributors may be used to endorse or promote products derived
14  *   from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 /*
29  * Copyright (c) 1986-1991 by Sun Microsystems Inc. 
30  */
31
32 #include <sys/cdefs.h>
33
34 /*
35  * rpc_generic.c, Miscl routines for RPC.
36  *
37  */
38 #include <pthread.h>
39 #include <reentrant.h>
40 #include <sys/types.h>
41 #include <sys/param.h>
42 #include <sys/socket.h>
43 #include <sys/time.h>
44 #include <sys/un.h>
45 #include <sys/resource.h>
46 #include <netinet/in.h>
47 #include <arpa/inet.h>
48 #include <rpc/rpc.h>
49 #include <ctype.h>
50 #include <stddef.h>
51 #include <stdio.h>
52 #include <netdb.h>
53 #include <netconfig.h>
54 #include <stdlib.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 static const 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 const 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(char *);
99 #endif
100 static int getnettype(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, defsize;
136
137         maxsize = 256 * 1024;   /* XXX */
138         switch (proto) {
139         case IPPROTO_TCP:
140                 defsize = 64 * 1024;    /* XXX */
141                 break;
142         case IPPROTO_UDP:
143                 defsize = UDPMSGSIZE;
144                 break;
145         default:
146                 defsize = RPC_MAXDATASIZE;
147                 break;
148         }
149         if (size == 0)
150                 return defsize;
151
152         /* Check whether the value is within the upper max limit */
153         return (size > maxsize ? (u_int)maxsize : (u_int)size);
154 }
155
156 /*
157  * Find the appropriate address buffer size
158  */
159 u_int
160 __rpc_get_a_size(af)
161         int af;
162 {
163         switch (af) {
164         case AF_INET:
165                 return sizeof (struct sockaddr_in);
166 #ifdef INET6
167         case AF_INET6:
168                 return sizeof (struct sockaddr_in6);
169 #endif
170         case AF_LOCAL:
171                 return sizeof (struct sockaddr_un);
172         default:
173                 break;
174         }
175         return ((u_int)RPC_MAXADDRSIZE);
176 }
177
178 #if 0
179 static char *
180 strlocase(p)
181         char *p;
182 {
183         char *t = p;
184
185         for (; *p; p++)
186                 if (isupper(*p))
187                         *p = tolower(*p);
188         return (t);
189 }
190 #endif
191
192 /*
193  * Returns the type of the network as defined in <rpc/nettype.h>
194  * If nettype is NULL, it defaults to NETPATH.
195  */
196 static int
197 getnettype(nettype)
198         const char *nettype;
199 {
200         int i;
201
202         if ((nettype == NULL) || (nettype[0] == 0)) {
203                 return (_RPC_NETPATH);  /* Default */
204         }
205
206 #if 0
207         nettype = strlocase(nettype);
208 #endif
209         for (i = 0; _rpctypelist[i].name; i++)
210                 if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
211                         return (_rpctypelist[i].type);
212                 }
213         return (_rpctypelist[i].type);
214 }
215
216 /*
217  * For the given nettype (tcp or udp only), return the first structure found.
218  * This should be freed by calling freenetconfigent()
219  */
220 struct netconfig *
221 __rpc_getconfip(nettype)
222         const char *nettype;
223 {
224         char *netid;
225         char *netid_tcp = (char *) NULL;
226         char *netid_udp = (char *) NULL;
227         struct netconfig *dummy;
228         extern thread_key_t tcp_key, udp_key;
229         extern mutex_t tsd_lock;
230
231         if (tcp_key == KEY_INITIALIZER) {
232                 mutex_lock(&tsd_lock);
233                 if (tcp_key == KEY_INITIALIZER)
234                         thr_keycreate(&tcp_key, free);
235                 mutex_unlock(&tsd_lock);
236         }
237         netid_tcp = (char *)thr_getspecific(tcp_key);
238         if (udp_key == KEY_INITIALIZER) {
239                 mutex_lock(&tsd_lock);
240                 if (udp_key == KEY_INITIALIZER)
241                         thr_keycreate(&udp_key, free);
242                 mutex_unlock(&tsd_lock);
243         }
244         netid_udp = (char *)thr_getspecific(udp_key);
245         if (!netid_udp && !netid_tcp) {
246                 struct netconfig *nconf;
247                 void *confighandle;
248
249                 if (!(confighandle = setnetconfig())) {
250                         syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
251                         return (NULL);
252                 }
253                 while ((nconf = getnetconfig(confighandle)) != NULL) {
254                         if (strcmp(nconf->nc_protofmly, NC_INET) == 0 ||
255                             strcmp(nconf->nc_protofmly, NC_INET6) == 0) {
256                                 if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
257                                                 netid_tcp == NULL) {
258                                         netid_tcp = strdup(nconf->nc_netid);
259                                         thr_setspecific(tcp_key,
260                                                         (void *) netid_tcp);
261                                 } else
262                                 if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
263                                                 netid_udp == NULL) {
264                                         netid_udp = strdup(nconf->nc_netid);
265                                         thr_setspecific(udp_key,
266                                                 (void *) netid_udp);
267                                 }
268                         }
269                 }
270                 endnetconfig(confighandle);
271         }
272         if (strcmp(nettype, "udp") == 0)
273                 netid = netid_udp;
274         else if (strcmp(nettype, "tcp") == 0)
275                 netid = netid_tcp;
276         else {
277                 return (NULL);
278         }
279         if ((netid == NULL) || (netid[0] == 0)) {
280                 return (NULL);
281         }
282         dummy = getnetconfigent(netid);
283         return (dummy);
284 }
285
286 /*
287  * Returns the type of the nettype, which should then be used with
288  * __rpc_getconf().
289  */
290 void *
291 __rpc_setconf(nettype)
292         const char *nettype;
293 {
294         struct handle *handle;
295
296         handle = (struct handle *) malloc(sizeof (struct handle));
297         if (handle == NULL) {
298                 return (NULL);
299         }
300         switch (handle->nettype = getnettype(nettype)) {
301         case _RPC_NETPATH:
302         case _RPC_CIRCUIT_N:
303         case _RPC_DATAGRAM_N:
304                 if (!(handle->nhandle = setnetpath())) {
305                         free(handle);
306                         return (NULL);
307                 }
308                 handle->nflag = TRUE;
309                 break;
310         case _RPC_VISIBLE:
311         case _RPC_CIRCUIT_V:
312         case _RPC_DATAGRAM_V:
313         case _RPC_TCP:
314         case _RPC_UDP:
315                 if (!(handle->nhandle = setnetconfig())) {
316                         syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
317                         free(handle);
318                         return (NULL);
319                 }
320                 handle->nflag = FALSE;
321                 break;
322         default:
323                 return (NULL);
324         }
325
326         return (handle);
327 }
328
329 /*
330  * Returns the next netconfig struct for the given "net" type.
331  * __rpc_setconf() should have been called previously.
332  */
333 struct netconfig *
334 __rpc_getconf(vhandle)
335         void *vhandle;
336 {
337         struct handle *handle;
338         struct netconfig *nconf;
339
340         handle = (struct handle *)vhandle;
341         if (handle == NULL) {
342                 return (NULL);
343         }
344         for (;;) {
345                 if (handle->nflag)
346                         nconf = getnetpath(handle->nhandle);
347                 else
348                         nconf = getnetconfig(handle->nhandle);
349                 if (nconf == NULL)
350                         break;
351                 if ((nconf->nc_semantics != NC_TPI_CLTS) &&
352                         (nconf->nc_semantics != NC_TPI_COTS) &&
353                         (nconf->nc_semantics != NC_TPI_COTS_ORD))
354                         continue;
355                 switch (handle->nettype) {
356                 case _RPC_VISIBLE:
357                         if (!(nconf->nc_flag & NC_VISIBLE))
358                                 continue;
359                         /* FALLTHROUGH */
360                 case _RPC_NETPATH:      /* Be happy */
361                         break;
362                 case _RPC_CIRCUIT_V:
363                         if (!(nconf->nc_flag & NC_VISIBLE))
364                                 continue;
365                         /* FALLTHROUGH */
366                 case _RPC_CIRCUIT_N:
367                         if ((nconf->nc_semantics != NC_TPI_COTS) &&
368                                 (nconf->nc_semantics != NC_TPI_COTS_ORD))
369                                 continue;
370                         break;
371                 case _RPC_DATAGRAM_V:
372                         if (!(nconf->nc_flag & NC_VISIBLE))
373                                 continue;
374                         /* FALLTHROUGH */
375                 case _RPC_DATAGRAM_N:
376                         if (nconf->nc_semantics != NC_TPI_CLTS)
377                                 continue;
378                         break;
379                 case _RPC_TCP:
380                         if (((nconf->nc_semantics != NC_TPI_COTS) &&
381                                 (nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
382                                 (strcmp(nconf->nc_protofmly, NC_INET)
383 #ifdef INET6
384                                  && strcmp(nconf->nc_protofmly, NC_INET6))
385 #else
386                                 )
387 #endif
388                                 ||
389                                 strcmp(nconf->nc_proto, NC_TCP))
390                                 continue;
391                         break;
392                 case _RPC_UDP:
393                         if ((nconf->nc_semantics != NC_TPI_CLTS) ||
394                                 (strcmp(nconf->nc_protofmly, NC_INET)
395 #ifdef INET6
396                                 && strcmp(nconf->nc_protofmly, NC_INET6))
397 #else
398                                 )
399 #endif
400                                 ||
401                                 strcmp(nconf->nc_proto, NC_UDP))
402                                 continue;
403                         break;
404                 }
405                 break;
406         }
407         return (nconf);
408 }
409
410 void
411 __rpc_endconf(vhandle)
412         void * vhandle;
413 {
414         struct handle *handle;
415
416         handle = (struct handle *) vhandle;
417         if (handle == NULL) {
418                 return;
419         }
420         if (handle->nflag) {
421                 endnetpath(handle->nhandle);
422         } else {
423                 endnetconfig(handle->nhandle);
424         }
425         free(handle);
426 }
427
428 /*
429  * Used to ping the NULL procedure for clnt handle.
430  * Returns NULL if fails, else a non-NULL pointer.
431  */
432 void *
433 rpc_nullproc(clnt)
434         CLIENT *clnt;
435 {
436         struct timeval TIMEOUT = {25, 0};
437
438         if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
439                 (xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
440                 return (NULL);
441         }
442         return ((void *) clnt);
443 }
444
445 /*
446  * Try all possible transports until
447  * one succeeds in finding the netconf for the given fd.
448  */
449 struct netconfig *
450 __rpcgettp(fd)
451         int fd;
452 {
453         const char *netid;
454         struct __rpc_sockinfo si;
455
456         if (!__rpc_fd2sockinfo(fd, &si))
457                 return NULL;
458
459         if (!__rpc_sockinfo2netid(&si, &netid))
460                 return NULL;
461
462         /*LINTED const castaway*/
463         return getnetconfigent((char *)netid);
464 }
465
466 int
467 __rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
468 {
469         socklen_t len;
470         int type, proto;
471         struct sockaddr_storage ss;
472
473         len = sizeof ss;
474         if (getsockname(fd, (struct sockaddr *)&ss, &len) < 0)
475                 return 0;
476         sip->si_alen = len;
477
478         len = sizeof type;
479         if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
480                 return 0;
481
482         /* XXX */
483         if (ss.ss_family != AF_LOCAL) {
484                 if (type == SOCK_STREAM)
485                         proto = IPPROTO_TCP;
486                 else if (type == SOCK_DGRAM)
487                         proto = IPPROTO_UDP;
488                 else
489                         return 0;
490         } else
491                 proto = 0;
492
493         sip->si_af = ss.ss_family;
494         sip->si_proto = proto;
495         sip->si_socktype = type;
496
497         return 1;
498 }
499
500 /*
501  * Linear search, but the number of entries is small.
502  */
503 int
504 __rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
505 {
506         int i;
507
508         for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
509                 if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
510                     strcmp(nconf->nc_netid, "unix") == 0 &&
511                     strcmp(na_cvt[i].netid, "local") == 0)) {
512                         sip->si_af = na_cvt[i].af;
513                         sip->si_proto = na_cvt[i].protocol;
514                         sip->si_socktype =
515                             __rpc_seman2socktype((int)nconf->nc_semantics);
516                         if (sip->si_socktype == -1)
517                                 return 0;
518                         sip->si_alen = __rpc_get_a_size(sip->si_af);
519                         return 1;
520                 }
521
522         return 0;
523 }
524
525 int
526 __rpc_nconf2fd_flags(const struct netconfig *nconf, int flags)
527 {
528         struct __rpc_sockinfo si;
529         int fd;
530
531         if (!__rpc_nconf2sockinfo(nconf, &si))
532                 return 0;
533
534         if ((fd = socket(si.si_af, si.si_socktype | flags, si.si_proto)) >= 0 &&
535             si.si_af == AF_INET6) {
536                 int val = 1;
537
538 #ifdef INET6
539                 setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &val, sizeof(val));
540 #endif
541         }
542         return fd;
543 }
544
545 int
546 __rpc_nconf2fd(const struct netconfig *nconf)
547 {
548         return __rpc_nconf2fd_flags(nconf, 0);
549 }
550
551 int
552 __rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
553 {
554         int i;
555         struct netconfig *nconf;
556
557         nconf = getnetconfigent("local");
558
559         for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
560                 if (na_cvt[i].af == sip->si_af &&
561                     na_cvt[i].protocol == sip->si_proto) {
562                         if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
563                                 if (netid)
564                                         *netid = "unix";
565                         } else {
566                                 if (netid)
567                                         *netid = na_cvt[i].netid;
568                         }
569                         if (nconf != NULL)
570                                 freenetconfigent(nconf);
571                         return 1;
572                 }
573         }
574         if (nconf != NULL)
575                 freenetconfigent(nconf);
576
577         return 0;
578 }
579
580 char *
581 taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
582 {
583         struct __rpc_sockinfo si;
584
585         if (!__rpc_nconf2sockinfo(nconf, &si))
586                 return NULL;
587         return __rpc_taddr2uaddr_af(si.si_af, nbuf);
588 }
589
590 struct netbuf *
591 uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
592 {
593         struct __rpc_sockinfo si;
594         
595         if (!__rpc_nconf2sockinfo(nconf, &si))
596                 return NULL;
597         return __rpc_uaddr2taddr_af(si.si_af, uaddr);
598 }
599
600 char *
601 __rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
602 {
603         char *ret;
604         struct sockaddr_in *sin;
605         struct sockaddr_un *sun;
606         char namebuf[INET_ADDRSTRLEN];
607 #ifdef INET6
608         struct sockaddr_in6 *sin6;
609         char namebuf6[INET6_ADDRSTRLEN];
610 #endif
611         u_int16_t port;
612
613         if (nbuf->len <= 0)
614                 return NULL;
615
616         switch (af) {
617         case AF_INET:
618                 sin = nbuf->buf;
619                 if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
620                     == NULL)
621                         return NULL;
622                 port = ntohs(sin->sin_port);
623                 if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
624                     port & 0xff) < 0)
625                         return NULL;
626                 break;
627 #ifdef INET6
628         case AF_INET6:
629                 sin6 = nbuf->buf;
630                 if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
631                     == NULL)
632                         return NULL;
633                 port = ntohs(sin6->sin6_port);
634                 if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
635                     port & 0xff) < 0)
636                         return NULL;
637                 break;
638 #endif
639         case AF_LOCAL:
640                 sun = nbuf->buf;
641                 /*      if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
642                     offsetof(struct sockaddr_un, sun_path)),
643                     sun->sun_path) < 0)*/
644                 if (asprintf(&ret, "%.*s", (int)(sizeof(*sun) -
645                                                  offsetof(struct sockaddr_un, sun_path)),
646                              sun->sun_path) < 0)
647
648                         return (NULL);
649                 break;
650         default:
651                 return NULL;
652         }
653
654         return ret;
655 }
656
657 struct netbuf *
658 __rpc_uaddr2taddr_af(int af, const char *uaddr)
659 {
660         struct netbuf *ret = NULL;
661         char *addrstr, *p;
662         unsigned port, portlo, porthi;
663         struct sockaddr_in *sin;
664 #ifdef INET6
665         struct sockaddr_in6 *sin6;
666 #endif
667         struct sockaddr_un *sun;
668
669         port = 0;
670         sin = NULL;
671         addrstr = strdup(uaddr);
672         if (addrstr == NULL)
673                 return NULL;
674
675         /*
676          * AF_LOCAL addresses are expected to be absolute
677          * pathnames, anything else will be AF_INET or AF_INET6.
678          */
679         if (*addrstr != '/') {
680                 p = strrchr(addrstr, '.');
681                 if (p == NULL)
682                         goto out;
683                 portlo = (unsigned)atoi(p + 1);
684                 *p = '\0';
685
686                 p = strrchr(addrstr, '.');
687                 if (p == NULL)
688                         goto out;
689                 porthi = (unsigned)atoi(p + 1);
690                 *p = '\0';
691                 port = (porthi << 8) | portlo;
692         }
693
694         ret = (struct netbuf *)malloc(sizeof *ret);
695         if (ret == NULL)
696                 goto out;
697         
698         switch (af) {
699         case AF_INET:
700                 sin = (struct sockaddr_in *)malloc(sizeof *sin);
701                 if (sin == NULL)
702                         goto out;
703                 memset(sin, 0, sizeof *sin);
704                 sin->sin_family = AF_INET;
705                 sin->sin_port = htons(port);
706                 if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
707                         free(sin);
708                         free(ret);
709                         ret = NULL;
710                         goto out;
711                 }
712                 ret->maxlen = ret->len = sizeof *sin;
713                 ret->buf = sin;
714                 break;
715 #ifdef INET6
716         case AF_INET6:
717                 sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
718                 if (sin6 == NULL)
719                         goto out;
720                 memset(sin6, 0, sizeof *sin6);
721                 sin6->sin6_family = AF_INET6;
722                 sin6->sin6_port = htons(port);
723                 if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
724                         free(sin6);
725                         free(ret);
726                         ret = NULL;
727                         goto out;
728                 }
729                 ret->maxlen = ret->len = sizeof *sin6;
730                 ret->buf = sin6;
731                 break;
732 #endif
733         case AF_LOCAL:
734                 sun = (struct sockaddr_un *)malloc(sizeof *sun);
735                 if (sun == NULL)
736                         goto out;
737                 memset(sun, 0, sizeof *sun);
738                 sun->sun_family = AF_LOCAL;
739                 strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
740                 ret->len = SUN_LEN(sun);
741                 ret->maxlen = sizeof(struct sockaddr_un);
742                 ret->buf = sun;
743                 break;
744         default:
745                 break;
746         }
747 out:
748         free(addrstr);
749         return ret;
750 }
751
752 int
753 __rpc_seman2socktype(int semantics)
754 {
755         switch (semantics) {
756         case NC_TPI_CLTS:
757                 return SOCK_DGRAM;
758         case NC_TPI_COTS_ORD:
759                 return SOCK_STREAM;
760         case NC_TPI_RAW:
761                 return SOCK_RAW;
762         default:
763                 break;
764         }
765
766         return -1;
767 }
768
769 int
770 __rpc_socktype2seman(int socktype)
771 {
772         switch (socktype) {
773         case SOCK_DGRAM:
774                 return NC_TPI_CLTS;
775         case SOCK_STREAM:
776                 return NC_TPI_COTS_ORD;
777         case SOCK_RAW:
778                 return NC_TPI_RAW;
779         default:
780                 break;
781         }
782
783         return -1;
784 }
785
786 /*
787  * XXXX - IPv6 scope IDs can't be handled in universal addresses.
788  * Here, we compare the original server address to that of the RPC
789  * service we just received back from a call to rpcbind on the remote
790  * machine. If they are both "link local" or "site local", copy
791  * the scope id of the server address over to the service address.
792  */
793 int
794 __rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
795 {
796 #ifdef INET6
797         struct sockaddr *sa_new, *sa_svc;
798         struct sockaddr_in6 *sin6_new, *sin6_svc;
799
800         sa_svc = (struct sockaddr *)svc->buf;
801         sa_new = (struct sockaddr *)new->buf;
802
803         if (sa_new->sa_family == sa_svc->sa_family &&
804             sa_new->sa_family == AF_INET6) {
805                 sin6_new = (struct sockaddr_in6 *)new->buf;
806                 sin6_svc = (struct sockaddr_in6 *)svc->buf;
807
808                 if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
809                      IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
810                     (IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
811                      IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
812                         sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
813                 }
814         }
815 #endif
816         return 1;
817 }
818
819 int
820 __rpc_sockisbound(int fd)
821 {
822         struct sockaddr_storage ss;
823         union {
824                 struct sockaddr_in  sin;
825                 struct sockaddr_in6 sin6;
826                 struct sockaddr_un  usin;
827         } u_addr;
828         socklen_t slen;
829
830         slen = sizeof (struct sockaddr_storage);
831         if (getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
832                 return 0;
833
834         switch (ss.ss_family) {
835                 case AF_INET:
836                         memcpy(&u_addr.sin, &ss, sizeof(u_addr.sin)); 
837                         return (u_addr.sin.sin_port != 0);
838 #ifdef INET6
839                 case AF_INET6:
840                         memcpy(&u_addr.sin6, &ss, sizeof(u_addr.sin6)); 
841                         return (u_addr.sin6.sin6_port != 0);
842 #endif
843                 case AF_LOCAL:
844                         /* XXX check this */
845                         memcpy(&u_addr.usin, &ss, sizeof(u_addr.usin)); 
846                         return (u_addr.usin.sun_path[0] != 0);
847                 default:
848                         break;
849         }
850
851         return 0;
852 }
853
854 /*
855  * Helper function to set up a netbuf
856  */
857 struct netbuf *
858 __rpc_set_netbuf(struct netbuf *nb, const void *ptr, size_t len)
859 {
860         if (nb->len != len) {
861                 if (nb->len)
862                         mem_free(nb->buf, nb->len);
863                 nb->buf = mem_alloc(len);
864                 if (nb->buf == NULL)
865                         return NULL;
866
867                 nb->maxlen = nb->len = len;
868         }
869         memcpy(nb->buf, ptr, len);
870         return nb;
871 }