xref: /freebsd/lib/libc/rpc/clnt_generic.c (revision 4e37855e0185c77686e5adf2278ad39796b96361)
18360efbdSAlfred Perlstein /*	$NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $	*/
28360efbdSAlfred Perlstein 
399064799SGarrett Wollman /*
44e37855eSAlfred Perlstein  * The contents of this file are subject to the Sun Standards
54e37855eSAlfred Perlstein  * License Version 1.0 the (the "License";) You may not use
64e37855eSAlfred Perlstein  * this file except in compliance with the License.  You may
74e37855eSAlfred Perlstein  * obtain a copy of the License at lib/libc/rpc/LICENSE
84e37855eSAlfred Perlstein  *
94e37855eSAlfred Perlstein  * Software distributed under the License is distributed on
104e37855eSAlfred Perlstein  * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
114e37855eSAlfred Perlstein  * express or implied.  See the License for the specific
124e37855eSAlfred Perlstein  * language governing rights and limitations under the License.
134e37855eSAlfred Perlstein  *
144e37855eSAlfred Perlstein  * The Original Code is Copyright 1998 by Sun Microsystems, Inc
154e37855eSAlfred Perlstein  *
164e37855eSAlfred Perlstein  * The Initial Developer of the Original Code is:  Sun
174e37855eSAlfred Perlstein  * Microsystems, Inc.
184e37855eSAlfred Perlstein  *
194e37855eSAlfred Perlstein  * All Rights Reserved.
204e37855eSAlfred Perlstein  *
2199064799SGarrett Wollman  * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
2299064799SGarrett Wollman  * unrestricted use provided that this legend is included on all tape
2399064799SGarrett Wollman  * media and as a part of the software program in whole or part.  Users
2499064799SGarrett Wollman  * may copy or modify Sun RPC without charge, but are not authorized
2599064799SGarrett Wollman  * to license or distribute it to anyone else except as part of a product or
2699064799SGarrett Wollman  * program developed by the user.
2799064799SGarrett Wollman  *
2899064799SGarrett Wollman  * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
2999064799SGarrett Wollman  * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
3099064799SGarrett Wollman  * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
3199064799SGarrett Wollman  *
3299064799SGarrett Wollman  * Sun RPC is provided with no support and without any obligation on the
3399064799SGarrett Wollman  * part of Sun Microsystems, Inc. to assist in its use, correction,
3499064799SGarrett Wollman  * modification or enhancement.
3599064799SGarrett Wollman  *
3699064799SGarrett Wollman  * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
3799064799SGarrett Wollman  * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
3899064799SGarrett Wollman  * OR ANY PART THEREOF.
3999064799SGarrett Wollman  *
4099064799SGarrett Wollman  * In no event will Sun Microsystems, Inc. be liable for any lost revenue
4199064799SGarrett Wollman  * or profits or other special, indirect and consequential damages, even if
4299064799SGarrett Wollman  * Sun has been advised of the possibility of such damages.
4399064799SGarrett Wollman  *
4499064799SGarrett Wollman  * Sun Microsystems, Inc.
4599064799SGarrett Wollman  * 2550 Garcia Avenue
4699064799SGarrett Wollman  * Mountain View, California  94043
4799064799SGarrett Wollman  */
4899064799SGarrett Wollman 
494e37855eSAlfred Perlstein /* #ident	"@(#)clnt_generic.c	1.40	99/04/21 SMI" */
508360efbdSAlfred Perlstein 
5199064799SGarrett Wollman #if defined(LIBC_SCCS) && !defined(lint)
5299064799SGarrett Wollman /*static char *sccsid = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";*/
5399064799SGarrett Wollman /*static char *sccsid = "from: @(#)clnt_generic.c	2.2 88/08/01 4.0 RPCSRC";*/
5499064799SGarrett Wollman #endif
55d3d20c82SDavid E. O'Brien #include <sys/cdefs.h>
56d3d20c82SDavid E. O'Brien __FBSDID("$FreeBSD$");
5799064799SGarrett Wollman 
5899064799SGarrett Wollman /*
594e37855eSAlfred Perlstein  * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
604e37855eSAlfred Perlstein  * All rights reserved.
6199064799SGarrett Wollman  */
628360efbdSAlfred Perlstein #include "namespace.h"
639f5afc13SIan Dowse #include "reentrant.h"
648360efbdSAlfred Perlstein #include <sys/types.h>
654e37855eSAlfred Perlstein #include <sys/fcntl.h>
6699064799SGarrett Wollman #include <sys/socket.h>
678360efbdSAlfred Perlstein #include <netinet/in.h>
688360efbdSAlfred Perlstein #include <netinet/tcp.h>
698360efbdSAlfred Perlstein #include <stdio.h>
70d201fe46SDaniel Eischen #include <errno.h>
7199064799SGarrett Wollman #include <netdb.h>
724e37855eSAlfred Perlstein #include <syslog.h>
738360efbdSAlfred Perlstein #include <rpc/rpc.h>
748360efbdSAlfred Perlstein #include <rpc/nettype.h>
754c3af266SPoul-Henning Kamp #include <string.h>
768360efbdSAlfred Perlstein #include <stdlib.h>
778360efbdSAlfred Perlstein #include <unistd.h>
788360efbdSAlfred Perlstein #include "un-namespace.h"
798360efbdSAlfred Perlstein #include "rpc_com.h"
8099064799SGarrett Wollman 
814e37855eSAlfred Perlstein extern bool_t __rpc_is_local_host(const char *);
824e37855eSAlfred Perlstein int __rpc_raise_fd(int);
834e37855eSAlfred Perlstein 
844e37855eSAlfred Perlstein #ifndef NETIDLEN
854e37855eSAlfred Perlstein #define	NETIDLEN 32
864e37855eSAlfred Perlstein #endif
874e37855eSAlfred Perlstein 
884e37855eSAlfred Perlstein 
8999064799SGarrett Wollman /*
908360efbdSAlfred Perlstein  * Generic client creation with version checking the value of
918360efbdSAlfred Perlstein  * vers_out is set to the highest server supported value
928360efbdSAlfred Perlstein  * vers_low <= vers_out <= vers_high  AND an error results
938360efbdSAlfred Perlstein  * if this can not be done.
944e37855eSAlfred Perlstein  *
954e37855eSAlfred Perlstein  * It calls clnt_create_vers_timed() with a NULL value for the timeout
964e37855eSAlfred Perlstein  * pointer, which indicates that the default timeout should be used.
9799064799SGarrett Wollman  */
9899064799SGarrett Wollman CLIENT *
994e37855eSAlfred Perlstein clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
1004e37855eSAlfred Perlstein 	rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
1014e37855eSAlfred Perlstein {
1024e37855eSAlfred Perlstein 
1034e37855eSAlfred Perlstein 	return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
1044e37855eSAlfred Perlstein 				vers_high, nettype, NULL));
1054e37855eSAlfred Perlstein }
1064e37855eSAlfred Perlstein 
1074e37855eSAlfred Perlstein /*
1084e37855eSAlfred Perlstein  * This the routine has the same definition as clnt_create_vers(),
1094e37855eSAlfred Perlstein  * except it takes an additional timeout parameter - a pointer to
1104e37855eSAlfred Perlstein  * a timeval structure.  A NULL value for the pointer indicates
1114e37855eSAlfred Perlstein  * that the default timeout value should be used.
1124e37855eSAlfred Perlstein  */
1134e37855eSAlfred Perlstein CLIENT *
1144e37855eSAlfred Perlstein clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
1154e37855eSAlfred Perlstein     rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
1164e37855eSAlfred Perlstein     const char *nettype, const struct timeval *tp)
11799064799SGarrett Wollman {
1188360efbdSAlfred Perlstein 	CLIENT *clnt;
1198360efbdSAlfred Perlstein 	struct timeval to;
1208360efbdSAlfred Perlstein 	enum clnt_stat rpc_stat;
1218360efbdSAlfred Perlstein 	struct rpc_err rpcerr;
12299064799SGarrett Wollman 
1234e37855eSAlfred Perlstein 	clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
1248360efbdSAlfred Perlstein 	if (clnt == NULL) {
12599064799SGarrett Wollman 		return (NULL);
12699064799SGarrett Wollman 	}
1278360efbdSAlfred Perlstein 	to.tv_sec = 10;
1288360efbdSAlfred Perlstein 	to.tv_usec = 0;
1298360efbdSAlfred Perlstein 	rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
1308360efbdSAlfred Perlstein 			(char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to);
1318360efbdSAlfred Perlstein 	if (rpc_stat == RPC_SUCCESS) {
1328360efbdSAlfred Perlstein 		*vers_out = vers_high;
1338360efbdSAlfred Perlstein 		return (clnt);
1348360efbdSAlfred Perlstein 	}
1354e37855eSAlfred Perlstein 	while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
1364e37855eSAlfred Perlstein 		unsigned int minvers, maxvers;
1378360efbdSAlfred Perlstein 
1388360efbdSAlfred Perlstein 		clnt_geterr(clnt, &rpcerr);
1398360efbdSAlfred Perlstein 		minvers = rpcerr.re_vers.low;
1408360efbdSAlfred Perlstein 		maxvers = rpcerr.re_vers.high;
1418360efbdSAlfred Perlstein 		if (maxvers < vers_high)
1424e37855eSAlfred Perlstein 			vers_high = maxvers;
1434e37855eSAlfred Perlstein 		else
1444e37855eSAlfred Perlstein 			vers_high--;
1458360efbdSAlfred Perlstein 		if (minvers > vers_low)
1464e37855eSAlfred Perlstein 			vers_low = minvers;
1478360efbdSAlfred Perlstein 		if (vers_low > vers_high) {
1488360efbdSAlfred Perlstein 			goto error;
1498360efbdSAlfred Perlstein 		}
1504e37855eSAlfred Perlstein 		CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
1518360efbdSAlfred Perlstein 		rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
1528360efbdSAlfred Perlstein 				(char *)NULL, (xdrproc_t)xdr_void,
1538360efbdSAlfred Perlstein 				(char *)NULL, to);
1548360efbdSAlfred Perlstein 		if (rpc_stat == RPC_SUCCESS) {
1558360efbdSAlfred Perlstein 			*vers_out = vers_high;
1568360efbdSAlfred Perlstein 			return (clnt);
1578360efbdSAlfred Perlstein 		}
1588360efbdSAlfred Perlstein 	}
1598360efbdSAlfred Perlstein 	clnt_geterr(clnt, &rpcerr);
1608360efbdSAlfred Perlstein 
1618360efbdSAlfred Perlstein error:
1628360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = rpc_stat;
1638360efbdSAlfred Perlstein 	rpc_createerr.cf_error = rpcerr;
1648360efbdSAlfred Perlstein 	clnt_destroy(clnt);
1658360efbdSAlfred Perlstein 	return (NULL);
1668360efbdSAlfred Perlstein }
1678360efbdSAlfred Perlstein 
16899064799SGarrett Wollman /*
1698360efbdSAlfred Perlstein  * Top level client creation routine.
1708360efbdSAlfred Perlstein  * Generic client creation: takes (servers name, program-number, nettype) and
1718360efbdSAlfred Perlstein  * returns client handle. Default options are set, which the user can
1728360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s.
1738360efbdSAlfred Perlstein  *
1748360efbdSAlfred Perlstein  * It tries for all the netids in that particular class of netid until
1758360efbdSAlfred Perlstein  * it succeeds.
1768360efbdSAlfred Perlstein  * XXX The error message in the case of failure will be the one
1778360efbdSAlfred Perlstein  * pertaining to the last create error.
1788360efbdSAlfred Perlstein  *
1794e37855eSAlfred Perlstein  * It calls clnt_create_timed() with the default timeout.
18099064799SGarrett Wollman  */
1818360efbdSAlfred Perlstein CLIENT *
1824e37855eSAlfred Perlstein clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
1834e37855eSAlfred Perlstein     const char *nettype)
1844e37855eSAlfred Perlstein {
1854e37855eSAlfred Perlstein 
1864e37855eSAlfred Perlstein 	return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
1874e37855eSAlfred Perlstein }
1884e37855eSAlfred Perlstein 
1894e37855eSAlfred Perlstein /*
1904e37855eSAlfred Perlstein  * This the routine has the same definition as clnt_create(),
1914e37855eSAlfred Perlstein  * except it takes an additional timeout parameter - a pointer to
1924e37855eSAlfred Perlstein  * a timeval structure.  A NULL value for the pointer indicates
1934e37855eSAlfred Perlstein  * that the default timeout value should be used.
1944e37855eSAlfred Perlstein  *
1954e37855eSAlfred Perlstein  * This function calls clnt_tp_create_timed().
1964e37855eSAlfred Perlstein  */
1974e37855eSAlfred Perlstein CLIENT *
1984e37855eSAlfred Perlstein clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
1994e37855eSAlfred Perlstein     const char *netclass, const struct timeval *tp)
2008360efbdSAlfred Perlstein {
2018360efbdSAlfred Perlstein 	struct netconfig *nconf;
2028360efbdSAlfred Perlstein 	CLIENT *clnt = NULL;
2038360efbdSAlfred Perlstein 	void *handle;
2048360efbdSAlfred Perlstein 	enum clnt_stat	save_cf_stat = RPC_SUCCESS;
2058360efbdSAlfred Perlstein 	struct rpc_err	save_cf_error;
2064e37855eSAlfred Perlstein 	char nettype_array[NETIDLEN];
2074e37855eSAlfred Perlstein 	char *nettype = &nettype_array[0];
2088360efbdSAlfred Perlstein 
2094e37855eSAlfred Perlstein 	if (netclass == NULL)
2104e37855eSAlfred Perlstein 		nettype = NULL;
2114e37855eSAlfred Perlstein 	else {
2124e37855eSAlfred Perlstein 		size_t len = strlen(netclass);
2134e37855eSAlfred Perlstein 		if (len >= sizeof (nettype_array)) {
2144e37855eSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
2154e37855eSAlfred Perlstein 			return (NULL);
2164e37855eSAlfred Perlstein 		}
2174e37855eSAlfred Perlstein 		strcpy(nettype, netclass);
2184e37855eSAlfred Perlstein 	}
2198360efbdSAlfred Perlstein 
2204e37855eSAlfred Perlstein 	if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
22199064799SGarrett Wollman 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
22299064799SGarrett Wollman 		return (NULL);
22399064799SGarrett Wollman 	}
2248360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = RPC_SUCCESS;
2258360efbdSAlfred Perlstein 	while (clnt == NULL) {
2268360efbdSAlfred Perlstein 		if ((nconf = __rpc_getconf(handle)) == NULL) {
2278360efbdSAlfred Perlstein 			if (rpc_createerr.cf_stat == RPC_SUCCESS)
2288360efbdSAlfred Perlstein 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
22999064799SGarrett Wollman 			break;
2308360efbdSAlfred Perlstein 		}
2318360efbdSAlfred Perlstein #ifdef CLNT_DEBUG
2328360efbdSAlfred Perlstein 		printf("trying netid %s\n", nconf->nc_netid);
2338360efbdSAlfred Perlstein #endif
2344e37855eSAlfred Perlstein 		clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
2358360efbdSAlfred Perlstein 		if (clnt)
2368360efbdSAlfred Perlstein 			break;
2378360efbdSAlfred Perlstein 		else
2388360efbdSAlfred Perlstein 			/*
2398360efbdSAlfred Perlstein 			 *	Since we didn't get a name-to-address
2408360efbdSAlfred Perlstein 			 *	translation failure here, we remember
2418360efbdSAlfred Perlstein 			 *	this particular error.  The object of
2428360efbdSAlfred Perlstein 			 *	this is to enable us to return to the
2438360efbdSAlfred Perlstein 			 *	caller a more-specific error than the
2448360efbdSAlfred Perlstein 			 *	unhelpful ``Name to address translation
2458360efbdSAlfred Perlstein 			 *	failed'' which might well occur if we
2468360efbdSAlfred Perlstein 			 *	merely returned the last error (because
2478360efbdSAlfred Perlstein 			 *	the local loopbacks are typically the
2488360efbdSAlfred Perlstein 			 *	last ones in /etc/netconfig and the most
2498360efbdSAlfred Perlstein 			 *	likely to be unable to translate a host
2504e37855eSAlfred Perlstein 			 *	name).  We also check for a more
2514e37855eSAlfred Perlstein 			 *	meaningful error than ``unknown host
2524e37855eSAlfred Perlstein 			 *	name'' for the same reasons.
2538360efbdSAlfred Perlstein 			 */
2544e37855eSAlfred Perlstein 			if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
2554e37855eSAlfred Perlstein 			    rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
2568360efbdSAlfred Perlstein 				save_cf_stat = rpc_createerr.cf_stat;
2578360efbdSAlfred Perlstein 				save_cf_error = rpc_createerr.cf_error;
2588360efbdSAlfred Perlstein 			}
2598360efbdSAlfred Perlstein 	}
2608360efbdSAlfred Perlstein 
2618360efbdSAlfred Perlstein 	/*
2628360efbdSAlfred Perlstein 	 *	Attempt to return an error more specific than ``Name to address
2634e37855eSAlfred Perlstein 	 *	translation failed'' or ``unknown host name''
2648360efbdSAlfred Perlstein 	 */
2654e37855eSAlfred Perlstein 	if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
2664e37855eSAlfred Perlstein 				rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
2678360efbdSAlfred Perlstein 					(save_cf_stat != RPC_SUCCESS)) {
2688360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = save_cf_stat;
2698360efbdSAlfred Perlstein 		rpc_createerr.cf_error = save_cf_error;
2708360efbdSAlfred Perlstein 	}
2718360efbdSAlfred Perlstein 	__rpc_endconf(handle);
2728360efbdSAlfred Perlstein 	return (clnt);
2738360efbdSAlfred Perlstein }
2748360efbdSAlfred Perlstein 
2758360efbdSAlfred Perlstein /*
2768360efbdSAlfred Perlstein  * Generic client creation: takes (servers name, program-number, netconf) and
2778360efbdSAlfred Perlstein  * returns client handle. Default options are set, which the user can
2788360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s : clnt_control()
2794e37855eSAlfred Perlstein  * It finds out the server address from rpcbind and calls clnt_tli_create().
2804e37855eSAlfred Perlstein  *
2814e37855eSAlfred Perlstein  * It calls clnt_tp_create_timed() with the default timeout.
2828360efbdSAlfred Perlstein  */
2838360efbdSAlfred Perlstein CLIENT *
2844e37855eSAlfred Perlstein clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
2854e37855eSAlfred Perlstein     const struct netconfig *nconf)
2864e37855eSAlfred Perlstein {
2874e37855eSAlfred Perlstein 
2884e37855eSAlfred Perlstein 	return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
2894e37855eSAlfred Perlstein }
2904e37855eSAlfred Perlstein 
2914e37855eSAlfred Perlstein /*
2924e37855eSAlfred Perlstein  * This has the same definition as clnt_tp_create(), except it
2934e37855eSAlfred Perlstein  * takes an additional parameter - a pointer to a timeval structure.
2944e37855eSAlfred Perlstein  * A NULL value for the timeout pointer indicates that the default
2954e37855eSAlfred Perlstein  * value for the timeout should be used.
2964e37855eSAlfred Perlstein  */
2974e37855eSAlfred Perlstein CLIENT *
2984e37855eSAlfred Perlstein clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
2994e37855eSAlfred Perlstein     const struct netconfig *nconf, const struct timeval *tp)
3008360efbdSAlfred Perlstein {
3018360efbdSAlfred Perlstein 	struct netbuf *svcaddr;			/* servers address */
3028360efbdSAlfred Perlstein 	CLIENT *cl = NULL;			/* client handle */
3038360efbdSAlfred Perlstein 
3048360efbdSAlfred Perlstein 	if (nconf == NULL) {
3058360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
30699064799SGarrett Wollman 		return (NULL);
30799064799SGarrett Wollman 	}
3088360efbdSAlfred Perlstein 
3098360efbdSAlfred Perlstein 	/*
3108360efbdSAlfred Perlstein 	 * Get the address of the server
3118360efbdSAlfred Perlstein 	 */
3124e37855eSAlfred Perlstein 	if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
3134e37855eSAlfred Perlstein 			(struct netconfig *)nconf, (char *)hostname,
3144e37855eSAlfred Perlstein 			&cl, (struct timeval *)tp)) == NULL) {
3158360efbdSAlfred Perlstein 		/* appropriate error number is set by rpcbind libraries */
3168360efbdSAlfred Perlstein 		return (NULL);
3178360efbdSAlfred Perlstein 	}
3188360efbdSAlfred Perlstein 	if (cl == NULL) {
3198360efbdSAlfred Perlstein 		cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
3208360efbdSAlfred Perlstein 					prog, vers, 0, 0);
3218360efbdSAlfred Perlstein 	} else {
3228360efbdSAlfred Perlstein 		/* Reuse the CLIENT handle and change the appropriate fields */
3238360efbdSAlfred Perlstein 		if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
3248360efbdSAlfred Perlstein 			if (cl->cl_netid == NULL)
3258360efbdSAlfred Perlstein 				cl->cl_netid = strdup(nconf->nc_netid);
3268360efbdSAlfred Perlstein 			if (cl->cl_tp == NULL)
3278360efbdSAlfred Perlstein 				cl->cl_tp = strdup(nconf->nc_device);
3288360efbdSAlfred Perlstein 			(void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
3298360efbdSAlfred Perlstein 			(void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
3308360efbdSAlfred Perlstein 		} else {
3318360efbdSAlfred Perlstein 			CLNT_DESTROY(cl);
3328360efbdSAlfred Perlstein 			cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
3338360efbdSAlfred Perlstein 					prog, vers, 0, 0);
3348360efbdSAlfred Perlstein 		}
3358360efbdSAlfred Perlstein 	}
3368360efbdSAlfred Perlstein 	free(svcaddr->buf);
3378360efbdSAlfred Perlstein 	free(svcaddr);
3388360efbdSAlfred Perlstein 	return (cl);
3398360efbdSAlfred Perlstein }
3408360efbdSAlfred Perlstein 
3418360efbdSAlfred Perlstein /*
3428360efbdSAlfred Perlstein  * Generic client creation:  returns client handle.
3438360efbdSAlfred Perlstein  * Default options are set, which the user can
3448360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s : clnt_control().
3458360efbdSAlfred Perlstein  * If fd is RPC_ANYFD, it will be opened using nconf.
3468360efbdSAlfred Perlstein  * It will be bound if not so.
3478360efbdSAlfred Perlstein  * If sizes are 0; appropriate defaults will be chosen.
3488360efbdSAlfred Perlstein  */
3498360efbdSAlfred Perlstein CLIENT *
3504e37855eSAlfred Perlstein clnt_tli_create(int fd, const struct netconfig *nconf,
3514e37855eSAlfred Perlstein 	struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
3524e37855eSAlfred Perlstein 	uint sendsz, uint recvsz)
3538360efbdSAlfred Perlstein {
3548360efbdSAlfred Perlstein 	CLIENT *cl;			/* client handle */
3558360efbdSAlfred Perlstein 	bool_t madefd = FALSE;		/* whether fd opened here */
3568360efbdSAlfred Perlstein 	long servtype;
3578360efbdSAlfred Perlstein 	int one = 1;
3588360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
3594e37855eSAlfred Perlstein 	extern int __rpc_minfd;
3608360efbdSAlfred Perlstein 
3618360efbdSAlfred Perlstein 	if (fd == RPC_ANYFD) {
3628360efbdSAlfred Perlstein 		if (nconf == NULL) {
3638360efbdSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
3648360efbdSAlfred Perlstein 			return (NULL);
3658360efbdSAlfred Perlstein 		}
3668360efbdSAlfred Perlstein 
3678360efbdSAlfred Perlstein 		fd = __rpc_nconf2fd(nconf);
3688360efbdSAlfred Perlstein 
3698360efbdSAlfred Perlstein 		if (fd == -1)
3708360efbdSAlfred Perlstein 			goto err;
3714e37855eSAlfred Perlstein 		if (fd < __rpc_minfd)
3724e37855eSAlfred Perlstein 			fd = __rpc_raise_fd(fd);
3738360efbdSAlfred Perlstein 		madefd = TRUE;
3748360efbdSAlfred Perlstein 		servtype = nconf->nc_semantics;
3758360efbdSAlfred Perlstein 		if (!__rpc_fd2sockinfo(fd, &si))
3768360efbdSAlfred Perlstein 			goto err;
3778360efbdSAlfred Perlstein 		bindresvport(fd, NULL);
3788360efbdSAlfred Perlstein 	} else {
3798360efbdSAlfred Perlstein 		if (!__rpc_fd2sockinfo(fd, &si))
3808360efbdSAlfred Perlstein 			goto err;
3818360efbdSAlfred Perlstein 		servtype = __rpc_socktype2seman(si.si_socktype);
3828360efbdSAlfred Perlstein 		if (servtype == -1) {
3838360efbdSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
3844e37855eSAlfred Perlstein 			return (NULL);
3858360efbdSAlfred Perlstein 		}
3868360efbdSAlfred Perlstein 	}
3878360efbdSAlfred Perlstein 
3888360efbdSAlfred Perlstein 	if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
3898360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;	/* XXX */
3908360efbdSAlfred Perlstein 		goto err1;
3918360efbdSAlfred Perlstein 	}
3928360efbdSAlfred Perlstein 
3938360efbdSAlfred Perlstein 	switch (servtype) {
3944e37855eSAlfred Perlstein 	case NC_TPI_COTS:
3958360efbdSAlfred Perlstein 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
3968360efbdSAlfred Perlstein 		break;
3974e37855eSAlfred Perlstein 	case NC_TPI_COTS_ORD:
3984e37855eSAlfred Perlstein 		if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
3998360efbdSAlfred Perlstein 			_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
4008360efbdSAlfred Perlstein 			    sizeof (one));
4014e37855eSAlfred Perlstein 		}
4024e37855eSAlfred Perlstein 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
4038360efbdSAlfred Perlstein 		break;
4048360efbdSAlfred Perlstein 	case NC_TPI_CLTS:
4058360efbdSAlfred Perlstein 		cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
40699064799SGarrett Wollman 		break;
40799064799SGarrett Wollman 	default:
4088360efbdSAlfred Perlstein 		goto err;
40999064799SGarrett Wollman 	}
4108360efbdSAlfred Perlstein 
4118360efbdSAlfred Perlstein 	if (cl == NULL)
4128360efbdSAlfred Perlstein 		goto err1; /* borrow errors from clnt_dg/vc creates */
4138360efbdSAlfred Perlstein 	if (nconf) {
4148360efbdSAlfred Perlstein 		cl->cl_netid = strdup(nconf->nc_netid);
4158360efbdSAlfred Perlstein 		cl->cl_tp = strdup(nconf->nc_device);
4168360efbdSAlfred Perlstein 	} else {
4178360efbdSAlfred Perlstein 		cl->cl_netid = "";
4188360efbdSAlfred Perlstein 		cl->cl_tp = "";
4198360efbdSAlfred Perlstein 	}
4208360efbdSAlfred Perlstein 	if (madefd) {
4218360efbdSAlfred Perlstein 		(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
4224e37855eSAlfred Perlstein /*		(void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
4238360efbdSAlfred Perlstein 	};
4248360efbdSAlfred Perlstein 
4258360efbdSAlfred Perlstein 	return (cl);
4268360efbdSAlfred Perlstein 
4278360efbdSAlfred Perlstein err:
4288360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
4298360efbdSAlfred Perlstein 	rpc_createerr.cf_error.re_errno = errno;
4308360efbdSAlfred Perlstein err1:	if (madefd)
4318360efbdSAlfred Perlstein 		(void)_close(fd);
4328360efbdSAlfred Perlstein 	return (NULL);
43399064799SGarrett Wollman }
4344e37855eSAlfred Perlstein 
4354e37855eSAlfred Perlstein /*
4364e37855eSAlfred Perlstein  *  To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
4374e37855eSAlfred Perlstein  *  we try to not use them.  The __rpc_raise_fd() routine will dup
4384e37855eSAlfred Perlstein  *  a descriptor to a higher value.  If we fail to do it, we continue
4394e37855eSAlfred Perlstein  *  to use the old one (and hope for the best).
4404e37855eSAlfred Perlstein  */
4414e37855eSAlfred Perlstein int __rpc_minfd = 3;
4424e37855eSAlfred Perlstein 
4434e37855eSAlfred Perlstein int
4444e37855eSAlfred Perlstein __rpc_raise_fd(int fd)
4454e37855eSAlfred Perlstein {
4464e37855eSAlfred Perlstein 	int nfd;
4474e37855eSAlfred Perlstein 
4484e37855eSAlfred Perlstein 	if (fd >= __rpc_minfd)
4494e37855eSAlfred Perlstein 		return (fd);
4504e37855eSAlfred Perlstein 
4514e37855eSAlfred Perlstein 	if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
4524e37855eSAlfred Perlstein 		return (fd);
4534e37855eSAlfred Perlstein 
4544e37855eSAlfred Perlstein 	if (_fsync(nfd) == -1) {
4554e37855eSAlfred Perlstein 		_close(nfd);
4564e37855eSAlfred Perlstein 		return (fd);
4574e37855eSAlfred Perlstein 	}
4584e37855eSAlfred Perlstein 
4594e37855eSAlfred Perlstein 	if (_close(fd) == -1) {
4604e37855eSAlfred Perlstein 		/* this is okay, we will syslog an error, then use the new fd */
4614e37855eSAlfred Perlstein 		(void) syslog(LOG_ERR,
4624e37855eSAlfred Perlstein 			"could not close() fd %d; mem & fd leak", fd);
4634e37855eSAlfred Perlstein 	}
4644e37855eSAlfred Perlstein 
4654e37855eSAlfred Perlstein 	return (nfd);
4664e37855eSAlfred Perlstein }
467