Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 6 Oct 2001 17:30:02 -0700 (PDT)
From:      Martin Blapp <mb@imp.ch>
To:        freebsd-bugs@FreeBSD.org
Subject:   Re: bin/29177: [PATCH] rpc client create functions with additional timeout
Message-ID:  <200110070030.f970U2U29332@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR bin/29177; it has been noted by GNATS.

From: Martin Blapp <mb@imp.ch>
To: <freebsd-gnats-submit@FreeBSD.org>
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 <sys/types.h>
 +#include <sys/fcntl.h>
  #include <sys/socket.h>
  #include <netinet/in.h>
  #include <netinet/tcp.h>
  #include <stdio.h>
  #include <errno.h>
  #include <netdb.h>
 +#include <syslog.h>
  #include <rpc/rpc.h>
  #include <rpc/nettype.h>
  #include <string.h>
 @@ -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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200110070030.f970U2U29332>