xref: /dragonfly/lib/libc/rpc/clnt_generic.c (revision cf89a63b)
1 /*
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
6  *
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.
11  *
12  * The Original Code is Copyright 1998 by Sun Microsystems, Inc
13  *
14  * The Initial Developer of the Original Code is:  Sun
15  * Microsystems, Inc.
16  *
17  * All Rights Reserved.
18  *
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.
25  *
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.
29  *
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.
33  *
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.
37  *
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.
41  *
42  * Sun Microsystems, Inc.
43  * 2550 Garcia Avenue
44  * Mountain View, California  94043
45  *
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 $
52  */
53 
54 /*
55  * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
56  * All rights reserved.
57  */
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>
65 #include <stdio.h>
66 #include <errno.h>
67 #include <netdb.h>
68 #include <syslog.h>
69 #include <rpc/rpc.h>
70 #include <rpc/nettype.h>
71 #include <string.h>
72 #include <stdlib.h>
73 #include <unistd.h>
74 #include "un-namespace.h"
75 #include "rpc_com.h"
76 
77 extern bool_t	__rpc_is_local_host(const char *);
78 int		__rpc_raise_fd(int);
79 
80 #ifndef NETIDLEN
81 #define	NETIDLEN 32
82 #endif
83 
84 
85 /*
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.
90  *
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.
93  */
94 CLIENT *
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)
97 {
98 
99 	return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
100 				vers_high, nettype, NULL));
101 }
102 
103 /*
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.
108  */
109 CLIENT *
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)
113 {
114 	CLIENT *clnt;
115 	struct timeval to;
116 	enum clnt_stat rpc_stat;
117 	struct rpc_err rpcerr;
118 
119 	clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
120 	if (clnt == NULL) {
121 		return (NULL);
122 	}
123 	to.tv_sec = 10;
124 	to.tv_usec = 0;
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;
129 		return (clnt);
130 	}
131 	while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
132 		unsigned int minvers, maxvers;
133 
134 		clnt_geterr(clnt, &rpcerr);
135 		minvers = rpcerr.re_vers.low;
136 		maxvers = rpcerr.re_vers.high;
137 		if (maxvers < vers_high)
138 			vers_high = maxvers;
139 		else
140 			vers_high--;
141 		if (minvers > vers_low)
142 			vers_low = minvers;
143 		if (vers_low > vers_high) {
144 			goto error;
145 		}
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,
149 				NULL, to);
150 		if (rpc_stat == RPC_SUCCESS) {
151 			*vers_out = vers_high;
152 			return (clnt);
153 		}
154 	}
155 	clnt_geterr(clnt, &rpcerr);
156 
157 error:
158 	rpc_createerr.cf_stat = rpc_stat;
159 	rpc_createerr.cf_error = rpcerr;
160 	clnt_destroy(clnt);
161 	return (NULL);
162 }
163 
164 /*
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.
169  *
170  * It tries for all the netids in that particular class of netid until
171  * it succeeds.
172  * XXX The error message in the case of failure will be the one
173  * pertaining to the last create error.
174  *
175  * It calls clnt_create_timed() with the default timeout.
176  */
177 CLIENT *
178 clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
179     const char *nettype)
180 {
181 
182 	return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
183 }
184 
185 /*
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.
190  *
191  * This function calls clnt_tp_create_timed().
192  */
193 CLIENT *
194 clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
195     const char *netclass, const struct timeval *tp)
196 {
197 	struct netconfig *nconf;
198 	CLIENT *clnt = NULL;
199 	void *handle;
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];
204 
205 	if (netclass == NULL)
206 		nettype = NULL;
207 	else {
208 		size_t len = strlen(netclass);
209 		if (len >= sizeof (nettype_array)) {
210 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
211 			return (NULL);
212 		}
213 		strcpy(nettype, netclass);
214 	}
215 
216 	if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
217 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
218 		return (NULL);
219 	}
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;
225 			break;
226 		}
227 #ifdef CLNT_DEBUG
228 		printf("trying netid %s\n", nconf->nc_netid);
229 #endif
230 		clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
231 		if (clnt)
232 			break;
233 		else
234 			/*
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.
249 			 */
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;
254 			}
255 	}
256 
257 	/*
258 	 *	Attempt to return an error more specific than ``Name to address
259 	 *	translation failed'' or ``unknown host name''
260 	 */
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;
266 	}
267 	__rpc_endconf(handle);
268 	return (clnt);
269 }
270 
271 /*
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().
276  *
277  * It calls clnt_tp_create_timed() with the default timeout.
278  */
279 CLIENT *
280 clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
281     const struct netconfig *nconf)
282 {
283 
284 	return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
285 }
286 
287 /*
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.
292  */
293 CLIENT *
294 clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
295     const struct netconfig *nconf, const struct timeval *tp)
296 {
297 	struct netbuf *svcaddr;			/* servers address */
298 	CLIENT *cl = NULL;			/* client handle */
299 
300 	if (nconf == NULL) {
301 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
302 		return (NULL);
303 	}
304 
305 	/*
306 	 * Get the address of the server
307 	 */
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 */
312 		return (NULL);
313 	}
314 	if (cl == NULL) {
315 		cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
316 					prog, vers, 0, 0);
317 	} else {
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);
326 		} else {
327 			CLNT_DESTROY(cl);
328 			cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
329 					prog, vers, 0, 0);
330 		}
331 	}
332 	free(svcaddr->buf);
333 	free(svcaddr);
334 	return (cl);
335 }
336 
337 /*
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.
344  */
345 CLIENT *
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)
349 {
350 	CLIENT *cl;			/* client handle */
351 	bool_t madefd = FALSE;		/* whether fd opened here */
352 	long servtype;
353 	int one = 1;
354 	struct __rpc_sockinfo si;
355 	extern int __rpc_minfd;
356 
357 	if (fd == RPC_ANYFD) {
358 		if (nconf == NULL) {
359 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
360 			return (NULL);
361 		}
362 
363 		fd = __rpc_nconf2fd(nconf);
364 
365 		if (fd == -1)
366 			goto err;
367 		if (fd < __rpc_minfd)
368 			fd = __rpc_raise_fd(fd);
369 		madefd = TRUE;
370 		servtype = nconf->nc_semantics;
371 		if (!__rpc_fd2sockinfo(fd, &si))
372 			goto err;
373 		bindresvport(fd, NULL);
374 	} else {
375 		if (!__rpc_fd2sockinfo(fd, &si))
376 			goto err;
377 		servtype = __rpc_socktype2seman(si.si_socktype);
378 		if (servtype == -1) {
379 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
380 			return (NULL);
381 		}
382 	}
383 
384 	if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
385 		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;	/* XXX */
386 		goto err1;
387 	}
388 
389 	switch (servtype) {
390 	case NC_TPI_COTS:
391 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
392 		break;
393 	case NC_TPI_COTS_ORD:
394 		if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
395 			_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
396 			    sizeof (one));
397 		}
398 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
399 		break;
400 	case NC_TPI_CLTS:
401 		cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
402 		break;
403 	default:
404 		goto err;
405 	}
406 
407 	if (cl == NULL)
408 		goto err1; /* borrow errors from clnt_dg/vc creates */
409 	if (nconf) {
410 		cl->cl_netid = strdup(nconf->nc_netid);
411 		cl->cl_tp = strdup(nconf->nc_device);
412 	} else {
413 		cl->cl_netid = "";
414 		cl->cl_tp = "";
415 	}
416 	if (madefd) {
417 		CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
418 /*		CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
419 	};
420 
421 	return (cl);
422 
423 err:
424 	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
425 	rpc_createerr.cf_error.re_errno = errno;
426 err1:	if (madefd)
427 		_close(fd);
428 	return (NULL);
429 }
430 
431 /*
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).
436  */
437 int __rpc_minfd = 3;
438 
439 int
440 __rpc_raise_fd(int fd)
441 {
442 	int nfd;
443 
444 	if (fd >= __rpc_minfd)
445 		return (fd);
446 
447 	if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
448 		return (fd);
449 
450 	if (_fsync(nfd) == -1) {
451 		_close(nfd);
452 		return (fd);
453 	}
454 
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);
458 	}
459 
460 	return (nfd);
461 }
462