From owner-freebsd-bugs Sat Oct 6 17:31:18 2001 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id B7C5437B406 for ; Sat, 6 Oct 2001 17:30:02 -0700 (PDT) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.4/8.11.4) id f970U2U29332; Sat, 6 Oct 2001 17:30:02 -0700 (PDT) (envelope-from gnats) Date: Sat, 6 Oct 2001 17:30:02 -0700 (PDT) Message-Id: <200110070030.f970U2U29332@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: Martin Blapp Subject: Re: bin/29177: [PATCH] rpc client create functions with additional timeout Reply-To: Martin Blapp Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org The following reply was made to PR bin/29177; it has been noted by GNATS. From: Martin Blapp To: Cc: Subject: Re: bin/29177: [PATCH] rpc client create functions with additional timeout Date: Sun, 7 Oct 2001 02:28:00 +0200 (CEST) License change reviewed by Warner Losh. I'll send a mail again to freebsd-audit to get this ok'ed. ----------------------------------------------------------------- Last modified: 2001-10-05 23:35 Changed files: include/rpc/clnt.h lib/libc/rpc/clnt_generic.c lib/libc/rpc/rpc_clnt_create.3 lib/libc/rpc/rpcb_clnt.c lib/libc/rpc/Makefile.inc New files: lib/libc/rpc/LICENSE Comment: Add timed functions for the client create routines. This should help us a lot with timeouts, so we don't have to wait everytime the default timeout of 25 seconds. The logic has changed a bit, so we do a check first if the local rpcbind is up before we do a query. Part of the code was from tircp 2.8 (tirpc1999). There is also a new function __rpc_raise_fd available, to avoid conflicts with the "magic" file descriptors (0, 1, and 2). I added the new license as needed in the modified files. Index: include/rpc/clnt.h =================================================================== RCS file: /usr/home/ncvs/src/include/rpc/clnt.h,v retrieving revision 1.14 diff -u -r1.14 clnt.h --- include/rpc/clnt.h 23 Jun 2001 19:43:16 -0000 1.14 +++ include/rpc/clnt.h 5 Oct 2001 21:25:13 -0000 @@ -36,7 +36,8 @@ /* * clnt.h - Client side remote procedure call interface. * - * Copyright (C) 1984, Sun Microsystems, Inc. + * Copyright (c) 1986-1991,1994-1999 by Sun Microsystems, Inc. + * All rights reserved. */ #ifndef _RPC_CLNT_H_ @@ -257,6 +258,7 @@ #define NULLPROC ((rpcproc_t)0) +__BEGIN_DECLS /* * Below are the client handle creation routines for the various * implementations of client side rpc. They can return NULL if a @@ -266,16 +268,9 @@ /* * Generic client creation routine. Supported protocols are those that * belong to the nettype namespace (/etc/netconfig). - * CLIENT * - * clnt_create(host, prog, vers, prot); - * const char *host; -- hostname - * const rpcprog_t prog; -- program number - * const rpcvers_t vers; -- version number - * const char *prot; -- protocol */ -__BEGIN_DECLS -extern CLIENT *clnt_create __P((const char *, const rpcprog_t, const rpcvers_t, - const char *)); +extern CLIENT *clnt_create (const char *, const rpcprog_t, const rpcvers_t, + const char *); /* * * const char *hostname; -- hostname @@ -285,12 +280,26 @@ */ /* + * Generic client creation routine. Just like clnt_create(), except + * it takes an additional timeout parameter. + */ +extern CLIENT * clnt_create_timed(const char *, const rpcprog_t, + const rpcvers_t, const char *, const struct timeval *); +/* + * + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const char *nettype; -- network type + * const struct timeval *tp; -- timeout + */ + +/* * Generic client creation routine. Supported protocols are which belong * to the nettype name space. */ -extern CLIENT *clnt_create_vers __P((const char *, const rpcprog_t, rpcvers_t *, - const rpcvers_t, const rpcvers_t, - const char *)); +extern CLIENT *clnt_create_vers (const char *, const rpcprog_t, rpcvers_t *, + const rpcvers_t, const rpcvers_t, const char *); /* * const char *host; -- hostname * const rpcprog_t prog; -- program number @@ -300,13 +309,29 @@ * const char *nettype; -- network type */ +/* + * Generic client creation routine. Supported protocols are which belong + * to the nettype name space. + */ +extern CLIENT * clnt_create_vers_timed(const char *, const rpcprog_t, + rpcvers_t *, const rpcvers_t, const rpcvers_t, const char *, + const struct timeval *); +/* + * const char *host; -- hostname + * const rpcprog_t prog; -- program number + * rpcvers_t *vers_out; -- servers highest available version + * const rpcvers_t vers_low; -- low version number + * const rpcvers_t vers_high; -- high version number + * const char *nettype; -- network type + * const struct timeval *tp -- timeout + */ /* * Generic client creation routine. It takes a netconfig structure * instead of nettype */ -extern CLIENT *clnt_tp_create __P((const char *, const rpcprog_t, - const rpcvers_t, const struct netconfig *)); +extern CLIENT *clnt_tp_create (const char *, const rpcprog_t, + const rpcvers_t, const struct netconfig *); /* * const char *hostname; -- hostname * const rpcprog_t prog; -- program number @@ -315,16 +340,29 @@ */ /* - * Generic TLI create routine. Only provided for compatibility. + * Generic client creation routine. Just like clnt_tp_create(), except + * it takes an additional timeout parameter. + */ +extern CLIENT * clnt_tp_create_timed(const char *, const rpcprog_t, + const rpcvers_t, const struct netconfig *, const struct timeval *); +/* + * const char *hostname; -- hostname + * const rpcprog_t prog; -- program number + * const rpcvers_t vers; -- version number + * const struct netconfig *netconf; -- network config structure + * const struct timeval *tp -- timeout */ -extern CLIENT *clnt_tli_create __P((const int, const struct netconfig *, - const struct netbuf *, const rpcprog_t, - const rpcvers_t, const u_int, const u_int)); +/* + * Generic TLI create routine. Only provided for compatibility. + */ +extern CLIENT *clnt_tli_create (const int, const struct netconfig *, + struct netbuf *, const rpcprog_t, + const rpcvers_t, const u_int, const u_int); /* * const register int fd; -- fd * const struct netconfig *nconf; -- netconfig structure - * const struct netbuf *svcaddr; -- servers address + * struct netbuf *svcaddr; -- servers address * const u_long prog; -- program number * const u_long vers; -- version number * const u_int sendsz; -- send size @@ -334,9 +372,8 @@ /* * Low level clnt create routine for connectionful transports, e.g. tcp. */ -extern CLIENT *clnt_vc_create __P((const int, const struct netbuf *, - const rpcprog_t, const rpcvers_t, - const u_int, const u_int)); +extern CLIENT *clnt_vc_create (const int, const struct netbuf *, + const rpcprog_t, const rpcvers_t, const u_int, const u_int); /* * const int fd; -- open file descriptor * const struct netbuf *svcaddr; -- servers address @@ -349,9 +386,9 @@ /* * Low level clnt create routine for connectionless transports, e.g. udp. */ -extern CLIENT *clnt_dg_create __P((const int, const struct netbuf *, - const rpcprog_t, const rpcvers_t, - const u_int, const u_int)); +extern CLIENT *clnt_dg_create (const int, const struct netbuf *, + const rpcprog_t, const rpcvers_t, + const u_int, const u_int); /* * const int fd; -- open file descriptor * const struct netbuf *svcaddr; -- servers address @@ -368,7 +405,7 @@ * u_long prog; * u_long vers; */ -extern CLIENT *clnt_raw_create __P((rpcprog_t, rpcvers_t)); +extern CLIENT *clnt_raw_create (rpcprog_t, rpcvers_t); __END_DECLS Index: lib/libc/rpc/Makefile.inc =================================================================== RCS file: /usr/home/ncvs/src/lib/libc/rpc/Makefile.inc,v retrieving revision 1.20 diff -u -r1.20 Makefile.inc --- lib/libc/rpc/Makefile.inc 27 Mar 2001 17:26:51 -0000 1.20 +++ lib/libc/rpc/Makefile.inc 5 Oct 2001 21:25:13 -0000 @@ -78,7 +78,9 @@ rpc_clnt_calls.3 clnt_geterr.3 \ rpc_clnt_create.3 clnt_control.3 \ rpc_clnt_create.3 clnt_create.3 \ + rpc_clnt_create.3 clnt_create_timed.3 \ rpc_clnt_create.3 clnt_create_vers.3 \ + rpc_clnt_create.3 clnt_create_vers_timed.3 \ rpc_clnt_create.3 clnt_destroy.3 \ rpc_clnt_create.3 clnt_pcreateerror.3 \ rpc_clnt_create.3 clnt_spcreateerror.3 \ @@ -86,6 +88,7 @@ rpc_clnt_create.3 clnt_raw_create.3 \ rpc_clnt_create.3 clnt_tli_create.3 \ rpc_clnt_create.3 clnt_tp_create.3 \ + rpc_clnt_create.3 clnt_tp_create_timed.3 \ rpc_clnt_create.3 clnt_vc_create.3 \ rpc_svc_calls.3 svc_dg_enablecache.3 \ rpc_svc_calls.3 svc_exit.3 \ Index: lib/libc/rpc/clnt_generic.c =================================================================== RCS file: /usr/home/ncvs/src/lib/libc/rpc/clnt_generic.c,v retrieving revision 1.12 diff -u -r1.12 clnt_generic.c --- lib/libc/rpc/clnt_generic.c 2 Apr 2001 21:41:43 -0000 1.12 +++ lib/libc/rpc/clnt_generic.c 5 Oct 2001 21:25:13 -0000 @@ -1,6 +1,23 @@ /* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */ /* + * The contents of this file are subject to the Sun Standards + * License Version 1.0 the (the "License";) You may not use + * this file except in compliance with the License. You may + * obtain a copy of the License at lib/libc/rpc/LICENSE + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is Copyright 1998 by Sun Microsystems, Inc + * + * The Initial Developer of the Original Code is: Sun + * Microsystems, Inc. + * + * All Rights Reserved. + * * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users @@ -29,7 +46,7 @@ * Mountain View, California 94043 */ -/* #ident "@(#)clnt_generic.c 1.20 94/05/03 SMI" */ +/* #ident "@(#)clnt_generic.c 1.40 99/04/21 SMI" */ #if defined(LIBC_SCCS) && !defined(lint) /*static char *sccsid = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";*/ @@ -38,17 +55,20 @@ #endif /* - * Copyright (c) 1986-1991 by Sun Microsystems Inc. + * Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc. + * All rights reserved. */ #include "namespace.h" #include "reentrant.h" #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -57,55 +77,79 @@ #include "un-namespace.h" #include "rpc_com.h" +extern bool_t __rpc_is_local_host(const char *); +int __rpc_raise_fd(int); + +#ifndef NETIDLEN +#define NETIDLEN 32 +#endif + + /* * Generic client creation with version checking the value of * vers_out is set to the highest server supported value * vers_low <= vers_out <= vers_high AND an error results * if this can not be done. + * + * It calls clnt_create_vers_timed() with a NULL value for the timeout + * pointer, which indicates that the default timeout should be used. */ CLIENT * -clnt_create_vers(hostname, prog, vers_out, vers_low, vers_high, nettype) - const char *hostname; - rpcprog_t prog; - rpcvers_t *vers_out; - rpcvers_t vers_low; - rpcvers_t vers_high; - const char *nettype; +clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out, + rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype) +{ + + return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low, + vers_high, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create_vers(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + */ +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) { CLIENT *clnt; struct timeval to; enum clnt_stat rpc_stat; struct rpc_err rpcerr; - clnt = clnt_create(hostname, prog, vers_high, nettype); + clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp); if (clnt == NULL) { return (NULL); } to.tv_sec = 10; to.tv_usec = 0; - rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, - (char *) NULL, (xdrproc_t) xdr_void, (char *) NULL, to); + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to); if (rpc_stat == RPC_SUCCESS) { *vers_out = vers_high; return (clnt); } - if (rpc_stat == RPC_PROGVERSMISMATCH) { - unsigned long minvers, maxvers; + while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) { + unsigned int minvers, maxvers; clnt_geterr(clnt, &rpcerr); minvers = rpcerr.re_vers.low; maxvers = rpcerr.re_vers.high; if (maxvers < vers_high) - vers_high = (rpcvers_t)maxvers; + vers_high = maxvers; + else + vers_high--; if (minvers > vers_low) - vers_low = (rpcvers_t)minvers; + vers_low = minvers; if (vers_low > vers_high) { goto error; } - CLNT_CONTROL(clnt, CLSET_VERS, (char *)(void *)&vers_high); - rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, - (char *) NULL, (xdrproc_t) xdr_void, - (char *) NULL, to); + CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high); + rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void, + (char *)NULL, (xdrproc_t)xdr_void, + (char *)NULL, to); if (rpc_stat == RPC_SUCCESS) { *vers_out = vers_high; return (clnt); @@ -131,23 +175,48 @@ * XXX The error message in the case of failure will be the one * pertaining to the last create error. * - * It calls clnt_tp_create(); + * It calls clnt_create_timed() with the default timeout. */ CLIENT * -clnt_create(hostname, prog, vers, nettype) - const char *hostname; /* server name */ - rpcprog_t prog; /* program number */ - rpcvers_t vers; /* version number */ - const char *nettype; /* net type */ +clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const char *nettype) +{ + + return (clnt_create_timed(hostname, prog, vers, nettype, NULL)); +} + +/* + * This the routine has the same definition as clnt_create(), + * except it takes an additional timeout parameter - a pointer to + * a timeval structure. A NULL value for the pointer indicates + * that the default timeout value should be used. + * + * This function calls clnt_tp_create_timed(). + */ +CLIENT * +clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const char *netclass, const struct timeval *tp) { struct netconfig *nconf; CLIENT *clnt = NULL; void *handle; enum clnt_stat save_cf_stat = RPC_SUCCESS; struct rpc_err save_cf_error; + char nettype_array[NETIDLEN]; + char *nettype = &nettype_array[0]; + if (netclass == NULL) + nettype = NULL; + else { + size_t len = strlen(netclass); + if (len >= sizeof (nettype_array)) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + strcpy(nettype, netclass); + } - if ((handle = __rpc_setconf(nettype)) == NULL) { + if ((handle = __rpc_setconf((char *)nettype)) == NULL) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } @@ -161,7 +230,7 @@ #ifdef CLNT_DEBUG printf("trying netid %s\n", nconf->nc_netid); #endif - clnt = clnt_tp_create(hostname, prog, vers, nconf); + clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp); if (clnt) break; else @@ -177,9 +246,12 @@ * the local loopbacks are typically the * last ones in /etc/netconfig and the most * likely to be unable to translate a host - * name). + * name). We also check for a more + * meaningful error than ``unknown host + * name'' for the same reasons. */ - if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE) { + if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE && + rpc_createerr.cf_stat != RPC_UNKNOWNHOST) { save_cf_stat = rpc_createerr.cf_stat; save_cf_error = rpc_createerr.cf_error; } @@ -187,10 +259,11 @@ /* * Attempt to return an error more specific than ``Name to address - * translation failed'' + * translation failed'' or ``unknown host name'' */ - if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE) && - (save_cf_stat != RPC_SUCCESS)) { + if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE || + rpc_createerr.cf_stat == RPC_UNKNOWNHOST) && + (save_cf_stat != RPC_SUCCESS)) { rpc_createerr.cf_stat = save_cf_stat; rpc_createerr.cf_error = save_cf_error; } @@ -202,14 +275,27 @@ * Generic client creation: takes (servers name, program-number, netconf) and * returns client handle. Default options are set, which the user can * change using the rpc equivalent of _ioctl()'s : clnt_control() - * It finds out the server address from rpcbind and calls clnt_tli_create() + * It finds out the server address from rpcbind and calls clnt_tli_create(). + * + * It calls clnt_tp_create_timed() with the default timeout. */ CLIENT * -clnt_tp_create(hostname, prog, vers, nconf) - const char *hostname; /* server name */ - rpcprog_t prog; /* program number */ - rpcvers_t vers; /* version number */ - const struct netconfig *nconf; /* net config struct */ +clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const struct netconfig *nconf) +{ + + return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL)); +} + +/* + * This has the same definition as clnt_tp_create(), except it + * takes an additional parameter - a pointer to a timeval structure. + * A NULL value for the timeout pointer indicates that the default + * value for the timeout should be used. + */ +CLIENT * +clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers, + const struct netconfig *nconf, const struct timeval *tp) { struct netbuf *svcaddr; /* servers address */ CLIENT *cl = NULL; /* client handle */ @@ -222,8 +308,9 @@ /* * Get the address of the server */ - if ((svcaddr = __rpcb_findaddr(prog, vers, nconf, hostname, - &cl)) == NULL) { + if ((svcaddr = __rpcb_findaddr_timed(prog, vers, + (struct netconfig *)nconf, (char *)hostname, + &cl, (struct timeval *)tp)) == NULL) { /* appropriate error number is set by rpcbind libraries */ return (NULL); } @@ -259,20 +346,16 @@ * If sizes are 0; appropriate defaults will be chosen. */ CLIENT * -clnt_tli_create(fd, nconf, svcaddr, prog, vers, sendsz, recvsz) - int fd; /* fd */ - const struct netconfig *nconf; /* netconfig structure */ - const struct netbuf *svcaddr; /* servers address */ - rpcprog_t prog; /* program number */ - rpcvers_t vers; /* version number */ - u_int sendsz; /* send size */ - u_int recvsz; /* recv size */ +clnt_tli_create(int fd, const struct netconfig *nconf, + struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers, + uint sendsz, uint recvsz) { CLIENT *cl; /* client handle */ bool_t madefd = FALSE; /* whether fd opened here */ long servtype; int one = 1; struct __rpc_sockinfo si; + extern int __rpc_minfd; if (fd == RPC_ANYFD) { if (nconf == NULL) { @@ -284,12 +367,12 @@ if (fd == -1) goto err; - + if (fd < __rpc_minfd) + fd = __rpc_raise_fd(fd); madefd = TRUE; servtype = nconf->nc_semantics; if (!__rpc_fd2sockinfo(fd, &si)) goto err; - bindresvport(fd, NULL); } else { if (!__rpc_fd2sockinfo(fd, &si)) @@ -297,9 +380,8 @@ servtype = __rpc_socktype2seman(si.si_socktype); if (servtype == -1) { rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; - return NULL; + return (NULL); } - } if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) { @@ -308,14 +390,15 @@ } switch (servtype) { - case NC_TPI_COTS_ORD: + case NC_TPI_COTS: cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); - if (!nconf || !cl) - break; - /* XXX fvdl - is this useful? */ - if (strncmp(nconf->nc_protofmly, "inet", 4) == 0) + break; + case NC_TPI_COTS_ORD: + if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) { _setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one, sizeof (one)); + } + cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz); break; case NC_TPI_CLTS: cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz); @@ -335,7 +418,7 @@ } if (madefd) { (void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL); -/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, (char *) NULL); */ +/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */ }; return (cl); @@ -346,4 +429,37 @@ err1: if (madefd) (void)_close(fd); return (NULL); +} + +/* + * To avoid conflicts with the "magic" file descriptors (0, 1, and 2), + * we try to not use them. The __rpc_raise_fd() routine will dup + * a descriptor to a higher value. If we fail to do it, we continue + * to use the old one (and hope for the best). + */ +int __rpc_minfd = 3; + +int +__rpc_raise_fd(int fd) +{ + int nfd; + + if (fd >= __rpc_minfd) + return (fd); + + if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1) + return (fd); + + if (_fsync(nfd) == -1) { + _close(nfd); + return (fd); + } + + if (_close(fd) == -1) { + /* this is okay, we will syslog an error, then use the new fd */ + (void) syslog(LOG_ERR, + "could not close() fd %d; mem & fd leak", fd); + } + + return (nfd); } Index: lib/libc/rpc/rpc.3 =================================================================== RCS file: /usr/home/ncvs/src/lib/libc/rpc/rpc.3,v retrieving revision 1.17 diff -u -r1.17 rpc.3 --- lib/libc/rpc/rpc.3 1 Oct 2001 16:08:58 -0000 1.17 +++ lib/libc/rpc/rpc.3 5 Oct 2001 21:25:13 -0000 @@ -338,6 +338,12 @@ .Xr rpc_clnt_create 3 .It Fn clnt_create .Xr rpc_clnt_create 3 +.It Fn clnt_create_timed +.Xr rpc_clnt_create 3 +.It Fn clnt_create_vers +.Xr rpc_clnt_create 3 +.It Fn clnt_create_vers_timed +.Xr rpc_clnt_create 3 .It Fn clnt_destroy .Xr rpc_clnt_create 3 .It Fn clnt_dg_create @@ -363,6 +369,8 @@ .It Fn clnt_tli_create .Xr rpc_clnt_create 3 .It Fn clnt_tp_create +.Xr rpc_clnt_create 3 +.It Fn clnt_tp_create_timed .Xr rpc_clnt_create 3 .It Fn clnt_udpcreate .Xr rpc_soc 3 Index: lib/libc/rpc/rpc_clnt_create.3 =================================================================== RCS file: /usr/home/ncvs/src/lib/libc/rpc/rpc_clnt_create.3,v retrieving revision 1.5 diff -u -r1.5 rpc_clnt_create.3 --- lib/libc/rpc/rpc_clnt_create.3 3 Oct 2001 16:47:56 -0000 1.5 +++ lib/libc/rpc/rpc_clnt_create.3 5 Oct 2001 21:25:13 -0000 @@ -11,7 +11,9 @@ .Nm rpc_clnt_create , .Nm clnt_control , .Nm clnt_create , +.Nm clnt_create_timed , .Nm clnt_create_vers , +.Nm clnt_create_vers_timed , .Nm clnt_destroy , .Nm clnt_dg_create , .Nm clnt_pcreateerror , @@ -19,6 +21,7 @@ .Nm clnt_spcreateerror , .Nm clnt_tli_create , .Nm clnt_tp_create , +.Nm clnt_tp_create_timed , .Nm clnt_vc_create , .Nm rpc_createerr .Nd "library routines for dealing with creation and manipulation of" @@ -33,7 +36,11 @@ .Ft "CLIENT *" .Fn clnt_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" .Ft "CLIENT *" +.Fn clnt_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const char *nettype" "const struct timeval *timeout" +.Ft "CLIENT *" .Fn clnt_create_vers "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "const char *nettype" +.Ft "CLIENT *" +.Fn clnt_create_vers_timed "const char * host" "const rpcprog_t prognum" "rpcvers_t *vers_outp" "const rpcvers_t vers_low" "const rpcvers_t vers_high" "char *nettype" "const struct timeval *timeout" .Ft void .Fn clnt_destroy "CLIENT *clnt" .Ft "CLIENT *" @@ -49,6 +56,8 @@ .Ft "CLIENT *" .Fn clnt_tp_create "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" .Ft "CLIENT *" +.Fn clnt_tp_create_timed "const char * host" "const rpcprog_t prognum" "const rpcvers_t versnum" "const struct netconfig *netconf" "const struct timeval *timeout" +.Ft "CLIENT *" .Fn clnt_vc_create "const int fildes" "const struct netbuf *svcaddr" "const rpcprog_t prognum" "const rpcvers_t versnum" "const u_int sendsz" "const u_int recvsz" .Sh DESCRIPTION RPC library routines allow C language programs to make procedure @@ -158,6 +167,17 @@ .Fn clnt_call later (see .Xr rpc_clnt_calls 3 ) . +.It Fn clnt_create_timed +Generic client creation routine which is similar to +.Fn clnt_create +but which also has the additional parameter +.Fa timeout +that specifies the maximum amount of time allowed for +each transport class tried. In all other respects, the +.Fn clnt_create_timed +call behaves exactly like the +.Fn clnt_create +call. .It Fn clnt_create_vers Generic client creation routine which is similar to .Fn clnt_create @@ -213,6 +233,17 @@ does this for you and returns a valid handle only if a version within the range supplied is supported by the server. +.It Fn clnt_create_vers_timed +Generic client creation routine which is similar to +.Fn clnt_create_vers +but which also has the additional parameter +.Fa timeout +that specifies the maximum amount of time allowed for +each transport class tried. In all other respects, the +.Fn clnt_create_vers_timed +call behaves exactly like the +.Fn clnt_create_vers +call. .It Fn clnt_destroy A function macro that destroys the client's RPC handle. Destruction usually involves deallocation @@ -393,6 +424,20 @@ The .Fn clnt_pcreateerror routine can be used to print the reason for failure. +.It Fn clnt_tp_create_timed +Like +.Fn clnt_tp_create +except +.Fn clnt_tp_create_timed +has the extra parameter +.Fa timeout +which specifies the maximum time allowed for +for the creation attempt to succeed. +In all other respects, the +.Fn clnt_tp_create_timed +call behaves exactly like the +.Fn clnt_tp_create +call. .It Fn clnt_vc_create This routine creates an RPC client for the remote program Index: lib/libc/rpc/rpc_com.h =================================================================== RCS file: /usr/home/ncvs/src/lib/libc/rpc/rpc_com.h,v retrieving revision 1.1 diff -u -r1.1 rpc_com.h --- lib/libc/rpc/rpc_com.h 19 Mar 2001 12:49:51 -0000 1.1 +++ lib/libc/rpc/rpc_com.h 5 Oct 2001 21:25:13 -0000 @@ -30,7 +30,8 @@ * Mountain View, California 94043 */ /* - * Copyright (c) 1986 - 1991 by Sun Microsystems, Inc. + * Copyright (c) 1986-1991,1997-1998 by Sun Microsystems, Inc. + * All rights reserved. */ /* @@ -73,9 +74,10 @@ void *rpc_nullproc __P((CLIENT *)); int __rpc_sockisbound __P((int)); -struct netbuf *__rpcb_findaddr __P((rpcprog_t, rpcvers_t, +struct netbuf *__rpcb_findaddr_timed __P((rpcprog_t, rpcvers_t, const struct netconfig *, - const char *, CLIENT **)); + const char *, CLIENT **, + struct timeval *)); bool_t __rpc_control __P((int,void *)); char *_get_next_token __P((char *, int)); Index: lib/libc/rpc/rpcb_clnt.c =================================================================== RCS file: /usr/home/ncvs/src/lib/libc/rpc/rpcb_clnt.c,v retrieving revision 1.4 diff -u -r1.4 rpcb_clnt.c --- lib/libc/rpc/rpcb_clnt.c 2 Aug 2001 21:31:21 -0000 1.4 +++ lib/libc/rpc/rpcb_clnt.c 5 Oct 2001 21:25:13 -0000 @@ -2,6 +2,23 @@ /* $FreeBSD: src/lib/libc/rpc/rpcb_clnt.c,v 1.4 2001/08/02 21:31:21 iedowse Exp $ */ /* + * The contents of this file are subject to the Sun Standards + * License Version 1.0 the (the "License";) You may not use + * this file except in compliance with the License. You may + * obtain a copy of the License at lib/libc/rpc/LICENSE + * + * Software distributed under the License is distributed on + * an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See the License for the specific + * language governing rights and limitations under the License. + * + * The Original Code is Copyright 1998 by Sun Microsystems, Inc + * + * The Initial Developer of the Original Code is: Sun + * Microsystems, Inc. + * + * All Rights Reserved. + * * Sun RPC is a product of Sun Microsystems, Inc. and is provided for * unrestricted use provided that this legend is included on all tape * media and as a part of the software program in whole or part. Users @@ -76,6 +93,7 @@ static struct timeval tottimeout = { 60, 0 }; static const struct timeval rmttimeout = { 3, 0 }; +static struct timeval rpcbrmttime = { 15, 0 }; extern bool_t xdr_wrapstring __P((XDR *, char **)); @@ -631,6 +649,47 @@ } /* + * Quick check to see if rpcbind is up. Tries to connect over + * local transport. + */ +bool_t +__rpcbind_is_up() +{ + struct netconfig *nconf; + struct sockaddr_un sun; + void *localhandle; + int sock; + + nconf = NULL; + localhandle = setnetconfig(); + while (nconf = getnetconfig(localhandle)){ + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) + break; + } + if (nconf == NULL) + return (FALSE); + + endnetconfig(localhandle); + + memset(&sun, 0, sizeof sun); + sock = _socket(AF_LOCAL, SOCK_STREAM, 0); + if (sock < 0) + return (FALSE); + sun.sun_family = AF_LOCAL; + strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path)); + sun.sun_len = SUN_LEN(&sun); + + if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) { + _close(sock); + return (FALSE); + } + + _close(sock); + return (TRUE); +} + +/* * An internal function which optimizes rpcb_getaddr function. It also * returns the client handle that it uses to contact the remote rpcbind. * @@ -649,13 +708,15 @@ * starts working properly. Also look under clnt_vc.c. */ struct netbuf * -__rpcb_findaddr(program, version, nconf, host, clpp) +__rpcb_findaddr_timed(program, version, nconf, host, clpp, tp) rpcprog_t program; rpcvers_t version; const struct netconfig *nconf; const char *host; CLIENT **clpp; + struct timeval *tp; { + static bool_t check_rpcbind = TRUE; CLIENT *client = NULL; RPCB parms; enum clnt_stat clnt_st; @@ -673,6 +734,12 @@ parms.r_addr = NULL; + /* + * Use default total timeout if no timeout is specified. + */ + if (tp == NULL) + tp = &tottimeout; + #ifdef PORTMAP /* Try version 2 for TCP or UDP */ if (strcmp(nconf->nc_protofmly, NC_INET) == 0) { @@ -687,22 +754,31 @@ */ if (strcmp(nconf->nc_proto, NC_TCP) == 0) { struct netconfig *newnconf; + void *handle; - if ((newnconf = getnetconfigent("udp")) == NULL) { + if ((handle = getnetconfigent("udp")) == NULL) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return (NULL); + } + if ((newnconf = __rpc_getconf(handle)) == NULL) { + __rpc_endconf(handle); rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; return (NULL); } client = getclnthandle(host, newnconf, &parms.r_addr); - freenetconfigent(newnconf); + __rpc_endconf(handle); } else { client = getclnthandle(host, nconf, &parms.r_addr); } - if (client == NULL) { + if (client == NULL) return (NULL); - } - /* Set the version */ - CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&pmapvers); + /* + * Set version and retry timeout. + */ + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); + CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers); + pmapparms.pm_prog = program; pmapparms.pm_vers = version; pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ? @@ -711,7 +787,7 @@ clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, (xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms, (xdrproc_t) xdr_u_short, (caddr_t)(void *)&port, - tottimeout); + *tp); if (clnt_st != RPC_SUCCESS) { if ((clnt_st == RPC_PROGVERSMISMATCH) || (clnt_st == RPC_PROGUNAVAIL)) @@ -725,7 +801,7 @@ goto error; } port = htons(port); - CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)(void *)&remote); + CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote); if (((address = (struct netbuf *) malloc(sizeof (struct netbuf))) == NULL) || ((address->buf = (char *) @@ -748,6 +824,20 @@ try_rpcbind: /* + * Check if rpcbind is up. This prevents needless delays when + * accessing applications such as the keyserver while booting + * disklessly. + */ + if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) { + if (!__rpcbind_is_up()) { + rpc_createerr.cf_stat = RPC_PMAPFAILURE; + rpc_createerr.cf_error.re_errno = 0; + goto error; + } + check_rpcbind = FALSE; + } + + /* * Now we try version 4 and then 3. * We also send the remote system the address we used to * contact it in case it can help to connect back with us @@ -762,33 +852,17 @@ /* * If a COTS transport is being used, try getting address via CLTS * transport. This works only with version 4. - * NOTE: This is being done for all transports EXCEPT LOOPBACK - * because with loopback the cost to go to a COTS is same as - * the cost to go through CLTS, plus you get the advantage of - * finding out immediately if the local rpcbind process is dead. */ -#if 1 - if ((nconf->nc_semantics == NC_TPI_COTS_ORD || - nconf->nc_semantics == NC_TPI_COTS) && - (strcmp(nconf->nc_protofmly, NC_LOOPBACK) != 0)) { -#else - if (client != NULL) { - CLNT_DESTROY(client); - client = NULL; - } - if (nconf->nc_semantics == NC_TPI_CLTS) { -#endif + if (nconf->nc_semantics == NC_TPI_COTS_ORD || + nconf->nc_semantics == NC_TPI_COTS) { + void *handle; struct netconfig *nconf_clts; rpcb_entry_list_ptr relp = NULL; if (client == NULL) { /* This did not go through the above PORTMAP/TCP code */ -#if 1 if ((handle = __rpc_setconf("datagram_v")) != NULL) { -#else - if ((handle = __rpc_setconf("circuit_v")) != NULL) { -#endif while ((nconf_clts = __rpc_getconf(handle)) != NULL) { if (strcmp(nconf_clts->nc_protofmly, @@ -816,10 +890,13 @@ /*LINTED const castaway*/ parms.r_addr = (char *) &nullstring[0]; /* for XDRing */ } + + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime); + clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, (xdrproc_t) xdr_rpcb_entry_list_ptr, - (char *)(void *)&relp, tottimeout); + (char *)(void *)&relp, *tp); if (clnt_st == RPC_SUCCESS) { if ((address = got_entry(relp, nconf)) != NULL) { xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr, @@ -850,12 +927,8 @@ regular_rpcbind: /* Now the same transport is to be used to get the address */ -#if 1 if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) || (nconf->nc_semantics == NC_TPI_COTS))) { -#else - if (client && nconf->nc_semantics == NC_TPI_CLTS) { -#endif /* A CLTS type of client - destroy it */ CLNT_DESTROY(client); client = NULL; @@ -873,13 +946,14 @@ } /* First try from start_vers and then version 3 (RPCBVERS) */ + + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime); for (vers = start_vers; vers >= RPCBVERS; vers--) { /* Set the version */ CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers); clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, (xdrproc_t) xdr_rpcb, (char *)(void *)&parms, - (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, - tottimeout); + (xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp); if (clnt_st == RPC_SUCCESS) { if ((ua == NULL) || (ua[0] == NULL)) { /* address unknown */ @@ -966,8 +1040,9 @@ { struct netbuf *na; - if ((na = __rpcb_findaddr(program, version, nconf, - host, (CLIENT **) NULL)) == NULL) + if ((na = __rpcb_findaddr_timed(program, version, + (struct netconfig *) nconf, (char *) host, + (CLIENT **) NULL, (struct timeval *) NULL)) == NULL) return (FALSE); if (na->len > address->maxlen) { To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message