Ian Kent 48c41b
autofs-5.0.5 - fix rpc fail on large export list
Ian Kent 48c41b
Ian Kent 48c41b
From: Ian Kent <raven@themaw.net>
Ian Kent 48c41b
Ian Kent 48c41b
If the export list on a server is larger than the UDP transport packet
Ian Kent 48c41b
size the transfer will fail and autofs will try TCP instead, but there
Ian Kent 48c41b
were some problems with the conversion to allow for IPv6 using libtirpc.
Ian Kent 48c41b
Ian Kent 48c41b
When creating the local socket for an RPC connection we incorrectly
Ian Kent 48c41b
performed a connect instead of a bind to the ilocal TCP socket. Aslo the
Ian Kent 48c41b
timed connect, which should be done before creating the RPC client was
Ian Kent 48c41b
not being done, which can lead to lengthy timeouts.
Ian Kent 48c41b
---
Ian Kent 48c41b
Ian Kent 48c41b
 CHANGELOG      |    1 +
Ian Kent 48c41b
 lib/rpc_subs.c |   47 ++++++++++++++++++++++++-----------------------
Ian Kent 48c41b
 2 files changed, 25 insertions(+), 23 deletions(-)
Ian Kent 48c41b
Ian Kent 48c41b
Ian Kent 48c41b
diff --git a/CHANGELOG b/CHANGELOG
Ian Kent 48c41b
index 88bcc1b..20566a6 100644
Ian Kent 48c41b
--- a/CHANGELOG
Ian Kent 48c41b
+++ b/CHANGELOG
Ian Kent 48c41b
@@ -15,6 +15,7 @@
Ian Kent 48c41b
 - fix pidof init script usage.
Ian Kent 48c41b
 - check for path mount location in generic module.
Ian Kent 48c41b
 - dont fail mount on access fail.
Ian Kent 48c41b
+- fix rpc fail on large export list.
Ian Kent 48c41b
 
Ian Kent 48c41b
 03/09/2009 autofs-5.0.5
Ian Kent 48c41b
 -----------------------
Ian Kent 48c41b
diff --git a/lib/rpc_subs.c b/lib/rpc_subs.c
Ian Kent 48c41b
index 628f0fc..3b11dce 100644
Ian Kent 48c41b
--- a/lib/rpc_subs.c
Ian Kent 48c41b
+++ b/lib/rpc_subs.c
Ian Kent 48c41b
@@ -53,6 +53,7 @@
Ian Kent 48c41b
 /* Get numeric value of the n bits starting at position p */
Ian Kent 48c41b
 #define getbits(x, p, n)      ((x >> (p + 1 - n)) & ~(~0 << n))
Ian Kent 48c41b
 
Ian Kent 48c41b
+static int connect_nb(int, struct sockaddr *, socklen_t, struct timeval *);
Ian Kent 48c41b
 inline void dump_core(void);
Ian Kent 48c41b
 
Ian Kent 48c41b
 static CLIENT *rpc_clntudp_create(struct sockaddr *addr, struct conn_info *info, int *fd)
Ian Kent 48c41b
@@ -97,11 +98,17 @@ static CLIENT *rpc_clnttcp_create(struct sockaddr *addr, struct conn_info *info,
Ian Kent 48c41b
 	struct sockaddr_in *in4_raddr;
Ian Kent 48c41b
 	struct sockaddr_in6 *in6_raddr;
Ian Kent 48c41b
 	CLIENT *client = NULL;
Ian Kent 48c41b
+	socklen_t slen;
Ian Kent 48c41b
 
Ian Kent 48c41b
 	switch (addr->sa_family) {
Ian Kent 48c41b
 	case AF_INET:
Ian Kent 48c41b
 		in4_raddr = (struct sockaddr_in *) addr;
Ian Kent 48c41b
 		in4_raddr->sin_port = htons(info->port);
Ian Kent 48c41b
+		slen = sizeof(struct sockaddr_in);
Ian Kent 48c41b
+
Ian Kent 48c41b
+		if (connect_nb(*fd, addr, slen, &info->timeout) < 0)
Ian Kent 48c41b
+			break;
Ian Kent 48c41b
+
Ian Kent 48c41b
 		client = clnttcp_create(in4_raddr,
Ian Kent 48c41b
 					info->program, info->version, fd,
Ian Kent 48c41b
 					info->send_sz, info->recv_sz);
Ian Kent 48c41b
@@ -114,6 +121,11 @@ static CLIENT *rpc_clnttcp_create(struct sockaddr *addr, struct conn_info *info,
Ian Kent 48c41b
 #else
Ian Kent 48c41b
 		in6_raddr = (struct sockaddr_in6 *) addr;
Ian Kent 48c41b
 		in6_raddr->sin6_port = htons(info->port);
Ian Kent 48c41b
+		slen = sizeof(struct sockaddr_in6);
Ian Kent 48c41b
+
Ian Kent 48c41b
+		if (connect_nb(*fd, addr, slen, &info->timeout) < 0)
Ian Kent 48c41b
+			break;
Ian Kent 48c41b
+
Ian Kent 48c41b
 		client = clnttcp6_create(in6_raddr,
Ian Kent 48c41b
 					 info->program, info->version, fd,
Ian Kent 48c41b
 					 info->send_sz, info->recv_sz);
Ian Kent 48c41b
@@ -260,32 +272,21 @@ static CLIENT *rpc_do_create_client(struct sockaddr *addr, struct conn_info *inf
Ian Kent 48c41b
 		return NULL;
Ian Kent 48c41b
 	}
Ian Kent 48c41b
 
Ian Kent 48c41b
+	if (!info->client) {
Ian Kent 48c41b
+		*fd = open_sock(addr->sa_family, type, proto);
Ian Kent 48c41b
+		if (*fd < 0)
Ian Kent 48c41b
+			return NULL;
Ian Kent 48c41b
+
Ian Kent 48c41b
+		if (bind(*fd, laddr, slen) < 0)
Ian Kent 48c41b
+			return NULL;
Ian Kent 48c41b
+	}
Ian Kent 48c41b
+
Ian Kent 48c41b
 	switch (info->proto->p_proto) {
Ian Kent 48c41b
 	case IPPROTO_UDP:
Ian Kent 48c41b
-		if (!info->client) {
Ian Kent 48c41b
-			*fd = open_sock(addr->sa_family, type, proto);
Ian Kent 48c41b
-			if (*fd < 0)
Ian Kent 48c41b
-				return NULL;
Ian Kent 48c41b
-
Ian Kent 48c41b
-			if (bind(*fd, laddr, slen) < 0) {
Ian Kent 48c41b
-				close(*fd);
Ian Kent 48c41b
-				return NULL;
Ian Kent 48c41b
-			}
Ian Kent 48c41b
-		}
Ian Kent 48c41b
 		client = rpc_clntudp_create(addr, info, fd);
Ian Kent 48c41b
 		break;
Ian Kent 48c41b
 
Ian Kent 48c41b
 	case IPPROTO_TCP:
Ian Kent 48c41b
-		if (!info->client) {
Ian Kent 48c41b
-			*fd = open_sock(addr->sa_family, type, proto);
Ian Kent 48c41b
-			if (*fd < 0)
Ian Kent 48c41b
-				return NULL;
Ian Kent 48c41b
-
Ian Kent 48c41b
-			if (connect_nb(*fd, laddr, slen, &info->timeout) < 0) {
Ian Kent 48c41b
-				close(*fd);
Ian Kent 48c41b
-				return NULL;
Ian Kent 48c41b
-			}
Ian Kent 48c41b
-		}
Ian Kent 48c41b
 		client = rpc_clnttcp_create(addr, info, fd);
Ian Kent 48c41b
 		break;
Ian Kent 48c41b
 
Ian Kent 48c41b
@@ -327,7 +328,7 @@ static CLIENT *create_udp_client(struct conn_info *info)
Ian Kent 48c41b
 		if (client)
Ian Kent 48c41b
 			goto done;
Ian Kent 48c41b
 
Ian Kent 48c41b
-		if (!info->client) {
Ian Kent 48c41b
+		if (!info->client && fd != RPC_ANYSOCK) {
Ian Kent 48c41b
 			close(fd);
Ian Kent 48c41b
 			fd = RPC_ANYSOCK;
Ian Kent 48c41b
 		}
Ian Kent 48c41b
@@ -352,7 +353,7 @@ static CLIENT *create_udp_client(struct conn_info *info)
Ian Kent 48c41b
 		if (client)
Ian Kent 48c41b
 			break;
Ian Kent 48c41b
 
Ian Kent 48c41b
-		if (!info->client) {
Ian Kent 48c41b
+		if (!info->client && fd != RPC_ANYSOCK) {
Ian Kent 48c41b
 			close(fd);
Ian Kent 48c41b
 			fd = RPC_ANYSOCK;
Ian Kent 48c41b
 		}
Ian Kent 48c41b
@@ -477,7 +478,7 @@ static CLIENT *create_tcp_client(struct conn_info *info)
Ian Kent 48c41b
 		if (client)
Ian Kent 48c41b
 			break;
Ian Kent 48c41b
 
Ian Kent 48c41b
-		if (!info->client) {
Ian Kent 48c41b
+		if (!info->client && fd != RPC_ANYSOCK) {
Ian Kent 48c41b
 			close(fd);
Ian Kent 48c41b
 			fd = RPC_ANYSOCK;
Ian Kent 48c41b
 		}