source: rtems-libbsd/freebsd/lib/libc/rpc/clnt_generic.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 60b1d40, checked in by Sebastian Huber <sebastian.huber@…>, on 06/09/16 at 08:23:57

RPC(3): Import from FreeBSD

  • Property mode set to 100644
File size: 12.8 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*      $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $       */
4
5/*-
6 * Copyright (c) 2010, Oracle America, Inc.
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are met:
11 * - Redistributions of source code must retain the above copyright notice,
12 *   this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright notice,
14 *   this list of conditions and the following disclaimer in the documentation
15 *   and/or other materials 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.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
31 */
32
33/* #ident       "@(#)clnt_generic.c     1.40    99/04/21 SMI" */
34
35#if defined(LIBC_SCCS) && !defined(lint)
36static char *sccsid2 = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";
37static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC";
38#endif
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41
42/*
43 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
44 * All rights reserved.
45 */
46#include "namespace.h"
47#include "reentrant.h"
48#include <sys/types.h>
49#include <sys/fcntl.h>
50#include <sys/socket.h>
51#include <netinet/in.h>
52#include <netinet/tcp.h>
53#include <stdio.h>
54#include <errno.h>
55#include <netdb.h>
56#include <syslog.h>
57#include <rpc/rpc.h>
58#include <rpc/nettype.h>
59#include <string.h>
60#include <stdlib.h>
61#include <unistd.h>
62#include "un-namespace.h"
63#include "rpc_com.h"
64
65extern bool_t __rpc_is_local_host(const char *);
66int __rpc_raise_fd(int);
67
68#ifndef NETIDLEN
69#define NETIDLEN 32
70#endif
71
72
73/*
74 * Generic client creation with version checking the value of
75 * vers_out is set to the highest server supported value
76 * vers_low <= vers_out <= vers_high  AND an error results
77 * if this can not be done.
78 *
79 * It calls clnt_create_vers_timed() with a NULL value for the timeout
80 * pointer, which indicates that the default timeout should be used.
81 */
82CLIENT *
83clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
84        rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
85{
86
87        return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
88                                vers_high, nettype, NULL));
89}
90
91/*
92 * This the routine has the same definition as clnt_create_vers(),
93 * except it takes an additional timeout parameter - a pointer to
94 * a timeval structure.  A NULL value for the pointer indicates
95 * that the default timeout value should be used.
96 */
97CLIENT *
98clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
99    rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
100    const char *nettype, const struct timeval *tp)
101{
102        CLIENT *clnt;
103        struct timeval to;
104        enum clnt_stat rpc_stat;
105        struct rpc_err rpcerr;
106
107        clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
108        if (clnt == NULL) {
109                return (NULL);
110        }
111        to.tv_sec = 10;
112        to.tv_usec = 0;
113        rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
114                        (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to);
115        if (rpc_stat == RPC_SUCCESS) {
116                *vers_out = vers_high;
117                return (clnt);
118        }
119        while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
120                unsigned int minvers, maxvers;
121
122                clnt_geterr(clnt, &rpcerr);
123                minvers = rpcerr.re_vers.low;
124                maxvers = rpcerr.re_vers.high;
125                if (maxvers < vers_high)
126                        vers_high = maxvers;
127                else
128                        vers_high--;
129                if (minvers > vers_low)
130                        vers_low = minvers;
131                if (vers_low > vers_high) {
132                        goto error;
133                }
134                CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
135                rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
136                                (char *)NULL, (xdrproc_t)xdr_void,
137                                (char *)NULL, to);
138                if (rpc_stat == RPC_SUCCESS) {
139                        *vers_out = vers_high;
140                        return (clnt);
141                }
142        }
143        clnt_geterr(clnt, &rpcerr);
144
145error:
146        rpc_createerr.cf_stat = rpc_stat;
147        rpc_createerr.cf_error = rpcerr;
148        clnt_destroy(clnt);
149        return (NULL);
150}
151
152/*
153 * Top level client creation routine.
154 * Generic client creation: takes (servers name, program-number, nettype) and
155 * returns client handle. Default options are set, which the user can
156 * change using the rpc equivalent of _ioctl()'s.
157 *
158 * It tries for all the netids in that particular class of netid until
159 * it succeeds.
160 * XXX The error message in the case of failure will be the one
161 * pertaining to the last create error.
162 *
163 * It calls clnt_create_timed() with the default timeout.
164 */
165CLIENT *
166clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
167    const char *nettype)
168{
169
170        return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
171}
172
173/*
174 * This the routine has the same definition as clnt_create(),
175 * except it takes an additional timeout parameter - a pointer to
176 * a timeval structure.  A NULL value for the pointer indicates
177 * that the default timeout value should be used.
178 *
179 * This function calls clnt_tp_create_timed().
180 */
181CLIENT *
182clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
183    const char *netclass, const struct timeval *tp)
184{
185        struct netconfig *nconf;
186        CLIENT *clnt = NULL;
187        void *handle;
188        enum clnt_stat  save_cf_stat = RPC_SUCCESS;
189        struct rpc_err  save_cf_error;
190        char nettype_array[NETIDLEN];
191        char *nettype = &nettype_array[0];
192
193        if (netclass == NULL)
194                nettype = NULL;
195        else {
196                size_t len = strlen(netclass);
197                if (len >= sizeof (nettype_array)) {
198                        rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
199                        return (NULL);
200                }
201                strcpy(nettype, netclass);
202        }
203
204        if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
205                rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
206                return (NULL);
207        }
208        rpc_createerr.cf_stat = RPC_SUCCESS;
209        while (clnt == NULL) {
210                if ((nconf = __rpc_getconf(handle)) == NULL) {
211                        if (rpc_createerr.cf_stat == RPC_SUCCESS)
212                                rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
213                        break;
214                }
215#ifdef CLNT_DEBUG
216                printf("trying netid %s\n", nconf->nc_netid);
217#endif
218                clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
219                if (clnt)
220                        break;
221                else
222                        /*
223                         *      Since we didn't get a name-to-address
224                         *      translation failure here, we remember
225                         *      this particular error.  The object of
226                         *      this is to enable us to return to the
227                         *      caller a more-specific error than the
228                         *      unhelpful ``Name to address translation
229                         *      failed'' which might well occur if we
230                         *      merely returned the last error (because
231                         *      the local loopbacks are typically the
232                         *      last ones in /etc/netconfig and the most
233                         *      likely to be unable to translate a host
234                         *      name).  We also check for a more
235                         *      meaningful error than ``unknown host
236                         *      name'' for the same reasons.
237                         */
238                        if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
239                            rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
240                                save_cf_stat = rpc_createerr.cf_stat;
241                                save_cf_error = rpc_createerr.cf_error;
242                        }
243        }
244
245        /*
246         *      Attempt to return an error more specific than ``Name to address
247         *      translation failed'' or ``unknown host name''
248         */
249        if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
250                                rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
251                                        (save_cf_stat != RPC_SUCCESS)) {
252                rpc_createerr.cf_stat = save_cf_stat;
253                rpc_createerr.cf_error = save_cf_error;
254        }
255        __rpc_endconf(handle);
256        return (clnt);
257}
258
259/*
260 * Generic client creation: takes (servers name, program-number, netconf) and
261 * returns client handle. Default options are set, which the user can
262 * change using the rpc equivalent of _ioctl()'s : clnt_control()
263 * It finds out the server address from rpcbind and calls clnt_tli_create().
264 *
265 * It calls clnt_tp_create_timed() with the default timeout.
266 */
267CLIENT *
268clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
269    const struct netconfig *nconf)
270{
271
272        return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
273}
274
275/*
276 * This has the same definition as clnt_tp_create(), except it
277 * takes an additional parameter - a pointer to a timeval structure.
278 * A NULL value for the timeout pointer indicates that the default
279 * value for the timeout should be used.
280 */
281CLIENT *
282clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
283    const struct netconfig *nconf, const struct timeval *tp)
284{
285        struct netbuf *svcaddr;                 /* servers address */
286        CLIENT *cl = NULL;                      /* client handle */
287
288        if (nconf == NULL) {
289                rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
290                return (NULL);
291        }
292
293        /*
294         * Get the address of the server
295         */
296        if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
297                        (struct netconfig *)nconf, (char *)hostname,
298                        &cl, (struct timeval *)tp)) == NULL) {
299                /* appropriate error number is set by rpcbind libraries */
300                return (NULL);
301        }
302        if (cl == NULL) {
303                cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
304                                        prog, vers, 0, 0);
305        } else {
306                /* Reuse the CLIENT handle and change the appropriate fields */
307                if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
308                        if (cl->cl_netid == NULL)
309                                cl->cl_netid = strdup(nconf->nc_netid);
310                        if (cl->cl_tp == NULL)
311                                cl->cl_tp = strdup(nconf->nc_device);
312                        (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
313                        (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
314                } else {
315                        CLNT_DESTROY(cl);
316                        cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
317                                        prog, vers, 0, 0);
318                }
319        }
320        free(svcaddr->buf);
321        free(svcaddr);
322        return (cl);
323}
324
325/*
326 * Generic client creation:  returns client handle.
327 * Default options are set, which the user can
328 * change using the rpc equivalent of _ioctl()'s : clnt_control().
329 * If fd is RPC_ANYFD, it will be opened using nconf.
330 * It will be bound if not so.
331 * If sizes are 0; appropriate defaults will be chosen.
332 */
333CLIENT *
334clnt_tli_create(int fd, const struct netconfig *nconf,
335        struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
336        uint sendsz, uint recvsz)
337{
338        CLIENT *cl;                     /* client handle */
339        bool_t madefd = FALSE;          /* whether fd opened here */
340        long servtype;
341        int one = 1;
342        struct __rpc_sockinfo si;
343        extern int __rpc_minfd;
344
345        if (fd == RPC_ANYFD) {
346                if (nconf == NULL) {
347                        rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
348                        return (NULL);
349                }
350
351                fd = __rpc_nconf2fd(nconf);
352
353                if (fd == -1)
354                        goto err;
355                if (fd < __rpc_minfd)
356                        fd = __rpc_raise_fd(fd);
357                madefd = TRUE;
358                servtype = nconf->nc_semantics;
359                if (!__rpc_fd2sockinfo(fd, &si))
360                        goto err;
361                bindresvport(fd, NULL);
362        } else {
363                if (!__rpc_fd2sockinfo(fd, &si))
364                        goto err;
365                servtype = __rpc_socktype2seman(si.si_socktype);
366                if (servtype == -1) {
367                        rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
368                        return (NULL);
369                }
370        }
371
372        if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
373                rpc_createerr.cf_stat = RPC_UNKNOWNHOST;        /* XXX */
374                goto err1;
375        }
376
377        switch (servtype) {
378        case NC_TPI_COTS:
379                cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
380                break;
381        case NC_TPI_COTS_ORD:
382                if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
383                        _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
384                            sizeof (one));
385                }
386                cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
387                break;
388        case NC_TPI_CLTS:
389                cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
390                break;
391        default:
392                goto err;
393        }
394
395        if (cl == NULL)
396                goto err1; /* borrow errors from clnt_dg/vc creates */
397        if (nconf) {
398                cl->cl_netid = strdup(nconf->nc_netid);
399                cl->cl_tp = strdup(nconf->nc_device);
400        } else {
401                cl->cl_netid = "";
402                cl->cl_tp = "";
403        }
404        if (madefd) {
405                (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
406/*              (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
407        };
408
409        return (cl);
410
411err:
412        rpc_createerr.cf_stat = RPC_SYSTEMERROR;
413        rpc_createerr.cf_error.re_errno = errno;
414err1:   if (madefd)
415                (void)_close(fd);
416        return (NULL);
417}
418
419/*
420 *  To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
421 *  we try to not use them.  The __rpc_raise_fd() routine will dup
422 *  a descriptor to a higher value.  If we fail to do it, we continue
423 *  to use the old one (and hope for the best).
424 */
425int __rpc_minfd = 3;
426
427int
428__rpc_raise_fd(int fd)
429{
430        int nfd;
431
432        if (fd >= __rpc_minfd)
433                return (fd);
434
435        if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
436                return (fd);
437
438        if (_fsync(nfd) == -1) {
439                _close(nfd);
440                return (fd);
441        }
442
443        if (_close(fd) == -1) {
444                /* this is okay, we will syslog an error, then use the new fd */
445                (void) syslog(LOG_ERR,
446                        "could not close() fd %d; mem & fd leak", fd);
447        }
448
449        return (nfd);
450}
Note: See TracBrowser for help on using the repository browser.