]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/libc/rpc/clnt_generic.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / lib / libc / rpc / clnt_generic.c
1 /*      $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $       */
2
3 /*
4  * The contents of this file are subject to the Sun Standards
5  * License Version 1.0 the (the "License";) You may not use
6  * this file except in compliance with the License.  You may
7  * obtain a copy of the License at lib/libc/rpc/LICENSE
8  *
9  * Software distributed under the License is distributed on
10  * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
11  * express or implied.  See the License for the specific
12  * language governing rights and limitations under the License.
13  *
14  * The Original Code is Copyright 1998 by Sun Microsystems, Inc
15  *
16  * The Initial Developer of the Original Code is:  Sun
17  * Microsystems, Inc.
18  *
19  * All Rights Reserved.
20  *
21  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
22  * unrestricted use provided that this legend is included on all tape
23  * media and as a part of the software program in whole or part.  Users
24  * may copy or modify Sun RPC without charge, but are not authorized
25  * to license or distribute it to anyone else except as part of a product or
26  * program developed by the user.
27  *
28  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
29  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
30  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
31  *
32  * Sun RPC is provided with no support and without any obligation on the
33  * part of Sun Microsystems, Inc. to assist in its use, correction,
34  * modification or enhancement.
35  *
36  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
37  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
38  * OR ANY PART THEREOF.
39  *
40  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
41  * or profits or other special, indirect and consequential damages, even if
42  * Sun has been advised of the possibility of such damages.
43  *
44  * Sun Microsystems, Inc.
45  * 2550 Garcia Avenue
46  * Mountain View, California  94043
47  */
48
49 /* #ident       "@(#)clnt_generic.c     1.40    99/04/21 SMI" */
50
51 #if defined(LIBC_SCCS) && !defined(lint)
52 static char *sccsid2 = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";
53 static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC";
54 #endif
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57
58 /*
59  * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
60  * All rights reserved.
61  */
62 #include "namespace.h"
63 #include "reentrant.h"
64 #include <sys/types.h>
65 #include <sys/fcntl.h>
66 #include <sys/socket.h>
67 #include <netinet/in.h>
68 #include <netinet/tcp.h>
69 #include <stdio.h>
70 #include <errno.h>
71 #include <netdb.h>
72 #include <syslog.h>
73 #include <rpc/rpc.h>
74 #include <rpc/nettype.h>
75 #include <string.h>
76 #include <stdlib.h>
77 #include <unistd.h>
78 #include "un-namespace.h"
79 #include "rpc_com.h"
80
81 extern bool_t __rpc_is_local_host(const char *);
82 int __rpc_raise_fd(int);
83
84 #ifndef NETIDLEN
85 #define NETIDLEN 32
86 #endif
87
88
89 /*
90  * Generic client creation with version checking the value of
91  * vers_out is set to the highest server supported value
92  * vers_low <= vers_out <= vers_high  AND an error results
93  * if this can not be done.
94  *
95  * It calls clnt_create_vers_timed() with a NULL value for the timeout
96  * pointer, which indicates that the default timeout should be used.
97  */
98 CLIENT *
99 clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
100         rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
101 {
102
103         return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
104                                 vers_high, nettype, NULL));
105 }
106
107 /*
108  * This the routine has the same definition as clnt_create_vers(),
109  * except it takes an additional timeout parameter - a pointer to
110  * a timeval structure.  A NULL value for the pointer indicates
111  * that the default timeout value should be used.
112  */
113 CLIENT *
114 clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
115     rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
116     const char *nettype, const struct timeval *tp)
117 {
118         CLIENT *clnt;
119         struct timeval to;
120         enum clnt_stat rpc_stat;
121         struct rpc_err rpcerr;
122
123         clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
124         if (clnt == NULL) {
125                 return (NULL);
126         }
127         to.tv_sec = 10;
128         to.tv_usec = 0;
129         rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
130                         (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to);
131         if (rpc_stat == RPC_SUCCESS) {
132                 *vers_out = vers_high;
133                 return (clnt);
134         }
135         while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
136                 unsigned int minvers, maxvers;
137
138                 clnt_geterr(clnt, &rpcerr);
139                 minvers = rpcerr.re_vers.low;
140                 maxvers = rpcerr.re_vers.high;
141                 if (maxvers < vers_high)
142                         vers_high = maxvers;
143                 else
144                         vers_high--;
145                 if (minvers > vers_low)
146                         vers_low = minvers;
147                 if (vers_low > vers_high) {
148                         goto error;
149                 }
150                 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
151                 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
152                                 (char *)NULL, (xdrproc_t)xdr_void,
153                                 (char *)NULL, to);
154                 if (rpc_stat == RPC_SUCCESS) {
155                         *vers_out = vers_high;
156                         return (clnt);
157                 }
158         }
159         clnt_geterr(clnt, &rpcerr);
160
161 error:
162         rpc_createerr.cf_stat = rpc_stat;
163         rpc_createerr.cf_error = rpcerr;
164         clnt_destroy(clnt);
165         return (NULL);
166 }
167
168 /*
169  * Top level client creation routine.
170  * Generic client creation: takes (servers name, program-number, nettype) and
171  * returns client handle. Default options are set, which the user can
172  * change using the rpc equivalent of _ioctl()'s.
173  *
174  * It tries for all the netids in that particular class of netid until
175  * it succeeds.
176  * XXX The error message in the case of failure will be the one
177  * pertaining to the last create error.
178  *
179  * It calls clnt_create_timed() with the default timeout.
180  */
181 CLIENT *
182 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
183     const char *nettype)
184 {
185
186         return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
187 }
188
189 /*
190  * This the routine has the same definition as clnt_create(),
191  * except it takes an additional timeout parameter - a pointer to
192  * a timeval structure.  A NULL value for the pointer indicates
193  * that the default timeout value should be used.
194  *
195  * This function calls clnt_tp_create_timed().
196  */
197 CLIENT *
198 clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
199     const char *netclass, const struct timeval *tp)
200 {
201         struct netconfig *nconf;
202         CLIENT *clnt = NULL;
203         void *handle;
204         enum clnt_stat  save_cf_stat = RPC_SUCCESS;
205         struct rpc_err  save_cf_error;
206         char nettype_array[NETIDLEN];
207         char *nettype = &nettype_array[0];
208
209         if (netclass == NULL)
210                 nettype = NULL;
211         else {
212                 size_t len = strlen(netclass);
213                 if (len >= sizeof (nettype_array)) {
214                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
215                         return (NULL);
216                 }
217                 strcpy(nettype, netclass);
218         }
219
220         if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
221                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
222                 return (NULL);
223         }
224         rpc_createerr.cf_stat = RPC_SUCCESS;
225         while (clnt == NULL) {
226                 if ((nconf = __rpc_getconf(handle)) == NULL) {
227                         if (rpc_createerr.cf_stat == RPC_SUCCESS)
228                                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
229                         break;
230                 }
231 #ifdef CLNT_DEBUG
232                 printf("trying netid %s\n", nconf->nc_netid);
233 #endif
234                 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
235                 if (clnt)
236                         break;
237                 else
238                         /*
239                          *      Since we didn't get a name-to-address
240                          *      translation failure here, we remember
241                          *      this particular error.  The object of
242                          *      this is to enable us to return to the
243                          *      caller a more-specific error than the
244                          *      unhelpful ``Name to address translation
245                          *      failed'' which might well occur if we
246                          *      merely returned the last error (because
247                          *      the local loopbacks are typically the
248                          *      last ones in /etc/netconfig and the most
249                          *      likely to be unable to translate a host
250                          *      name).  We also check for a more
251                          *      meaningful error than ``unknown host
252                          *      name'' for the same reasons.
253                          */
254                         if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
255                             rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
256                                 save_cf_stat = rpc_createerr.cf_stat;
257                                 save_cf_error = rpc_createerr.cf_error;
258                         }
259         }
260
261         /*
262          *      Attempt to return an error more specific than ``Name to address
263          *      translation failed'' or ``unknown host name''
264          */
265         if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
266                                 rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
267                                         (save_cf_stat != RPC_SUCCESS)) {
268                 rpc_createerr.cf_stat = save_cf_stat;
269                 rpc_createerr.cf_error = save_cf_error;
270         }
271         __rpc_endconf(handle);
272         return (clnt);
273 }
274
275 /*
276  * Generic client creation: takes (servers name, program-number, netconf) and
277  * returns client handle. Default options are set, which the user can
278  * change using the rpc equivalent of _ioctl()'s : clnt_control()
279  * It finds out the server address from rpcbind and calls clnt_tli_create().
280  *
281  * It calls clnt_tp_create_timed() with the default timeout.
282  */
283 CLIENT *
284 clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
285     const struct netconfig *nconf)
286 {
287
288         return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
289 }
290
291 /*
292  * This has the same definition as clnt_tp_create(), except it
293  * takes an additional parameter - a pointer to a timeval structure.
294  * A NULL value for the timeout pointer indicates that the default
295  * value for the timeout should be used.
296  */
297 CLIENT *
298 clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
299     const struct netconfig *nconf, const struct timeval *tp)
300 {
301         struct netbuf *svcaddr;                 /* servers address */
302         CLIENT *cl = NULL;                      /* client handle */
303
304         if (nconf == NULL) {
305                 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
306                 return (NULL);
307         }
308
309         /*
310          * Get the address of the server
311          */
312         if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
313                         (struct netconfig *)nconf, (char *)hostname,
314                         &cl, (struct timeval *)tp)) == NULL) {
315                 /* appropriate error number is set by rpcbind libraries */
316                 return (NULL);
317         }
318         if (cl == NULL) {
319                 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
320                                         prog, vers, 0, 0);
321         } else {
322                 /* Reuse the CLIENT handle and change the appropriate fields */
323                 if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
324                         if (cl->cl_netid == NULL)
325                                 cl->cl_netid = strdup(nconf->nc_netid);
326                         if (cl->cl_tp == NULL)
327                                 cl->cl_tp = strdup(nconf->nc_device);
328                         (void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
329                         (void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
330                 } else {
331                         CLNT_DESTROY(cl);
332                         cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
333                                         prog, vers, 0, 0);
334                 }
335         }
336         free(svcaddr->buf);
337         free(svcaddr);
338         return (cl);
339 }
340
341 /*
342  * Generic client creation:  returns client handle.
343  * Default options are set, which the user can
344  * change using the rpc equivalent of _ioctl()'s : clnt_control().
345  * If fd is RPC_ANYFD, it will be opened using nconf.
346  * It will be bound if not so.
347  * If sizes are 0; appropriate defaults will be chosen.
348  */
349 CLIENT *
350 clnt_tli_create(int fd, const struct netconfig *nconf,
351         struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
352         uint sendsz, uint recvsz)
353 {
354         CLIENT *cl;                     /* client handle */
355         bool_t madefd = FALSE;          /* whether fd opened here */
356         long servtype;
357         int one = 1;
358         struct __rpc_sockinfo si;
359         extern int __rpc_minfd;
360
361         if (fd == RPC_ANYFD) {
362                 if (nconf == NULL) {
363                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
364                         return (NULL);
365                 }
366
367                 fd = __rpc_nconf2fd(nconf);
368
369                 if (fd == -1)
370                         goto err;
371                 if (fd < __rpc_minfd)
372                         fd = __rpc_raise_fd(fd);
373                 madefd = TRUE;
374                 servtype = nconf->nc_semantics;
375                 if (!__rpc_fd2sockinfo(fd, &si))
376                         goto err;
377                 bindresvport(fd, NULL);
378         } else {
379                 if (!__rpc_fd2sockinfo(fd, &si))
380                         goto err;
381                 servtype = __rpc_socktype2seman(si.si_socktype);
382                 if (servtype == -1) {
383                         rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
384                         return (NULL);
385                 }
386         }
387
388         if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
389                 rpc_createerr.cf_stat = RPC_UNKNOWNHOST;        /* XXX */
390                 goto err1;
391         }
392
393         switch (servtype) {
394         case NC_TPI_COTS:
395                 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
396                 break;
397         case NC_TPI_COTS_ORD:
398                 if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
399                         _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
400                             sizeof (one));
401                 }
402                 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
403                 break;
404         case NC_TPI_CLTS:
405                 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
406                 break;
407         default:
408                 goto err;
409         }
410
411         if (cl == NULL)
412                 goto err1; /* borrow errors from clnt_dg/vc creates */
413         if (nconf) {
414                 cl->cl_netid = strdup(nconf->nc_netid);
415                 cl->cl_tp = strdup(nconf->nc_device);
416         } else {
417                 cl->cl_netid = "";
418                 cl->cl_tp = "";
419         }
420         if (madefd) {
421                 (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
422 /*              (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
423         };
424
425         return (cl);
426
427 err:
428         rpc_createerr.cf_stat = RPC_SYSTEMERROR;
429         rpc_createerr.cf_error.re_errno = errno;
430 err1:   if (madefd)
431                 (void)_close(fd);
432         return (NULL);
433 }
434
435 /*
436  *  To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
437  *  we try to not use them.  The __rpc_raise_fd() routine will dup
438  *  a descriptor to a higher value.  If we fail to do it, we continue
439  *  to use the old one (and hope for the best).
440  */
441 int __rpc_minfd = 3;
442
443 int
444 __rpc_raise_fd(int fd)
445 {
446         int nfd;
447
448         if (fd >= __rpc_minfd)
449                 return (fd);
450
451         if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
452                 return (fd);
453
454         if (_fsync(nfd) == -1) {
455                 _close(nfd);
456                 return (fd);
457         }
458
459         if (_close(fd) == -1) {
460                 /* this is okay, we will syslog an error, then use the new fd */
461                 (void) syslog(LOG_ERR,
462                         "could not close() fd %d; mem & fd leak", fd);
463         }
464
465         return (nfd);
466 }