rpcbind/0006-First-part-of-init_transport-refactoring.patch

495 lines
13 KiB
Diff

From 9cea37f331fe76a9690e93677999cc47f3f70631 Mon Sep 17 00:00:00 2001
From: Olaf Kirch <okir@suse.de>
Date: Tue, 20 Aug 2013 09:26:37 +0200
Subject: [PATCH 06/13] 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