xref: /freebsd/lib/libc/rpc/clnt_generic.c (revision dc36d6f9)
18360efbdSAlfred Perlstein /*	$NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $	*/
28360efbdSAlfred Perlstein 
344443e42SHiroki Sato /*-
48a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
58a16b7a1SPedro F. Giffuni  *
644443e42SHiroki Sato  * Copyright (c) 2010, Oracle America, Inc.
744443e42SHiroki Sato  * All rights reserved.
84e37855eSAlfred Perlstein  *
944443e42SHiroki Sato  * Redistribution and use in source and binary forms, with or without
1044443e42SHiroki Sato  * modification, are permitted provided that the following conditions are met:
1144443e42SHiroki Sato  * - Redistributions of source code must retain the above copyright notice,
1244443e42SHiroki Sato  *   this list of conditions and the following disclaimer.
1344443e42SHiroki Sato  * - Redistributions in binary form must reproduce the above copyright notice,
1444443e42SHiroki Sato  *   this list of conditions and the following disclaimer in the documentation
1544443e42SHiroki Sato  *   and/or other materials provided with the distribution.
1644443e42SHiroki Sato  * - Neither the name of the "Oracle America, Inc." nor the names of its
1744443e42SHiroki Sato  *   contributors may be used to endorse or promote products derived
1844443e42SHiroki Sato  *   from this software without specific prior written permission.
194e37855eSAlfred Perlstein  *
2044443e42SHiroki Sato  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2144443e42SHiroki Sato  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2244443e42SHiroki Sato  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2344443e42SHiroki Sato  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
2444443e42SHiroki Sato  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2544443e42SHiroki Sato  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2644443e42SHiroki Sato  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2744443e42SHiroki Sato  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2844443e42SHiroki Sato  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2944443e42SHiroki Sato  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3044443e42SHiroki Sato  * POSSIBILITY OF SUCH DAMAGE.
3199064799SGarrett Wollman  */
3299064799SGarrett Wollman 
3399064799SGarrett Wollman /*
344e37855eSAlfred Perlstein  * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
354e37855eSAlfred Perlstein  * All rights reserved.
3699064799SGarrett Wollman  */
378360efbdSAlfred Perlstein #include "namespace.h"
389f5afc13SIan Dowse #include "reentrant.h"
398360efbdSAlfred Perlstein #include <sys/types.h>
404e37855eSAlfred Perlstein #include <sys/fcntl.h>
4199064799SGarrett Wollman #include <sys/socket.h>
428360efbdSAlfred Perlstein #include <netinet/in.h>
438360efbdSAlfred Perlstein #include <netinet/tcp.h>
448360efbdSAlfred Perlstein #include <stdio.h>
45d201fe46SDaniel Eischen #include <errno.h>
4699064799SGarrett Wollman #include <netdb.h>
474e37855eSAlfred Perlstein #include <syslog.h>
488360efbdSAlfred Perlstein #include <rpc/rpc.h>
498360efbdSAlfred Perlstein #include <rpc/nettype.h>
504c3af266SPoul-Henning Kamp #include <string.h>
518360efbdSAlfred Perlstein #include <stdlib.h>
528360efbdSAlfred Perlstein #include <unistd.h>
538360efbdSAlfred Perlstein #include "un-namespace.h"
548360efbdSAlfred Perlstein #include "rpc_com.h"
5599064799SGarrett Wollman 
564e37855eSAlfred Perlstein extern bool_t __rpc_is_local_host(const char *);
574e37855eSAlfred Perlstein int __rpc_raise_fd(int);
584e37855eSAlfred Perlstein 
594e37855eSAlfred Perlstein #ifndef NETIDLEN
604e37855eSAlfred Perlstein #define	NETIDLEN 32
614e37855eSAlfred Perlstein #endif
624e37855eSAlfred Perlstein 
634e37855eSAlfred Perlstein 
6499064799SGarrett Wollman /*
658360efbdSAlfred Perlstein  * Generic client creation with version checking the value of
668360efbdSAlfred Perlstein  * vers_out is set to the highest server supported value
678360efbdSAlfred Perlstein  * vers_low <= vers_out <= vers_high  AND an error results
688360efbdSAlfred Perlstein  * if this can not be done.
694e37855eSAlfred Perlstein  *
704e37855eSAlfred Perlstein  * It calls clnt_create_vers_timed() with a NULL value for the timeout
714e37855eSAlfred Perlstein  * pointer, which indicates that the default timeout should be used.
7299064799SGarrett Wollman  */
7399064799SGarrett Wollman CLIENT *
clnt_create_vers(const char * hostname,rpcprog_t prog,rpcvers_t * vers_out,rpcvers_t vers_low,rpcvers_t vers_high,const char * nettype)744e37855eSAlfred Perlstein clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
754e37855eSAlfred Perlstein 	rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
764e37855eSAlfred Perlstein {
774e37855eSAlfred Perlstein 
784e37855eSAlfred Perlstein 	return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
794e37855eSAlfred Perlstein 				vers_high, nettype, NULL));
804e37855eSAlfred Perlstein }
814e37855eSAlfred Perlstein 
824e37855eSAlfred Perlstein /*
834e37855eSAlfred Perlstein  * This the routine has the same definition as clnt_create_vers(),
844e37855eSAlfred Perlstein  * except it takes an additional timeout parameter - a pointer to
854e37855eSAlfred Perlstein  * a timeval structure.  A NULL value for the pointer indicates
864e37855eSAlfred Perlstein  * that the default timeout value should be used.
874e37855eSAlfred Perlstein  */
884e37855eSAlfred Perlstein CLIENT *
clnt_create_vers_timed(const char * hostname,rpcprog_t prog,rpcvers_t * vers_out,rpcvers_t vers_low,rpcvers_t vers_high,const char * nettype,const struct timeval * tp)894e37855eSAlfred Perlstein clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
904e37855eSAlfred Perlstein     rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
914e37855eSAlfred Perlstein     const char *nettype, const struct timeval *tp)
9299064799SGarrett Wollman {
938360efbdSAlfred Perlstein 	CLIENT *clnt;
948360efbdSAlfred Perlstein 	struct timeval to;
958360efbdSAlfred Perlstein 	enum clnt_stat rpc_stat;
968360efbdSAlfred Perlstein 	struct rpc_err rpcerr;
9799064799SGarrett Wollman 
984e37855eSAlfred Perlstein 	clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
998360efbdSAlfred Perlstein 	if (clnt == NULL) {
10099064799SGarrett Wollman 		return (NULL);
10199064799SGarrett Wollman 	}
1028360efbdSAlfred Perlstein 	to.tv_sec = 10;
1038360efbdSAlfred Perlstein 	to.tv_usec = 0;
1048360efbdSAlfred Perlstein 	rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
1058360efbdSAlfred Perlstein 			(char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to);
1068360efbdSAlfred Perlstein 	if (rpc_stat == RPC_SUCCESS) {
1078360efbdSAlfred Perlstein 		*vers_out = vers_high;
1088360efbdSAlfred Perlstein 		return (clnt);
1098360efbdSAlfred Perlstein 	}
1104e37855eSAlfred Perlstein 	while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
1114e37855eSAlfred Perlstein 		unsigned int minvers, maxvers;
1128360efbdSAlfred Perlstein 
1138360efbdSAlfred Perlstein 		clnt_geterr(clnt, &rpcerr);
1148360efbdSAlfred Perlstein 		minvers = rpcerr.re_vers.low;
1158360efbdSAlfred Perlstein 		maxvers = rpcerr.re_vers.high;
1168360efbdSAlfred Perlstein 		if (maxvers < vers_high)
1174e37855eSAlfred Perlstein 			vers_high = maxvers;
1184e37855eSAlfred Perlstein 		else
1194e37855eSAlfred Perlstein 			vers_high--;
1208360efbdSAlfred Perlstein 		if (minvers > vers_low)
1214e37855eSAlfred Perlstein 			vers_low = minvers;
1228360efbdSAlfred Perlstein 		if (vers_low > vers_high) {
1238360efbdSAlfred Perlstein 			goto error;
1248360efbdSAlfred Perlstein 		}
1254e37855eSAlfred Perlstein 		CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
1268360efbdSAlfred Perlstein 		rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
1278360efbdSAlfred Perlstein 				(char *)NULL, (xdrproc_t)xdr_void,
1288360efbdSAlfred Perlstein 				(char *)NULL, to);
1298360efbdSAlfred Perlstein 		if (rpc_stat == RPC_SUCCESS) {
1308360efbdSAlfred Perlstein 			*vers_out = vers_high;
1318360efbdSAlfred Perlstein 			return (clnt);
1328360efbdSAlfred Perlstein 		}
1338360efbdSAlfred Perlstein 	}
1348360efbdSAlfred Perlstein 	clnt_geterr(clnt, &rpcerr);
1358360efbdSAlfred Perlstein 
1368360efbdSAlfred Perlstein error:
1378360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = rpc_stat;
1388360efbdSAlfred Perlstein 	rpc_createerr.cf_error = rpcerr;
1398360efbdSAlfred Perlstein 	clnt_destroy(clnt);
1408360efbdSAlfred Perlstein 	return (NULL);
1418360efbdSAlfred Perlstein }
1428360efbdSAlfred Perlstein 
14399064799SGarrett Wollman /*
1448360efbdSAlfred Perlstein  * Top level client creation routine.
1458360efbdSAlfred Perlstein  * Generic client creation: takes (servers name, program-number, nettype) and
1468360efbdSAlfred Perlstein  * returns client handle. Default options are set, which the user can
1478360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s.
1488360efbdSAlfred Perlstein  *
1498360efbdSAlfred Perlstein  * It tries for all the netids in that particular class of netid until
1508360efbdSAlfred Perlstein  * it succeeds.
1518360efbdSAlfred Perlstein  * XXX The error message in the case of failure will be the one
1528360efbdSAlfred Perlstein  * pertaining to the last create error.
1538360efbdSAlfred Perlstein  *
1544e37855eSAlfred Perlstein  * It calls clnt_create_timed() with the default timeout.
15599064799SGarrett Wollman  */
1568360efbdSAlfred Perlstein CLIENT *
clnt_create(const char * hostname,rpcprog_t prog,rpcvers_t vers,const char * nettype)1574e37855eSAlfred Perlstein clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
1584e37855eSAlfred Perlstein     const char *nettype)
1594e37855eSAlfred Perlstein {
1604e37855eSAlfred Perlstein 
1614e37855eSAlfred Perlstein 	return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
1624e37855eSAlfred Perlstein }
1634e37855eSAlfred Perlstein 
1644e37855eSAlfred Perlstein /*
1654e37855eSAlfred Perlstein  * This the routine has the same definition as clnt_create(),
1664e37855eSAlfred Perlstein  * except it takes an additional timeout parameter - a pointer to
1674e37855eSAlfred Perlstein  * a timeval structure.  A NULL value for the pointer indicates
1684e37855eSAlfred Perlstein  * that the default timeout value should be used.
1694e37855eSAlfred Perlstein  *
1704e37855eSAlfred Perlstein  * This function calls clnt_tp_create_timed().
1714e37855eSAlfred Perlstein  */
1724e37855eSAlfred Perlstein CLIENT *
clnt_create_timed(const char * hostname,rpcprog_t prog,rpcvers_t vers,const char * netclass,const struct timeval * tp)1734e37855eSAlfred Perlstein clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
1744e37855eSAlfred Perlstein     const char *netclass, const struct timeval *tp)
1758360efbdSAlfred Perlstein {
1768360efbdSAlfred Perlstein 	struct netconfig *nconf;
1778360efbdSAlfred Perlstein 	CLIENT *clnt = NULL;
1788360efbdSAlfred Perlstein 	void *handle;
1798360efbdSAlfred Perlstein 	enum clnt_stat	save_cf_stat = RPC_SUCCESS;
1808360efbdSAlfred Perlstein 	struct rpc_err	save_cf_error;
1814e37855eSAlfred Perlstein 	char nettype_array[NETIDLEN];
1824e37855eSAlfred Perlstein 	char *nettype = &nettype_array[0];
1838360efbdSAlfred Perlstein 
1844e37855eSAlfred Perlstein 	if (netclass == NULL)
1854e37855eSAlfred Perlstein 		nettype = NULL;
1864e37855eSAlfred Perlstein 	else {
1874e37855eSAlfred Perlstein 		size_t len = strlen(netclass);
1884e37855eSAlfred Perlstein 		if (len >= sizeof (nettype_array)) {
1894e37855eSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
1904e37855eSAlfred Perlstein 			return (NULL);
1914e37855eSAlfred Perlstein 		}
1924e37855eSAlfred Perlstein 		strcpy(nettype, netclass);
1934e37855eSAlfred Perlstein 	}
1948360efbdSAlfred Perlstein 
1954e37855eSAlfred Perlstein 	if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
19699064799SGarrett Wollman 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
19799064799SGarrett Wollman 		return (NULL);
19899064799SGarrett Wollman 	}
1998360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = RPC_SUCCESS;
2008360efbdSAlfred Perlstein 	while (clnt == NULL) {
2018360efbdSAlfred Perlstein 		if ((nconf = __rpc_getconf(handle)) == NULL) {
2028360efbdSAlfred Perlstein 			if (rpc_createerr.cf_stat == RPC_SUCCESS)
2038360efbdSAlfred Perlstein 				rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
20499064799SGarrett Wollman 			break;
2058360efbdSAlfred Perlstein 		}
2068360efbdSAlfred Perlstein #ifdef CLNT_DEBUG
2078360efbdSAlfred Perlstein 		printf("trying netid %s\n", nconf->nc_netid);
2088360efbdSAlfred Perlstein #endif
2094e37855eSAlfred Perlstein 		clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
2108360efbdSAlfred Perlstein 		if (clnt)
2118360efbdSAlfred Perlstein 			break;
2128360efbdSAlfred Perlstein 		else
2138360efbdSAlfred Perlstein 			/*
2148360efbdSAlfred Perlstein 			 *	Since we didn't get a name-to-address
2158360efbdSAlfred Perlstein 			 *	translation failure here, we remember
2168360efbdSAlfred Perlstein 			 *	this particular error.  The object of
2178360efbdSAlfred Perlstein 			 *	this is to enable us to return to the
2188360efbdSAlfred Perlstein 			 *	caller a more-specific error than the
2198360efbdSAlfred Perlstein 			 *	unhelpful ``Name to address translation
2208360efbdSAlfred Perlstein 			 *	failed'' which might well occur if we
2218360efbdSAlfred Perlstein 			 *	merely returned the last error (because
2228360efbdSAlfred Perlstein 			 *	the local loopbacks are typically the
2238360efbdSAlfred Perlstein 			 *	last ones in /etc/netconfig and the most
2248360efbdSAlfred Perlstein 			 *	likely to be unable to translate a host
2254e37855eSAlfred Perlstein 			 *	name).  We also check for a more
2264e37855eSAlfred Perlstein 			 *	meaningful error than ``unknown host
2274e37855eSAlfred Perlstein 			 *	name'' for the same reasons.
2288360efbdSAlfred Perlstein 			 */
2294e37855eSAlfred Perlstein 			if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
2304e37855eSAlfred Perlstein 			    rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
2318360efbdSAlfred Perlstein 				save_cf_stat = rpc_createerr.cf_stat;
2328360efbdSAlfred Perlstein 				save_cf_error = rpc_createerr.cf_error;
2338360efbdSAlfred Perlstein 			}
2348360efbdSAlfred Perlstein 	}
2358360efbdSAlfred Perlstein 
2368360efbdSAlfred Perlstein 	/*
2378360efbdSAlfred Perlstein 	 *	Attempt to return an error more specific than ``Name to address
2384e37855eSAlfred Perlstein 	 *	translation failed'' or ``unknown host name''
2398360efbdSAlfred Perlstein 	 */
2404e37855eSAlfred Perlstein 	if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
2414e37855eSAlfred Perlstein 				rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
2428360efbdSAlfred Perlstein 					(save_cf_stat != RPC_SUCCESS)) {
2438360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = save_cf_stat;
2448360efbdSAlfred Perlstein 		rpc_createerr.cf_error = save_cf_error;
2458360efbdSAlfred Perlstein 	}
2468360efbdSAlfred Perlstein 	__rpc_endconf(handle);
2478360efbdSAlfred Perlstein 	return (clnt);
2488360efbdSAlfred Perlstein }
2498360efbdSAlfred Perlstein 
2508360efbdSAlfred Perlstein /*
2518360efbdSAlfred Perlstein  * Generic client creation: takes (servers name, program-number, netconf) and
2528360efbdSAlfred Perlstein  * returns client handle. Default options are set, which the user can
2538360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s : clnt_control()
2544e37855eSAlfred Perlstein  * It finds out the server address from rpcbind and calls clnt_tli_create().
2554e37855eSAlfred Perlstein  *
2564e37855eSAlfred Perlstein  * It calls clnt_tp_create_timed() with the default timeout.
2578360efbdSAlfred Perlstein  */
2588360efbdSAlfred Perlstein CLIENT *
clnt_tp_create(const char * hostname,rpcprog_t prog,rpcvers_t vers,const struct netconfig * nconf)2594e37855eSAlfred Perlstein clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
2604e37855eSAlfred Perlstein     const struct netconfig *nconf)
2614e37855eSAlfred Perlstein {
2624e37855eSAlfred Perlstein 
2634e37855eSAlfred Perlstein 	return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
2644e37855eSAlfred Perlstein }
2654e37855eSAlfred Perlstein 
2664e37855eSAlfred Perlstein /*
2674e37855eSAlfred Perlstein  * This has the same definition as clnt_tp_create(), except it
2684e37855eSAlfred Perlstein  * takes an additional parameter - a pointer to a timeval structure.
2694e37855eSAlfred Perlstein  * A NULL value for the timeout pointer indicates that the default
2704e37855eSAlfred Perlstein  * value for the timeout should be used.
2714e37855eSAlfred Perlstein  */
2724e37855eSAlfred Perlstein CLIENT *
clnt_tp_create_timed(const char * hostname,rpcprog_t prog,rpcvers_t vers,const struct netconfig * nconf,const struct timeval * tp)2734e37855eSAlfred Perlstein clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
2744e37855eSAlfred Perlstein     const struct netconfig *nconf, const struct timeval *tp)
2758360efbdSAlfred Perlstein {
2768360efbdSAlfred Perlstein 	struct netbuf *svcaddr;			/* servers address */
2778360efbdSAlfred Perlstein 	CLIENT *cl = NULL;			/* client handle */
2788360efbdSAlfred Perlstein 
2798360efbdSAlfred Perlstein 	if (nconf == NULL) {
2808360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
28199064799SGarrett Wollman 		return (NULL);
28299064799SGarrett Wollman 	}
2838360efbdSAlfred Perlstein 
2848360efbdSAlfred Perlstein 	/*
2858360efbdSAlfred Perlstein 	 * Get the address of the server
2868360efbdSAlfred Perlstein 	 */
2874e37855eSAlfred Perlstein 	if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
2884e37855eSAlfred Perlstein 			(struct netconfig *)nconf, (char *)hostname,
2894e37855eSAlfred Perlstein 			&cl, (struct timeval *)tp)) == NULL) {
2908360efbdSAlfred Perlstein 		/* appropriate error number is set by rpcbind libraries */
2918360efbdSAlfred Perlstein 		return (NULL);
2928360efbdSAlfred Perlstein 	}
2938360efbdSAlfred Perlstein 	if (cl == NULL) {
2948360efbdSAlfred Perlstein 		cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
2958360efbdSAlfred Perlstein 					prog, vers, 0, 0);
2968360efbdSAlfred Perlstein 	} else {
2978360efbdSAlfred Perlstein 		/* Reuse the CLIENT handle and change the appropriate fields */
2988360efbdSAlfred Perlstein 		if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
2998360efbdSAlfred Perlstein 			if (cl->cl_netid == NULL)
3008360efbdSAlfred Perlstein 				cl->cl_netid = strdup(nconf->nc_netid);
3018360efbdSAlfred Perlstein 			if (cl->cl_tp == NULL)
3028360efbdSAlfred Perlstein 				cl->cl_tp = strdup(nconf->nc_device);
3038360efbdSAlfred Perlstein 			(void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
3048360efbdSAlfred Perlstein 			(void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
3058360efbdSAlfred Perlstein 		} else {
3068360efbdSAlfred Perlstein 			CLNT_DESTROY(cl);
3078360efbdSAlfred Perlstein 			cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
3088360efbdSAlfred Perlstein 					prog, vers, 0, 0);
3098360efbdSAlfred Perlstein 		}
3108360efbdSAlfred Perlstein 	}
3118360efbdSAlfred Perlstein 	free(svcaddr->buf);
3128360efbdSAlfred Perlstein 	free(svcaddr);
3138360efbdSAlfred Perlstein 	return (cl);
3148360efbdSAlfred Perlstein }
3158360efbdSAlfred Perlstein 
3168360efbdSAlfred Perlstein /*
3178360efbdSAlfred Perlstein  * Generic client creation:  returns client handle.
3188360efbdSAlfred Perlstein  * Default options are set, which the user can
3198360efbdSAlfred Perlstein  * change using the rpc equivalent of _ioctl()'s : clnt_control().
3208360efbdSAlfred Perlstein  * If fd is RPC_ANYFD, it will be opened using nconf.
3218360efbdSAlfred Perlstein  * It will be bound if not so.
3228360efbdSAlfred Perlstein  * If sizes are 0; appropriate defaults will be chosen.
3238360efbdSAlfred Perlstein  */
3248360efbdSAlfred Perlstein CLIENT *
clnt_tli_create(int fd,const struct netconfig * nconf,struct netbuf * svcaddr,rpcprog_t prog,rpcvers_t vers,uint sendsz,uint recvsz)3254e37855eSAlfred Perlstein clnt_tli_create(int fd, const struct netconfig *nconf,
3264e37855eSAlfred Perlstein 	struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
3274e37855eSAlfred Perlstein 	uint sendsz, uint recvsz)
3288360efbdSAlfred Perlstein {
3298360efbdSAlfred Perlstein 	CLIENT *cl;			/* client handle */
3308360efbdSAlfred Perlstein 	bool_t madefd = FALSE;		/* whether fd opened here */
3318360efbdSAlfred Perlstein 	long servtype;
3328360efbdSAlfred Perlstein 	int one = 1;
3338360efbdSAlfred Perlstein 	struct __rpc_sockinfo si;
3344e37855eSAlfred Perlstein 	extern int __rpc_minfd;
3358360efbdSAlfred Perlstein 
3368360efbdSAlfred Perlstein 	if (fd == RPC_ANYFD) {
3378360efbdSAlfred Perlstein 		if (nconf == NULL) {
3388360efbdSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
3398360efbdSAlfred Perlstein 			return (NULL);
3408360efbdSAlfred Perlstein 		}
3418360efbdSAlfred Perlstein 
3428360efbdSAlfred Perlstein 		fd = __rpc_nconf2fd(nconf);
3438360efbdSAlfred Perlstein 
3448360efbdSAlfred Perlstein 		if (fd == -1)
3458360efbdSAlfred Perlstein 			goto err;
3464e37855eSAlfred Perlstein 		if (fd < __rpc_minfd)
3474e37855eSAlfred Perlstein 			fd = __rpc_raise_fd(fd);
3488360efbdSAlfred Perlstein 		madefd = TRUE;
3498360efbdSAlfred Perlstein 		servtype = nconf->nc_semantics;
3508360efbdSAlfred Perlstein 		if (!__rpc_fd2sockinfo(fd, &si))
3518360efbdSAlfred Perlstein 			goto err;
3528360efbdSAlfred Perlstein 		bindresvport(fd, NULL);
3538360efbdSAlfred Perlstein 	} else {
3548360efbdSAlfred Perlstein 		if (!__rpc_fd2sockinfo(fd, &si))
3558360efbdSAlfred Perlstein 			goto err;
3568360efbdSAlfred Perlstein 		servtype = __rpc_socktype2seman(si.si_socktype);
3578360efbdSAlfred Perlstein 		if (servtype == -1) {
3588360efbdSAlfred Perlstein 			rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
3594e37855eSAlfred Perlstein 			return (NULL);
3608360efbdSAlfred Perlstein 		}
3618360efbdSAlfred Perlstein 	}
3628360efbdSAlfred Perlstein 
3638360efbdSAlfred Perlstein 	if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
3648360efbdSAlfred Perlstein 		rpc_createerr.cf_stat = RPC_UNKNOWNHOST;	/* XXX */
3658360efbdSAlfred Perlstein 		goto err1;
3668360efbdSAlfred Perlstein 	}
3678360efbdSAlfred Perlstein 
3688360efbdSAlfred Perlstein 	switch (servtype) {
3694e37855eSAlfred Perlstein 	case NC_TPI_COTS:
3708360efbdSAlfred Perlstein 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
3718360efbdSAlfred Perlstein 		break;
3724e37855eSAlfred Perlstein 	case NC_TPI_COTS_ORD:
3734e37855eSAlfred Perlstein 		if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
3748360efbdSAlfred Perlstein 			_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
3758360efbdSAlfred Perlstein 			    sizeof (one));
3764e37855eSAlfred Perlstein 		}
3774e37855eSAlfred Perlstein 		cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
3788360efbdSAlfred Perlstein 		break;
3798360efbdSAlfred Perlstein 	case NC_TPI_CLTS:
3808360efbdSAlfred Perlstein 		cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
38199064799SGarrett Wollman 		break;
38299064799SGarrett Wollman 	default:
3838360efbdSAlfred Perlstein 		goto err;
38499064799SGarrett Wollman 	}
3858360efbdSAlfred Perlstein 
3868360efbdSAlfred Perlstein 	if (cl == NULL)
3878360efbdSAlfred Perlstein 		goto err1; /* borrow errors from clnt_dg/vc creates */
3888360efbdSAlfred Perlstein 	if (nconf) {
3898360efbdSAlfred Perlstein 		cl->cl_netid = strdup(nconf->nc_netid);
3908360efbdSAlfred Perlstein 		cl->cl_tp = strdup(nconf->nc_device);
3918360efbdSAlfred Perlstein 	} else {
3928360efbdSAlfred Perlstein 		cl->cl_netid = "";
3938360efbdSAlfred Perlstein 		cl->cl_tp = "";
3948360efbdSAlfred Perlstein 	}
3958360efbdSAlfred Perlstein 	if (madefd) {
3968360efbdSAlfred Perlstein 		(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
3974e37855eSAlfred Perlstein /*		(void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL);  */
398341f552dSPedro F. Giffuni 	}
3998360efbdSAlfred Perlstein 
4008360efbdSAlfred Perlstein 	return (cl);
4018360efbdSAlfred Perlstein 
4028360efbdSAlfred Perlstein err:
4038360efbdSAlfred Perlstein 	rpc_createerr.cf_stat = RPC_SYSTEMERROR;
4048360efbdSAlfred Perlstein 	rpc_createerr.cf_error.re_errno = errno;
4058360efbdSAlfred Perlstein err1:	if (madefd)
4068360efbdSAlfred Perlstein 		(void)_close(fd);
4078360efbdSAlfred Perlstein 	return (NULL);
40899064799SGarrett Wollman }
4094e37855eSAlfred Perlstein 
4104e37855eSAlfred Perlstein /*
4114e37855eSAlfred Perlstein  *  To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
4124e37855eSAlfred Perlstein  *  we try to not use them.  The __rpc_raise_fd() routine will dup
4134e37855eSAlfred Perlstein  *  a descriptor to a higher value.  If we fail to do it, we continue
4144e37855eSAlfred Perlstein  *  to use the old one (and hope for the best).
4154e37855eSAlfred Perlstein  */
4164e37855eSAlfred Perlstein int __rpc_minfd = 3;
4174e37855eSAlfred Perlstein 
4184e37855eSAlfred Perlstein int
__rpc_raise_fd(int fd)4194e37855eSAlfred Perlstein __rpc_raise_fd(int fd)
4204e37855eSAlfred Perlstein {
4214e37855eSAlfred Perlstein 	int nfd;
4224e37855eSAlfred Perlstein 
4234e37855eSAlfred Perlstein 	if (fd >= __rpc_minfd)
4244e37855eSAlfred Perlstein 		return (fd);
4254e37855eSAlfred Perlstein 
4264e37855eSAlfred Perlstein 	if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
4274e37855eSAlfred Perlstein 		return (fd);
4284e37855eSAlfred Perlstein 
4294e37855eSAlfred Perlstein 	if (_fsync(nfd) == -1) {
4304e37855eSAlfred Perlstein 		_close(nfd);
4314e37855eSAlfred Perlstein 		return (fd);
4324e37855eSAlfred Perlstein 	}
4334e37855eSAlfred Perlstein 
4344e37855eSAlfred Perlstein 	if (_close(fd) == -1) {
4354e37855eSAlfred Perlstein 		/* this is okay, we will syslog an error, then use the new fd */
4364e37855eSAlfred Perlstein 		(void) syslog(LOG_ERR,
4374e37855eSAlfred Perlstein 			"could not close() fd %d; mem & fd leak", fd);
4384e37855eSAlfred Perlstein 	}
4394e37855eSAlfred Perlstein 
4404e37855eSAlfred Perlstein 	return (nfd);
4414e37855eSAlfred Perlstein }
442