summaryrefslogtreecommitdiffstats
path: root/lib/libc/rpc/rpcb_clnt.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/rpc/rpcb_clnt.c')
-rw-r--r--lib/libc/rpc/rpcb_clnt.c149
1 files changed, 112 insertions, 37 deletions
diff --git a/lib/libc/rpc/rpcb_clnt.c b/lib/libc/rpc/rpcb_clnt.c
index c4db751..b47f36b 100644
--- a/lib/libc/rpc/rpcb_clnt.c
+++ b/lib/libc/rpc/rpcb_clnt.c
@@ -1,6 +1,23 @@
/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun 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
@@ -75,6 +92,7 @@ __FBSDID("$FreeBSD$");
static struct timeval tottimeout = { 60, 0 };
static const struct timeval rmttimeout = { 3, 0 };
+static struct timeval rpcbrmttime = { 15, 0 };
extern bool_t xdr_wrapstring(XDR *, char **);
@@ -654,6 +672,47 @@ got_entry(relp, nconf)
}
/*
+ * 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.
*
@@ -672,13 +731,15 @@ got_entry(relp, nconf)
* 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;
@@ -696,6 +757,12 @@ __rpcb_findaddr(program, version, nconf, host, clpp)
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) {
@@ -710,22 +777,31 @@ __rpcb_findaddr(program, version, nconf, host, clpp)
*/
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) ?
@@ -734,7 +810,7 @@ __rpcb_findaddr(program, version, nconf, host, clpp)
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))
@@ -748,7 +824,7 @@ __rpcb_findaddr(program, version, nconf, host, clpp)
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 *)
@@ -771,6 +847,20 @@ __rpcb_findaddr(program, version, nconf, host, clpp)
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
@@ -785,33 +875,17 @@ try_rpcbind:
/*
* 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,
@@ -839,10 +913,13 @@ try_rpcbind:
/*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,
@@ -873,12 +950,8 @@ try_rpcbind:
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;
@@ -896,13 +969,14 @@ regular_rpcbind:
}
/* 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 */
@@ -989,8 +1063,9 @@ rpcb_getaddr(program, version, nconf, address, host)
{
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) {
OpenPOWER on IntegriCloud