<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">diff -Nur autofs-4.1.3.orig/lib/rpc_subs.c autofs-4.1.3/lib/rpc_subs.c
--- autofs-4.1.3.orig/lib/rpc_subs.c	2004-06-14 21:55:29.000000000 +0800
+++ autofs-4.1.3/lib/rpc_subs.c	2004-06-14 21:54:35.000000000 +0800
@@ -1,38 +1,284 @@
+/* ----------------------------------------------------------------------- *
+ *   
+ *  rpc_subs.c - routines for rpc discovery
+ *
+ *   Copyright 2004 Ian Kent &lt;raven@themaw.net&gt; - All Rights Reserved
+ *   Copyright 2004 Jeff Moyer &lt;jmoyer@redaht.com&gt; - All Rights Reserved
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ *   USA; either version 2 of the License, or (at your option) any later
+ *   version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
 #include &lt;rpc/rpc.h&gt;
+#include &lt;rpc/pmap_prot.h&gt;
 #include &lt;nfs/nfs.h&gt;
 #include &lt;linux/nfs2.h&gt;
 #include &lt;linux/nfs3.h&gt;
 #include &lt;rpc/xdr.h&gt;
- 
+
+#include &lt;unistd.h&gt;
+#include &lt;sys/socket.h&gt;
+#include &lt;netdb.h&gt;
+#include &lt;netinet/in.h&gt;
+#include &lt;sys/fcntl.h&gt;
+#include &lt;errno.h&gt;
+
 #include "automount.h"
 
+#define PMAP_TOUT_UDP	2
+#define PMAP_TOUT_TCP	3
+
+struct conn_info {
+	const char *host;
+	unsigned short port;
+	unsigned long program;
+	unsigned long version;
+	struct protoent *proto;
+	unsigned int send_sz;
+	unsigned int recv_sz;
+	struct timeval timeout;
+};
+
+/*
+ * Create a UDP RPC client
+ */
+static CLIENT* create_udp_client(struct conn_info *info)
+{
+	int fd = -1;
+	CLIENT *client;
+	struct sockaddr_in addr;
+	struct hostent *hp;
+
+	if (info-&gt;proto-&gt;p_proto != IPPROTO_UDP)
+		return NULL;
+
+	memset(&amp;addr, 0, sizeof(addr));
+
+	hp = gethostbyname(info-&gt;host);
+	if (!hp)
+		return NULL;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(info-&gt;port);
+	memcpy(&amp;addr.sin_addr.s_addr, hp-&gt;h_addr, hp-&gt;h_length);
+
+	client = clntudp_bufcreate(&amp;addr,
+				   info-&gt;program, info-&gt;version,
+				   info-&gt;timeout, &amp;fd,
+				   info-&gt;send_sz, info-&gt;recv_sz);
+
+	return client;
+}
+
+/*
+ *  Perform a non-blocking connect on the socket fd.
+ *
+ *  tout contains the timeout.  It will be modified to contain the time
+ *  remaining (i.e. time provided - time elasped).
+ */
+static int connect_nb(int fd, struct sockaddr_in *addr, struct timeval *tout)
+{
+	int flags, ret, len;
+	fd_set wset, rset;
+
+	flags = fcntl(fd, F_GETFL, 0);
+	if (flags &lt; 0)
+		return -1;
+
+	ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+	if (ret &lt; 0)
+		return -1;
+
+	/* 
+	 * From here on subsequent sys calls could change errno so
+	 * we set ret = -errno to capture it in case we decide to
+	 * use it later.
+	 */
+	ret = connect(fd, (struct sockaddr *)addr, sizeof(struct sockaddr));
+	if (ret &lt; 0 &amp;&amp; errno != EINPROGRESS) {
+		ret = -errno;
+		goto done;
+	}
+
+	if (ret == 0)
+		goto done;
+
+	/* now wait */
+	FD_ZERO(&amp;rset);
+	FD_SET(fd, &amp;rset);
+	wset = rset;
+
+	ret = select(fd + 1, &amp;rset, &amp;wset, NULL, tout);
+	if (ret &lt;= 0) {
+		if (ret == 0)
+			ret = -ETIMEDOUT;
+		else
+			ret = -errno;
+		goto done;
+	}
+
+	if (FD_ISSET(fd, &amp;rset) || FD_ISSET(fd, &amp;wset)) {
+		int stat;
+
+		len = sizeof(ret);
+		stat = getsockopt(fd, SOL_SOCKET, SO_ERROR, &amp;ret, &amp;len);
+		if (stat &lt; 0) {
+			ret = -errno;
+			goto done;
+		}
+
+		/* Oops - something wrong with connect */
+		if (ret)
+			ret = -ret;
+	}
+
+done:
+	fcntl(fd, F_SETFL, flags);
+	return ret;
+}
+
+/*
+ * Create a TCP RPC client using non-blocking connect
+ */
+static CLIENT* create_tcp_client(struct conn_info *info)
+{
+	int fd;
+	CLIENT *client;
+	struct sockaddr_in addr;
+	struct hostent *hp;
+	int ret;
+
+	if (info-&gt;proto-&gt;p_proto != IPPROTO_TCP)
+		return NULL;
+
+	memset(&amp;addr, 0, sizeof(addr));
+
+	hp = gethostbyname(info-&gt;host);
+	if (!hp)
+		return NULL;
+
+	addr.sin_family = AF_INET;
+	addr.sin_port = htons(info-&gt;port);
+	memcpy(&amp;addr.sin_addr.s_addr, hp-&gt;h_addr, hp-&gt;h_length);
+
+	fd = socket(PF_INET, SOCK_STREAM, info-&gt;proto-&gt;p_proto);
+	if (fd &lt; 0)
+		return NULL;
+
+	ret = connect_nb(fd, &amp;addr, &amp;info-&gt;timeout);
+	if (ret &lt; 0)
+		goto out_close;
+
+	client = clnttcp_create(&amp;addr,
+				info-&gt;program, info-&gt;version, &amp;fd,
+				info-&gt;send_sz, info-&gt;recv_sz);
+	if (!client)
+		goto out_close;
+
+	return client;
+
+out_close:
+	close(fd);
+	return NULL;
+}
+
+static unsigned short portmap_getport(struct conn_info *info)
+{
+	struct conn_info pmap_info;
+	unsigned short port = 0;
+	CLIENT *client;
+	enum clnt_stat stat;
+	struct pmap parms;
+
+	pmap_info.host = info-&gt;host;
+	pmap_info.port = PMAPPORT;
+	pmap_info.program = PMAPPROG;
+	pmap_info.version = PMAPVERS;
+	pmap_info.proto = info-&gt;proto;
+	pmap_info.send_sz = RPCSMALLMSGSIZE;
+	pmap_info.recv_sz = RPCSMALLMSGSIZE;
+	pmap_info.timeout.tv_sec = PMAP_TOUT_UDP;
+	pmap_info.timeout.tv_usec = 0;
+
+	if (info-&gt;proto-&gt;p_proto == IPPROTO_TCP) {
+		pmap_info.timeout.tv_sec = PMAP_TOUT_TCP;
+		client = create_tcp_client(&amp;pmap_info);
+	} else
+		client = create_udp_client(&amp;pmap_info);
+
+	if (!client)
+		return 0;
+	
+	parms.pm_prog = info-&gt;program;
+	parms.pm_vers = info-&gt;version;
+	parms.pm_prot = info-&gt;proto-&gt;p_proto;
+	parms.pm_port = 0;
+
+	stat = clnt_call(client, PMAPPROC_GETPORT,
+			 (xdrproc_t) xdr_pmap, (caddr_t) &amp;parms,
+			 (xdrproc_t) xdr_u_short, (caddr_t) &amp;port,
+			 pmap_info.timeout);
+
+	clnt_destroy(client);
+
+	if (stat != RPC_SUCCESS)
+		return 0;
+
+	return port;
+}
+
 static int rpc_ping_proto(const char *host,
-			  unsigned long nfs_version, const char *proto,
+			  unsigned long nfs_version,
+			  const char *proto,
 			  long seconds, long micros)
 {
+	struct conn_info info;
 	CLIENT *client;
-	struct timeval tout;
 	enum clnt_stat stat;
+	struct protoent *prot;
+
+	prot = getprotobyname(proto);
+	if (!prot)
+		return 1;
+
+	info.host = host;
+	info.program = NFS_PROGRAM;
+	info.version = nfs_version;
+	info.proto = prot;
+	info.send_sz = 0;
+	info.recv_sz = 0;
+	info.timeout.tv_sec = seconds;
+	info.timeout.tv_usec = micros;
 
-	client = clnt_create(host, NFS_PROGRAM, nfs_version, proto);
-	if (client == NULL) {
+	info.port = portmap_getport(&amp;info);
+	if (!info.port)
 		return 0;
-	}
 
-	tout.tv_sec = seconds;
-	tout.tv_usec = micros;
+	if (prot-&gt;p_proto == IPPROTO_UDP) {
+		info.send_sz = UDPMSGSIZE;
+		info.recv_sz = UDPMSGSIZE;
+		client = create_udp_client(&amp;info);
+	} else
+		client = create_tcp_client(&amp;info);
+
+	if (!client)
+		return 0;
 
-	clnt_control(client, CLSET_TIMEOUT, (char *)&amp;tout);
-	clnt_control(client, CLSET_RETRY_TIMEOUT, (char *)&amp;tout);
+	clnt_control(client, CLSET_TIMEOUT, (char *) &amp;info.timeout);
+	clnt_control(client, CLSET_RETRY_TIMEOUT, (char *) &amp;info.timeout);
 
 	stat = clnt_call(client, NFSPROC_NULL,
-			 (xdrproc_t)xdr_void, 0, (xdrproc_t)xdr_void, 0, tout);
+			 (xdrproc_t) xdr_void, 0, (xdrproc_t) xdr_void, 0,
+			 info.timeout);
 
 	clnt_destroy(client);
 
-	if (stat != RPC_SUCCESS) {
+	if (stat != RPC_SUCCESS)
 		return 0;
-	}
 
 	return 1;
 }
@@ -108,10 +354,39 @@
 
 	taken = elapsed(start, end);
 
-	if (result != NULL) {
+	if (result != NULL)
 		*result = taken;
-	}
 
 	return status;
 }
 
+#if 0
+#include &lt;stdio.h&gt;
+
+int main(int argc, char **argv)
+{
+	int ret;
+	double res = 0.0;
+
+	ret = rpc_ping("budgie", 10, 0);
+	printf("ret = %d\n", ret);
+
+	res = 0.0;
+	ret = rpc_time("raven", NFS2_VERSION, RPC_PING_TCP, 10, 0, &amp;res);
+	printf("v2 tcp ret = %d, res = %f\n", ret, res);
+
+	res = 0.0;
+	ret = rpc_time("raven", NFS3_VERSION, RPC_PING_TCP, 10, 0, &amp;res);
+	printf("v3 tcp ret = %d, res = %f\n", ret, res);
+
+	res = 0.0;
+	ret = rpc_time("raven", NFS2_VERSION, RPC_PING_UDP, 10, 0, &amp;res);
+	printf("v2 udp ret = %d, res = %f\n", ret, res);
+
+	res = 0.0;
+	ret = rpc_time("raven", NFS3_VERSION, RPC_PING_UDP, 10, 0, &amp;res);
+	printf("v3 udp ret = %d, res = %f\n", ret, res);
+
+	exit(0);
+}
+#endif
</pre></body></html>