18360efbdSAlfred Perlstein /* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */ 28360efbdSAlfred Perlstein 3*44443e42SHiroki Sato /*- 4*44443e42SHiroki Sato * Copyright (c) 2010, Oracle America, Inc. 5*44443e42SHiroki Sato * All rights reserved. 64e37855eSAlfred Perlstein * 7*44443e42SHiroki Sato * Redistribution and use in source and binary forms, with or without 8*44443e42SHiroki Sato * modification, are permitted provided that the following conditions are met: 9*44443e42SHiroki Sato * - Redistributions of source code must retain the above copyright notice, 10*44443e42SHiroki Sato * this list of conditions and the following disclaimer. 11*44443e42SHiroki Sato * - Redistributions in binary form must reproduce the above copyright notice, 12*44443e42SHiroki Sato * this list of conditions and the following disclaimer in the documentation 13*44443e42SHiroki Sato * and/or other materials provided with the distribution. 14*44443e42SHiroki Sato * - Neither the name of the "Oracle America, Inc." nor the names of its 15*44443e42SHiroki Sato * contributors may be used to endorse or promote products derived 16*44443e42SHiroki Sato * from this software without specific prior written permission. 174e37855eSAlfred Perlstein * 18*44443e42SHiroki Sato * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19*44443e42SHiroki Sato * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*44443e42SHiroki Sato * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*44443e42SHiroki Sato * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22*44443e42SHiroki Sato * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23*44443e42SHiroki Sato * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24*44443e42SHiroki Sato * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25*44443e42SHiroki Sato * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26*44443e42SHiroki Sato * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27*44443e42SHiroki Sato * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28*44443e42SHiroki 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); */ 4058360efbdSAlfred Perlstein }; 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