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>
