xref: /freebsd/lib/libc/rpc/clnt_generic.c (revision 341f552d8c069e849fb1d974e487dcaccc297cc8)
18360efbdSAlfred Perlstein /*	$NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $	*/
28360efbdSAlfred Perlstein 
344443e42SHiroki Sato /*-
444443e42SHiroki Sato  * Copyright (c) 2010, Oracle America, Inc.
544443e42SHiroki Sato  * All rights reserved.
64e37855eSAlfred Perlstein  *
744443e42SHiroki Sato  * Redistribution and use in source and binary forms, with or without
844443e42SHiroki Sato  * modification, are permitted provided that the following conditions are met:
944443e42SHiroki Sato  * - Redistributions of source code must retain the above copyright notice,
1044443e42SHiroki Sato  *   this list of conditions and the following disclaimer.
1144443e42SHiroki Sato  * - Redistributions in binary form must reproduce the above copyright notice,
1244443e42SHiroki Sato  *   this list of conditions and the following disclaimer in the documentation
1344443e42SHiroki Sato  *   and/or other materials provided with the distribution.
1444443e42SHiroki Sato  * - Neither the name of the "Oracle America, Inc." nor the names of its
1544443e42SHiroki Sato  *   contributors may be used to endorse or promote products derived
1644443e42SHiroki Sato  *   from this software without specific prior written permission.
174e37855eSAlfred Perlstein  *
1844443e42SHiroki Sato  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1944443e42SHiroki Sato  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2044443e42SHiroki Sato  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2144443e42SHiroki Sato  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2244443e42SHiroki Sato  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2344443e42SHiroki Sato  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2444443e42SHiroki Sato  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2544443e42SHiroki Sato  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2644443e42SHiroki Sato  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2744443e42SHiroki Sato  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2844443e42SHiroki Sato  * POSSIBILITY OF SUCH DAMAGE.
2999064799SGarrett Wollman  */
3099064799SGarrett Wollman 
314e37855eSAlfred Perlstein /* #ident	"@(#)clnt_generic.c	1.40	99/04/21 SMI" */
328360efbdSAlfred Perlstein 
3399064799SGarrett Wollman #if defined(LIBC_SCCS) && !defined(lint)
34a986ef57SDavid E. O'Brien static char *sccsid2 = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";
35a986ef57SDavid E. O'Brien static char *sccsid = "from: @(#)clnt_generic.c	2.2 88/08/01 4.0 RPCSRC";
3699064799SGarrett Wollman #endif
37d3d20c82SDavid E. O'Brien #include <sys/cdefs.h>
38d3d20c82SDavid E. O'Brien __FBSDID("$FreeBSD$");
3999064799SGarrett Wollman 
4099064799SGarrett Wollman /*
414e37855eSAlfred Perlstein  * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
424e37855eSAlfred Perlstein  * All rights reserved.
4399064799SGarrett Wollman  */
448360efbdSAlfred Perlstein #include "namespace.h"
459f5afc13SIan Dowse #include "reentrant.h"
468360efbdSAlfred Perlstein #include <sys/types.h>
474e37855eSAlfred Perlstein #include <sys/fcntl.h>
4899064799SGarrett Wollman #include <sys/socket.h>
498360efbdSAlfred Perlstein #include <netinet/in.h>
508360efbdSAlfred Perlstein #include <netinet/tcp.h>
518360efbdSAlfred Perlstein #include <stdio.h>
52d201fe46SDaniel Eischen #include <errno.h>
5399064799SGarrett Wollman #include <netdb.h>
544e37855eSAlfred Perlstein #include <syslog.h>
558360efbdSAlfred Perlstein #include <rpc/rpc.h>
568360efbdSAlfred Perlstein #include <rpc/nettype.h>
574c3af266SPoul-Henning Kamp #include <string.h>
588360efbdSAlfred Perlstein #include <stdlib.h>
598360efbdSAlfred Perlstein #include <unistd.h>
608360efbdSAlfred Perlstein #include "un-namespace.h"
618360efbdSAlfred Perlstein #include "rpc_com.h"
6299064799SGarrett Wollman 
634e37855eSAlfred Perlstein extern bool_t __rpc_is_local_host(const char *);
644e37855eSAlfred Perlstein int __rpc_raise_fd(int);
654e37855eSAlfred Perlstein 
664e37855eSAlfred Perlstein #ifndef NETIDLEN
674e37855eSAlfred Perlstein #define	NETIDLEN 32
684e37855eSAlfred Perlstein #endif
694e37855eSAlfred Perlstein 
704e37855eSAlfred Perlstein 
7199064799SGarrett Wollman /*
728360efbdSAlfred Perlstein  * Generic client creation with version checking the value of
738360efbdSAlfred Perlstein  * vers_out is set to the highest server supported value
748360efbdSAlfred Perlstein  * vers_low <= vers_out <= vers_high  AND an error results
758360efbdSAlfred Perlstein  * if this can not be done.
764e37855eSAlfred Perlstein  *
774e37855eSAlfred Perlstein  * It calls clnt_create_vers_timed() with a NULL value for the timeout
784e37855eSAlfred Perlstein  * pointer, which indicates that the default timeout should be used.
7999064799SGarrett Wollman  */
8099064799SGarrett Wollman CLIENT *
814e37855eSAlfred Perlstein clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
824e37855eSAlfred Perlstein 	rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
834e37855eSAlfred Perlstein {
844e37855eSAlfred Perlstein 
854e37855eSAlfred Perlstein 	return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
864e37855eSAlfred Perlstein 				vers_high, nettype, NULL));
874e37855eSAlfred Perlstein }
884e37855eSAlfred Perlstein 
894e37855eSAlfred Perlstein /*
904e37855eSAlfred Perlstein  * This the routine has the same definition as clnt_create_vers(),
914e37855eSAlfred Perlstein  * except it takes an additional timeout parameter - a pointer to
924e37855eSAlfred Perlstein  * a timeval structure.  A NULL value for the pointer indicates
934e37855eSAlfred Perlstein  * that the default timeout value should be used.
944e37855eSAlfred Perlstein  */
954e37855eSAlfred Perlstein CLIENT *
964e37855eSAlfred Perlstein clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
974e37855eSAlfred Perlstein     rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
984e37855eSAlfred Perlstein     const char *nettype, const struct timeval *tp)
9999064799SGarrett Wollman {
1008360efbdSAlfred Perlstein 	CLIENT *clnt;
1018360efbdSAlfred Perlstein 	struct timeval to;
1028360efbdSAlfred Perlstein 	enum clnt_stat rpc_stat;
1038360efbdSAlfred Perlstein 	struct rpc_err rpcerr;
10499064799SGarrett Wollman 
1054e37855eSAlfred Perlstein 	clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
1068360efbdSAlfred Perlstein 	if (clnt == NULL) {
10799064799SGarrett Wollman 		return (NULL);
10899064799SGarrett Wollman 	}
1098360efbdSAlfred Perlstein 	to.tv_sec = 10;
1108360efbdSAlfred Perlstein 	to.tv_usec = 0;
1118360efbdSAlfred Perlstein 	rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
1128360efbdSAlfred Perlstein 			(char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to);
1138360efbdSAlfred Perlstein 	if (rpc_stat == RPC_SUCCESS) {
1148360efbdSAlfred Perlstein 		*vers_out = vers_high;
1158360efbdSAlfred Perlstein 		return (clnt);
1168360efbdSAlfred Perlstein 	}
1174e37855eSAlfred Perlstein 	while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
1184e37855eSAlfred Perlstein 		unsigned int minvers, maxvers;
1198360efbdSAlfred Perlstein 
1208360efbdSAlfred Perlstein 		clnt_geterr(clnt, &rpcerr);
1218360efbdSAlfred Perlstein 		minvers = rpcerr.re_vers.low;
1228360efbdSAlfred Perlstein 		maxvers = rpcerr.re_vers.high;
1238360efbdSAlfred Perlstein 		if (maxvers < vers_high)
1244e37855eSAlfred Perlstein 			vers_high = maxvers;
1254e37855eSAlfred Perlstein 		else
1264e37855eSAlfred Perlstein 			vers_high--;
1278360efbdSAlfred Perlstein 		if (minvers > vers_low)
1284e37855eSAlfred Perlstein 			vers_low = minvers;
1298360efbdSAlfred Perlstein 		if (vers_low > vers_high) {
1308360efbdSAlfred Perlstein 			goto error;
1318360efbdSAlfred Perlstein 		}
1324e37855eSAlfred Perlstein 		CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
1338360efbdSAlfred Perlstein 		rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
1348360efbdSAlfred Perlstein 				(char *)NULL, (xdrproc_t)xdr_void,
1358360efbdSAlfred Perlstein 				(char *)NULL, to);
1368360efbdSAlfred Perlstein 		if (rpc_stat == RPC_SUCCESS) {
1378360efbdSAlfred Perlstein 			*vers_out = vers_high;
1388360efbdSAlfred Perlstein 			return (clnt);
1398360efbdSAlfred Perlstein 		}
1408360efbdSAlfred Perlstein 	}
1418360efbdSAlfred Perlstein 	clnt_geterr(clnt, &rpcerr);
1428360efbdSAlfred Perlstein 
1438360efbdSAlfred Perlstein error:
1448360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = rpc_stat;
1458360efbdSAlfred Perlstein 	rpc_createerr.cf_error = rpcerr;
1468360efbdSAlfred Perlstein 	clnt_destroy(clnt);
1478360efbdSAlfred Perlstein 	return (NULL);
1488360efbdSAlfred Perlstein }
1498360efbdSAlfred Perlstein 
15099064799SGarrett Wollman /*
1518360efbdSAlfred Perlstein  * Top level client creation routine.
1528360efbdSAlfred Perlstein  * Generic client creation: takes (servers name, program-number, nettype) and
1538360efbdSAlfred Perlstein  * returns client handle. Default options are set, which the user can
1548360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s.
1558360efbdSAlfred Perlstein  *
1568360efbdSAlfred Perlstein  * It tries for all the netids in that particular class of netid until
1578360efbdSAlfred Perlstein  * it succeeds.
1588360efbdSAlfred Perlstein  * XXX The error message in the case of failure will be the one
1598360efbdSAlfred Perlstein  * pertaining to the last create error.
1608360efbdSAlfred Perlstein  *
1614e37855eSAlfred Perlstein  * It calls clnt_create_timed() with the default timeout.
16299064799SGarrett Wollman  */
1638360efbdSAlfred Perlstein CLIENT *
1644e37855eSAlfred Perlstein clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
1654e37855eSAlfred Perlstein     const char *nettype)
1664e37855eSAlfred Perlstein {
1674e37855eSAlfred Perlstein 
1684e37855eSAlfred Perlstein 	return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
1694e37855eSAlfred Perlstein }
1704e37855eSAlfred Perlstein 
1714e37855eSAlfred Perlstein /*
1724e37855eSAlfred Perlstein  * This the routine has the same definition as clnt_create(),
1734e37855eSAlfred Perlstein  * except it takes an additional timeout parameter - a pointer to
1744e37855eSAlfred Perlstein  * a timeval structure.  A NULL value for the pointer indicates
1754e37855eSAlfred Perlstein  * that the default timeout value should be used.
1764e37855eSAlfred Perlstein  *
1774e37855eSAlfred Perlstein  * This function calls clnt_tp_create_timed().
1784e37855eSAlfred Perlstein  */
1794e37855eSAlfred Perlstein CLIENT *
1804e37855eSAlfred Perlstein clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
1814e37855eSAlfred Perlstein     const char *netclass, const struct timeval *tp)
1828360efbdSAlfred Perlstein {
1838360efbdSAlfred Perlstein 	struct netconfig *nconf;
1848360efbdSAlfred Perlstein 	CLIENT *clnt = NULL;
1858360efbdSAlfred Perlstein 	void *handle;
1868360efbdSAlfred Perlstein 	enum clnt_stat	save_cf_stat = RPC_SUCCESS;
1878360efbdSAlfred Perlstein 	struct rpc_err	save_cf_error;
1884e37855eSAlfred Perlstein 	char nettype_array[NETIDLEN];
1894e37855eSAlfred Perlstein 	char *nettype = &nettype_array[0];
1908360efbdSAlfred Perlstein 
1914e37855eSAlfred Perlstein 	if (netclass == NULL)
1924e37855eSAlfred Perlstein 		nettype = NULL;
1934e37855eSAlfred Perlstein 	else {
1944e37855eSAlfred Perlstein 		size_t len = strlen(netclass);
1954e37855eSAlfred Perlstein 		if (len >= sizeof (nettype_array)) {
1964e37855eSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1974e37855eSAlfred Perlstein 			return (NULL);
1984e37855eSAlfred Perlstein 		}
1994e37855eSAlfred Perlstein 		strcpy(nettype, netclass);
2004e37855eSAlfred Perlstein 	}
2018360efbdSAlfred Perlstein 
2024e37855eSAlfred Perlstein 	if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
20399064799SGarrett Wollman 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
20499064799SGarrett Wollman 		return (NULL);
20599064799SGarrett Wollman 	}
2068360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = RPC_SUCCESS;
2078360efbdSAlfred Perlstein 	while (clnt == NULL) {
2088360efbdSAlfred Perlstein 		if ((nconf = __rpc_getconf(handle)) == NULL) {
2098360efbdSAlfred Perlstein 			if (rpc_createerr.cf_stat == RPC_SUCCESS)
2108360efbdSAlfred Perlstein 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
21199064799SGarrett Wollman 			break;
2128360efbdSAlfred Perlstein 		}
2138360efbdSAlfred Perlstein #ifdef CLNT_DEBUG
2148360efbdSAlfred Perlstein 		printf("trying netid %s\n", nconf->nc_netid);
2158360efbdSAlfred Perlstein #endif
2164e37855eSAlfred Perlstein 		clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
2178360efbdSAlfred Perlstein 		if (clnt)
2188360efbdSAlfred Perlstein 			break;
2198360efbdSAlfred Perlstein 		else
2208360efbdSAlfred Perlstein 			/*
2218360efbdSAlfred Perlstein 			 *	Since we didn't get a name-to-address
2228360efbdSAlfred Perlstein 			 *	translation failure here, we remember
2238360efbdSAlfred Perlstein 			 *	this particular error.  The object of
2248360efbdSAlfred Perlstein 			 *	this is to enable us to return to the
2258360efbdSAlfred Perlstein 			 *	caller a more-specific error than the
2268360efbdSAlfred Perlstein 			 *	unhelpful ``Name to address translation
2278360efbdSAlfred Perlstein 			 *	failed'' which might well occur if we
2288360efbdSAlfred Perlstein 			 *	merely returned the last error (because
2298360efbdSAlfred Perlstein 			 *	the local loopbacks are typically the
2308360efbdSAlfred Perlstein 			 *	last ones in /etc/netconfig and the most
2318360efbdSAlfred Perlstein 			 *	likely to be unable to translate a host
2324e37855eSAlfred Perlstein 			 *	name).  We also check for a more
2334e37855eSAlfred Perlstein 			 *	meaningful error than ``unknown host
2344e37855eSAlfred Perlstein 			 *	name'' for the same reasons.
2358360efbdSAlfred Perlstein 			 */
2364e37855eSAlfred Perlstein 			if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
2374e37855eSAlfred Perlstein 			    rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
2388360efbdSAlfred Perlstein 				save_cf_stat = rpc_createerr.cf_stat;
2398360efbdSAlfred Perlstein 				save_cf_error = rpc_createerr.cf_error;
2408360efbdSAlfred Perlstein 			}
2418360efbdSAlfred Perlstein 	}
2428360efbdSAlfred Perlstein 
2438360efbdSAlfred Perlstein 	/*
2448360efbdSAlfred Perlstein 	 *	Attempt to return an error more specific than ``Name to address
2454e37855eSAlfred Perlstein 	 *	translation failed'' or ``unknown host name''
2468360efbdSAlfred Perlstein 	 */
2474e37855eSAlfred Perlstein 	if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
2484e37855eSAlfred Perlstein 				rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
2498360efbdSAlfred Perlstein 					(save_cf_stat != RPC_SUCCESS)) {
2508360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = save_cf_stat;
2518360efbdSAlfred Perlstein 		rpc_createerr.cf_error = save_cf_error;
2528360efbdSAlfred Perlstein 	}
2538360efbdSAlfred Perlstein 	__rpc_endconf(handle);
2548360efbdSAlfred Perlstein 	return (clnt);
2558360efbdSAlfred Perlstein }
2568360efbdSAlfred Perlstein 
2578360efbdSAlfred Perlstein /*
2588360efbdSAlfred Perlstein  * Generic client creation: takes (servers name, program-number, netconf) and
2598360efbdSAlfred Perlstein  * returns client handle. Default options are set, which the user can
2608360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s : clnt_control()
2614e37855eSAlfred Perlstein  * It finds out the server address from rpcbind and calls clnt_tli_create().
2624e37855eSAlfred Perlstein  *
2634e37855eSAlfred Perlstein  * It calls clnt_tp_create_timed() with the default timeout.
2648360efbdSAlfred Perlstein  */
2658360efbdSAlfred Perlstein CLIENT *
2664e37855eSAlfred Perlstein clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
2674e37855eSAlfred Perlstein     const struct netconfig *nconf)
2684e37855eSAlfred Perlstein {
2694e37855eSAlfred Perlstein 
2704e37855eSAlfred Perlstein 	return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
2714e37855eSAlfred Perlstein }
2724e37855eSAlfred Perlstein 
2734e37855eSAlfred Perlstein /*
2744e37855eSAlfred Perlstein  * This has the same definition as clnt_tp_create(), except it
2754e37855eSAlfred Perlstein  * takes an additional parameter - a pointer to a timeval structure.
2764e37855eSAlfred Perlstein  * A NULL value for the timeout pointer indicates that the default
2774e37855eSAlfred Perlstein  * value for the timeout should be used.
2784e37855eSAlfred Perlstein  */
2794e37855eSAlfred Perlstein CLIENT *
2804e37855eSAlfred Perlstein clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
2814e37855eSAlfred Perlstein     const struct netconfig *nconf, const struct timeval *tp)
2828360efbdSAlfred Perlstein {
2838360efbdSAlfred Perlstein 	struct netbuf *svcaddr;			/* servers address */
2848360efbdSAlfred Perlstein 	CLIENT *cl = NULL;			/* client handle */
2858360efbdSAlfred Perlstein 
2868360efbdSAlfred Perlstein 	if (nconf == NULL) {
2878360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
28899064799SGarrett Wollman 		return (NULL);
28999064799SGarrett Wollman 	}
2908360efbdSAlfred Perlstein 
2918360efbdSAlfred Perlstein 	/*
2928360efbdSAlfred Perlstein 	 * Get the address of the server
2938360efbdSAlfred Perlstein 	 */
2944e37855eSAlfred Perlstein 	if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
2954e37855eSAlfred Perlstein 			(struct netconfig *)nconf, (char *)hostname,
2964e37855eSAlfred Perlstein 			&cl, (struct timeval *)tp)) == NULL) {
2978360efbdSAlfred Perlstein 		/* appropriate error number is set by rpcbind libraries */
2988360efbdSAlfred Perlstein 		return (NULL);
2998360efbdSAlfred Perlstein 	}
3008360efbdSAlfred Perlstein 	if (cl == NULL) {
3018360efbdSAlfred Perlstein 		cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
3028360efbdSAlfred Perlstein 					prog, vers, 0, 0);
3038360efbdSAlfred Perlstein 	} else {
3048360efbdSAlfred Perlstein 		/* Reuse the CLIENT handle and change the appropriate fields */
3058360efbdSAlfred Perlstein 		if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
3068360efbdSAlfred Perlstein 			if (cl->cl_netid == NULL)
3078360efbdSAlfred Perlstein 				cl->cl_netid = strdup(nconf->nc_netid);
3088360efbdSAlfred Perlstein 			if (cl->cl_tp == NULL)
3098360efbdSAlfred Perlstein 				cl->cl_tp = strdup(nconf->nc_device);
3108360efbdSAlfred Perlstein 			(void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
3118360efbdSAlfred Perlstein 			(void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
3128360efbdSAlfred Perlstein 		} else {
3138360efbdSAlfred Perlstein 			CLNT_DESTROY(cl);
3148360efbdSAlfred Perlstein 			cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
3158360efbdSAlfred Perlstein 					prog, vers, 0, 0);
3168360efbdSAlfred Perlstein 		}
3178360efbdSAlfred Perlstein 	}
3188360efbdSAlfred Perlstein 	free(svcaddr->buf);
3198360efbdSAlfred Perlstein 	free(svcaddr);
3208360efbdSAlfred Perlstein 	return (cl);
3218360efbdSAlfred Perlstein }
3228360efbdSAlfred Perlstein 
3238360efbdSAlfred Perlstein /*
3248360efbdSAlfred Perlstein  * Generic client creation:  returns client handle.
3258360efbdSAlfred Perlstein  * Default options are set, which the user can
3268360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s : clnt_control().
3278360efbdSAlfred Perlstein  * If fd is RPC_ANYFD, it will be opened using nconf.
3288360efbdSAlfred Perlstein  * It will be bound if not so.
3298360efbdSAlfred Perlstein  * If sizes are 0; appropriate defaults will be chosen.
3308360efbdSAlfred Perlstein  */
3318360efbdSAlfred Perlstein CLIENT *
3324e37855eSAlfred Perlstein clnt_tli_create(int fd, const struct netconfig *nconf,
3334e37855eSAlfred Perlstein 	struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
3344e37855eSAlfred Perlstein 	uint sendsz, uint recvsz)
3358360efbdSAlfred Perlstein {
3368360efbdSAlfred Perlstein 	CLIENT *cl;			/* client handle */
3378360efbdSAlfred Perlstein 	bool_t madefd = FALSE;		/* whether fd opened here */
3388360efbdSAlfred Perlstein 	long servtype;
3398360efbdSAlfred Perlstein 	int one = 1;
3408360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
3414e37855eSAlfred Perlstein 	extern int __rpc_minfd;
3428360efbdSAlfred Perlstein 
3438360efbdSAlfred Perlstein 	if (fd == RPC_ANYFD) {
3448360efbdSAlfred Perlstein 		if (nconf == NULL) {
3458360efbdSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
3468360efbdSAlfred Perlstein 			return (NULL);
3478360efbdSAlfred Perlstein 		}
3488360efbdSAlfred Perlstein 
3498360efbdSAlfred Perlstein 		fd = __rpc_nconf2fd(nconf);
3508360efbdSAlfred Perlstein 
3518360efbdSAlfred Perlstein 		if (fd == -1)
3528360efbdSAlfred Perlstein 			goto err;
3534e37855eSAlfred Perlstein 		if (fd < __rpc_minfd)
3544e37855eSAlfred Perlstein 			fd = __rpc_raise_fd(fd);
3558360efbdSAlfred Perlstein 		madefd = TRUE;
3568360efbdSAlfred Perlstein 		servtype = nconf->nc_semantics;
3578360efbdSAlfred Perlstein 		if (!__rpc_fd2sockinfo(fd, &si))
3588360efbdSAlfred Perlstein 			goto err;
3598360efbdSAlfred Perlstein 		bindresvport(fd, NULL);
3608360efbdSAlfred Perlstein 	} else {
3618360efbdSAlfred Perlstein 		if (!__rpc_fd2sockinfo(fd, &si))
3628360efbdSAlfred Perlstein 			goto err;
3638360efbdSAlfred Perlstein 		servtype = __rpc_socktype2seman(si.si_socktype);
3648360efbdSAlfred Perlstein 		if (servtype == -1) {
3658360efbdSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
3664e37855eSAlfred Perlstein 			return (NULL);
3678360efbdSAlfred Perlstein 		}
3688360efbdSAlfred Perlstein 	}
3698360efbdSAlfred Perlstein 
3708360efbdSAlfred Perlstein 	if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
3718360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;	/* XXX */
3728360efbdSAlfred Perlstein 		goto err1;
3738360efbdSAlfred Perlstein 	}
3748360efbdSAlfred Perlstein 
3758360efbdSAlfred Perlstein 	switch (servtype) {
3764e37855eSAlfred Perlstein 	case NC_TPI_COTS:
3778360efbdSAlfred Perlstein 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
3788360efbdSAlfred Perlstein 		break;
3794e37855eSAlfred Perlstein 	case NC_TPI_COTS_ORD:
3804e37855eSAlfred Perlstein 		if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
3818360efbdSAlfred Perlstein 			_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
3828360efbdSAlfred Perlstein 			    sizeof (one));
3834e37855eSAlfred Perlstein 		}
3844e37855eSAlfred Perlstein 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
3858360efbdSAlfred Perlstein 		break;
3868360efbdSAlfred Perlstein 	case NC_TPI_CLTS:
3878360efbdSAlfred Perlstein 		cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
38899064799SGarrett Wollman 		break;
38999064799SGarrett Wollman 	default:
3908360efbdSAlfred Perlstein 		goto err;
39199064799SGarrett Wollman 	}
3928360efbdSAlfred Perlstein 
3938360efbdSAlfred Perlstein 	if (cl == NULL)
3948360efbdSAlfred Perlstein 		goto err1; /* borrow errors from clnt_dg/vc creates */
3958360efbdSAlfred Perlstein 	if (nconf) {
3968360efbdSAlfred Perlstein 		cl->cl_netid = strdup(nconf->nc_netid);
3978360efbdSAlfred Perlstein 		cl->cl_tp = strdup(nconf->nc_device);
3988360efbdSAlfred Perlstein 	} else {
3998360efbdSAlfred Perlstein 		cl->cl_netid = "";
4008360efbdSAlfred Perlstein 		cl->cl_tp = "";
4018360efbdSAlfred Perlstein 	}
4028360efbdSAlfred Perlstein 	if (madefd) {
4038360efbdSAlfred Perlstein 		(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
4044e37855eSAlfred Perlstein /*		(void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
405*341f552dSPedro F. Giffuni 	}
4068360efbdSAlfred Perlstein 
4078360efbdSAlfred Perlstein 	return (cl);
4088360efbdSAlfred Perlstein 
4098360efbdSAlfred Perlstein err:
4108360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
4118360efbdSAlfred Perlstein 	rpc_createerr.cf_error.re_errno = errno;
4128360efbdSAlfred Perlstein err1:	if (madefd)
4138360efbdSAlfred Perlstein 		(void)_close(fd);
4148360efbdSAlfred Perlstein 	return (NULL);
41599064799SGarrett Wollman }
4164e37855eSAlfred Perlstein 
4174e37855eSAlfred Perlstein /*
4184e37855eSAlfred Perlstein  *  To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
4194e37855eSAlfred Perlstein  *  we try to not use them.  The __rpc_raise_fd() routine will dup
4204e37855eSAlfred Perlstein  *  a descriptor to a higher value.  If we fail to do it, we continue
4214e37855eSAlfred Perlstein  *  to use the old one (and hope for the best).
4224e37855eSAlfred Perlstein  */
4234e37855eSAlfred Perlstein int __rpc_minfd = 3;
4244e37855eSAlfred Perlstein 
4254e37855eSAlfred Perlstein int
4264e37855eSAlfred Perlstein __rpc_raise_fd(int fd)
4274e37855eSAlfred Perlstein {
4284e37855eSAlfred Perlstein 	int nfd;
4294e37855eSAlfred Perlstein 
4304e37855eSAlfred Perlstein 	if (fd >= __rpc_minfd)
4314e37855eSAlfred Perlstein 		return (fd);
4324e37855eSAlfred Perlstein 
4334e37855eSAlfred Perlstein 	if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
4344e37855eSAlfred Perlstein 		return (fd);
4354e37855eSAlfred Perlstein 
4364e37855eSAlfred Perlstein 	if (_fsync(nfd) == -1) {
4374e37855eSAlfred Perlstein 		_close(nfd);
4384e37855eSAlfred Perlstein 		return (fd);
4394e37855eSAlfred Perlstein 	}
4404e37855eSAlfred Perlstein 
4414e37855eSAlfred Perlstein 	if (_close(fd) == -1) {
4424e37855eSAlfred Perlstein 		/* this is okay, we will syslog an error, then use the new fd */
4434e37855eSAlfred Perlstein 		(void) syslog(LOG_ERR,
4444e37855eSAlfred Perlstein 			"could not close() fd %d; mem & fd leak", fd);
4454e37855eSAlfred Perlstein 	}
4464e37855eSAlfred Perlstein 
4474e37855eSAlfred Perlstein 	return (nfd);
4484e37855eSAlfred Perlstein }
449