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