File 0008-First-part-of-init_transport-refactoring.patch of Package rpcbind

From 5388d9b484838437c364aed925f3f6acb021264d Mon Sep 17 00:00:00 2001
From: Olaf Kirch <okir@suse.de>
Date: Tue, 20 Aug 2013 09:26:37 +0200
Subject: [PATCH 08/24] First part of init_transport refactoring

This patch splits out the hostname resolution and socket creation/binding
code into individual functions, and calls those from init_transport instead.

Signed-off-by: Olaf Kirch <okir@suse.de>
---
 src/rpcbind.c | 407 +++++++++++++++++++++++++++++-----------------------------
 1 file changed, 201 insertions(+), 206 deletions(-)

diff --git a/src/rpcbind.c b/src/rpcbind.c
index 896d509..a7dcc0e 100644
--- a/src/rpcbind.c
+++ b/src/rpcbind.c
@@ -268,6 +268,186 @@ main(int argc, char *argv[])
 }
 
 /*
+ * Helper function - maybe this should go elsewhere
+ */
+static void
+sockaddr2netbuf(const struct sockaddr *sa, socklen_t alen, struct netbuf *abuf)
+{
+	abuf->len = abuf->maxlen = alen;
+	abuf->buf = malloc(alen);
+
+	if (abuf->buf == NULL) {
+		syslog(LOG_ERR, "not enough memory for address buffer (%u bytes)", alen);
+		exit(1);
+	}
+
+	memcpy(abuf->buf, sa, alen);
+}
+
+/*
+ * Perform hostname lookup
+ */
+static int
+do_hostname_lookup(struct netconfig *nconf, const char *hostname, struct netbuf *abuf)
+{
+	struct addrinfo hints, *res = NULL;
+	struct __rpc_sockinfo si;
+	int aicode;
+
+	if (!__rpc_nconf2sockinfo(nconf, &si)) {
+		syslog(LOG_ERR, "cannot get sockinfo for %s", nconf->nc_netid);
+		return -1;
+	}
+
+	memset(&hints, 0, sizeof hints);
+	hints.ai_flags = AI_PASSIVE;
+	hints.ai_family = si.si_af;
+	hints.ai_socktype = si.si_socktype;
+	hints.ai_protocol = si.si_proto;
+
+	if (hostname == NULL) {
+		/*
+		 * If no hosts were specified, just bind to INADDR_ANY
+		 */
+	} else {
+		u_int32_t host_addr[4];  /* IPv4 or IPv6 */
+
+		switch (hints.ai_family) {
+		case AF_INET:
+			if (inet_pton(AF_INET, hostname, host_addr) == 1)
+				hints.ai_flags |= AI_NUMERICHOST;
+			else if (inet_pton(AF_INET6, hostname, host_addr) == 1)
+				return 0;
+			break;
+
+		case AF_INET6:
+			if (inet_pton(AF_INET6, hostname, host_addr) == 1)
+				hints.ai_flags |= AI_NUMERICHOST;
+			else if (inet_pton(AF_INET, hostname, host_addr) == 1)
+				return 0;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	if ((aicode = getaddrinfo(hostname, servname, &hints, &res)) != 0) {
+		if ((aicode = getaddrinfo(hostname, "portmapper", &hints, &res)) != 0) {
+			syslog(LOG_ERR,
+			    "cannot get %s address for %s: %s",
+			    nconf->nc_netid,
+			    hostname? hostname : "*",
+			    gai_strerror(aicode));
+			return 0;
+		}
+	}
+
+	/* XXX: should we loop over all addresses returned? */
+	sockaddr2netbuf(res->ai_addr, res->ai_addrlen, abuf);
+	freeaddrinfo(res);
+	return 1;
+}
+
+static void
+build_local_addr(const char *path, struct netbuf *abuf)
+{
+	struct sockaddr_un sun;
+
+	memset(&sun, 0, sizeof sun);
+	sun.sun_family = AF_LOCAL;
+	strcpy(sun.sun_path, path);
+
+	sockaddr2netbuf((struct sockaddr *) &sun, SUN_LEN(&sun), abuf);
+}
+
+/*
+ * Create a bound socket
+ *
+ * Return values:
+ *   -1 means error or problem with this netconfig entry.
+ */
+static int
+create_transport_socket(struct netconfig *nconf, const char *hostname, struct netbuf *abuf, int *fdret)
+{
+	int fd = -1;
+	int r;
+	mode_t oldmask;
+
+	*fdret = -1;
+
+	if (strcmp(nconf->nc_netid, "local") == 0 || strcmp(nconf->nc_netid, "unix") == 0) {
+		unlink(_PATH_RPCBINDSOCK);
+		build_local_addr(_PATH_RPCBINDSOCK, abuf);
+	} else {
+		r = do_hostname_lookup(nconf, hostname, abuf);
+		if (r <= 0)
+			return r;
+	}
+
+	/*
+	 * XXX - using RPC library internal functions.
+	 */
+	if ((fd = __rpc_nconf2fd(nconf)) < 0) {
+		syslog(LOG_ERR, "cannot create socket for %s", nconf->nc_netid);
+		return -1;
+	}
+
+	if (nconf->nc_semantics != NC_TPI_CLTS) {
+		int on = 1;
+
+		/* For connection oriented sockets, always set REUSEADDR.
+		 * This allows us to restart the server even if there are
+		 * TCP sockets loitering around in TIME_WAIT */
+		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) != 0) {
+			syslog(LOG_ERR, "cannot set SO_REUSEADDR on %s", nconf->nc_netid);
+			return -1;
+		}
+	}
+
+	oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
+	if (bind(fd, (struct sockaddr *) abuf->buf, abuf->len) != 0) {
+		syslog(LOG_ERR, "cannot bind %s on %s: %m",
+			hostname? hostname : "*",
+			nconf->nc_netid);
+		(void) umask(oldmask);
+		goto skip;
+	}
+	(void) umask(oldmask);
+
+	if (nconf->nc_semantics != NC_TPI_CLTS) {
+		if (listen(fd, SOMAXCONN) < 0) {
+			syslog(LOG_ERR, "unable to listen on %s socket: %m",
+					nconf->nc_netid);
+			return -1;
+		}
+	}
+
+
+#ifdef RPCBIND_DEBUG
+	if (debugging) {
+		/*
+		 * for debugging print out our universal
+		 * address
+		 */
+		char *uaddr;
+
+		uaddr = taddr2uaddr(nconf, abuf);
+		(void) fprintf(stderr, "rpcbind : my %s address is %s\n", nconf->nc_netid, uaddr);
+		(void) free(uaddr);
+	}
+#endif
+
+	*fdret = fd;
+	return 1;
+
+skip:
+	if (fd >= 0)
+		close(fd);
+	return 0;
+}
+
+/*
  * Adds the entry into the rpcbind database.
  * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
  * Returns 0 if succeeds, else fails
@@ -277,20 +457,9 @@ init_transport(struct netconfig *nconf)
 {
 	int fd = -1;
 	struct t_bind taddr;
-	struct addrinfo hints, *res;
 	struct __rpc_sockinfo si;
 	SVCXPRT	*my_xprt = NULL;
 	int status;	/* bound checking ? */
-	int aicode;
-	int addrlen = 0;
-	int nhostsbak;
-	int checkbind;
-	int on = 1;
-	struct sockaddr *sa = NULL;
-	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
-	struct sockaddr_un sun;
-	mode_t oldmask;
-        res = NULL;
 
 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
 		(nconf->nc_semantics != NC_TPI_COTS) &&
@@ -315,24 +484,10 @@ init_transport(struct netconfig *nconf)
 		return (1);
 	}
 
-	if ((strcmp(nconf->nc_netid, "local") == 0) ||
-	    (strcmp(nconf->nc_netid, "unix") == 0)) {
-		memset(&sun, 0, sizeof sun);
-		sun.sun_family = AF_LOCAL;
-		unlink(_PATH_RPCBINDSOCK);
-		strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
-		addrlen = SUN_LEN(&sun);
-		sa = (struct sockaddr *)&sun;
-	} else {
-		/* Get rpcbind's address on this transport */
-
-		memset(&hints, 0, sizeof hints);
-		hints.ai_flags = AI_PASSIVE;
-		hints.ai_family = si.si_af;
-		hints.ai_socktype = si.si_socktype;
-		hints.ai_protocol = si.si_proto;
-	}
 	if (nconf->nc_semantics == NC_TPI_CLTS) {
+		int nhostsbak;
+		int checkbind;
+
 		/*
 		 * If no hosts were specified, just bind to INADDR_ANY.  Otherwise
 		 * make sure 127.0.0.1 is added to the list.
@@ -343,9 +498,9 @@ init_transport(struct netconfig *nconf)
 		if (nhostsbak == 1)
 			hosts[0] = "*";
 		else {
-			if (hints.ai_family == AF_INET) {
+			if (si.si_af == AF_INET) {
 				hosts[nhostsbak - 1] = "127.0.0.1";
-			} else if (hints.ai_family == AF_INET6) {
+			} else if (si.si_af == AF_INET6) {
 				hosts[nhostsbak - 1] = "::1";
 			} else
 				return 1;
@@ -356,47 +511,9 @@ init_transport(struct netconfig *nconf)
 		*/
 		checkbind = 0;
 		while (nhostsbak > 0) {
-			--nhostsbak;
-			/*
-			 * XXX - using RPC library internal functions.
-			 */
-			if ((fd = __rpc_nconf2fd(nconf)) < 0) {
-				syslog(LOG_ERR, "cannot create socket for %s",
-				    nconf->nc_netid);
-				return (1);
-			}
+			int r;
 
-			hints.ai_flags &= ~AI_NUMERICHOST;
-			switch (hints.ai_family) {
-			case AF_INET:
-				if (inet_pton(AF_INET, hosts[nhostsbak],
-				    host_addr) == 1) {
-					hints.ai_flags |= AI_NUMERICHOST;
-				} else {
-					/*
-					 * Skip if we have an AF_INET6 adress.
-					 */
-					if (inet_pton(AF_INET6,
-					    hosts[nhostsbak], host_addr) == 1)
-						continue;
-				}
-				break;
-			case AF_INET6:
-				if (inet_pton(AF_INET6, hosts[nhostsbak],
-				    host_addr) == 1) {
-					hints.ai_flags |= AI_NUMERICHOST;
-				} else {
-					/*
-					 * Skip if we have an AF_INET adress.
-					 */
-					if (inet_pton(AF_INET, hosts[nhostsbak],
-					    host_addr) == 1)
-						continue;
-				}
-	        		break;
-			default:
-				break;
-			}
+			--nhostsbak;
 
 			/*
 			 * If no hosts were specified, just bind to INADDR_ANY
@@ -404,68 +521,14 @@ init_transport(struct netconfig *nconf)
 			if (strcmp("*", hosts[nhostsbak]) == 0)
 				hosts[nhostsbak] = NULL;
 
-			if ((aicode = getaddrinfo(hosts[nhostsbak],
-			    servname, &hints, &res)) != 0) {
-			  if ((aicode = getaddrinfo(hosts[nhostsbak],
-						    "portmapper", &hints, &res)) != 0) {
-				syslog(LOG_ERR,
-				    "cannot get local address for %s: %s",
-				    nconf->nc_netid, gai_strerror(aicode));
-				continue;
-			  }
-			}
-			addrlen = res->ai_addrlen;
-			sa = (struct sockaddr *)res->ai_addr;
-			oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
-                        if (bind(fd, sa, addrlen) != 0) {
-				syslog(LOG_ERR, "cannot bind %s on %s: %m",
-					(hosts[nhostsbak] == NULL) ? "*" :
-					hosts[nhostsbak], nconf->nc_netid);
-				if (res != NULL)
-					freeaddrinfo(res);
+			memset(&taddr, 0, sizeof(taddr));
+
+			r = create_transport_socket(nconf, hosts[nhostsbak], &taddr.addr, &fd);
+			if (r < 0)
+				goto error;
+			if (r == 0)
 				continue;
-			} else
-				checkbind++;
-			(void) umask(oldmask);
-
-			/* Copy the address */
-			taddr.addr.maxlen = taddr.addr.len = addrlen;
-			taddr.addr.buf = malloc(addrlen);
-			if (taddr.addr.buf == NULL) {
-				syslog(LOG_ERR,
-				    "cannot allocate memory for %s address",
-				    nconf->nc_netid);
-				if (res != NULL)
-					freeaddrinfo(res);
-				return 1;
-			}
-			memcpy(taddr.addr.buf, sa, addrlen);
-#ifdef RPCBIND_DEBUG
-			if (debugging) {
-				/*
-				 * for debugging print out our universal
-				 * address
-				 */
-				char *uaddr;
-				struct netbuf nb;
-				int sa_size = 0;
-
-				nb.buf = sa;
-				switch( sa->sa_family){
-				case AF_INET:
-				  sa_size = sizeof (struct sockaddr_in);
-				  break;
-				case AF_INET6:
-				  sa_size = sizeof (struct sockaddr_in6);				 
-				  break;
-				}
-				nb.len = nb.maxlen = sa_size;
-				uaddr = taddr2uaddr(nconf, &nb);
-				(void) fprintf(stderr,
-				    "rpcbind : my address is %s\n", uaddr);
-				(void) free(uaddr);
-			}
-#endif
+
 			my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 
                                 RPC_MAXDATASIZE, RPC_MAXDATASIZE);
 			if (my_xprt == (SVCXPRT *)NULL) {
@@ -473,84 +536,15 @@ init_transport(struct netconfig *nconf)
                                         nconf->nc_netid);
 				goto error;
 			}
+			checkbind = 1;
+			fd = -1;
 		}
 		if (!checkbind)
 			return 1;
 	} else {	/* NC_TPI_COTS */
-		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
-			syslog(LOG_ERR, "cannot create socket for %s",
-			    nconf->nc_netid);
-			return (1);
-		}
-
-		if ((strcmp(nconf->nc_netid, "local") != 0) &&
-		    (strcmp(nconf->nc_netid, "unix") != 0)) {
-			if ((aicode = getaddrinfo(NULL, servname, &hints, &res))!= 0) {
-			  if ((aicode = getaddrinfo(NULL, "portmapper", &hints, &res))!= 0) {
-			  printf("cannot get local address for %s: %s",  nconf->nc_netid, gai_strerror(aicode));
-			  syslog(LOG_ERR,
-				    "cannot get local address for %s: %s",
-				    nconf->nc_netid, gai_strerror(aicode));
-				return 1;
-			  }
-			}
-			addrlen = res->ai_addrlen;
-			sa = (struct sockaddr *)res->ai_addr;
-		}
-		oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
-		__rpc_fd2sockinfo(fd, &si);
-		if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on,
-				sizeof(on)) != 0) {
-			syslog(LOG_ERR, "cannot set SO_REUSEADDR on %s",
-				nconf->nc_netid);
-			if (res != NULL)
-				freeaddrinfo(res);
-			return 1;
-		}
-		if (bind(fd, sa, addrlen) < 0) {
-			syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
-			if (res != NULL)
-				freeaddrinfo(res);
-			return 1;
-		}
-		(void) umask(oldmask);
-
-		/* Copy the address */
-		taddr.addr.len = taddr.addr.maxlen = addrlen;
-		taddr.addr.buf = malloc(addrlen);
-		if (taddr.addr.buf == NULL) {
-			syslog(LOG_ERR, "cannot allocate memory for %s address",
-			    nconf->nc_netid);
-			if (res != NULL)
-				freeaddrinfo(res);
-			return 1;
-		}
-		memcpy(taddr.addr.buf, sa, addrlen);
-#ifdef RPCBIND_DEBUG
-		if (debugging) {
-			/* for debugging print out our universal address */
-			char *uaddr;
-			struct netbuf nb;
-		        int sa_size2 = 0;
-
-			nb.buf = sa;
-			switch( sa->sa_family){
-			case AF_INET:
-			  sa_size2 = sizeof (struct sockaddr_in);
-			  break;
-			case AF_INET6:
-			  sa_size2 = sizeof (struct sockaddr_in6);				 
-			  break;
-			}
-			nb.len = nb.maxlen = sa_size2;
-			uaddr = taddr2uaddr(nconf, &nb);
-			(void) fprintf(stderr, "rpcbind : my address is %s\n",
-			    uaddr);
-			(void) free(uaddr);
-		}
-#endif
-
-		listen(fd, SOMAXCONN);
+		memset(&taddr, 0, sizeof(taddr));
+		if (create_transport_socket(nconf, NULL, &taddr.addr, &fd) <= 0)
+			goto error;
 
 		my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
 		if (my_xprt == (SVCXPRT *)NULL) {
@@ -682,7 +676,8 @@ init_transport(struct netconfig *nconf)
 	}
 	return (0);
 error:
-	close(fd);
+	if (fd >= 0)
+		close(fd);
 	return (1);
 }
 
-- 
1.7.12.4

openSUSE Build Service is sponsored by