[patch] rresvport_af(3) uses setsockopt(SO_REUSEADDR)

Andrey Zonov andrey.zonov at gmail.com
Wed Nov 24 18:38:25 UTC 2010


Hi,

I've made the patch for rresvport_af(3) and rcmd_af(3) which makes 
possible to use more connections for rsh/rshd.
I've also reviewed freebsd src tree and I think these changes in libc do 
not break any existing applications.

Can anybody look at the patch?

-- 
Andrey Zonov

-------------- next part --------------
Index: libexec/rshd/rshd.c
===================================================================
--- libexec/rshd/rshd.c	(revision 215508)
+++ libexec/rshd/rshd.c	(working copy)
@@ -278,11 +278,6 @@
 	(void) alarm(0);
 	if (port != 0) {
 		int lport = IPPORT_RESERVED - 1;
-		s = rresvport_af(&lport, af);
-		if (s < 0) {
-			syslog(LOG_ERR, "can't get stderr port: %m");
-			exit(1);
-		}
 		if (port >= IPPORT_RESERVED ||
 		    port < IPPORT_RESERVED/2) {
 			syslog(LOG_NOTICE|LOG_AUTH,
@@ -291,10 +286,31 @@
 			    port);
 			exit(1);
 		}
-		*((in_port_t *)&fromp->sa_data) = htons(port);
-		if (connect(s, fromp, fromp->sa_len) < 0) {
-			syslog(LOG_INFO, "connect second port %d: %m", port);
-			exit(1);
+		for ( ;; ) {
+			s = rresvport_af(&lport, af);
+			if (s < 0) {
+				if (errno == EADDRINUSE ||
+				    errno == EADDRNOTAVAIL) {
+					lport--;
+					continue;
+				}
+				if (errno == EAGAIN)
+					syslog(LOG_ERR, "socket: all ports in use");
+				else
+					syslog(LOG_ERR, "can't get stderr port: %m");
+				exit(1);
+			}
+			*((in_port_t *)&fromp->sa_data) = htons(port);
+			if (connect(s, fromp, fromp->sa_len) < 0) {
+				if (errno == EADDRINUSE) {
+					lport--;
+					close(s);
+					continue;
+				}
+				syslog(LOG_INFO, "connect second port %d: %m", port);
+				exit(1);
+			}
+			break;
 		}
 	}
 
@@ -535,11 +551,11 @@
 	char c;
 
 	do {
+		if (cnt-- == 0)
+			rshd_errx(1, "%s too long", error);
 		if (read(STDIN_FILENO, &c, 1) != 1)
 			exit(1);
 		*buf++ = c;
-		if (--cnt == 0)
-			rshd_errx(1, "%s too long", error);
 	} while (c != 0);
 }
 
Index: lib/libc/net/rcmd.c
===================================================================
--- lib/libc/net/rcmd.c	(revision 215508)
+++ lib/libc/net/rcmd.c	(working copy)
@@ -152,6 +152,11 @@
 	for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
 		s = rresvport_af(&lport, ai->ai_family);
 		if (s < 0) {
+			if (errno == EADDRINUSE ||
+			    errno == EADDRNOTAVAIL) {
+				lport--;
+				continue;
+			}
 			if (errno != EAGAIN && ai->ai_next) {
 				ai = ai->ai_next;
 				continue;
@@ -212,17 +217,34 @@
 			fprintf(stderr, "Trying %s...\n", paddr);
 		}
 	}
-	lport--;
+	lport = IPPORT_RESERVED - 1;
 	if (fd2p == 0) {
 		_write(s, "", 1);
 		lport = 0;
 	} else {
-		int s2 = rresvport_af(&lport, ai->ai_family), s3;
+		int s2, s3;
 		socklen_t len = ai->ai_addrlen;
 		int nfds;
 
-		if (s2 < 0)
-			goto bad;
+		for ( ;; ) {
+			s2 = rresvport_af(&lport, ai->ai_family);
+			if (s2 < 0) {
+				if (errno == EADDRINUSE ||
+				    errno == EADDRNOTAVAIL) {
+					lport--;
+					continue;
+				}
+				if (errno == EAGAIN)
+					(void)fprintf(stderr,
+					    "rcmd: socket2: All ports in use\n");
+				else
+					(void)fprintf(stderr, "rcmd: socket2: %s\n",
+					    strerror(errno));
+				goto bad;
+			}
+			break;
+		}
+
 		_listen(s2, 1);
 		(void)snprintf(num, sizeof(num), "%d", lport);
 		if (_write(s, num, strlen(num)+1) != strlen(num)+1) {
@@ -366,6 +388,27 @@
 		return (-1);
 	}
 #endif
+	if (*alport && *alport < IPPORT_RESERVED - 1) {
+		if (*alport < IPPORT_RESERVED / 2) {
+			(void)_close(s);
+			errno = EAGAIN;
+			return (-1);
+		}
+		int reuse = 1;
+		if (_setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0) {
+			(void)_close(s);
+			return (-1);
+		}
+
+		*sport = htons((u_short)*alport);
+		if (_bind(s, (struct sockaddr *)&ss, ((struct sockaddr *)&ss)->sa_len) < 0) {
+			(void)_close(s);
+			return (-1);
+		}
+		*alport = (int)ntohs(*sport);
+		return (s);
+	}
+
 	*sport = 0;
 	if (bindresvport_sa(s, (struct sockaddr *)&ss) == -1) {
 		(void)_close(s);


More information about the freebsd-hackers mailing list