2 * The contents of this file are subject to the Sun Standards
3 * License Version 1.0 the (the "License";) You may not use
4 * this file except in compliance with the License. You may
5 * obtain a copy of the License at lib/libc/rpc/LICENSE
7 * Software distributed under the License is distributed on
8 * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
9 * express or implied. See the License for the specific
10 * language governing rights and limitations under the License.
12 * The Original Code is Copyright 1998 by Sun Microsystems, Inc
14 * The Initial Developer of the Original Code is: Sun
17 * All Rights Reserved.
19 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
20 * unrestricted use provided that this legend is included on all tape
21 * media and as a part of the software program in whole or part. Users
22 * may copy or modify Sun RPC without charge, but are not authorized
23 * to license or distribute it to anyone else except as part of a product or
24 * program developed by the user.
26 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
27 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
30 * Sun RPC is provided with no support and without any obligation on the
31 * part of Sun Microsystems, Inc. to assist in its use, correction,
32 * modification or enhancement.
34 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
35 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
36 * OR ANY PART THEREOF.
38 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
39 * or profits or other special, indirect and consequential damages, even if
40 * Sun has been advised of the possibility of such damages.
42 * Sun Microsystems, Inc.
44 * Mountain View, California 94043
46 * @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI
47 * @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC
48 * @(#)clnt_generic.c 1.40 99/04/21 SMI
49 * $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $
50 * $FreeBSD: src/lib/libc/rpc/clnt_generic.c,v 1.15 2004/10/16 06:11:34 obrien Exp $
51 * $DragonFly: src/lib/libc/rpc/clnt_generic.c,v 1.4 2005/01/31 22:29:38 dillon Exp $
55 * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
56 * All rights reserved.
58 #include "namespace.h"
59 #include "reentrant.h"
60 #include <sys/types.h>
61 #include <sys/fcntl.h>
62 #include <sys/socket.h>
63 #include <netinet/in.h>
64 #include <netinet/tcp.h>
70 #include <rpc/nettype.h>
74 #include "un-namespace.h"
77 extern bool_t __rpc_is_local_host(const char *);
78 int __rpc_raise_fd(int);
86 * Generic client creation with version checking the value of
87 * vers_out is set to the highest server supported value
88 * vers_low <= vers_out <= vers_high AND an error results
89 * if this can not be done.
91 * It calls clnt_create_vers_timed() with a NULL value for the timeout
92 * pointer, which indicates that the default timeout should be used.
95 clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
96 rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
99 return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
100 vers_high, nettype, NULL));
104 * This the routine has the same definition as clnt_create_vers(),
105 * except it takes an additional timeout parameter - a pointer to
106 * a timeval structure. A NULL value for the pointer indicates
107 * that the default timeout value should be used.
110 clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
111 rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
112 const char *nettype, const struct timeval *tp)
116 enum clnt_stat rpc_stat;
117 struct rpc_err rpcerr;
119 clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
125 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
126 NULL, (xdrproc_t)xdr_void, NULL, to);
127 if (rpc_stat == RPC_SUCCESS) {
128 *vers_out = vers_high;
131 while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
132 unsigned int minvers, maxvers;
134 clnt_geterr(clnt, &rpcerr);
135 minvers = rpcerr.re_vers.low;
136 maxvers = rpcerr.re_vers.high;
137 if (maxvers < vers_high)
141 if (minvers > vers_low)
143 if (vers_low > vers_high) {
146 CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
147 rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
148 NULL, (xdrproc_t)xdr_void,
150 if (rpc_stat == RPC_SUCCESS) {
151 *vers_out = vers_high;
155 clnt_geterr(clnt, &rpcerr);
158 rpc_createerr.cf_stat = rpc_stat;
159 rpc_createerr.cf_error = rpcerr;
165 * Top level client creation routine.
166 * Generic client creation: takes (servers name, program-number, nettype) and
167 * returns client handle. Default options are set, which the user can
168 * change using the rpc equivalent of _ioctl()'s.
170 * It tries for all the netids in that particular class of netid until
172 * XXX The error message in the case of failure will be the one
173 * pertaining to the last create error.
175 * It calls clnt_create_timed() with the default timeout.
178 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
182 return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
186 * This the routine has the same definition as clnt_create(),
187 * except it takes an additional timeout parameter - a pointer to
188 * a timeval structure. A NULL value for the pointer indicates
189 * that the default timeout value should be used.
191 * This function calls clnt_tp_create_timed().
194 clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
195 const char *netclass, const struct timeval *tp)
197 struct netconfig *nconf;
200 enum clnt_stat save_cf_stat = RPC_SUCCESS;
201 struct rpc_err save_cf_error;
202 char nettype_array[NETIDLEN];
203 char *nettype = &nettype_array[0];
205 if (netclass == NULL)
208 size_t len = strlen(netclass);
209 if (len >= sizeof (nettype_array)) {
210 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
213 strcpy(nettype, netclass);
216 if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
217 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
220 rpc_createerr.cf_stat = RPC_SUCCESS;
221 while (clnt == NULL) {
222 if ((nconf = __rpc_getconf(handle)) == NULL) {
223 if (rpc_createerr.cf_stat == RPC_SUCCESS)
224 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
228 printf("trying netid %s\n", nconf->nc_netid);
230 clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
235 * Since we didn't get a name-to-address
236 * translation failure here, we remember
237 * this particular error. The object of
238 * this is to enable us to return to the
239 * caller a more-specific error than the
240 * unhelpful ``Name to address translation
241 * failed'' which might well occur if we
242 * merely returned the last error (because
243 * the local loopbacks are typically the
244 * last ones in /etc/netconfig and the most
245 * likely to be unable to translate a host
246 * name). We also check for a more
247 * meaningful error than ``unknown host
248 * name'' for the same reasons.
250 if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
251 rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
252 save_cf_stat = rpc_createerr.cf_stat;
253 save_cf_error = rpc_createerr.cf_error;
258 * Attempt to return an error more specific than ``Name to address
259 * translation failed'' or ``unknown host name''
261 if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
262 rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
263 (save_cf_stat != RPC_SUCCESS)) {
264 rpc_createerr.cf_stat = save_cf_stat;
265 rpc_createerr.cf_error = save_cf_error;
267 __rpc_endconf(handle);
272 * Generic client creation: takes (servers name, program-number, netconf) and
273 * returns client handle. Default options are set, which the user can
274 * change using the rpc equivalent of _ioctl()'s : clnt_control()
275 * It finds out the server address from rpcbind and calls clnt_tli_create().
277 * It calls clnt_tp_create_timed() with the default timeout.
280 clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
281 const struct netconfig *nconf)
284 return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
288 * This has the same definition as clnt_tp_create(), except it
289 * takes an additional parameter - a pointer to a timeval structure.
290 * A NULL value for the timeout pointer indicates that the default
291 * value for the timeout should be used.
294 clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
295 const struct netconfig *nconf, const struct timeval *tp)
297 struct netbuf *svcaddr; /* servers address */
298 CLIENT *cl = NULL; /* client handle */
301 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
306 * Get the address of the server
308 if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
309 (struct netconfig *)nconf, (char *)hostname,
310 &cl, (struct timeval *)tp)) == NULL) {
311 /* appropriate error number is set by rpcbind libraries */
315 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
318 /* Reuse the CLIENT handle and change the appropriate fields */
319 if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
320 if (cl->cl_netid == NULL)
321 cl->cl_netid = strdup(nconf->nc_netid);
322 if (cl->cl_tp == NULL)
323 cl->cl_tp = strdup(nconf->nc_device);
324 CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
325 CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
328 cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
338 * Generic client creation: returns client handle.
339 * Default options are set, which the user can
340 * change using the rpc equivalent of _ioctl()'s : clnt_control().
341 * If fd is RPC_ANYFD, it will be opened using nconf.
342 * It will be bound if not so.
343 * If sizes are 0; appropriate defaults will be chosen.
346 clnt_tli_create(int fd, const struct netconfig *nconf,
347 struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
348 uint sendsz, uint recvsz)
350 CLIENT *cl; /* client handle */
351 bool_t madefd = FALSE; /* whether fd opened here */
354 struct __rpc_sockinfo si;
355 extern int __rpc_minfd;
357 if (fd == RPC_ANYFD) {
359 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
363 fd = __rpc_nconf2fd(nconf);
367 if (fd < __rpc_minfd)
368 fd = __rpc_raise_fd(fd);
370 servtype = nconf->nc_semantics;
371 if (!__rpc_fd2sockinfo(fd, &si))
373 bindresvport(fd, NULL);
375 if (!__rpc_fd2sockinfo(fd, &si))
377 servtype = __rpc_socktype2seman(si.si_socktype);
378 if (servtype == -1) {
379 rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
384 if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
385 rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */
391 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
393 case NC_TPI_COTS_ORD:
394 if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
395 _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
398 cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
401 cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
408 goto err1; /* borrow errors from clnt_dg/vc creates */
410 cl->cl_netid = strdup(nconf->nc_netid);
411 cl->cl_tp = strdup(nconf->nc_device);
417 CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
418 /* CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
424 rpc_createerr.cf_stat = RPC_SYSTEMERROR;
425 rpc_createerr.cf_error.re_errno = errno;
432 * To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
433 * we try to not use them. The __rpc_raise_fd() routine will dup
434 * a descriptor to a higher value. If we fail to do it, we continue
435 * to use the old one (and hope for the best).
440 __rpc_raise_fd(int fd)
444 if (fd >= __rpc_minfd)
447 if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
450 if (_fsync(nfd) == -1) {
455 if (_close(fd) == -1) {
456 /* this is okay, we will syslog an error, then use the new fd */
457 syslog(LOG_ERR, "could not close() fd %d; mem & fd leak", fd);